Guidance for AI agents working in the codegen repository.
Codegen = polyglot generator repo. Generates and installs AI-agent harnesses (Claude Code) consumed by downstream Phoenix and static-site projects. Tech stack: Bash + Python (process_template.py, hook_registrations.py) + Jinja-style .md.j2 templates + Elixir/ExUnit test harness.
→ See context/repo-structure.md for physical layout of every file and directory.
→ See context/development.md for Make targets, tech stack details, and coding conventions.
Codegen uses the standard multi-agent chain. Role routing for this repo:
developer-phoenix-backend ← ALL non-UI work in codegen (schemas, contexts, controllers, hooks, rules, scripts)
↓ (if frontend slice)
developer-phoenix-frontend ← only if HEEx/LiveView/Tailwind/JS changes needed
↓
reviewer-phoenix
↓
context-curator
↓
codegen-commit --subject "<text>" ← deterministic script, not a subagent
Codegen-specific gloss — developer-phoenix-backend scope:
In this repo "backend" means everything: Bash scripts, Python generator pipeline, Elixir/ExUnit test harness, .md.j2 templates, rule files, hook scripts, scaffold files. There is no separate UI layer; developer-phoenix-frontend is only needed if a downstream-facing HEEx template, LiveView module, or Tailwind class is being changed.
Split discipline (downstream Phoenix apps): lib/<app>/ (contexts, schemas, workers, mailers) → backend. lib/<app>_web/ LiveView modules (*_live.ex), HEEx templates, JS hooks, Tailwind → frontend. Reviewer routes feedback to the correct subagent based on which layer the fix lands in.
NEVER IMPLEMENT — Orchestrator MUST NOT write code, edit source files, or run build commands directly. Delegate all implementation to the appropriate subagent.
ALWAYS RUN FULL CYCLE — After any rule, template, hook, or scaffold change the full install cycle MUST be run by the developer subagent:
make test→make install→ parity checks →make test-stacks(pre-deploy gate). Skipping steps leaves stale baked prompts in~/.claude/.
What the developer subagent runs after any change:
- Edit a
.md.j2template, rule file, hook script, or scaffold script make test— fast, hermetic; no LLM callsmake install— regenerate agents, register hooks, render settings; propagates edits to~/.claude/- Post-gate checks (optional):
make harness-path-check— standalone optional manual target make test-stacks— slow ExUnit scaffold suite; real LLM calls; run as pre-deploy gate
Gate command = make test (fast, hermetic). make test-stacks is the pre-deploy gate (slow, real LLM calls). make ci exists as a pure alias for make test (ci: test) — not a distinct target; the Phoenix-only gate is the downstream generated app's make ci. Codegen's own GATE_COMMAND is declared once in .claude/gate-config.sh, never per cycle.
Multiple SHAPED pitches in codegen/pitches/ready/ → drain with claude-build --queue --watch. This routes to mix codegen.loop.queue (LoopQueueDrain), which already: orders ready/ by blocks_on: frontmatter, spawns one fresh codegen-build child per pitch, verifies each ship is non-orphaning (HEAD moved forward since the pre-spawn head_before, never reset away), moves ready/<slug>.md → shipped/<slug>.md only on a VERIFIED ship, and — with --watch — sleeps and re-scans on an empty queue instead of exiting, honoring mid-arrival quiescence. Cross-box possession: codegen-drain assign. Fleet distribution never separates a ready pitch from a prerequisite or dependent — assign --auto/assign --slug --node keep a blocks_on: chain on one node for its full ready → building → shipped lifecycle, fail-closed on any unreachable node.
NEVER hand-roll a drain, driver, or relaunch loop — no /tmp/*.sh polling ready/, no shell wrapper re-implementing ship verification or backoff. This has happened before, cost real commits, and the fix is always to use the shipped drain, not to patch the hand-rolled one.
- Work in current directory only (never
../) - No worktrees — commit directly to main
Cross-reference modified files against PROJECT_CONTEXT.md § Domain Context Files Update column. Update every matched row before reporting done. If structural changes added new modules or files that no row covers, add a new row to § Domain Context Files with concrete Load-when and Update-when targets.
Final message MUST contain exactly one fenced JSON block with build result and NOTHING after it:
{ "status": "success" }or, on failure:
{ "status": "failed", "reason": "<short reason>" }Rules:
- Block MUST be in a
```jsonfenced code block (lowercasejsonafter the opening```). - Block MUST be the last thing in final message — no prose, no commit hashes, no farewells after closing
```. statusis exactly"success"or"failed"(lowercase string).- For failures,
reasonis single short sentence (under 200 chars). - Emit at most ONE such JSON block. A second one anywhere in final message → build recorded as failed.
This block is parsed programmatically. If you omit it, emit invalid JSON, or include extra text after it, build is recorded as failed even if all work succeeded. Do NOT output it before committing.
{"status":"success"} requires ALL of:
- Session log exists with all subagent sections
- CI passed (loop's dev-gate step →
ALL CLEAR ✅in session log) - Quality approved (reviewer-phoenix)
- Git commit made
- Issue Discovery → Immediate Fixing — find, fix, never just document
- Session logging — record commands in
codegen/logging/ - Credentials — never replace real credential/token values with placeholders