Skip to content

SDLC current orchestration — technical map

State: open/active · Genre: plan

Companion to README.md. A full map of how orchestration works in this repo today, read with one question in mind: where does orchestration logic live — in Claude (markdown skills, model judgment) or in deterministic TypeScript (the sdlc CLI / lib services)? Where is the boundary, and what crosses it?

The SDLC plugin splits into two planes joined by a narrow text contract. The skill plane (34 markdown SKILL.md files Claude runs as instructions) holds the control flow, the sub-agent fan-out, and the real judgment. The op plane (deterministic TypeScript under solutions/ontological/lib/, exposed as the sdlc <noun> <verb> CLI — ~19 nouns, ~70 verbs) holds every deterministic capability. Each op is a defineOp({ path, input: ZodSchema, output: ZodSchema, handler }) in solutions/ontological/lib/registry.ts; the CLI (solutions/ontological/cli/registry_adapter.ts) is a generated generic adapter with no per-verb code. Skills cross the boundary by shelling out, checking the exit code, and reading one SCREAMING-KEBAB marker line (e.g. ACQUIRED task=… lease_id=…, TASK-WORK-DONE pr=#42). This is an RPC-style contract; registry.ts:310 notes that the MCP JSON Schema is derived from the op input, and ops get an injected OpCtx instead of reading the ambient cwd/env, so they can already run off-process.

The orchestration loop (orchestrate/SKILL.md) is ~80% deterministic delegation. “Is there work?” is already decided in code (the orchestrate watch op — no LLM). Each tick, Claude syncs main, fans out pr-check sub-agents (classification is the pure pr classify op), counts in-flight (the task inflight op), checks the control-plane lease, then dispatches task-work against task next candidates after winning a lease CAS. Verdict routing is a fixed dispatch table. A large part of the skill (the ESCAPE_RECOVERY_MAP, lenient-recovery, marker naming) is cost from using an LLM worker that disappears once both sides are deterministic.

The lease system (services/lease/) is the most engine-ready piece: a distributed advisory lease where leases are git refs (refs/sdlc/tasks/<id>), CAS via git push --force-with-lease, host-UUID ownership with same-host inherit and steal-on-expired — closer to a distributed lock service (etcd) than to flock. It is authoritative; task status: frontmatter is a “workflow cache” (schema.ts:74).

State lives in three places — the .sdlc/ runtime dir (gitignored: orchestrator-log, pr-cursors, worktrees, baselines), git refs (the lease), and committed frontmatter. No database; every tick rebuilds from disk + git + gh, so restarting loses nothing.

For the MCP decision: the deterministic base is already an any-agent engine in all but name. Only the per-tick control loop, the parallel dispatch scheduling, and the flaky-sub-agent parsing really live in Claude — the last being pure cost the engine removes. There is no MCP server today (plugin.json declares skills + CLI only). The real model work shrinks to a few judgment calls (relevance, thin/subjective-spec reading, writing code, answering reviews) that an engine would invoke as bounded LLM tool calls.


  • Skill plane — solutions/ontological/skills/<slug>/SKILL.md, run by Claude as instructions. Holds control flow, sequencing, sub-agent fan-out, and model-judgment steps. 34 skills ship.
  • Op plane — the deterministic TS “op substrate” under solutions/ontological/lib/, exposed as sdlc <noun> <verb>. Every capability is a defineOp({ path, input: ZodSchema, output: ZodSchema, handler }) descriptor in a process-level index (solutions/ontological/lib/registry.ts). ~19 nouns, ~70 verbs. The CLI (solutions/ontological/cli/registry_adapter.ts) is a generated generic adapter with no per-verb code.

The boundary is a single-line text contract: skills shell out bun run ${CLAUDE_PLUGIN_ROOT}cli/sdlc.ts <noun> <verb> …, check the exit code, and read one marker line (or --output json). No structured IPC, no shared memory — argv in, exit code + marker out.

Key finding: the deterministic plane is already adapter-neutral. registry.ts:310 notes that the op’s Zod input is where “JSON Schema for MCP derives from it,” and ops get an injected OpCtx ({ projectRoot, dryRun, io, git, gh, sdlcConfig }, registry.ts:175-182) instead of reading the ambient cwd/env — which is what makes them callable off-process. What is Claude-only today: (a) the per-tick control loop, (b) the parallel sub-agent fan-out, (c) a few judgment calls.

1. The orchestration loop — /sdlc:orchestrate

Section titled “1. The orchestration loop — /sdlc:orchestrate”

solutions/ontological/skills/orchestrate/SKILL.md. One invocation = one reconcile-and-dispatch tick. Long-running work stays inside dispatched sub-agents.

Two wake surfaces, both gated by deterministic code:

  1. Fixed-cadence /loop /sdlc:orchestrate (2–6h) — the safety net; the only surface that catches CI-FAILED/CONFLICTS changes, lease expiry, and dead-stop notification.
  2. Event-gated Monitor wrapping sdlc orchestrate watch (orchestrator/ops/watch.ts) — a deterministic pending-work check, no LLM. Three predicates (evaluateTaskReady, evaluatePrAttention, evaluatePrGone) over live state; it prints at most one PENDING reasons=… prs=… tasks=… line, and only when there is real work; exit is always 0, so the presence of stdout is the only signal. Idle = no orchestrator transcripts. watch_loop.sh polls every 60s and never exits.

The “is there work?” decision is already in deterministic code; the model is woken only when the code says so and is handed the exact PR numbers / task basenames.

Per-tick steps — who decides:

StepWhatClaude vs deterministic
1 Sync maingit pull --rebase --autostash; abort on conflictClaude runs git; abort is mechanical
2 Reconcile PRsper PR, dispatch Agent → /sdlc:pr-check <N>; route on verdictFan-out = Claude; classification is deterministic (pr classify); routing is a fixed table
3 Count in-flighttask inflight --output json → {implementing, awaiting-review, stale, other} + capsFully deterministic (task/ops/inflight.ts)
3a Control-plane gatelease inspect refs/sdlc/control-plane --json; compare sdlc_version majorFully deterministic (lease/control_plane.ts); branch on exit 0/5/other
4 Dispatch ready taskstask next → pickup order; per candidate lease task acquire (CAS); on win dispatch Agent → /sdlc:task-work; cap at max_implementations - implementingOrder, dependency filter, lease claim all deterministic (task/ops/next.ts, lease/runtime.ts); Claude owns the loop + cap math + parallel fan-out
5 Digestorchestrate log-tick … appends one line to .sdlc/orchestrator-log.mdField grammar + tick numbering deterministic (orchestrator/ops/log-tick.ts)
6 NotifyPushNotification only on a true dead-stop (no open PRs AND no pickable tasks AND ≥1 blocked/needs-definition)Fixed boolean
7 Returnre-print the digest; /loop schedules the next tick via ScheduleWakeupClaude/harness

Where judgment matters: almost nowhere in a meaningful way. Verdict routing (MERGED|CLOSED→close-out, NEEDS-RESPONSE→pr-respond, CONFLICTS|CI-FAILED→resolution sub-agent, CLEAN→nothing) is a fixed switch. The large block at SKILL.md lines ~512-660 (TASK_WORK_VERDICT_RE, ESCAPE_MARKER_RE, ESCAPE_RECOVERY_MAP, lenient last-line recovery, per-slug back-off) is only there to handle an LLM sub-agent that adds prose or stops early — it goes away once both sides are deterministic. The real model decisions are small (shorten /loop when busy; write the human-readable digest text).

2. The task lifecycle — open → in-progress → PR → review → merged → closed

Section titled “2. The task lifecycle — open → in-progress → PR → review → merged → closed”
[SKILL = Claude] {op/CLI = deterministic}
open/ready ──/sdlc:task-work───────────────────────────────────► in-progress + open PR
1 resolve {task resolve}
2 pre-flight {task probe-state} ← blocked_preflight / resume_candidate
2a acquire lease {lease task acquire} CAS-CREATE / same-host inherit
3a quality baseline {quality baseline capture}
3b permission probe {task preflight-permissions}
4 worktree git worktree add ; {quality run --key worktree_init}
5a readiness GATE [/sdlc:task-ensure-ready] → {task gap-report} + LLM judgment
5b start-commit {task start} {commit-to-main ephemeral wt} + lease→working
6 IMPLEMENT [Agent writes code] + {lease heartbeat-loop} sidecar
7 quality gate {quality run --diff-against-baseline}
8 post-mortem [Agent] {commit create --kind task-lifecycle} [/sdlc:spawn-task-pr]
9 sync/rebase [check_ancestry.ts] + git rebase
10 open PR gh pr create (lease footer) ; {lease task transition --phase awaiting-review} (+handoff.md)
▼
awaiting-review ──/sdlc:pr-check (per tick)──► verdict {pr classify}
├─ NEEDS-RESPONSE ─/sdlc:pr-respond─► {lease parse-footer}{lease task fence}{lease task reacquire responding}
│ [Agent addresses comments] {heartbeat} {transition awaiting-review}
└─ MERGED ─/sdlc:task-close-out─► {lease task reacquire closing}{task close-commit}(status→closed/done)
git worktree remove + branch -d {lease task archive}
▼
closed/done

Step by step, where the boundary sits:

  • Pickup: which task = deterministic (task next, task/ops/next.ts). The relevance check (“does this still match reality?”) = model judgment, backed by task probe-state facts.
  • Claim: deterministic lease CAS (lease task acquire, runtime.ts:acquireLease). Same-host inherit / cross-host LeaseConflict is in code; the skill branches on exit 0/4/1.
  • Readiness gate (/sdlc:task-ensure-ready): the facts come from sdlc task gap-report (task/ops/gap-report.ts — “facts, not judgment, runs NO LLM”: missing sections, left-in placeholders, unresolved touchpoint paths, claim-resolver findings). The reading is model judgment: implementation-ready.md leaves exactly three things to the LLM — “is a section thin?”, “is this AC subjective?”, “is this corpus assumption actually wrong?” (confirm before flagging; candidates from sdlc task scan-corpus-assumptions). This is the clearest boundary in the system.
  • Start/flip: deterministic — sdlc task start flips status: in-progress, commits on origin/main via an ephemeral worktree (git/commit-to-main.ts), and CAS-REPLACEs the lease to working.
  • Implementation: model — the Agent writes code; the deterministic lease heartbeat-loop start sidecar keeps the lease alive at TTL/2.
  • Quality gate: deterministic — quality run --diff-against-baseline gates only on new drift (quality/ops/run.ts, quality/baseline.ts). Walking each AC = judgment.
  • PR classification (/sdlc:pr-check): fully deterministic — pr classify (pr/ops/classify.ts:294) is a priority-ordered pure function: MERGED→CLOSED→CONFLICTS→CI-FAILED→NEEDS-RESPONSE→CLEAN (+ERROR). The skill is a one-line wrapper.
  • Review response (/sdlc:pr-respond): the lease steps are deterministic (parse-footer→fence→reacquire responding→transition awaiting-review); addressing comments = model judgment (the Agent).
  • Close-out (/sdlc:task-close-out): almost entirely deterministic — the status gate, merged-PR detection, the merge-base --is-ancestor reachability check, the task close-commit op (flip to closed/done, add completion_note, regen, push via an ephemeral worktree), worktree/branch teardown, lease task archive. The skill “hand-edits no files.” The most engine-ready step.

Lifecycle fact: task/schema.ts:74-80 — under GitHub Ref Leases the status: frontmatter is a workflow cache; the real claim is the lease ref refs/sdlc/tasks/<id>. There is no declarative state machine; the legal-transition policy lives in skill prose (§8).

solutions/ontological/lib/services/lease/ + solutions/ontological/conventions/lease-aware-skills.md. The GitHub Ref Leases protocol — the most engine-like, any-agent piece.

Leases are git refs on a configured remote “authority” (SDLC_LEASE_AUTHORITY env or lease_authority: in sdlc.yaml). The ref points at a commit whose tree holds lease.json (canonical JSON) + an optional handoff.md. Namespaces: refs/sdlc/tasks/<id> (active), refs/sdlc/archive/tasks/<id> (audit trail), refs/sdlc/ops/<op>/<key>, refs/sdlc/control-plane.

CAS primitive (primitives.ts) = git push --force-with-lease:

casCreate : git push --force-with-lease=<ref>: <authority> <newSha>:<ref> # ref must NOT exist
casReplace : git push --force-with-lease=<ref>:<expected> <authority> <newSha>:<ref> # ref must == expected
casDelete : git push --force-with-lease=<ref>:<expected> <authority> :<ref>

The payload is serialized with a hand-written canonicalJson (canonical_json.ts, byte-for-byte match with Python json.dumps(sort_keys, separators)) and a pinned commit identity (tree.ts) so the SHAs are deterministic. The authority ref is the single source of truth; atomicity is git’s server-side ref-update CAS, not a clock.

Payload + phases (schemas.ts:70-93, zod .strict()): lease_id (stable identity), owner (= the host_id UUID), lease_token (fences stale heartbeats), phase, claimed_at, expires_at (nullable), pr_number. The phase enum (:55-62): claimed | working | blocked | awaiting-review | responding | closing. Rules (runtime.ts:425-426): entering claimed/working rotates lease_token; awaiting-review/blocked set expires_at=null; otherwise floor(now)+ttl (default 3600s).

Core ops (runtime.ts, each atomic per call, no cache): acquireLease (CAS-CREATE, same-host inherit on conflict else LeaseConflict); transitionLease (caller-driven CAS-REPLACE, no steal); heartbeatLease (bump expires_at); reacquireLease (CAS-REPLACE with steal-on-expired — logs STOLEN … from=<owner>, flips the owner, rotates the token; “two operators racing a PR resolve to one owner”); releaseToArchive (idempotent archive-then-delete).

Ownership: currentHostId() (runtime.ts:207-216) = a stable per-host UUID at host.json in sdlc’s fleet durable home (sdlcTier().durable().path). The owner is this UUID; the comparison is exact string equality. This is a host-level, not process-level mutex — same-host runs inherit each other’s claim (the orchestrate→task-work handoff); different hosts conflict.

Vs a process filelock: it is distributed (any host with push access), the authority is a remote git ref, liveness is via TTL + advisory steal-on-expired (not the kernel), identity is host UUID + lease_id + a rotating lease_token, it is re-entrant on the same host by design, it keeps full history, and it fences via token rotation + a PR-footer fence check. It is a distributed advisory lease with fencing tokens (etcd/Chubby style), not flock. Expiry is advisory — only reacquireLease checks the clock, and even then it just logs and proceeds; the real safety is the CAS.

How Claude interacts: entirely through sdlc lease … CLI verbs, never importing the library; it branches on exit codes (0 ok, 2 CAS-FAILED, 3 LEASE-EXPIRED, 4 LEASE-CONFLICT, 5 REF-NOT-FOUND, 6 SCHEMA-ERROR, 7 NAMESPACE-CONFLICT). It finds the lease by branch name (git branch --show-current → strip task/ → ref), so dispatched sub-agents and hand-run operators take the same path. The heartbeat is a backgrounded deterministic sidecar (lease heartbeat-loop start). MCP-readiness: already done — nothing here is Claude-coupled.

4. Gates — solutions/ontological/lib/services/gate/

Section titled “4. Gates — solutions/ontological/lib/services/gate/”

Two different meanings of “gate”:

  1. services/gate/ = commit-time lefthook lint gates (fully deterministic, no LLM): gate worktree-scope, gate skill-prose (lints each SKILL.md against invariants.yaml — for example it requires orchestrate’s “in-flight limits” phrase), gate markdown-fixtures. This is CI/pre-commit machinery, not lifecycle gates.
  2. The readiness gate is not here — it is sdlc task gap-report + sdlc task probe-state in the task entity package, with the contract in task/implementation-ready.md and the reading in /sdlc:task-ensure-ready (§2). The gap-report.ts “facts, not judgment, runs NO LLM” comment is the clearest statement of the plugin’s design idea.

No database. Three places:

  • (a) .sdlc/ (gitignored): orchestrator-log.md (one line per tick; tick# = line count + 1), orchestrator-watch.json (ETag/emission bookkeeping, safe to delete), pr-cursors/<N>.json ({last_seen_comment_at, last_invoked_at, self_posted_at[]} — for new-comment detection), worktrees/<basename>/, commit-worktrees/ (ephemeral), quality-baselines/<sha>.json (kept to 5), runtime/lease-heartbeat-*.pid/.log, migration.log, skill-ext/<slug>/<event>.sh (optional project hooks).
  • (b) Git refs on the authority: refs/sdlc/tasks/*, refs/sdlc/archive/tasks/*, refs/sdlc/control-plane, refs/sdlc/ops/* — the real coordination state (durable, distributed, auditable).
  • (c) Committed frontmatter (docs/planning/<plural>/): task status, autonomy, depends_on, priority, readiness_verified_at, definition_gap, completion_note, prs, last_reviewed — the workflow cache.
  • (d) Config — sdlc.yaml: quality_checks:, worktree_init:, orchestrator: (max_implementations=5, max_awaiting_review=20), pr_check: (author_comments, ignored_authors), lease_authority:.

The persistence model: an append-only log + level-triggered projections (cursors/watch-state recomputed each poll, so loss is fine) + git refs + git-committed frontmatter. No process holds long-lived state; every tick rebuilds from disk + git + gh. This is a good setup for moving the control out — an engine restarting mid-flight loses nothing.

Skills shell out and read (a) the exit code + (b) one marker line (or --output json). Examples:

# Lease acquire (task-work 2a) — check exit code, read one token
lease task acquire <basename>
# 0 → "ACQUIRED task=<basename> lease_id=<uuid> phase=claimed" (read lease_id=)
# 4 → "LEASE-CONFLICT ref=<ref> reason=owner=<other-host-id>" (stop)
# In-flight (orchestrate 3) — JSON
task inflight --project-root <main-repo> --output json
# → {counts:{implementing,awaiting-review,stale}, limits:{...}, tasks:[...]}
# Readiness facts (ensure-ready 3) — JSON of deterministic facts
task gap-report <path> --output json
# → {has_gaps, gaps[], sections[], placeholders[], touchpoints{...}, claims[]}
# PR classify (pr-check) — pass the verdict through
pr classify <pr-number> [--mock-state <path>]
# → "<VERDICT> reason=\"...\"" VERDICT ∈ {MERGED,CLOSED,CONFLICTS,CI-FAILED,NEEDS-RESPONSE,CLEAN,ERROR}
# Digest (orchestrate 5) — pass computed fields, the op owns the grammar
orchestrate log-tick --sync ok --prs MERGED=1,CLEAN=2 --implementing 3 --tasks-dispatched foo:claim=won …

Marker discipline (solutions/ontological/skills/CLAUDE.md): every terminal marker is SCREAMING-KEBAB, prefixed by the skill slug — TASK-WORK-DONE, ENSURE-READY-OK:, TASK-CLOSE-OUT-DONE, PR-RESPONSE-COMPLETE:, TASK-AUTO-DEFINE-DEFINED:; the one shared un-prefixed marker is ERROR reason="…". This naming exists only because skills call skills as sub-agents and the parent LLM reads the child’s stdout for a marker — bare DONE pr= markers collided across skills and cost two task-work runs on 2026-05-28. The whole marker system + orchestrate’s escape/lenient/anomaly recovery is cost from using an LLM worker — it protects against a worker that does not parse contracts reliably; it would not exist if both sides were deterministic.

Contract shape: argv in → (exit code, one marker line | JSON) out. This is an RPC-style contract — one Zod-schema serialization away from an MCP tool call, and registry.ts:310 says the MCP JSON Schema already derives from the same op input.

7. Agent coupling — what survives moving the control to an engine

Section titled “7. Agent coupling — what survives moving the control to an engine”

Already engine-ready (no Claude coupling) — pure ops with Zod I/O + an injected OpCtx; the MCP/HTTP adapter is generated, not written:

  • The whole lease subsystem (services/lease/).
  • PR classification (pr/ops/classify.ts) — a pure function; the skill is a wrapper.
  • The pending-work check (orchestrator/ops/watch.ts) — already decides “is there work” in code.
  • In-flight categorization + pickup order (task/ops/inflight.ts, next.ts).
  • The digest writer (orchestrator/ops/log-tick.ts).
  • Readiness facts (gap-report.ts), probe-state, quality run/baseline, commit-to-main, close-commit, all entities/task CRUD, the cleanup scanner, detect-runners — the whole ~70-verb surface.

Tied to Claude/markdown today (would not survive as-is):

  • The per-tick control loop itself (orchestrate/SKILL.md) — sequencing, the parallel Agent fan-out, the cap math. This is the part in charge; an engine takes it over.
  • The sub-agent verdict-parsing code (escape-recovery, back-off, marker naming) — entirely cost from the LLM worker; it goes away in an engine world.
  • The implementation step (task-work 6) — writing code is real model work; an engine still runs an LLM, but as a tool call.
  • The review-comment response (pr-respond 6) — model judgment.

Real judgment vs convention an engine could do:

StepReal judgment?
task-work relevance checkReal — but backed by probe-state; an engine could pre-filter and escalate only unclear cases
ensure-ready thin/subjective-ACReal — gap-report stops short on purpose
ensure-ready corpus-assumption confirmReal — but candidate detection is deterministic
orchestrate verdict routingNot judgment — a fixed table
orchestrate “shorten loop when busy”Convention
close-out (all)Not judgment — already mechanical
pr-check classificationNot judgment — already a pure op
AC-coverage walkReal only for ACs that can’t be automated (UI feel, copy)

Conclusion for the MCP decision: the deterministic base is already an any-agent engine in all but name — a CLI adapter today, an MCP adapter as a generated sibling — and the op substrate was built for it (the OpCtx injection seam, Zod I/O, “JSON Schema for MCP derives from it”). No MCP server is declared today — solutions/ontological/.claude-plugin/plugin.json ships skills + CLI only (name sdlc, version 0.2.0).

11 entity types (entities/_registry.ts:237-249): backlog, capability, decision, driver, milestone, principle, product, reference, standard, task, term. There is no epic type (epic-ness is a task’s parent_key).

Task status enum (entities/task/schema.ts:56-80) — 4 majors, 14 values:

planning/draft, planning/proposed, planning/needs-definition, planning/backlog # forming, not pickable
open/ready # pickable
in-progress, in-progress/blocked # claimed
closed/{done,superseded,partially-superseded,obsoleted,relocated,no-repro,wontdo} # terminal (need completion_note)

.superRefine (schema.ts:207-220) enforces the one conditional rule: closed/* ⇒ completion_note. SCHEMA_VERSION = "5".

autonomy enum (schema.ts:103-113): human-only | supervised | autonomous/pr (or absent). It gates autonomous pickup: task next --exclude-autonomy human-only; autonomous/pr self-readies via ensure-ready→auto-define; work always stops at an open PR — nothing ever auto-merges; the human stays at the merge gate.

Other frontmatter: depends_on (drives the task next dispatchability filter + dependency lift), priority (boolean ordering override), readiness_verified_at (stamped on pass), definition_gap (on fail), completion_note, last_reviewed, prs, impact, complexity.

What drives transitions: no declarative state machine, no transition-validation graph. The model checks only that status is a legal enum value + the closed/* ⇒ completion_note rule. Transitions are done by skills (which choose the next status) and written through one op — sdlc task update (task/ops/update.ts → model/ops/_update.ts:137-206), which validates the schema and rejects immutable-field changes — so it enforces shape, not transition legality. The transition vocabulary is standardized only at the commit-message layer: the task-lifecycle kind lists ["start","verify-ready","flag-needs-definition", "record-pr","close-done","close-obsoleted","post-mortem"] (task/commits/lifecycle/schema.ts:33-41). The “which transition when” policy is spread across skill prose. This is a prime thing to move into the engine — today the status machine is implied in markdown; an engine would make it explicit and checked, with the lease ref already serving as the real claim that status only copies.


  • solutions/ontological/skills/orchestrate/SKILL.md — the tick loop
  • solutions/ontological/skills/task-work/SKILL.md — the per-task flow (1430 lines)
  • solutions/ontological/skills/{task-ensure-ready,task-auto-define,pr-check,pr-respond,task-close-out}/SKILL.md
  • solutions/ontological/conventions/lease-aware-skills.md
  • solutions/ontological/lib/registry.ts — defineOp/OpCtx/invokeOp, exit-code taxonomy (:81-101), MCP note (:310)
  • solutions/ontological/cli/{sdlc.ts,registry_adapter.ts,_common.ts} — the generic CLI adapter
  • solutions/ontological/lib/services/lease/{primitives,runtime,schemas,control_plane,footer}.ts — the lock
  • solutions/ontological/lib/services/orchestrator/ops/{watch,log-tick}.ts — the check + digest
  • solutions/ontological/lib/services/pr/ops/classify.ts:294 — the PR verdict classifier
  • solutions/ontological/lib/services/quality/{ops/run.ts,baseline.ts} — the quality gate + baseline
  • solutions/ontological/lib/services/git/commit-to-main.ts — ephemeral-worktree main-commit isolation
  • solutions/ontological/lib/model/entities/task/{schema.ts,implementation-ready.md} — the status/autonomy model + readiness contract
  • solutions/ontological/lib/model/entities/task/ops/{next,inflight,probe-state,gap-report,update,close-commit}.ts
  • solutions/ontological/.claude-plugin/plugin.json — the manifest: skills + CLI only, no MCP server today

← Back to Notes