Skip to content

v2.19.0 - Slim plugin install, working install docs

Latest

Choose a tag to compare

@admarble admarble released this 02 Oct 03:13
· 82 commits to main since this release
f41af73

Added

  • /spec stops on recurrence and lists producers; spec can halt the run before exec (#1250). Design Review Q3 now counts prior fixes (git log -S plus an issue search): ≥2 is a stop, not a precedent, and the plan either fixes the class or records deliberately local, reason: …, class tracked in #N. The Simple tier keeps this count. A new Q5 (Standard/Complex) lists every producer and consumer of the artifact; with ≥2 producers the plan collapses them or adds a parity test on every field. When Q3 or Q5 contradicts the issue's prescribed lever, spec emits SPEC_DIVERGENCE in its SEQUANT_PHASE marker, and sequant run now halts before exec with the same evidence bundle the phase loop prints (#995) — previously the spec path never read the field. memory/constitution.md §3 adds "one producer per artifact". See ADR-0005.
  • Configurable worktree root (#1199). run.worktreeRoot in .sequant/settings.json, or the SEQUANT_WORKTREE_ROOT env var (which wins), sets where issue worktrees are created, for both sequant run and scripts/new-feature.sh. A relative value resolves against the main repo root; the default stays ../worktrees. new-feature.sh reads the setting with a JSONC-tolerant text match (a //-commented key is ignored), and its SEQUANT_NPM_CACHE directory follows the root. The pre-tool.sh commit warning and quality-checks.sh's build comparison now detect a worktree with git rev-parse --git-dir vs --git-common-dir instead of matching worktrees/ in the path; the hook also checks the command's directory rather than its own.
  • The run log records which model and which sequant produced each verdict (#1198). Each phase entry now has model, the model the phase actually ran on (from the driver's modelUsage). For a phase with a role: policy it also has requestedModel, the role: string as configured. The run log's top level has sequantVersion and driver. The top-level model in metrics.json now comes from the first phase that reported a resolved model; it falls back to ANTHROPIC_MODEL ?? "opus" only when no phase reported one. All the new fields are optional, so older logs still parse.
  • sequant init --manifest-only and sequant sync --only skills (#1209). init --manifest-only writes just .sequant-manifest.json and exits — no directories, templates, or settings — for the case where sequant run's only real requirement is that one file; a second run leaves an existing manifest untouched. sync --only skills restricts both the apply and the --dry-run preview to .claude/skills/** plus the manifest, skipping the .mcp.json pin, AGENTS.md, the opencode shim, scripts/dev, and .claude/settings.json/agents/hooks/memory entirely. run's manifest-missing message now prints the minimal manifest shape (version, stack, installedAt, files: {}) and names init --manifest-only instead of sending the user through the full init flow. The skills pre-flight's remedy and run-orchestrator's main-checkout message both now recommend sequant sync --only skills, replacing the wider (and, for this case, inaccurate) sequant sync recommendation from #1201.
  • sequant_run's per-issue result carries the qa phase's summary (#1200). Each issue in the structured response now includes acMet, acTotal, gaps and findings from the qa phase's condensed summary, for every verdict — not just on success. findings and gaps are each capped at 10 entries, and each gap and each finding's description/evidence at 300 characters. gaps repeats the findings' descriptions, so it needs the same caps. If a many-issue run is still over the 64KB MCP limit, findings and then gaps are dropped from the last issue backward; acMet, acTotal and the verdict always stay. Any cap or drop sets truncated: true. An MCP caller that gets NEEDS_VERIFICATION or AC_NOT_MET no longer needs a second tool call to learn why.
  • Opt out of a PR auto-closing its issue (#1197). run.prIssueLink (default "closes") controls whether sequant run's automated PR path emits Fixes #N or Refs #N; an issue carrying the configurable run.prNoCloseLabel (default no-autoclose) always gets Refs #N regardless of the setting. In refs mode the PR body is scrubbed for any other <closing verb> #N (or owner/repo#N) reference to the same issue, tables included, since GitHub parses a closing keyword anywhere in the body. /exec's manual PR template and /merger//fullsolve's pre-merge checks (query closingIssuesReferences, halt naming the issue) follow the same rule.
  • Native engineering rubrics as skill references (#1135). /qa §2 points to qa/references/review-dimensions.md for the security and performance items §2e does not pattern-match (XSS, CSRF, command injection, authn/authz, insecure deserialization, path traversal, SSRF; allocations, hot-path complexity, missing indexes, unbounded queries/loops, non-timer resource leaks). /improve ranks candidates with improve/references/tech-debt-scoring.md, scored (Impact + Risk) × (6 − Effort). /testgen consults testgen/references/testing-pyramid.md when the spec names no test level. docs/adr/ adds an ADR convention, and /spec asks for an ADR in the exec PR when the plan chooses between designs. Plain markdown, portable to every driver; qa/SKILL.md and exec/SKILL.md did not grow.

Changed

  • /spec flags vacuous Evidence: (#1203). Spec now runs each command-shaped Evidence: against the base branch before accepting the AC. A check that already passes on unchanged code (a grep matching existing text, a test that exists today) gates nothing, so spec flags it and tightens it until it fails today. This is the AC-level form of the constitution's mutation-verification rule.
  • TodoWrite is gone from the exec, fullsolve, loop and test skills (#1135). Under the sonnet/opus pins, which resolve to Sonnet 5 and Opus 5.5, Claude Code no longer offers the tool, and CLAUDE_CODE_ENABLE_TODO_TOOLS=1 adds TaskCreate/TaskUpdate instead, not TodoWrite. /test's plan is now a markdown checklist.
  • /release pre-flight validates the plugin manifests (#1135). It runs claude plugin validate on .claude-plugin/plugin.json and .claude-plugin/marketplace.json separately, because claude plugin validate . checks only the marketplace manifest, and stops the release on an error. docs/reference/run-command.md lists what the opus/sonnet/haiku/fable aliases resolve to as of Claude Code 2.1.283.
  • /release recounts the "At a Glance" table and explains publish lag. Step 4.6 now carries the exact commands for each count (the table had drifted to 57 test files against 343), and Step 9 says a publish npm answered with 202 can take minutes to appear, how to read ~/.npm/_logs for the real argv, tag and PUT status, and how to poll the registry directly.
  • A bare npm publish now lands on the next dist-tag (#1184). package.json sets publishConfig.tag: next, so latest moves only through the deliberate /release --soaked promotion. A bare publish moved latest straight past the soak on both 2.17.0 and 2.18.0. An explicit --tag (e.g. --tag beta) still wins. Gate-tested by running the real npm publish against a local registry.

Fixed

  • Interactive sequant init no longer crashes with Prompt type "list" is not registered (#1256). inquirer 14 removed the list prompt; init's prompts now use select.
  • sequant doctor and sequant run --dry-run stop passing first runs that will fail (#1257). doctor fails, instead of passing, outside a git repository; subdirectories of a repository still pass. It also warns when the repository has no GitHub remote, and when .claude/skills/{spec,exec,qa} exist on disk but aren't committed, since phase worktrees are checked out from git and won't see them. run --dry-run reports issues as "planned · nothing executed" instead of "✔ passed", and on an issue number that doesn't exist it names the issue and exits 1 instead of planning it.
  • The CLI and docs no longer contradict each other on a first run. sync and update no longer claim that plugins auto-update; they show the two-step plugin install that works (/plugin marketplace add sequant-io/sequant, then /plugin install sequant@sequant). --help drops internal issue numbers. The README scopes "never merges" to sequant run (/fullsolve merges only with --auto-merge). The docs index gains a "Features: when to use what" section.
  • sequant run worktrees record their exact base ref, and the exec guard and the rebase before the PR read it (#1234). resolveBaseRef read branch.<b>.sequantBase, which only the legacy new-feature.sh writes, so for every sequant run worktree the exec guard compared against origin/main. When --base was ahead of main, the base's own commits counted as commits ahead, and the guard's none/uncommitted branches (#534/#879) never fired: exec phases that left their work uncommitted passed. Worktrees now record branch.<b>.sequantBaseRef, which is read first and must resolve to a commit. The legacy key and the origin/main fallback are unchanged.
  • The plugin marketplace now ships a slim plugin/ folder instead of the whole dev repo (#1265). .claude-plugin/marketplace.json's source was "./", so every install and update ran npm ci over this repo's full package.json/lockfile and wrote a ~700 MB node_modules that nothing in the plugin reads — the hooks are shell, the MCP server arrives through a pinned npx, and nothing references node_modules, dist/, scripts/, bin/ or package.json. source now points at ./plugin, a generated folder with no package.json holding only what loads at runtime: skills/, hooks/ (+ hooks.json), .mcp.json, memory/constitution.md, README.md and LICENSE. plugin/hooks/ and plugin/skills/ are generated from templates/ by scripts/sync-hooks.sh and scripts/check-skill-sync.ts --fix, and a drift test fails CI if they diverge. The install id (sequant@sequant) is unchanged, so existing installs upgrade in place. Root hooks/, skills/ and .claude-plugin/plugin.json are retired in a follow-up PR; root .mcp.json stays, since it is also this repo's own project MCP config.
  • The post-tool.sh auto-format hook no longer downloads prettier via npx (#1264). The hook used to run npx prettier --write on every edited .ts/.tsx/.js/.jsx/.json file; in a project with no local prettier and a cold npx cache, that silently fetched and ran the latest prettier from the registry — an unpinned package launcher reaching the network from a hook installed in every sequant project. It now resolves the edited file's repo root and runs only node_modules/.bin/prettier when that binary exists; otherwise it skips and logs SKIP_FORMAT (no local prettier). Projects without a local prettier are simply no longer auto-formatted by this hook.
  • The documented plugin install command now works (#1263). /plugin install sequant@sequant-io/sequant was never valid — the part after @ is a marketplace name (sequant), not a GitHub owner/repo, so it failed with Plugin "sequant" not found in marketplace "sequant-io/sequant". The remaining occurrences in docs/features/plugin-distribution.md and docs/internal/plugin-path-audit.md now use (#1261 had already fixed README.md, the issue template and scripts/prepare-marketplace.ts) the correct two-step form (/plugin marketplace add sequant-io/sequant then /plugin install sequant@sequant), and plugin-install-test.yml gained a CI step that extracts the install block from README.md and runs it verbatim against an isolated CLAUDE_CONFIG_DIR, so a future regression fails CI instead of shipping silently.
  • sequant run has one PR producer, and it updates an existing PR instead of skipping it (#1247). Under SEQUANT_ORCHESTRATOR the /exec skill now pushes its branch but opens no PR, by gh pr create or the in-place MCP pull-request tool. The orchestrator opens it right after exec, so QA can read its body, and updates it after QA. When a PR already exists for the branch (a pre-#1247 exec-made one, or a "PR already exists" race), createPR pushes the branch and updates that PR through gh api -X PATCH instead of returning it untouched, so the non-A+ QA note, the ready-gate report, exec's summary and the --stacked base reach it. Title and body are overwritten only when the existing body is empty or carries sequant's 🤖 Generated by \sequant run`trailer; a hand-edited body is left alone (and logged), though--stackedstill sets the base. A failed update warns and the run keeps its PR. Exec's summary is now saved on the issue's state, so a later qa-only run's PR carries it instead of the "Automated PR for issue #N." placeholder.--no-pr` therefore means no PR from either producer.
  • The Codex usage-limit tests no longer depend on the wall clock (#1248). evaluateCodexRun accepts an optional now (defaulting to Date.now(), so runtime behaviour is unchanged), and the two tests that map the #1087 fixture to BillingError pin it. Without the pin they would have failed from 2026-10-09 to 2026-10-16, while the fixture's reset time sat inside the 7-day RateLimitError horizon, turning main red. A new case covers the in-horizon RateLimitError branch on purpose.
  • sequant run PRs no longer double the conventional-commit prefix or ship a placeholder body (#1223). The PR title now reuses the issue title's own conventional-commit type (feat(adopt): x → feat(#1209): x) instead of prepending a label-derived feat/fix in front of a title that already has one (previously feat(#1209): feat(adopt): x); a bug(scope): title maps to fix, the same as a bug label, and a breaking-change ! is kept (feat(api)!: x → feat(#N)!: x); titles without a recognized prefix keep the old label-derived behavior. The PR body's ## Summary now carries the exec phase's own ## Summary or ### Summary section when present, falling back to the old placeholder text only when exec produced none. The summary comes from the latest exec pass, so it's current after a quality-loop iteration. Any closing keyword (closes, fixes, resolves) inside that imported summary, including cross-repo (owner/repo#N) and issue-URL references, is rewritten to Refs unconditionally, so an agent-written summary line like "Close #279 with the AC mapping comment" can't auto-close an unrelated issue — the PR body's own trailer is unaffected and still closes the linked issue.
  • A sequant run that didn't run qa no longer marks the issue ready_for_merge (#1233). A successful --phases spec or --phases exec run recorded the issue as done, so the next sequant run N --phases exec skipped it unless you passed --force, which also force-takes the issue lock. ready_for_merge and awaiting_verification now require a qa phase that ran in that run; otherwise the issue stays in_progress. A --resume run that skips an already-completed qa also records in_progress; a --phases qa run restores the terminal status. The chain checkpoint-failure warning now says whether a re-run will skip or resume the link.
  • resolvedModel in .sequant/metrics.json and the run log names the phase's main model again, not the Haiku helper (#1227). Claude Code phases now make a small Haiku side call before the main model's first response, so taking the first modelUsage key recorded claude-haiku-4-5-* for every phase from 2026-09-20 on. It's now chosen by rule: the key matching the dispatched model, else a key with cache reads (only the main loop has them), else the largest token volume. phaseUsage was always correct.
  • A watchdog-killed sequant run now writes a run log and preserves a mid-flight worktree instead of half-deleting it (#1222). Signal-driven shutdown used to run cleanup tasks in strict LIFO order; "Finalize run logs" registered early and each worktree's removal task registered later (lazily, as the worktree was created), so LIFO always ran the removals first. git worktree remove --force on a tree with node_modules can take longer than the outer SIGKILL grace, so a killed run could be SIGKILLed mid-removal — leaving a half-deleted worktree and no run log. ShutdownManager.registerCleanup now takes an optional { phase: "finalize" | "resource" }; every "finalize" task runs before any "resource" task, regardless of registration order, with LIFO preserved within each phase. The worktree-removal cleanup also now preserves a clean worktree when its issue has a phase in progress or it has commits ahead of its base branch — not just when it's dirty — so a mid-flight worktree with committed-but-unmerged work (like #1198's 3 WIP commits) survives. The MCP run tool's SIGKILL_GRACE_MS is now derived from ShutdownManager's own forceExitTimeout plus a buffer, instead of a shorter standalone literal, so a cleanup that respects its own timeout isn't cut off by the outer kill.
  • The pre-tool.sh git reset --hard guard checks the repository the reset targets, not the hook's own cwd (#1228). PreToolUse runs before the command's shell, so a cd <worktree> && prefix had not taken effect yet. The guard ran git status, the unpushed-commit check and the MERGE_HEAD check in the main checkout, so it blocked resets of clean worktrees whenever the main checkout was dirty, and allowed resets of dirty worktrees whenever it was clean. git -C <dir> reset --hard also never triggered the guard. The guard now resolves the target in this order: the git -C path, then the cd target, then the command's cwd. All three checks and the branch named in the remediation text use that directory, and git -C <dir> reset now triggers the guard. A dynamic or missing target falls back to the command's cwd, so an unresolvable target is never allowed silently. Plugin users get the fix with the next release's plugin version bump.
  • sequant://install is recomputed on every read and no longer reports a broken manifest as "not installed" (#1195). The resource used to be a snapshot taken once when sequant serve started, so a manifest written later was never seen until a restart. Any read error was also swallowed into {installed: false}. It now reads the install status fresh each time, and a manifest that exists but can't be read or parsed is reported as {error}. The startup stderr warning is still a one-shot.
  • parseQaSummary no longer returns null when a qa phase's AC table uses bold status words or the skill's documented emoji (#1194). The status-cell matcher only accepted an emoji-prefixed keyword, so a table written | AC-1 | **MET** | … | (no emoji) or using ⏳ PENDING / 🔄 Overridden (both in the skill's own examples) counted zero AC rows and the function returned null before it ever read the SEQUANT_QA_GAPS findings marker — a NEEDS_VERIFICATION verdict with real findings posted only the verdict heading, with no way to tell what needed a human look. The matcher now tolerates a **-bold cell with no emoji, normalizes NOT MET/NOT_MET, and recognizes ⏳/🔄 Overridden (counted as an approved exception, not a failure). A valid marker now survives an all-unparseable AC table instead of being discarded by the early acTotal === 0 return. The NEEDS_VERIFICATION verdict comment lists PENDING AC ids and any pause_for_human findings in their own section, distinct from the general gaps list.
  • The skills pre-flight and sequant run's worktree-missing-skills messages print one remedy, and the plugin install path documents what it needs (#1201). The pre-flight's remedy previously said "run sequant sync" without naming what it rewrites (tracked hooks, .claude/settings.json, scripts/dev, sequant-owned AGENTS.md), while run-orchestrator.ts independently told the same user to "commit .claude/skills" — two remedies for the same failure, hand-written at each call site. The orchestrator now threads preflight.remedy into both worktree messages, and the main-checkout message (which still leads with git pull) carries the same sync caveat through a shared SYNC_REWRITES_NOTE. The README's plugin-install section now states that .claude/skills/{spec,exec,qa} must exist and be committed for sequant run, and /sequant:setup (all three mirrored copies) now copies those phase skills (plus the _shared references they link to) from the plugin into .claude/skills/ and tells the user to commit them. It checks every source directory before deleting anything, so running it outside a plugin install leaves committed skills untouched, closing the gap where a plugin-only user had no npm-free way to get them.
  • A uv stack no longer runs the bare, failing uv pip install -q (#1217). Worktree provisioning, dependency reinstall and merge-check now install a uv repo with uv sync --frozen when uv.lock exists, otherwise with uv pip install -q -r <requirements file>, and skip the install when neither exists — the same fallback #1196 gave pip.
  • detectPackageManagerSync now agrees with the async detector on Python repos (#1231). It previously checked JS lockfiles only and fell back to "npm" for everything else, so a uv/poetry repo whose manifest declared no packageManager resolved to npm in resolvePackageManager — the fallback installWorktreeDeps and merge-check's combined-branch test both use — and skipped the install (or test/build) entirely instead of reaching #1217's uv/poetry/pip handling. It now mirrors detectPackageManager's full order: JS lockfiles, package.json → npm, Python lockfiles, pyproject.toml/requirements*.txt → pip, npm last.
  • Worktree provisioning, dependency reinstall and merge-check no longer run a failing install/test on a non-Node repo (#1196). ensureWorktree installed whenever node_modules was missing, which is always true in a non-Node worktree, and resolvePackageManager's fallback is JS-lockfile-only — so a pure-Python worktree always attempted npm ci against a tree with no package.json. installWorktreeDeps now skips (and logs why) when no manifest exists for the resolved package manager. A pip stack's install command now names its requirements*.txt file, or is skipped, rather than running the bare, failing no-op pip install -q. merge-check's combined-branch test now skips the test/build step with an info finding, instead of a severity: error BLOCKED, when the repo defines no such script.
  • /spec's self-skip on a re-run now emits a SEQUANT_SPEC marker restating the prior plan (#1213). #1193 made the orchestrator fail a spec phase that produced no fresh SEQUANT_SPEC marker, but /spec's phase-detection self-skip (when a prior spec:completed marker is found) wrote only a skip message and no marker — latent while the detection grep never matched escaped JSON, live the day that grep is fixed. The self-skip branch (all 3 mirrored SKILL.md copies) now restates the prior spec's marker verbatim before exiting, and falls through to normal execution instead of skipping when no valid prior marker is found. The guard is unchanged: a self-skip with no marker still fails.
  • sequant run checks the main checkout that spec runs in (#1193). Spec does not run in a worktree, but since #933 the skills pre-flight checked only worktrees. A main checkout behind origin/<base> and missing .claude/skills/spec/SKILL.md passed, and spec planned without its skill. The run now checks the main checkout for the skills of the phases that run there before it creates any worktree, and names the missing path. It also warns when the main checkout is behind origin/<base>, with the commit count. A spec that emits no SEQUANT_SPEC marker, in its output or in an issue comment posted during the phase, is now recorded as failed, not success. Aider is exempt from the marker check.
  • sequant init --mcp, project .mcp.json, opencode's MCP entry, phase agents and the plugin-directory .mcp.json launch the MCP server through the inline node -e launcher (#1089). They ran npx -y sequant@<pin> serve from the project directory, so a stale sequant in the project's own node_modules could shadow the pin and kill the handshake with CONNECTION_CLOSED (the #1084 failure, which only the plugin's own .mcp.json had fixed). sequant update and sync migrate an existing npx -y sequant@<pin> serve entry to the launcher; other hand-edited entries only get their pin refreshed. A committed .mcp.json now carries the ~8 KB launcher source.
  • opencode phases now report token usage (#1115). The driver sums each step_finish event's tokens into modelUsage, so sequant stats and the token metrics count opencode runs instead of recording 0. Reasoning tokens count as output and cache reads/writes map to the cache counters, the same way claude-code reports them; a run with no pinned model is keyed opencode-default. aider usage and typed opencode quota errors still need a real captured run and stay open on #1115.
  • /upstream files a finding issue only when the change touches something sequant uses (#1186). Breaking changes still always get an issue. Other actionable findings now need a case-sensitive mention of a tool, hook event, dependency-map key or documented claude command (claude plugin install/update/eval), or an affected path that exists in the repo. Everything else is listed in the assessment issue only, so a lowercase "task" or "read" in a release note no longer files an issue. The dependency map drops the generic permission/hook/MCP keys and paths that no longer exist, maps PreToolUse, PostToolUse and SessionEnd to the shipped hook scripts, and OpenTelemetry joins outOfScope.

Documentation

  • run --help for --no-pr and the PR-creation docs describe the after-exec PR (#1247). The run opens the PR after exec and updates it after QA, and --no-pr skips both. sequant abort gets its own reference page (docs/reference/abort-command.md).
  • New guide: "Write Issues Sequant Can Execute" (docs/guides/writing-issues.md). It covers the acceptance-criteria format, Depends on: #N for ordering, and a copy-paste GitHub issue form.

Security

  • The GitHub Action's comment-trigger example now runs only for repository owners, organization members and collaborators. The example workflow and docs/features/github-actions-integration.md gate the trigger on author_association. If you copied the old example, update your workflow's if: to match.

Full Changelog: v2.18.0...v2.19.0