refactor: drop dev-cycle-profile.yml for conventions + CLAUDE.md facts

The profile was never parsed — it was prose the skill bodies told the model to read, so most slots were dead, constant across every project, or fiction (the whole pipeline block, including the "tdd is opt-in" claim, was enforced by nothing).

Split it in two: constants become fixed conventions named directly by the skills (new docs/conventions.md), and the few genuinely per-project facts move to each project's CLAUDE.md under '## Skills plugin: project facts'. tdd/fieldtest/docwriter are now always available; the only behavioural toggle left is spec auto-sign.

Delete docs/profile-schema.md and templates/project-profile.yml; add docs/conventions.md and a project-facts section to templates/CLAUDE.md.fragment; rewrite all SKILL/agent prose and the pipeline/design/migration/README/INSTALL docs accordingly.
This commit is contained in:
2026-06-13 16:30:02 +02:00
parent 268ee705f4
commit 26e9630496
40 changed files with 752 additions and 894 deletions
+13 -10
View File
@@ -23,8 +23,10 @@ to prevent>
## Standing reading list
<list of always-binding documents — derived from the project
profile's `standing_reading.always` plus `standing_reading.by_role.<this-role>`>
<list of always-binding documents — the fixed always list (`CLAUDE.md`
plus `git log -10 --format=full`), the per-role standing reading the
project lists in its CLAUDE.md project facts, and the project's glossary
if it has one>
## Carrier contract
@@ -119,15 +121,16 @@ forcefully than "this role helps with X".
### Standing reading list
The plugin's skill body computes this from the project profile
(`standing_reading.always` + `standing_reading.by_role.<role>`)
and passes the resolved list to the agent via the carrier. The
agent's body says, prosaically: "Read everything in the standing
reading list before doing anything else."
The plugin's skill body composes this list and passes it to the agent
via the carrier. It is built from a fixed always list — `CLAUDE.md`
plus `git log -10 --format=full`, binding on every role — extended by
the per-role standing reading the project lists in its CLAUDE.md project
facts. The agent's body says, prosaically: "Read everything in the
standing reading list before doing anything else."
A set `paths.glossary` is implicitly part of `always`, so every role
reads the project glossary without a per-role entry (see
`profile-schema.md` § `paths`).
When the project's CLAUDE.md project facts name a glossary path, that
glossary is implicitly part of the always list, so every role reads the
project glossary without a per-role entry.
The agent file itself does not hardcode file paths.
+144
View File
@@ -0,0 +1,144 @@
# Conventions
The skills plugin used to read a per-project `dev-cycle-profile.yml`.
It no longer does. There was never a parser — the profile was prose
the skill bodies told the model to read, and almost every slot was
either dead, constant across all projects, or derivable. So the
plugin now splits cleanly in two:
- **Fixed conventions** (this file) — the things that were constant
across every project. They are not configurable; the skill and agent
bodies name them directly.
- **Per-project facts** — the handful of things that genuinely vary
per project (where the code lives, how to build and test it, the
tracker slug, …). These live as prose in each project's own
`CLAUDE.md` under a `## Skills plugin: project facts` heading. See
`../templates/CLAUDE.md.fragment` for the template, and the section
list at the bottom of this file.
## File layout
| Artefact | Location |
|----------|----------|
| Specs (from `specify`) | `docs/specs/` |
| Plans (from `planner`) | `docs/plans/` |
These directories are fixed. A project that keeps specs and plans
elsewhere is the rare exception and states the override in its
`CLAUDE.md` project facts.
## Naming
Counter-prefixed, per directory: `NNNN-slug.md`, 4-digit
zero-padded. The counter is per directory, assigned in creation
order, and stable for the life of the file. New files take the
next-higher number; deleted files retire their number (numbers are
not recycled). `brainstorm` / `specify` / `planner` scan the target
directory for the next free number before writing.
The slug separator is `-`.
## Vocabulary
The pipeline's nouns are fixed:
| Term | Meaning |
|------|---------|
| **cycle** | One round in the pipeline graph (`brainstorm → specify → planner → implement → audit → [fieldtest]`). NOT the top-level container. |
| **iteration** | A sub-unit of a cycle. |
| **milestone** | Tracker container spanning many cycles; closes only when complete AND functional (see `pipeline.md` § Milestone-close gate). |
| **contract** | A single design-ledger entry. |
When a project declares a glossary (in its CLAUDE.md project facts),
that glossary is the source of truth for domain nomenclature and
overrides these names where they collide (see `glossary-convention.md`).
## Standing reading
Every agent reads, at the start of every dispatch:
- the project's `CLAUDE.md`
- `git log -10 --format=full`
A project may add more — globally or per role — in its CLAUDE.md
project facts (`standing reading`). If the project declares a
glossary, that file is implicitly standing reading for every role
too.
## Git discipline
- **Only the orchestrator commits.** No skill agent runs `git commit`.
Agents write into the working tree as unstaged changes; the
orchestrator inspects, decides commit shape, and commits.
- **main HEAD is sacrosanct.** Nobody runs `git reset` / `git revert`
on main (or any other protected branch). main moves forward only via
orchestrator commits; a wrong agent diff is discarded with
`git checkout -- <paths>` / `git stash`, never by rewinding main.
These also appear in the universal-discipline fragment
(`../templates/CLAUDE.md.fragment`) that each project's CLAUDE.md
imports.
## Issue tracker
The tracker is **Gitea** and the commit close-marker is `closes #N`
(`refs #N` for non-closing work). The per-project repo slug and the
list/show commands live in the project's CLAUDE.md project facts
(see below) — the `boss` skill reads the forward queue from there,
and the `spec-skeptic` `scope-fork` juror reads single issues with
their comment threads from there.
## Pipeline
The phase set, the gates, and the conditional dispatch are **fixed**
and documented once in `pipeline.md`. There is no per-project pipeline
configuration. In particular: `brainstorm`, `specify`, `planner`,
`implement`, `audit`, `debug`, `tdd`, `fieldtest`, and `docwriter` are
always available. `tdd` is a standard entry path for test-specifiable
work — not an opt-in. `audit` is mandatory at cycle close.
`fieldtest` / `docwriter` are orchestrator-dispatched. The single
behavioural toggle is spec auto-sign under `/boss`, declared (when a
project wants it) in that project's CLAUDE.md project facts.
## Per-project facts (in each project's CLAUDE.md)
Under `## Skills plugin: project facts`, where applicable:
| Fact | Used by | Notes |
|------|---------|-------|
| **code roots** | architect, quality-reviewer, fieldtester | Directories reviewers walk. Required. |
| **build / test command** | implement, audit | Required. Exit 0 = success. |
| **lint command** | (quality) | Optional. |
| **doc-build command** | docwriter | Optional; prints warnings on stderr. |
| **regression scripts** | audit (bencher) | Optional list; non-zero exit = regress. |
| **architect sweeps** | audit (architect) | Optional list; non-zero exit = drift suspicion. |
| **spec-validation parsers** | specify, grounding-check | Optional; fence-label → `{ext, cmd}` table. `cmd` MUST contain `{file}`. Absent label → documented skip, never silent pass. |
| **design ledger** | architect, most agents | Optional path (e.g. `design/INDEX.md`). |
| **glossary** | every role | Optional path; implicitly standing reading. |
| **design contracts / models** | docwriter, specify | Optional dirs. Aspirational-source frontmatter marker recommended (see below). |
| **bench dir** | fieldtest, bencher | Optional path. |
| **public interface** | fieldtester | Optional list — the only surface the fieldtester may read; everything else (code roots, bench) is forbidden to it. |
| **fieldtest examples** | fieldtester | Optional path where fixtures are written. |
| **by-role standing reading** | named agent | Optional; extra files/commands a specific role reads. |
| **issue tracker** | boss, spec-skeptic | Repo slug + list command + show command (the latter MUST render an issue WITH its comments). |
| **spec auto-sign** | boss, specify | Optional; `enabled` lets `/boss` sign a spec in the user's place through the auto-sign gate (default: human signature). |
### Aspirational-source marker (recommendation)
Files under a project's design-models / RFCs / proposals directory
commonly carry aspirational code — constructs written before the
surface that parses them exists. To let a later `specify` tell
aspirational content from validated contract, give each such file a
frontmatter marker:
```yaml
---
status: aspirational
validated-against: <commit-sha | "no validation">
---
```
When the marker is absent the signal is simply absent — `specify`
degrades to treating the content as unmarked, never hard-failing.
Content lifted from an aspirational source is flagged and must clear
the parse-every-block gate before it ships in a spec.
+50 -43
View File
@@ -1,20 +1,28 @@
# Design
## Why split plugin from profile
## Why split plugin from project
The skills system originally evolved inside the AILang project,
where it grew organically against AILang's specific paths,
build commands, vocabulary, and contracts. Lifting it into a
plugin requires a clean separation between what is universal
(belongs in the plugin) and what is project-specific (belongs
in a per-project profile).
in the project's `CLAUDE.md`).
The litmus test: would a sentence in a SKILL or agent body
still make sense in a Python web project, a Rust CLI, and a
TypeScript library? If yes, plugin. If it mentions `cargo`,
`crates/`, `docs/design/INDEX.md`, `Form A`, or any project-specific
identifier, it goes to the profile (as a slot) or to the
project's `CLAUDE.md` (as sittenkodex).
identifier, it goes to the project's `CLAUDE.md` — either as a
project fact (the few mechanical facts the skills consume) or as
sittenkodex (domain contracts, anti-patterns).
There is no separate profile file. An earlier design had a
per-project `dev-cycle-profile.yml`, but it was never parsed — it
was prose the skill bodies told the model to read, and almost every
slot was constant across projects, dead, or derivable. So the
constant parts became fixed conventions (`conventions.md`) and the
genuinely-varying parts moved into each project's `CLAUDE.md`.
## Plugin layer (universal)
@@ -54,44 +62,42 @@ The plugin owns:
- **Output budget discipline** — agents have word budgets on
their reports.
## Profile layer (project-specific)
## Fixed conventions (universal)
The profile fills slots that the plugin's prose references
generically. Concretely:
The constants that used to be configurable but were the same in
every project are now plugin conventions, named directly in skill
and agent bodies and documented once in `conventions.md`:
spec dir `docs/specs`, plan dir `docs/plans`, 4-digit per-directory
naming, the vocabulary cycle / iteration / milestone / contract,
standing reading (`CLAUDE.md` + `git log -10`), git discipline
(only-orchestrator commits, main sacrosanct), Gitea + `closes #N`,
and the whole pipeline graph (see `pipeline.md`).
- **Paths**: `spec_dir`, `plan_dir`, `design_ledger`,
`design_contracts`, `design_models`, `code_roots`, `bench_dir`.
- **Commands**: `build`, `test`, `lint`, `regression` (list).
- **Vocabulary**: `cycle`, `subcycle`, `ledger_entry`.
- **Naming**: `counter_dirs`, `policy` (`stable_per_directory_4digit`
or `date_prefix` or `flat`).
- **Standing reading**: `always` (a list), `by_role` (a map
from role to list).
- **Git**: `main_sacrosanct` (bool, default true),
`only_orchestrator_commits` (bool, default true),
`issue_tracker.kind` (`gitea` / `github` / `linear` / `none`),
`issue_tracker.close_marker` (e.g. `"closes #N"`).
- **Pipeline customisations**: per-phase `mandatory_before`,
`mandatory_at`, `boss_only`, `when` (a condition tag).
## Project facts (project-specific)
The full schema lives in `profile-schema.md`. The functional
starting template is `../templates/project-profile.yml`.
The handful of facts that genuinely vary per project live in the
project's `CLAUDE.md` under `## Skills plugin: project facts`:
code roots, build / test / lint / doc-build commands, regression
scripts, architect sweeps, design-ledger / glossary / contracts /
models / bench / public-interface / fieldtest-examples paths,
spec-validation parsers, by-role standing reading, the issue-tracker
repo slug and commands, and spec auto-sign. The template is in
`../templates/CLAUDE.md.fragment`; the per-fact reference is the
table in `conventions.md`.
## Resolution model
The plugin uses **profile-driven prompts**, not template
rendering. Each SKILL.md and agent file is generic prose that
references the profile prosaically:
The plugin uses **convention-and-fact prompts**, not template
rendering and not a config parser. Each SKILL.md and agent file is
generic prose that either names a fixed convention directly or
points at a project fact:
> Write the spec to the directory configured under `paths.spec_dir`
> in the project profile. Use the naming policy configured under
> `naming.policy`.
> Write the spec to `docs/specs`. Use the project's build command
> (its CLAUDE.md project facts).
When Claude Code loads the skill, the project profile is in
context (the skill body explicitly instructs the model to read
it first). The model performs the substitution at read-time.
This avoids a build step and keeps a single source of truth in
the repo.
The project's `CLAUDE.md` is always in context (it is standing
reading #1), so the model resolves the facts at read-time. This
avoids a build step and keeps a single source of truth in the repo.
## Sittenkodex split
@@ -104,18 +110,19 @@ which are conditions for the plugin's own correctness.
The relationship:
- **Plugin** (this repo): mechanics, universal discipline
- **Profile** (per project): slots — paths, commands,
vocabulary, naming, git conventions, pipeline customisations
- **Project CLAUDE.md**: sittenkodex — domain-specific anti-
patterns and acceptance criteria
- **Plugin** (this repo): mechanics, universal discipline, fixed
conventions
- **Project CLAUDE.md**: project facts — the few mechanical facts
the skills consume (code roots, build/test, tracker slug, …) —
plus sittenkodex (domain-specific anti-patterns and acceptance
criteria)
## What's out of scope for this plugin
- **Issue-tracker integration**: the plugin can read the
profile's `issue_tracker.kind`, `issue_tracker.list_cmd`, and
`issue_tracker.show_cmd` and invoke the configured listing /
single-issue commands, and `specify` may post a reconciliation
- **Issue-tracker integration**: the plugin reads the project's
issue-tracker commands (the repo slug, list command, and
single-issue-with-comments command, all in its CLAUDE.md project
facts) and invokes them, and `specify` may post a reconciliation
comment via the tracker's comment command — but the plugin does
not directly call Gitea / GitHub / Linear APIs. Every read and
write goes through the configured shell command, so the plugin
+9 -10
View File
@@ -9,18 +9,17 @@ this convention.
## Where it lives
A project opts in by setting `paths.glossary` in its
`.claude/dev-cycle-profile.yml` (see `profile-schema.md` § `paths`).
When the slot is set, the file it names is standing reading for every
role — no separate `standing_reading.always` entry is required. When
the slot is unset, the whole feature is a documented no-op.
A project opts in by naming a glossary path in its CLAUDE.md project
facts (see `conventions.md`). When it is named, the file it points to
is standing reading for every role — no separate standing-reading entry
is required. When the project names none, the whole feature is a
documented no-op.
A set glossary is the source of truth for the project's nomenclature.
A glossary is the source of truth for the project's nomenclature.
Where any other document names a concept differently — including the
example renamings in `profile-schema.md` § `vocabulary` — the
glossary's canonical entry, and its **Avoid** list, win. A
`vocabulary.*` slot only sets which term the glossary then pins as
canonical; it does not override the glossary.
fixed vocabulary in `conventions.md` (cycle / iteration / milestone /
contract) — the glossary's canonical entry, and its **Avoid** list,
win.
## Format
+9 -4
View File
@@ -36,9 +36,12 @@ the structural binding.
`docs/design/INDEX.md`, `crates/`, `bench/`).
2. Strip project-specific commands (`cargo build`,
`bench/check.py`).
3. Replace literals with profile-slot references in prose.
3. Replace literals with fixed conventions named directly (see
`conventions.md`) or, where they vary per project, a reference to
the project's `CLAUDE.md` project facts.
4. Strip project vocabulary (`AILang`, `Form A`, `.ail.json`,
`Boss`); use the profile's vocabulary slots.
`Boss`); use the fixed vocabulary (cycle / iteration / milestone /
contract).
5. Strip project-specific contracts (honesty-rule,
feature-acceptance). These belong in the project's own
`CLAUDE.md`, not the plugin.
@@ -51,8 +54,10 @@ the structural binding.
1. Drop the `ailang-` prefix from the `name:` frontmatter
field. The skill path is the disambiguator.
2. Replace hardcoded standing-reading paths
(`docs/design/INDEX.md`, etc.) with a reference to the profile's
`standing_reading` section.
(`docs/design/INDEX.md`, etc.) with the fixed standing reading
(`CLAUDE.md` + `git log -10`) plus, for role-specific files, a
reference to the per-role standing reading in the project's
`CLAUDE.md` project facts.
3. Replace project-specific Iron Law clauses with the universal
discipline constants; project-specific clauses go to the
project's own `CLAUDE.md`.
+21 -19
View File
@@ -98,15 +98,16 @@ Hard-gate before plan — the spec-production core and the carrier of the
"no plan without an approved spec" invariant. Takes a settled design
(directly from sources, or a ratified design handed over by
`brainstorm`), applies the feature-acceptance criterion, writes the
spec to the configured `spec_dir`, runs the parse-every-block and
spec to `docs/specs`, runs the parse-every-block and
`grounding-check` gates, and takes user sign-off — with review but no
interview. Bounces to `brainstorm` the moment the sources do not
resolve a load-bearing design decision. A core node, not opt-in
(unlike `tdd`).
resolve a load-bearing design decision. A core node — the
spec-production gate before `planner` on every design path.
The sign-off is the user's by default, including under `/boss`. The
one exception is the opt-in `pipeline.boss.spec_auto_sign` slot: with
it on, a `/boss` run may sign a spec in the user's place — but only
one exception is spec auto-sign (a project that enables it in its
CLAUDE.md project facts): with it on, a `/boss` run may sign a spec in
the user's place — but only
when every objective gate is green AND a unanimous five-lens
`spec-skeptic` panel passes; the orchestrator's own confidence never
signs. A `BLOCK` is never signed over: an editorial one (`criterion` /
@@ -123,7 +124,7 @@ resolution instead of blocking on the stale body. See
### planner
Hard-gate before implement. Produces a placeholder-free,
bite-sized implementation plan in the configured `plan_dir`
bite-sized implementation plan in `docs/plans`
that the implement skill can execute task-by-task. Dispatches
the plan-recon agent for read-only file-structure mapping.
@@ -150,7 +151,7 @@ the GREEN side to the implement skill in mini mode.
### tdd
Opt-in alternative to the `brainstorm → specify → planner` design entry,
A standard alternative entry, alongside `brainstorm → specify → planner`,
for work whose desired behaviour is test-specifiable — expressible
as one failing test. RED-first: the `tdd-author` agent turns a
description or issue into a single minimal, autonomous RED
@@ -213,9 +214,9 @@ documents what the skill skips and under what conditions:
- `implement` is the iteration body; not skippable.
- `audit` is mandatory at cycle close.
- `debug` is mandatory RED-first for any observable bug.
- `tdd` is an opt-in alternative entry to `brainstorm` for
- `tdd` is a standard alternative entry to `brainstorm` for
test-specifiable work; it bounces back to `brainstorm` on a
design fork. A profile that omits the `tdd` phase disables it.
design fork. Always available — not opt-in.
- `fieldtest` and `docwriter` are optional and orchestrator-
dispatched.
@@ -225,14 +226,15 @@ commit body — never as undocumented practice.
## Pipeline configuration
The phase set, gating, and conditional dispatch are configured
in the project profile under `pipeline:`. A project that does
not want `fieldtest` simply omits the key. A project that wants
a different gate set (e.g. `planner` without a `brainstorm`
gate, for trivial bug-fix iterations) configures it there.
There is none. The phase set, the gates, and the conditional
dispatch shown above are fixed — the same for every project. All
phases (`brainstorm`, `specify`, `planner`, `implement`, `audit`,
`debug`, `tdd`, `fieldtest`, `docwriter`) are always available; which
ones run on a given iteration is the orchestrator's judgement per the
skip rules above, not a per-project setting. The only behavioural
toggle is spec auto-sign under `/boss`, declared in a project's
CLAUDE.md project facts. See `conventions.md`.
See `profile-schema.md` for the syntax.
If the profile sets `paths.glossary`, that file is standing reading
for every role — the canonical-nomenclature source every skill and
agent consults (see `glossary-convention.md`). Unset, it is a no-op.
If a project declares a glossary in its CLAUDE.md project facts, that
file is standing reading for every role — the canonical-nomenclature
source every skill and agent consults (see `glossary-convention.md`).
-290
View File
@@ -1,290 +0,0 @@
# Profile schema
Location: `<project-root>/.claude/dev-cycle-profile.yml`
Encoding: YAML. Each top-level key is a section. Keys are
lowercase snake_case. Lists are YAML sequences.
## `paths`
| Key | Type | Default | Description |
|---------------------|--------|------------------------|-------------|
| `spec_dir` | string | `docs/specs` | Where the specify skill writes specs. |
| `plan_dir` | string | `docs/plans` | Where the planner skill writes plans. |
| `glossary` | string | (unset) | Canonical-nomenclature file (optional). If set, it is standing reading for every role — no separate `standing_reading.always` entry is needed; unset is a documented no-op. See `glossary-convention.md`. |
| `design_ledger` | string | `docs/design/INDEX.md` | Canonical specification index (optional — projects without a design ledger can omit). |
| `design_contracts` | string | `design/contracts` | Directory of prose-authoritative contracts (optional). |
| `design_models` | string | `design/models` | Directory of onboarding whitepapers (optional). |
| `code_roots` | list | `[src]` | Code directories the architect / quality reviewer walk. |
| `bench_dir` | string | `bench` | Where regression harnesses live (optional). |
| `public_interface` | list | `[README.md, docs]` | Directories and files the `fieldtester` may read — the project's outward-facing surface (READMEs, design ledger, examples, public API docs). Everything else (especially `code_roots` and `bench_dir`) is forbidden to the fieldtester. |
| `fieldtest_examples`| string | `examples/fieldtest` | Where the `fieldtester` agent writes its fixtures. |
Omitted optional keys signal that the feature is unused in this
project; skills that depend on them either short-circuit or
skip the corresponding step.
### Aspirational-source marker (recommendation)
Files under `design_models` (or an equivalent `RFCs` /
`proposals` directory) commonly carry aspirational code —
constructs written before the surface that would parse them
exists. To let a later specify tell aspirational content from
validated contract, projects are encouraged (not required) to
give each such file a frontmatter marker:
```yaml
---
status: aspirational
validated-against: <commit-sha | "no validation">
---
```
`status: aspirational` says "the code here is a target, not a
verified fact"; `validated-against` records the last commit at
which someone actually ran the code through the live tool (or
`"no validation"`). A design ledger (`design_ledger`) is likewise
encouraged to distinguish "model" rows from "contract" rows so a
reading agent can mechanically tell which carry verified
behaviour.
When a file lacks the marker the signal is simply absent — the
specify skill degrades to treating its content as unmarked, never
hard-failing. The marker is consumed by the specify skill (see
its Step 1 and Step 4): content lifted from an aspirational source
is flagged and must clear the Step-4 parse-every-block gate before
it ships in a spec.
## `naming`
| Key | Type | Default | Description |
|--------------------|--------|----------------------------------|-------------|
| `counter_dirs` | list | `[docs/specs, docs/plans, design/contracts, design/models]` | Directories that use the counter-prefix policy. |
| `policy` | enum | `stable_per_directory_4digit` | One of `stable_per_directory_4digit`, `date_prefix`, `flat`. |
| `slug_separator` | string | `-` | Separator inside the slug. |
`stable_per_directory_4digit` means each listed directory has a
per-directory counter, 4-digit zero-padded, assigned in
creation order, stable for the life of the file. New files
take the next-higher number; deleted files retire their number.
`date_prefix` uses `YYYY-MM-DD-slug.md`.
`flat` uses `slug.md`.
## `commands`
| Key | Type | Default | Description |
|----------------|--------|----------------|-------------|
| `build` | string | (required) | Build command — exit 0 means success. |
| `test` | string | (required) | Test command — exit 0 means success. |
| `lint` | string | (optional) | Lint command — exit 0 means success. |
| `doc_build` | string | (optional) | Documentation-build command used by the `docwriter` skill. Should print warnings on stderr so the agent can enumerate them (e.g. `cargo doc --no-deps 2>&1`). Omit if the project has no API docs. |
| `regression` | list | `[]` | Regression scripts run by the audit skill. Each entry is a shell command; non-zero exit is a regress. |
| `architect_sweeps` | list | `[]` | Project-specific architect sweep commands run by the `architect` agent in addition to its universal checks. Each entry is a shell command; non-zero exit means at least one sweep matched and the matches are drift-suspicions to verify. Optional. |
## `spec_validation`
Optional. A registry mapping each markdown fence label to the tool
that validates a spec code block of that kind. The specify
parse-gate and the grounding-check code-block pass run these
parsers so that spec code blocks are treated as hypotheses to
verify, not as authoritative truth.
```yaml
spec_validation:
parsers:
ail:
ext: ".ail"
cmd: "ail parse {file}"
ail-json:
ext: ".ail.json"
cmd: "ail check {file}"
ll:
ext: ".ll"
cmd: "llvm-as {file} -o /dev/null"
```
The key of each `parsers` entry is the fence info-string of a spec
code block (the token immediately after the opening ` ``` `). Only
blocks whose label has an entry are validated; a block whose label
is absent from the map is skipped and the skip is documented ("no
parser for fence label X") — never a silent pass.
| Key | Type | Description |
|-------|--------|-------------|
| `ext` | string | Extension (including the leading dot) the harness gives the temp file it writes the block into, so tools that key off extension — `.ail` vs `.ail.json` — see the right one. |
| `cmd` | string | Validation command. MUST contain the `{file}` placeholder, which is substituted with the temp file's path. Exit 0 means a clean parse; any non-zero exit is a parse failure the consuming skill turns into a BLOCK. |
A malformed entry — `cmd` missing the `{file}` placeholder, or
either `ext` or `cmd` absent — is a profile error the consuming
skill surfaces, not a silent skip; the gate fails closed.
Omitting the whole `spec_validation` section disables the
block-validation gates: the consuming skills short-circuit, exactly
as with other omitted optional features.
## `vocabulary`
| Key | Type | Default | Description |
|----------------|--------|----------------|-------------|
| `cycle` | string | `cycle` | One round in the pipeline graph (NOT the top-level container). Examples: `cycle`, `release`, `epic`. |
| `subcycle` | string | `iteration` | A sub-unit of a cycle. Examples: `iteration`, `sprint`, `story`. |
| `milestone` | string | `milestone` | Tracker container spanning many cycles; closes only when complete AND functional (see `pipeline.md` § Milestone-close gate). Examples: `milestone`, `epic`, `release`. |
| `ledger_entry` | string | `contract` | What a single design-ledger entry is called. Examples: `contract`, `RFC`, `ADR`. |
Skills use these names in their generated artefacts and prose.
Picking accurate vocabulary keeps prose readable; the underlying
mechanics are identical regardless of name.
The renamings shown as examples above illustrate the slot only; they
are not nomenclature for any particular project. When a project sets
`paths.glossary`, that glossary is the source of truth for its
nomenclature and overrides these examples where they collide — a word
offered here may sit under **Avoid** in a given project's glossary
(see `glossary-convention.md`).
## `standing_reading`
| Key | Type | Default | Description |
|----------------|--------|----------------|-------------|
| `always` | list | `[CLAUDE.md]` | Files every agent reads at start of every dispatch. |
| `by_role` | map | `{}` | Map from role name to list of additional files. |
Role names match agent slugs: `architect`, `bencher`, `debugger`,
`implementer`, `tester`, `fieldtester`, `docwriter`,
`grounding-check`, `plan-recon`, `spec-reviewer`, `quality-reviewer`.
Entries may be shell commands as well as file paths — they are
read as opaque strings the agent should fetch / execute, e.g.
`"git log -10 --format=full"`.
A set `paths.glossary` is implicitly appended to every role's
`always` list — it does not need its own entry here. The slot's
authoritative semantics live at the `paths` row above.
## `git`
| Key | Type | Default | Description |
|------------------------------|------|---------|-------------|
| `main_sacrosanct` | bool | `true` | If true, no actor may reset or revert main. |
| `only_orchestrator_commits` | bool | `true` | If true, no agent commits; the orchestrator commits. |
| `issue_tracker.kind` | enum | `none` | One of `gitea`, `github`, `linear`, `none`. |
| `issue_tracker.close_marker` | string | `"closes #N"` | Marker the orchestrator includes in commit bodies to auto-close issues. |
| `issue_tracker.url` | string | (empty) | Human-browsable URL of the issue list — surfaced in notifications and cross-references. |
| `issue_tracker.list_cmd` | string | (empty) | Shell command that lists open issues. Used by the `boss` skill to read the forward queue. Examples: `tea issues ls --repo X/Y --state open`, `gh issue list --repo X/Y --state open`. |
| `issue_tracker.show_cmd` | string | (empty) | Shell command that renders **one** issue **with its comment thread**; the orchestrator and the `spec-skeptic` `scope-fork` juror append the issue index as the final argument (e.g. `tea issues --comments``tea issues --comments 55`). MUST include comments — a `specify` reconciliation comment (see `specify/SKILL.md` Step 1.5) is invisible to the juror otherwise. Examples: `tea issues --comments`, `gh issue view --comments`. If empty, the juror reads only the issue body and a fork resolved in-context but not echoed into the body cannot be ratified — auto-sign falls back to the human sign-off. |
| `protected_branches` | list | `[main]` | Branches that are sacrosanct in the same sense as main. |
## `notifications`
| Key | Type | Default | Description |
|-----------|--------|---------|-------------|
| `command` | string | (empty) | Shell command the `boss` skill invokes on done-state and bounce-back. Receives the message text as a single argument. Example: `"~/.claude/notify.sh"`. If empty, the orchestrator falls back to printing the notification in chat. |
## `pipeline`
Per-phase configuration. Each phase has its own sub-map.
```yaml
pipeline:
brainstorm: {} # optional discovery front-end; no hard gate of its own
specify:
gates: [planner] # core node — planner cannot start until the spec is approved
planner:
gates: [implement]
implement: {} # standard
audit:
mandatory_at: cycle_close # auto-fires at end of each cycle
fieldtest:
boss_only: true # only orchestrator dispatches
when: surface_touch # condition tag (orchestrator judgement)
milestone_fieldtest:
boss_only: true
when: surface_touch # end-to-end proof of the milestone's promise
gates_close: milestone # its green roll-up is the functional leg of the milestone-close gate
docwriter:
boss_only: true
when: api_stable_across_n_cycles
debug:
trigger: bug # observable misbehaviour
red_first: true # RED test before any fix
# specify above is a CORE node (always present); tdd below is opt-in.
tdd: # opt-in: omit the key to disable the entry path
trigger: test_specifiable_feature # behaviour expressible as one failing test
red_first: true # RED executable-spec before any implementation
alt_to: brainstorm # alternative design entry; bounces back on a design fork
boss:
user_invoked: true # autonomous-orchestrator mode, /boss
spec_auto_sign: false # opt-in: let /boss sign a spec in the user's place (default off)
```
Phases not listed are disabled for the project. A project that
does not want a `fieldtest` phase simply omits the key. `tdd` is
opt-in the same way.
`boss.spec_auto_sign` is an opt-in slot, default off (a missing key
reads as `false`). With it off — the conservative default — a
`specify` dispatch in a `/boss` session always pauses at its Step-6
user-review gate for the user's signature, exactly as before. With it
**on**, the orchestrator may sign a spec in the user's place, but only
through `specify`'s auto-sign gate: every objective gate green
(precondition, parse, a `grounding-check` `PASS` with no human
override) AND a unanimous five-lens `spec-skeptic` panel. A `BLOCK` is
never signed over: an *editorial* one (`criterion` / `ambiguity` /
`plan-readiness`) the orchestrator repairs in a bounded loop (≤ 2
rounds, re-running the objective gates and re-dispatching all five
lenses each round), while a *design* one (`scope-fork` / `grounding`),
an `INFRA_ERROR`, any objective gate not green, or an exhausted budget
falls back to the human sign-off pause. Model self-confidence alone
never signs — the gate is built specifically not to rely on it. On a
clean sign the
orchestrator commits the spec (subject carries `(boss-signed)`), sends
the mandatory informational-with-veto notify, and continues to
`planner` without stopping. See `../specify/SKILL.md` Step 6 (gate
owner), `../specify/agents/spec-skeptic.md` (the juror), and
`../boss/SKILL.md` §"Spec auto-sign" (notify + veto contract). `specify`, by contrast, is a **core** node — it
is the spec-production gate before `planner` on every design path,
reachable directly from settled sources or via the optional
`brainstorm` discovery stage. `tdd` opt-in only adds the
test-specifiable bypass; with `tdd` omitted, the design entry paths
are `brainstorm → specify → planner` and `specify → planner`.
## Example: minimal profile
```yaml
paths:
spec_dir: docs/specs
plan_dir: docs/plans
code_roots: [src]
commands:
build: cargo build
test: cargo test
vocabulary:
cycle: cycle
subcycle: iteration
standing_reading:
always:
- CLAUDE.md
- "git log -10 --format=full"
git:
issue_tracker:
kind: github
close_marker: "closes #N"
pipeline:
brainstorm: {} # optional discovery; no hard gate
specify: { gates: [planner] }
planner: { gates: [implement] }
implement: {}
audit: { mandatory_at: cycle_close }
debug: { trigger: bug, red_first: true }
```
This minimal profile enables five phases, no fieldtest, no
docwriter, no design-ledger. Good starting point for a small
project.