Skip to content

anthrex 0.3.0

Pre-release
Pre-release

Choose a tag to compare

@github-actions github-actions released this 20 Oct 11:56
· 16 commits to main since this release
c63f55c

The protocol version is now 26 (22 for milestone 9.13's OrchestratorInfo.untrusted,
23 for milestone 9.14's build admission, 24 for milestone 9.15's lessons, 25 for
milestone 9.16's brakes: RunRequest::Hold, RunReply::Held, RunsSnapshot.brakes,
RunInfo.handoff, a routing decision's failover, the settings document's brakes;
26 for milestone 9.17's plan and review quality: a finding's target, the brief
task note kind, RunInfo.plan_frame, PlannerInfo.frame, TaskInfo.replaces and
replaced_by, add_task's replaces, a task record's replaces and
brief_findings, and HistoryStats.replaced): a client needs a daemon of the same
release. Stop the old daemon (anthrex daemon stop) after upgrading.

Downgrading. run.json is now format 7 (milestone 9.15: a run's frozen lessons,
its discard reason, a task's lessons shown and risk note, and the distill and
risk-note ops; milestone 9.16: a run's failovers and its context handoff; milestone
9.17: a run's plan frames, an epic's frame, the approved spec's Non-goals, a task's
replaces, a finding's target and the brief notes; milestone 9.19: each design
agent's raw token usage). A 0.2.0 daemon skips a run
this release wrote (run format 7; this one reads up to 1) and
leaves it as it is, as does any daemon that reads an older format. The hold lives in
brakes.json in the data directory, which older releases ignore: an older daemon
does not hold dispatch. Releases before
0.2.0 have no such guard and can drop this release's new run fields when they save
(the untrusted-read record, the orchestrator's retry count, the pinned gate files, a
pending override proposal and an override count's protected list): finish or discard
your runs before downgrading below 0.2.0.

Added

  • Reviewers see what the run is for (milestone 9.17). Every reviewer prompt now
    has the run goal as its second line (Run goal: …, the same line the worker gets),
    and, before the brief, the plan's out-of-scope list (Out of scope for this run …)
    or, in a design-flow run, the approved spec's Non-goals.

  • brief findings. A reviewer that thinks the brief itself is wrong (wrong for the
    goal, out of scope, or missing something the goal needs) files a finding with
    target: brief. It never sends the worker back and never blocks the merge; it
    becomes a brief task note that wakes the orchestrator (t1's reviewer says the brief is wrong: …). A run without an orchestrator, such as a plan file, shows it to
    you as a sticky attention line in anthrex run status (t1: the reviewer says the brief is wrong (1 notes); read them in the task's notes). The inspector, the report
    ((brief, from the reviewer)) and history (brief_findings) show them apart from
    the code findings.

  • Decided for you · Out of scope. The orchestrator's plan submit, and each
    sub-planner's submit_epic, now carry decided (each question the goal left open,
    with the answer chosen) and out_of_scope (what the run will not do); a submit
    without them is refused, with the reason. At the plan gate the review opens on
    the frame (frame 2 decided for you · 1 out of scope · f shows them, or frame none stated in the attention colour), and f flips the detail between the frame
    and the selected task. anthrex run status prints decided for you: <question> → <answer> and out of scope: <item> after the goal while the plan awaits you, and
    the run report has a Plan frame section. Plan files, your own run edit --submit
    and design-flow runs need no frame.

  • replaces. An orchestrator's add_task can name the cancelled or blocked tasks
    it takes over (replaces: ["t1"]); a blocked one is cancelled (cancelled: replaced by t2), and split_task records it for its children. The inspector shows replaces
    and replaced by, the report cancelled (replaced by t2), and the history record
    names what it replaces. anthrex run stats and the TUI's stats page judge the work
    by the replacement: replaced records leave the class rows (replaced 1 (judged by their replacements)).

  • Shared sequences. The orchestrator's and sub-planners' contracts now say that a
    task taking the next number of a shared sequence (a migration number, a version
    constant, a registry entry) owns the file that holds it, so two such tasks never run
    at once.

  • A dispatch hold (milestone 9.16). C-b H (with a confirm) or anthrex hold on
    stops every new agent session daemon-wide; sessions already running finish their
    work, are reviewed and merge. The status bar shows HELD, an alert and every
    run's attention line say so, and new goals are refused with dispatch is held daemon-wide · anthrex hold off; queued goals wait. The hold survives a daemon
    restart (brakes.json, written atomically; a corrupt file holds). C-b H again or
    anthrex hold off releases it and says how many queued goals start; anthrex hold status shows the hold and the quota.

  • A subscription quota brake. anthrex reads each CLI's own rate-limit readings,
    Claude's rate_limit_event and the token_count lines of Codex's session rollout
    under $CODEX_HOME/sessions, with no credentials and no vendor request. While a
    runtime's 5-hour window is at 90 % or its 7-day window at 95 %, no new session of
    that runtime starts until the window resets; in-flight work still finishes. A
    runtime with no recent reading is never braked, and the run log says so once.
    [orchestrator.brakes] (quota_brake, quota_pause_5h_percent,
    quota_pause_7d_percent, quota_fresh_secs) sets it, also from the Settings
    screen; anthrex run status prints the brake lines while something is held.

  • Cross-runtime failover. A fresh session whose runtime is braked starts on its
    role row's "if it struggles" fallback when that is on the other runtime: claude braked: t2 started on codex (fallback). A reviewer never gets its author's model,
    overlapping work never splits runtimes, and the hold stops failover too. A row whose
    fallback is on the same runtime waits instead.

  • The orchestrator's context handoff. When a goal is continued on a chain whose
    orchestrator session is 80 % of its context window or 300,000 tokens full
    ([orchestrator] handoff_at_percent, handoff_at_tokens, context_window_tokens),
    a fresh orchestrator session starts with the summary and recent history, the old
    window is renamed <h4>/orchestrator (handed off), and the run's inspector shows
    where it came from. A live orchestrator at 90 % gets an attention line.

  • Lessons (milestone 9.15). anthrex now learns from its own runs in a repository.
    Each failed check or proof records a failure signature on the task's history record,
    and a signature seen in two runs within 14 days becomes a known failure. After a
    recovered, blocked or blocking-review task, or a failed or discarded run, a
    background distiller (one decider call, off the run, at most 20 a day per
    repository, on a redacted dossier) proposes lessons: episodic ones go on trial at
    once, procedural and semantic ones wait for your approval. A run freezes the active
    lessons at its start, and each worker's first turn gets the best few for its files
    under Notes from earlier runs in this repository. …, its reviewer the same under
    Known pitfalls in this repository; a lesson earns credit when the tasks shown it
    merge. A reviewer can also get a short risk note written from the brief alone. The
    new [lessons] table turns each part on or off and sizes it.

  • anthrex lessons list | approve | reject | forget. List the repository's lessons
    with their status, layer and green/outcomes (--all, --json), approve or reject
    proposed ones, and forget a lesson or dismiss a known failure (y/N per id unless
    --yes).

  • The Lessons page and the knowledge graph page. On the Profile screen (C-b P),
    l lists the lessons (a approve, r reject, d forget, t all) and its hint
    counts those waiting for review; g there draws them as a graph of module hubs and
    lesson dots, with selection by arrows, an inspect panel, search, zoom and pan.

  • A discard reason. anthrex run discard <run> --reason "<text>", and a reason
    field in the TUI's discard form, record why a run was thrown away on its history
    record and in its distill dossier.

  • Files that run outside the sandbox are protected. CI, git-hook, cargo and
    toolchain files join the protected paths: .github/workflows/**,
    .github/actions/**, .gitlab-ci.yml, .circleci/**, .buildkite/**,
    Jenkinsfile, azure-pipelines.yml, .githooks/**, .husky/**,
    .pre-commit-config.yaml, **/.cargo/** (the directory itself too, so a .cargo
    committed as a symbolic link is caught), **/rust-toolchain and
    **/rust-toolchain.toml (21 built-in paths in all). A task
    whose branch changes one without its owns naming it exactly is bounced at
    task_done with a line that says why (… runs outside the run's sandbox (CI, git hooks, cargo or toolchain config); this task may change it only if its owns names it exactly). A task whose owns names a protected file is noted at the plan gate
    (owns names protected <path>; the user approves this grant with the plan).

  • The gate's own scripts are pinned. At run start anthrex reads which tracked
    files the profile's commands name (check, setup, single_test, the tier
    commands; make, just, tox and nox add their own files) and protects them.
    Before every gate command it compares them in the checkout with the base commit; if
    the run changed one, the command never runs and the run halts for you (the gate's script <path> differs from the base commit's; the run changed what measures it).
    Only you can resume it. A task may change a gate script when its owns names it
    exactly and you approve that with the plan.

  • An orchestrator retry cap. After the orchestrator has retried one task twice,
    that task's next block is yours (· the orchestrator retried it 2 times; the user decides); your own run retry gives it its two retries back.

  • Untrusted text is tracked. Once the orchestrator has read text from outside the
    run (a pull-request comment, or a review or CI fix task's block, note or result),
    its override and accept_red become an orchestrator asks question to you (do it / leave it), and its approve_hold is refused, for the rest of the run and any
    next goal it continues. anthrex run status prints untrusted text read: <source> at <HH:MM>; override, accept_red and approve_hold go to the user, and the run view's
    inspector shows an untrusted row. A fix task's wake-up no longer carries its
    worker's text (read it with run_status).

Changed

  • The orchestrator cannot merge or grant protected changes on its own. Its
    override of a task whose branch changes a protected file the task's owns does
    not name is refused and the task's block becomes yours; it cannot approve a hold
    whose tasks name a protected file, nor add such a task outside a hold after the plan
    gate. Your own run override still goes through and lists the protected paths it
    changes; for a pinned gate script the reply adds that it stays pinned until a task's owns names it (run edit), so the next gate command halts until you add a task whose
    owns names it.
  • brief findings leave the code-review counts (milestone 9.17). A history
    record's reviews_rejected no longer counts a round whose only findings are about
    the brief, the orchestrator's digest shows them apart in a task's review text (r1 changes (1 brief)), and an integration review whose findings are all about the
    brief approves its epic.
  • Tokens are billed tokens everywhere, and a run's total counts its design agents
    (milestone 9.19). A brainstormer's and a document reviewer's tokens no longer count
    cache reads (input, cache writes and output, as every other role's), and the run's
    usage now credits them under brainstormer and doc_reviewer, so its total covers
    every role. history.jsonl lines are now written at v 6: from v 6 a phase
    line's agent tokens are billed tokens and a run line's usage includes the design
    roles; the design budget refit takes its token samples from v 6 lines only. A run
    designed before the upgrade keeps no split of its design agents' tokens, so its total
    leaves them out (an undercount, never a cache-read overcount). The run spend row
    reads tokens 1.8M (all roles) · cache hits 71% of input · worker tool calls 412
    (tokens ≥… (tasks only) from a daemon without run usage), REPORT.md and the
    inspector print tokens as 750k and 1.2M, and run stats leaves a merged task with
    no recorded tokens out of its token median (- when none are left).
  • Every number has one meaning, label and format (milestone 9.19), written down in
    docs/numbers.md, which ? help (a numbers group) and the README link to. The
    protocol stays 26; run.json is format 7 and history.jsonl lines are v 6 (both
    from the token change above).
  • Clock times name their zone. The TUI and the CLI show local time with its offset
    (14:30 +02:00, Thu 14:30 +02:00 within six days, else the date); text the daemon
    writes (attention lines, prompts, the proposal file, the REFIT column) stays UTC and
    says UTC. On Linux, a change of the system time zone mid-session is picked up only
    after a restart (DST changes are picked up at once). After the upgrade the
    orchestrator digest's at values read 2026-09-21 11:40 UTC, not 11:40
    (cosmetic: the times are the same).
  • One duration and one age format: 42s, 41m 12s, 1h 05m, 3d 04h, floored;
    just now under 10 s, else <duration> ago. Fixed-width cells (the sidebar, graph
    boxes, the alerts list) show the largest unit only.
  • One progress count and one stage position. 3/5 merged leaves out cancelled,
    reported and replaced tasks everywhere, a run still being designed shows its design
    word instead of 0/0 merged, and every position reads stage 2 of 3.
  • Unknown is not zero. A missing value reads unknown (- in a table cell): a
    sub-agent with no end time, a check that never ran (✗ never ran), a doc gate still
    loading, an age before the first snapshot.
  • Context fill never reads 450%: context 91% full (183k / 200k), context over 100% (450k / 200k window), or context 183k (window unknown).
  • Ages freeze when the daemon link is lost. Timers and ages stop counting, and the
    badge reads DISCONNECTED · as of <ago>; the model picker's age is the catalog's own
    fetch age.
  • anthrex hold status tells the truth: (read 3m 10s ago), (stale: read 1h 35m ago) for a stale reading, the brake text the TUI shows for a braked runtime, and the
    hold's age (on since Thu 14:30 +02:00 (2h 05m ago)).
  • anthrex tree labels its numbers: #1 id 7 (the position C-b <n> uses and the
    id ls, kill and attach take), claude 2 · codex 1 · shell 1, and running 3m 10s, ran 12s or done - for a sub-agent.
  • anthrex run stats labels its aggregates: MED LINES, MED CALLS, MED TOKENS,
    MED WORK (a floored duration, was rounded minutes) and BOUNCES (ALL), a footer
    saying what the medians are over, and rounds: 3 ended · 1 run iterated. The TUI's
    stats page uses the same words and shows the rounds line.

Fixed

  • A host sleep no longer stalls an open turn or delivers into it. Across a laptop
    sleep the wall clock jumped, so the stall watchdog interrupted an open worker turn
    and the outbox delivered a message mid-turn (against decision 42), and the minutes
    budget charged the sleep. The daemon now measures each sleep (wall time against the
    awake clock) and excuses it from an agent session's stall clock, its waits (rate
    limit, delivery and count retries, the interrupt's grace, a failed turn's continue)
    and its minutes budget, and from a design phase's budget, a design agent's session
    seconds and a stopped racer's exit wait; budgets count awake time. Orchestrator
    notices and the GitHub-facing delivery polls still run on wall time. Records of what
    happened stay wall times.
  • A wall clock set back now moves every session clock back with it. A clock set
    ahead by mistake and then corrected looked like a sleep and then like nothing, so
    every open turn's stall clock and every running wait stayed out by the mistake:
    a turn set a year ahead and back never stalled. The daemon now also detects a wall
    clock that falls behind the awake clock and gives each stall clock, wait, budget,
    orchestrator-stall wait and writer-cap recovery the awake time it had left.

Backlog hardening (milestone 9.18), no new features. The protocol (26) and the run
format (6) are unchanged.

  • More secrets are redacted from provider prompts and the Lessons page: Stripe
    sk_live_ and sk_test_ keys, AWS secret access keys (after their key name, or on
    the line of an AKIA or ASIA key id), Basic credentials, and URL passwords
    spelled %3A%2F%2F…%40 or :\/\/…@.
  • timeout 600 cargo test waits for its build slot like a bare cargo test, and so
    do stdbuf and cargo llvm-cov, cargo miri, cargo hack and cargo insta test.
  • A cached green is not reused after a CARGO_PROFILE_* change. CARGO_PROFILE_*,
    CARGO_TARGET_<triple>_RUSTFLAGS, CARGO_BUILD_RUSTFLAGS and CARGO_INCREMENTAL are
    now part of the tier cache key. If you set any of them, your next tier run misses the
    cache once.
  • A task's own [task.budget] raises its size ceiling. The budget ladder's next-size
    check now uses, per axis, the larger of the task's budget and its class's, so a task
    given more room is not stopped at its class's limit. Token totals no longer overflow.
  • A wheel scroll no longer holds the orchestrator's wake-up. Mouse reports sent
    while a wake-up is pasted no longer count as typing, so the wake-up is submitted.
  • Dialogs wrap in display columns, so a path with CJK characters or emoji no longer
    breaks the force-remove prompt's box.
  • A failed tool call shows as failed at once in the conversation view, from Claude's
    PostToolUseFailure hook, instead of staying pending until the transcript is read.
  • Lessons requests never hang. anthrex lessons (list, graph, approve,
    reject, forget) refuses a store or history that is not a regular file, such as a
    FIFO, instead of blocking on it, and gives up after 30 s on a file system that stops
    answering. A stuck approve, reject or forget no longer holds the store's lock,
    so later changes and the lesson distiller still write. A FIFO at history.jsonl no
    longer holds a run start's tuning or run stats either: it is refused unread.
  • lessons.jsonl is compacted. Once it reaches 1 MiB, the lines no reader needs
    (a closed lesson's day-old attempts, and records a later line replaces) are dropped.
    Only the newest three moved-aside tuning.toml.bad-* files are kept.

Install: see docs/install.md.
The binaries are unsigned; on macOS, clear the quarantine flag as described there.