v0.0.15 - #1
Merged
Merged
Conversation
The root guard used `git rev-parse --show-toplevel`, which inside a leftover `../ts-*` task worktree returns that worktree's root, so the guard passed and BASE_BRANCH became a peer's claim branch — shifting the per-task lock name and letting two instances claim the same todo, with merges landing in the peer's in-flight branch instead of the base. Replace the check with the first entry of `git worktree list --porcelain`, which is always the main worktree, so one compare refuses both the subdir launch and the linked-worktree launch. `--show-toplevel` is removed, not kept as a fallback. - TEST.md: loosen B3's message assertion, add B4 (leftover branch + worktree, launch inside it, assert non-zero exit and no `*-task-*-task-*` branch). - .github/smoke.sh: numbered case 7 for the porcelain|sed main-root form, asserted from both the main and a linked worktree (BSD vs GNU sed).
Increment a per-instance todos-done-<base>-<id> counter at the same merge_task rc=0 point that credits ownership time, so the count and the time credit always agree on who did the work. Report it on the Todos: line and rename the heading to execution stats. Delete the Claude loops accumulator (CLAUDE_TOTAL / WAS_DONE / RUN_START and its per-iteration all_todos_done call). Closes ISSUE-015
…udeZero (ISSUE-018)
`claudezero.sh 2>&1 | tee run.log` captured every TUI redraw and escape
sequence. claude now writes to fd 4, which points at the terminal when stdout
has been redirected and a controlling terminal exists, and falls back to a dup
of stdout otherwise (no redirect, or no tty as in tests/CI/nohup) — so captured
output is unchanged there.
`usage()` gains the logging example with the Ctrl+C-safe `{ trap '' INT; tee
run.log; }` wrapper, plus a comment recording why the braces are load-bearing:
Ctrl+C signals the whole foreground group and a bare pipe reader dies, taking
the closing report with it.
No in-script logging mode: the shell already redirects; this only stops claude
from polluting the redirect.
TEST.md gains Scenario G — G1 asserts the no-tty fallback deterministically
(session-leader detach via setsid or a python3 shim, since macOS has no
setsid), G2 documents the pty check with both BSD and util-linux `script`
syntaxes.
# Conflicts: # claudezero.sh
…vity> Pass --name to the claude launch so the prompt box, /resume picker and terminal title carry the same instance id the execution-stats report heads, plus a dojo student activity picked from the id (16#<first two chars> % 10) so the name is stable across context restarts. Loop mode gets it too. TEST.md Scenario G covers name construction, unsplit argv, restart stability and the derivation. Closes ISSUE-019
Sum the four billed token categories (input, output, cache creation, cache read) from the claude session transcripts, and print them as a headline total with the breakdown beneath the timing rows. The Stop hook now records each session's transcript_path into a per-instance list in the git dir (destination passed via CLAUDEZERO_TRANSCRIPTS, since the hook file itself is shared by all instances in the repo). After claude exits, the loop makes one whole-file awk pass over those transcripts, deduping by requestId — a single API request is written as one line per content block, each repeating the same usage object — and taking only the parent field on each line, never the usage.iterations[] copy or the cache_creation ephemeral leaves that already sum into it. No dollar figure: there is no first-party programmatic rate source, and a hardcoded table would print confidently wrong money after any model launch. Any parse miss prints "Tokens: n/a" and leaves the run untouched. Also renames the report heading from "execution time" to "execution stats" — a token block is not a duration. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
# Conflicts: # .github/smoke.sh # README.md # TEST.md # claudezero.sh
# Conflicts: # claudezero.sh
…SSUE-020) The zero prompt spent three agent steps on one decision — "is this task mine to work?" — and a failed validation in step 2.c left the claim from 2.b behind until a peer stole it. `claim_task` composes the three functions that already sit side by side in the emitted zero.sh: acquire, validate the worktree's branch, then `is_done`. It prints the worktree path on stdout (single field, no newline) and exits 0 when the task is yours; each skip reason goes to stderr with its own code — 1 not claimed, 3 validation failed, 4 already landed — which the prompt treats alike. On exit 3 it clears the session marker but leaves the worktree alone: force-removing a worktree on an unexpected branch would destroy unknown work. `acquire`, `release` and `done` stay as subcommands (TEST.md drives them directly). No new lock, no new fd — acquire's per-task reclaim lock already spans the whole call. Prompt steps b/c/d collapse into one CLAIM step; e/f/g become c/d/e, and the step-letter references in TEST.md were recomputed against the final prompt (the merge references said 2.f while the prompt already had 2.g). TASK_BRANCH stops being an agent variable — failure reports now read the branch with `git -C "$wt" symbolic-ref --short HEAD`. TEST.md gains Scenario H covering all four exit paths, the single-field stdout, the exit-3 claim leak, and the raw-vs-sanitized id split. `claim` goes through ensure_owner, so the driver runs under a copy of bash named `claude`.
# Conflicts: # TEST.md
Every exit path (Ctrl+C break, MAX_LOOPS break) now prints this instance's execution-stats report after credit_inflight_time, then a TOTAL block summing todos, todo time and tokens across every instance of this run. The sum is a glob over the per-instance files in the git common dir — no registry, no flock, no baseline — so a crashed peer's landed work still counts. Solo runs print no TOTAL. TEST.md Scenario I covers the sums, dedupe, solo suppression and degradation. Closes ISSUE-017
Names the claude session `(<id>) <nick> · <activity>`: a 3-5 letter word no
peer running against this repo currently holds, so an operator can say "kill
kit" instead of reading eight hex chars off a terminal title.
The nickname lives on line 3 of the existing $INSTANCE_DIR/<id> liveness
marker, so it is released on exit for free and a crashed instance's name comes
back at the next launch's GC — no registry file, no reservation TTL. The pick
runs once per launch, after the startup GC and under instance.lock, so two
instances launched together cannot draw the same word. Past fifteen live
instances names take an ascending suffix ("bob 1", then "bob 2").
An unreadable registry or a failed lock costs uniqueness, never the launch.
ClaudeZero's own output is unchanged — reports still key on the id.
Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
print_fleet_total suppressed the block whenever the base-slug globs yielded a single instance id, on the grounds that a one-instance total only restates the per-instance block above it. That holds for the figures but not for the heading, which names the instance count — the one figure the per-instance block never carries. Suppressing it made a correct solo sum indistinguishable from a fleet sum that matched no files because the base slug was not what the operator thought. Lower the guard to -ge 1 and pluralize the heading from the same printf, so the block reads identically at every fleet size. n=0 stays silent: absence now has one meaning. TEST.md J2 fabricates this run's own transcript so exactly one id lands on disk, asserts the singular heading and matching figures, and adds a zero-ids case proving the guard is not -ge 0. ISSUE-017's superseded solo-suppression spans point at this bug.
Indices 5, 6, and 9 of dojo_student each claimed a single unit of work, so a name like `(2A56168E) moss · carving one checkbox into ice` asserted a ceiling the instance does not have — it keeps claiming todos until the list is empty. Reword in place at their existing indices; the modulus and the id → index mapping are untouched, so names stay restart-stable. Indices 5 and 6 also stop sharing the checkbox-carving image, so the ten slots are ten distinct labels again. TEST.md's ACT array, ISSUE-019's list and rationale, and ISSUE-021's example name follow the new strings. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
VERSION and a dated CHANGELOG section for the 27 commits on this branch: fleet-wide TOTAL, per-instance tokens and todo counts, session names and nicknames, claude's TUI on fd 4, the collapsed `claim` step, and three fixes (linked-worktree launch guard, solo TOTAL, dojo wording). Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
The tap bump fired on `release: published`, so cutting a version needed a GitHub Release in addition to the tag. Homebrew only needs the tarball at `archive/refs/tags/vX.Y.Z.tar.gz`, which exists as soon as the tag does, and a Release adds nothing the CHANGELOG does not already carry. A tag push has no release payload, so name the tag and commit explicitly via `github.ref_name` and `github.sha`. Not automated: creating the Release from a workflow. A Release created with GITHUB_TOKEN does not trigger other workflows, so a chained tap bump would silently never fire. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
"permission auto mode" reads as a mode named "permission auto"; the flag's own wording is auto permission mode. "zero todos faster" repeats the tool's own jargon where plain "work out todos" carries it.
Zero mode reads the todo through `git show <base>:<path>`, so the list has to live in the repo whose branches carry the work. It sat under the now-ignored `issues/`, where every lookup resolved to nothing. Drops the per-line ticket links: the ticket files stay in the issues repo, which a task worktree cannot see. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
… branch The merge gate diffs the todo against the branch's fork point on the base. A todo that is not tracked there — never added, or gitignored, which the dirty-tree guard does not catch — makes every merge refuse for checking zero boxes, so no task can ever land. Refuse at startup instead. Covered by TEST.md scenario B5.
The execution-stats header printed only the eight hex characters of the instance id, while the terminal title and /resume picker carry the nickname. A report in a scrollback could not be matched to the terminal it came from without reading hex. The nickname is now drawn into INSTANCE_NICK at launch (still one pick_nickname call) and the header reads `execution stats (instance <id> · <nick>)`. ISSUE-027
Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
bash 3.2 — the /bin/bash macOS ships, and what a Homebrew install runs — cannot parse a heredoc inside $(…). `prompt=$(cat <<'PROMPT_EOF' … )` made the whole script unparsable there: "unexpected EOF while looking for matching `''", so the macOS CI leg was red and no mac user could run it. Read the heredoc straight into the variable with `read -r -d ''` instead, trimming the trailing newline `$(cat)` used to strip. Rendered prompt is byte-identical to before, under both bash 3.2 and bash 5. Covered by TEST.md scenario S3.
A descriptor opened from the /dev/tty clone device is not kqueue-registrable on macOS, so a piped run killed claude at startup with `EINVAL … kqueue`. Dup the terminal stdin the shell was handed instead: a real tty fd, opened read-write, so it takes writes and kqueue both. The probe becomes `[ ! -t 1 ] && [ -t 0 ]`. Scenario G drops the setsid/python3 detach dance for a plain `< /dev/null`, and G2 no longer needs a script(1) wrapper — the documented pipe form from a terminal is exactly the case now. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
…s in the readme The changelog's 0.0.15 section missed BUG-026 — the guard that refuses a zero-mode launch when the todo file is not tracked on the base branch. The readme still showed the pre-branch UI: version 0.0.14 in the sample run, no fleet TOTAL block, and no mention of named claude sessions or the fd-4 split that makes a piped run log only ClaudeZero's reports. Quickstart now also says the todo file has to be committed on the branch. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Adds missing articles (notably in the todo-format example line), splits comma splices, fixes the dangling participle in the header, and adds the missing colon before the test command. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Version 0.0.15
What changed
Tests run
/bin/bash3.2*-task-*-task-*branchTokens: n/aboth modes, timing rows kept