Keyboard shortcuts

Press ← or → to navigate between chapters

Press S or / to search in the book

Press ? to show this help

Press Esc to hide this help

Configuration

Writ uses a two tier configuration system that mirrors git: a global config for your defaults and a project config for per repository overrides. Any setting in the global config can be overridden at the project level.

Configuration Hierarchy

~/.writ/config              Global defaults (like ~/.gitconfig)
.writ/config.toml           Project-level overrides
CLI flags                   Per-invocation override (highest priority)
Environment variables       WRIT_FORMAT, WRIT_COMMIT_MODE, etc.

Resolution order (highest priority first):

  1. CLI flag (--format toon)
  2. Environment variable (WRIT_FORMAT=toon)
  3. Project config (.writ/config.toml)
  4. Global config (~/.writ/config)
  5. Built-in default

Global Config

Created automatically on first writ init. Located at ~/.writ/config.

[user]
name = "Andrew"                           # your name for seal attribution

[output]
format = "toon"                           # default output format: json | toon | json-compact

[init]
frameworks = ["claude", "codex", "generic"]  # default frameworks to configure

[workflow]
commit_mode = "user"                      # user | propose | auto
commit_strategy = "single"                # single | per-spec | grouped

Project Config

Created by writ init in each project. Located at .writ/config.toml.

[project]
name = "my-project"
profile = "development"                   # deployment profile

[output]
format = "toon"                           # override global format for this project

[workflow]
commit_mode = "user"                      # user | propose | auto
commit_strategy = "single"               # single | per-spec | grouped
stale_timeout = 3600                      # seconds before a spec is flagged stale (0 to disable)

[workflow.auto]
verify_command = "cargo test --quiet"     # must exit 0 for auto-commit to proceed
max_specs_per_commit = 10                 # prevent mega-commits
branch = "writ/auto"                      # target branch for auto commits (not main)
notify = "log"                            # log | stdout | none

[gc]
profile = "development"                   # storage profile
max_storage_bytes = 5368709120            # 5 GB
retention_days = 30
compression_level = 3

Output Formats

Three output formats for writ context and other structured commands:

FormatFlagDescription
json--format jsonStandard JSON. Maximum compatibility. Default if no config is set.
toon--format toonToken Oriented Object Notation. Field names declared once, rows streamed as values. Recommended for LLM agents.
json-compact--format json-compactMinified JSON. No whitespace. Good for CI pipelines.

Set your default format globally:

# During first writ init, you'll be prompted:
# Default output format for agent context:
#   (1) toon          Token Oriented Object Notation (optimized for LLM agents)
#   (2) json          Standard JSON (maximum compatibility)
#   (3) json-compact  Minified JSON

Or set it directly in config:

# ~/.writ/config (global)
[output]
format = "toon"

# .writ/config.toml (project override)
[output]
format = "json"

Override per command:

writ context --format toon
writ status --format json
writ diff --format json-compact

Workflow Modes

Three modes that scale from solo developer to enterprise fleet. Set during writ init or in config.

user (Default)

The user runs writ finish manually. Maximum control, maximum safety.

[workflow]
commit_mode = "user"

Flow: agents complete specs → user runs writ status → user runs writ finish → git commit created.

propose

An orchestrator proposes commits. The user reviews and accepts.

[workflow]
commit_mode = "propose"

Flow: agents complete specs → orchestrator runs writ finish --propose → user reviews with writ finish --review → user accepts with writ finish --accept.

Good for medium teams (10-50 agents) with supervised autonomous work.

auto

Fully autonomous. Orchestrator commits directly. Requires high trust.

[workflow]
commit_mode = "auto"

[workflow.auto]
verify_command = "cargo test --quiet"    # must exit 0 to commit
max_specs_per_commit = 10                # prevent mega-commits
branch = "writ/auto"                     # commit to a branch, not main
notify = "log"                           # log | stdout | none

