Skip to content

dmytri/shipshape

Folders and files

NameName
Last commit message
Last commit date

Latest commit

 

History

190 Commits
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 

Repository files navigation

Shipshape

skills.sh

Shipshape is a portable skill set for coding agents. It turns product intent into durable Cucumber specs, derives work from failing verification, and isolates agent roles so discovery context does not leak into implementation.

Specifications are durable. Code is disposable. Agents are replaceable.

The Ship of Theseus is a classical thought experiment recorded by Plutarch. The Athenians preserved the hero's ship by repair: rotten timber out, new timber in, until none of the original planks remained. Was it still the same ship?

AI agents make the old question urgent. An agent can rewrite code, tests, fixtures, and support files in an afternoon, and every pass replaces more planks. A codebase maintained this way needs a durable source of identity, something that survives its own repair.

Shipshape's answer is that the ship was never its planks. Identity lives in the specification. Durable specs, traceable Planks, and verified behaviour preserve what matters while everything else remains free to change.

Why Shipshape

Most spec-driven tools define what a spec looks like. Shipshape defines what makes a spec binding.

A spec governs only while something reddens when it is violated. Without that, spec-driven development is document-driven development: progress becomes checked boxes, and the spec's authority is social rather than mechanical. So Shipshape ships the whole loop, not only the spec format:

  • Scenarios give behaviour a falsifiable form.
  • Verification doctrine keeps the green honest: real by default, every test double justified and named, every methodology check proven by a planted red.
  • Planks trace every production seam to the steps that require it, so spec and code cannot drift apart silently.
  • Verification economy keeps the loop cheap enough to run on every change. An expensive truth procedure gets rationed, and a rationed truth procedure stops governing.
  • Fitting out brings an existing codebase under the same discipline, seam by seam.
  • Role custody and the context bulkhead keep discovery chat out of implementation, so the spec stays the single source of intent.

This scope matters more with agents than with humans. An agent is an optimizer pointed at green: when a mock, a weakened assertion, or a vacuous check satisfies the target, the spec holds while the product does not. A human team backfills missing discipline from its engineering culture. An agent has no ambient culture; the discipline is in the harness or it is nowhere.

The position has prior art. Peter Naur's Programming as Theory Building holds that a program is a theory its programmers carry, and that the program dies when the theory leaves with them. A replaceable agent carries nothing between sessions, so the theory cannot live in any head: it lives in durable artifacts or it dies with every context clear. Goodhart's Law names the other pressure: a measure that becomes a target stops measuring, which is why the doctrine treats green as evidence, never proof.

Shipshape spends what agents have in surplus to protect what they cannot be trusted to conserve. Inference, repo-wide upkeep, and re-derivation from durable artifacts are cheap for an agent, so the design uses them freely: planks key on human-readable step text, roles re-derive state instead of remembering it, and Shipwright infers latent structure for Captain to ratify. Honest green, clean context, and current design are what agents cannot be trusted to conserve, so those are guarded by mechanism.

Install

npx skills add dmytri/shipshape --skill '*'

This installs all six skills: /shipshape, /captain, /qm, /crew, /boatswain, and /shipwright.

On agents that Vercel's plugins tool supports, such as Claude Code and Cursor, install Shipshape as a plugin instead:

npx plugins add dmytri/shipshape

The plugin carries the same six skills and adds mechanical enforcement. Plugin installs invoke skills under the plugin namespace, for example /shipshape:captain. See Enforcement and portability.

Quickstart

  1. Start with Captain:

    /captain
    

    No RIGGING.md yet? Captain routes to /shipwright for fitting out first. On a brand-new project this is quick. On an existing codebase it is the thorough scan below: every production seam is planked, every uncovered behaviour inventoried. Captain reviews the results with you before the normal spec-driven loop begins.

  2. Tell Captain the product behaviour you want.

  3. Captain writes or updates .feature specs and writes the watchbill.json entry with each edit.

  4. Clear the agent context, or use a runtime that clears context automatically.

  5. Start Quartermaster:

    /qm
    
  6. QM reads the watchbill, verifies its ordered scope, and dispatches Crew against failing targets.

  7. Boatswain performs hygiene, verification recheck, and local commit custody.

  8. Captain reports back and handles decisions such as push, PR, publish, release, or deploy.

