agentsclimarketplace

Spec sync

Skill chris-peterson/sextant/skills/spec-sync

Reconcile SPEC.md and the source — full-domain coverage + drift analysis, applied as one-way syncs.From its SKILL.md

Install
npx -y skills add chris-peterson/sextant --skill spec-sync

Assembled from the repository path, not quoted from the project. Check it against their README if it does not work.

One thing to look at

  • 0 stars0 stars. Stars are a popularity signal and not a quality one, but at this level it is likely that nobody has read this closely except its author, and you would be relying on your own review.

SKILL.md

13.2 KB, ~3.2k tokens by cl100k_base, as published. Nobody here has run it

Spec Sync

The single skill for understanding and reconciling the relationship between SPEC.md and the implementation. Every run analyzes the full domain — all requirements against all code, in both directions, plus requirement-quality checks — and reports where the contract and the code agree, diverge, or drift.

By default it analyzes and proposes; it writes nothing but the coverage ledger (STATUS.md). When you name a direction, it applies that resolution:

  • --to-spec (source → spec): the code does something the spec doesn't capture. The skill drafts an EARS requirement and routes it through spec-req for your confirmation — it proposes, it does not canonize code into the contract silently.
  • --to-source (spec → code): the spec requires something the code doesn't do. Writing that code is implementation — design, tests, review — not a mechanical sync. The skill produces the gap list and hands off to a development session. It never silently writes code to match a sentence.

Only the ledger is ever written without a judgment call, and that write is delegated to spec-status so the two skills never duplicate it.

%%{ init: { 'look': 'handDrawn' } }%%
flowchart TD
    Start(["/sextant:spec-sync [dir]"]) --> Locate["Locate SPEC.md + impls"]

    subgraph "Step 2: Full-domain analysis (read-only)"
        Locate --> Forward["Forward: spec → code coverage"]
        Forward --> Reverse["Reverse: code → spec drift + orphan check"]
        Reverse --> Quality["Requirement quality: EARS + overly-specific"]
        Quality --> Cross["Cross-impl comparison (if multiple)"]
    end

    Cross --> Classify["Classify each divergence + recommend direction"]
    Classify --> Mode{"Direction flag?"}

    Mode -->|"none (default)"| Plan["Report + reconciliation plan"]
    Plan --> Ledger1["Refresh ledger (spec-status)"]
    Ledger1 --> Done1(["Stop — nothing else written"])

    Mode -->|"--to-spec"| Draft["Draft EARS requirements from drift"]
    Draft --> ConfirmS["Confirm each → spec-req writes SPEC.md"]
    ConfirmS --> Ledger2["Refresh ledger (spec-status)"]

    Mode -->|"--to-source"| Gaps["Build impl gap list"]
    Gaps --> Handoff["Hand to dev session (no auto-code)"]
    Handoff --> Ledger3["Refresh ledger (spec-status)"]

Step 1: Locate spec and implementations

Find the current SPEC.md using the shared discovery order in references/locate-spec.md (that file is the source of truth). In brief, first hit wins: STATUS.md spec-pointer → spec/ directory (incl. vnext/, exploration/, migration/) → justfile spec variable → CURRENT_SPEC_VERSION → root SPEC.md (or docs/spec.md).

spec-sync is always user-invoked and interactive — it is not wired to hooks or called from a release workflow like /ship-it. So if no spec is found, say so and point the user at spec-req init rather than no-op'ing silently:

No SPEC.md found. spec-sync reconciles a spec against code — there's no spec
here yet. Run /sextant:spec-req init to scaffold one.

Read the spec and extract every requirement ID ([XX-NN] format) into a full inventory:

Found N requirements across M categories:
  CM: CM-01, CM-02, CM-03
  OP: OP-01, OP-02
  ...
  FUT: FUT-01, FUT-02 (deferred — excluded from coverage)

Counting rule. Count per references/counting-rule.md (the source of truth): one distinct [XX-NN] ID = one requirement, lettered decompositions (CL-21a, …) each count as one, FUT/deferred and retired IDs excluded. Getting this wrong is the most common STATUS.md drift, so the inventory count must be exact before anything downstream relies on it.