Flow: agents complete specs → orchestrator runs writ finish --auto → verification runs → git commit created on target branch.

Safety rails: test verification blocks bad commits. Branch targeting keeps auto commits off main. Max specs per commit prevents runaway batches.

Deployment Profiles

Set during initialization with writ init --profile <name>. Controls storage budgets, retention periods, and compression levels.

ProfileStorage BudgetRetentionCompressionUse Case
raspberry-pi500 MB7 daysLevel 1Constrained environments
development5 GB30 daysLevel 3Local development
production100 GB90 daysLevel 3Production systems
enterpriseUnlimited365 daysLevel 6Enterprise deployments

Claude Code Hooks

writ init -y writes these hooks into .claude/settings.json, beside any hooks of your own, and writ uninit removes only writ’s. Every writ hook exits 0, so a hook never fails the agent’s tool call; problems go to .writ/hooks.log.

EventMatcherWhat writ does
SessionStartallPrints the short instructions and the brief
PreToolUseBashOpens a window for the command: records the tree before it runs, and closes any earlier window of the same agent that never got an end event
PostToolUseEdit, Write, MultiEdit, NotebookEdit, BashSeals the path the tool changed, under the agent’s spec
PostToolUseFailureEdit, Write, MultiEdit, NotebookEdit, BashThe same as PostToolUse. Claude Code sends this event instead of PostToolUse when the tool call fails, and a command can write files before it fails
UserPromptSubmitallKeeps the prompt’s first sentence as the title of an auto spec
StopallSeals any edited file the edit hooks missed
SubagentStopallThe same for a subagent, and ends a named subagent’s instance
SessionEndallCloses the session’s auto specs and records the session end

A project set up before PostToolUseFailure was added reads version_skew in writ doctor until you run writ init -y again.

When the store lock is busy, a hook waits at most 200 ms, then leaves the path for the agent’s next hook or its Stop:

[hooks]
lock_wait_ms = 200

Test Fixture Settings

These settings exist for writ’s own test fixtures. Do not set them in a project where agents work.

[seal] foreign_line_check

By default every seal an agent makes (by hand, through the hook, from Python or over MCP) is refused when it would record the removal of lines another agent’s spec sealed, and writ names that agent and the lines. Test fixtures that build two diverged versions of a file on purpose turn this off in .writ/config.toml:

[seal]
foreign_line_check = false

writ init never writes this key. While it is set to false:

  • writ doctor reports a yellow finding: “foreign-line check on seal is disabled in config; the finish check still applies”. It is marked for a person, and its fix is to remove the key. writ context shows the same line.
  • writ finish still checks that the merge keeps every sealed line, as it always does.
  • The commit receipt says how many seals in the commit were made with the check off: “N seal(s) made with the foreign-line check disabled in config”.

Files

FileLocationPurpose
~/.writ/configHome directoryGlobal defaults (format, frameworks, workflow mode)
.writ/Project rootWrit repository data (seals, objects, heads, keys, config)
.writ/config.tomlInside .writProject-level configuration overrides
.writ/gc-config.jsonInside .writGarbage collection settings (profile, budgets, retention)
.writ/keys/Inside .writCryptographic keys (Ed25519 convergence keypair, AES-GCM encrypted)
.writignoreProject rootFiles to exclude from tracking (gitignore-compatible syntax)

.writignore

Same syntax as .gitignore. Created automatically by writ init with sensible defaults:

.git/
node_modules/
__pycache__/
*.pyc
.env
target/
dist/
build/

Add project specific exclusions as needed. Writ respects nested .writignore files the same way git respects nested .gitignore files.

Environment Variables

VariableEffectExample
WRIT_FORMATOverride output formatWRIT_FORMAT=toon writ context
WRIT_COMMIT_MODEOverride workflow modeWRIT_COMMIT_MODE=auto writ finish
WRIT_PROFILEOverride deployment profileWRIT_PROFILE=production writ init