How it works

sequenceDiagram
    participant User
    participant Captain
    participant QM
    participant Boatswain
    participant Crew

    User->>Captain: Describe product intent
    Captain->>Captain: Write .feature specs, watchbill.json
    Captain->>Boatswain: Pre-clean a dirty deck
    Boatswain->>Captain: Stale artifacts flagged
    Note over Captain,QM: Context clears
    QM->>QM: Read watchbill.json, run its scope
    QM->>Crew: Dispatch failing target
    Crew->>Crew: Smallest production change
    Crew->>QM: Target pass
    QM->>Boatswain: Post-implementation hygiene, verify
    Boatswain->>Captain: Deck clean, verify pass, committed
    Captain->>User: Report result, offer outbound
Loading

Shipshape separates agent work by custody and context. Each role sees only the context needed for its job and writes only its own layer.

Role Owns Does not own
Captain Human-facing discovery, .feature specs, assets, CAPTAIN.md, optional watchbill.json Production code, verification, hidden implementation instructions
Quartermaster Verification design, tests, fixtures, step definitions, harness support Product intent, production code, Captain notes
Crew The smallest production-code change for one failing verification target Specs, tests, broad refactors, product interpretation
Boatswain Hygiene, stale artifact flagging, non-code cleanup, verification recheck, local commit custody New behaviour, product decisions, push, PR, publish, release, deploy
Shipwright In-harbour code inspection, @captain candidate scenarios, @planks(...) annotations, safe removal of @shipwright-flagged code Product intent, production-code behaviour changes

On deck, Captain is the only human-facing role. QM, Crew, and Boatswain are internal roles that report through verification output, repository changes, and role hand-offs. Shipwright works off deck in harbour and MAY speak with the user there, because it writes no production code or binding spec; its findings and binding decisions still route to Captain.

The most important boundary is Captain to QM. Captain may use human conversation to discover intent. QM starts from clean context and reads only durable repository artifacts. Discovery chat, rationale, and abandoned ideas never reach tests or implementation.

Progress is not a checked box in markdown. Progress is fewer undefined, unimplemented, or failing verification targets. Verification discovers the worklist; the watchbill scopes what is verified. Passing checks are evidence, not proof. Execution is spent on focused runs, ordered enumeration sweeps, and full regressions. The full regression runs at voyage and harbour pivots, not as the default inner loop. Reports distinguish fresh results from cache-backed results. When no discovered work remains, Captain offers to run the entire test suite across all tiers.

Verification works best when production code exposes narrow behaviour seams. Shipshape discourages hidden product behaviour in global state, constructors, static initialization, and service locators. Seams serve real verification. They never replace normal-path real coverage with mocks, fakes, or test-only branches.

What a session looks like

A user asks Captain:

Let customers pay with a saved card at checkout.

Captain captures the behaviour as a durable scenario:

Feature: Saved card checkout

  Scenario: Customer pays with a saved card
    Given a customer has a saved card
    And the checkout total is "$42.00"
    When the customer pays with the saved card
    Then the payment is authorized
    And the order is confirmed

Captain may focus the next verification pass with watchbill.json:

{
  "watch1": {
    "scenarios": [
      "features/checkout/saved-card-checkout.feature:Customer pays with a saved card"
    ]
  }
}

After context clears, QM reads only durable repository artifacts and runs focused verification. Exact commands come from the adopting project's RIGGING.md. A fitted-out TypeScript project might carry this one:

# Rigging

## Stack

- language: typescript
- runtime: node@22
- packageManager: pnpm

## Directories

- implementation: src/
- specs: features/
- verification: features/steps/, features/support/
- assets: assets/

## Commands

