Skip to content

feat: Herdr restores panes through ak, ak last, release v1.2.0 - #41

Open
xergioalex wants to merge 2 commits into
mainfrom
feat/herdr-resume-through-ak
Open

xergioalex wants to merge 2 commits into
mainfrom
feat/herdr-resume-through-ak

Conversation

@xergioalex

@xergioalex xergioalex commented Oct 27, 2026 •

Copy link
Copy Markdown
Member

Problem

After a reboot or a Herdr restart, Herdr reopens each agent pane from the session id the CLI's Herdr integration reported, and by default runs the bare CLI: claude --resume <id>, grok --resume <id>. Without ak the CLI has no profile home, no key from the env file and no autonomy flag, so:

  • a profile session (ak claude @work1) is looked up in ~/.claude and not found, or opens in the wrong account;
  • an API-key CLI (ak grok with XAI_API_KEY in the env file) shows its login menu.

Outside Herdr there was no short way back to "the last agent I ran here" without remembering its kind and profile.

What changes

Herdr resumes through ak (lib/restore.py)

Herdr's pane.report_agent_session accepts a resume_argv, which is the command Herdr runs on restore. An interactive ak <kind> [@profile] inside a Herdr pane (HERDR_ENV=1, HERDR_PANE_ID) now starts a small detached watcher next to the CLI. Each time Herdr records a new session id for that CLI, the watcher reports it again with:

ak <kind> @<profile> [--ask] --resume <id>

The report keeps Herdr's own source and agent and uses a later seq.

  • Re-reports on every id change. A test against Herdr 0.9.5 showed that a later report without resume_argv, even with a different id, keeps the earlier resume_argv. After a /clear, Herdr would otherwise resume the previous conversation.
  • Explicit profile, @default included. A default profile set later cannot move the session to another account. --ask is kept for opted-out launches, and provider variants keep their kind.
  • Cross-platform, stdlib only. It talks to Herdr through the herdr CLI, not a raw socket. Liveness uses os.kill(pid, 0) on POSIX and OpenProcess/WaitForSingleObject on Windows, where os.kill would terminate the process. The watcher detaches with a double fork on POSIX and with DETACHED_PROCESS on Windows.
  • Safe. The watcher's environment is only PATH, the home and temp variables and HERDR_*, so no key, token or profile home reaches it. It writes nothing, prints nothing and exits with the CLI.
  • Covered CLIs: every CLI Herdr reports sessions for (claude, codex, cursor, opencode, pi, grok and their variants). It needs the session report, so a profile needs ak profiles hooks <cli> @name.
  • Opt-out: AGENTKIT_HERDR_RESUME=0.

ak last (lib/last.py)

Every interactive launch records its kind, profile and posture per working directory, in launches.json in the state dir (mode 0600, the 200 most recent directories, no key or session id).

  • ak last relaunches it with -c.
  • ak last -r opens the CLI's picker in that account.
  • ak last ls lists the record.

ak run is not recorded.

Interface

Interface stays 1: ak doctor --json, ak env and ak run are unchanged. New: the ak last subcommand and the AGENTKIT_HERDR_RESUME variable.

Tests

  • tests/py/restore_checks.py (python only, added to the native Windows CI step) covers:
    • the resume command and Herdr's argv rules;
    • when the watcher starts;
    • its secret-free environment;
    • the report arguments;
    • the watch loop against a scripted Herdr: one report per id, re-report on a new id, retry after a refused report, other agents ignored, giving up when Herdr is unreachable;
    • liveness on the host OS;
    • the launch record: per-directory entries, pruning, mode 0600, a corrupt file, a write failure that never stops a launch.
  • New restore scope: the real launcher with a fake herdr. It checks the reported command for claude @work and for grok with @default and --ask, that no key reaches the watcher, that Herdr is never called outside a pane or with the opt-out, and the ak last, ak last -r and ak last ls flows.
  • security scope: the trust-cwd write check now excludes launches.json and checks separately that the file is 0600 and holds no key.
  • Full suite: bash tests/run.sh gives passed: 2452 failed: 0 skipped: 1. bash scripts/check-public-hygiene.sh is clean.

Verified by hand on macOS with Herdr 0.9.5

  • ak claude @work1 and ak grok (API key, @default) in real panes. Herdr's session.json stored agent_resume.argv = ["ak","claude","@work1","--resume",<id>] and ["ak","grok","@default","--resume",<id>].
  • Running the stored commands, which is what Herdr runs on restore, brought grok back logged in with its API key on the same session, and Claude back on its @work1 session. Each watcher exited with its CLI.
  • The Herdr server itself was not restarted, because that would have restarted every pane on the machine.

Release

This PR also carries the v1.2.0 release commit (version sources, dated CHANGELOG section, SECURITY.md), following the v1.1.0 convention. After merge, the annotated tag v1.2.0 on the merge commit triggers release.yml (tarball, SHA256SUMS, notes).

🤖 Generated with Claude Code

…minal

Herdr restores an agent pane from the session id the CLI's integration
reports and, by default, restarts the bare CLI (`claude --resume <id>`):
no profile home, no key from the env file, no autonomy flag - the session
is not found, the wrong account opens, or the CLI asks for a login.

- lib/restore.py: an interactive `ak <kind> [@Profile]` inside a Herdr pane
  starts a detached watcher that re-reports each new session id with
  resume_argv `ak <kind> @<profile> [--ask] --resume <id>` (same source and
  agent, later seq). It reports again on every id change because Herdr
  keeps an older resume_argv when a later report omits it. It exits with
  the CLI, writes nothing, and gets no key or token. macOS, Linux and
  Windows; AGENTKIT_HERDR_RESUME=0 turns it off.
- lib/last.py: every interactive launch records kind, profile and posture
  per directory (launches.json in the state dir, 0600); `ak last`
  relaunches it with -c, `ak last -r` opens the picker, `ak last ls` lists.
- Tests: tests/py/restore_checks.py (also run natively on Windows CI) and
  the `restore` scope with a fake herdr; the security scope accounts for
  the launch record.
- Docs: profiles, SECURITY, TESTING_GUIDE, README, skill, env template,
  CHANGELOG.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
@xergioalex xergioalex added the Ready Ready for review label Oct 27, 2026
- Version 1.2.0 in every version source: lib/common.py, the three skills'
  metadata, the install and skill commands in the README and docs, the
  schemas' $id, the issue template, the tests that assert it, and the
  addon registry (.dwp/config.json).
- CHANGELOG 1.2.0 (dated 2026-10-27): the Herdr resume watcher and
  `ak last`; link references for 1.2.0.
- SECURITY.md lists 1.2.0 as latest.
- Interface stays 1.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
@xergioalex xergioalex changed the title feat: Herdr restores panes through ak, and ak last resumes in any terminal feat: Herdr restores panes through ak, ak last, release v1.2.0 Oct 27, 2026
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

Ready Ready for review

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant