Skip to content

Releases: developzoneio/specwright

v1.6.0

Choose a tag to compare

@developzoneio developzoneio released this 10 Aug 03:08
06e331f

Added

  • ## Quickstart section in README.md (SW-8) - a numbered path (install -> /sd:setup ->
    /sd:feature <slug>, with the bundled fixture as the fallback for readers with no project handy)
    so a new reader reaches their first spec-approval gate without piecing the flow together from
    separate sections. See the README restructure under Changed below for where this section
    finally landed - it absorbed the install commands outright. Also adds a star / "using this at
    work" call-to-action to ## Support, and nine GitHub topics plus a repo description fix (the
    command count had drifted from what's on disk) via gh repo edit.
  • ## Spawned specs in the feature, bug, refactor, and perf spec templates (SW-42) - follow-up
    work discovered mid-spec previously had nowhere to land except prose, where it evaporated. The
    RCA template's reserved-ID table (Reserved ID | Type | Title | Owner) is now the one convention
    across every spec type, not two. Each affected workflow's close-out prompts for the section
    when the retro names deferred work - a prompt, not a gate: gate counts are unchanged, since
    hard-gating hygiene would tax every spec for a minority's benefit.
    • The section ships with no <<...>> token. It is filled at close-out, i.e. after
      approved, so an author-fill placeholder there would be an SL010 BLOCK on every spec that
      deferred nothing. Header + separator is the empty state, and it is also SL090's trigger.
    • SL090, the first 🟡 SUGGEST rule - a done spec whose body names deferred work with an
      empty spawned-specs table. Advisory, never a failure, and its trigger vocabulary is a closed
      phrase list rather than a judgement call, because an advisory that fires on a hunch is noise.
      SL091-SL099 open the close-out-hygiene band.
    • A reserved ID is not a registry entry. Documented alongside the index consistency rules:
      it gets an .specs/index.md row only once its directory exists. Writing the row first
      manufactures the ghost row SL032 exists to catch - the fourth of the four real-world
      follow-ups that motivated this change was exactly that.
  • /sd:port - the fidelity-first port pipeline (SW-41) - the orchestration story that wires the
    rest of the port epic (SW-37 skill, SW-38 template/snapshot layout, SW-39 extraction mode, SW-40
    parity gate) into one command: bridge/extract -> freeze -> host survey -> fidelity tables -> pin
    behavior -> plan -> execute batched -> justified-diff parity -> close-out. Ten phases, six gates,
    four of them HARD (donor set frozen, fidelity tables complete, behavior pinned, justified-diff
    parity) with no override path; the other two (plan approval, per-batch tests) are ordinary
    approvals. --scope is always explicit - Phase 0 asks when it is omitted rather than inferring
    it, because scope selects the Phase 5 pinning mechanism. --from selects topology (a bridged
    cross-repo contract artifact vs an in-repo path/symbol) without changing anything downstream.
    • Port policy stays Layer 2. Phase 0 reads a Port policy heading from the host's
      .specs/constitution.md and always states the effective policy in its output, including the
      fallback (structural mirror, per sd-port-fidelity) when the host declares nothing - the
      engine supplies the mechanism, never a hardcoded posture.
    • Behavior pinning is scope-dependent and gate-verified. endpoint gets a contract test
      suite runnable against both donor and host; module gets characterization tests through an
      interface-typed construction seam, so re-pointing donor -> host changes exactly one factory
      method and assertion bodies stay byte-identical; feature uses whichever the surface allows;
      pattern skips pinning (no donor instance) but the gate still proves the host production tree
      is unmodified via an empty git diff / git status --porcelain, not a good-faith claim.
    • A port-specific complexity metric. The existing decompose thresholds count impacted files
      and layers, which trip on nearly every port by construction (a port's file count equals the
      donor's). Phase 6 instead counts deviation-table rows requiring adaptation - the quantity that
      actually scales with how much judgment the work needs - and records the rationale in
      01-plan.md.
    • The anti-drift mechanism lives in the task block, not the gate. Every port task's Pattern refs cites a snapshot member range (04-artifacts/source/<path>:<first>-<last>), never prose
      and never a host sibling, and Acceptance carries the licensed-deviation ID list. Anything not
      on that list is reproduced as-is. A task missing either is a planning defect, refused before
      execution rather than caught only at the parity gate.
    • Lifecycle divergence, deliberate. Unlike /sd:feature and /sd:refactor, abort never
      jumps a port spec to archived - it leaves the spec at its current state so re-invoking resumes
      exactly there, since a partially-frozen or partially-pinned port has no clean "give up" shortcut
      the way an unstarted feature does.
    • WORKFLOW_TYPE = port added to sd-implementer - neither feature (allows new public API
      freely) nor refactor (forbids new public API, requires INVARIANTS) was the right constraint
      set for reproducing a donor's structure under a licensed-deviation list, so this is a genuine
      fifth mode, not a reuse of an existing one.
    • port joins the prompt-router keyword map (backport, port from, port the, donor repo, mirror from, replicate from - deliberately multi-word phrases; a bare "port" would
      fire on "support", "report", "portal"), shipped in both hook implementations plus the
      project-config.template.json default.
    • contractLint.budgets.skillsBytes raised 12377 -> 12412 - skills/sd-port-fidelity/SKILL.md
      picked up two small cross-references to /sd:port's phases (the freeze step, the fidelity-table
      author) replacing prose that pointed at "a documented manual step until the port pipeline
      lands"; the ratchet moves with it.
    • Deliberately NOT built: --sync / re-port drift detection, multi-donor ports, and editing a
      host project's build/lint/coverage configuration to exclude the snapshot - the command warns
      about tooling that globs .specs/, it never edits.
    • Known gaps carried forward: no SL06x rule machine-checks the port task-block contract
      (Pattern refs range + licensed-deviation list) - it is enforced by Phase 6 refusing to execute a
      defective block, not by /sd:spec validate; and spec-gate/subagent-retro still do not
      recognize the PORT- prefix (only prompt-router's keyword routing landed this round) - see
      docs/troubleshooting.md. PROJECT-SNAPSHOT.md does not exist in this repo and never has (see
      the historical note below); nothing in this change introduces it.
  • Port parity adjudication: port-parity TASK_TYPE on sd-reviewer, the parity diff artifact,
    and the parity gate
    (SW-40) - the enforcement half of the port epic and the only mechanism in
    it that can see logic drift, structural mismatch, or silent simplification; test-green and
    contract compliance are blind to all three, which left the fidelity rules from SW-37 as
    honour-system prose. The main thread writes 04-artifacts/parity/: one unified diff per
    non-omit path mapping row, an all-deletion diff for a row whose host file is absent, an
    all-addition diff for a changeset file with no row at all, plus INDEX.md listing them.
    sd-reviewer consumes INDEX.md as DIFF_REF and classifies every hunk with
    sd-port-fidelity's vocabulary, now five classes rather than four. overreached is the new one -
    a deviation row covers the hunk but the hunk changes more than that row's Host form states -
    and it is the class a rubber stamp hides in. Two whole-artifact checks join it: member
    completeness, reported as a count with each absent row named, and path conformance, one BLOCK per
    unmapped changeset file. A justified hunk is a PASS and is deliberately NOT written up, so a
    real BLOCK cannot drown in a list of accepted diffs. templates/specs/port.template.md's fixed
    AC-1 gains overreached and a Host form-covers-the-hunk clause: reworded to track the skill's
    vocabulary, never renumbered, because the number is what every fidelity finding anchors to.
    • Diff generation stays on the main thread, enforced by the tool allowlist - sd-reviewer
      gains no Bash and no write tool and stays in contractLint.readOnlyAgents (CL201). The
      reviewer that cannot produce the diff also cannot fix what the diff shows; adjudicating from a
      file it did not write is the entire structural guarantee.
    • The /sd:verify overlap, decided before any checking logic was written - member
      completeness and path conformance stay with the reviewer and /sd:verify is untouched, no new
      VF0xx rule. Rationale recorded in docs/architecture.md: /sd:verify decides everything from
      00-spec.md and 02-tasks.md with fixed regex shapes, and neither check can be decided that
      way - one needs a member boundary recognized in an arbitrary host language, the other needs a
      changeset input /sd:verify does not take.
    • Deliberately NOT built: semantic equivalence checking, which is the behavior-pinning
      phase's job rather than the diff's, and auto-generation of deviation rows from unexplained
      hunks, which would let the diff justify itself and turn the gate into a rubber stamp. The gate
      stays HARD with exactly two resolutions - revert the host toward the snapshot, or add a
      deviation row whose group and citation hold up and re-run - and no override.
    • Known gap: the pipeline command that would generate the parity artifacts and host the gate
      is SW-41. Until it lands, diff generation ...
Read more

v1.5.0

Choose a tag to compare

@developzoneio developzoneio released this 23 Jul 16:14
7125fcc

Fixed

  • Three CI-only failures surfaced by PR #23, none reachable from a real install. (1)
    scripts/validate.sh Check 7 used declare -A and mapfile (both bash 4+), which crash on
    macOS's stock /bin/bash 3.2 (declare: -A: invalid option, then mapfile: command not found
    once the first was fixed) - rewritten as plain indexed arrays with linear-scan
    q_get/q_set/fp_get/fp_append lookup helpers and a while read loop in place of
    mapfile, no behavior change. (2) The
    "Lesson validator (PowerShell)" CI step asserts the leaky fixture correctly FAILS validation,
    but GitHub Actions appends an implicit exit $LASTEXITCODE to every pwsh step, so the
    intentional non-zero exit code from the leaky-fixture check failed the step even though the
    assertion itself passed - fixed with an explicit exit 0 after the assertion. (3)
    tests/hooks/run-conformance.ps1's -SelfTest stub bash script exits immediately without
    reading stdin, and writing the JSON payload to its now-closed pipe raised an unhandled
    IOException: Broken pipe on Linux runners - Invoke-HookProcess now wraps the
    StandardInput.Write/Close pair in a try/catch, since a child that never reads its input is
    not a harness failure.

