init-project
purpose
Bootstrap a new project's agent documentation system from a portable bundle in one shot. After init the project self-maintains using the deployed standard (doc-organization.md §8.3 decision tree + portable meta-standards). init runs once per project; update may be re-run later at that project to pull newer portable files from the bundle (3-way safe merge — never clobbers un-promoted local edits). check/promote maintain the bundle itself and run only at this master repo.
dependencies
./portable/rules/— 9 portable rules of the Claude Code set (always-loaded + path-scoped)./portable/codex-rules/— agents-md-standards.md, codex-agents-standards.md (deploy to.codex/rules/) — the Codex set's own standards, authored not mirrored: each describes a mechanism the other platform does not have (harness-adapter.md§4)./portable/guide/— bug-report-format.md, capability-packaging.md, doc-system-mechanics.md, five-why.md, fix-impact-analysis.md, lesson-capture.md, markdown.md, mermaid.md, decision-journal.md, harness-adapter.md, orchestration-policy.md, review-checklist-method.md, role-selection.md, rule-health.md, task-planning.md, verification-gate-design.md, worktree.md (deploy to.agent-workspace/guide/general/)./portable/roles/— business-analyst.md, tech-lead.md, developer.md, qa.md, project-manager.md, security.md, comtor.md (deploy to.agent-workspace/guide/roles/) — the genome role set, seven sections each, capped at 90 lines (role-selection.md§3)./portable/tooling/— verify_lesson_router.py, verify_role_files.py, verify_decision_log.py, verify_wiki.py, scan_rule_health.py, render_codex.py (each with its test_*.py), test_trigger_kinds.py and archive_decisions.py (deploy to.agent-workspace/tooling/) — the gates over the genome's own artifacts, Python 3 stdlib only; a project's own tools never enter this group./portable/skills/— document-writer/ (whole tree)./portable/agents/— empty; the group exists so a project can promote a subagent of its own into it (subagent-standards.mdgoverns the file shape)./templates/— CLAUDE.md.tpl, guide/index.md.tpl, docs/index.md.tpl, lessons/index.md.tpl, roles/index.md.tpl, decisions/index.md.tpl, wiki/index.md.tpl./VERSION— bundle version, bumped on every promotescripts/update.mjs(repo root) — engine for theupdatemode (3-way bundle→live merge);scripts/init-manifest.mjs— computes the step-6 manifest;scripts/sync-version.mjs— version single-source sync
modes
| invocation | runs where | action |
|---|---|---|
/init-project |
new project | deploy bundle (workflow below) |
/init-project check |
master repo (init'd) | sha256 compare bundle ↔ live per §map → report drift |
/init-project promote |
master repo (init'd) | copy live → bundle for every mapped file, bump VERSION |
/init-project update |
initialized project | pull newer portable files bundle → live, 3-way safe (manifest ↔ live ↔ bundle); skip conflicts (workflow below) |
Harness target — claude (default) · codex · both. Asked at interview (step 2), recorded in the manifest. Every target deploys the identical body; codex and both additionally render the Codex binding surface (step 3b). A target added later needs step 3b alone — nothing in the body changes, which is the whole point of harness-adapter.md §1.
workflow (init — new project)
- Create the agent workspace
.agent-workspace/at the project root — everything the agent owns lives here, nothing of it underdocs/(doc-organization.md §11). Subfolders are created by the step that fills them:guide/(step 3),lessons/(step 4),tasks/andworktrees/(first use at runtime). Add.agent-workspace/tasks/and.agent-workspace/worktrees/to.gitignore— task state and throwaway checkouts are never committed (orchestration-policy.md §5).tooling/is filled by step 3 — the genome ships its own gates there (.agent-workspace/tooling/); a project keeps its own scripts beside them, grouped one subfolder per purpose, and those never enter the bundle. - Scan project: detect stack + optional modules per
## module matrixsignal column. Output: proposed module set + discovered slot values. - Interview: confirm proposed module set; ask slots not scannable (dev ports in use, scope ownership, doc language, the decision-journal per-shard cap, always-loaded budget — offer 600 lines as the default; the genome's own floor is the figure recorded in the placement-data row of the router this init renders). Unanswerable slot → leave TODO marker, never invent a value; module uncertain → skip it.
- Copy
portable/verbatim:portable/rules/*→.claude/rules/;portable/codex-rules/*→.codex/rules/;portable/guide/*→.agent-workspace/guide/general/;portable/roles/*→.agent-workspace/guide/roles/;portable/tooling/*→.agent-workspace/tooling/;portable/skills/*→.claude/skills/;portable/agents/*→.claude/agents/. 3b. Codex target only — render the platform set:python .agent-workspace/tooling/render_codex.py. It composesAGENTS.md(the root index plus every always-loaded rule inlined in full), mirrors the shared rules into.codex/rules/*.mdwith paths rewritten, writes the full body of each skill into.agents/skills/and each agent into.codex/agents/*.toml, and ships.codex/config.tomlwith aproject_doc_max_bytessized to the chain (harness-adapter.md§5). Run it AFTER step 4, since the chain is composed from the root index step 4 produces; run it again after step 5 appends its triggers. Never hand-write a generated file —render_codex.py --checkis the gate, and it is what a project wires into its pre-commit hook. No file of either platform set may name a path of the other; the gate fails on that too. - Render templates: fill
{{slots}}from interview intoCLAUDE.md,.agent-workspace/guide/index.md,docs/index.md; missing slot → keep TODO marker.lessons/index.md.tplcarries no slot — copy it verbatim to.agent-workspace/lessons/index.md, seeding the lesson store empty (lesson-capture.md§5); its §1 is the only router a lesson store is ever registered in, andCLAUDE.md.tplalready carries the one line that reaches it — never add a per-store trigger.roles/index.md.tplcarries no slot either — copy it verbatim to.agent-workspace/guide/roles/index.md; its §1 holds the genome roles and its §1a is the empty table a project adds its own roles to (role-selection.md§5).decisions/index.md.tplrenders to.agent-workspace/decisions/index.md, seeding the journal with a router and no entry (decision-journal.md§5: an entry is written when a decision is made, never upfront); its only slot, the per-shard entry ceiling the gate reads — unanswerable → TODO marker.wiki/index.md.tplrenders to.agent-workspace/wiki/index.mdONLY when the wiki module is confirmed (see## module matrix), seeding the tier with a router and no cluster (wiki-tier.md§2: a cluster is created when an investigation first touches its lookup topic, never upfront). Its slots are the extension pointswiki-tier.md§7 requires the project to declare — the locator root and the claim-class table are the two the interview must reach; unanswerable → TODO marker, never an invented value. Module not confirmed → the template is not rendered and no wiki trigger is written; the rule still deploys.- A rendered target that already exists is MERGED, never overwritten. A project with its own
CLAUDE.mdis carrying rules nothing else records — release steps, ownership, domain guardrails — and rendering over them deletes the only copy. Carry every existing rule into the project-rule slots, then add the template's; the deployed standard is additive to that project, not a replacement for it. A category the project has no work products for (docs/) is not rendered at all — an empty router is scaffolding, not content; record the.tplsha in the manifest anyway soupdatewarns only on a real template change.
- A rendered target that already exists is MERGED, never overwritten. A project with its own
- Generate optional rules: for each confirmed optional module, write a project-fitted rule into
.agent-workspace/guide/general/perrule-writing-standards, and append its trigger line toCLAUDE.mdin the same step — no hardcoded template. - Write manifest
.claude/init-manifest.json:{ version, deployedAt, files:[{path,sha256}], templates:[{path,sha256}], modules:[...] }(provenance;files[]read byupdatefor 3-way drift detection — keep sha256 accurate;templates[]records the.tplsha each rendered file was built from —path= template path relative totemplates/e.g.CLAUDE.md.tpl, used byupdateto WARN when a template changed since deploy). Generate it —node <plugin>/scripts/init-manifest.mjs --project <project-root> --modules <list>— never hand-write the hashes: a wrong sha256 does not fail here, it surfaces later as a phantom CONFLICT or a silent overwrite of a local edit. - Verify: every deployed file is at the correct tier; every rule/guide file carries
scope:frontmatter; CLAUDE.md within token budget; every behavior-affecting on-demand file has a trigger line or router entry (reachability, file→trigger); everyMUST Readtrigger in CLAUDE.md resolves to a deployed file (reachability, trigger→file — no dead trigger);.agent-workspace/lessons/index.mdexists and CLAUDE.md carries the lookup line pointing at it (without it every future lesson store is born dead);.agent-workspace/guide/roles/index.mdexists, CLAUDE.md carries the role lookup line pointing at it, and every role name in that index (primary and checking cells alike) resolves to a.mdfile of the same name under.agent-workspace/guide/roles/— the router is rendered by step 4 and the role files are copied by step 3, independently, so a router existing alone does not prove the role files landed; the deployed gates run green from the project root —python .agent-workspace/tooling/verify_lesson_router.py,python .agent-workspace/tooling/verify_role_files.py,python .agent-workspace/tooling/verify_decision_log.py,python .agent-workspace/tooling/verify_wiki.pypython .agent-workspace/tooling/test_trigger_kinds.pyand each pairedtest_*.py, all exit 0 (scan_rule_health.pyis a REPORT, not a deploy gate — it exits 0 with open findings and only exits 1 when the always-loaded budget is breached or the ledger is malformed) (verify_wiki.pyon a project without the wiki module reportsclusters: 0and passes; it fails only if the router is missing while clusters exist, orsource_rootis undeclared) (running them is the only proof the copied gate matches the copied artifacts; a gate present but red means the deploy is incomplete, not that the gate is wrong); no unrendered{{slot}}remains except intentional TODO markers; on acodexorbothtarget,python .agent-workspace/tooling/render_codex.py --checkexits 0 — that one command covers the whole set: nothing missing, nothing orphaned, no cross-reference, and the chain under the cap the rendered config declares (a stale surface means step 3b ran before step 5 appended its triggers — re-run it). Done = checklist passes + manifest written.
bundle ↔ live map (check / promote — master repo; update — initialized project)
| bundle path | live path |
|---|---|
portable/rules/* |
.claude/rules/* |
portable/guide/* |
.agent-workspace/guide/general/* |
portable/roles/* |
.agent-workspace/guide/roles/* — index.md excluded: it is rendered from templates/roles/index.md.tpl and is scope: project |
portable/tooling/* |
.agent-workspace/tooling/* |
portable/skills/* |
.claude/skills/* |
portable/agents/* |
.claude/agents/* |
portable/codex-rules/* |
.codex/rules/* — the AUTHORED Codex rules only; the generated mirrors beside them carry a marker and are owned by render_codex.py |
Everything else in the Codex set — AGENTS.md, .codex/config.toml, the mirrored .codex/rules/*.md, .agents/skills/*, .codex/agents/* — is NOT in this map and never enters the bundle: it is generated from the Claude Code set by render_codex.py, so its drift gate is render_codex.py --check, not a sha256 pair (harness-adapter.md §5).
- Precondition: the master repo must itself be init'd — it is deployed instance #1 (
doc-organization.md §4), and without a live tiercheckhas nothing to compare andpromotehas nothing to copy from. A master repo with no.claude/rules/runs/init-projecton itself first (step 4's merge rule applies to its existingCLAUDE.md). Until then the bundle is edited directly and no mechanism can detect that it drifted. check: sha256 each pair → list mismatches. Default update direction is live → bundle (promote); fix live first, then promote.promote: copy live → bundle for every mapped file, then bump the version vianode scripts/sync-version.mjs set <x.y.z>(writes canonicalVERSION+ mirrors it into.claude-plugin/*and the README badge).
workflow (update — initialized project)
Direction bundle → live (reverse of promote). Touches only the verbatim portable set; rendered phenotype (CLAUDE.md, index.md, project-authored guides) is out of scope. Invoke update.mjs by its path inside the installed plugin (it self-locates the bundle from its own location); --project is the initialized project root and defaults to the current directory.
- Dry-run:
node <plugin>/scripts/update.mjs --project <project-root>→ review the ADD / UPDATE / CONFLICT plan and the version delta. - Resolve every CONFLICT first — a conflict = a portable file edited locally since deploy. Promote it upstream (so the improvement enters the bundle) or overwrite manually after review. Never blind-overwrite.
- Apply:
node <plugin>/scripts/update.mjs --apply --project <project-root>→ writes ADD + UPDATE, skips conflicts, refreshes manifestversion+files[].sha256. - Additive + in-place only —
updatenever deletes: a file removed from the bundle stays in the project, and a file deleted locally is re-added. Prune those manually if needed.templates/*(CLAUDE.md, index.md — rendered phenotype) are never overwritten: their slots hold project-specific values.updateonly emits a WARN when a.tplchanged since deploy (sha vsmanifest.templates[]); re-render manually (diff.tplvs live, re-apply structural changes, keep slot values) or re-run/init-project. The WARN persists until the next init re-records the template sha.
- Exit code: 0 = up-to-date or applied cleanly; 1 = conflicts remain; 2 = setup error (no manifest → project was not init'd by this plugin).
- Verify reachability of every ADD — mandatory, and the reason step 4's WARN is not enough.
updatewrites the portable file but never the trigger line or router entry that reaches it, so a newly-added guide lands as dead content: present in the project, read by nobody. For each ADD, confirm the liveCLAUDE.mdcarries its trigger (when the file is behavior-affecting perdoc-organization.md§10 interception test) AND the live.agent-workspace/guide/index.mdcarries its router entry; write whichever is missing, and create any directory the new file's guidance assumes (e.g. a store folder seeded fromtemplates/). Done = every ADD reachable by trigger or router, both directions resolving.
module matrix
| module | includes | deploy when | scan signal (examples, not exhaustive) |
|---|---|---|---|
| core | portable/* (all 4 groups) + 4 templates |
always | — |
| runtime | .agent-workspace/guide/general/local-runtime.md + CLAUDE.md trigger (skill writes per scan, step 5) |
project self-runs a dev server | package.json dev/start scripts, launchSettings.json, vite/next/dotnet/django/cargo config |
| e2e | .agent-workspace/guide/general/<tool>.md (named after detected tool) + CLAUDE.md trigger (step 5) |
project has E2E browser tests | playwright/cypress/selenium dep, e2e/ folder, E2E config |
| wiki | .agent-workspace/wiki/index.md rendered from wiki/index.md.tpl + CLAUDE.md trigger (step 5) |
the project investigates SUBJECT MATERIAL it does not own — a legacy codebase, a customer's system, a body of source documents — and needs established claims written back. The rule wiki-tier.md ships in core either way: it is paths:-scoped to .agent-workspace/wiki/**, so it costs nothing while the tier is absent |
a large read-only source tree the project analyses but does not build; an existing investigation/analysis workflow; the user confirms there is external material to establish facts about |
- Optional module deploys only when scan confirms OR user confirms at interview — uncertain → skip.
- Git: minimal guardrail (commit only on request, never push) ships in
CLAUDE.md.tpl; detailed policy isscope: project— project writes.agent-workspace/guide/general/git.mdon demand, adding its trigger line in the same commit (reachability — never a trigger pointing at a missing file). - A skipped module needed later → project writes the rule itself per the deployed standard. New module enters the bundle only via
promoteafter a real project battle-tests the pattern.
independence rules
- Skill runs once per project; deployed files reference no file of this master repo; project rules never name this skill.
- Self-contained except the bundle↔live map above, which executes only at the master repo for check/promote.
examples
✅ scan finds package.json with "dev" script → propose runtime module → step 5 writes
general/local-runtime.md + appends "self-run dev server → MUST Read ..." to CLAUDE.md
❌ deploy runtime module with no scan signal and no interview confirm (guessed module)
✅ /init-project check → "MISMATCH: portable/rules/doc-organization.md != .claude/rules/doc-organization.md"
→ fix live first → /init-project promote
❌ edit portable/* directly then init a new project (bundle diverges silently from live)
reference files
- bundle:
./portable/** - templates:
./templates/** - version:
./VERSION