The selector forced every task through the heaviest methodology's
critical path: a behaviour-preserving, type-enumerable change paid the
same specify -> planner -> implement front-half as a novel feature,
because it was neither new behaviour (tdd) nor an observed bug (debug)
and so fell to specify by elimination. Two coupled defects — a selector
with no verification axis, and an all-or-nothing executor — kept the
existing lighter path unreachable and uneconomical. This fixes both.
Part A — verification-keyed selector (boss/SKILL.md):
- Replace the three-way "design line" with an ordered cascade that adds
a verification/enumeration axis ahead of the settled-vs-fork question.
Each lighter arm carries a positive trigger matched by signature, not
reached by elimination.
- New `compiler-driven` arm: a type/signature edit at a definition site
that propagates mechanically. Observe-then-bounce — make the edit,
build, run the suite; clean build AND suite green unchanged commits;
a hole bounces up (specify for a design choice, tdd for discovered
test-specifiable new behaviour); a regression bounces to debug.
- The observed-bug RED-first gate is first in the cascade, so a
mechanical-looking fix cannot bypass it.
- The straddle rule ("add an enum variant") is codified as a rule:
mechanical/forwarding -> compiler-driven; encodes new behaviour ->
tdd/spec; doubt routes up.
- The executor is the elevated inline carve-out plus a shipped workflow,
not a heavy new skill ("the largest concrete win is small").
Part B — Workflow substrate (implement/workflows/):
- implement-loop.js: the per-task loop as a deterministic script. Each
phase (implementer -> spec-compliance -> quality, + tester for E2E) is
a separate top-level agent() call, so a single phase is independently
invokable and inter-phase aggregation/re-loop is code. Retires the
implement-orchestrator agent's inline-role-switch workaround (the four
phase agents survive as the agent-types the script dispatches).
- compiler-driven-edit.js: the observe-then-bounce loop.
- install.sh / uninstall.sh symlink shipped workflows into
~/.claude/workflows/.
- specify and brainstorm stay prose + interactive (human-intent oracle);
only the autonomous/mechanical loops moved. try-and-error is deferred.
Docs (pipeline taxonomy, design, agent-template, migration, README) and
all selector<->executor cross-references updated; the arm and its
executor are co-located so a future re-route through the full loop is a
visible regression.
Verified by an adversarial multi-agent pass: PASS on all six acceptance
criteria; two coherence concerns fixed. The shipped scripts are
syntax-validated but exercised only in a downstream target project (the
skills repo is not itself a pipeline target).
closes #7
6.7 KiB
Design
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 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 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)
The plugin owns:
- Pipeline form — the directed graph of phases:
design → plan → execute → review → close, entered through a selector cascade of entry paths walked on a verification / enumeration axis (observed bug →debug; design fork →brainstorm; behaviour-preserving type/signature edit →compiler-driven; test-specifiable →tdd; else → spec-driven). The taxonomy of paths and their oracles lives inpipeline.md§ The methodology taxonomy. - Hard-gates — spec before plan, plan before implement, audit before cycle-close. Skipping rules are codified per skill.
- Agent template — every agent file follows the same structure: frontmatter (name, description, tools), Iron Law, standing reading list, numbered process, status protocol, output format, common rationalisations, red flags.
- TDD as an independent inner-loop discipline — the implementer agent carries TDD even when the plan task forgot to script a RED-first step.
- RED-first bug fixes — non-negotiable for any observable misbehaviour; the debug skill is the gate.
- Status protocol —
DONE / DONE_WITH_CONCERNS / PARTIAL / BLOCKED / NEEDS_CONTEXT, plus reviewer-specific terminal states. - Working-tree-as-quarantine — agents write artefacts to the working tree, never commit. Only the orchestrator commits.
- main HEAD sacrosanct — no reset, no revert, by any actor. main moves forward only via orchestrator commits.
- No nested subagent dispatch — a hard Claude Code platform
constraint: an agent cannot spawn further agents. Workflows do not
lift it; a workflow script orchestrates from the top level, and
the agents it spawns still cannot spawn further agents. This is
exactly why the autonomous execution loops moved onto the Workflow
substrate: the
implement-loopandcompiler-driven-editscripts (implement/workflows/) run the per-phase agents as their own top-levelagent()calls, so a single phase is independently invokable — which retired the formerimplement-orchestratoragent's inline-role-switch workaround (it had to absorb the three phases into one context precisely because it could not nest). The four phase agents survive as the agent-types the scripts dispatch; what was retired is the dispatch/aggregation prose. The interactive paths (specify,brainstorm) stay prose skills — their oracle is human intent and needs a human in the loop, which a run-to-completion workflow cannot host. - No orphan agents — every agent lives under the skill that dispatches it.
- Output budget discipline — agents have word budgets on their reports.
Fixed conventions (universal)
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).
Project facts (project-specific)
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,
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 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
docs/specs. Use the project's build command (its CLAUDE.md project facts).
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
The plugin does not carry project-specific anti-patterns,
feature-acceptance gates, or domain contracts. Those belong in
the project's own CLAUDE.md. The plugin only carries the
universal discipline constants (only-orchestrator commits,
main sacrosanct, no orphan agents, agents-don't-call-agents)
which are conditions for the plugin's own correctness.
The relationship:
- 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 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
specifymay post a reconciliation comment or create a seeding issue via the tracker's comment / create commands — but the plugin does not directly call Gitea / GitHub / Linear APIs. Every read and write goes through the configured shell command, so the plugin remains transport-agnostic.