Skip to content

Composition spectrum — one op registry, deterministic-to-LLM placement, path[] surface

Status: open/active

  • Build every capability on a spectrum from pure-deterministic to near-pure-skill: place it at the leftmost point that fits, and favor moving left as it matures (P-0001-prefer-deterministic-over-llm). The deterministic-tail / LLM-head split is one point on that spectrum, not the only shape. The sdlc CLI is one generated adapter over a single op registry. Deliberate, bounded child-LLM steps are legitimate (with guardrails); only redundant re-interpretation of the same input is discouraged.

The op registry surface (unchanged from D-0007 / D-H7FS)

Section titled “The op registry surface (unchanged from D-0007 / D-H7FS)”

Expose user-facing functionality as ops in the single registry under solutions/ontological/lib (D-0007-deterministic-op-substrate, amended by D-H7FS-op-substrate-surface); adapters (the sdlc <path…> CLI, MCP, HTTP) are generated front-doors over it, never parallel implementations. A command is a path: string[] — 2–3 kebab segments, hard cap 3. The registry key is path.join(" "); the legacy { noun, verb } export normalizes to path: [noun, verb]. Plumbing nouns register hidden from sdlc --help (revealed with --advanced/-ad).

The single-registry rule binds SDLC’s own user-facing functionality. A domain-blind component that ships as a standalone tool — the work-runner engine, the graph scheduler (S-0008-apps-consume-substrate-through-published-surfaces) — carries its own CLI, because it has consumers that are not SDLC and runners on hosts where sdlc is absent. sdlc wraps that CLI as one more consumer: sdlc engine is a convenience over the engine’s own door, not a second implementation of it. What the rule forbids is a parallel implementation of an SDLC capability standing beside the registry.

Output contract (D-H7FS-op-substrate-surface §4): every op’s canonical result is its zod output object. A single --output text|json|jsonl parameter shapes the projection — --json is kept as an alias. Defaults are op-declared: an op with a cli.render hook defaults to text; without one, json. Deterministic for skills and CI — never TTY-sniffed.

The composition spectrum (the organizing frame)

Section titled “The composition spectrum (the organizing frame)”

For any capability, place it at the leftmost point that fits; favor moving left as it matures (P-0001). Every point is legitimate for the right situation. Premature determinization is its own anti-pattern — do not force a fuzzy or early-phase capability leftward before its shape is known.

flowchart LR
P1["1 · Pure deterministic<br/>all code, no LLM — the ideal"]
P2["2 · Deterministic core<br/>+ LLM head"]
P3["3 · Mixture<br/>interleaved det + judgment"]
P4["4 · Nested<br/>child-LLM sub-components"]
P5["5 · Near-pure skill<br/>LLM-driven — the bootstrap form"]
P1 --- P2 --- P3 --- P4 --- P5
P5 == "favor moving left as it matures" ==> P1

Left = more deterministic (the ideal); right = more LLM (the bootstrap form). Place at the leftmost point that fits; favor moving left as it matures — premature determinization is its own anti-pattern.

#PointWhat it is
1Pure deterministicAll code, no LLM. The ideal. An op that never invokes an LLM.
2Deterministic core + LLM headA deterministic op (the tail) fed by an interchangeable head as a freeform entry point. A head is itself a spectrum: thin (interpret → one op) to procedural (many ops with judgment between). A CLI head resolves via claude -p; a skill head uses the ambient session.
3MixtureInterleaved deterministic steps and LLM-judgment steps within one composition, at the same level (P-0001 roles 3–4 at judgment ports).
4NestedDefined LLM-judgment steps as sub-components of a larger deterministic+agent composition — a child LLM task spawned with its own structured-I/O contract. Recursively composable.
5Near-pure skillHard-to-determinize or early-phase capability, defined almost entirely as an LLM-driven skill. The bootstrap form.

Point 3 vs point 4 discriminator: an LLM step that shares the parent’s level and context is a mixture (3); an LLM task dispatched as a bounded child with a contract at the boundary is nested (4).

This is the compositional axis. P-0001’s five maturation stages are the temporal axis (how a workflow hardens over time); the two are complementary. A workflow maturing P-0001 Stage 3→4 is a capability sliding left here from point 5/3 toward 2/1. The conceptual layer is the sibling philosophy doc.

A deterministic composition (or a skill) MAY deliberately call a child LLM at a defined judgment port (P-0001 role 3 / role 4). This is legitimate.

The only discouraged case is the redundant one: re-interpreting, in a fresh nested LLM (e.g. claude -p), the same freeform input the current session could resolve in-session at the same level — a wasteful double-LLM for a single interpretation. When the current session already holds the interpretation, call the deterministic op (the tail) directly.

Guardrails — required on any nested LLM step:

GuardrailRequirement
Bounded scopeThe child has a narrow, defined job, not open-ended “be helpful.”
Structured I/O at the boundaryThe child receives and returns structured data where feasible; the boundary carries a contract, not ambient prose.
Depth/cost awarenessThe dispatch is deliberate about recursion depth and token cost; the boundary is chosen, not incidental.

The standard covers all four ways a composition reaches a child LLM. Each must carry the guardrails above.

