Two things a new contributor currently has to reverse-engineer, and I'd like
to write both up if you want them.
1. No CONTRIBUTING.md
The Contributing section in the README is one line, and the things that
actually trip someone up on a fresh clone are not in it:
npm ci, not npm install — CI fails if the lockfile and package.json
disagree, which is the point, but you only learn it from the workflow.
- The Node floor is exactly
20.18.1, not 20. The comment in ci.yml
explains why; nothing a contributor reads first does.
npm test globs test/*.test.ts, and test/e2e*.sh is deliberately
outside it because it drives a live Overleaf account. ci.yml warns not
to "fix" that by widening the glob — but only someone reading the workflow
finds that warning. It belongs where a contributor looks before pushing.
- How to run the e2e suite at all: which env vars, what a throwaway project
needs to contain.
#46 is the concrete case: npm run lint was a documented command that broke
on a fresh clone. That is the class of problem a contributor guide catches.
2. Nothing explains the shape of client.ts
docs/ covers the git remote helper and MCP — both user-facing. A
contributor opening client.ts cold has no way to know:
- There is no public Overleaf API; the client authenticates as a logged-in
browser session and everything follows from that.
- Auth is a session cookie plus a CSRF token scraped out of the HTML.
extractCsrfToken has three fallbacks because Overleaf changed its markup;
listProjects has three for the same reason. Those look like defensive
clutter until you know they are scar tissue.
- The file tree comes from a hand-rolled Socket.IO 0.9 client
(getProjectFromSocket) because it left the meta tags. That is the most
fragile surface in the repo and the least self-evident.
uploadFile overwrites whole files. It is not the OT edit path the web
editor uses — which is why push has no merge semantics, and why diff
needed to exist at all.
- Which modules are pure and unit-testable without an account (
diff.ts,
ignore.ts, paths.ts, rename-plan.ts, scan.ts) and which need a live
one. That split is deliberate and worth stating, since it tells a
contributor where a new feature's logic should go.
I went through all of this from scratch recently, so I can write it while
it is still fresh — which also means I'm the right kind of wrong reader for
it, not someone who already knows the answers.
Questions before I draft anything
CONTRIBUTING.md at the root, or folded into the README? The root is
currently lean and user docs live in docs/, so I'd rather follow your
preference than guess.
- The architecture note as
docs/ARCHITECTURE.md, or kept as comments in
client.ts? The file already carries substantial comments and I don't
want to split one explanation across two places.
- Anything about the release flow worth writing down —
publish.yml is
tag-triggered and the CHANGELOG is hand-maintained, neither of which is
stated anywhere a contributor would look.
Happy to send it as one PR or two.
Two things a new contributor currently has to reverse-engineer, and I'd like
to write both up if you want them.
1. No CONTRIBUTING.md
The Contributing section in the README is one line, and the things that
actually trip someone up on a fresh clone are not in it:
npm ci, notnpm install— CI fails if the lockfile and package.jsondisagree, which is the point, but you only learn it from the workflow.
20.18.1, not20. The comment inci.ymlexplains why; nothing a contributor reads first does.
npm testglobstest/*.test.ts, andtest/e2e*.shis deliberatelyoutside it because it drives a live Overleaf account.
ci.ymlwarns notto "fix" that by widening the glob — but only someone reading the workflow
finds that warning. It belongs where a contributor looks before pushing.
needs to contain.
#46 is the concrete case:
npm run lintwas a documented command that brokeon a fresh clone. That is the class of problem a contributor guide catches.
2. Nothing explains the shape of
client.tsdocs/covers the git remote helper and MCP — both user-facing. Acontributor opening
client.tscold has no way to know:browser session and everything follows from that.
extractCsrfTokenhas three fallbacks because Overleaf changed its markup;listProjectshas three for the same reason. Those look like defensiveclutter until you know they are scar tissue.
(
getProjectFromSocket) because it left the meta tags. That is the mostfragile surface in the repo and the least self-evident.
uploadFileoverwrites whole files. It is not the OT edit path the webeditor uses — which is why
pushhas no merge semantics, and whydiffneeded to exist at all.
diff.ts,ignore.ts,paths.ts,rename-plan.ts,scan.ts) and which need a liveone. That split is deliberate and worth stating, since it tells a
contributor where a new feature's logic should go.
I went through all of this from scratch recently, so I can write it while
it is still fresh — which also means I'm the right kind of wrong reader for
it, not someone who already knows the answers.
Questions before I draft anything
CONTRIBUTING.mdat the root, or folded into the README? The root iscurrently lean and user docs live in
docs/, so I'd rather follow yourpreference than guess.
docs/ARCHITECTURE.md, or kept as comments inclient.ts? The file already carries substantial comments and I don'twant to split one explanation across two places.
publish.ymlistag-triggered and the CHANGELOG is hand-maintained, neither of which is
stated anywhere a contributor would look.
Happy to send it as one PR or two.