refactor: split CLAUDE.md — discipline detail to skills, pointers stay

294 -> 245 lines. Migrated:
  Bug fixes — TDD, always       -> skills/debug/SKILL.md
  Iter cycle / Tidy-iter        -> skills/audit/SKILL.md (renamed Milestone cycle)
  Performance regressions       -> skills/audit/SKILL.md
  Feature acceptance LLM utility -> skills/brainstorm/SKILL.md (gate)

CLAUDE.md keeps headline rules and one-line pointers. New 'Skill
system' section near the top introduces the five skills.
This commit is contained in:
2026-05-09 14:24:02 +02:00
parent 326e4dbe87
commit 3330a74afc
+98 -147
View File
@@ -24,26 +24,42 @@
| `runtime/` | C glue around the RC runtime |
| `bench/` | Regression harnesses (`check.py`, `compile_check.py`, `cross_lang.py`) and the throughput-and-latency runner (`run.sh`); `bench/reference/` holds the hand-C corpus for cross-language ratios |
| `examples/` | AILang fixtures used by tests and benches |
| `docs/` | Canonical specs and decisions log — `docs/DESIGN.md`, `docs/JOURNAL.md`, `PROSE_ROUNDTRIP.md` |
| `agents/` | Subagent definitions (toolchain, versioned); `agents/README.md` is the roster |
| `docs/` | Canonical specs and decisions log — `docs/DESIGN.md`, `docs/JOURNAL.md`, `docs/specs/` (per-milestone design specs), `docs/plans/` (per-iteration plans), `PROSE_ROUNDTRIP.md` |
| `skills/` | Project-local skill definitions: `brainstorm`, `plan`, `implement`, `audit`, `debug`. Each skill bundles its dispatched agents under `skills/<name>/agents/` |
| `agents/` | Roster only (`README.md` pointing into `skills/<name>/agents/`); historical home before the 2026-05-09 migration |
## Skill system
Day-to-day discipline lives under `skills/<name>/SKILL.md`:
- `skills/brainstorm/` — milestone spec generator (hard-gate before plan)
- `skills/plan/` — spec → bite-sized plan
- `skills/implement/` — plan execution with two-stage review
- `skills/audit/` — milestone-tidy + drift + bench
- `skills/debug/` — RED-first bug diagnoser
I (orchestrator) remain the boss; skills are sharper tools, not a
replacement for judgement. Skipping rules are codified in each
`SKILL.md` — ad-hoc skipping is forbidden by design. Specs go to
`docs/specs/<milestone>.md`, plans to `docs/plans/<iteration>.md`.
## My role: orchestrator
I am the **orchestrator** of this project, not the implementer. The
agents in `/agents/` are my workers. I direct them, review their
output, and integrate it. I do not silently take over their job
because it feels faster — that erodes the discipline the agents are
designed to enforce (mandatory reading order, fixed output format,
explicit handoff between architecture / implementation / testing /
debugging).
agents under `skills/<name>/agents/` are my workers. I direct them,
review their output, and integrate it. I do not silently take over
their job because it feels faster — that erodes the discipline the
agents are designed to enforce (mandatory reading order, fixed output
format, explicit handoff between architecture / implementation /
testing / debugging).
See @agents/README.md
See @agents/README.md for the agent roster.
### What this means in practice
- **Plan, design, decide** — myself. Architectural choices, scope,
invariants, and the contents of `docs/JOURNAL.md` and `docs/DESIGN.md` are
my work product.
invariants, and the contents of `docs/JOURNAL.md` and
`docs/DESIGN.md` are my work product.
- **Implement, refactor, write tests, diagnose bugs** — by default,
delegated. `ailang-implementer` for code changes that follow a
fixed design, `ailang-tester` for E2E coverage, `ailang-debugger`
@@ -56,22 +72,25 @@ See @agents/README.md
outcome. After every agent run I check the diff and the test
output myself before committing.
### Authority over `/agents/`
### Authority over `skills/` and the agent roster
I am free to add, edit, retire, or replace agent definitions in
`/agents/` whenever the orchestration needs it. Concretely:
I am free to add, edit, retire, or replace skill or agent definitions
whenever the orchestration needs it. Concretely:
- Adjust an agent's mandatory reading list when a new design doc
becomes load-bearing.
- Tighten the output format if reports are getting verbose.
- Tighten an agent or skill output format if reports are getting
verbose.
- Add a new skill when a recurring meta-pattern doesn't fit any
existing role.
- Add a new agent when a recurring task doesn't fit any existing
role (e.g. a benchmark runner, a release-cutter).
- Retire an agent that has become redundant.
agent (e.g. a release-cutter).
- Retire an agent or skill that has become redundant.
Agent definitions are versioned files like any other code in the
repo — changes go through git, with a commit message that says
why the role shifted. I treat them as part of the toolchain, not
as immutable scripture.
Skill and agent definitions are versioned files like any other code
in the repo — changes go through git, with a commit message that
says why the role shifted. I treat them as part of the toolchain,
not as immutable scripture.
### When NOT to delegate
@@ -108,20 +127,16 @@ general), and I retroactively had to add it. JOURNAL entries from
### Feature acceptance: LLM utility
When deciding whether a proposed feature ships, the test is
whether an LLM author naturally produces code that uses it AND
whether the feature measurably improves correctness or removes
redundancy. Aesthetic appeal does not count; neither does human
ergonomics. The full criterion lives in docs/DESIGN.md
("Feature-acceptance criterion").
This is the positive complement to the rule above. Together they
narrow the space of valid feature rationales to one thing: what
AILang's actual user — the LLM author — gets out of it.
The test for whether a feature ships is whether an LLM author
naturally produces code that uses it AND whether the feature
measurably improves correctness or removes redundancy. Aesthetic
appeal does not count; neither does human ergonomics. Full criterion
lives in `docs/DESIGN.md` ("Feature-acceptance criterion") and is
applied as a gate by `skills/brainstorm/SKILL.md` during spec writing.
### Direction freedom
I have authority to choose the next iter, refactor, or feature
I have authority to choose the next iteration, refactor, or feature
without asking. Wrong calls are recoverable: every commit is
reachable via git, branches and tags exist for sharper rollback
points (`pre-rc` is one such), and reverting one or several commits
@@ -151,7 +166,7 @@ question.
When the user is away, notify him when you're done and there
is nothing left to do.
~/.claude/notify.sh "Text"
~/.claude/notify.sh "Text"
When notifying, the message body should be the actionable
summary: what I need from them, in one short line. Skip the
@@ -163,132 +178,68 @@ exception, not the rule.
## Bug fixes — TDD, always
Every bug fix is test-driven. Concretely:
Bug fixes are RED-first, autonomous, no orchestrator gate. Full
discipline (Iron Law, four phases, Phase 4.5 architecture trigger,
common rationalisations) lives in `skills/debug/SKILL.md`. Headline:
1. **Red first.** Before touching the fix, write a test that
demonstrates the bug — it must fail on the current code,
ideally with output that pins down the symptom (segfault,
wrong stdout, refcount underflow, panic). If a minimal
reproducer already exists (e.g. handed back by the bencher
or debugger), shape the test around that.
2. **Green second.** Make the smallest change that turns the
red test green. No surrounding cleanup, no opportunistic
refactor; the fix is the fix.
3. **Keep the test.** It stays as a regression — never delete
it after merging. Future iters that touch nearby code
exercise it automatically.
1. **RED first** — write a failing test that pins down the symptom,
commit it as `test: red for <symptom>` BEFORE any fix.
2. **GREEN second** — minimal change to turn the test green; no
surrounding cleanup.
3. **Keep the test** — never deleted; future iterations exercise it.
Bug fixes do NOT need orchestrator permission. When a bug is
unambiguous (build broken, fixture crashes, observable wrong
output, structured diagnostic from the bench / debugger), the
fix is autonomous orchestrator work. The user's role is to
direct *features*, not to gate *fixes*.
A bug fix without a regression test is a code change, not a fix.
A bug fix without a regression test is a code change, not a
fix. The test is what makes the fix durable across future
edits.
## Milestone cycle
## Iter cycle
Work clusters into **milestones** (formerly "families", e.g. 18af
delivered the RC + uniqueness memory model as one milestone). Each
milestone runs through the skill pipeline:
Work is organised into **iters** — tightly scoped commits that
ship a feature, a refactor, or a tidy. Iters cluster into named
families (18af, 19ac, …) where each family advances one larger
concern (e.g. 18af together delivers the RC + uniqueness memory
model).
### Tidy-iter at family boundaries
After every named iter family closes, the next iter is a
**tidy-iter**: run `ailang-architect` over the whole surface, read
its drift report, and resolve every item by either (a) fixing the
drift, (b) updating docs/DESIGN.md to ratify what shipped, or (c)
recording in docs/JOURNAL.md that the drift is acceptable and why.
The tidy-iter is non-optional. Without a scheduled cleanup,
codebases grow by accretion — every iter adds, none tears out,
and the deferral compounds across families. Skipping a tidy-iter
requires an explicit JOURNAL entry naming the reason (e.g. a
sibling family is blocking, or the user has asked to defer).
### Performance regressions
Three scripts gate the tidy-iter alongside the architect drift
report:
- **`bench/check.py`** — runtime regressions (gc/bump/rc throughput
and PTY tail-latency over the bench fixture corpus, baselined in
`bench/baseline.json`).
- **`bench/compile_check.py`** — compile-time regressions
(`ail check` and `ail build --opt=-O0` wall-time over a curated
example corpus, baselined in `bench/baseline_compile.json`).
- **`bench/cross_lang.py`** — cross-language ratios (AILang at
`--alloc=rc` and `--alloc=bump` vs. hand-C reference compiled
with `clang -O2` over the same workloads, baselined in
`bench/baseline_cross_lang.json`). The headline answer to
"LLVM-linkable, performance is extremely important" — guards
against AILang/C ratios drifting upward over time.
Run all three at every family close. The canonical sequence is:
```bash
bench/check.py && bench/compile_check.py && bench/cross_lang.py
```
brainstorm → plan → implement → audit
```
The exit code is the gate:
Inside a milestone, work proceeds as **iterations** (formerly
"iters"). Each iteration goes through `plan` then `implement` and
adds a JOURNAL entry. At milestone close, `audit` runs mandatorily
— architect drift review against `docs/DESIGN.md` plus the three
regression scripts (`bench/check.py`, `bench/compile_check.py`,
`bench/cross_lang.py`). Detailed discipline:
- **Exit 0 (green).** All metrics within their per-metric
tolerance vs. `bench/baseline.json`. Tidy-iter can close.
- **Exit 1 (red).** At least one metric regressed beyond
tolerance. Treat the regression like an architect-drift item:
fix (revert the offending iter, refactor the hot path, diagnose
with `ailang-bencher` or `ailang-debugger`), or ratify
(`--update-baseline` on the firing script together with a
JOURNAL entry naming the iter that intentionally moved the
metric and why).
- **Exit 2 (infrastructure failure).** Bench-output format
changed (`check.py` parser misalignment), or a corpus fixture
is missing / fails to spawn (`compile_check.py`). Fix the
infrastructure before re-running. Never claim a regression on
exit-2.
- Mandatory tidy at milestone close (and how to defer it):
`skills/audit/SKILL.md`.
- Performance-regression gating with exit codes 0/1/2:
`skills/audit/SKILL.md`.
- Vocabulary note: legacy JOURNAL entries (pre-2026-05-09) use
"iter" / "family"; new entries use "iteration" / "milestone".
Existing entries are not retroactively renamed.
Skipping the bench-check at a family boundary requires the same
explicit JOURNAL entry as skipping the architect drift review:
name the reason, name the sibling family that's blocking, name
when it'll be re-run.
## Roles of `docs/JOURNAL.md`, `docs/DESIGN.md`, `docs/specs/`, `docs/plans/`
A bug-fix iter that adds a new bench fixture (e.g. proving the
fix's invariant under load) bumps `bench/baseline.json` as part
of the same commit. The new fixture's numbers are baseline-zero
on first capture; they become regression-relevant from the next
tidy-iter onward.
- **`docs/DESIGN.md`** is the canonical specification. It describes
what AILang *is*: schema, semantics, invariants, runtime contracts.
Every new feature must justify itself against `docs/DESIGN.md`
before it can ship; if the feature requires changes to
`docs/DESIGN.md`, those changes are part of the same iteration.
`docs/DESIGN.md` is also the artefact `ailang-architect` checks
the code against during drift review.
Two non-goals to keep clear: (1) per-metric tolerances are tuned
for run-to-run noise on a quiet developer machine, NOT the
language's correctness bar — Decision-10 thresholds (rc/bump ≤
1.3× / p99/median ≤ 5×) live in docs/DESIGN.md and are evaluated
against absolute numbers, separate from the regression check.
(2) Improvements (metric beat its baseline by more than tolerance)
do NOT auto-update the baseline; they are surfaced in the report
so the orchestrator can ratify them via `--update-baseline` with
a paired JOURNAL entry.
### Roles of docs/JOURNAL.md and docs/DESIGN.md
- **docs/DESIGN.md** is the canonical specification. It describes what
AILang *is*: schema, semantics, invariants, runtime contracts.
Every new feature must justify itself against docs/DESIGN.md before
it can ship; if the feature requires changes to docs/DESIGN.md,
those changes are part of the same iter. docs/DESIGN.md is also the
artefact `ailang-architect` checks the code against during
drift review.
- **docs/JOURNAL.md** is the decisions log. It records *why* the
- **`docs/JOURNAL.md`** is the decisions log. It records *why* the
project moved the way it did — alternatives considered and
rejected, lessons from past iters, queued options for future
rejected, lessons from past iterations, queued options for future
work, and the rationale behind choices that does not belong in
docs/DESIGN.md (rationale is about the choice, not about the
`docs/DESIGN.md` (rationale is about the choice, not about the
language).
Together they answer two questions: "what is the language right
now?" (DESIGN) and "how did we get here, and what's next?"
(JOURNAL).
- **`docs/specs/<milestone>.md`** (since 2026-05-09): per-milestone
design spec produced by `skills/brainstorm`. Hard-gate before any
plan or code work for the milestone.
- **`docs/plans/<iteration>.md`** (since 2026-05-09): per-iteration
bite-sized executable plan produced by `skills/plan`, consumed
by `skills/implement`.
Together these answer two questions: "what is the language right
now?" (DESIGN) and "how did we get here, and what's next?" (JOURNAL,
specs, plans).