warden v0.10.1

Project files reference

On this page

Every file and folder warden reads or writes in your project, what each is for, and which ones you commit.

This page is also the map of the .warden/ folder. Each doc folder has one job, listed below.

The .warden/ layout#

.warden/
  warden.json            project id, task id format, site port, warden version   (committed)
  steps.json             setup, checks, review, triage, fixer scope               (committed)
  triage-rules.json      known failure patterns, added by the fixer               (committed)
  reports.md             table of reports sent to the warden maintainers          (committed)
  tools/                 the project's own tools and their roles                  (committed)
  flows/                 saved flows                                              (committed)
  context/               facts about the project                                  (committed)
  rules/                 rules every agent step must follow                       (committed)
  decisions/             choices that were made                                   (committed)
  knowledge/             facts learned while working on the code                  (committed)
  checks/                periodic checks                                          (committed)
  retros/                retro notes                                              (committed)
  fixes/                 notes from the fixer                                     (committed)
  history/<task>/        the run record of each shipped task                      (committed)
  state/                 live run state                                           (gitignored)

Each doc folder (context, rules, decisions, knowledge, checks, retros, fixes, flows) has an INDEX.md with one line per file.

Files at a glance#

PathWritten byRead byCommittedEdit by hand?
.warden/warden.jsonwarden init --write, warden upgrade --doneevery commandyesRarely. Locked while a run is live
.warden/steps.jsonwarden init --writestart (copy from the main branch), gatesyesYes, on the main branch. Locked while a run is live
.warden/triage-rules.jsonwarden init --write (empty), the fixertriage, fix landingyesNormally only the fixer. Locked while a run is live
.warden/reports.mdwarden report, warden report --status --writesession startyesNo
.warden/tools/index.ts, tool.tswarden tools --init, then youwarden toolsyesYes, it is your code
.warden/tools/roles.jsonwarden tools --init, then youwarden tools, orchestrate, hooksyesYes. Locked while a run is live
.warden/tools/replaces.jsonwarden tools --init, then youwarden tools --usage, warden tools --skillyesYes
.claude/skills/project-tools/SKILL.mdwarden tools --skillClaude Code (the agent)yesNo: run warden tools --skill again
.warden/flows/<name>.jsonwarden flow savewarden start --flowyesYes. Locked while a run is live
.warden/context/*.md/warden:init, then youagent steps (via INDEX.md), siteyesYes
.warden/rules/*.mdyou, retrosevery agent stepyesYes
.warden/decisions/NNNN-*.mdplan steps, agents, youagent steps (via INDEX.md)yesAdd new ones; never edit an old one
.warden/knowledge/*.mdagents, spikes, the fixeragent steps (via INDEX.md)yesYes
.warden/checks/*.mdwarden init --write, youwarden checks, session startyesYes
.warden/retros/<date>.md/warden:retrothe retro checkyesNo
.warden/fixes/*.mdthe fixertriage rules, the fixeryesNo
.warden/history/<task>/the engine, at the ship stepsite, retroyesNever. The hooks refuse it
.warden/state/the engine and hooksevery commandno (gitignored)Never. The hooks refuse it
scripts/warden-setup.shwarden init --write, then you, the fixersetup.commandsyesYes
.gitignorewarden init --write adds .warden/state/ and .worktrees/git, warden start --worktree (checks .worktrees/ is ignored)yesYes
.claude/settings.jsonwarden init --write with teamInstallClaude CodeyesYes
.worktrees/warden start --worktree, the engine (fix worktrees, triage clean copies)git, warden cleanno (gitignored)Only through a run's own rules

"Locked while a run is live" means the hooks refuse edits to the file while any run is active, waiting or blocked. See hooks.


.warden/warden.json#

json
{ "schema": 1, "wardenVersion": "0.6.1", "projectId": "pg", "taskIdPattern": "^PG-\\d{3}$", "sitePort": 4400 }
FieldTypeDefaultRule
schemanumber—Must be 1
wardenVersionstringthe installed version at initA semver such as 0.6.1. The warden version this layout matches. When the installed warden is newer, session start offers /warden:upgrade
projectIdstring—Matches ^[a-z][a-z0-9-]{1,40}$. Used in report records and temp folder names
taskIdPatternstring—A JavaScript regular expression that starts with ^ and ends with $. warden start refuses a task id that does not match
sitePortinteger44001 to 65535. The port of warden site
lastRetrostring or null—Old key (before 0.2). Still read when .warden/checks/retro.md is missing; warden upgrade --done removes it
siteobject—0.7. Settings of warden site; its only key is thresholds, the limits of the warning signals (see below). Only the site reads it: a bad value never breaks a run, and warden upgrade --done keeps it as it is

site.thresholds (every key optional; a bad value falls back to its default and shows under Project health):

KeyDefaultRule
slowFactor2A number from 1 to 10. A step is slow above slowFactor × its usual time
minSlowSec120A step is never slow before this many seconds
minSamples5Runs of a step type needed to learn its usual time; with fewer, usualSec is used
sampleSize201 to 200. How many of the newest runs the usual time (a median) is learned from
usualSecanalyze, plan, check, review, ship 600; implement 1200; fix 900Usual seconds per step type until enough runs are known
loopBounces3Bounces in one run that flag a loop
fixerRounds2Fixer rounds in one run that flag a loop
rejectedOutputs3Rejected outputs in a row at one step that flag a loop
fixerOutSec1800A fixer that has not returned after this long is flagged
fixLandingSec1800Time limit of landing a merged fix
jobGraceSec300Extra time past a gate's limit before it is flagged overdue

Every value but slowFactor is an integer of at least 1. See lead overview.

.warden/steps.json#

See the steps.json reference.

.warden/triage-rules.json#

Known failure patterns. A rule only labels a failure; it never decides the verdict. The fixer adds a rule with each fix, and the engine reads the rules from the main branch only.

json
{ "schema": 1, "rules": [
  { "id": "TR-0001", "pattern": "^error: PORT is not set$", "flags": "", "verdict": "OPS",
    "fixNote": ".warden/fixes/2026-10-01-PG-012.md", "task": "PG-012", "addedAt": "2026-10-01" } ] }
FieldTypeRule
idstringTR-NNNN, unique
patternstringA JavaScript regular expression, tested against each line of the failing log (after warden replaces folder paths with <root> and <tmp>)
flagsstring"" or "i"
verdictstringOPS or UNCLEAR. Never CODE
fixNotestringPath of the fix note, .warden/fixes/<file>.md
taskstringThe task that added the rule
addedAtstringA date

A new rule must be narrow: it must match a line of the failing log and no line of any log from a command that passed in the same run.

.warden/reports.md#

A Markdown table of the reports this project sent to the warden maintainers:

| ID | Title | Status | Fixed in |
|---|---|---|---|
| R-eb85-0001 | warden wait times out on a slow review | fixed | 0.6.1 |

warden report adds a row. warden report --status --write brings the rows up to date. Session start never changes this file; it only tells the agent when a status changed. The report records themselves live in the data folder (see environment). It is always the main checkout's copy that changes, also when the command runs in a task worktree.

.warden/tools/#

The project's own tools. See tools and roles and write a tool.

FilePurpose
index.tsexport default [ ...tools ]. Only tools listed here exist; warden never scans the folder
tool.tsThe contract types (Tool, Check, DagTicket, TicketDetail, SetStatusResult, and from 0.8 CreateResult and LinkResult) and the command() helper. Written once; the project owns it
roles.jsonRole name to tool name, for example {"tickets": "backlog", "graph": "graph", "pr": "git-pr"}. Starts as {}
replaces.jsonTool name to the raw commands it covers, for example {"pr": ["gh pr", "az repos pr"]}. Nothing is refused for it: the project tools skill points the agent to the tool, and warden tools --usage counts those commands for the retro (0.10). Starts as {}
<name>.ts or <name>/One tool per file or folder

Role and tool names match ^[a-z][a-z0-9-]{0,40}$. warden uses the roles tickets, graph and pr.

.warden/flows/#

Saved flows, <name>.json, plus INDEX.md with lines - <name>.json: <description>. Written by warden flow save. See flow files.

Doc folders#

Each folder has a single purpose. Keep each file under 200 lines and give it a line in the folder's INDEX.md. warden docs check (and the built-in warden-docs check, once a day) checks this for context, rules, decisions, knowledge, checks and retros.

FolderHoldsHow agents see it
context/Facts about the project: overview, architecture, stack, glossary and other topics. Facts only, no rulesIts INDEX.md is in every agent step's "Read as needed" section
rules/Rules every agent step must follow, often a mistake that kept coming back (<topic>.md)The text of every file (sorted by name, at most 16 KiB in total) is in every agent step's "Project rules" section
decisions/One file per choice made, NNNN-<slug>.md with the next free four-digit number. Never edit an old one; write a new one that replaces itIts INDEX.md is in "Read as needed". A plan step lists the files it wrote in decisions
knowledge/Facts about the code learned while working (<area>.md), spike notesIts INDEX.md is in "Read as needed"
checks/Periodic check definitions, see belowwarden checks, session start
retros/Retro notes, <YYYY-MM-DD>.md (a second retro on the same day adds a section)The retro check
fixes/Fix notes from the fixer, <YYYY-MM-DD>-<task>[-n].mdThe triage rule that points at the note; the fixer gets the note when the rule matches again

The site (warden site) shows the files of context, rules, decisions, knowledge, checks, retros and fixes.

An INDEX.md line is a list item. Either a link, - [Title](file.md), or a name and a description, - file.md: description.

Fix note format#

The fixer writes it, and warden checks these headings exactly:

markdown
# Fix 2026-10-01 PG-012
## Symptom
## Root cause
## Fix
## Test
## How triage should classify this next time

.warden/checks/#

One Markdown file per periodic check, <name>.md, with name matching ^[a-z][a-z0-9-]{0,40}$. The file starts with a frontmatter block between two --- lines.

markdown
---
every: 1d
kind: command
run: warden docs check
auto: true
timeoutSec: 60
---
# Warden docs check

What the check is for, and what to do when it fails.
KeyKindsRequiredRule
everybothyes<n>d, with n from 1 to 365 days
kindbothyescommand (warden runs run) or agent (the agent follows the text)
runcommandyesShell command, run in the main checkout
autocommandnotrue or false (default). true: session start runs it in the background when due. false: session start offers it
timeoutSeccommandno1 to 540, default 300
lastbothnoYYYY-MM-DD or never. Only the starting value; once the check ran, the date in .warden/state/_checks/<name>.json wins

Unknown or repeated keys make the file invalid. For an agent check, the text after the frontmatter (up to a ## Results heading, if any) is what warden checks run <name> prints as instructions.

warden init --write adds two built-in checks:

FileKindEveryWhat it does
retro.mdagent2dOffers a retro (/warden:retro). last is set to the init date
warden-docs.mdcommand, auto1dRuns warden docs check

When retro.md is missing, warden still lists a retro check built from the old lastRetro field.

.warden/history/<task>/#

The run record, written by the engine when the run enters its ship step, into the task worktree. The ship step commits it with the change, so it lands on the main branch with the PR. A run without a ship step (for example do) has no history folder.

FileContent
run.jsonThe run as it was at ship entry, with status: "shipping"
flow.jsonThe flow the run used
task.mdThe task text
plan.mdThe plan, when a plan step ran
events.jsonlEvery event up to the ship step
triage/<n>.jsonEach triage report
review/<round>-<try>.jsonEach review round
review/leftover.mdBlocking findings left after the last review round, when there were any
summary.jsonTime, tokens and estimated cost per step, rounds, verdicts, findings, author, commit, branch

Logs, raw reviewer output and the steps.json copy are not copied. The engine rewrites the folder each time the run enters the ship step again.

summary.json:

ts
{
  schema: 1; task; flow; status: "shipping";
  startedAt; endedAt; durationMs;
  steps: { id, type, startedAt, endedAt, durationMs, attempts,
           tokens: { input, output, cacheRead, cacheWrite }, costUsd }[];
  rounds: { review, fixer, checkRuns, codeStrikesTotal };
  verdicts: { verdict: "CODE" | "OPS" | "UNCLEAR"; rule: string | null; at }[];
  findings: { blocking, minor, dropped, leftovers };
  tokens: { input, output, cacheRead, cacheWrite }; costUsd;   // costUsd is an estimate
  author: { name, email }; commit; pr: null; branch;
}

Tokens come from the transcripts of the sessions and subagents linked to the task. The reviewer's tokens and cost are added to the review step.

.warden/state/#

Live state. It is gitignored and lives in the main checkout only, even for runs in other worktrees. Never edit it by hand; use warden reset to remove a run.

.warden/state/
  <task>/
    run.json               the run: status, current step, counters, proofs, waiting reason
    flow.json              the flow copy
    steps.json             the steps.json copy from the main branch
    task.md                the task text
    plan.md                the accepted plan
    events.jsonl           one event per line
    sessions.jsonl         the sessions and subagents that worked on the task
    gate.log               output of the engine worker
    setup-<i>.log          setup at start
    retry-setup-<i>.log    setup after a retry merged the main branch
    checks/<n>/<name>.log  check command logs, one folder per check run
    triage/<n>.json        triage reports; triage/<n>/ holds their logs
    review/<round>-<try>.json, .raw.txt   review rounds and the reviewer's raw output
    review/leftover.md     findings left after the last review round
    outputs/<seq>-<step>.json             every hand-in, accepted or not
    fix/<n>.json, fix/<n>-repair-<i>.log  fixer outputs and repair logs
    .lock                  the task lock
  _sessions/               one record per Claude Code session (and per subagent)
  _checks/<name>.json      periodic check results; <name>.log and <name>.lock while running
  _orchestrate/<epic>.json the cached orchestrate plan
  _reports.json            report statuses already told at session start

Folder names that start with _ are not tasks.

run.json fields you will meet#

FieldMeaning
statusactive, waiting, blocked, shipped, done or archived (0.9.4: closed without doing it)
current{id, type, startedAt, startSha, startDirty, attempt, mode?}. id is a flow step id, or fix-<n>
waiting{kind, reason, since} with kind approve, merge-fix, human (blocked) or question, or null
counterscodeStrikes, fixerRounds, reviewRound, checkRuns, triageCount, staleProofs
limitsThe limits in force (flow limits, else defaults)
proofs{stepId, kind, sha, at} for each gate that passed since the latest implement
routeBackWhy the run went back to an earlier step: {from, reason, kind, triageReport?, logTail?, findings?}, kind code, review, fixer-code, rejected or dirty
gateThe running engine job (check, review, ship-prep, fix-landing), or null
fixThe fix in progress: {n, worktree, branch, baseSha, verdict, report, mayMerge}, or null
leftoversPath of review/leftover.md, or null
tickettrue for a run started from a ticket (every run since 0.9; runs started from text before 0.9 have none). Warden sets the ticket to done once the ship reports the task merged. Runs from 0.6.1 to 0.9.2 may also hold ticketFiles and ticketError, which 0.9.3 ignores

Event types#

Events in events.jsonl have {seq, ts, task, type, step?, data?}. Types:

run.started, step.started, step.ended, output.accepted, output.rejected, gate.started, gate.command, gate.passed, gate.failed, gate.restarted, gate.discarded, triage.verdict, fix.started, fix.result, fix.landed, review.round, route.back, approve.waiting, approve.granted, approve.rejected, approve.skipped, run.blocked, run.retry, retry.merged-main, history.written, run.shipped, run.done, run.archived (0.9.4, with the reason), session.linked, stop.blocked, hook.denied, git.fetch-failed, proof.stale, ticket.status, question.asked, question.answered.

Files outside .warden/#

PathPurpose
scripts/warden-setup.shThe setup script. setup.commands runs it with sh. It should start with set -e and do what a fresh checkout needs (install packages, copy .env.example)
.worktrees/<task>The task worktree made by warden start --worktree. .gitignore must list .worktrees/. warden clean removes it once the task shipped and its branch is merged
.worktrees/<task>-fix-<n>The fixer's worktree, on branch warden-fix/<task>-<n>. Removed when the fix step ends
.worktrees/<task>-clean-<n>Triage's clean copy of the main branch. Always removed afterwards
<parent>/<repo>.worktrees/<task>Where warden before 0.8 put task and fix worktrees. Runs started then keep using them
$TMPDIR/warden-setup-<task>-<ms>.logThe setup log kept when setup fails at warden start
.claude/settings.jsonWith teamInstall, gets extraKnownMarketplaces["warden-marketplace"] (source copied from your install, autoUpdate: true) and enabledPlugins["warden@warden-marketplace"]: true
.claude/settings.local.jsonBefore 0.8, warden start --worktree added <repo>.worktrees to permissions.additionalDirectories. Keep it while runs from then are left

Task branches default to the task id in lower case. Fix branches are warden-fix/<task>-<n>.

What to commit#

Commit everything under .warden/ except state/, plus scripts/warden-setup.sh, .gitignore, and .claude/settings.json when you use the team install. warden start reads .warden/ from the main branch, so push it there before the first run.

See also#

Type to search titles, headings and text.