Spec Director Refactor¶
How OperationsCenter's spec_director was decomposed so that every LLM call
goes through the backend executor — closing audit, lifecycle, and provenance
gaps that direct-Claude code paths had left open.
Canonical decision record: OperationsCenter ADR 0007.
Context¶
spec_director was a single watcher containing three Claude-bypassing paths
(board hygiene, campaign generation, phase orchestration). Two of them called
Claude directly, skipping model-binding policy, rate limiting, retry, the audit
trail, and lifecycle capture — a generated spec just appeared on disk with no
run_id provenance.
Decision¶
Fold all LLM-needing operations through the normal
Plane task → board_worker → ExecutionCoordinator → backend pipeline. Split the
non-LLM operations into focused watchers that emit Plane tasks instead of
executing work themselves.
| Concern | Owner | LLM? |
|---|---|---|
| Hygiene (archive, bootstrap, auto-promote, recovery) | spec_hygiene watcher |
No |
| Trigger detection (drop-file, queue-drain) | spec_trigger watcher |
No |
| Spec generation execution | board_worker via spec-author task-kind |
Yes (via backend) |
| Phase orchestration LLM step | Same spec-author handler, task_phase label |
Yes (via backend) |
Architecture¶
flowchart TD
Plane["<b>Plane</b><br/>source of truth for all task state"]
Trigger["<b>spec_trigger</b> (watcher)<br/>drop-file · queue-drain<br/>on fire: creates Plane task<br/>(kind: spec-author)"]
Hygiene["<b>spec_hygiene</b> (watcher)<br/>archive · bootstrap · auto-promote<br/>recovery · phase-advance detection<br/>rebuilds active.json projection<br/>on phase-advance: creates Plane task<br/>(kind: spec-author, task_phase)"]
OConsole["<b>OperatorConsole</b><br/>watcher_status reads<br/>active.json projection"]
Worker["<b>board_worker</b><br/>picks up spec-author task<br/>planning → execute<br/>→ ExecutionCoordinator<br/>→ cl_dispatch_wrap<br/>→ backend writes file, commits, pushes<br/>→ RunArtifactWriter<br/>→ _handle_success: opens spec,<br/>creates campaign sub-tasks"]
Trigger -- "creates task" --> Plane
Hygiene -- "creates task / transitions" --> Plane
Plane -- "reads" --> Hygiene
Hygiene -- "writes active.json" --> OConsole
Plane -- "spec-author task" --> Worker
Worker -- "commits spec, campaign tasks" --> Plane
Key invariants¶
- All LLM calls go through the backend executor.
_claude_cli.pyis deleted; a CI grep guard prevents reintroduction. - Plane is single-source-of-truth for task state.
state/campaigns/active.jsonis a Plane-derived projection rebuilt byspec_hygieneeach cycle; OperatorConsole reads it (single writer). - Audit trail is end-to-end closed: the spec file embeds
generated_by_run: <run_id>, campaign sub-tasks carryparent_run, andrun_metadata.jsonrecordsspec_slugforspec-authortasks — any spec traces back to its execution.
Related¶
- Sync & Data Transport — the same manifest-as-authority and shim-contract patterns recur there.