Skip to content

Contributing

Overview

Contributions to this implementation are welcome. This guide covers prerequisites, development workflow, testing, and how to submit changes.

Path convention. <record>/ below = a created intent's record dir, aidlc/spaces/<space>/intents/<YYMMDD>-<label>/ — where per-intent state, audit shards, knowledge, and artifacts live.

Prerequisites

  • Claude Code -- native install (recommended, auto-updates): macOS/Linux/WSL curl -fsSL https://claude.ai/install.sh | bash; Windows PowerShell irm https://claude.ai/install.ps1 | iex. Or brew install --cask claude-code. (see Claude Code docs)
  • bun -- Required to build, package, test, directly run authored TypeScript sources, and use locally generated dist/<harness>/ projections. Native release runtimes use the installed aidlc command. Install via curl -fsSL https://bun.sh/install | bash; on Windows use powershell -c "irm bun.sh/install.ps1 | iex".
  • timeout (GNU coreutils) -- Required by the test suite for LLM test timeouts (L2/L3). Pre-installed on Linux. macOS: brew install coreutils then add gnubin to PATH: export PATH="/opt/homebrew/opt/coreutils/libexec/gnubin:$PATH" (in ~/.zshenv or ~/.zshrc).
  • Bash -- Optional for the POSIX compatibility wrapper (tests/run-tests.sh). The primary test runner is bun tests/run-tests.ts; at runtime, none of the distributable hooks require Bash.
  • Bedrock access -- Required for running live integration and e2e tests (L2/L3). Not needed for L1 protocol tests.

After cloning, install the pinned development dependencies used by the packager, type checker, and tests:

bun install --frozen-lockfile

Repository Structure

core/                # Hand-authored, harness-neutral source (tools, stages, agents, rules, knowledge, hooks)
harness/<name>/      # Per-harness authored surfaces; claude/, kiro/, kiro-ide/, codex/, opencode/, copilot/
scripts/package.ts   # The build: materializes ignored local projections (`--check` builds twice and compares)
scripts/build-binaries.ts # Release-only compiled CLI artifacts in ignored build/binaries/ after package --check
dist/<harness>/      # GENERATED + ignored: dist/claude/, dist/kiro/, dist/kiro-ide/, dist/codex/, dist/opencode/, dist/copilot/ — never hand-edit or commit
tests/               # All-TypeScript test suite (t*.test.ts, run via bun)
docs/                # Documentation
  guide/             # User guide (how to use AI-DLC)
  harness-engineering/  # Harness engineer guide (configure AI-DLC without code)
  reference/         # Developer reference (how it works internally)

For the full architecture, see reference/01-architecture.md.

Development Workflow

  1. Fork and branch from main (the integration branch and PR target), then run bun install --frozen-lockfile
  2. Read the architecture -- reference/01-architecture.md explains the execution model, agent delegation, and hook system
  3. Understand the entry points -- the deterministic engine core/tools/aidlc-orchestrate.ts (with exactly five subcommands: next, continue, report, park, and team-board; continue is internal steering transport and team-board is the read-only Team Construction query) owns routing; the conductor harness/claude/skills/aidlc/SKILL.md is a thin forwarding loop that acts on its directives. For the normative engine / directive / conductor / swarm contract see The Skill System
  4. Make changes -- Edit the harness-neutral source in core/ (tools, stages, agents, hooks, rules, knowledge) or a harness surface in harness/<name>/ (the orchestrator skill, settings). Then run bun scripts/package.ts to materialize the ignored local dist/ and dist-release/ roots. Never hand-edit or commit either root. package.ts --check ignores those on-disk trees, builds the complete projection set twice in independent temporary roots, and byte-compares the results.
  5. Test -- Run bun tests/run-tests.ts before submitting
  6. Submit -- Open a PR against main

