Command overview
beacon handoff finds the agent sessions stored on this machine so you can pick one up again.
Command syntax
Supported runtimes
When a Codex thread has more than one rollout file,
beacon handoff lists it once, under its newest file. Cline can hold the same task both as a CLI session and in its older task history; the CLI session is the copy that is listed. Cline kanban cards are not sessions and are not listed. Prime Agent subagent transcripts, under session-artifacts, are listed as subagents of the session that started them. Hermes Agent delegate subagents are listed as subagents of the session that spawned them. When Hermes compresses a long conversation it continues it in a new session; each of those sessions is listed, and reopening any of them reopens the latest. A DeepSeek Harness session that DSH spawned for delegated work is listed as a subagent of the session that started it; a fork of a session is listed as a session of its own. Grok Build keeps its subagents’ child sessions in the same tree as other sessions; those whose summary.json has a subagent session_kind are listed as subagents. OpenClaw transcript ids are unique only within one agent. When two agents hold the same id, both are listed, and export and resume report the id as ambiguous rather than pick one. A Cursor conversation can be stored both as a transcript and as a Composer record under one id; it is listed once, as the transcript when cursor-agent can reopen it and as the Composer record otherwise. Cursor subagent transcripts are listed as subagents of the conversation that started them.
OpenClaw Gateway sessions are read from the JSONL transcripts and the sessions.json index in each agent’s sessions directory, as beacon endpoint openclaw sessions sync reads them. Recent OpenClaw releases keep live sessions in a per-agent SQLite database and treat that directory as legacy, so sessions that exist only in the database are not listed.
--store-dir <runtime>=<path> takes the location in the table: for Pi its sessions directory, as beacon endpoint pi sync --sessions-dir does, and for Prime Agent the agent directory holding both of its roots. For Factory Droid it is the sessions directory, as beacon endpoint factory sync --sessions-dir does. For GitHub Copilot CLI it is the ~/.copilot directory that holds session-state, as beacon endpoint copilot sync --copilot-dir does. For Hermes Agent it is the state.db file, as beacon endpoint hermes sync --db does. For DeepSeek Harness it is its DSH_HOME, as beacon endpoint dsh sync --dsh-home does. For fx it is its sessions directory, as beacon endpoint fx sync --sessions-dir does. For Grok Build it is its sessions directory, as beacon endpoint grok sync --sessions-dir does. Like that sync, beacon handoff does not read GROK_HOME; pass --store-dir grok=$GROK_HOME/sessions when it is set. For OpenClaw Gateway it is its state directory, as beacon endpoint openclaw sessions sync --openclaw-dir does. For Cursor it is the projects directory, as beacon endpoint cursor sync --projects-dir does. Cursor’s global storage database is always read from its default location.
fx records no session title, so an fx session is listed under its first prompt, and its directory is the workspace fx last bound it to.
Runtimes Beacon starts but does not read
Beacon keeps no reader for these runtimes’ own session stores, solist does not show their sessions. export and resume still find one by id in Beacon’s runtime log, and they can be the runtime another session continues in (--agent):
Kimi Code can only take a prompt non-interactively, and Senpi (
omo) moves Pi’s agent directory into its own the first time it runs, so Beacon does not start them.
beacon handoff list
Lists resumable sessions, newest first.
A store that cannot be read is reported as a warning (on stderr, or under
warnings in JSON), and the sessions from the other runtimes are still listed.
beacon handoff export
Writes a handoff brief for one session: a Markdown summary of what it asked for, what it changed, and where it stopped, for another agent or person to continue from.
--harness when two runtimes use the same id.
A brief has these sections:
- Source session: runtime, session id, title, directory, branch, last activity, session file, and activity counts.
- Where it stood: the first request, the latest request, and the last agent message.
- Files changed and Recent commands, with exit codes where the runtime reports them.
- Recent activity: the last 30 steps (prompts, agent messages, commands, file changes, tool failures, MCP calls), each cut to 1,200 characters.
- Before continuing: check the working tree, and confirm the task before changing anything.
export reads it from Beacon’s runtime log instead. This works for any runtime Beacon captured, but the log keeps less of each step, and the brief says so.
Briefs are written to ~/.beacon/endpoint/handoffs. The directory is 0700 and each file is 0600, because a brief carries prompt text and command output. An existing brief is never overwritten.
beacon handoff resume
Picks a session up again, in its own runtime or another one.
-
Reopen natively. Beacon reopens the session with its full context when all of these hold: it continues in the same runtime, that runtime’s CLI can load this kind of session, and the session file is still on this machine.
-
Start a new session from a brief. Otherwise, or with
--agentnaming another runtime or with--new, Beacon writes a brief (seeexport) and starts a new session. The first message of that session points at the brief:The prompt names the brief by its path and asks the agent to read it, then confirm the task before changing anything. The brief is never inlined into the command line, because a command line is visible to every local user through the process table. The prompt ends with a handoff marker (see below).
--agent), and --agent hermes reopens only Hermes’s own sessions.
Claude Code, Cline, Prime Agent, Hermes Agent and Grok Build subagent sessions, and Cline’s older task history, can’t be reopened by their CLIs, so they always continue from a brief. A session known only from Beacon’s runtime log also continues from a brief, and it needs --agent if its own runtime isn’t one Beacon can start.
Beacon cannot start DeepSeek Harness, because it has no interactive terminal session to start: dsh --profile headless answers one task and exits, and dsh web is a browser UI. A DeepSeek Harness session therefore continues in another runtime, named with --agent, and --agent dsh is refused.
fx has no interactive session that starts from a prompt (fx ask runs one request and exits), so it is not in the new-session table. Beacon reopens an fx session natively, and continues it in another runtime with --agent; --agent fx for another runtime’s session, --new on an fx session, and an fx session whose files are gone stop with an error rather than launching anything. fx looks a session id up within the workspace it runs in, so Beacon starts it in the session’s workspace, and --cwd naming another directory stops with an error too, since fx could not find the session there. fx’s default permission mode is auto, where a reviewer resolves permission requests, and fx has no command-line flag to change it. Beacon passes none: it reopens your own session under whatever permission mode your fx configuration sets.
OpenClaw’s TUI is a client of the Gateway, so the Gateway must be running (openclaw gateway run, or its installed service) for either command to connect; Beacon does not start it. The Gateway reopens a conversation by its session key, such as agent:main:main, not by its transcript id, so an OpenClaw session is reopened natively only when the agent’s sessions.json files the transcript under a key qualified with that agent (agent:<agent>:...); otherwise it continues from a brief. The Gateway answers for that key with whatever conversation it now holds under it: a key it no longer knows can open as an empty conversation. A new session gets a key of its own, beacon-handoff- and a hash of its prompt, because without --session the TUI would post into the agent’s shared main session. Beacon never passes --deliver, so replies stay in the TUI and are not sent out through the Gateway’s chat channels.
cursor-agent --resume reopens only chats the CLI itself started, which it keeps under ~/.cursor/chats (or CURSOR_CONFIG_DIR, or $XDG_CONFIG_HOME/cursor) keyed by the directory the chat ran in. Beacon reopens a Cursor session natively only when that chat store exists for the session’s recorded directory, and only from that directory: with --cwd pointing elsewhere, it continues from a brief. Conversations from the Cursor IDE, Composer records, and subagent transcripts continue from a brief. Beacon never passes --force or --yolo, so cursor-agent still asks before running commands.
Cline approves every tool call by default. Beacon always passes --auto-approve false, so a session Beacon starts never gets auto-approval on Beacon’s say-so. You can still turn it on inside the Cline TUI.
The same holds for every runtime Beacon starts. Oh My Pi and goose approve every tool call by default, so Beacon passes --approval-mode=always-ask to Oh My Pi and sets GOOSE_MODE=approve for goose. Where a CLI takes an approval mode, Beacon names the mode that asks (Gemini CLI, Qwen Code, Muse Code, and Devin CLI, whose DEVIN_PERMISSION_MODE could otherwise hold dangerous), so a user or project setting that approves everything does not carry over. Beacon never passes a flag that turns approvals off.
GitHub Copilot CLI asks before each tool call unless COPILOT_ALLOW_ALL=true is set, which also trusts the directory, or COPILOT_PLAN_THEN_AUTOPILOT starts it in plan mode and carries the plan out without waiting. Beacon removes both from the environment it launches Copilot with (--print shows them under env), and never passes --allow-all-tools or --yolo. Copilot sessions are not tied to a directory, but Beacon still starts Copilot in the session’s recorded directory.
Hermes Agent asks before dangerous commands by default. Beacon never passes --yolo, and it removes HERMES_YOLO_MODE from the environment it starts Hermes in, so an exported variable can’t turn those prompts off. hermes --resume looks the id up in the state database Hermes itself uses (under HERMES_HOME when that is set), not in a --store-dir path.
Grok Build’s configured permission mode can be always-approve. Beacon always passes --permission-mode default, the mode that asks before running tools, so a session Beacon starts or reopens never inherits always-approve from that config. You can still change the mode inside the Grok TUI. Grok looks a session id up under the directory it runs in, which is why the resume runs in the session’s recorded directory. With --cwd naming another directory, a Grok session continues from a brief instead.
By default, the runtime runs in this terminal. --launch auto instead opens a new terminal surface
on a desktop and creates a detached tmux session on SSH or headless Linux. When Beacon runs inside
cmux on macOS, it opens another terminal in the calling workspace; otherwise it uses Terminal.app.
This is useful from an agent harness, whose command subprocess generally does not own a TTY that
another interactive runtime can use.
The launch modes are:
Linux desktop detection supports
xdg-terminal-exec, GNOME Terminal, Konsole, Kitty, WezTerm,
Alacritty, foot, x-terminal-emulator, xterm, and a simple executable named by $TERMINAL.
Detached launches use a private, expiring 0600 specification under
~/.beacon/endpoint/handoffs. The new terminal runs a hidden Beacon trampoline that consumes the
specification, starts the exact approval-safe argument vector, and confirms startup to the calling
process. Prompt or brief content is never interpolated into a terminal-launch shell command.
If the runtime does not confirm startup within 15 seconds, Beacon removes the specification and
reports the launch as cancelled, so a terminal that opens late starts nothing and a retry cannot
start the runtime twice. The trampoline claims the specification by renaming it before it reads
it, so only one side wins: if the terminal had already claimed it, Beacon says the runtime may
still start there instead of reporting it cancelled. Check that terminal before retrying.
A new terminal starts from its own environment rather than the calling process’s. Beacon carries
the variables that locate a runtime’s configuration and sessions (CLAUDE_CONFIG_DIR,
CLINE_DIR, CODEX_HOME, COPILOT_HOME, CURSOR_CONFIG_DIR, GEMINI_CLI_HOME,
HERMES_DATA_DIR_SUFFIX, HERMES_HOME, KIRO_HOME, OH_PERSISTENCE_DIR, OMP_PROFILE,
OPENCLAW_STATE_DIR, OPENCODE_DB, PI_CODING_AGENT_DIR, PI_CONFIG_DIR, PI_PROFILE,
PRIME_AGENT_CODING_AGENT_DIR, QWEN_HOME and XDG_CONFIG_HOME/XDG_DATA_HOME/XDG_STATE_HOME)
into the specification. It never writes other variables there, so credentials such as API keys must be
available in the new terminal’s own environment, for example from your shell profile.
The runtime starts in the session’s recorded directory. If that directory no longer exists, Beacon
stops rather than starting somewhere else; pass --cwd to choose a directory. Beacon prints the
plan and asks Continue? [Y/n] before launching. From a non-TTY tool, pass --yes with a detached
launch mode. A current launch exits with the runtime’s own exit code.
Linking a new session to the one it continues
A session started from a brief has a new session id. So that the two stay connected in the telemetry, the first prompt of the new session ends with a handoff marker:session.handoff, next to the usual prompt.submitted:
e.handoff.source_harness and e.handoff.source_session_id.
Two paths record the link:
- Live hooks and plugins. Every runtime whose prompts Beacon captures as they are sent records it: the shared prompt hook (Claude Code, Cursor, Factory Droid, Qwen Code, Kiro, Kimi Code, Devin, Muse Code, OpenHands, Grok Build, DeepSeek Harness, Hermes Agent, VS Code), Antigravity (including the prompt it recovers from its transcript when the prompt hook does not fire), the Cline, OpenCode and OpenClaw plugins, and the Pi, Oh My Pi, Prime Agent and Senpi extensions (
harness.collection_methodhookorplugin). - Session-store sync.
beacon endpoint claude sync,codex sync,opencode sync,cline sync,pi sync,prime sync,factory sync,copilot sync,hermes sync,dsh sync,fx sync,grok sync,openclaw sessions syncandcursor syncrecord it when they read the prompt back from the runtime’s store (harness.collection_method: poll).
beacon endpoint codex sync, not a prompt hook, so a session continued in Codex is linked by the sync. The same holds for GitHub Copilot CLI, whose live path is OTLP: beacon endpoint copilot sync records the link. For a runtime that also has a prompt hook or plugin, a sync can record the same link the hook already did; the two carry different collection_method values, as every other event those runtimes report through both paths does. A sync’s link has a deterministic event.id, so syncing again never duplicates it.
The marker is a claim made in prompt text, not a verified identity: anyone can type it. fidelity: observed records that the marker was seen, not that beacon handoff resume wrote it. A native resume keeps the session’s own id, so it needs no link.