Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
6 changes: 6 additions & 0 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -27,6 +27,12 @@
# Refreshed per turn by mise-tasks/stop-guard.sh from the Stop payload; committing
# it would put a whole session's prose in the tree.
/.claude/.transcript.jsonl
# Its sibling for the session task store (CLOUD-1376), derived beside it and
# refreshed from the same Stop payload. Committing this one leaks no prose — a
# symlink is a path — but it names ONE container's session by id, so every other
# checkout inherits a dangling pointer, and `doctor session` reads a dangling link
# as could-not-look forever. The engine writes it; the tree never carries it.
/.claude/.tasks

# Per-user local Claude memory — never shared (personal overrides of CLAUDE.md).
CLAUDE.local.md
Expand Down
6 changes: 3 additions & 3 deletions AGENTS.md
Original file line number Diff line number Diff line change
Expand Up @@ -144,9 +144,9 @@ a pager (the exit status becomes the pager's) or detaching it with `nohup`/`&`
(the wake-up is lost). Redirect to a file; put `run_in_background` on the long
command, never on a launcher that returns at once. Gated by `verdict-not-discarded`.
**Never** use a foreground `sleep`, spin a foreground busy-poll, or end a turn idle
"to watch" something — background it and act on its exit, and commit first, since
**committed-and-pushed is the only state that survives a VM reclaim**. A bounded
background run means a real exit condition, not a wall-clock cap on the CI poll.
"to watch" something — background it, act on its exit, and commit first, since
**committed-and-pushed is the only state surviving a reclaim, and that is the TREE's
half**: declared work dies too, so **"safe to end?" is `batten doctor session`**.

## Non-negotiable project rules

Expand Down
20 changes: 20 additions & 0 deletions batten.toml
Original file line number Diff line number Diff line change
Expand Up @@ -266,8 +266,28 @@ mutation = "change it in a pull request — a registered module is protected bec
# observed zero.
#
# `memory_root` is omitted, so `selfwrite::DEFAULT_MEMORY_ROOT` applies.
#
# `tasks` NAMES THIS HOST'S SESSION TASK STORE (CLOUD-1376), and it is the
# consumer's fact rather than the engine's: the store sits outside the repository
# root and its layout belongs to the launcher, so deriving it in `crates/batten`
# would be a directory layout in the core (rule 1). `{session}` is the ONLY thing
# the engine substitutes, from the id the envelope already normalises across
# hosts, and `batten doctor session` opens what that names.
#
# WHY IT IS ON THIS TABLE. The header above already carries two facts about one
# host — the transcript's format and the memory root — and `transcript.rs` states
# why they share a table rather than splitting: a second table over the same
# subject is the widening rule 6 forbids. The task store is a third fact about
# that same host.
#
# WHAT DECLARING IT BUYS, measured 2026-09-02: asked "safe to archive?", this
# consumer's own agent enumerated the working tree, the stash, local branches and
# running processes, found all four clean, and answered yes — while
# `21.json` in that store read `"status": "pending"`. Undeclared, the verb answers
# could-not-look, which is honest and useless. Declared, it answers `1`.
[transcript]
path = ".claude/.transcript.jsonl"
tasks = "~/.claude/tasks/{session}"

# ---------------------------------------------------------------------------
# Pinned tools (CLOUD-90), fetched and cached out of tree.
Expand Down
73 changes: 70 additions & 3 deletions completions/batten.bash
Original file line number Diff line number Diff line change
Expand Up @@ -292,12 +292,18 @@ _batten() {
batten__subcmd__doctor,hooks)
cmd="batten__subcmd__doctor__subcmd__hooks"
;;
batten__subcmd__doctor,session)
cmd="batten__subcmd__doctor__subcmd__session"
;;
batten__subcmd__doctor__subcmd__help,help)
cmd="batten__subcmd__doctor__subcmd__help__subcmd__help"
;;
batten__subcmd__doctor__subcmd__help,hooks)
cmd="batten__subcmd__doctor__subcmd__help__subcmd__hooks"
;;
batten__subcmd__doctor__subcmd__help,session)
cmd="batten__subcmd__doctor__subcmd__help__subcmd__session"
;;
batten__subcmd__generate,completions)
cmd="batten__subcmd__generate__subcmd__completions"
;;
Expand Down Expand Up @@ -505,6 +511,9 @@ _batten() {
batten__subcmd__help__subcmd__doctor,hooks)
cmd="batten__subcmd__help__subcmd__doctor__subcmd__hooks"
;;
batten__subcmd__help__subcmd__doctor,session)
cmd="batten__subcmd__help__subcmd__doctor__subcmd__session"
;;
batten__subcmd__help__subcmd__generate,completions)
cmd="batten__subcmd__help__subcmd__generate__subcmd__completions"
;;
Expand Down Expand Up @@ -2544,7 +2553,7 @@ _batten() {
return 0
;;
batten__subcmd__doctor)
opts="-J -q -v -y -h --json --strictness --fail-on-warning --config-from --config-in --silent --quiet --verbose --debug --trace --log-level --no-color --no-input --yes --help hooks help"
opts="-J -q -v -y -h --json --strictness --fail-on-warning --config-from --config-in --silent --quiet --verbose --debug --trace --log-level --no-color --no-input --yes --help hooks session help"
if [[ ${cur} == -* || ${COMP_CWORD} -eq 2 ]] ; then
COMPREPLY=( $(compgen -W "${opts}" -- "${cur}") )
return 0
Expand Down Expand Up @@ -2574,7 +2583,7 @@ _batten() {
return 0
;;
batten__subcmd__doctor__subcmd__help)
opts="hooks help"
opts="hooks session help"
if [[ ${cur} == -* || ${COMP_CWORD} -eq 3 ]] ; then
COMPREPLY=( $(compgen -W "${opts}" -- "${cur}") )
return 0
Expand Down Expand Up @@ -2615,6 +2624,20 @@ _batten() {
COMPREPLY=( $(compgen -W "${opts}" -- "${cur}") )
return 0
;;
batten__subcmd__doctor__subcmd__help__subcmd__session)
opts=""
if [[ ${cur} == -* || ${COMP_CWORD} -eq 4 ]] ; then
COMPREPLY=( $(compgen -W "${opts}" -- "${cur}") )
return 0
fi
case "${prev}" in
*)
COMPREPLY=()
;;
esac
COMPREPLY=( $(compgen -W "${opts}" -- "${cur}") )
return 0
;;
batten__subcmd__doctor__subcmd__hooks)
opts="-J -q -v -y -h --json --strictness --fail-on-warning --config-from --config-in --silent --quiet --verbose --debug --trace --log-level --no-color --no-input --yes --help"
if [[ ${cur} == -* || ${COMP_CWORD} -eq 3 ]] ; then
Expand Down Expand Up @@ -2645,6 +2668,36 @@ _batten() {
COMPREPLY=( $(compgen -W "${opts}" -- "${cur}") )
return 0
;;
batten__subcmd__doctor__subcmd__session)
opts="-J -q -v -y -h --json --strictness --fail-on-warning --config-from --config-in --silent --quiet --verbose --debug --trace --log-level --no-color --no-input --yes --help"
if [[ ${cur} == -* || ${COMP_CWORD} -eq 3 ]] ; then
COMPREPLY=( $(compgen -W "${opts}" -- "${cur}") )
return 0
fi
case "${prev}" in
--strictness)
COMPREPLY=($(compgen -W "permissive standard strict" -- "${cur}"))
return 0
;;
--config-from)
COMPREPLY=($(compgen -f "${cur}"))
return 0
;;
--config-in)
COMPREPLY=($(compgen -f "${cur}"))
return 0
;;
--log-level)
COMPREPLY=($(compgen -W "silent quiet normal verbose debug trace" -- "${cur}"))
return 0
;;
*)
COMPREPLY=()
;;
esac
COMPREPLY=( $(compgen -W "${opts}" -- "${cur}") )
return 0
;;
batten__subcmd__enforce)
opts="-J -q -v -y -h --rule --json --strictness --fail-on-warning --config-from --config-in --silent --quiet --verbose --debug --trace --log-level --no-color --no-input --yes --help"
if [[ ${cur} == -* || ${COMP_CWORD} -eq 2 ]] ; then
Expand Down Expand Up @@ -3418,7 +3471,7 @@ _batten() {
return 0
;;
batten__subcmd__help__subcmd__doctor)
opts="hooks"
opts="hooks session"
if [[ ${cur} == -* || ${COMP_CWORD} -eq 3 ]] ; then
COMPREPLY=( $(compgen -W "${opts}" -- "${cur}") )
return 0
Expand All @@ -3445,6 +3498,20 @@ _batten() {
COMPREPLY=( $(compgen -W "${opts}" -- "${cur}") )
return 0
;;
batten__subcmd__help__subcmd__doctor__subcmd__session)
opts=""
if [[ ${cur} == -* || ${COMP_CWORD} -eq 4 ]] ; then
COMPREPLY=( $(compgen -W "${opts}" -- "${cur}") )
return 0
fi
case "${prev}" in
*)
COMPREPLY=()
;;
esac
COMPREPLY=( $(compgen -W "${opts}" -- "${cur}") )
return 0
;;
batten__subcmd__help__subcmd__enforce)
opts=""
if [[ ${cur} == -* || ${COMP_CWORD} -eq 3 ]] ; then
Expand Down
Loading