#MechanismForm
1Sub-agent spawningA composition (often a skill) dispatches an Agent/Workflow sub-agent for a bounded job.
2Agent step in a registered processThe process registry (D-VSLI-distributed-work-runner-architecture) binds a kind: to a step definition, and agent step is one tagged step variant beside built-in, shell command, and child process over the step protocol. It is the judgment port, reached through the agent-driver port. Decomposition — a process minting child work orders for the scheduler to dispatch — is the recursive point-4 form, but dispatch is leaf-only: a work order with children is a structural rollup, never dispatched, until the decomposition guardrails settle.
3Op/head invoking a bounded LLM stepA deterministic op or head calls claude -p / the SDK at a defined judgment port with a structured contract (mechanism behind backlog capture).
4LLM-backed toolAn external / MCP tool that is itself an LLM, consumed as a (deterministic-looking) step.

Registry marking. An op that contains a child-LLM judgment port (mechanism 3, or a mechanism-4 tool) is no longer pure-deterministic and must be distinguishable in the registry from a pure op, so the determinism guarantee for the pure tail — and any future “no-LLM in the validator path” lint — keeps a machine-checkable basis. The brand lives in the registry-surface decision (D-0007-deterministic-op-substrate / D-H7FS-op-substrate-surface); this standard requires the distinction exist, not its exact shape.

A pure-deterministic op has no LLM dependency, so its behavior is reproducible, auditable, and unit-testable in isolation; the LLM is an optional front door, never a requirement. One registry keeps a single source of truth for the mechanics and makes every capability reachable identically from a shell, CI, a Claude session, or another agent.

The spectrum exists because not every capability can — or should — be pure code. Most workflows can’t be entirely deterministic, but they can be deterministic with judgment ports (P-0001 role 4). Treating a child LLM as a typed, structured-I/O port rather than ambient orchestration keeps everything around the port deterministic, so opening the boundary does not forfeit testability. The old hard ban (“heads never nest Claude”) was an over-extension that P-0001 never stated and that contradicted P-0001’s own roles 3–4; it also outlawed the dominant existing pattern (every sub-agent-spawning skill). The narrowed rule keeps the one real waste — re-paying for an interpretation the session already has — and legitimizes the rest.

When adding user-facing functionality, find the leftmost point that fits:

  • Pure deterministic (1). Implement the op with path: string[] (2–3 segments), structured Zod input/output, --dry-run, a stable stdout marker, no Claude reference. Declare a cli.render hook when the output has a natural text form — this makes text the default and ensures parity for line-oriented callers.
  • Deterministic core + LLM head (2). If freeform input is useful, add an interpretation head (e.g. capture beside create) that fills missing fields via claude -p and calls the tail. Explicit flags always win over LLM-derived values; a complete structured invocation (or --no-llm) skips the LLM. A /sdlc:<path…> skill that already holds the interpretation in-session calls the deterministic op directly — going back through the head would redundantly re-interpret the same input.
  • Mixture / nested (3–4). A composition (op or skill) MAY interleave or dispatch a deliberate, bounded child LLM at a judgment port. Apply the three guardrails (bounded scope, structured I/O at the boundary, depth/cost awareness). Pick the mechanism (sub-agent, agent step in a registered process, claude -p / SDK port, or LLM-backed tool) that fits, and mark the op if it hosts a port.
  • Near-pure skill (5). For a hard-to-determinize or early-phase capability, a SKILL.md driving the LLM is the right shape. Park it here deliberately and let it mature left as its shape crystallizes — do not determinize it prematurely.

Prototype pair: sdlc backlog create / capture with the /sdlc:backlog-capture skill — points 1, 2, and the redundant-nesting carve-out in one worked example.

  • Redundant re-interpretation. A skill already running in Claude that shells to its own LLM head (sdlc <noun> capture) or to a fresh claude -p to re-interpret the same freeform input it could resolve in-session at the same level — a wasteful double-LLM for one interpretation. Call the deterministic op directly. (This is the only forbidden nesting case; a deliberate bounded child LLM for a different, defined sub-job is legitimate.)
  • Unbounded LLM inside an op. A deterministic op that invokes an LLM “to be helpful” with no bounded scope and no structured boundary contract. A deliberate bounded judgment-port call (with the three guardrails) is allowed and is the legitimate form; an open-ended, structureless one is the anti-pattern.
  • Parallel top-level script. Shipping a new user-facing capability as its own top-level script instead of a registry op — fragments discoverability and drifts from the adapters.
  • Legacy descriptor shape. Using { noun, verb } on a new descriptor — author path: [noun, verb] or the full 3-segment form directly.

Relationship to S-0001-co-locate-first-promote-when-shared: ops are capabilities, so they are born in solutions/ontological/lib; the per-skill SKILL.md stays co-located and only shells to the adapter.

Relationship to P-0012-rust-core-adapters-as-needed: this standard places a capability on the deterministic-to-LLM axis — how much judgment it needs, and where the judgment ports sit. P-0012 governs the language of whatever lands on the deterministic side: Rust at the core and through every layer that wraps it, other languages only as adapters at the edge with a named consumer. The two are orthogonal. Placement at point 1 says nothing about language; a choice of language says nothing about placement.

Relationship to S-0003-deterministic-general-extension-points: the four-layer boundary’s layer-2 deterministic tools MAY embed a bounded LLM judgment port under these guardrails, so the boundary is a permeable port, not a wall. The two standards must stay aligned on whether a lib op may invoke an LLM (it may, at a marked port).

Conceptual layer: the 5-point spectrum, the favor-left rule, the deliberate-vs-redundant nesting model, and the four mechanisms derive from P-0001-prefer-deterministic-over-llm’s maturation stages and four LLM roles; this standard is their prescriptive form.

Title note: the prior title named only the deterministic-tail / LLM-head point. The standard now spans the whole spectrum; the id S-0004 is stable (D-0002) so existing wikilinks survive the retitle.


← Back to Standards