Release binary artifacts are not part of dist/ and are not produced by the packager. After bun scripts/package.ts --check is clean, run bun scripts/build-binaries.ts for the native artifact or add --all-targets for the release matrix. The script writes each executable under build/binaries/<target>/, stages complete generated distributions under that target's runtime/<harness>/ directory, and writes build/binaries/build-results-<target>.json. Targets executable on the build host run sensors, graph compilation, validation, generated-surface checks, plugin selection/composition, orchestration, ordinary Bolt and autonomous swarm composition, packaged-runtime immutability, hooks, statusline, adapters, explicit project routing, doctor JSON, init dry-run, versions/plugin listings, Unix completions, and package verification without a bun executable on PATH. Cross artifacts receive inspection gates and are explicitly labeled UNVERIFIED; host-run artifacts are labeled VERIFIED. The staged runtime/<harness>/ trees are read-only fallbacks; mutating commands must target an installed project harness. Any failed gate fails the build.

After the target binaries are present, bun scripts/package-release.ts regenerates and verifies the local projections, packages dist-release/ into the versioned aidlc-runtime-X.Y.Z.tar.gz, and emits version.json, checksums.txt, install.sh, and install.ps1. The per-target runtime/ directories are smoke-gate staging; release data archives are rebuilt from the freshly generated native projections, not copied from those sidecars. --require-release-matrix requires all seven targets and a matching verification record for each binary. The generated flat directory is the contract consumed by the installer and release packaging tooling.

The tag-triggered release workflow is deliberately candidate-preserving: verification and installer lint run first; target-native jobs produce binaries and evidence; package-release.ts runs once to create release-candidate; the staging job checksums and uploads it without signing; and Unix/Windows lifecycle jobs consume those bytes. publish re-verifies and attests the candidate, adds the exported bundle, validates the complete inventory, and uploads one attested-release artifact. release rechecks the tag and checksums, creates the GitHub Release in this repository with GITHUB_TOKEN, and verifies the uploaded asset inventory. Never rebuild, repackage, or substitute the candidate. The full trust design is Supply-Chain Security.

Testing

The suite is entirely TypeScript (t*.test.ts, run via bun) across four levels — smoke, unit, integration, e2e — that map onto the three-layer pyramid (smoke + unit = L1 Protocol, integration = L2 Stage, e2e = L3 Acceptance). After the pinned development dependencies are installed, L1 runs locally without external services; the live integration and e2e files require the claude CLI tool (and Bedrock creds) and skip cleanly when it is absent.

Quick reference:

# L1 Protocol -- runs in seconds, no dependencies
bun tests/run-tests.ts

# L2 Stage -- CI pipeline (requires claude CLI tool)
bun tests/run-tests.ts --ci

# L3 Acceptance -- release gate (requires claude CLI tool)
bun tests/run-tests.ts --release

# POSIX compatibility wrapper
bash tests/run-tests.sh --ci

# Individual levels
bash tests/run-tests.sh --smoke        # File structure validation
bash tests/run-tests.sh --unit         # Hook behavior, stage content
bash tests/run-tests.sh --integration  # Cross-component and stage/CLI tests
bash tests/run-tests.sh --e2e          # Workflow, worktree, and terminal journeys

For the full test strategy, stubs, and how to add new tests, see reference/09-testing.md.

Changing Dispatcher Routes

core/tools/aidlc.ts is the registry for public, hidden, and host-only command routes. A new route must declare all policy dimensions rather than inheriting behavior accidentally:

  1. Set projectRequirement, outputModes, visibility, networkPolicy, and mutationScope.
  2. Choose pinPolicy deliberately: active for machine lifecycle/management, inspect for active-binary diagnosis and repair, or pinned for project engine behavior.
  3. Map the route to an existing tool or add the tool to TOOLS; hooks, statusline, adapters, and low-level delegates use route-only entries rather than public aliases.
  4. Add route and policy assertions to tests/unit/t230-dispatcher-routes.test.ts, including global-flag ordering and compiled/dev parity when applicable.
  5. If authored prose invokes the command, use {{INVOKE}} or {{TOOL_PREFIX}} so copy and native projections stay distinct. Regenerate both local channels and run the package determinism guard.

