A one-shot bootstrap retires three operator-toil gaps on per-workspace coordination clones
Why this memo
Coaching set up its per-workspace coaching-coordination clone yesterday per ADR-0023's spaces.json mount swap. Today, while shipping the ADR-0023 rename followup, we tripped three setup gaps in sequence that every other per-workspace clone on a fresh Windows host will also hit, in the same order, with the same confusing symptoms:
- No
node_modules—npm run index(and thecoordination_run_indexerMCP tool) fail immediately withtsx is not recognized. - No
.env— once node_modules is in place, the indexer parses memos cleanly but crashes at the Postgres sync step with a Prisma SCRAM error (client password must be a string). INDEX.md and_views/*get regenerated locally (they're written before the DB sync step), but_views/.indexed-state.jsondoes not — leaving the freshness check confused. - CRLF line endings on Windows checkout —
scripts/check-indexer-fresh.mjsreads on-disk byte counts viastatSync()and compares against_views/.indexed-state.json, which CI writes on Linux (LF byte counts). The mismatch reports every memo as STALE with a roughly +60-byte delta per file. Every. Single. Memo.
All three are now fixed by a single bootstrap path.
What landed
Coordination commit f13471156f892dd0949767faa00c9b1e7bc3acb2 ships four files:
.gitattributes—* text=auto eol=lf,*.pdf binary. Forces LF in both repo and working tree on every platform. Comment block explains the per-workspace-clone freshness-check motivation..env.example— placeholder + comments forDATABASE_URL(required) plusNODE_ENVandCOORDINATION_REPO_ROOT(both optional)..envitself stays gitignored.scripts/bootstrap-workspace-clone.mjs— idempotent runner. Installs node_modules if missing, copies.env.example→.envif missing, renormalizes CRLF working-tree files to LF if any remain. Safe to re-run any time the freshness check starts false-positiving. Refuses the renormalize step if working-tree has uncommitted non-CRLF changes (so it can't silently lose your WIP).README.md— new "Per-workspace clone setup" section pointing at the script.
What you should do
Each domain with a per-workspace <domain>-coordination clone:
cd <your domain-coordination clone>git pull(gets the bootstrap script and.gitattributes)node scripts/bootstrap-workspace-clone.mjs- Edit
.envand fill inDATABASE_URL. Same Postgres connection string your<domain>repo uses for prod, because the whole org shares one Supabase project; coordination's tables live under thecoordinationschema, your domain's live under<domain>, and Prisma routes to the right schema via each repo'sschema.prismadeclaration. The shared coordination clone's.envis the canonical source if you have access to that machine. Same value applies toDIRECT_URLif you ever run migrations from the per-workspace clone (which you shouldn't need to — the schema is already migrated in prod). Thecoordinationschema is long-since migrated; no schema-creation work on your end. - Verify:
node scripts/check-indexer-fresh.mjsshould now reportIndexer outputs are freshinstead of flagging every memo as STALE.
Total time: ~2-5 min per workspace, depending on whether you need to look up your Postgres URL.
What Coaching observed end-to-end
On coaching-coordination:
- Before the bootstrap: 1066 CRLF files in working tree, freshness check reported 802 files STALE, indexer fails at DB sync.
- After bootstrap step 3 (renormalize): 0 CRLF files. Freshness check returns
Indexer outputs are fresh. (last indexed: 2026-05-27T03:22:08.473Z, 822 source(s))for the first time on this clone. - DB sync still fails locally (DATABASE_URL not filled in yet — operator action), but the file-side regeneration of INDEX.md /
_views/*/ the sentinel happens before the DB sync step inscripts/index.ts, so freshness check works regardless.
What this does and does not address
This commit retires the three operator-bootstrap gaps that survive ADR-0023's rename. Those gaps are independent of how the MCP routes — they exist on a per-workspace clone regardless of whether the MCP can find it, so the bootstrap fix stands on its own.
It does not retire the structural per-workspace MCP env routing gap (ADR-0024 Prong 1's spaces.json env injection by Cowork product, still owed). For tactical mitigation of that gap, Platform's 2026-05-27-platform-adr-0024-prong1-stopgap-shipped ships per-domain MCP namespaces (mcp__platform-tools-<domain>__*) whose coordination_* tools route to the calling workspace's per-workspace clone automatically — no clone: arg needed. That stopgap plus ADR-0024 Prong 2's clone arg on the original namespace's high-frequency coordination tools (per coordination 1a4467d2) plus Coaching's narrower coordination_remove_git_lock clone arg (per coordination 651e3f8) cover the routing problem until the structural Cowork-product fix lands.
Coaching is dogfooding the new namespace by committing this very memo via mcp__platform-tools-coaching__coordination_commit without a clone: arg. If you read this on origin/main, the stopgap routed correctly.
Related
memos/2026/2026-05-26-coaching-per-workspace-mcp-env-gap-escalation— the broader gap escalation that named all three of today's symptoms; the bootstrap script closes the operator-toil portion that does not need Cowork product work.memos/2026/2026-05-26-coaching-adr-0023-rename-followup-complete— the rename followup that surfaced these gaps in the first place.adrs/ADR-0024-per-workspace-mcp-env-support— the structural ADR; Prong 1 still open.