Harness-agnostic
SDLC runs today inside Claude Code’s plugin mechanism. That’s a convenient bootstrap, not the destination.
The principle
Section titled “The principle”The op registry is the system. The CLI is one adapter over it. The data (markdown + frontmatter on disk) and the deterministic ops are portable: they don’t depend on Claude Code, or on any single door, to be meaningful.
A future MCP server, HTTP service, or other agent harness operates on the same registry. Claude remains a front door — not the front door.
One op, many doors
Section titled “One op, many doors”Every deterministic operation is declared once in the registry as a
defineOp descriptor and projected into each door. The contract is
restated nowhere: add a conforming module and the op appears in every
adapter with no hand-wiring (D-0007-deterministic-op-substrate §2/§5).
solutions/ontological/lib/registry.ts one defineOp descriptor path · input · output · handler │ ┌───────────────┼───────────────┐ ▼ ▼ ▼ CLI (sdlc) MCP HTTP shipped derived derived segments tool name = route = verbatim underscore-join /<seg>/<seg>[/<seg>] method by verb classAdapter projection is a pure function of the path
(D-H7FS-op-substrate-surface §5):
| Door | Projection | Example |
|---|---|---|
| CLI | path segments verbatim; interior segments are description-only group subcommands | sdlc quality baseline capture |
| MCP | tool name = underscore-join, intra-segment hyphens kept; a forward map, uniqueness enforced by project-check | quality_baseline_capture, gate_worktree-scope |
| HTTP | /<seg>/<seg>[/<seg>]; method by verb class (create/update/start → POST; get-schema/list/scan → GET) | POST /quality/baseline/capture |
The CLI is the one shipped door (solutions/ontological/cli/registry_adapter.ts); it
builds a recursive command trie from the paths and dispatches each leaf
through invokeOp. MCP and HTTP are bound to the rules above — tool names
and routes are derived, never hand-assigned — but neither is built yet.
What the constraint demands
Section titled “What the constraint demands”1. The data layer is just files
Section titled “1. The data layer is just files”Tasks, milestones, decisions, standards, and the rest are plain markdown
with YAML frontmatter under docs/planning/<plural>/. No database, no
service, no Claude-specific format. Anything that can read a directory of
markdown can read the data. The moment the canonical state lives in a
proprietary store, the system is welded to whatever wrote it.
2. Ops carry no ambient context
Section titled “2. Ops carry no ambient context”A handler runs against an injected ctx — { projectRoot, dryRun, io, git, gh } — and reads no ambient cwd or env (OpCtx in
solutions/ontological/lib/registry.ts). That DI seam is exactly what makes an op
callable off-process: an MCP or HTTP caller has no working directory to
inherit. The same seam makes ops testable with fake io/git/gh, and
lets --dry-run and --output be applied once by the adapter rather than
re-coded per verb.
3. Long-running work has a lifecycle, not a request/response
Section titled “3. Long-running work has a lifecycle, not a request/response”A server or a heartbeat loop never returns a single result object, so it
can’t be a plain op — its handler would hang invokeOp’s
await-then-validate. defineService is the registry sibling for these:
same path-keyed index and help surface, but a lifecycle
(start/stop?/list?) dispatched outside the output-parse pipeline
(defineService in solutions/ontological/lib/registry.ts, §3). Lifecycle failures map
to the SERVICE_ERROR exit tier — already-running, stale pidfile,
port-in-use. The dashboard and the lease heartbeat loop are the two
services shipped today.
defineService({ path, lifecycle }) │ ┌───────────────────┼───────────────────┐ ▼ ▼ ▼ start stop? list? may never returns releases the reports running (server / loop) pidfile/port instances │ └─ dispatched OUTSIDE invokeOp's await-then-output.safeParse (a non-returning loop would hang it) — exit via SERVICE_ERRORWhat “harness-agnostic” does NOT mean
Section titled “What “harness-agnostic” does NOT mean”It does not mean the LLM is interchangeable with a non-LLM today. The parts of the workflow that
genuinely need judgment — readiness verification, backlog triage, semantic doc-drift — are
LLM-shaped right now, and live in solutions/ontological/plugin/plugins/sdlc/skills/, outside the
substrate. A pure-machine door reaches every op; it does not reach the skills that compose them
with judgment.
The claim is narrower: the data and the deterministic ops don’t require the LLM. One registry, projected into many doors, means a capability is reachable identically from a shell, CI, a Claude session, or a non-Claude agent — with no per-adapter contract drift.
See also
Section titled “See also”- Deterministic-first — the output contract every door projects.
- Roadmap — where the MCP/HTTP doors stand and what’s next.