- discover: `pnpm cucumber-js --dry-run --tags "not @captain and not @shipwright"`
- focused: `pnpm cucumber-js "{scenario}" --tags "not @captain and not @shipwright"`
- broad: `pnpm cucumber-js --tags "not @captain and not @shipwright"`
- coverage: `pnpm c8 cucumber-js --tags "not @captain and not @shipwright"`
- step-usage: `pnpm cucumber-js --dry-run --format usage-json`
- plank-inventory: `pnpm jsdoc -X src/`
- typecheck: `pnpm tsc --noEmit`
- lint: `pnpm eslint .`

## Perturbation

- message: `PERTURBATION: consider current durable context; remove when fixed`
- perturb: `throw new Error("PERTURBATION: consider current durable context; remove when fixed");`

## Tiers

- default: @logic
- sandbox: @sandbox
- policy: @sandbox requires test API keys in the environment

## Dependencies

- policy: locked; no new dependencies without a spec

## Outbound

- outbound: npm
- ship: `pnpm publish`
- verify: `npm view <package> version`
$ npm run test:bdd -- "features/checkout/saved-card-checkout.feature:Customer pays with a saved card"

Undefined step:
  When the customer pays with the saved card

QM adds or updates executable verification. If production behaviour fails, QM dispatches Crew with one target:

Target:
features/checkout/saved-card-checkout.feature:Customer pays with a saved card

Failure:
Expected payment status "authorized", received "requires_payment_method".

Crew makes the smallest production-code change:

+ /**
+  * @planks("When the customer pays with the saved card")
+  */
  async function payWithSavedCard(checkout, savedCard) {
-   return payments.createIntent({ amount: checkout.total });
+   return payments.createIntent({
+     amount: checkout.total,
+     paymentMethodId: savedCard.paymentMethodId,
+     confirm: true
+   });
  }

QM reruns the focused check:

1 scenario passed
5 steps passed

Boatswain flags stale artifacts, cleans non-code cruft, reruns configured verification, commits locally, and returns to Captain. Captain reports the result and asks whether to push, open a PR, publish, release, or deploy.

Watchbill

watchbill.json is the verification scope order: Captain limits what QM verifies, and verification output over that scope creates the worklist. It does not create work. Verification still decides what is undefined, unimplemented, failing, or passing. It is the only channel that creates QM targets; a scenario the scope missed waits for the next full regression, pre-outbound or harbour.

Example:

{
  "watch1": {
    "scenarios": [
      "features/checkout/card-payment.feature:Card payment is authorized"
    ]
  },
  "watch2": {
    "scenarios": [
      "features/checkout/refund.feature:Refund returns captured funds"
    ]
  }
}

Rules:

  • Top-level keys are ordered watch groups such as watch1, watch2, and watch3.
  • Each watch contains only scenarios.
  • Each watch entry is a scenario reference in <spec>.feature:<Scenario Name> form or a tier tag directing an unfiltered tier run.
  • QM processes watches in order unless verification, product intent, environment, or tooling blocks.
  • If Watchbill and verification disagree, verification wins.

Traceability

Feature files are canon. Shipshape derives the map from current feature files, through scenarios and steps, into step definitions and production seams.

A seam is a stable production boundary where behaviour can be entered, observed, or owned. Shipshape uses seams for real verification and Planks traceability, not for mocks, fakes, test-only branches, or harness-only code. Trace annotations are hoisted to seams because Planks may be distributed below that boundary.

Planks are the behaviour-bearing production code required by Gherkin step contracts. Shipshape coins the term. An individual plank may be as small as an argument, expression, branch, call, state change, or persisted value. Shipshape does not trace individual planks. It traces plank sets by annotating the smallest stable production seam that owns the behaviour.

/**
 * @planks("When the customer pays with the saved card")
 * @planks("Then the payment is authorized")
 */