Added

  • /sd:status - a read-only reader for the metrics log (SW-16). SW-10 has been accumulating
    .specs/_metrics/events.jsonl with no consumer; the data existed and was invisible. The new
    13th slash command summarises the live log plus .specs/index.md: specs in progress, gate
    activity broken out by kind (verify / protected / code-edit) and decision
    (allow / warn / block), lifecycle transitions, and a friction section ranking where the
    operator is actually stuck - which specs are blocked most, which code-edit warns are being
    ignored, which specs accumulate stale retros, and which in-progress specs are absent from the log
    entirely. Read-only: no spec is created, no gate is evaluated, nothing is written.
    Three decisions are worth recording because they diverge from a naive reading of the ticket.
    (1) jq is an oracle, not a runtime dependency. The acceptance criterion "counts reconcile
    against jq" reads like a dependency; it is not. The schema is flat, metadata-only and written in
    fixed key order, so exact substring counting is deterministic - and jq aborts on a
    partially-written line, which would lose the whole report to one interrupted append, exactly what
    the ticket forbids. jq verifies the numbers; it does not produce them.
    (2) Counting is delegated to the shell, never to eyeballing. A capped log is ~8000 lines;
    the command prescribes the exact count commands rather than asking for a summary, because a
    number that was estimated cannot reconcile with an independent count.
    (3) The live file only - events.jsonl.1 is noted in one header line and never read, per the
    read contract set in SW-15.
    Every degrade path is a labelled state (ST001-ST005): no config, metrics disabled, log
    absent, log empty. A blank report would read as "no friction", so an empty table is treated as a
    defect rather than an edge case. Malformed lines are skipped and counted, and the skipped
    count is always shown - a silent skip and a clean file are not the same fact.
    Verification corpus at tests/metrics/ (populated / malformed / empty fixtures, expected numbers,
    and the jq oracle procedure), pinned to LF in .gitattributes. It is documented as a manual
    corpus: commands/status.md is a prompt file and CI cannot execute it, so it is deliberately not
    wired into scripts/validate.*.

  • Size cap and single-generation rotation for the metrics log (SW-15). A new hooks.metrics.maxSizeKb
    (default 1024 KB, ~1 MB) bounds .specs/_metrics/events.jsonl: before each append, if the live
    file already meets or exceeds maxSizeKb * 1024 bytes, the hook rolls it to events.jsonl.1
    (single generation - any previous .1 is overwritten) and starts fresh. Implemented in all four
    metrics writers (spec-gate and subagent-retro, PowerShell and bash) so the two platforms roll
    at the same raw-byte boundary ((Get-Item).Length / wc -c). Inherits every SW-10 invariant:
    rotation is best-effort and never stops the append (a silent stop would read as "metrics
    working" while dropping data - worse than unbounded growth, per the ticket), a failed roll (locked
    file on Windows, read-only dir) is a silent no-op, and it never alters a gate decision or the
    hook's exit code. An absent maxSizeKb is treated as 1024, so a project-config.json
    written before this feature stays bounded with no edit; an explicit 0/negative disables rotation,
    and any non-number is invalid and also disables it (SW-22 type-strictness). events.jsonl.1 is a
    grace buffer, not part of any read contract - there is no consumer of the log today, and when
    one exists it reads only the live file. Added to templates/project-config.template.json and both
    hooks' embedded default configs; documented in docs/architecture.md and docs/troubleshooting.md.
    New conformance fixtures at tests/hooks/fixtures/{spec-gate,subagent-retro}/metrics-rotates-at-cap
    and .../metrics-rotation-failure-noop prove PS and bash rotate identically.

  • Sanctioned mid-execution re-plan loop (SW-14). A new sd-replan-loop skill defines a HARD Gate
    Re-plan
    for the two workflows that produce a 01-plan.md + 02-tasks.md pair - /sd:feature
    and /sd:refactor - so a plan-invalidating discovery adapts the plan without violating
    immutability or skipping a gate. The gate is reachable from both the Execute phase and the
    batch/holistic review (the one real corpus failure surfaced at review, not mid-task). On
    approval it appends an R<n> entry to an append-only ## Revisions log at the end of 01-plan.md
    (original plan prose left intact), regenerates only the affected task blocks in 02-tasks.md
    via sd-spec-architect (TASK = plan with REPLAN_SCOPE, no new architect mode), and marks each
    regenerated task Revised-by: R<n> (a conditional field in sd-atomic-task-format, like refactor's
    Parallel batch). Like Gate Complexity, it is a conditional gate that fires only on its trigger,
    so /sd:feature still advertises 3 hard gates and /sd:refactor still 6. It never re-plans a
    done spec. Scope was corrected from the ticket on evidence: /sd:bug and /sd:rca produce no
    task list to re-plan, and /sd:perf already carries its own revert-and-reselect loop, so all three
    are left untouched. See docs/adr/0003-adaptive-replan-loop.md.

  • SL070-SL073 in /sd:spec validate: a new revision-log integrity band cross-checking the
    ## Revisions log in 01-plan.md against the Revised-by markers in 02-tasks.md. SL070
    (dangling marker), SL071 (one-sided/unreferenced revision), and SL072 (broken append-only
    history) are 🔴 BLOCK; SL073 (malformed entry) is 🟠 WARN. The checks run only when a ## Revisions
    section or a Revised-by marker exists, so a never-re-planned spec produces no finding. SL074-
    SL079 reserved. Honest boundary recorded in the ADR: validate is a static linter with no
    Plan-phase snapshot, so it enforces the revision record's internal consistency but cannot detect an
    unmarked silent edit by diffing - that is prevented by the gate, not the lint.

  • Conformance fixtures at tests/revision-log/fixtures/ (SW-14): a valid revision record that passes
    and a dangling-marker record that must BLOCK, pinned to LF via .gitattributes. They state the
    contract; like the other fixture trees they have no runner (documented, not silently skipped).

  • Complexity triage + forced decomposition in /sd:feature (SW-13). The architect writes a
    spec-level complexity frontmatter field (S | M | L, distinct from a task's
    Estimated complexity) with a one-line rationale at create time. Gate 2 then measures the actual
    plan against decompose thresholds - **> 8 tasks, > 2 production layers (Tests/Config excluded),

    8 impacted files, or an unresolved Open question** (the > 8 line set from the corpus canyon
    between 3-4-task and 10-12-task specs; the Tests/Config exclusion keeps ordinary 2-layer mediums
    under threshold).
    Over threshold, Gate 2 becomes a HARD Gate Complexity that refuses one oversized plan and
    forces a split into medium child specs (FEAT-<parent-arg>-<child-slug>, linked via existing
    /sd:spec link spawns / depends-on; the parent becomes an immutable archived umbrella). Under
    threshold it stays the normal plan approval with zero added friction - still 3 hard gates, not

    1. A create-time complexity: L also escalates models a tier (explorer -> sonnet, architect ->
      opus, aliases only, per-invocation), deepening the impact map and plan for genuinely large work.
      Task counts use the tolerant sd-atomic-task-format heading grammar, not a naive ### T<NN>
      regex. See docs/adr/0002-complexity-triage-decomposition.md. Linting of the field + split
      integrity is deferred to SW-4 (/sd:spec validate).
  • Field label grammar in sd-atomic-task-format (SW-11). Task-block labels are now matched
    case-insensitively, with ** optional and the colon permitted inside or outside the emphasis -
    all three forms found in live specs (- **Files**:, - Files:, - **Files:**) parse
    identically. A field's value runs to the next field label, not the next newline, so multi-line
    Acceptance and Pattern refs values are no longer truncated. The grammar is defined once and
    applies to every field and every reader; per-field matchers are forbidden.

  • SL060 (WARN) in /sd:spec validate: a task block in 02-tasks.md with no Pattern refs
    field. SL061-SL069 reserved for further task-block content rules. This is the first rule
    that reads inside a spec artifact rather than around it - see...

