Appearance
When something breaks
What a session start, a sync, or an install can report, what each report means, and what to do. This page owns the symptoms; the pages it links own the mechanisms. Every exit code is in the exit code table.
Exit 8: the source is over the rule cap
What you see: add, sync, or update refuses one source with exit 8, and the hint names --memory and --cap. Nothing is written for that source, and every other source is unaffected.
What it means: the source's rule-flagged set has more memories than ruleCap allows, 25 by default. The cap is a count and a hard gate; truncating would drop the last rule silently.
What to do: install fewer memories, or raise the cap once, which persists it in config.json:
bash
npx -y @vivswan/maxims add @owner/repo --rule -m prefer-timeouts-to-hangs,commit-small-and-often
npx -y @vivswan/maxims add @owner/repo --rule --cap 40Exit 8: a rule file is over the harness byte budget
What you see: the run names the source it holds and how many bytes over the budget the file is, with exit 8. That source is held and every other source in the file refreshes; when the file is still over, the next is held too. The byte budget column of the harness matrix shows which harnesses have one.
Held first is the newest source among those whose block the run changes in the file: holding one whose block is already there as drawn cannot make the file fit. When no block changes (your own text grew the file), the newest source in the file is held.
text
! @you/notes is 716 bytes over the budget for /home/user/AGENTS.md
! narrow the install with --memory or split the source, or keep @you/notes off DeepSeek Harness with maxims unlink @you/notes -a dshWhat it means: the harness loads at most that many bytes, so a larger file would lose rules silently; maxims holds a source rather than truncate. A held source keeps the rules it had on disk. The DeepSeek Harness catch is the case that set the rule.
What to do: give that harness fewer rules from the held source: narrow its selection with --memory, or keep it off that harness with unlink <source> -a <id>.
Exit 5: store locked
What you see: a command waits up to 5 seconds, then exits 5 with this message and hint, <who> being the holder's command line, pid, host, and start time, or an unidentified process when the lock file carries no record:
text
store is locked by <who>
wait for it to finish, or remove <path to state.json.lock> if that process is goneWhat it means: another maxims process holds state.json.lock: a second manual command, or a hook that took the lock first. A hook that meets a held lock exits 0 without waiting, so the hook itself never reports this; the concurrency section owns the rules.
What to do: let the other command finish and run yours again. A lock left behind by a crashed process is stolen after 60 seconds on its own, and the theft is logged.
Exit 4: a harness config could not be written
What you see: exit 4 naming a file, for example a harness config such as settings.json or hooks.json that did not parse, or one that parses only as JSONC where the harness reads strict JSON:
text
cannot edit ~/.claude/settings.json: a trailing comma at line 9, column 44; Claude Code reads strict JSONCodex's config.toml is only read, for its hooks flag, and is never refused: a user or trusted-project one that does not parse is read as hooks off, with the reason in a notice, and an untrusted project's is skipped as Codex skips it; see Codex's unreadable config.
What it means: maxims edits only the parsed tree of a config file and never rewrites one it cannot parse. Your intent is already recorded, so nothing is stranded. The exit code table lists the other exit 4 causes.
What to do: fix the file by hand, a trailing comma or a comment where the format forbids one, then run sync.
Exit 4: stray marker lines surround the block to remove
What you see: remove or unlink exits 4 with these two lines, @you/notes being the source you removed and @old/notes the source the stray lines name. Every later sync prints the same two lines and exits 0 while the block is still there; a hook run puts them in the session's context where the stdout column of the harness matrix says the harness passes sync's output on.
text
! maxims: removing the @you/notes block would pair the stray maxims markers for @old/notes around it into a managed block
! maxims: edit or delete the stray "maxims:begin" and "maxims:end" lines around the block, then retryWhat it means: a <!-- maxims:begin ... --> line and a <!-- maxims:end ... --> line you left in a shared file are plain text while a managed block stands between them; the rule file section owns the markers. Removing that block would join them into a block the next sync takes, your lines with it.
maxims holds the file instead: nothing in it changes, the sources whose block in it this run writes or removes stay at last-good, and any other source refreshes.
What to do: open the file, delete or edit the stray maxims:begin and maxims:end lines the message names, then run sync; the block leaves with that run.
Exit 4: a block's marker carries no version, or another one
What you see: sync exits 4 with these two lines naming the file and the marker line; the sources with a block in the held file, on disk or rendered this run, stay at last-good, and any other source refreshes.
A hook run exits 0 and writes the same two lines without the ! prefix, which reach the session where the stdout column of the harness matrix says the harness passes sync's output on.
doctor reports the file as one x row carrying the same words, checks every other file, and exits 1 as it does for any x row.
text
! maxims: /home/user/AGENTS.md: the marker "<!-- maxims:begin @you/notes sha=3f2a9c1e -->" carries no version; this maxims writes version 1 and cannot refresh the block it opens
! maxims: delete the block from that line through its maxims:end line, then run sync, which writes it afreshWhat it means: the rule file section owns the marker grammar and its version. The block behind that marker can be neither refreshed nor removed, so the file is held rather than given a second block or stripped of yours. A newer version names the upgrade in the hint.
What to do: open the file, delete the block from that maxims:begin line through its maxims:end line, then run sync; the block is written afresh.
Exit 3: nothing resolved to install
What you see: one of three messages, each with exit 3 and nothing written.
| message | cause |
|---|---|
| the file and the character named | a memory carries a hidden character |
a --memory name the source lacks | a misspelled or renamed memory |
| "Found 0 memories", after one warning per skipped file | the wrong folder, or every file fails the contract |
What it means: the install would be incomplete, so maxims writes nothing rather than a set of rules you believe is loaded and is not.
What to do: for a hidden character, fix the file upstream or pass --allow-hidden. For a name, add <source> --list prints the names the source has. For zero memories, check --from, and run lint in the source repo to see the reason per file; the lint section owns it.
state.json was quarantined
What you see: sync prints this line, <path> being the quarantined file beside state.json, named state.json.corrupt-<timestamp>:
text
maxims: state.json was corrupt and moved to <path>; re-add your sourcesWhat it means: the file did not parse against the schema, after a hand edit or a downgrade of maxims past a migration. A state file is never partly obeyed. A dry run or a read-only verb never quarantines; the migrations section owns the rule.
What to do: open the quarantined file, undo the edit, move it back to state.json, then sync. If a downgrade caused it, upgrade maxims first and then move the file back. Otherwise re-add your sources.
A project folder moved or was renamed
What you see: inside the moved folder a sync installs nothing for the project, and list names a project root that no longer exists.
What it means: a project-scope source records its project root in state.json, as destination: {scope: "project", root}, and nothing follows a rename. This is by design; the state schema owns the field.
What to do: edit the root of each of the project's sources, and the project's key under disabled.project and hooks.project, in state.json by hand, the way the moving section edits the other absolute paths, then run sync inside the folder.
--quiet printed nothing
What you see: the hook ran, but nothing from maxims appears in the agent's context, or sync --quiet in a terminal prints no line.
What it means: quiet mode prints only what a session must hear, and a second run within 60 seconds of the last exits as soon as it reads the stamp.
| after a quiet run | on stdout |
|---|---|
| a source gone stale | one maxims: the rules from <key> ... line per source, last good copy kept |
| a write failed | one maxims: <message> line per failure |
| a source was held for a harness's byte budget (the exit 8 section above) | its two lines: the overage and the way out |
| a reviewed source has a revision held for review | maxims: <key> has <n> changed lines held for review; run maxims accept <key> |
| a file a harness reads changed | maxims: rules refreshed (1 file updated), or (<n> files updated) |
under --dry-run, a file a harness reads would change | maxims: rules would be refreshed (<n> files to update); nothing is written |
| none of those | nothing |
the harness's stdout column in the matrix is none or - | nothing reaches the agent, whatever sync printed |
the column is json: | the same lines inside one JSON document, in the named field |
What to do: run sync without --quiet in a terminal to see the full report. log/refresh.log in the canonical home records what each run changed.
Cline reports the TaskStart hook as failed on the first task after install
What you see: Cline flags its TaskStart hook as timed out or failed once, on the first task after add --add-hook, and the task itself goes on.
What it means: Cline stops a hook that has not finished after 30 seconds. The hook runs npx -y @vivswan/maxims sync --quiet, and the first run on a machine with a cold npx cache spends most of that budget downloading the package, so it can cross the limit before sync starts.
Nothing is lost: whatever add wrote is already in place, the rule file included when you passed --rule, and the hook only keeps it fresh.
What to do: Nothing is required. Once the download has completed, the package is cached and later task starts skip it. To finish the download by hand, run the same command once in a terminal and let it end:
bash
npx -y @vivswan/maxims sync --quietThe Cline catch names the hook's other prerequisites.
A sync notice names a harness you defined yourself
What you see: a terminal sync prints this line at every run and skips that harness, @Octocat/rules being the source and my-harness the id from <MAXIMS_HOME>/harnesses.json; list shows the same reason under the source. The adding a harness page owns that file.
text
! maxims: @Octocat/rules: skipped my-harness (not defined in harnesses.json; run maxims unlink <source> -a <id> to drop it)What it means: A source in state still lists that id in intent.harnesses, but the file no longer defines it. Intent is never dropped on its own, so the notice repeats until you change either side. A hook run under --quiet does not print it; log/refresh.log in the canonical home records it.
What to do: Restore the definition in harnesses.json, or take the id out of intent with unlink <source> -a <id> for each source the notice names; the verb table owns unlink.