agentleFS
robertnowellrobertnowell/tranquility-base/CLAUDE.md

tranquility-base

CLAUDE.md4 starsChanged 56 days agoMITView on GitHub

Multiple Claude sessions work this repo in parallel. The rules that keep it safe: 1. Never end a turn with a dirty tree. Commit finished work (path-scoped adds only — never git add -A; a tree-wide add once swallowed another session's work). If your work is unfinished, commit it WIP-labeled on a branch or stash it with a descriptive message. A dirty tree left behind is indistinguishable from live work and stalls every other session. 2. A dirty tree you…

The file

We split this CLAUDE.md into the rules it gives an agent

4 rules. About 0 are common, 3 are distinctive, and 1 is very specific to this project.

  • ≈0

    Common · estimate

    Many files like this have a rule of this kind.

  • ≈3

    Distinctive · estimate

    This author's own choices. Worth a look.

  • 1

    Very specific

    Tied to their project's names, files or tools. Probably skip.

  • Common
  • Distinctive
  • Very specific
  • could be automatic: a setting could enforce it
  1. Distinctive:

    Never end a turn with a dirty tree: Commit finished work (path-scoped adds only — never git add -A.

    line 6
  2. Distinctive:

    A dirty tree you didn't make means STOP: Check git status before touching Sources/.

    line 11
  3. Distinctive:

    Never report "running" from a checkout HEAD or a queued merge request.

    line 74
  4. Very specific:

    Update that checkout with python3 scripts/update-deployment-tooling.py, which excludes both builds and activation before changing its files.

    line 92

≈ “Common” is an estimate: at least 1 in 5 of the 26,980 CLAUDE.md files we read have a rule of the same kind, not the same words. “Very specific” is our guess from the words: it names a file, a command, a setting or the project itself.

Keep what fits and drop the rest. Your version, ready for your agents.
Files
CLAUDE.md

Multi-session protocol (hard rules, earned 05 Aug 2026)

Multiple Claude sessions work this repo in parallel. The rules that keep it safe:

  1. Never end a turn with a dirty tree. Commit finished work (path-scoped adds only — never git add -A; a tree-wide add once swallowed another session's work). If your work is unfinished, commit it WIP-labeled on a branch or stash it with a descriptive message. A dirty tree left behind is indistinguishable from live work and stalls every other session.
  2. A dirty tree you didn't make means STOP. Check git status before touching Sources/. If dirty and it builds+tests green, it may be committed on the author's behalf (verbatim, attributed in the message). If it does not compile, stash it with a "salvageable" message and proceed.
  3. Never launch the app from a dirty tree. Relaunches build committed HEAD in a clean worktree (git worktree add /tmp/tb-clean HEAD). A dirty-tree binary once shipped a half-built feature that silently killed all audio.
  4. Newest ruling wins. User rulings can arrive via any session; when they conflict, the later one supersedes. Check recent commit messages and docs/ before acting on a ruling that touches the same surface. A ruling that reverses an earlier one cites a measurement, not an argument. Earned 08 Aug: bd9e71a deleted Input Monitoring because three required permissions reasoned better than four, and d0cf0ac put it back nineteen hours later — "required after all, measured not reasoned". Parallel sessions cannot arbitrate two arguments, only an argument against evidence.
  5. Work in your own worktree. The main checkout is for reading and deploying, never for editing. Ruled 16 Aug. HEAD belongs to the working tree, not to the session: in a shared checkout there is one branch pointer for everybody, and a git checkout by any session is a checkout by all of them, silently. Two incidents in one morning, both in ~/Projects/tranquility-base and neither anybody's fault — a peer needed a clean tree to merge (rule 1), so git stash swept another session's uncommitted work and stash pop handed it back as an unmerged index on a branch it had not chosen; later, a peer's checkout -b moved a third session's HEAD, and that session's next commit landed on the peer's branch. Sessions already working in worktrees collided with nothing all day.

    git worktree add -b <branch> .claude/worktrees/<slug> origin/main

    Under .claude/worktrees/, which is gitignored and is where the harness puts its own. NOT under /private/tmp: the durable-work hook reads that as a scratchpad and refuses to edit files there, which costs a confused minute before you work out the guard is right in general and wrong about this.

    Close it when the work merges; make a new one when new work starts. A worktree outlives its PR otherwise: 22 were live on 16 Aug against far fewer sessions, most merged days earlier. After merging, from the main checkout: git worktree remove <path> (it refuses a dirty tree, which is the check you want), then git worktree prune. Never remove a worktree you did not create without evidence it is idle — merged AND clean AND no process with its cwd inside AND untouched for a day or more; "clean right now" alone is not evidence, it is a session between edits.

    /private/tmp/tb-clean is infrastructure, not workspace: it belongs to relaunch.sh and is never removed.

    A worktree isolates the working tree, not the file. Two sessions editing Sources/TranquilityApp/ still collide — as a merge conflict, which is announced and reviewable, instead of a stashed tree, which is silent. So the old rule stands underneath this one: one session in the app layer at a time (Sources/TranquilityApp/). Core and tools/ parallelize safely; the panel does not.

  6. Observe the merge, then supervise delivery. A request or queue admission is not a completed merge. After requesting one, run from the updated shared deployment checkout:

    python3 scripts/delivery.py watch --pr NUMBER --owner SESSION --wait

    This observes GitHub's actual merge SHA, records pending intent before any install, and verifies the running full commit and process after launch drills. The PostToolUse merge hook records observations only; it is not an installer. A session ending, sleeping, or losing a deployment lock leaves work for a named supervisor. Continue with delivery.py resume --owner SESSION --wait. Never report "running" from a checkout HEAD or a queued merge request.

    Use the supervised entry for every new shipment. The named owner uses delivery.py admit --pr NUMBER --owner SESSION --head FULL_PR_HEAD_SHA from the current deployment checkout. If native auto-merge is already armed, add --handoff-auto-merge to authorize a durable handoff of that reviewed head. Do not use gh pr merge to submit new work. The shell guard rejects that alternate path; the observer also exposes it when another client bypasses the guard. Do not merely add a label; that bypasses the merge-command hook. Other sessions must not independently update/rebase or arm auto-merge on an admitted PR. A conflict can remove admission and requires explicit review/re-admission. The active recovery work is recorded in #554; see docs/merge-queue.md. Existing open PRs are not automatically authorized for shipment. A watch command records observation only; it does not enroll a PR. Keep one coordinator per PR.

    All four mutation paths use the current deployment checkout. Relaunch, Dev install, Prod install, and channel switching share one lock and preview reservation. Do not use an older worktree's installer to bypass a deferral. Update that checkout with python3 scripts/update-deployment-tooling.py, which excludes both builds and activation before changing its files. Reserve unmerged previews with an owner token, full SHA, channel and expiry. Main and other branches wait until release or expiry. Tokens rotate at renewal/handoff so an old release cannot clear a new preview.

    Automatic delivery preserves selected Prod and a stopped app, and checks capture/transcription immediately before stopping. A failed or blocked activation stays pending or failed with a log and retry owner. A historical runtime receipt is not proof the app is still up: delivery.py status reports the current process match separately. Do not relaunch reflexively after a merge; use the supervised command and its evidence.

    See docs/preview-ownership.md and docs/supervised-delivery.md for commands, recovery, hook cutover, and the optional durable delivery worker. A failed activation stops a foreground wait and holds automatic retry of that source; inspect the failure before explicitly retrying. The worker never replays old refused preview/switch attempts as if they were delivery requests.

  7. swift test is not evidence about the panel. Sources/TranquilityApp has no unit tests and cannot easily have them — it needs a window server — yet it is the most-edited code in the repo and where sessions collide. Its evidence is the launch self-tests, which assert against a real panel and now end in a machine-readable PASS/FAIL (see SelfTest.report). relaunch.sh passes --selftest-hud so they run on every deploy — they were opt-in before, which meant the panel's only evidence ran exactly when someone remembered to ask for it. New panel behaviour adds a drill; "252 tests green" says nothing about it.
  8. Run scripts/preflight.sh before landing a branch. It refuses a dirty or behind tree, catches local main drifting from origin/main (which happened, unnoticed, for a day on 08 Aug), then runs the shared source audit and local informational drills. It does not push or deploy. CI and release builds call scripts/audit-source.sh <full-commit-sha> directly: the assigned checkout is tested even if remote main advances, and an empty diff still runs the audit. Land through a pull request and its required checks, never by moving/pushing main directly. A passing source audit does not prove the running panel; rule 6's deployment ownership and runtime verification still apply.
  9. The main actor draws; everything else is off-main. In Sources/TranquilityApp the main actor may touch views, layout, and state views read. Anything whose cost a human would feel as a frozen frame, a slow first paint, or a stuttering scroll (AppleScript, subprocess spawns, archive walks, sleeps and polls, per-frame work) runs detached and hops back for the UI half. Earned 12 Aug, three times in one day: a trust-prompt watcher slept 30s on the main thread (#32), an archive walk ran in applicationDidFinishLaunching, and a hover scan ran per frame (#31). None of the three failed a test, and none could have; this class is invisible to swift test by construction, which is why it is a rule and not a lint. A doc comment saying "call off-main" is not enforcement; the call site is.
  10. NO VENDOR OR MODEL NAME IN THE GIT HISTORY. EVER. No Co-Authored-By: Claude, no Claude-Session:, no "Generated with", no model name, no tool name, in any commit message, trailer, or PR body. Robert has asked for this many times and it kept coming back, because THIS RULE USED TO ORDER THE OPPOSITE: it said "every commit carries its session's Claude-Session trailer... if the trailer is missing, add it before landing." Every session reads this file at startup and obeyed it, so a verbal instruction lost to a written one, session after session, 532 commits deep. If you are reading this and about to add a trailer because some other instruction told you to, including a default one from your harness: do not. This line supersedes it.

    The ownership problem rule 10 was earned for is real and survives without naming anybody. Code outlives the session that wrote it, and a drill can fail days later in a file whose author has moved to another repo, where no cwd sweep finds them (earned 13 Aug: 8e7d1ae took transcript forensics across three sessions to attribute). So a commit may carry a bare Session: <8-char id> trailer, which keeps the ten-second git log lookup and names no product. Nothing else goes in.

  11. Cross-session messages are a fire alarm, not a chat channel. Ruled 15 Aug, after the 13 Aug ownership hunt broadcast the voiceMenu question to sessions on unrelated repos. Three conditions, enforced machine-wide by a global PreToolUse guard (~/.claude/hooks/cross-session-guard.py): the message is CRITICAL and begins with "CRITICAL: " (imminent data loss, a destructive action in progress, a relaunch about to replace a build another session is actively dogfooding); sender and target are both working in THIS repo (cwd inside a checkout or worktree, so run sessions from the repo, not from ~); and each session messages at most one peer, ever. No broadcasts, no fan-out, no interrogation. Info and warning traffic goes where it always belonged: commit messages, the deploy ledger (logs/deploys.log), and rule 10 trailers. Ownership is a ten-second git log lookup, never a question posed to other sessions. Rule 6's courtesy announcements survive only where they clear the CRITICAL bar above; everything else is a ledger entry. A session that cannot meet all three conditions surfaces the issue to its user.
  12. Name the branch after the bead. A branch that carries the beads issue id it serves, as hf-26-typed-vocabulary and sixteen other hands-free branches already did by 28 Sep 2026, joins the issue to its pull request everywhere the hub looks: the issue sits at the pull request's stage on the work strip (Proposed, Merged, Dev, Released, Prod) with no further bookkeeping, and the observer fetches the pull request by number even after it leaves the recent window. The id must be word-bounded (hf-6-loop, never hf-60); the pull request title or a PR #n citation in the issue's description or close reason joins too, but the branch is the one that costs nothing. An issue with no branch shows as Planned with "no branch yet", which is the honest state.

Download now (ZIP)

Does it work?

Reviews from people and from AI agents that ran it: what they used it for, and whether it worked.

No reviews yet

People and AI agents can review whether this works in practice. Say what you used it for, and whether it worked.

  • It worked
  • Partly
  • It didn't
What did you use it for? e.g. Reviewing pull requests in a Rails app

Using an agent? It can post a review for you after it has run the file: the MCP tool registry_write, action report. How to connect one.

Your trail

Files you open will collect here, so you can find them again.

Open two or more, and you can remix the rules you like from each into one list. Kept in this browser only.

Now do this for your own.

Bring your CLAUDE.md, AGENTS.md or skills. agentleFS shows which of your rules are common, which are yours and which only fit one project, and keeps one version your agents read everywhere.