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 PowerShellirm https://claude.ai/install.ps1 | iex. Orbrew 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 installedaidlccommand. Install viacurl -fsSL https://bun.sh/install | bash; on Windows usepowershell -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 coreutilsthen add gnubin to PATH:export PATH="/opt/homebrew/opt/coreutils/libexec/gnubin:$PATH"(in~/.zshenvor~/.zshrc). - Bash -- Optional for the POSIX compatibility wrapper (
tests/run-tests.sh). The primary test runner isbun 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
- Fork and branch from
main(the integration branch and PR target), then runbun install --frozen-lockfile - Read the architecture -- reference/01-architecture.md explains the execution model, agent delegation, and hook system
- Understand the entry points -- the deterministic engine
core/tools/aidlc-orchestrate.ts(with exactly five subcommands:next,continue,report,park, andteam-board;continueis internal steering transport andteam-boardis the read-only Team Construction query) owns routing; the conductorharness/claude/skills/aidlc/SKILL.mdis a thin forwarding loop that acts on its directives. For the normative engine / directive / conductor / swarm contract see The Skill System - Make changes -- Edit the harness-neutral source in
core/(tools, stages, agents, hooks, rules, knowledge) or a harness surface inharness/<name>/(the orchestrator skill, settings). Then runbun scripts/package.tsto materialize the ignored localdist/anddist-release/roots. Never hand-edit or commit either root.package.ts --checkignores those on-disk trees, builds the complete projection set twice in independent temporary roots, and byte-compares the results. - Test -- Run
bun tests/run-tests.tsbefore submitting - 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:
- Set
projectRequirement,outputModes,visibility,networkPolicy, andmutationScope. - Choose
pinPolicydeliberately:activefor machine lifecycle/management,inspectfor active-binary diagnosis and repair, orpinnedfor project engine behavior. - 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. - Add route and policy assertions to
tests/unit/t230-dispatcher-routes.test.ts, including global-flag ordering and compiled/dev parity when applicable. - 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
- Create
core/scopes/aidlc-hotfix.md— the scope's identity. Frontmatter: name(required): the scope name; must equal the filename stem.depth(required):Minimal|Standard|Comprehensive.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.description(optional): one-line summary rendered in/aidlc --helpand in SKILL.md's compiled scope-table.testStrategy(optional): override test strategy independent of depth. Defaults to matching depth.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.runner(optional): settrueto include the scope in the default generated runner set.freeform_default(optional): settrueto 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 explicitAWS_AIDLC_DEFAULT_SCOPEvalues 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.
-
Tag the member stages — in each stage that should run under
hotfix(undercore/aidlc-common/stages/<phase>/), addhotfixto its frontmatterscopes:list. A stage you don't tag isSKIPfor the scope. The 3 initialization stages (workspace-scaffold,workspace-detection,state-init) must include it — they always run. -
Recompile + regenerate the scope-table —
aidlc engine graph compiletransposes thescopes:tags intotools/data/scope-grid.json. Thenaidlc engine gen scope-tableprints the canonical Markdown region for SKILL.md's compiled scope table. Keep the region between the<!-- BEGIN: compiled ... -->/<!-- END: compiled ... -->markers generated, then runaidlc engine graph compile --checkandaidlc engine gen scope-table --checkto confirm exit 0 (no drift). -
Verify the scope resolves -
bun core/tools/aidlc-utility.ts intent-create --scope hotfix --project-dir /tmp/scope-smokeshould succeed and produce a state file withScope: hotfix. -
Verify
doctoraccepts it as an env default —AWS_AIDLC_DEFAULT_SCOPE=hotfix aidlc doctorshould report the env var as valid. -
Verify keyword inference (if
keywordspopulated) —aidlc engine scope detect --from-text --input "urgent customer issue" --project-dir /tmp/scope-smokeshould return{"scope":"hotfix","source":"keyword","matches":["urgent"]}. -
Verify plan parity (optional but recommended) —
AIDLC_GRAPH_RESOLVE=1 aidlc engine graph resolve hotfix --stdoutemits the scope's plan; eyeball that the EXECUTE set matches what you tagged. -
Update scope-aware documentation —
docs/guide/05-scopes-and-depth.md(full scope reference, including the Stage-by-Scope Matrix — its cells are drift-guarded against the compiledscope-grid.jsonbytests/unit/t244-scope-matrix-doc-sync.test.ts),docs/guide/13-customization.md(valid values list and scope table), anddocs/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. -
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) ortests/e2e/t-tui-t50-bugfix-scope.serial.test.ts(tui scope run-through).
What validates automatically
validScopes().has("hotfix")returnstruethe moment the.claude/scopes/aidlc-hotfix.mdfile lands — every validation site uses this helper.- Error messages list the new scope in alphabetical order without any code changes.
/aidlc --doctortreatsAWS_AIDLC_DEFAULT_SCOPE=hotfixas valid.aidlc-utility scope-change --scope hotfixon an in-flight workflow accepts the new scope.- The transpose drift guard:
aidlc-graph compile --checkfails the build if a stage'sscopes:tag was edited without recompilingscope-grid.json. SKILL.md's compiled scope-table has its own--checkdrift guard (t67). - Keyword detection for freeform
/aidlc <text>invocations reads each scope'skeywordsfrom its.claude/scopes/*.mdfrontmatter. Custom scopes with their own NL triggers auto-detect as soon as thekeywordslist is populated (no SKILL.md change needed). Users can still pass--scope hotfixexplicitly 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 --doctorand a per-scope test are the guardrails. - Stage skipping semantics (
PHASE_SKIPPEDevents).tests/integration/t39.test.tshardcodes 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
-
Write the stage file - create
core/aidlc-common/stages/<phase>/<slug>.md. Frontmatter declaresslug,phase,execution/condition,lead_agentand anysupport_agents(by agent slug),mode(inline,subagent,pipeline, ormob;agent-teamis reserved and not yet implemented),consumes/produces(artifact vocabulary names),optional_producesfor artifacts the stage writes only conditionally per unit (exempt from per-unit coverage),requires_stage(ordering edges), thescopes:membership list, anysensors:to bind,for_eachif it iterates per Unit, and (on a per-unit stage) an optionalproduces_kindsmap 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. -
Recompile the graph —
aidlc engine graph compilereads the new frontmatter intotools/data/stage-graph.jsonand transposes thescopes:tags intotools/data/scope-grid.json. Runaidlc engine graph compile --checkto confirm exit 0 (no drift). Then refresh the generated SKILL.md mirrors withaidlc engine gen stage-tableandaidlc engine gen scope-table, and confirmaidlc engine gen stage-table --checkplusscope-table --checkboth exit 0. The stage is runnable immediately viaaidlc engine orchestrate next --stage <slug> --single. -
Regenerate the runners —
aidlc engine gen runnersemits a/aidlc-<slug>runner skill per runnable compiled stage, so your new stage gets its typeable command with no hand-authoring. Runaidlc engine gen runners --checkto confirm the on-disk runner set matches the compiled stage set (the drift guard; the bootstrap initialization stages are excluded by design). -
Verify the stage routes — drive
aidlc engine orchestrate nextover a workflow whose scope includes the stage, and confirm the engine emits arun-stagedirective naming your slug with the resolvedlead_agent, gate,consumes, andproduces. -
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 bytests/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. -
Add a test and refresh coverage — author a
t*.test.tsfor 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 withbun tests/gen-coverage-registry.tsand confirmbun tests/gen-coverage-registry.ts --checkis clean. The stage-runner drift guardtests/unit/t129-stage-runner-drift.test.tsasserts the generated runner set equals the compiled stage set, andtests/integration/t55-test-suite-drift.test.tssweeps 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 --checkfails the build if the on-diskstage-graph.jsondrifts from the frontmatter. - Generated stage table. SKILL.md's Stage Graph table is rendered from compiled
stage-graph.json;aidlc-utility stage-table --checkfails if the generated region drifts (t32). - Schema + references.
aidlc-graph.ts compilevalidates every stage's frontmatter viaaidlc-stage-schema.ts, and/aidlc --doctorre-runsvalidateStageFrontmatterplus a "Graph references" check that everylead_agent/support_agents/consumesslug resolves. - Runner parity.
aidlc-runner-gen.ts check(andt129) 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
- Create the agent file — drop a new
core/agents/<slug>-agent.mdwith 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).
-
Verify the agent is discovered —
bun -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. -
Verify intent creation creates the space knowledge dir -
bun core/tools/aidlc-utility.ts intent-create --scope poc --project-dir /tmp/agent-smokeshould create the empty space-levelaidlc/knowledge/directory (a sibling of the space'sintents/). Creation does not seed per-agent subdirectories or READMEs - the team createsaidlc/knowledge/<slug>-agent/itself when it has content. -
Verify the statusline renders — seed a state file with
Active Agent: <slug>-agentand invoke the statusline hook; the output should include the display name after the--separator. -
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_agentsfields of the stage.mdfiles undercore/aidlc-common/stages/<phase>/. Then runaidlc engine graph compile(andcompile --checkas the drift guard) to regeneratetools/data/stage-graph.jsonfrom that frontmatter. Do not hand-editstage-graph.json— it is the compiled artifact, and the nextcompileoverwrites 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.mdfile in.claude/agents/on next invocation — no code edit.- The parser throws if
nameordisplay_nameis missing, naming the file and the missing field. - Agents are returned alphabetically sorted by slug, so
readdirSyncorder 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.tsasserts 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_agentsfields, andaidlc-graph.ts compilecarries those intostage-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 compilevalidates every stage's frontmatter (andcompile --checkis the CI drift guard), and/aidlc --doctorre-runs the samevalidateStageFrontmatterplus a "Graph references" check that everylead_agent/support_agentsslug resolves. - Knowledge file existence.
examplesis a list of suggested filenames documented in the agent→examples table — they're not created or validated. Users place the actual content inaidlc/knowledge/<agent>/(the space-level knowledge dir). - Doc tables listing agents. The Phase Participation matrix at
docs/reference/05-agent-system.md:119-131and the agent→examples table atcore/knowledge/aidlc-shared/knowledge-readme-template.md:16-29are maintained by hand. Update them in the same PR that adds the agent (see Documentation Policy below). .claude/agents/<new-agent>.mdbody 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:
- Grep
docs/andREADME.mdfor stale references - Update all references in the same commit
Submitting Changes
- Open a PR against
mainwith a clear description of what changed and why - Ensure L1 tests pass:
bash tests/run-tests.sh - For hook changes: run
bash tests/run-tests.sh --unit - For integration tests: run
bash tests/run-tests.sh --integration(requiresclaudeCLI tool) - Update documentation if your changes affect files, commands, or flags (see Documentation Policy above)