Adding an Install-Mechanism Mutation

Project and machine mutations in init, lifecycle, pinning, and plugin management must use core/tools/aidlc-transaction.ts. Build a TransactionPlan from root-relative, non-overlapping operations; include expected destination state and source hashes for copy/tree operations. Put semantic checks in validateCandidates or validateCommitted, not after a successful transaction returns. A committed validator failure is part of the transaction and therefore rolls back.

Add fault-injection coverage before shipping: fail before/after staging, snapshot, commit, and committed validation as appropriate; assert every prior byte and mode is restored, the lock is released, and incomplete rollback leaves named recovery evidence. t243-install-mechanism.test.ts is the engine pattern; t224-plugin-selection.test.ts and t242-plugin-state.test.ts are project mutation examples.

Adding a Utility Handler

Before adding an audit event, read State Machine. The chapter lists every event in the taxonomy, its emitter, and the "same-commit rule" — update the code AND the chapter's tables in the same PR, or the drift test will fail.

Utility handlers fall into two categories:

Deterministic handlers (preferred)

For handlers that require no LLM reasoning (print text, read/format files, check prerequisites, create directories): 1. Add a subcommand to core/tools/aidlc-utility.ts 2. Register a semantic dispatcher noun/verb and call it from SKILL.md through aidlc engine <noun> <verb> (or its public route) 3. No task tracking needed -- the script runs in under a second 4. Handle audit logging inside the script via appendAuditEntry from aidlc-audit.ts (never hand-write **Event**: markdown blocks) 5. Add the verb to the aidlc-utility usage string. If it renders a generated SKILL.md region, also document the corresponding --check guard in this chapter.

The --help, --version, --status, and --doctor handlers are reference implementations. --doctor also accepts --export (with an optional --output <dir>), which runs a fresh doctor pass and then writes a small, redacted diagnostic report; the shared DoctorFinding model and the report-assembly logic live in core/tools/aidlc-doctor-bundle.ts, so the live report and the exported report draw from one set of findings.

The codekb-path, codekb-snapshot, codekb-publish, and codekb-scope-diff handlers are direct utility verbs: stage prose invokes bun <harness-dir>/tools/aidlc-utility.ts <verb>, not /aidlc <verb> (codekb-path is also reachable through the dispatcher as aidlc engine workspace codekb). codekb-path and codekb-scope-diff are read-only. codekb-snapshot may recover an interrupted prior CodeKB directory swap before returning the source/store generations. codekb-publish is the sole shared-store writer: it validates a complete nine-file candidate and commits it under a space+repo compare-and-swap lock. None emits an audit event or drives SKILL.md task tracking.

project-description and document-input use the same read-only direct-utility shape. Both consuming stages invoke project-description first: a marked record must decode its exact project-description.json string, while an unmarked pre-2.6.115 record explicitly falls back to the legacy Project state field. They invoke bun <harness-dir>/tools/aidlc-utility.ts document-input after writing the selected path with the native file-write tool to the active record's fixed .aidlc-document-input-path transport. Customer-chosen path bytes never enter the shell command. The handler resolves one exact project-root path, records the contained file identity, and requires the opened descriptor to match it before reading; parent-directory replacement, redirects, and unsupported input are refused. Successful reads emit the same inline untrusted-path and untrusted-content notices as DocumentKB.

LLM-driven handlers

For handlers that benefit from agent reasoning (filesystem scanning, decision-making): 1. Task tracking -- Create tasks via TaskCreate for each logical step, transition them with TaskUpdate (in_progress -> completed) as work progresses. This drives the task sidebar in Claude Code. 2. Statusline update -- If the active intent's aidlc-state.md exists, temporarily set Current Stage to describe the running utility (e.g., running health check), then restore the original value when done. The aidlc-statusline.ts hook reads this field for the terminal status bar. 3. Audit logging -- Invoke the appropriate semantic native dispatcher route, whose backing handler calls appendAuditEntry internally. Never hand-write **Event**: markdown blocks from LLM prose — see State Machine: Forbidden patterns.

