268ee705f4
The `spec-skeptic` `scope-fork` juror reads only the seeding issue plus the spec. On the legitimate `specify` direct-entry path — a fork settled in a long in-context design discussion — that resolution lives only in ephemeral chat the juror cannot replay. When the issue body lags the discussion (still lists the fork open), the juror correctly blocks, and a design BLOCK escalates without self-correction. The result: auto-sign was structurally almost unreachable for the in-context entry path. Close the blind spot by giving the juror an auditable source instead of weakening the gate. When `specify` enters in-context and a tracker issue still lists a now-resolved fork as open, the orchestrator posts a reconciliation comment recording each fork's resolution WITH provenance (a record of the user's decision, never a fresh orchestrator one) before writing the spec. The comment is persistent and audit-able — unlike a carrier digest — so it, not the orchestrator's confidence, is what the juror checks. Separation of powers keeps it honest: the orchestrator writes the comment, the adversarial juror enforces the provenance requirement. A bare `decision: X` with no provenance does not resolve the fork — the re-dispatched juror blocks on it. The escalation rule and the three-field carrier are untouched; only the juror's information changes. Mechanics: - specify Step 1.5: reconciliation-comment sub-step, provenance format, issue-less fallback (auto-sign -> human sign-off, no weak spec-note). - spec-skeptic: replace the "quoted in the dispatch" drift; juror reads the issue WITH comments via `issue_tracker.show_cmd`; provenance check. - new profile slot `issue_tracker.show_cmd` (must render comments); documented in schema + template. - issue skill: `tea issues <idx>` is body-only; `--comments` required (verified against tea 0.14.1 and Aura #55 — 180 vs 144 lines). - consistency: design.md out-of-scope, README, pipeline.md, boss skill.
291 lines
15 KiB
Markdown
291 lines
15 KiB
Markdown
# 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.
|