agent-resume

agent
Guvenlik Denetimi
Basarisiz
Health Uyari
  • License — License: MIT
  • Description — Repository has a description
  • Active repo — Last push 0 days ago
  • Low visibility — Only 6 GitHub stars
Code Basarisiz
  • rm -rf — Recursive force deletion command in test/test.sh
Permissions Gecti
  • Permissions — No dangerous permissions requested

Bu listing icin henuz AI raporu yok.

SUMMARY

Several Claude Code / Codex conversations in one repo? Each terminal pane resumes its own session after a reboot, not a picker. Agent CLIs scope sessions to the directory; agent-resume adds per-pane binding on top of tmux-resurrect.

README.md

agent-resume

ci
npm
license

Four panes open in one repo, a different Claude Code conversation in each.
Reboot the machine. Every pane comes back to its own directory with its own
conversation resumed, no picker.

The problem: sessions are scoped to the directory, not the pane

Agent CLIs key their history off the working directory. claude --continue is
documented as "continue the most recent conversation in the current directory",
and claude --resume opens a picker over that directory's sessions. That is the
wrong granularity the moment you run more than one pane per repo:

  • Four panes in ~/work/api: one on tests, one on a migration, two debugging.
    All four resolve to the same session list, so --continue in any of them
    returns whichever conversation was touched last, not that pane's.
  • Reboot and every pane loses its working directory. Nothing recorded which pane
    held which conversation, so restoring means cd-ing back and identifying
    sessions in a picker by timestamp and first message. On this repo's directory
    that picker has 89 entries.
  • Pick wrong and you have appended to a conversation that belongs to another
    pane, with its own accumulated context and plan.

Directory affinity is what the agent CLIs already do. Pane affinity is the part
that is missing, and it is exactly what a reboot destroys.

What it does

agent-resume gives each pane a session of its own and makes that binding
survive a reboot. It stands on tmux rather than reinventing it:

tmux              keeps live sessions alive across detach/reattach   (the 95% case, free)
tmux-resurrect    restores window layout + each pane's directory     (free)
tmux-continuum    auto-saves, auto-restores when tmux starts         (free)
agent shim        makes each restored pane resume ITS EXACT session  (the only custom part)

The binding is not a separate registry that can drift. resurrect already saves
every pane's full launch command against that pane's coordinates, so the shim
only has to make sure the session id is inside that command:

  1. Fresh interactive run. The shim launches claude --session-id <new-uuid>,
    so the id resurrect saves for that pane is the id of that pane's conversation.
    Four panes bake four different uuids.
  2. Pre-restore. A hook rewrites each saved --session-id <uuid> to
    --resume <uuid>, but only for sessions whose file still exists.
  3. Post-restore. A hook reads resurrect's save file and types the rewritten
    command into the matching restored pane (session:window.pane). Each pane
    gets its own conversation back, in its own directory.

The rewrite in step 2 is not optional. Replaying the saved command verbatim
fails, which is the whole reason a plain resurrect setup cannot do this:

claude --session-id <existing-uuid>   ->  Error: Session ID is already in use
claude --resume     <existing-uuid>   ->  resumes correctly

Step 3 is not optional either. resurrect will not relaunch Claude on its own,
because Claude renames its process to its version number (e.g. 2.1.210) and
resurrect's program matching is by name, so it never fires. resurrect leaves the
pane at a shell in the right directory; agent-resume types the resume command in.

The shim is a strict pass-through on any doubt. Non-interactive runs
(-p/--print), pipes, and explicit --resume/--continue go straight to the
real binary untouched. It never changes what the CLI does in those cases.

Manual resume, any agent

Inside a session you do not need tmux restore to get an exact resume. Bare
agent-resume resumes this pane's own session — every recorded launch
stores the pane's terminal identity (TMUX_PANE, ITERM_SESSION_ID, …, else
the controlling tty), and resume prefers the newest entry recorded from the
pane you are standing in. Only when this pane has no recorded session does it
fall back to the newest session for the current directory:

agent-resume            # this pane's session, else newest here (any agent)
agent-resume claude     # same, restricted to claude
agent-resume codex      # same, restricted to codex
agent-resume rovodev    # same, restricted to Rovo Dev (`acli rovodev run`)

So four panes in one repo each get their own conversation back, not whichever
was touched last.

For Claude, sessions are recorded twice over: the PATH shim bakes and records
an id at launch, and a SessionStart hook inside Claude Code records the
session even when something bypasses the shim (cmux's claude wrapper, a shell
alias, an absolute path). Resuming a session in a pane re-binds that pane to
it. For Codex, which insists on choosing its own id, agent-resume reads
Codex's local session metadata and picks the newest interactive session whose
recorded cwd matches, excluding exec runs and sub-agent rollouts. If the
recorded session file is gone it falls back to the agent's native resume-last;
it will not silently jump to a different directory's session.