The intent-create handler is fully deterministic: all three init stages (workspace-scaffold, workspace-detection, state-init) run inside a single aidlc-utility intent-create call. The welcome message is rendered at session start via companyAnnouncements in settings.json and is not a stage.

Adding a Scope

A scope is authored as a file (its identity) plus a per-stage membership tag. The identity lives in core/scopes/aidlc-<name>.md; the membership lives in each stage's frontmatter scopes: list under core/aidlc-common/stages/. Validation logic across init, scope-change, resolve-env-scope, doctor, and state tooling derives the list of valid scopes from the .claude/scopes/*.md files at runtime via validScopes() in core/tools/aidlc-lib.ts; the EXECUTE/SKIP grid is the transpose of the per-stage scopes: lists, compiled to tools/data/scope-grid.json. Adding a scope requires no TypeScript edits.

Steps

  1. Create core/scopes/aidlc-hotfix.md — the scope's identity. Frontmatter:
  2. name (required): the scope name; must equal the filename stem.
  3. depth (required): Minimal | Standard | Comprehensive.
  4. keywords (optional): NL triggers for /aidlc <freeform text> auto-detection. Flat string lists may use block (- item) or flow ([item, item]) form. Word-boundary matched, alphabetical-scope tie-break. Empty list opts out of inference.
  5. description (optional): one-line summary rendered in /aidlc --help and in SKILL.md's compiled scope-table.
  6. testStrategy (optional): override test strategy independent of depth. Defaults to matching depth.
  7. review_cap (optional): adversarial | advisory | none. Caps stage review classes for this scope; absence means no scope-level lowering. The cap can lower but never raise a stage declaration. Autonomous swarm reviews are exempt.
  8. runner (optional): set true to include the scope in the default generated runner set.
  9. freeform_default (optional): set true to nominate this scope when the preferred core default (classic) is not enabled. At most one enabled scope may claim it; graph compilation rejects ambiguous selected plugin sets. Unknown explicit AWS_AIDLC_DEFAULT_SCOPE values still fail validation.

