Troubleshooting
Start with the health check. It covers the environment, config, instruction files, increments, hooks, git and the installed plugin, and it tells you which command fixes each failure.
specweave doctor # full check; exits 1 when something failed
specweave doctor --quick # skip slow checks (network, hook dry-runs)
specweave doctor --fix # apply the safe fixes it knows about
specweave doctor --fix-status # repair metadata.json and spec.md status mismatches
--fix removes leftover legacy command directories and stale plugin caches, repairs lockfile hashes, and refreshes an out-of-date SpecWeave pre-commit hook. --fix-status treats metadata.json as the source of truth and rewrites the status in spec.md wherever the two disagree, which only matters for increments created before 3.0. Add --verbose to see every check, or --json for a machine-readable report.
If the problem is not listed below, run specweave update (CLI, instruction files, config and plugin in one go) and then specweave doctor again.
Install and upgrade
SyntaxError: Unexpected token 'with'
Your Node.js is too old. SpecWeave needs Node.js 20.12.0 or later.
node --version
nvm install 22 && nvm use 22 # or install the current LTS another way
npm install -g specweave@3
specweave: command not found
The CLI is not installed globally, or npm's global bin folder is not on your PATH.
npm install -g specweave@3
npm prefix -g # its bin/ folder must be on PATH
If npm install -g fails with EACCES, use a Node version manager such as nvm so global packages install into your home directory, rather than running npm with sudo.
npm ERR! code E401 during install or update
A stale auth token in ~/.npmrc is sent even for public packages. Install while ignoring your npm config:
npm install -g specweave@3 --registry https://registry.npmjs.org --userconfig /dev/null
To fix the cause, remove or refresh the registry.npmjs.org token in ~/.npmrc (npm login refreshes it).
The first commit after upgrading from 2.x is rejected
An old SpecWeave pre-commit hook rejects ledger.jsonl and handoff.md at the increment root. specweave doctor reports it as a failed "Pre-commit hook" check. Either command rewrites it (a hand-written hook is reported, never replaced):
specweave doctor --fix
specweave update
Skills or slash commands are missing in Claude Code
specweave update # refreshes the plugin as well as the project files
specweave refresh-plugins # just the plugin
Then restart the Claude Code session. Never edit ~/.claude/plugins/installed_plugins.json by hand; Claude Code manages it. In a cloud session or a Claude Code Projects thread there is no plugin; the same skills load from .claude/skills/, which init writes and you commit.
Hooks
SpecWeave installs two Claude Code hooks: SessionStart, which prints a short pickup, and Stop, which only acts while an auto session is running. The Jev Bash guard adds a PreToolUse hook only if you turn it on.
A hook printed an error or blocked something
Warnings, errors and blocks go to .specweave/logs/hooks.jsonl. Read them with:
specweave hooks log # last 20 entries
specweave hooks log --errors-only
specweave hooks log --blocks-only
specweave hooks log --hook stop --last 50
specweave doctor also dry-runs each hook and reports one that fails or runs too long.
A session hangs or crashes on a hook
Turn hooks off for this shell, clear the leftover state, and restart the tool:
export SPECWEAVE_DISABLE_HOOKS=1
specweave gc --yes
Then find the cause with specweave hooks log --errors-only and specweave doctor. Turn hooks back on with unset SPECWEAVE_DISABLE_HOOKS. If hooks never run at all, check that this variable is not set in your shell profile.
Tasks and the ledger
refused: T-03 is claimed by codex@laptop since ...
Another agent holds a live claim. Pick another task (specweave task next), or ask that agent to release it. The refusal names your three options:
specweave task release T-03 # run as the agent that holds it
specweave task claim T-03 --force # take it over deliberately
A claim older than the lease is stale and can be claimed without --force. The lease is 2 hours by default; change it with tasks.leaseHours in .specweave/config.json. specweave task list shows which claims are stale.
If the holder is you under another tool name (for example you switched from Claude Code to Codex on the same machine), you can set SPECWEAVE_TOOL so the identity matches, or release the old claims first with specweave task release --all-mine from the old tool. A handoff releases your claims for you.
A claim is refused because of Files or dependencies
shares Files with live claim(s) means another agent is editing the same files; pick a different task. depends on T-01 (not done) means an earlier task must finish first. --force overrides both when you are sure.
done needs evidence
task done records proof. Give it a command to run, or evidence you already have:
specweave task done T-02 --run "npm test -- draft"
specweave task done T-02 --evidence "a1b2c3d, 14 tests passed"
With --run, a non-zero exit means the task is not done; the full output is in reports/task-T-02.txt inside the increment.
Merge conflict in ledger.jsonl
The ledger is append-only, so the right resolution is always to keep every line from both sides. Order does not matter; events are sorted by timestamp when read. Open the file, delete only the <<<<<<<, ======= and >>>>>>> marker lines, keep every event line, then git add it. Never resolve it with git checkout --ours or --theirs, which throws away one side's claims and completions.
To stop this happening, make sure .gitattributes contains:
**/ledger.jsonl merge=union
specweave init writes it and specweave update-instructions (part of specweave update) adds it to an existing project.
Verify and complete
reports/verify.json missing or verify.json is not ok
specweave complete closes an increment only after a passing specweave verify.
specweave verify 0042
specweave complete 0042
verify runs the project's test, lint and build commands (from testing.commands in .specweave/config.json, or detected from your stack) and writes reports/verify.md and reports/verify.json. It also fails when acceptance criteria are not met. An AC is met when every task covering it is done, so the usual fix is to finish the open tasks, not to tick boxes. If verify prints No verification commands, fill in the Commands table in AGENTS.md or set testing.commands.
To close anyway, for example work that was dropped, give a reason. It is stored as closeReason in metadata.json:
specweave complete 0042 --reason "superseded by 0045"
A task command says there is no active increment, or several
task, verify and handoff act on the single active increment. Pass the id when there are several (specweave task next 0042), start a planned one with specweave start 0042, or check with specweave status.
Handoff and pickup
The next session cannot see my work
A cloud session (a Claude Code Projects thread, Codex cloud) or another machine sees only what is pushed. specweave handoff pushes by default when the repository has a remote: the branch, plus a snapshot of your uncommitted edits to wip/<branch> and specweave-handoff. Check its output:
Nothing was pushedmeans the repository has nooriginremote, or you passed--no-push. Add the remote and runspecweave handoffagain, or usespecweave handoff --inlinefor a prompt you can paste.- A
warning:line means a push failed (no permission, offline, detached HEAD, no commits yet). Fix what it names and runspecweave handoffagain.
See Cross-tool handoff.
pickup says a handoff is waiting but applied nothing
specweave pickup only changes your checkout when it is safe:
- Uncommitted changes here. Commit or stash them, then run
specweave pickupagain. - The branches have diverged. Merge the handed-off branch as the message says, then run
specweave pickupagain. - You ran
--no-apply. That only shows what is waiting.
Applied edits are left unstaged, the way the previous session had them.
pickup shows the wrong increment
Pass the id: specweave pickup 0042. If an increment you finished still shows as active, close it with specweave complete, or pause it with specweave pause 0042 --reason "...".
Sync
Sync only runs when you ask (specweave sync push), so a status change never fails because of a tracker.
specweave sync status # token source, account, can-push, provider health
specweave sync setup --validate # check the saved configuration and credentials
specweave sync push 0042 --dry-run
Report the output of sync status as it is; its token and permission errors are specific. See GitHub sync and the sync CLI reference.
Auto mode
specweave auto-status # what the session is doing
specweave cancel-auto # stop it
specweave auto --reset # clear stale auto state before starting again
Clean up local state
specweave gc removes known junk from .specweave/state/ (old markers, circuit-breaker files, caches). It is a dry run unless you pass --yes, it never touches the files coordination depends on, and it also reports the size of .worktrees/ and any nested .specweave/ folders without deleting them.
specweave gc # show what would be removed
specweave gc --yes # remove it
The SessionStart hook runs the same cleanup quietly at most once a day. .specweave/state/ is local; doctor warns if it is tracked by git.
Recover lost or broken increment files
Increments are ordinary files in git, so git is the recovery tool:
git log --oneline -- .specweave/increments/0042-checkout/
git restore --source=HEAD~1 .specweave/increments/0042-checkout/spec.md
Do not rewrite or delete lines in ledger.jsonl to "fix" a state. Append a new event instead: specweave task release, task skip --reason, or task block --reason.
Still stuck
Open an issue at github.com/anton-abyzov/specweave/issues with:
specweave --versionandnode --version- the output of
specweave doctor --json - recent entries from
specweave hooks log --errors-onlyif a hook is involved - the steps that reproduce it