Repository navigation
Added
/specstops on recurrence and lists producers; spec can halt the run before exec (#1250). Design Review Q3 now counts prior fixes (git log -Splus an issue search): ≥2 is a stop, not a precedent, and the plan either fixes the class or recordsdeliberately 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 emitsSPEC_DIVERGENCEin itsSEQUANT_PHASEmarker, andsequant runnow 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.worktreeRootin.sequant/settings.json, or theSEQUANT_WORKTREE_ROOTenv var (which wins), sets where issue worktrees are created, for bothsequant runandscripts/new-feature.sh. A relative value resolves against the main repo root; the default stays../worktrees.new-feature.shreads the setting with a JSONC-tolerant text match (a//-commented key is ignored), and itsSEQUANT_NPM_CACHEdirectory follows the root. Thepre-tool.shcommit warning andquality-checks.sh's build comparison now detect a worktree withgit rev-parse --git-dirvs--git-common-dirinstead of matchingworktrees/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'smodelUsage). For a phase with arole:policy it also hasrequestedModel, therole:string as configured. The run log's top level hassequantVersionanddriver. The top-levelmodelinmetrics.jsonnow comes from the first phase that reported a resolved model; it falls back toANTHROPIC_MODEL ?? "opus"only when no phase reported one. All the new fields are optional, so older logs still parse. sequant init --manifest-onlyandsequant sync --only skills(#1209).init --manifest-onlywrites just.sequant-manifest.jsonand exits — no directories, templates, or settings — for the case wheresequant run's only real requirement is that one file; a second run leaves an existing manifest untouched.sync --only skillsrestricts both the apply and the--dry-runpreview to.claude/skills/**plus the manifest, skipping the.mcp.jsonpin, AGENTS.md, the opencode shim,scripts/dev, and.claude/settings.json/agents/hooks/memoryentirely.run's manifest-missing message now prints the minimal manifest shape (version,stack,installedAt,files: {}) and namesinit --manifest-onlyinstead of sending the user through the fullinitflow. The skills pre-flight's remedy andrun-orchestrator's main-checkout message both now recommendsequant sync --only skills, replacing the wider (and, for this case, inaccurate)sequant syncrecommendation from #1201.sequant_run's per-issue result carries the qa phase's summary (#1200). Each issue in the structured response now includesacMet,acTotal,gapsandfindingsfrom the qa phase's condensed summary, for every verdict — not just on success.findingsandgapsare each capped at 10 entries, and each gap and each finding'sdescription/evidenceat 300 characters.gapsrepeats 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,acTotaland the verdict always stay. Any cap or drop setstruncated: true. An MCP caller that getsNEEDS_VERIFICATIONorAC_NOT_METno longer needs a second tool call to learn why.- Opt out of a PR auto-closing its issue (#1197).
run.prIssueLink(default"closes") controls whethersequant run's automated PR path emitsFixes #NorRefs #N; an issue carrying the configurablerun.prNoCloseLabel(defaultno-autoclose) always getsRefs #Nregardless of the setting. Inrefsmode the PR body is scrubbed for any other<closing verb> #N(orowner/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 (queryclosingIssuesReferences, halt naming the issue) follow the same rule. - Native engineering rubrics as skill references (#1135).
/qa§2 points toqa/references/review-dimensions.mdfor 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)./improveranks candidates withimprove/references/tech-debt-scoring.md, scored(Impact + Risk) × (6 − Effort)./testgenconsultstestgen/references/testing-pyramid.mdwhen the spec names no test level.docs/adr/adds an ADR convention, and/specasks for an ADR in the exec PR when the plan chooses between designs. Plain markdown, portable to every driver;qa/SKILL.mdandexec/SKILL.mddid not grow.
Changed
/specflags vacuousEvidence:(#1203). Spec now runs each command-shapedEvidence:against the base branch before accepting the AC. A check that already passes on unchanged code (agrepmatching 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.TodoWriteis gone from the exec, fullsolve, loop and test skills (#1135). Under thesonnet/opuspins, which resolve to Sonnet 5 and Opus 5.5, Claude Code no longer offers the tool, andCLAUDE_CODE_ENABLE_TODO_TOOLS=1addsTaskCreate/TaskUpdateinstead, notTodoWrite./test's plan is now a markdown checklist./releasepre-flight validates the plugin manifests (#1135). It runsclaude plugin validateon.claude-plugin/plugin.jsonand.claude-plugin/marketplace.jsonseparately, becauseclaude plugin validate .checks only the marketplace manifest, and stops the release on an error.docs/reference/run-command.mdlists what theopus/sonnet/haiku/fablealiases resolve to as of Claude Code 2.1.283./releaserecounts 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 with202can take minutes to appear, how to read~/.npm/_logsfor the realargv, tag andPUTstatus, and how to poll the registry directly.- A bare
npm publishnow lands on thenextdist-tag (#1184).package.jsonsetspublishConfig.tag: next, solatestmoves only through the deliberate/release --soakedpromotion. A bare publish movedlateststraight 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 realnpm publishagainst a local registry.
Fixed
- Interactive
sequant initno longer crashes withPrompt type "list" is not registered(#1256). inquirer 14 removed thelistprompt; init's prompts now useselect. sequant doctorandsequant run --dry-runstop passing first runs that will fail (#1257).doctorfails, 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-runreports 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.
syncandupdateno 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).--helpdrops internal issue numbers. The README scopes "never merges" tosequant run(/fullsolvemerges only with--auto-merge). The docs index gains a "Features: when to use what" section. sequant runworktrees record their exact base ref, and the exec guard and the rebase before the PR read it (#1234).resolveBaseRefreadbranch.<b>.sequantBase, which only the legacynew-feature.shwrites, so for everysequant runworktree the exec guard compared againstorigin/main. When--basewas ahead of main, the base's own commits counted as commits ahead, and the guard'snone/uncommittedbranches (#534/#879) never fired: exec phases that left their work uncommitted passed. Worktrees now recordbranch.<b>.sequantBaseRef, which is read first and must resolve to a commit. The legacy key and theorigin/mainfallback are unchanged.- The plugin marketplace now ships a slim
plugin/folder instead of the whole dev repo (#1265)..claude-plugin/marketplace.json'ssourcewas"./", so every install and update rannpm ciover this repo's fullpackage.json/lockfile and wrote a ~700 MBnode_modulesthat nothing in the plugin reads — the hooks are shell, the MCP server arrives through a pinnednpx, and nothing referencesnode_modules,dist/,scripts/,bin/orpackage.json.sourcenow points at./plugin, a generated folder with nopackage.jsonholding only what loads at runtime:skills/,hooks/(+hooks.json),.mcp.json,memory/constitution.md,README.mdandLICENSE.plugin/hooks/andplugin/skills/are generated fromtemplates/byscripts/sync-hooks.shandscripts/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. Roothooks/,skills/and.claude-plugin/plugin.jsonare retired in a follow-up PR; root.mcp.jsonstays, since it is also this repo's own project MCP config. - The
post-tool.shauto-format hook no longer downloads prettier vianpx(#1264). The hook used to runnpx prettier --writeon every edited.ts/.tsx/.js/.jsx/.jsonfile; 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 onlynode_modules/.bin/prettierwhen that binary exists; otherwise it skips and logsSKIP_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/sequantwas never valid — the part after@is a marketplace name (sequant), not a GitHubowner/repo, so it failed withPlugin "sequant" not found in marketplace "sequant-io/sequant". The remaining occurrences indocs/features/plugin-distribution.mdanddocs/internal/plugin-path-audit.mdnow use (#1261 had already fixedREADME.md, the issue template andscripts/prepare-marketplace.ts) the correct two-step form (/plugin marketplace add sequant-io/sequantthen/plugin install sequant@sequant), andplugin-install-test.ymlgained a CI step that extracts the install block from README.md and runs it verbatim against an isolatedCLAUDE_CONFIG_DIR, so a future regression fails CI instead of shipping silently. sequant runhas one PR producer, and it updates an existing PR instead of skipping it (#1247). UnderSEQUANT_ORCHESTRATORthe/execskill now pushes its branch but opens no PR, bygh pr createor 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),createPRpushes the branch and updates that PR throughgh api -X PATCHinstead of returning it untouched, so the non-A+ QA note, the ready-gate report, exec's summary and the--stackedbase 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).
evaluateCodexRunaccepts an optionalnow(defaulting toDate.now(), so runtime behaviour is unchanged), and the two tests that map the #1087 fixture toBillingErrorpin 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-dayRateLimitErrorhorizon, turningmainred. A new case covers the in-horizonRateLimitErrorbranch on purpose. sequant runPRs 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-derivedfeat/fixin front of a title that already has one (previouslyfeat(#1209): feat(adopt): x); abug(scope):title maps tofix, the same as abuglabel, 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## Summarynow carries the exec phase's own## Summaryor### Summarysection 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 toRefsunconditionally, 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 runthat didn't run qa no longer marks the issueready_for_merge(#1233). A successful--phases specor--phases execrun recorded the issue as done, so the nextsequant run N --phases execskipped it unless you passed--force, which also force-takes the issue lock.ready_for_mergeandawaiting_verificationnow require a qa phase that ran in that run; otherwise the issue staysin_progress. A--resumerun that skips an already-completed qa also recordsin_progress; a--phases qarun restores the terminal status. The chain checkpoint-failure warning now says whether a re-run will skip or resume the link. resolvedModelin.sequant/metrics.jsonand 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 firstmodelUsagekey recordedclaude-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.phaseUsagewas always correct.- A watchdog-killed
sequant runnow 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 --forceon a tree withnode_modulescan 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.registerCleanupnow 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 MCPruntool'sSIGKILL_GRACE_MSis now derived fromShutdownManager's ownforceExitTimeoutplus 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.shgit reset --hardguard checks the repository the reset targets, not the hook's own cwd (#1228). PreToolUse runs before the command's shell, so acd <worktree> &&prefix had not taken effect yet. The guard rangit status, the unpushed-commit check and theMERGE_HEADcheck 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 --hardalso never triggered the guard. The guard now resolves the target in this order: thegit -Cpath, then thecdtarget, then the command's cwd. All three checks and the branch named in the remediation text use that directory, andgit -C <dir> resetnow 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://installis recomputed on every read and no longer reports a broken manifest as "not installed" (#1195). The resource used to be a snapshot taken once whensequant servestarted, 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.parseQaSummaryno longer returnsnullwhen 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 returnednullbefore it ever read theSEQUANT_QA_GAPSfindings marker — aNEEDS_VERIFICATIONverdict 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, normalizesNOT 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 earlyacTotal === 0return. TheNEEDS_VERIFICATIONverdict comment lists PENDING AC ids and anypause_for_humanfindings 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 "runsequant sync" without naming what it rewrites (tracked hooks,.claude/settings.json,scripts/dev, sequant-ownedAGENTS.md), whilerun-orchestrator.tsindependently told the same user to "commit.claude/skills" — two remedies for the same failure, hand-written at each call site. The orchestrator now threadspreflight.remedyinto both worktree messages, and the main-checkout message (which still leads withgit pull) carries the same sync caveat through a sharedSYNC_REWRITES_NOTE. The README's plugin-install section now states that.claude/skills/{spec,exec,qa}must exist and be committed forsequant run, and/sequant:setup(all three mirrored copies) now copies those phase skills (plus the_sharedreferences 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 withuv sync --frozenwhenuv.lockexists, otherwise withuv pip install -q -r <requirements file>, and skip the install when neither exists — the same fallback #1196 gave pip. detectPackageManagerSyncnow 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 nopackageManagerresolved to npm inresolvePackageManager— the fallbackinstallWorktreeDepsand 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 mirrorsdetectPackageManager's full order: JS lockfiles,package.json→ npm, Python lockfiles,pyproject.toml/requirements*.txt→ pip,npmlast.- Worktree provisioning, dependency reinstall and merge-check no longer run a failing install/test on a non-Node repo (#1196).
ensureWorktreeinstalled whenevernode_moduleswas missing, which is always true in a non-Node worktree, andresolvePackageManager's fallback is JS-lockfile-only — so a pure-Python worktree always attemptednpm ciagainst a tree with no package.json.installWorktreeDepsnow skips (and logs why) when no manifest exists for the resolved package manager. A pip stack's install command now names itsrequirements*.txtfile, or is skipped, rather than running the bare, failing no-oppip install -q.merge-check's combined-branch test now skips the test/build step with an info finding, instead of aseverity: errorBLOCKED, when the repo defines no such script. /spec's self-skip on a re-run now emits aSEQUANT_SPECmarker restating the prior plan (#1213). #1193 made the orchestrator fail a spec phase that produced no freshSEQUANT_SPECmarker, but/spec's phase-detection self-skip (when a priorspec:completedmarker 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 mirroredSKILL.mdcopies) 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 runchecks the main checkout thatspecruns in (#1193). Spec does not run in a worktree, but since #933 the skills pre-flight checked only worktrees. A main checkout behindorigin/<base>and missing.claude/skills/spec/SKILL.mdpassed, 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 behindorigin/<base>, with the commit count. A spec that emits noSEQUANT_SPECmarker, 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.jsonlaunch the MCP server through the inlinenode -elauncher (#1089). They rannpx -y sequant@<pin> servefrom the project directory, so a stalesequantin the project's ownnode_modulescould shadow the pin and kill the handshake withCONNECTION_CLOSED(the #1084 failure, which only the plugin's own.mcp.jsonhad fixed).sequant updateandsyncmigrate an existingnpx -y sequant@<pin> serveentry to the launcher; other hand-edited entries only get their pin refreshed. A committed.mcp.jsonnow carries the ~8 KB launcher source.- opencode phases now report token usage (#1115). The driver sums each
step_finishevent'stokensintomodelUsage, sosequant statsand 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 keyedopencode-default. aider usage and typed opencode quota errors still need a real captured run and stay open on #1115. /upstreamfiles 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 documentedclaudecommand (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 genericpermission/hook/MCPkeys and paths that no longer exist, mapsPreToolUse,PostToolUseandSessionEndto the shipped hook scripts, and OpenTelemetry joinsoutOfScope.
Documentation
run --helpfor--no-prand the PR-creation docs describe the after-exec PR (#1247). The run opens the PR after exec and updates it after QA, and--no-prskips both.sequant abortgets 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: #Nfor 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.mdgate the trigger onauthor_association. If you copied the old example, update your workflow'sif:to match.
Full Changelog: v2.18.0...v2.19.0