export async function payWithSavedCard(checkout, savedCard) {
  // production behaviour
}
Concept Layer Purpose Example
Step Spec Durable product contract When the customer pays with the saved card
Seam Production Stable behaviour surface export async function payWithSavedCard()
Plank Trace Links seam to step @planks("When the customer pays with the saved card")
  • @planks("<Gherkin step>") marks a production seam whose behaviour is required by that exact step.
  • Include the Gherkin keyword. Normalize And and But to the inherited Given, When, or Then.
  • Not every step requires Planks. Every production seam does.
  • A seam may carry Planks for several steps. One step may be carried by several seams.
  • A seam must not contain behaviour outside its related step contracts. Extra behaviour is missing specification, misplaced code, or dead code.
  • Do not trace production code to features or scenarios. Scenario coverage is derived through Cucumber's scenario-to-step mapping.

Trace annotations explain why production seams exist. They do not create work, replace verification, or define product intent.

Perturbation

Perturbation treats the codebase as a reconciled system. Durable specs and context are the declared state, verification is the diff, and a perturbation deliberately marks a seam out of conformance so the normal loop rebuilds it, the way an infrastructure tool taints a resource to force recreation from declared state. The reconciler here is an agent rebuilding from durable context, and the scenarios passing again prove the behaviour survived.

Scenarios pin behaviour. Durable context also carries requirements that leave behaviour unchanged: a Rule: in a feature, a coding standard in AGENTS.md, a dependency or tooling value in RIGGING.md. When such a requirement changes, a seam can pass every step and still fall out of compliance.

A perturbation marks that seam for reimplementation. Captain adds the perturb statement from RIGGING.md at the seam and lists the seam's scenarios in watchbill.json, and the seam becomes a failing verification target. QM discovers the failure and dispatches it like any other. Crew reimplements the seam from current durable context and removes the perturbation statement with the reimplemented seam. The scenarios passing again prove the behaviour survived the rebuild. Boatswain verifies each removed perturbation before commit.

The perturbation statement carries a fixed message and nothing else: no step text, no scenario names, no rationale, no instructions. Requirements stay in durable artifacts.

A perturbation must become a failing verification target. One whose scenarios stay green has discovered an unexercised seam or a stale-green scenario, and Captain reads that from the verification report.

Harbour mode

When adding Shipshape to an existing codebase or between releases, run /shipwright. Shipwright works in-harbour, Crew is off deck. It scans production code with coverage tools and policy checks, then writes @captain-tagged scenario skeletons and @planks(...) annotations. Captain reviews each with the user: promote to a binding spec by removing the tag, or discard by retagging to @shipwright. The next harbour removes the code a @shipwright scenario traces to, then deletes the scenario. QM ignores @captain and @shipwright scenarios.

On an existing codebase, this is a long and painful process. Every production seam is planked, every uncovered behaviour inventoried, every policy violation flagged. There is no shortcut. But when it finishes, the codebase is traced to feature-file steps and ready for spec-driven development. The pain is the point: it surfaces how much of the codebase was undocumented, untested, or accidental.

Tags are workflow state with a bounded lifecycle: the voyage does not resume while @shipwright marks remain, and a completed harbour leaves the tree untagged except for @captain scenarios awaiting review.

sequenceDiagram
    participant User
    participant Shipwright
    participant Captain

    User->>Shipwright: /shipwright, scan this codebase
    Shipwright->>Shipwright: Run coverage, scan for violations
    Shipwright->>Captain: @captain scenarios written
    Captain->>User: Review each scenario, promote/discard
Loading

Structural evolution

Behaviour is not the only thing that drifts. Seams accrete, planks scatter, and structure decays while every scenario still passes. Shipshape treats structural change as first-class, but ships no refactoring engine and no catalogue of code smells. It makes structure legible and lets the project act.

The trace instruments surface structural drift as evidence, not opinion. The plank-inventory command shows planks scattered across many seams, or a seam carrying planks from unrelated steps. Coverage shows a planked seam that no scenario exercises. Optional scantlings constrain approved structure without creating work. Perturbation then rebuilds a seam cluster from current durable context, the same mechanism that carries a requirement change through a clean rebuild.