Read more

v1.4.0

Choose a tag to compare

@developzoneio developzoneio released this 05 Jul 08:09
7fb8e1c

Added

  • ROADMAP.md - published roadmap of near-term, planned, and exploratory work, linked from
    README.md (new ## Roadmap section + Documentation entry). Migrated the forward-looking items
    out of the non-standard ### Planned subsection that sat under the 1.2.0 changelog entry into
    this dedicated file.
  • /sd:setup codebase scan (Phase 2.5) - samples the project tree to pre-fill detected facts
    (stack, paths.{src,tests,docs}, commands.* from the project manifest, and a new ordered
    inside-out paths.layers map) into CLAUDE.md and project-config.json, with a single batch
    confirmation gate. Facts only - constitution rules are never auto-filled. Adds paths.layers to
    templates/project-config.template.json.
  • /sd:adr command (11th) + sd-docs-writer agent (6th) - drafts a numbered, MADR-style Architecture
    Decision Record under .specs/_adr/ from a spec's 03-decisions.md (or an ad-hoc decision), behind one
    hard approval gate. The agent (model sonnet, tools Read/Write/Glob/Grep, skill sd-evidence-citation)
    writes only the ADR file and never invents decisions; the command owns numbering and supersession links.
    Bumps command count 10 -> 11 and agent count 5 -> 6 across docs and the validators.
  • scripts/smoke-hooks.sh + scripts/smoke-hooks.ps1 - pipe fixture Claude Code hook JSON into
    prompt-router, spec-gate, and subagent-retro against a temp .specs/ tree and assert exit
    codes AND key output substrings, not just "did not crash": keyword-match routing (bash and
    PowerShell must agree), spec-gate allow/warn/block across in-progress / header-only-marker /
    docs-edit / malformed-stdin cases, and subagent-retro naming the real spec ID then debouncing a
    second run. .github/workflows/ci.yml adds macos-latest to the OS matrix (exercising the
    BSD-specific stat -f %m / date -j -f fallback branches that only run there) and a smoke-test
    step on every OS.

Changed

  • Removed hardcoded MSSQL/C#/TS references from agents/debugger.md, commands/perf.md,
    commands/rca.md, and commands/bug.md, per CLAUDE.md's stack-agnostic rule. sd-debugger's
    tool allowlist no longer bakes in mcp__mssql__execute_sql; its "Database discipline" section
    (renamed from "MSSQL discipline") now describes the same read-only SELECT/EXPLAIN discipline
    generically, deferring to whatever database MCP tool or CLI client the project provides.
    templates/project-config.template.json's mcp.mssql entry is renamed to mcp.database.
    perf.md/rca.md generalize "MSSQL access (via MCP)" to "database access (via the project's
    MCP tool or CLI)"; perf.md's final-review check drops the C#/TS-specific dynamic/any
    example in favor of "type-safety escapes for the project's language (as defined in
    constitution.md)"; bug.md's failing-test step now references paths.tests from
    project-config instead of a hardcoded tests/<mirrored path>/ with a C#-style example name.
  • De-duplicated rules that were copy-pasted from skills into agent bodies and commands (CLAUDE.md:
    "a rule used by multiple agents lives in one SKILL.md, never copy-pasted"), replacing each
    copy with a reference to the owning skill: agents/debugger.md's and agents/reviewer.md's
    Anti-patterns sections no longer restate sd-hypothesis-tree/sd-severity-taxonomy/
    sd-evidence-citation (role-specific bullets are kept); agents/code-explorer.md's
    Anti-patterns section no longer restates sd-evidence-citation. commands/feature.md and
    commands/refactor.md no longer inline the atomic task-block format - both now point at
    sd-atomic-task-format, which gains a documented "Refactor mode" Parallel batch field (the
    field refactor.md's inline copy had already drifted to include while feature.md's copy
    lacked it). commands/bug.md and commands/rca.md no longer restate the 5-mental-models /
    (Likelihood x Impact) / Cost-to-verify method inline - both now point at sd-hypothesis-tree.
  • scripts/validate.sh and scripts/validate.ps1 now derive their expected install-target
    counts (commands / agents / skills / hooks / templates) from the source tree instead of
    hardcoding them as literals in both files - a new command/agent/skill/template only needs to
    land in its source dir, never a constant bumped in two scripts (this already bit PR #12, which
    had to bump both). Each derived count is asserted > 0 so an empty or misnamed source dir
    fails loudly instead of vacuously passing Check 5.

