b2c92db725
Encode the tracker-growth practice ratified in the aura field run: - fieldtest/SKILL.md — tracker filing defaults to bundling: one collective issue per fieldtest for related friction/spec_gap findings, consolidate-before-filing ahead of ANY new issue, per-issue filing only for real bugs (low-severity may wait in the collective issue). The fieldtester's per-finding report is unchanged; this is an orchestrator-side filing rule. - docs/pipeline.md — new § Harvest sweep: the recognised batch shape for draining settled single-issue backlog (issue bodies as spec source, sequential implementer batches of 2-3, one non-removable independent whole-diff review, audit close, compact fieldtest under its normal skip rules). Registered as the specify/planner exception under § Skip rules. - specify/SKILL.md, planner/SKILL.md — codify the sweep as a named alternative / skip case, per "skipping is codified per skill, not ad hoc". - docs/conventions.md — register the noun in § Vocabulary. closes #36
269 lines
14 KiB
Markdown
269 lines
14 KiB
Markdown
# 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.
|
|
|
|
Both directories are **git-ignored** — their contents are transient
|
|
working files, never committed (see § Lifecycle). The ignore is
|
|
**project-local**: each project commits a `docs/.gitignore` whose two
|
|
entries, `specs/` and `plans/`, are relative to `docs/` and so match
|
|
`docs/specs/` and `docs/plans/`. That `docs/.gitignore` is the one
|
|
committed thing — it travels with the repo; the spec and plan files it
|
|
covers never are. It is created once (whichever skill first writes a
|
|
working file — `specify`, or `planner` on a direct tidy dispatch —
|
|
creates it if absent) and committed like any other repo file, after
|
|
which both directories are invisible to git for every future cycle. A
|
|
new project sets this up as part of adopting the plugin
|
|
(`../templates/CLAUDE.md.fragment`).
|
|
|
|
## Lifecycle
|
|
|
|
`docs/specs/` and `docs/plans/` hold **only the active cycle's
|
|
artefacts** — they are working space, not an archive. A spec or plan is
|
|
valid for the cycle that produces it; its code shapes drift the moment
|
|
the code moves, so a stale one left lying around reads as a live API
|
|
reference and misleads the next agent that opens it.
|
|
|
|
The two directories are **git-ignored** — their contents are never
|
|
committed. A spec/plan is a working file: present on disk while its
|
|
cycle is live (readable across sessions, since the working tree
|
|
persists), and at **cycle close** — after `audit` is drift-clean — the
|
|
orchestrator **discards** it with a plain shell `rm`. There is nothing
|
|
to `git rm` (it was never tracked) and no deletion commit is produced;
|
|
the working tree is simply left without a stale artefact. This is the
|
|
same shell-delete-an-uncommitted-file mechanic `specify` already uses on
|
|
its grounding-`BLOCK` failure path.
|
|
|
|
A spec/plan is therefore **transient on disk**: present for its own
|
|
cycle, `rm`'d afterwards, and — never having been committed — leaving no
|
|
trace in git. It is **not recoverable, by design**. The durable record
|
|
of a past cycle's design intent is the **design ledger only** (where the
|
|
rationale is lifted during audit); the implementation is committed as
|
|
normal code.
|
|
|
|
**No durable artefact may cite a spec or plan** — not by number, not by
|
|
path. Code, tests, docs, and ledger entries outlive the spec/plan that
|
|
prompted them, so any reference to `docs/specs/…` or "spec NNNN" would
|
|
dangle the moment the cycle closes. Cite the **design-ledger contract**
|
|
instead (e.g. a `C`-id); it is the durable record the spec's rationale
|
|
was lifted into.
|
|
|
|
## Naming
|
|
|
|
Files are named `slug.md` — a short kebab-case identifier of the
|
|
cycle's topic (slug separator `-`). There is **no numeric prefix**:
|
|
because the directories are git-ignored, shell-`rm`'d at cycle close,
|
|
and cited by nothing (see § Lifecycle), they hold at most the active
|
|
cycle's handful of files, so a slug is already unique enough — the old
|
|
scan-for-the-next-free-number ritual bought nothing and is gone. A
|
|
`fieldtest`-produced spec takes a `fieldtest-` prefix
|
|
(`fieldtest-slug.md`) so it is recognisable in the working tree as the
|
|
next cycle's planning input rather than this cycle's own spec — it is
|
|
written after audit's cycle-close sweep and discarded by the next
|
|
cycle's sweep (see `../fieldtest/SKILL.md`).
|
|
|
|
**The file name is not the cycle number.** The **cycle number** that
|
|
appears in commit subjects (`feat(NNNN)`, `audit(NNNN)`) and in `git
|
|
log` cycle ranges is a distinct, monotonic identifier that must survive
|
|
spec/plan discard. Source it from the highest `NNNN` in the
|
|
`feat(NNNN)` / `audit(NNNN)` git-log subjects, plus one — never from a
|
|
file name (there is none) and never from a per-directory scan. Cycle
|
|
commits therefore MUST carry the zero-padded `(NNNN)` cycle number in
|
|
their subject.
|
|
|
|
## 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). |
|
|
| **harvest sweep** | Batch shape draining accumulated settled single-issue backlog in one pass (see `pipeline.md` § Harvest sweep). |
|
|
| **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.
|
|
|
|
**Schema-bound workflow stages are tiered down** (issue #31). The
|
|
anonymous script stages in `implement/workflows/*.js` have no agent
|
|
file and author no code, and a freshly-primed context costs ~40k+ real
|
|
tokens regardless of task size — so they do not take the full read:
|
|
verify-type stages (mini-verify, the standard end-verify, the
|
|
compiler-driven build/suite verify) read only the project-facts
|
|
build/test commands; tree/extraction stages (preflight, plan-index,
|
|
plan-extract[-all], snapshot) read nothing beyond their own
|
|
instructions. This extends the narrowed per-role standing reading the
|
|
named agents already practise (`tester` reads `git log -3`,
|
|
`plan-recon`/`grounding-check` `-5`, `fieldtester` `-8`, `docwriter`
|
|
`--oneline`); judgment roles keep the full convention.
|
|
|
|
## 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 — below the session anchor.** Nobody runs
|
|
`git reset` / `git revert` on user-ratified main history (or any
|
|
protected branch). main moves forward only via orchestrator commits; a
|
|
wrong agent diff is discarded — by the orchestrator, between
|
|
iterations — with `git checkout -- <paths>` / `git stash`, never by
|
|
rewinding ratified history. That discard idiom is the orchestrator's
|
|
alone: an agent running INSIDE a multi-task `implement` iteration
|
|
never checkouts/restores a file — nothing commits between tasks, so
|
|
it would silently destroy sibling tasks' uncommitted work; in-loop
|
|
recovery is forward-editing or `BLOCKED` (`implement/SKILL.md` Iron
|
|
Law, issue #23).
|
|
**One narrow `/boss` exception — the rollback sandbox:** inside an
|
|
autonomous run the orchestrator anchors on the HEAD it started
|
|
from (the last user-ratified state; under the worktree bullet below
|
|
that is the run branch's base, so a reset moves only the branch and
|
|
can never reach `main`) and MAY `git reset --hard` its
|
|
*own* commits *above* that anchor — autonomous, **unpushed** work only
|
|
— back toward (never below) the anchor when it has run into a dead end.
|
|
A pushed commit has left the sandbox and is forward-only (`git revert`).
|
|
See `../boss/SKILL.md` § Direction freedom.
|
|
- **Substantive work runs in a git worktree — merge is human-in-the-loop.**
|
|
Any substantive work stream targeting `main` — a feature, a bug fix, a
|
|
refactor; anything beyond a trivial mechanical edit — is isolated into
|
|
a git worktree on its own branch before work starts, in every mode:
|
|
autonomous (`/boss`, see `../boss/SKILL.md` § The run worktree) and
|
|
interactive alike. (Background sessions are worktree-isolated by the
|
|
harness already; this convention extends the same isolation to the
|
|
sessions the harness does not guard.) The worktree branches from the
|
|
current **local** HEAD — pin `worktree.baseRef: "head"` in settings;
|
|
the harness default `fresh` bases the branch on origin's tip, which
|
|
is routinely stale under this convention's no-autonomous-push
|
|
discipline. Name the branch after the
|
|
tracker issue where one exists (`issue-N-<slug>`); a live worktree
|
|
branch is then also the visible being-worked-on signal in
|
|
`git worktree list`. The branch reaches `main` only through a
|
|
**user-ratified merge**: the user reviews the result, then the
|
|
orchestrator merges — fast-forward preferred (rebase the branch onto
|
|
`main` first if `main` has moved) — pushes (the ratification covers
|
|
the push), and removes the worktree and
|
|
deletes the branch. No pull request is opened, and the merge is never
|
|
autonomous. `closes #N` markers consequently fire at merge-and-push
|
|
time, when the commits reach the default branch.
|
|
**One exception:** the skills meta-repo itself forbids worktree
|
|
development outright (its `CLAUDE.md`: the install symlinks resolve to
|
|
the primary clone, so worktree edits are silently ineffective) and
|
|
stays direct-on-`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). Work-start is signalled by
|
|
**assignee, not label**: the actor that begins work on an issue
|
|
assigns it to the agent tracker user (`claude`) — one write, no
|
|
removal; the assignee survives the close as provenance. There is no
|
|
`in-progress` label. The live worktree branch (`issue-N-<slug>`,
|
|
§ Git discipline) is the git-side counterpart. 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
|
|
records its fork decisions on the run's reference issue there, and an
|
|
ad-hoc `spec-skeptic` `scope-fork` dispatch reads single issues with
|
|
their comment threads from there.
|
|
|
|
Separately, `/boss` files **skill-system deficiencies** — faults in the
|
|
plugin itself, hit mid-run — against the **plugin's own** tracker (slug
|
|
derived from the plugin checkout's git remote), provenance carried by a
|
|
body block and never a new label. The skills meta-repo is not driven
|
|
through its own pipeline, so this tracker and a project's tracker never
|
|
coincide. See `../boss/SKILL.md` § Skill-system feedback.
|
|
|
|
## 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. There is no
|
|
per-project behavioural toggle: spec auto-sign is always on under
|
|
`/boss`.
|
|
|
|
## 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. |
|
|
| **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). |
|
|
|
|
### 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 as a target,
|
|
not verified fact, before it ships in a spec.
|