Skip to main content

Configuration reference

.specweave/config.json holds project settings. specweave init writes it, and you rarely need to touch it. Every key on this page has a reader in the code. A top-level key SpecWeave does not know produces one warning line when the config loads and is otherwise ignored.

Per-increment state is not here. It lives in each increment's metadata.json and ledger.jsonl; see the metadata reference.

What init writes​

For a Claude Code project with a GitHub remote, specweave init writes roughly this:

{
"version": "2.0",
"project": { "name": "my-app", "version": "0.1.0" },
"adapters": { "default": "claude" },
"repository": { "provider": "github", "organization": "acme", "repo": "my-app" },
"testing": { "commands": [] },
"limits": { "activeIncrements": 3 },
"planning": { "deepInterview": "critical" },
"auto": { "maxTurns": 20, "maxSessionAge": 7200, "requireTests": false },
"livingDocs": false,
"lsp": { "enabled": true },
"workspace": { "name": "my-app", "repos": [] },
"sync": { "enabled": true, "autoSync": true, "settings": { "canUpsertInternalItems": true, "canUpdateExternalItems": true, "canUpdateStatus": true } }
}

version is the config schema version. It stays "2.0" in SpecWeave 3.0 because the file format did not change.

Without a git remote, repository.provider is "local" and there is no sync block. With another tool, adapters.default names it (codex, cursor, copilot, gemini, generic and so on) and lsp is not written.

The single most useful edit is filling in testing.commands.

Core keys​

project​

FieldNotes
nameThe project name. The only field SpecWeave itself reads.
version, description, techStack, teamFor your own use.

adapters​

FieldDefaultNotes
default"claude"The tool chosen at init. refresh-plugins uses it to decide where the skills go.

testing​

FieldDefaultNotes
commands[]The commands specweave verify runs, in order. Empty means auto-detect: package.json scripts test, lint, build, then Cargo, pytest or Go.
modenot setTDD, test-after, manual or none: how tests are written for new work. init writes it only when you choose one.
coverage.unit, coverage.integrationnot setLine coverage targets in percent. Below target is a warning at close, not a block. Written only when you set a target.
coverage.e2enot setShare of written end-to-end tests that must pass. Not line coverage.

tasks​

FieldDefaultNotes
leaseHours2Hours before an unfinished claim is stale and another agent may take the task over.

limits​

FieldDefaultNotes
activeIncrements3Advisory. Going over prints one note; nothing blocks. 0 turns the note off.

planning​

FieldDefaultNotes
deepInterview"critical"Depth of sw-increment's Decide step before spec.md is written. "critical" asks at most 5 decisions, each with a recommended answer. "deep" runs the sw-grill-me interview in rounds with no cap, and installs that skill. "off" asks nothing. Answers and defaults go under ## Decisions in spec.md. It never blocks. A 2.x "warn" reads as "critical".

auto​

Settings for specweave auto and its Stop hook.

FieldDefaultNotes
maxTurns20Hard stop for one auto session.
maxSessionAge7200Seconds before an idle auto session is treated as stale and reset.
requireTestsfalseAdd a "tests pass" condition to the session's success criteria.

These are the only auto keys 3.0 reads. Projects created with 2.x may also have enabled, maxRetries, requireValidation, requireJudgeLLM and skipQualityGates; they are ignored.

workspace​

Multi-repo workspaces: an umbrella folder with child repos under repositories/. init fills this in when it finds child repos.

{
"workspace": {
"name": "acme",
"repos": [
{ "id": "web-ui", "path": "repositories/acme/web-ui", "prefix": "FE", "role": "frontend" },
{ "id": "api", "path": "repositories/acme/api", "prefix": "BE", "role": "backend" }
]
}
}
FieldNotes
nameWorkspace name.
rootRepoSync target for the umbrella repo itself.
repos[].idMust match the repository name.
repos[].pathRelative or absolute path.
repos[].prefix, repos[].role, repos[].techStackRouting hints.
repos[].syncPer-repo github, jira or ado target.

The old umbrella, multiProject and projectMappings blocks are folded into workspace when the config loads.

sync​

External trackers. Nothing is written to GitHub, Jira or Azure DevOps until you run specweave sync push; starting, pausing or resuming an increment never calls a tracker.

FieldNotes
enabledMaster switch. init turns it on when it finds a GitHub or Azure DevOps remote.
github{ "enabled", "owner", "repo" }. First-class.
jira{ "enabled", "domain", "projectKey" }. Opt-in.
ado{ "enabled", "organization", "project" }. Opt-in.
settings.canUpsertInternalItems, settings.canUpdateExternalItemssync push only creates missing issues when one of these is true.
defaultProfile, profilesNamed tracker targets, written by specweave sync setup.