For Rovo Dev the id is also the agent's to choose, so the shim resolves the
binding the other way round: it runs acli rovodev run in the foreground,
snapshots ~/.rovodev/sessions either side of the run, and binds whichever
session that run actually opened or touched to this pane. Same per-pane
affinity as claude, decided on exit instead of at launch, and it covers a
--restore run too — the pane that resumes a session owns it. Rovo Dev records
each session's workspace in its metadata.json, so a --worktree run is filed
under the worktree it really ran in, and with no ledger at all agent-resume
can still find this directory's session from the store alone.

Pane identity survives while the pane lives (and inside tmux, across detach).
Across a reboot pane env vars are reassigned, which is exactly what the tmux
restore layer is for: resurrect replays each pane's exact launch command.

Install

Requirements: tmux and git (used once to fetch the tmux plugins). tpm is
not required.
install fetches tmux-resurrect and tmux-continuum into
~/.config/agent-resume/tmux-plugins and loads them directly; if you already run
tpm, the two run-shell lines coexist with it.

# via npm
npx agent-resume install

# or from a checkout
sh install.sh

# or curl-pipe
curl -fsSL https://raw.githubusercontent.com/rahulbansal16/agent-resume/main/install.sh | sh

Then:

exec $SHELL -l          # pick up the PATH change (shims)
tmux kill-server        # restart tmux so it loads the restore plugins
agent-resume doctor     # verify every link is green

Flags: --agents claude,codex,rovodev (default), --no-tmux, --no-shell,
--no-hook, --dry-run. Only agents actually on your PATH get a shim.

Rovo Dev is not a binary of its own — it is acli rovodev run, one subcommand
of the Atlassian CLI — so its shim installs on PATH as acli. That shim checks
the first two arguments and nothing else: acli jira, acli confluence,
acli admin, acli rovodev auth and every other subcommand exec straight
into the real binary before a single flag is inspected.

install also wires one hooks.SessionStart entry into
~/.claude/settings.json (via node, refusing to touch a file it cannot
parse) pointing at ~/.config/agent-resume/record-session.sh. This is what
makes recording reliable when claude is launched through something other than
the PATH shim. --no-hook skips it; uninstall removes it.

What it writes to your machine

If you have spent years tuning your tmux config, this is the section you want.
agent-resume keeps its own settings in its own file and adds exactly one line
to yours.
Nothing of yours is edited, reordered, or reformatted.

Run agent-resume install --dry-run to print the exact lines, in the exact
files, and exit without writing anything:

Files created under its own directory (nothing of yours in here):
  ~/.config/agent-resume/{shim.sh,tmux.conf,pre-restore-hook.sh,post-restore-hook.sh,record-session.sh}
  ~/.config/agent-resume/{shims,adapters,tmux-plugins}/

Edits to files you own:
  ~/.zshrc (appending; 84 existing lines untouched)
    + # >>> agent-resume >>>
    + export PATH="~/.config/agent-resume/shims:$PATH"
    + # <<< agent-resume <<<
  ~/.tmux.conf (appending; 212 existing lines untouched)
    + # >>> agent-resume >>>
    + # All of agent-resume's tmux settings live in the sourced file, so this
    + # block is the only thing it adds to your config. Delete the block (or run
    + # `agent-resume uninstall`) to detach it completely.
    + if-shell '[ -f "~/.config/agent-resume/tmux.conf" ]' 'source-file "~/.config/agent-resume/tmux.conf"'
    + # <<< agent-resume <<<
  ~/.claude/settings.json (adds one hooks.SessionStart entry -> ~/.config/agent-resume/record-session.sh)

That is the whole footprint. Specifically:

  • One source-file line in ~/.tmux.conf, wrapped in removable markers. All
    the actual settings (resurrect options, the two restore hooks, continuum
    interval, the plugin run-shell lines) live in ~/.config/agent-resume/tmux.conf,
    which you can read in full before installing: lib/tmux.conf.
  • No key bindings, no prefix change, no tmux option you would have an opinion
    about.
    Everything set is namespaced under @resurrect-* and @continuum-*.
  • Both files are backed up the first time agent-resume touches them, to
    <file>.bak.agent-resume. It never overwrites an existing backup, so the copy
    stays the pre-install original.
  • The if-shell guard means deleting our directory cannot break your tmux.
    rm -rf ~/.config/agent-resume leaves the source line pointing at nothing, and
    tmux still starts clean with no error (verified on tmux 3.6a).
  • agent-resume uninstall returns ~/.tmux.conf to byte-identical, which is
    asserted in the test suite rather than merely claimed.
  • --no-tmux skips the tmux side entirely. You then get manual
    agent-resume resume and no restore layer, and you can wire the two hooks into
    your own config however you prefer.