Shipshape names the quality gate and never the tool, and prefers tooling native to the project's stack over a popular import from another ecosystem. The project brings its own refactoring practice and its own tools. Shipshape keeps the trace honest through the change. This is why it stays small: structural taste lives in the project, and only what the trace can prove lives in the method.

Design position

Plain agent coding often traps product intent in chat. Memory-bank workflows preserve too much stale context. Markdown-heavy spec-driven workflows turn generated plans and task lists into false progress. Agents drift when the same context contains discovery, planning, tests, and code. Old specs, stale tests, and orphaned code pollute future work.

Shipshape answers those failure modes with a small, current-state workflow:

  • Product behaviour lives in .feature specs.
  • Work comes from failing verification over the watchbill's scope.
  • Roles have strict custody over specs, verification, implementation, and hygiene.
  • Context is cleared between Captain and Quartermaster.
  • Boatswain flags stale production artifacts and cleans non-code cruft.
  • watchbill.json scopes and orders what QM verifies. It does not create work.

Disposable does not mean careless. Code and tests must justify their existence against current executable behaviour. Humans edit code at any time. Shipshape has no backlog, no task list, and no agent memory of planned work. Agents derive the next action from current verification state. If you fix a bug by hand, QM sees it pass and moves on. If you break something, QM flags it. There is no stale plan to reconcile.

Boatswain enforces the standards the project writes down. Put code standards in AGENTS.md; unwritten standards do not exist.

