Repository navigation
Read agent sessions from cmux, with a registry fallback for sessions cmux missed - #51
Merged
Merged
Conversation
cmux 0.64.25 records every agent session itself, and `cmux sessions list --json --all` prints those records without its socket. bin/cmux_sessions.py is the one place that runs it: it returns typed records, finds the CLI via CMUX_BIN, an executable CMUX_BUNDLED_CLI_PATH, PATH, then the app bundle, and returns [] with one stderr line when cmux can't answer. world-scanner, session-context-watcher, build-ws-context and transcript-tail now read it instead of ~/.claude/cmux-registry.json and ~/.cmux-session-ledger.jsonl. Only the session cmux marks active on a surface counts as running there, and first_recorded_at comes from cmux's started_at. Output fields keep their names and values. Remove the ledger hook and cmux-restore-sessions (use cmux restore-session or cmux restore --surface). install.sh drops their old links, and patch-settings.py now removes the ledger and cmux-registry.py registrations instead of adding them. Keep hooks/cmux-auto-resume.py: agents started without cmux's Claude wrapper (absolute ~/.local/bin/claude, the fleet's scheduled spawns) are only recorded by cmux because it forwards their SessionStart. The coverage gate now measures hooks/ and install/ Python. Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
Two reviews blocked the first revision: cmux is not a complete source. Live session ee4ee641 (workspace:27, started outside cmux's wrapper) has no cmux record and no resume binding, because cmux-auto-resume.py forwarded its SessionStart once, fire-and-forget, and the forward failed. - bin/cmux_sessions.py: registry_fallback() returns ~/.claude/cmux-registry.json rows (mukul-memory's hook) only for sessions cmux has no record of; agent_process() rejects a reused pid; the CLI timeout is 15 s. - All readers use cmux first, then the fallback. world-scanner writes _meta.session_record_fallback and logs fallback_hits=N so the fallback can be retired after a soak with zero hits. On live state it verifies the same 10 sessions as base, ee4ee641 included; only the aea1111b pid-reuse ghost drops. - hooks/cmux-auto-resume.py starts a detached worker that checks the exit code, confirms the record with `cmux sessions list --session`, retries with backoff, and ledgers a final failure as cmux-session-forward-fail. - cmux-restore-sessions stays, reading cmux records then the registry, since native restore needs a resume binding. - hooks/cmux-session-ledger.py is a no-op stub for one release; its link stays, so a registration that outlives the pull still exits 0. - patch-settings.py registers cmux-auto-resume.py when missing, removes only the ledger registrations, leaves cmux-registry.py alone, and writes UTF-8. - Tests kill the two surviving len(...) != 1 mutants. Co-Authored-By: Claude Opus 5.5 (1M context) <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.
Summary
Agent sessions are now read from cmux's own records:
cmux sessions list --json --all, via the newbin/cmux_sessions.py. Sessions cmux missed fall back to mukul-memory's~/.claude/cmux-registry.json. The ledger hook is retired, the forward to cmux is now reliable, and fresh machines get the hook registered. Nothing is deployed.This revision fixes the two blocking reviews. cmux alone wasn't a complete source: live session ee4ee641 had no cmux record and no resume binding, so the first revision dropped it.
Merging deploys this
The pulse self-update pulls
mainand runsinstall.sh --applywithin about an hour.On live state: same verified sessions as base
Both scanners ran on this machine's live state, with output sent to a scratch dir.
personal/mainsession_start_registryfrom the registry fallback)session_idsfirst_recorded_atstarted_at: 4 sessions differ by under a second, and 3e46079d shows its original 10-06 start because it moved workspaces on 10-10_meta.session_record_fallback{"hits": 1, "session_ids": ["ee4ee641-…"]}The watcher on each scanner's
world.jsonfinds the same 10 sessions, ee4ee641 included. Thecmux-restore-sessions --dry-runplan is identical to base: same panels, same commands. That includes ee4ee641's panel, which has no resume binding.What changed
Adapter.
bin/cmux_sessions.py:list_sessions()waits up to 15 seconds, was 5; the reviewers measured 1.5–4.8 seconds under load. On failure it returns[]and writes one stderr line.registry_fallback(path, records)returns registry rows only for sessions cmux has no record of.agent_process(pid)rejects a registry pid that is no longerclaudeordroid.Readers. All five use cmux first, then the registry fallback:
world-scanner.pytries cmux's active record for each surface first, then a registry row. Two active cmux records for one surface verify neither. It writes_meta.session_record_fallbackand logsfallback_hits=N.session-context-watcher.pybuild-ws-context.py, where two cmux records for one surface are ambiguous and the newest registry row wins.transcript-tail.pycmux-restore-sessions.py: kept, and migrated from the ledger, because nativecmux restore --surfaceneeds a binding.Forward.
hooks/cmux-auto-resume.pystarts a detached worker and returns at once. The worker:cmux hooks <provider> session-startexit code;cmux sessions list --session <id>;cmux-session-forward-failentry to~/.assistant/actions-ledger.jsonl, which the brief and Slack feed surface.It never raises out of the hook.
Ledger hook.
hooks/cmux-session-ledger.pyis a no-op stub for one release, so the old registration still exits 0 betweengit pulland--apply. Its link stays.Installer.
install/patch-settings.py:python3 $HOME/.claude/hooks/cmux-auto-resume.py(timeout 10) on SessionStart, in both Claude settings and Factory hooks, if it's missing;cmux-registry.py;ensure_ascii=False;install.shis base apart from its help text, comments, and messages.Coverage gate. It now measures
hooks/andinstall/Python.Known, not changed
cmux-restore-sessions(base and branch alike) treats live sessions started outside cmux's wrapper as dead. Their argv doesn't carry the session id, sopgrepmisses them: 5 panels here, including ee4ee641 and the warm comms session. Its--dry-runis safe; a real run would typeclaude --resumeinto those live panes. This predates the PR.Tests
47f922a: 3097 passed, 2 skipped.bin/,hooks/, andinstall/are 100% covered, and all 5install.shhunks are mutation-proven.tests/mutation_smoke.py: 39 of 39 rejected (19 new), locally and in CI.len(…) != 1): now killed by tests with a claude and a factory record on one surface.Deploy (after merge; not run)
~/.claude/binis a symlink to~/dev/assistant/bin, so the pull updates the readers immediately.--applyregisters the hook and drops the ledger registrations.To retire the fallback, watch
_meta.session_record_fallback.hitsin~/.claude/cache/world.jsonand thefallback_hits=count in~/.assistant/logs/world-scanner.out. Once both stay at zero for a soak period, removeregistry_fallbackand its callers. Delete the ledger stub and its install.sh link in the next release.Rollback
Revert the merge commit, then run
install.sh --apply. That restores:cmux-restore-sessionson the ledger;patch-settings.pyre-registers it on SessionStart and SessionEnd. The ledger file resumes where it stopped.Two things a revert doesn't undo:
🤖 Generated with Claude Code