If you installed a version before 0.3.0, that release inlined its settings in
~/.tmux.conf. Re-running agent-resume install replaces the old block with the
one-liner; it does not leave both behind.

Verify it works

Use two panes, so you are testing the thing that actually breaks:

# pane 1
cd ~/some/project && claude     # say something identifiable
# pane 2 (same directory)
cd ~/some/project && claude     # say something different

tmux kill-server                # simulate a reboot
tmux                            # continuum auto-restores
# -> both panes return to ~/some/project, each resuming its own conversation

Commands

Command Does
agent-resume resume the newest session recorded for this directory
agent-resume <agent> same, restricted to one agent (claude, codex, rovodev, …)
agent-resume install install shims, the PATH entry, and the tmux source line
agent-resume install --dry-run print the exact lines it would add, and where, without writing
agent-resume uninstall remove shims and the managed blocks, restoring your configs
agent-resume doctor check tmux, plugins, shims, PATH, and both hooks
agent-resume status list the newest claude session per project directory

How much survives what

Event Directory Live agent process Conversation Per-pane binding
Detach / reattach, same machine ✅ tmux ✅ still running ✅ never stopped
Reboot / tmux kill-server ✅ resurrect relaunched --resumed into the same session ✅ per-pane
Plain terminal, no tmux ✅ via agent-resume ❌ directory-exact only

The reboot row is exact for agents that take a launch-time id (claude), because
the id is inside the command resurrect saved. codex and rovodev choose their
own ids, so nothing identifies their session inside the saved command: those
panes come back to the right directory at a shell, and agent-resume in the
pane resumes the exact conversation. It is deliberately not typed in for you —
two panes in one directory would otherwise race for the same session.

Add another agent (hermes, …)

Drop one file in ~/.config/agent-resume/adapters/<agent>.conf and re-run
agent-resume install --agents <agent>. No code changes: the shim identifies
itself from its own filename and reads the matching adapter.

AGENT_BIN="hermes"
AGENT_SUPPORTS_NEWID=1          # 1 if it can set the session id at launch
AGENT_NEWID_FLAG="--session-id"
AGENT_RESUME_FLAG="--resume"
AGENT_RESUME_LAST="--continue"  # fallback when nothing is recorded here
AGENT_CONTINUE_FLAGS="-c --continue -r --resume"   # already-resuming -> pass through
AGENT_PRINT_FLAGS="-p --print"                     # non-interactive -> pass through
AGENT_SESSION_DIR="$HOME/.hermes/sessions"
AGENT_SESSION_EXT="jsonl"
AGENT_ID_REGEX="[0-9a-f-]{36}"

AGENT_SUPPORTS_NEWID is the line that decides how much you get. An agent that
accepts a launch-time id gets full per-pane restore, because the id can be baked
into the command resurrect saves. An agent that does not still gets directory
restore from tmux plus exact manual resume via agent-resume — and if you tell
the adapter how to read its session store, per-pane binding as well.

Optional keys, for CLIs that do not fit the claude shape:

Key Does
AGENT_SUBCOMMAND the agent is a subcommand of a shared binary (rovodev is acli rovodev run); the shim owns only that subcommand and passes the rest of the binary through
AGENT_BIND_ON_EXIT cannot take an id at launch: run it in the foreground and bind the session it opened to this pane on exit
AGENT_DISCOVER_CWD find the session for a directory from the agent's own metadata, with no ledger entry
AGENT_SESSION_META_FILE sessions are a directory each, holding this metadata file; the directory name is the id
AGENT_SESSION_CWD_KEY JSON key holding the session's directory (cwd by default, workspace for rovodev)
AGENT_SESSION_META_FILTER substring the metadata must contain to count (codex uses it to skip exec runs)
AGENT_POSITIONAL_IS_PRINT a bare positional argument means a one-shot run, so it must not claim the pane
AGENT_VALUE_FLAGS flags whose value is a separate word, so it is not mistaken for that positional

Uninstall

agent-resume uninstall
rm -rf ~/.config/agent-resume     # also removes adapters and hooks

uninstall strips the marked block from ~/.tmux.conf and your shell rc,
returning both to exactly what they were, and deletes our tmux config and shims.
Your <file>.bak.agent-resume backups are left in place so you can diff. If you
prefer to do it by hand, delete the block between # >>> agent-resume >>> and
# <<< agent-resume <<< in each file.

License

MIT. Tests: sh test/test.sh (no tmux and no real agent needed).

Yorumlar (0)

Sonuc bulunamadi