Flags and token resolution are in the specweave sync reference.

hooks​

The explicit close-on-complete setting. With it, specweave complete closes the GitHub issue, Jira issue or Azure DevOps work item that sync push linked to the increment. Without it, complete leaves every tracker alone. specweave sync setup writes close_external_issue: true; set it to false to keep closure local.

{ "hooks": { "post_increment_done": { "close_external_issue": true } } }

close_external_issue covers every tracker. The narrower keys close one kind only: close_github_issue for GitHub, close_jira_issue and close_ado_work_item for Jira and Azure DevOps. Closure is skipped when sync.settings.canUpdateExternalItems is false.

jev​

Jev (System One) is off until specweave jev setup writes "enabled": true after a live test call. Only the name of the environment variable that holds the key is stored, never the key.

FieldDefault
enabledfalse
provider"openrouter" (or "typesafe")
model"jev-1.13" on OpenRouter
apiKeyEnvprovider default: OPENROUTER_API_KEY or TYPESAFE_API_KEY, then JEV_API_KEY
timeoutMs4000
thresholds{ "route": 0.7, "guardDeny": 0.85, "guardWarn": 0.5 }
guards.bashfalse
modelRoutingtrue
browse{ "allowDomains": [], "maxSteps": 20 }

SPECWEAVE_JEV=0 turns Jev off for one process; SPECWEAVE_JEV_PROVIDER and SPECWEAVE_JEV_MODEL override the file. See Jev.

skills​

Which optional skills the project installs. The six core skills (increment, do, auto, done, review, handoff) are always installed and cannot be disabled. specweave skills enable and disable write these lists for you.

{ "skills": { "enabled": ["grill-me", "glossary"], "disabled": ["sync"] } }
FieldNotes
enabledOptional skills to install even when nothing detects them: grill-me, glossary, sync, project, jev.
disabledOptional skills to leave out even when detected.

An optional skill that neither list names is on when the project detects it: planning.deepInterview: "deep" (grill-me), a GLOSSARY.md or GLOSSARY-MAP.md at the root (glossary), a configured tracker (sync), .specweave/project/hub.json (project) and jev.enabled (jev). specweave update removes SpecWeave's copy of an optional skill that is off. See the skills reference.

review​

Settings for specweave review, the cross-model review.

{
"review": {
"crossModel": true,
"reviewer": "auto",
"reviewers": {
"local": { "command": "./scripts/review.sh {out}", "family": "google" }
},
"timeoutMinutes": 30
}
}
FieldDefaultNotes
crossModelfalseWhen true, sw-review and sw-done run specweave review without being asked.
reviewer"auto"auto picks the first installed reviewer from another model family than the one that wrote the code, Codex first. A name pins one reviewer.
reviewers.<name>.commandbuilt in: codex, claudeA shell command that reads the brief on stdin. {out} is replaced with a file the reviewer writes its answer to; without {out}, stdout is the answer. The same name overrides a built-in reviewer.
reviewers.<name>.familythe nameThe reviewer's model family (openai, claude, xai, google), used to keep it apart from the author's.
timeoutMinutes30Minutes before the reviewer is stopped. --timeout overrides it for one run.

Kept for compatibility​

These keys are accepted without a warning because some code still reads them. You do not need to set them.

KeyRead by
repositoryRemote detection at init, and issue creation during sync push.
lsp{ "enabled": true } for Claude Code projects. See LSP integration.
cicdspecweave branch-name and the CI/CD helpers (pushStrategy, git, release).
issueTrackerThe older tracker block that specweave sync setup still writes for Jira and Azure DevOps.
pluginsplugins.enabled, the list of enabled Claude Code plugins.
livingDocsfalse by default. "onDone" regenerates living docs when an increment closes; specweave update sets it for 2.x projects that used living docs.

Removed keys​

specweave update and specweave update-instructions delete these and record what they dropped in .specweave/state/config-migration-2.json:

contextBudget, quality, cache, deduplication, archiving, apiDocs, statusLine, incrementAssist, billing, translation, language, documentation, reflect, pluginAutoLoad, banner, grill, codeReview, qualityGates, skillGen.

Also removed: hooks.banner, hooks.post_increment_planning, hooks.post_task_completion, sync.mode, and the testing sub-keys defaultTestMode, defaultCoverageTarget, coverageTargets, tddEnforcement and playwright (after they are renamed to testing.mode and testing.coverage). limits.maxActiveIncrements becomes limits.activeIncrements.

Git files​

init and update-instructions add this line to .gitattributes so parallel agents never conflict on the ledger:

**/ledger.jsonl merge=union

They also add runtime folders such as .specweave/state/ and .specweave/logs/ to .gitignore. .specweave/increments/ and .specweave/memory/ are committed.