Fixed

  • hooks/bash/prompt-router.sh emitted - /sd:0 instead of - /sd:<workflow> under bash 3.2
    (macOS system bash): declare -A is a bash-4 feature, so the associative arrays silently
    degraded to indexed arrays with all string subscripts arithmetic-evaluating to 0. Caught by
    the macOS CI smoke test (validate (macos-latest) was red since the matrix gained macOS).
    Rewrote keyword matching with parallel indexed arrays; the hook is now bash-3.2 compatible.
  • hooks/powershell/subagent-retro.ps1's debounce silently stopped persisting/reading state on
    PowerShell 7+, found by writing scripts/smoke-hooks.ps1: (1) Save-State's
    Split-Path -LiteralPath $StatePath -Parent throws "Parameter set cannot be resolved" on some
    PS7 builds (-LiteralPath there has no -Parent parameter set) - the surrounding try/catch
    swallowed it, so the state directory/file were never written; switched to Split-Path -Path
    (safe here - -Parent does no filesystem globbing, only -Resolve would). (2) Even once the
    state file wrote, Test-DebounceElapsed re-broke: PS7's ConvertFrom-Json auto-converts an
    ISO-8601 ...Z string to a [datetime] (PS 5.1 leaves it as a string), and re-Parse-ing an
    already-converted [datetime] stringifies it with the local culture - dropping the UTC marker -
    so [datetimeoffset]::Parse silently re-interpreted it as local time, skewing $age by the
    machine's UTC offset exactly like the bug fixed earlier in this file, just triggered a different
    way. Both are PowerShell-only; hooks/bash/subagent-retro.sh was unaffected (no bash twin
    change needed).
  • install/install.sh hardening: aligned to set -euo pipefail (was set -e only, so unset-
    variable typos and mid-pipeline failures - e.g. a sha256sum/shasum error - passed silently;
    those two pipelines now end || true since a hash-tool failure is expected-recoverable, not a
    reason to abort); added the same --prefix safety guard uninstall.sh already had (empty,
    /, \, or .. components rejected) to install/install.ps1 too, so install and uninstall
    accept the same set of prefixes on both platforms - previously only uninstall validated it, so
    --prefix ../evil would have written outside the intended tree; quoted the unquoted
    rel="${f#$src_root/}" strip pattern (glob-interpreted $src_root broke on a repo path
    containing [, *, or ?); and added an ERR trap that reports how many files already
    landed and the exact uninstall.sh command to run if a copy fails mid-install (no full
    transactional rollback - per-file .bak.* backups already protect overwritten files).
  • Post-1.3.0 docs drift: README.md's tagline said "Ten slash commands, five specialized
    subagents" (now eleven / six); the Commands table was missing /sd:adr and listed
    /sd:feature at 4 hard gates (the merged review+integration gate makes it 3); the Agents table
    was missing sd-docs-writer and listed a hardcoded MSSQL tool for sd-debugger; the .specs/
    tree diagram omitted _explorations/, _reviews/, _adr/; the Roadmap highlights repeated two
    items that already shipped. ROADMAP.md's ## Planned section still listed the /sd:setup
    codebase scan and sd-docs-writer agent, both shipped in 1.3.0+ (CHANGELOG is the source of
    truth for shipped work). docs/usage.md's Utility commands section had no /sd:adr entry.
    templates/project-config.template.json's workflow.gates.feature still listed the pre-merge
    4-gate sequence; collapsed to 3 and marked _comment-descriptive since no hook or command reads
    the block. CONTRIBUTING.md's agent frontmatter example omitted the mandated color: and
    skills: fields. examples/README.md gated a promised-features list on "not in v1.0.0", three
    minor versions after v1.0.0; reworded to point at ROADMAP.md.
  • Phase 0 of /sd:feature, /sd:bug, /sd:refactor, /sd:perf, and /sd:rca now guards
    against missing or malformed Layer-2 context instead of silently reading CLAUDE.md,
    .specs/constitution.md, .claude/project-config.json, and .specs/index.md and letting
    later phases fail on undefined config values. Missing .specs/, .specs/constitution.md, or
    .specs/index.md now STOPs with "No .specs/ found - run /sd:setup first." (matching
    spec.md/release.md/adr.md); malformed .claude/project-config.json STOPs naming the file;
    a missing CLAUDE.md only WARNs and continues, since the constitution (not CLAUDE.md) is the
    binding Layer-2 contract - matching the stance the four utility commands already took.
  • sd-code-explorer's impact-map task no longer instructs the agent to APPEND to
    OUTPUT_APPEND_TO - its tool allowlist has no Write/Edit, so it physically could not
    perform that write, silently starving 03-decisions.md (and everything downstream that reads
    it as IMPACT). The task now returns the structured analysis as final output; the informational
    OUTPUT_TARGET input names the file, and the calling command appends it. commands/feature.md
    and commands/refactor.md each gained an explicit main-thread append step after the impact-map
    invocation. commands/perf.md, commands/bug.md, and commands/rca.md's equivalent
    "Append ... to 03-decisions.md" steps after sd-debugger invocations (also write-tool-less)
    are now explicitly labeled as main-thread steps for the same reason.
  • /sd:bug, `/sd:rca...
Read more

v1.3.0

Choose a tag to compare

@developzoneio developzoneio released this 18 Jun 04:21
dbce5a5

Release-tooling and CI hardening. Adds the /sd:release command (10th), a single-command repo invariant validator with a Windows + Ubuntu CI matrix, an uninstaller, and a batch of command/agent refinements.

Added

  • /sd:release command (10th command) - generates release notes from completed specs: collects every spec in done status (feature / bug / refactor / perf; RCA excluded), groups them into Keep-a-Changelog sections (FEAT -> Added, BUG -> Fixed, REF/PERF -> Changed) under an inferred SemVer heading (any feature -> minor bump, else patch; major never auto-inferred), then transitions each done -> archived. One hard gate previews the notes and the archive plan before any write; --dry-run stops before writing. Pure file ops, no subagent (mirrors /sd:spec). Gives the done (merged, unshipped) vs archived (shipped) states a concrete meaning.
  • scripts/validate.ps1 + scripts/validate.sh - one command that runs every documented engine invariant: pure-ASCII scan of *.ps1, bash -n on *.sh, hook-pair parity, agent model: alias-only check, install-target file counts (real install to a temp base), and a non-empty [Unreleased] CHANGELOG gate. Exit 1 on any failure.
  • .github/workflows/ci.yml - runs validate on push/PR across a Windows + Ubuntu matrix, plus an install -> uninstall round-trip per the CLAUDE.md sandbox recipe.
  • install/uninstall.ps1 + install/uninstall.sh - removes the five <base>/<area>/sd/ directories with dry-run preview, confirmation prompt (-Force/--force to skip), and per-project cleanup reminders (.claude/settings.json hook wiring, .claude/.hookstate/).

Changed

  • scripts/validate.{ps1,sh} Check 6 now treats an empty [Unreleased] section as passing when the section immediately below it is a dated [x.y.z] - <date> release heading (the freshly cut version), so a clean post-release CHANGELOG no longer fails CI. A non-release-state empty [Unreleased] still fails, preserving the "every PR adds a changelog line" invariant.
  • /sd:perf Gate 6 now structurally refuses a no-measurable-gain "keep" instead of merely warning about it in prose. The gate branches on the noise check: a measurable improvement still offers keep / revert, but a within-noise result defaults to revert and allows keep only as an explicit logged constitution exception (decision kept (exception) + a reason recorded to 05-retro.md). With no reason supplied, the change is reverted.
  • docs/architecture.md gains two reference sections: a "Command -> agent routing" tree showing the subagent fan-out per command (and the three file-ops commands that invoke none), and an "Artifact ownership" table mapping each .specs/<ID>/ file to its producing phase/agent and downstream readers. Consolidates routing/ownership that previously lived only in scattered command files.
  • /sd:setup Q1 and the sd-spec-architect ticket protocol now state explicitly that automatic ticket-context fetch is JIRA-only: GitHub Issues and Linear are still recorded as the project tracker (for prompt-hook ID recognition), but their ticket content is not auto-fetched - paste it into the prompt instead. The ticket snapshot protocol is documented as JIRA-specific. Closes the silent degradation where non-JIRA projects got no ticket fetch and no explanation.

Fixed

  • /sd:spec status now spells out the illegal-transition refusal instead of the vague "REFUSED with explanation": it prints the current state, the requested state, the valid next state(s) from the state machine, and the shortest legal path to the requested state when reachable (e.g. draft -> done is rejected with the hint draft -> approved -> in-progress -> done). No file is mutated on refusal.
  • /sd:bug Phase 3 no longer assumes a confirmed root cause always arrives. The investigation loop previously said "Continue until one is CONFIRMED" with no exit, so a bug whose every hypothesis is rejected/inconclusive had no defined stopping point. Added Gate 3a (hypothesis tree exhausted): the loop now terminates on a CONFIRMED hypothesis OR an exhausted tree, and the exhausted case STOPs and asks the user to re-enumerate (with new evidence), add observability, or abort as "root cause not found" - never guessing a fix from an unconfirmed tree.
  • install/install.sh marked executable (mode 100755, matching uninstall.sh); it was 100644, so the documented ./install/install.sh invocation failed with "Permission denied" on a fresh Linux checkout. Surfaced by the new CI round-trip.
  • install/README.md: total file count corrected (21 -> 32), skills/sd/ added to the layout tree, install table, and manual uninstall commands (skills were missed since 1.1.0), and the -Prefix/--prefix option documented.

v1.1.0 — Agent Skills + dual-format hooks

Choose a tag to compare

@developzoneio developzoneio released this 03 Jun 16:45

Spec-driven development workflows for Claude Code.
Nine slash commands, five specialized subagents, three guard-rail hooks, nine templates, five reusable skills — all under the sd: namespace, stack-agnostic, cross-platform, and ready to drop into any project.

This is the initial public release on the specwright name. It bundles the rebranded engine (originally ck-spec-system) with the v1.1.0 architecture refresh: a new Agent Skills layer and a forward-compatible upgrade to the spec-gate hook contract.


Highlights

  • Agent Skills layer (new) — 5 reusable markdown rule packs that agents reference from YAML frontmatter. De-duplicates rules across agents, shrinks prompt bodies, and makes canonical rules auditable in one place.
  • Dual-format spec-gate output — emits both the new hookSpecificOutput.permissionDecision and the legacy decision field. The same hook works across Claude Code CLI versions; no runtime version probing.
  • All assets namespaced under sd:/sd:feature, sd-reviewer, skills/sd/, etc. Removable without touching the rest of your ~/.claude/.
  • Stack-agnostic — agents read CLAUDE.md and constitution.md at runtime; no hardcoded language, framework, or layer assumptions.
  • Cost-aware models — Sonnet for reasoning (spec, debug, review), Haiku for execution (implementer, explorer). Typical feature run lands around $2–$3.

What's included

Component Count Names
Slash commands 9 /sd:feature, /sd:bug, /sd:rca, /sd:refactor, /sd:perf, /sd:spec, /sd:explore, /sd:review, /sd:setup
Subagents 5 sd-spec-architect, sd-code-explorer, sd-debugger, sd-implementer, sd-reviewer
Skills (new in 1.1.0) 5 sd-severity-taxonomy, sd-hypothesis-tree, sd-atomic-task-format, sd-evidence-citation, sd-spec-templates
Hooks 3 prompt-router, spec-gate (dual-format), subagent-retro
Templates 9 4 setup + 5 spec (feature / bug / refactor / perf / rca)

Cross-platform: matching PowerShell + bash pairs for every hook. Content-hash-deduped installer with timestamped backups and dry-run preview.


New in 1.1.0

Agent Skills (new skills/sd/ layer)

A skill is a markdown rule pack referenced by agents from YAML frontmatter:

---
name: sd-reviewer
model: sonnet
skills:
  - sd-severity-taxonomy
  - sd-evidence-citation
---
Skill Used by Purpose
sd-severity-taxonomy sd-reviewer Severity rules (BLOCK / WARN / SUGGEST / PASS) and the mandatory review output format.
sd-hypothesis-tree sd-debugger Enumerate / verify protocol with the 5 mental models, (L × I) / C score formula, and the proximate-vs-root "why" ladder.
sd-atomic-task-format sd-spec-architect, sd-implementer The 9-field atomic task block plus canonical enums (Step type, Complexity, Reversibility).
sd-evidence-citation sd-code-explorer, sd-debugger, sd-reviewer file:line citation discipline, snippet length, evidence taxonomy, grouping.
sd-spec-templates sd-spec-architect Per-template authoring rules (feature / bug / refactor / perf / rca); which cross-phase fields to leave empty.

A skill is not an agent. It cannot be invoked directly, has no tools of its own, and produces no output on its own. It is a context block the agent inherits.

Agent frontmatter

  • All 5 agents declare a skills: [...] list.
  • All 5 agents declare a color: field for terminal rendering.
  • Agent prompt bodies shrank where content moved into a referenced skill (lookup discipline preserved).

Hooks — dual-format spec-gate block output

spec-gate.sh and spec-gate.ps1 now emit a single JSON object that carries both schemas:

{
  "decision": "block",
  "reason": "spec-gate: editing code file 'src/foo.cs' but no in-progress spec is recorded ...",
  "hookSpecificOutput": {
    "permissionDecision": "deny",
    "reason": "spec-gate: editing code file 'src/foo.cs' but no in-progress spec is recorded ..."
  }
}
  • New schema (hookSpecificOutput.permissionDecision = "deny") is read by recent CLI builds.
  • Legacy schema (decision = "block") is read by older CLI builds.
  • Both are harmless to the other reader. No version probing required.

Installer

  • Both install/install.sh and install/install.ps1 now wire skills/<prefix>/ alongside commands/, agents/, hooks/, templates/.
  • Dry-run verified: 31 files planned on a fresh install.
  • --prefix flag (defaults to sd) lets you namespace under a different prefix if you collide with another tool.

Documentation

  • README.md — new Skills section + updated Layer 1 diagram.
  • docs/architecture.md — new Agent skills section + dual-format hook schema note.
  • docs/history/ — archived UPGRADE-PLAN.md + REMAINING-WORK.md so future readers can see how this upgrade was scoped (6 phases, file-touch matrix, decision log).

Install

Windows (PowerShell 5.1+):

git clone https://github.com/developzoneio/specwright.git
cd specwright
.\install\install.ps1 -DryRun   # preview
.\install\install.ps1           # install to $env:USERPROFILE\.claude

macOS / Linux (bash 4+):

git clone https://github.com/developzoneio/specwright.git
cd specwright
./install/install.sh --dry-run  # preview
./install/install.sh            # install to ~/.claude

Then in any project:

cd <your-project>
claude
> /sd:setup

/sd:setup is interactive (3 questions at most) and scaffolds CLAUDE.md, .specs/, and .claude/project-config.json. See install/README.md for advanced options.


Compatibility

Component Tested on Notes
Claude Code CLI Latest as of June 2026 Dual-format spec-gate keeps older CLIs working too.
Windows 11 PowerShell 5.1 and 7.x Hooks are pure ASCII for CP1252 safety.
macOS 13+ bash 4+ via Homebrew stat -f %m syntax supported.
Ubuntu 22.04+ bash 5 stat -c %Y syntax supported.
jq 1.6+ Optional; bash hooks exit 0 if missing.

Optional MCP servers (all fall back gracefully if missing): Atlassian, Context7, sequential-thinking, GitNexus, MSSQL, Playwright, Tavily.


Upgrading from a pre-rebrand ck-spec-system install

If you previously installed under the ck/ namespace:

  1. Run the new installer — it lays down ~/.claude/<*>/sd/ alongside the old ck/ folders (your old install is untouched).
  2. In each project, re-run /sd:setup (it regenerates .claude/settings.json with hook paths pointing at hooks/sd/*).
  3. Once you're satisfied the sd: install works, remove the old ~/.claude/<*>/ck/ folders manually.

The dual-format hook output means you don't need to pin a specific Claude Code CLI version.


Full changelog

See CHANGELOG.md[1.1.0] for this release, [1.0.0] for the rebrand baseline.


Acknowledgements

Inspired by the spec-driven discipline of long-running software teams, and by the BMAD method for structuring AI-assisted workflows. Built on top of Claude Code by Anthropic.

Commits in this release carry a Co-Authored-By trailer crediting Claude Opus 4.7 (1M context).