The authoritative surface stays small:

  • .feature files define binding product behaviour.
  • Scantlings are optional, machine-checkable constraints such as an OpenAPI or schema file. A scantling creates no work; a scenario references it and asserts a seam conforms. Captain authors a project-owned scantling; a vendored one is read-only.
  • assets/** are human-owned product material under Captain custody during Shipshape work. Product-facing content should live in assets or project-approved content catalogs. Assets and catalogs are not instructions, backlog, rationale, project memory, or hidden requirements.
  • AGENTS.md is the human-facing agent entry document.
  • RIGGING.md holds project tooling values such as stack, directories, commands, and the perturbation statement.
  • CAPTAIN.md, if present, contains Captain-only non-binding notes.
  • watchbill.json scopes and orders what QM verifies.
  • @planks(...) annotations explain why production seams exist. They do not define product intent.
  • Git history preserves history. Current files describe current design.

If asset or catalog content must be protected as behaviour, specify that behaviour in a .feature scenario.

The mechanisms check each other. Perturbation audits what planks claim, planks select each commit's recheck, the context bulkhead keeps perturbation free of rationale, scantlings give the spec a channel for structure that scenarios express badly, the planted-red gate proves every check can redden, and verification economy keeps the loop cheap enough to run on every change. Each mechanism's exposed edge is another mechanism's job.

The vocabulary works with model training, not against it. An established term keeps its established meaning, such as Gherkin and the Meszaros test-double taxonomy, so the trained concept carries the rule. A coined term of art, such as plank, scantling, or watchbill, claims a name no established software meaning contests. A term that fights its trained meaning misleads every fresh context that reads it.

Shipshape is not an IDE, a memory bank, a backlog format, a task-list generator, a project constitution, a code generator, or a replacement for Cucumber. Partial adoption is a non-goal: the workflow is adopted whole, fitted out by Shipwright, not mixed piecemeal into an existing process.

Enforcement and portability

Shipshape skills work anywhere a coding agent can read repository files and follow role instructions. The workflow is portable by design: Cucumber specs, verification output, @planks(...) annotations, and git history carry the durable state.

Skill-only agents follow the rules by explicit discipline. Enforcing runtimes turn the same rules into mechanical checks. Skill-only is the baseline and strengthens as models improve. An enforcing runtime is preferred, and holds the workflow even for small models, because a blocked write and a red check are legible at any capability. This repository ships an optional plugin layer in the vendor-neutral open-plugin format that mechanizes these disciplines on supporting runtimes:

  • Context isolation. Role agents run Captain, QM, Crew, Boatswain, and Shipwright in isolated context windows. The Captain to QM bulkhead becomes mechanical.
  • Custody. Hooks block writes outside each role's write scope, block QM, Crew, and Shipwright from reading CAPTAIN.md and the session transcript, hold local commits to Boatswain, and keep outbound actions in the human-facing main session. Custody hooks bind the role agents. The human-facing main loop stays unrestricted; Captain's discipline is instructional, by design.
  • Rules. The open-plugin rules component carries cited role checklists that restate skill custody for runtimes that attach rules as context. The skills stay canonical; when a rule and a skill disagree, the skill wins.
  • Derived status. The /shipshape:status command reports deck state from repository signals: tree cleanliness, commits ahead of upstream, @captain and @shipwright counts, perturbations, and watchbill validity.
  • Install audit. The /shipshape:doctor command audits the installation itself: completeness of each installed copy, freshness against upstream, and coherence across channels and scopes, so stale or shadowed doctrine is found instead of trusted.
  • Orientation. On session start in a project with RIGGING.md, the plugin injects shipshape.md, a structural map of roles, artifacts, tags, and routing, plus one derived deck-state line suggesting the entry role. The map is non-normative; the skills stay canonical, and tests/map.sh checks its names against them.

The skills remain canonical and sufficient on their own. Every plugin artifact cites the skill text it enforces and adds no doctrine. Removing the plugin loses nothing but enforcement. Enforcement claims are per-runtime and verified downstream: a project that adopts Shipshape on a real coding agent, such as Estelle, exercises the custody and bulkhead mechanisms on that runtime and reports what holds. Live-fire verification belongs in those downstream projects, not in this repository. Unverified runtimes are unsupported for enforcement, never degraded.

Related approaches

Shipshape overlaps with spec-driven development tools, memory-bank workflows, and agent-team systems, but makes different tradeoffs. These tools mostly define the spec format and the change lifecycle. Shipshape also ships the verification doctrine, traceability, and custody that make the spec binding, which is why its instruction set carries more than a format.

Approach Common pattern Shipshape difference
Spec-driven development tools Requirements, plans, proposals, tasks, or implementation phases Current Cucumber specs are the product contract; verification state discovers work.
Memory banks Preserve context across sessions Chat context is discarded; durable repository artifacts carry current intent.
Agent-team systems Use roles, agents, or personas to organize work Roles are custody boundaries, not an organization simulation.
Codegen-first systems Generate or synchronize code from specs Code is disposable from specs, but implementation changes through failing verification targets.

Shipshape combines four ideas: role custody, context isolation, verification as progress, and Cucumber-native traceability.

Related systems include Kiro, Spec Kit, OpenSpec, Tessl, BMAD Method, Superpowers, Paperclip, Fusion, companies.sh, Gastown, and similar systems.

For background, see Birgitta Bockeler's article on SDD tools on Martin Fowler's site: Exploring Gen AI: Spec-Driven Development Tools. For the vocabulary stance, see Semantic Anchors, a catalog of established terms that activate well-defined concepts in models.

Maturity

Shipshape is pre-validation. It has a single author and no published case studies. Skill-only use relies on voluntary agent discipline. The plugin layer mechanizes custody and context isolation on supporting runtimes, and a project that adopts Shipshape on a real coding agent verifies those mechanisms downstream and reports what holds. Shipshape inherits the no-version-pinning supply-chain properties of skills.sh. The ideas are internally consistent and the vocabulary is deliberate, but Shipshape has not yet been proven outside its origin.

Origin

Shipshape was extracted from work done at Saleor, an open-source, headless GraphQL e-commerce platform.

For an agent-oriented way to start Saleor storefront work, see Jolly. Jolly is experimental and should be treated as a preview.

License

BSD Zero Clause License

About

Shipshape is a context-isolated spec-driven development workflow for coding agents. Specs are durable. Code is disposable. Agents are replaceable.

Topics

Resources

License

Stars

5 stars

Watchers

0 watching

Forks

Packages

 
 
 

Contributors

Languages