The body is prose intent — "why these stages, why skip those". validScopes() derives from .claude/scopes/*.md presence, so the scope is valid the moment the file lands. Run /aidlc --doctor after editing to catch structural issues.

---
name: hotfix
depth: Minimal
keywords:
  - hotfix
  - urgent
description: Urgent production fix
runner: true
---

# hotfix scope

Lean path for the urgent production patch — regression test and deploy, nothing else.
  1. Tag the member stages — in each stage that should run under hotfix (under core/aidlc-common/stages/<phase>/), add hotfix to its frontmatter scopes: list. A stage you don't tag is SKIP for the scope. The 3 initialization stages (workspace-scaffold, workspace-detection, state-init) must include it — they always run.

  2. Recompile + regenerate the scope-tableaidlc engine graph compile transposes the scopes: tags into tools/data/scope-grid.json. Then aidlc engine gen scope-table prints the canonical Markdown region for SKILL.md's compiled scope table. Keep the region between the <!-- BEGIN: compiled ... --> / <!-- END: compiled ... --> markers generated, then run aidlc engine graph compile --check and aidlc engine gen scope-table --check to confirm exit 0 (no drift).

  3. Verify the scope resolves - bun core/tools/aidlc-utility.ts intent-create --scope hotfix --project-dir /tmp/scope-smoke should succeed and produce a state file with Scope: hotfix.

  4. Verify doctor accepts it as an env defaultAWS_AIDLC_DEFAULT_SCOPE=hotfix aidlc doctor should report the env var as valid.

  5. Verify keyword inference (if keywords populated) — aidlc engine scope detect --from-text --input "urgent customer issue" --project-dir /tmp/scope-smoke should return {"scope":"hotfix","source":"keyword","matches":["urgent"]}.

  6. Verify plan parity (optional but recommended)AIDLC_GRAPH_RESOLVE=1 aidlc engine graph resolve hotfix --stdout emits the scope's plan; eyeball that the EXECUTE set matches what you tagged.

  7. Update scope-aware documentationdocs/guide/05-scopes-and-depth.md (full scope reference, including the Stage-by-Scope Matrix — its cells are drift-guarded against the compiled scope-grid.json by tests/unit/t244-scope-matrix-doc-sync.test.ts), docs/guide/13-customization.md (valid values list and scope table), and docs/reference/03-orchestrator.md (scope-to-stage mapping) all enumerate scopes explicitly. Per the documentation policy at the end of this chapter, update them in the same PR.

  8. Add a scope-routing workflow test — if the scope has behavior that differs from existing scopes (new phase skipping pattern, new depth combination), add a routed journey test modeled after tests/e2e/t53.test.ts (sdk scope routing) or tests/e2e/t-tui-t50-bugfix-scope.serial.test.ts (tui scope run-through).

What validates automatically

  • validScopes().has("hotfix") returns true the moment the .claude/scopes/aidlc-hotfix.md file lands — every validation site uses this helper.
  • Error messages list the new scope in alphabetical order without any code changes.
  • /aidlc --doctor treats AWS_AIDLC_DEFAULT_SCOPE=hotfix as valid.
  • aidlc-utility scope-change --scope hotfix on an in-flight workflow accepts the new scope.
  • The transpose drift guard: aidlc-graph compile --check fails the build if a stage's scopes: tag was edited without recompiling scope-grid.json. SKILL.md's compiled scope-table has its own --check drift guard (t67).
  • Keyword detection for freeform /aidlc <text> invocations reads each scope's keywords from its .claude/scopes/*.md frontmatter. Custom scopes with their own NL triggers auto-detect as soon as the keywords list is populated (no SKILL.md change needed). Users can still pass --scope hotfix explicitly to bypass inference.

What does NOT validate automatically

  • A scopes: tag with a typo'd scope name still compiles — it just produces a grid column nobody asks for, silently dropping that stage from the real scope. /aidlc --doctor and a per-scope test are the guardrails.
  • Stage skipping semantics (PHASE_SKIPPED events). tests/integration/t39.test.ts hardcodes the 9 known scope names in a per-scope loop — a new scope is not exercised until that list is extended. Add your new scope to that loop as part of the same PR.

Adding a Stage

A stage is authored as a Markdown file with YAML frontmatter under core/aidlc-common/stages/<phase>/<slug>.md. The compiler reads the frontmatter into tools/data/stage-graph.json, and the runner generator emits a typeable /aidlc-<slug> skill from the compiled stage list for core stages (plugin-owned stages use their bare plugin-prefixed slug). The extensibility contract is "to add a stage, write a stage file" — no engine edit is required to register it, because the engine routes off the compiled graph. (The full field reference and the three-compartment body format live in the Harness Engineer Guide's Anatomy of a Stage and Adding a Stage; the schema is Stage Definition.)

Steps

  1. Write the stage file - create core/aidlc-common/stages/<phase>/<slug>.md. Frontmatter declares slug, phase, execution/condition, lead_agent and any support_agents (by agent slug), mode (inline, subagent, pipeline, or mob; agent-team is reserved and not yet implemented), consumes / produces (artifact vocabulary names), optional_produces for artifacts the stage writes only conditionally per unit (exempt from per-unit coverage), requires_stage (ordering edges), the scopes: membership list, any sensors: to bind, for_each if it iterates per Unit, and (on a per-unit stage) an optional produces_kinds map to prune produces artifacts to each Unit's kind. The body carries the stage's three compartments. See Stage Definition for the full field contract.

  2. Recompile the graphaidlc engine graph compile reads the new frontmatter into tools/data/stage-graph.json and transposes the scopes: tags into tools/data/scope-grid.json. Run aidlc engine graph compile --check to confirm exit 0 (no drift). Then refresh the generated SKILL.md mirrors with aidlc engine gen stage-table and aidlc engine gen scope-table, and confirm aidlc engine gen stage-table --check plus scope-table --check both exit 0. The stage is runnable immediately via aidlc engine orchestrate next --stage <slug> --single.

  3. Regenerate the runnersaidlc engine gen runners emits a /aidlc-<slug> runner skill per runnable compiled stage, so your new stage gets its typeable command with no hand-authoring. Run aidlc engine gen runners --check to confirm the on-disk runner set matches the compiled stage set (the drift guard; the bootstrap initialization stages are excluded by design).

  4. Verify the stage routes — drive aidlc engine orchestrate next over a workflow whose scope includes the stage, and confirm the engine emits a run-stage directive naming your slug with the resolved lead_agent, gate, consumes, and produces.

  5. Update scope-aware and stage-aware documentation — a new stage changes the stage count and the per-scope plans. Update docs/guide/05-scopes-and-depth.md (the Stage-by-Scope Matrix — its cells are drift-guarded by tests/unit/t244-scope-matrix-doc-sync.test.ts), docs/reference/16-artifact-vocabulary.md (the non-initialisation stage count), the Harness Engineer Guide's stage chapters, and any scope reference that enumerates the plan. Per the documentation policy at the end of this chapter, do it in the same PR.

  6. Add a test and refresh coverage — author a t*.test.ts for the stage's behaviour (the suite is discovered, so dropping the file under the right level directory is all the runner needs — there is no registry row to add). Then regenerate the coverage index with bun tests/gen-coverage-registry.ts and confirm bun tests/gen-coverage-registry.ts --check is clean. The stage-runner drift guard tests/unit/t129-stage-runner-drift.test.ts asserts the generated runner set equals the compiled stage set, and tests/integration/t55-test-suite-drift.test.ts sweeps for stale paths and markers.

What validates automatically

  • Graph placement. Once you compile, the stage's edges (requires_stage, consumes, produces) are resolved and ordered; compile --check fails the build if the on-disk stage-graph.json drifts from the frontmatter.
  • Generated stage table. SKILL.md's Stage Graph table is rendered from compiled stage-graph.json; aidlc-utility stage-table --check fails if the generated region drifts (t32).
  • Schema + references. aidlc-graph.ts compile validates every stage's frontmatter via aidlc-stage-schema.ts, and /aidlc --doctor re-runs validateStageFrontmatter plus a "Graph references" check that every lead_agent / support_agents / consumes slug resolves.
  • Runner parity. aidlc-runner-gen.ts check (and t129) fail if a compiled stage has no runner, or a runner exists for a stage that is gone.

What does NOT validate automatically

  • A new frontmatter key the compiler doesn't recognise. Wanting a key the schema doesn't implement is a framework change: it edits the code that reads the data, so it follows the engine/compile-pipeline path rather than this recipe. The reserved-key namespace in Stage Definition exists so future structural extensions land predictably.
  • Documentation enumerations. Stage counts and per-scope plan tables across docs/ are maintained by hand; update them in the same PR (see Documentation Policy below).

Adding an Agent

Agent metadata (display name, example knowledge files) is read from each agent's .md frontmatter under core/agents/. The loadAgents() helper in core/tools/aidlc-lib.ts discovers every .md file in that directory and derives the metadata map consumed by the statusline hook (to render the display name). Adding an agent requires no TypeScript edits.

Steps

  1. Create the agent file — drop a new core/agents/<slug>-agent.md with the required frontmatter:
---
name: <slug>-agent
display_name: <Human-Readable Name>
examples:
  - example-knowledge-file-one.md
  - example-knowledge-file-two.md
description: >
  One-paragraph description of the agent's responsibilities and which stages it leads or supports.
disallowedTools: Task
tier: judgment
---

The name field must match the filename stem exactly. display_name is the human-facing label used by the statusline. examples lists suggested knowledge filenames documented in the agent→examples table — they're suggestions for the user, not loaded at runtime and not written to disk. tier (judgment | balanced | templated) is the authored dial the packager projects into each harness's model/effort keys — never author raw model:/effort: in core frontmatter (see Agent System).

  1. Verify the agent is discoveredbun -e "import { loadAgents } from 'core/tools/aidlc-lib.ts'; console.log(loadAgents().find(a => a.slug === '<slug>-agent'));" should print the new agent's metadata.

  2. Verify intent creation creates the space knowledge dir - bun core/tools/aidlc-utility.ts intent-create --scope poc --project-dir /tmp/agent-smoke should create the empty space-level aidlc/knowledge/ directory (a sibling of the space's intents/). Creation does not seed per-agent subdirectories or READMEs - the team creates aidlc/knowledge/<slug>-agent/ itself when it has content.

  3. Verify the statusline renders — seed a state file with Active Agent: <slug>-agent and invoke the statusline hook; the output should include the display name after the -- separator.

  4. Wire the agent into stages — a new agent that should lead or support stages is named in each stage's frontmatter, in the lead_agent / support_agents fields of the stage .md files under core/aidlc-common/stages/<phase>/. Then run aidlc engine graph compile (and compile --check as the drift guard) to regenerate tools/data/stage-graph.json from that frontmatter. Do not hand-edit stage-graph.json — it is the compiled artifact, and the next compile overwrites any manual change. This is separate from discovery — loadAgents() makes the agent visible; the stage frontmatter (compiled into the graph) makes it active.

What validates automatically

  • loadAgents() discovers any new .md file in .claude/agents/ on next invocation — no code edit.
  • The parser throws if name or display_name is missing, naming the file and the missing field.
  • Agents are returned alphabetically sorted by slug, so readdirSync order on any platform produces the same output.
  • Intent creation creates the empty space-level aidlc/knowledge/ directory (it does not seed per-agent subdirectories or READMEs).
  • Statusline rendering derives the display name from the same metadata source.
  • tests/unit/t61.test.ts asserts all five properties end-to-end against a fixture agent.

What does NOT validate automatically

  • Stage-graph participation. Stage frontmatter references agents by slug in its lead_agent / support_agents fields, and aidlc-graph.ts compile carries those into stage-graph.json. Adding a new agent without naming it in any stage's frontmatter means the agent exists but never runs. Stage-graph schema validation (core/tools/aidlc-stage-schema.ts) is wired in: aidlc-graph.ts compile validates every stage's frontmatter (and compile --check is the CI drift guard), and /aidlc --doctor re-runs the same validateStageFrontmatter plus a "Graph references" check that every lead_agent / support_agents slug resolves.
  • Knowledge file existence. examples is a list of suggested filenames documented in the agent→examples table — they're not created or validated. Users place the actual content in aidlc/knowledge/<agent>/ (the space-level knowledge dir).
  • Doc tables listing agents. The Phase Participation matrix at docs/reference/05-agent-system.md:119-131 and the agent→examples table at core/knowledge/aidlc-shared/knowledge-readme-template.md:16-29 are maintained by hand. Update them in the same PR that adds the agent (see Documentation Policy below).
  • .claude/agents/<new-agent>.md body content. Only the frontmatter is parsed. The body prose (Core Responsibilities, Collaboration, optional Memory Focus, Key Principles) is read by the agent itself when activated — write it to match the existing agent files' structure.

Documentation Policy

When adding, removing, or renaming files, directories, commands, or flags:

  1. Grep docs/ and README.md for stale references
  2. Update all references in the same commit

Submitting Changes

  1. Open a PR against main with a clear description of what changed and why
  2. Ensure L1 tests pass: bash tests/run-tests.sh
  3. For hook changes: run bash tests/run-tests.sh --unit
  4. For integration tests: run bash tests/run-tests.sh --integration (requires claude CLI tool)
  5. Update documentation if your changes affect files, commands, or flags (see Documentation Policy above)