Then locate the implementation(s): the repo root, a versioned implementations/<version>/<impl>/ tree, and any STATUS.md files that already track coverage. A pre-existing STATUS.md is a starting point, not the answer — the analysis verifies whether it's accurate.

Step 2: Full-domain analysis

This is the read-only core. It runs in full on every invocation — there is no narrowed-axis mode. (The analysis is the heavy part of the skill; for a large spec it is a good candidate to delegate to a subagent — pass the spec path and impl root, let it return the structured findings while the main agent works.)

Forward — spec → code coverage

For each non-FUT requirement ID:

  1. Read the requirement text to understand what it specifies.
  2. Search the implementation for evidence — grep the ID in comments/docs, grep keywords from the requirement text, and read the relevant source to verify behavior. Read the actual code; a requirement about "sorting by date" may be implemented without ever naming the ID.
  3. Classify:
    • Covered — implementation satisfies it. Record file(s) and line(s).
    • Partial — some aspects implemented, others missing. Note the gap.
    • Missing — no evidence of implementation.
    • Contradicts — implementation does something different from the spec.

Reverse — code → spec drift + orphan check

Best-effort, from available signals:

  1. Recent commitsgit log for features/behaviors that don't map to any requirement ID.
  2. Session context — decisions made during implementation that never made it into the spec.
  3. STATUS.md notes — existing "spec problem" / "drift" annotations.
  4. Orphaned tracking — a concept plumbed through state / overrides / hooks but never reaching any render surface, output, API, or side effect. When a concept is fully tracked but never surfaced, that's load-bearing context for a removal decision — surface the finding, don't recommend the removal.

Flag anything the code does that the spec doesn't mention as drift.

Requirement quality — EARS + overly-specific

Scan every requirement's text (this needs only the spec, not the code):

EARS conformance. Requirements should use one of the five EARS patterns (see references/ears-patterns.md). Flag non-conforming requirements with a suggested rewrite. Advisory, not blocking — early drafts may be intentionally informal.

Overly-specific. Flag requirements that prescribe how (specific OSC sequences, file paths, library names, hardcoded numbers, internal function names) instead of what. The contract is user-observable behavior; mechanism belongs in implementation notes. Suggest a higher-level rewrite for each.

Cross-implementation comparison

When multiple implementations exist, classify each separately and present a matrix:

| Requirement | impl-1 (Python) | impl-2 (JS) | impl-3 (hybrid) |
|-------------|-----------------|-------------|-----------------|
| CM-01       | Covered         | Covered     | Missing         |
| OP-01       | Missing         | Missing     | Missing         |

A requirement missing from all implementations is a strong signal of a spec problem — the requirement may be unclear or impractical.

When there is no implementation yet

The analysis is simpler: report the full requirement inventory, run the quality checks, flag ambiguous or contradictory requirements, and confirm the spec is ready to build against.

The report

Present findings as a structured report:

## Spec ⇄ Code — <project> (spec <version>)

### Coverage: N/M requirements (X%)

| Status      | Count | Requirements            |
|-------------|-------|-------------------------|
| Covered     | N     | CM-01, CM-02, OP-01, …  |
| Partial     | N     | OP-03, BR-01, …         |
| Missing     | N     | LS-02, CM-04, …         |
| Contradicts | N     | OP-02, …                |
| Deferred    | N     | FUT-01, FUT-02, …       |

### Detailed findings
(for each non-Covered requirement: status, evidence, gap)

### Drift (code → spec)
(undocumented behavior; orphaned tracking)

### Requirement quality
(EARS non-conformance; overly-specific requirements; with suggested rewrites)

Step 3: Classify each divergence by resolution direction

Map every non-aligned item to the direction that should fix it:

DivergenceResolution directionWhat applying it means
Spec requires X, code is Missing it--to-sourceimplement X (dev work)
Spec requires X, code Contradicts (does Y)needs a decisionreword the spec or fix the code — surface, don't pick
Code does Z, spec is silent (drift)--to-specadd a requirement for Z (or decide Z should be removed)
Spec is ambiguous and impls disagree--to-spectighten the requirement text

