Workflow

From intent to code, with a trail at every step

The cycle has four commands and one property that ties them together: each one produces an artifact the next one consumes, and all of them stay in your repository. Before them there is an optional step zero — the study, for when you don’t yet know what to propose. It isn’t a chat with a good memory — it’s a chain of versioned documents that outlives the conversation, the person and the agent.

A fifth command, /pipeline, runs the whole chain end to end — it is resumable from the exact point where it stopped, and it flags when the step-zero study is worth running first.

The cycle

Four commands, four artifacts — and a step zero

Step 00 is optional — the study you run when you don’t yet know what to propose. The four that follow each have a gate: you don’t implement without a specification, you don’t close a phase without a review. The gates are code, not a recommendation.

  1. 00

    Before proposing, study — when clarity is missing

    Not every piece of work starts with the solution in hand. The study diverges before it converges — it maps the territory, enumerates options, weighs trade-offs or chases a root cause — and comes out with the open questions numbered, each one with an owner, plus the same contract block the rest of the chain reads. Ending with no decision is a valid outcome; what isn’t valid is deciding without having looked. The proposal that follows inherits the study instead of re-exploring from scratch.

    /analysis

  2. 01

    Intent becomes a document — and a contract

    You describe what you want. Out comes a proposal with the problem, the scenarios, the design principles, the risks and the acceptance criteria. Alongside it, embedded in the same file, comes a machine-readable contract block: the units the work breaks down into, the criteria that verify them, and the anchors that link every scenario to the criterion that closes it.

    /proposal

  3. 02

    Every unit becomes a specified phase

    The proposal isn’t run directly. Every unit of the contract becomes its own specification, with numbered, testable business rules, invariants, and the deterministic tests that will prove each one. This is where “the agent understood” stops being a bet: what it’s going to do is written down beforehand, and so is what counts as done.

    /ai-spec

  4. 03

    Implementation runs against the spec, not the chat

    The agent implements by reading the phase’s specification, not the conversation. Nothing is written without your approval, and at the end the test suite and the build are run — not declared. A phase that didn’t produce the files the spec promised doesn’t close.

    /implement

  5. 04

    An independent read decides whether it passed

    The review runs with context isolated from whoever implemented it, and returns a verdict: approved, approved with observations, or changes needed. Changes needed sends the phase back to implementation — and the trigger is the verdict, not a critical-finding count, because a rule with no test fails without ever being critical.

    /review

Pipeline of a feature in Harness Studio, with all four phases complete — each with its spec, implementation and review gates — followed by criteria verification, final review and follow-up.Pipeline of a feature in Harness Studio, with all four phases complete — each with its spec, implementation and review gates — followed by criteria verification, final review and follow-up.
A real feature from this project, from the first gate to the follow-up.

How SDD becomes real

The specification isn’t prose — it’s a contract

Spec-driven development usually dies at the same point: the spec is a document nobody can execute, so it ages on the sidelines while the code moves on. Here it has a half that the machine reads, and that’s the half that drives execution.

The spec has a half a machine reads

Alongside the prose humans review, every artifact carries a structured block with the units, the criteria and the anchors. It’s that block — not the text — that the orchestrator consumes to decide how many phases the work splits into and in what order they depend on each other.

Phases are born from the contract, not from reading

When the contract exists and is valid, the phases are derived from it and signed with a checksum. If the proposal changes, the signature stops matching and the phases get recalculated — and any work already logged is found again by the unit’s identity, never by its position in a list.

Without a contract, the flow degrades instead of stopping

An old proposal, with no block? The orchestrator falls back to the prose table of phases, and then to asking you — announcing which step it fell to and why. No execution gets interrupted for lack of a contract; what doesn’t happen is silent degradation.

The same contract serves different front ends

A formal proposal and a user story emit the same contract. That’s why switching the team’s methodology doesn’t rewrite the pipeline: whatever comes next reads the contract and has no idea which origin it came from.

The practical consequence: the spec can’t silently age. If it changes, the contract’s signature stops matching, and the orchestrator says it stopped matching — instead of carrying on executing a plan nobody approved.

Execution

A run that dies midway doesn’t lose the work

Progress lives in a versioned file

Every step that finishes is written to the run’s state as soon as it completes — never in a batch. The file says which phase is at which step, which artifact came out of each one, and who started the run, with identity coming from git.

Interruption isn’t loss

Closed the terminal, lost the connection, ran out of day? The next run reads the state, skips what’s already done, and continues from the first pending step. You can also run a specific range of phases on purpose, to review in batches.

The step in progress is claimed

Before starting, the step is marked as in progress, with a timestamp and an attempt number. A run that died midway is distinguishable from one that’s still working — and whoever resumes it knows which attempt they’re on, instead of guessing.

What failed stays on record

A step that fails writes the error and stops, instead of carrying on over a broken foundation. The next run finds the record of what happened, not an ambiguous state that only looks like progress.