Contradictions are never auto-resolved in either direction. They are the case where both artifacts make a claim and only a human can say which is right. Surface each with both sides stated; let the user choose the direction.

Step 4: Act on the direction

Default (no flag) — analyze, propose, refresh the ledger

Present the report above plus a reconciliation plan grouped by direction:

→ to-source (spec leads, code missing):  3 items
   [OP-04] retry-with-backoff — no implementation found
   [CM-05] config validation on startup — partial (src/cfg.ts:40, no error path)

→ to-spec (code leads, spec silent):  2 items
   src/export.ts:88 — CSV export; no requirement covers it

⚠ needs decision (contradiction):  1 item
   [UP-01] "system monospace" — code ships a bundled font (src/ui.css:12)

Recommended: run `spec-sync --to-spec` to capture the 2 drift items, then a
dev session for the 3 to-source gaps. Resolve [UP-01] by hand.

Then refresh the ledger (call spec-status) so STATUS.md records current coverage and the open divergences, and stop. The ledger is the only thing the default writes — it leaves the tracker correct without touching spec or code.

--to-spec — capture code into the contract

For each --to-spec drift item:

  1. Draft a requirement in EARS syntax (the spec-req new patterns) describing the observed behavior.
  2. Present it for confirmation — including the option to reject (the behavior might be a bug to remove rather than a feature to document).
  3. On confirmation, write it to SPEC.md via spec-req's create flow (auto-assigned category + number, sorted into the right section).

Never write a requirement the user hasn't confirmed. Capturing code wholesale would canonize whatever the code happens to do — the opposite of spec-leads development. The default lean is source → spec because code usually moves faster than the spec; the confirmation gate keeps that lean from becoming rubber-stamping. After writing, refresh the ledger via spec-status.

--to-source — surface the implementation gap

spec-sync does not write code. For each --to-source item (Missing or Partial requirements where the spec is authoritative), produce an actionable gap list:

Implementation gaps (spec → code):

  [OP-04] When a request fails transiently, the system shall retry with
          exponential backoff. → no implementation. Suggested home: src/http.ts
  [CM-05] config validation on startup → partial; missing the error path.
          src/cfg.ts:40

Then hand off to a development session seeded with this list — a new-feature workflow (or a greenfield one for a fresh implementation). If your setup has the recipe plugin, /recipe new-feature / /recipe greenfield are those workflows; otherwise just start a normal dev session with the gap list. The user (or a dev session) writes and tests the code; spec-status then flips the rows to Covered on the next ledger refresh.

Boundaries

  • Full-domain analysis, every run. No narrowed-axis mode — you always get coverage + drift + quality across the whole spec and code.
  • Bidirectional detection, one-directional application. The default detects both ways and writes only the ledger. Applying is always an explicit --to-spec or --to-source, confirmed per item.
  • Never auto-resolves a contradiction. Both artifacts disagree; a human picks the winner.
  • Never silently writes code. --to-source emits a gap list and hands to a dev session.
  • Never canonizes code without confirmation. --to-spec drafts and asks before writing SPEC.md.
  • Delegates the ledger write. STATUS.md is always refreshed through spec-status, never written directly here.

Related

  • /sextant:spec-status — the lightweight ledger writer. spec-sync delegates every STATUS.md refresh to it. Use it on its own (or wired into /ship-it) for the automatable "just update the tracker" loop, where spec-sync is the deliberate, interactive deep look.
  • /sextant:spec-req--to-spec routes drafted requirements through its create flow; also the place to look up or trace a single requirement. Its init mode is what to run first when there's no spec to reconcile against yet.
  • /sextant:impl-new — scaffolds a candidate whose seeded STATUS.md this skill's analysis reads against.

What ships with it

Read from the repository

Just SKILL.md. No reference files, no scripts.

Keep looking

Skills are one crate of 326,764. Ordering is by how many stacks a row turns up in, so the top of any crate is what has actually been picked rather than what has the most stars.