Customization

The convention is the team’s; the preference is yours

Every command’s behavior resolves across three layers. The middle one is versioned and reviewed like code; the top one stays on your machine and never reaches the repository.

LayerWho edits itWhere it livesVersioned
BaseWhoever writes the skillships with the productYes
TeamThe team, by code review.claude/skill-config/Yes
PersonalEach developer, per machine.local.json (outside git)No

Base

The default behavior of every command. You don’t edit it — you receive it, and it updates along with the product.

Team

The team’s convention: context every command must carry, steps that run before or after a skill, rigor tier. It lives in git and is reviewed like any other file — changing the convention is a pull request, not a verbal agreement.

Personal

Your own preference, on your own machine, that never reaches the repository and bothers nobody. Disagreeing with the team default on something that only affects you doesn’t require convincing the team.

How the layers combine

Summing and overriding are different rules, on purpose

Context and steps add up; they don’t compete

Facts every command must know, and preparation steps, are concatenated in the order base → team → personal, preserving each layer’s own order. Your personal preference adds to the team’s convention instead of replacing it — which is the right behavior for the kind of thing these keys carry.

The completion hook is scalar: the outermost layer wins entirely

What runs when a command finishes doesn’t add up, though — the layer closest to you replaces the whole value, no merging. And explicitly declaring “none” counts as a declaration: that’s how a team turns off an inherited hook, instead of living with it.

Not everything is customizable, and that’s deliberate

Commands that write over existing work — rotating the history, reorganizing modules, preparing the environment, creating a branch, removing obsolete code — don’t accept flow hooks. For them, “customizing” would mean removing the check that prevents loss. The refusal is enforced by the engine, not left to discipline.

One execution profile per machine

Beyond skill behavior, execution has profiles: which model runs each step, whether steps run isolated in subagents or in the same session, what to do with what’s left over at the end. You choose your machine’s active profile without touching the repository default.

Team fit

The flow speaks your methodology’s language

The cycle above is the same on any team. What changes is the vocabulary, the command you specify with, what’s grouped by what, and the screen the cockpit opens to — all configuration, not one line of the product.

Switching methodology doesn’t rewrite the pipeline

On an agile team you specify with /story and see the work as kanban with velocity; on an enterprise team, the same work shows up as a traceability matrix. The specify step changes front end; the implement and review steps have no idea there’s a difference, because they read the contract, not the document.

And rigor is dialed separately from that

Methodology and rigor are independent axes: an agile team can go up to the strict tier on a payment feature without ever stopping talking in stories and sprints. Choosing one doesn’t lock you into the other.

See the two axes in detail

After development

Traceability that resolves, not that’s just declared

Finishing implementation isn’t the end of the chain. The question left over — is this requirement really covered by code and by a test? — is answered against the real repository.

  1. 01

    The matrix is resolved against the code, not asserted

    The anchors the specification declared — scenario leads to use case, which leads to criterion — are resolved against the real repository. Every link gets a status: resolved, partial or unresolved, with file and line as evidence. Whatever’s left uncovered shows up by name, instead of being discovered in production.

    /traceability

  2. 02

    It comes out in two forms, for two readers

    A readable matrix — scenario, use case, criterion, code, test, status — for whoever’s reviewing. And the same content, structured, deterministic and versionable, for whoever’s automating. Both come from the same resolution, so they can’t drift apart.

  3. 03

    The gate scales with the project’s rigor

    At the lightest tier the gate is skipped; at standard it warns; at strict it blocks whenever an unresolved link exists. It’s the same risk-based dosing that holds through the rest of the flow — the project decides when the lock closes, not the tool.

  4. 04

    Evidence is packaged for whoever audits it

    Traceability, security scan results and the reviews are bundled into a single evidence package. Auditing stops being a dig through folders and becomes an artifact you hand over.

The trail left behind

Six months later, the answer is in the repository

The history logs what was done, with real authorship

Every work session logs a start and an end, with scope and outcome, and authorship comes from git — not from a field someone filled in. It’s the chronological record of what happened, in the order it happened.

The decision outlives whoever made it

Structural choices become dated records with context, discarded alternatives and consequences. A decision that’s been superseded gets a banner on top and keeps its body intact — the history of the decision matters as much as the decision.

What’s left over becomes a tracked item

A postponed finding, an unverified criterion, an environment limitation: it all goes into a central registry with severity, owner and status, linked to the feature that produced it. Debt stops depending on someone remembering.

What goes out of circulation goes out with a date

Deprecating something is a record with its own life cycle — announced, deprecated, sunset pending, removed — instead of a comment nobody finds. It disappears when it was decided to disappear, not when someone stumbles onto it.

All of it versions alongside the code and is readable by humans and machines — even if you stop using Spaccy. Request early access and run the first cycle.