sesh-cli

Compare original and translation side by side

🇺🇸

Original

English
🇨🇳

Translation

Chinese

sesh CLI skill

sesh CLI 技能

Use this skill when the user wants to use
sesh
(manage their coding-agent sessions), not develop sesh itself.
sesh
is multi-machine coding-agent session management that feels like one machine. A per-machine daemon (
sesh-daemon
) owns a local SQLite store and runs a tmux walker (which pane each session is in) + agent transcript watchers. Daemons peer-to-peer over gRPC so every machine sees every machine's sessions (a full mesh). The
sesh
CLI/TUI talks only to the local daemon over a unix socket.
当用户想要使用
sesh
(管理他们的coding-agent会话)而非开发sesh本身时,使用本技能。
sesh
是一款多机器coding-agent会话管理工具,使用体验如同在单台机器上操作。每台机器上的守护进程
sesh-daemon
)负责管理本地SQLite存储,并运行tmux遍历器(跟踪每个会话所在的窗格)以及Agent转录监视器。守护进程通过gRPC实现对等节点间通信,因此每台机器都能看到所有机器的会话(全网格架构)。
sesh
CLI/TUI仅通过Unix套接字与本地守护进程通信。

Short UUIDs

短UUID

Every command that takes a
<uuid>
also accepts a short prefix — the first 8 characters (or any unambiguous prefix). For example, if a session's UUID is
a808a699-…
, you can use
a808a699
or even
a808
if that prefix is unique:
bash
sesh info a808a699          # same as sesh info a808a699-xxxx-xxxx-xxxx-xxxx
sesh send a808a699 "hello"
sesh pane-capture a808      # only if a808 uniquely identifies one session
If a prefix matches multiple sessions, non-archived sessions win. If the tie is still ambiguous (multiple non-archived, or multiple archived with no active match), the command errors and lists all matching UUIDs.
Use
sesh find <prefix>
to explore matches before acting:
bash
sesh find a808              # list every session whose UUID starts with a808
所有接受
<uuid>
参数的命令也支持短前缀——UUID的前8个字符(或任何无歧义的前缀)。例如,如果某个会话的UUID是
a808a699-…
,你可以使用
a808a699
,甚至在该前缀唯一的情况下使用
a808
bash
sesh info a808a699          # 等同于 sesh info a808a699-xxxx-xxxx-xxxx-xxxx
sesh send a808a699 "hello"
sesh pane-capture a808      # 仅当a808能唯一标识一个会话时可用
如果某个前缀匹配多个会话,未归档会话优先。如果仍存在歧义(多个未归档会话,或多个归档会话且无活跃匹配项),命令会报错并列出所有匹配的UUID。
使用
sesh find <prefix>
在执行操作前查看匹配项:
bash
sesh find a808              # 列出所有UUID以a808开头的会话

Before running commands

执行命令前须知

  • Read-only — safe to run anytime:
    list
    ,
    find
    ,
    info
    ,
    state
    ,
    pane
    ,
    pane-resolve
    ,
    tags
    ,
    tail
    ,
    transcript
    ,
    doctor
    ,
    daemon status
    ,
    peer
    (listing),
    pick
    /
    tui
    (interactive; they emit a selection, they don't mutate).
  • Mutating / side-effecting — confirm intent first:
    new
    (spawns an agent),
    register
    ,
    rename
    ,
    tag
    /
    untag
    /
    retag
    ,
    archive
    /
    unarchive
    ,
    delete
    ,
    send
    (messages the agent),
    abort
    ,
    compact
    ,
    autoname
    ,
    autoname-toggle
    ,
    resume
    (switches/launches tmux),
    copy
    ,
    backup
    /
    restore
    /
    import
    ,
    daemon start/stop/restart
    ,
    peer add/remove
    .
  • Be especially careful with:
    • delete <uuid>
      — removes the record (a tombstone propagates across the mesh).
      --force
      tombstones a sesh this machine doesn't own (orphan cleanup); only use it when the owning machine is gone. Once deleted, the session is gone everywhere: it is no longer resolvable (by full UUID or short prefix) and all reads/mutations on it report "not found" (exit 1).
    • send <uuid> <message>
      — actually drives the agent.
    • import
      — one-shot migration of v1
      ~/.sesh/sessions.json
      .
  • 只读命令——随时可安全执行
    list
    find
    info
    state
    pane
    pane-resolve
    tags
    tail
    transcript
    doctor
    daemon status
    peer
    (列出节点)、
    pick
    /
    tui
    (交互式;仅输出选择结果,不修改数据)。
  • 修改类/有副作用命令——请先确认意图
    new
    (启动Agent)、
    register
    rename
    tag
    /
    untag
    /
    retag
    archive
    /
    unarchive
    delete
    send
    (给Agent发送消息)、
    abort
    compact
    autoname
    autoname-toggle
    resume
    (切换/启动tmux)、
    copy
    backup
    /
    restore
    /
    import
    daemon start/stop/restart
    peer add/remove
  • 尤其需要注意以下命令:
    • delete <uuid>
      ——删除会话记录(墓碑标记会在网格中传播)。
      --force
      参数用于标记本机不拥有的会话(清理孤立会话);仅在会话所属机器已下线时使用。一旦删除,会话将在所有机器上消失:无法通过完整UUID或短前缀找到,所有对该会话的读取/修改操作都会返回“未找到”(退出码1)。
    • send <uuid> <message>
      ——直接驱动Agent执行操作。
    • import
      ——一次性迁移v1版本的
      ~/.sesh/sessions.json
      文件。

Core concepts

核心概念

  • UUID & short id. Each session has a UUID. The "short id" is the part up to the first
    -
    (e.g.
    a42f8a74
    ); the TUI shows it and most users refer to sessions by it. Commands accept the full UUID.
  • Machine = origin. Every record carries the machine that owns it (
    $SESH_MACHINE
    ). The owning machine is the single writer for it. Reads work from anywhere (the mesh synced the record locally). Everything else routes cross-machine through one owner-routing seam — run it from any machine that peers with the owner and it's forwarded to the owner's daemon, which applies it and (for a mutation) propagates the updated record back. This covers record mutations (
    rename
    /
    tag
    /
    untag
    /
    retag
    /
    archive
    /
    unarchive
    /
    delete
    /
    autoname-toggle
    )
    , agent actions (
    send
    /
    abort
    /
    compact
    )
    , and transcript reads (
    tail
    /
    transcript
    /
    autoname
    )
    . You no longer have to ssh to the owner to mutate or read a remote session. (A termux-owned session still can't be reached from a server that termux doesn't dial back — that errors clearly.
    delete --force
    for an orphan whose owner is gone stays local, since there's no owner to forward to.)
  • Live vs detached. "Live" = the session currently has a tmux pane (the walker found it); "detached" = no pane. The glyphs:
    live+idle,
    live+busy,
    detached.
  • Archived is orthogonal to live/busy — an archived session can still be live. Views: active (default), archived, all.
  • Agents:
    claude
    ,
    pi
    ,
    codex
    . Some verbs are agent-specific (
    abort
    /
    compact
    are pi-only).
  • UUID与短ID:每个会话都有一个UUID。“短ID”是第一个
    -
    之前的部分(例如
    a42f8a74
    );TUI会显示短ID,大多数用户也通过短ID指代会话。命令接受完整UUID作为参数。
  • 机器=源节点:每条记录都携带其所属机器的标识(
    $SESH_MACHINE
    )。所属机器是该记录的唯一写入方。读取操作可在任意机器上进行(网格已将记录同步到本地)。所有跨机器操作都通过单一源节点路由层转发——在任何与源节点连通的机器上执行命令,都会转发到源节点的守护进程,由其执行操作并(针对修改类命令)将更新后的记录同步回网格。这涵盖了记录修改操作(
    rename
    /
    tag
    /
    untag
    /
    retag
    /
    archive
    /
    unarchive
    /
    delete
    /
    autoname-toggle
    Agent操作(
    send
    /
    abort
    /
    compact
    以及转录读取操作(
    tail
    /
    transcript
    /
    autoname
    。你无需通过SSH登录到源节点即可修改或读取远程会话。 (Termux所属的会话仍无法被未反向连接的服务器访问——此类情况会明确报错。针对已下线源节点的孤立会话执行
    delete --force
    仅在本地生效,因为没有可转发的源节点。)
  • 活跃与分离状态:“活跃”指会话当前拥有tmux窗格(遍历器已找到);“分离”指无窗格。状态图标:
    活跃+空闲、
    活跃+忙碌、
    分离。
  • 归档状态独立于活跃/忙碌状态——已归档的会话仍可处于活跃状态。视图选项:活跃(默认)、归档、全部。
  • Agent类型
    claude
    pi
    codex
    。部分命令是Agent专属的(
    abort
    /
    compact
    仅适用于pi)。

The TUI —
sesh tui
(the primary interface)

TUI界面——
sesh tui
(主界面)

Full-screen manager over every machine's sessions, with live updates. Columns: id · name · cwd · agent · machine · socket · tags · created (rows sort by creation time, earliest→latest). The name (blue) and cwd (green) columns are color-accented so they stand out; archived rows are dimmed gray and the cursor row is reverse-highlighted.
Keys:
↑↓
/
jk
/
Ctrl-j
/
Ctrl-k
move ·
/
fuzzy-filter ·
Tab
cycle active/archived/all ·
i
toggle the id column ·
y
show full UUID popup ·
a
archive ·
u
unarchive ·
r
rename ·
t
add-tag ·
x
remove-tag ·
d
delete ·
Enter
select ·
q
/
Esc
quit.
sesh tui
emits the selected session on
Enter
(it doesn't drive tmux itself — "emit, don't drive"); a wrapper navigates.
sesh tui --enter
opts into driving locally instead (switch to a live pane / resume a detached one / ssh into a remote owner).
全屏管理所有机器的会话,并支持实时更新。列项:id · 名称 · 工作目录(cwd) · Agent类型 · 机器 · 套接字 · 标签 · 创建时间(行按创建时间排序,从最早到最新)。名称(蓝色)和工作目录(绿色)列带有颜色高亮,以便区分;归档行显示为灰色,光标所在行显示为反色高亮。
快捷键:
↑↓
/
jk
/
Ctrl-j
/
Ctrl-k
移动光标 ·
/
模糊过滤 ·
Tab
切换活跃/归档/全部视图 ·
i
切换ID列显示 ·
y
显示完整UUID弹窗 ·
a
归档会话 ·
u
取消归档 ·
r
重命名 ·
t
添加标签 ·
x
删除标签 ·
d
删除会话 ·
Enter
选择会话 ·
q
/
Esc
退出。
sesh tui
在按下
Enter
输出选中的会话(不直接驱动tmux——“输出而非驱动”);可通过包装脚本实现导航。
sesh tui --enter
选项可直接在本地驱动tmux(切换到活跃窗格/恢复分离会话/SSH登录到远程源节点)。

Entering / resuming a session

进入/恢复会话

bash
sesh resume <uuid>                       # live → switch to its pane; detached → resume the agent
sesh resume <uuid> --target socket:sess  # create that tmux session (if absent) + open a window
sesh resume                              # no uuid → interactive picker
sesh pick                                # pick a session; print the selection (json/nul/kv) on stdout
sesh pick --select <uuid> --enter        # non-interactive enter of a specific sesh
resume
/
pick
/
tui
use vanilla
tmux switch-client
/
attach
— no master-tmux assumptions. The myrig shell layer (
sesh-tui
,
sesh-enter
) wraps these to route through master-tmux.
bash
sesh resume <uuid>                       # 活跃会话→切换到对应窗格;分离会话→恢复Agent
sesh resume <uuid> --target socket:sess  # 创建指定tmux会话(若不存在)并打开窗口
sesh resume                              # 无uuid参数→交互式选择器
sesh pick                                # 选择会话;在标准输出打印选择结果(json/nul/kv格式)
sesh pick --select <uuid> --enter        # 非交互式进入指定会话
resume
/
pick
/
tui
使用原生
tmux switch-client
/
attach
命令——无需依赖主tmux假设。myrig shell层(
sesh-tui
sesh-enter
)包装这些命令以实现主tmux路由。

Listing & inspecting

列出与查看会话

bash
sesh list                                # active sessions, all machines
sesh list --machine <name>               # one machine
sesh list --archived                     # include archived (alias: --include-archived)
sesh list --agent claude --tag work      # filters
sesh list --columns uuid,name,agent,machine,status,cwd,tags,archived,tmux-socket,tmux-session,tmux-window,tmux-pane,live   # TSV for fzf/awk (unknown column name errors)
sesh find <partial-uuid>                 # list all sessions (including archived) matching a UUID prefix
sesh info <uuid> [--json]                # full record
sesh state <uuid>                        # turnStatus + per-agent extras
sesh tags                                # all tags in use across the mesh (every machine)
sesh tail <uuid> [-n N]                  # last N transcript lines (any machine; forwards to the owner)
sesh transcript <uuid>                   # full transcript (any machine; forwards to the owner)
sesh pane [--pane %ID] [--socket-path P] # which REGISTERED sesh owns a tmux pane (store-backed; status bars)
sesh pane-resolve --pane %ID --socket-path P  # uuid of the agent LIVE in a pane, registered or not (walker-backed)
sesh pane-capture <uuid> [-n N]          # capture current pane text (local; for inspecting stuck TUI state)
sesh pane-keys <uuid> <key>...           # send raw tmux key names to a pane (local; for navigating TUI prompts)
pane
vs
pane-resolve
:
pane
reads the store (only knows registered records);
pane-resolve
runs the walker to identify the live agent in a pane even if it was never registered — the primitive for adopting an agent (
uuid=$(sesh pane-resolve …) && sesh register "$uuid" …
). Works for all three agents (claude via argv/
agents --json
, pi via its rpc socket, codex via the rollout it holds open). Local-only (pane ids are per-tmux-server, like
pane
).
--json
emits
{uuid, agent, cwd, machine, tmux}
. Exit codes:
0
resolved ·
3
no agent in the pane ·
4
agent found but unresolvable (e.g. a codex that hasn't taken its first turn yet — it has no session on disk until then).
All
--json
output uses camelCase keys.
info --json
and each element of
list --json
/
find --json
are the full session record:
{uuid, name, agent, machine, cwd, turnStatus, archived, autoRename, summary, lastAutoNameTurnCount, contextPct, filePath, tmux:{socket, session, window, pane}, createdAt, updatedAt, originSeq, tags, deleted}
. To check a tombstone:
sesh info <uuid> --json | grep '"deleted": true'
.
pane-capture
returns the visible text of the pane (last N lines, default 50).
pane-keys
sends raw tmux key names (Enter, Escape, Up, Down, q, 1, 2, …) — use it for TUI prompts that appear before the agent accepts conversation messages. Both are local-only and refuse a remote-owned uuid with a clear "owned by <machine>; run on <machine>" error — they drive the local tmux, so feeding a remote record's per-machine pane/socket would error cryptically or hit the wrong local pane. Run them on the owning machine.
bash
sesh list                                # 所有机器的活跃会话
sesh list --machine <name>               # 指定机器的会话
sesh list --archived                     # 包含归档会话(别名:--include-archived)
sesh list --agent claude --tag work      # 过滤条件
sesh list --columns uuid,name,agent,machine,status,cwd,tags,archived,tmux-socket,tmux-session,tmux-window,tmux-pane,live   # 生成TSV格式输出,供fzf/awk使用(未知列名会报错)
sesh find <partial-uuid>                 # 列出所有UUID前缀匹配的会话(包括归档会话)
sesh info <uuid> [--json]                # 完整会话记录
sesh state <uuid>                        # 会话状态+Agent专属信息
sesh tags                                # 网格中所有机器使用的标签
sesh tail <uuid> [-n N]                  # 最后N行转录内容(任意机器;转发到源节点)
sesh transcript <uuid>                   # 完整转录内容(任意机器;转发到源节点)
sesh pane [--pane %ID] [--socket-path P] # 哪个已注册的sesh会话拥有指定tmux窗格(基于存储;适用于状态栏)
sesh pane-resolve --pane %ID --socket-path P  # 窗格中活跃Agent的uuid,无论是否注册(基于遍历器)
sesh pane-capture <uuid> [-n N]          # 捕获当前窗格文本(本地;用于查看卡住的TUI状态)
sesh pane-keys <uuid> <key>...           # 向窗格发送原始tmux按键名称(本地;用于导航TUI提示)
pane
pane-resolve
的区别:
pane
读取存储(仅知晓已注册记录);
pane-resolve
运行遍历器以识别窗格中的活跃Agent,即使该Agent从未注册——这是“接管”Agent的基础操作(
uuid=$(sesh pane-resolve …) && sesh register "$uuid" …
)。适用于所有三种Agent(claude通过argv/
agents --json
识别,pi通过其rpc套接字识别,codex通过其保持打开的部署进程识别)。仅本地可用(窗格ID是每个tmux服务器独有的,与
pane
相同)。
--json
参数输出
{uuid, agent, cwd, machine, tmux}
格式。退出码:
0
解析成功 ·
3
窗格中无Agent ·
4
找到Agent但无法解析(例如codex尚未完成第一轮交互——此时磁盘上还没有会话记录)。
所有
--json
输出使用**驼峰式(camelCase)**键名。
info --json
以及
list --json
/
find --json
的每个元素都是完整的会话记录:
{uuid, name, agent, machine, cwd, turnStatus, archived, autoRename, summary, lastAutoNameTurnCount, contextPct, filePath, tmux:{socket, session, window, pane}, createdAt, updatedAt, originSeq, tags, deleted}
。检查墓碑标记:
sesh info <uuid> --json | grep '"deleted": true'
pane-capture
返回窗格的可见文本(最后N行,默认50行)。
pane-keys
发送原始tmux按键名称(Enter、Escape、Up、Down、q、1、2等)——用于处理Agent接受对话消息前出现的TUI提示。这两个命令仅本地可用,且拒绝远程所属的uuid,会明确报错“会话所属机器为<machine>;请在<machine>上运行”——它们驱动本地tmux,因此传入远程记录的窗格/套接字信息会导致模糊错误或操作错误的本地窗格。请在会话所属机器上运行这些命令。

Startup prompts that can block a freshly-spawned claude session

新启动的claude会话可能遇到的启动提示

When spawning a claude session in a directory whose
CLAUDE.md
imports files outside the cwd (e.g.
@~/.config/AGENTS.md
), claude may open to an interactive confirmation:
Allow external CLAUDE.md file imports?
  > 1. Yes, allow external imports
    2. No, disable external imports
Enter to confirm · Esc to cancel
sesh send
will not work while this prompt is visible — the agent hasn't initialised yet. The recovery pattern:
bash
sesh pane-capture <uuid>              # confirm the prompt is showing
sesh pane-keys <uuid> Enter           # confirm option 1 (already selected)
在当前目录的
CLAUDE.md
引用了工作目录外文件(例如
@~/.config/AGENTS.md
)的情况下启动claude会话时,claude可能会弹出交互式确认提示:
Allow external CLAUDE.md file imports?
  > 1. Yes, allow external imports
    2. No, disable external imports
Enter to confirm · Esc to cancel
在此提示可见时,
sesh send
无法工作——Agent尚未初始化。解决方法:
bash
sesh pane-capture <uuid>              # 确认提示已出现
sesh pane-keys <uuid> Enter           # 确认选择选项1(已默认选中)

wait a moment, then:

等待片刻后:

sesh send <uuid> "your first message"

If you spawn frequently in the same directory and keep hitting this prompt,
configure the acceptance globally:
- Accept it once interactively in a manually-opened claude session; claude
  remembers the answer per-project in `~/.claude/projects/<dir>/settings.json`.
- Or set `allowExternalImports: true` in your `~/.claude/settings.json`.
sesh send <uuid> "your first message"

如果你经常在同一目录启动会话并遇到此提示,可全局配置自动确认:
- 在手动打开的claude会话中交互式确认一次;claude会在`~/.claude/projects/<dir>/settings.json`中记住每个项目的设置。
- 或在`~/.claude/settings.json`中设置`allowExternalImports: true`。

Lifecycle (run from anywhere — mutations forward to the owner)

会话生命周期(可在任意机器运行——修改操作会转发到源节点)

bash
sesh new --agent claude --name foo --tag work [-- agent-args...]  # spawn + register from birth; cwd defaults to $PWD
sesh new --agent claude --model opus     # launch with a specific model (see "Model selection")
sesh new --agent claude --target socket:sess --msg "greet me" --name foo  # spawn window + send initial message, print reply
sesh new --agent pi --dry-run            # print the plan, register nothing (add --json for a JSON plan)
sesh new --agent claude --no-launch      # register only
sesh new --agent claude --session-id <uuid> --no-launch  # pre-assign the UUID (must be a well-formed UUID)
sesh new --agent claude --cwd ./sub      # --cwd is absolutized to a realpath (relative is resolved against $PWD)
sesh new --headless --agent claude --msg "do X" --name child  # persistent headless child (no tmux window)
sesh register <session-id> --agent pi --name foo   # record an already-running agent; --cwd defaults to $PWD
sesh rename <uuid> <name>                # sets autoRename=false (unless --keep-auto)
sesh tag <uuid> <tag>...    /  sesh untag <uuid> <tag>...  /  sesh retag <uuid> old=new   # empty/whitespace tag names are rejected (e.g. tag '' or retag old=)
sesh archive <uuid>  /  sesh unarchive <uuid>            # orthogonal to live/busy
sesh delete <uuid> [--force]             # tombstone (propagates); --force for an orphan
Note:
codex
can't pre-assign a session id, so interactive
new --agent codex
is unsupported — start it and
sesh register
. (
new --headless --agent codex
and
delegate --agent codex
DO work — they recover the id from codex's own output.)
bash
sesh new --agent claude --name foo --tag work [-- agent-args...]  # 启动并注册会话;工作目录默认当前目录
sesh new --agent claude --model opus     # 使用指定模型启动(参见“模型选择”)
sesh new --agent claude --target socket:sess --msg "greet me" --name foo  # 创建窗口并发送初始消息,打印回复
sesh new --agent pi --dry-run            # 打印计划,不注册会话(添加--json参数可输出JSON格式计划)
sesh new --agent claude --no-launch      # 仅注册会话
sesh new --agent claude --session-id <uuid> --no-launch  # 预分配UUID(必须是格式正确的UUID)
sesh new --agent claude --cwd ./sub      # --cwd会解析为绝对路径(相对路径基于当前目录解析)
sesh new --headless --agent claude --msg "do X" --name child  # 持久化无头子会话(无tmux窗口)
sesh register <session-id> --agent pi --name foo   # 记录已在运行的Agent;工作目录默认当前目录
sesh rename <uuid> <name>                # 设置autoRename=false(除非使用--keep-auto参数)
sesh tag <uuid> <tag>...    /  sesh untag <uuid> <tag>...  /  sesh retag <uuid> old=new   # 空标签或空白标签会被拒绝(例如tag ''或retag old=)
sesh archive <uuid>  /  sesh unarchive <uuid>            # 独立于活跃/忙碌状态
sesh delete <uuid> [--force]             # 标记墓碑(会在网格中传播);--force用于处理孤立会话
注意:
codex
无法预分配会话ID,因此不支持交互式
new --agent codex
——请先启动codex,再执行
sesh register
。(
new --headless --agent codex
delegate --agent codex
可以正常工作——它们从codex的输出中恢复ID。)

Spawning child agents —
new --headless
and
delegate

启动子Agent——
new --headless
delegate

Two ways for one agent to spawn another (e.g. a parent agent farming out work). Both run the agent non-interactively — no tmux window:
bash
undefined
有两种方式让一个Agent启动另一个Agent(例如父Agent分配任务)。两种方式都以非交互式运行Agent——无tmux窗口:
bash
undefined

PERSISTENT child you keep talking to. Runs the first turn (--msg), creates

持久化子会话,可反复对话。执行第一轮交互(--msg),在磁盘上创建会话,注册会话,打印回复。之后可使用
sesh send <uuid>
以无头模式恢复会话。仅适用于claude/codex。

the session on disk, registers it, prints the reply. Later `sesh send

<uuid>` resumes it headlessly. claude/codex only.

sesh new --headless --agent claude --msg "You are my test runner. Reply READY." --name runner sesh send <uuid> "run the suite and summarise failures" # talk to it over time
sesh new --headless --agent claude --msg "You are my test runner. Reply READY." --name runner sesh send <uuid> "run the suite and summarise failures" # 后续对话

EPHEMERAL one-shot: spawn a worker, give it ONE task, print the reply, then

临时一次性会话:启动Worker,分配一个任务,打印回复,然后删除会话。⚠️会话返回结果后会消失——后续无法访问(使用--keep参数可保留会话)。适用于pi、claude和codex。

DELETE the session. ⚠️ The session DISAPPEARS once it returns — it is gone

afterward (use --keep to retain it). pi, claude, and codex.

sesh delegate --agent codex "What is 2+2? Reply with just the number." sesh delegate --agent claude --keep --name audit "audit auth.go for bugs" # keep the session

- **`new --headless`** is for a child you'll converse with repeatedly;
  **`delegate`** is for "do this one thing and tell me the answer." Reach for
  delegate unless you need to follow up.
- `--headless` requires `--msg` (the first turn is what creates the on-disk
  session). **pi can't run headless** (it needs a live terminal to serve its
  rpc socket) — `new --headless --agent pi` errors; use `delegate --agent pi`
  (one-shot) or interactive `new --agent pi` instead. pi works fine with
  `delegate` because that's a single `pi -p` turn.
- **`--msg` also works for non-headless (tmux) spawns** — requires `--target`
  or a running `$TMUX` session. Waits for the agent to appear live in its pane,
  then delivers the message and prints the reply. Incompatible with `--no-launch`.
- delegate's worker runs read-only-ish (codex `--sandbox read-only`); it's
  meant to answer, not mutate your workspace unattended.
sesh delegate --agent codex "What is 2+2? Reply with just the number." sesh delegate --agent claude --keep --name audit "audit auth.go for bugs" # 保留会话

- **`new --headless`**适用于需要反复对话的子Agent;**`delegate`**适用于“完成这一项任务并返回结果”的场景。除非需要后续跟进,否则优先使用delegate。
- `--headless`需要配合`--msg`参数(第一轮交互会在磁盘上创建会话)。**pi无法以无头模式运行**(需要活跃终端来提供rpc套接字)——`new --headless --agent pi`会报错;请使用`delegate --agent pi`(一次性任务)或交互式`new --agent pi`。pi可以正常使用`delegate`,因为这是单次`pi -p`交互。
- **`--msg`也适用于非无头(tmux)启动**——需要`--target`参数或正在运行的`$TMUX`会话。等待Agent在窗格中变为活跃状态,然后发送消息并打印回复。与`--no-launch`参数不兼容。
- delegate的Worker以只读模式运行(codex使用`--sandbox read-only`);仅用于返回结果,不会无人值守地修改你的工作区。

Model selection —
--model
(set at launch)

模型选择——
--model
(启动时设置)

sesh new
and
sesh delegate
take
--model
to launch the agent with a specific model. It maps to each agent's own flag (
claude/codex/pi --model
; codex's
-m
), so use that agent's model names:
bash
sesh new --agent claude --model opus              # alias or full id (sonnet, opus, claude-opus-4-8)
sesh new --agent pi --model sonnet:high           # pi patterns: provider/id, alias, :<thinking>
sesh delegate --agent codex --model gpt-5.4 "…"   # codex model id
Defaults via
~/.sesh/config.toml
— set a default model per agent (with an optional global fallback) so you don't pass
--model
every time:
toml
[models]
default = "opus"          # fallback for any agent when it has no specific default
claude  = "opus"
codex   = "gpt-5.5"
pi      = "anthropic/claude-opus-4-7"
Precedence:
--model
flag >
[models].<agent>
>
[models].default
>
the agent's own built-in default (no flag passed).
--list-models
(pi) /
claude --help
/ codex docs enumerate valid names.
Scope notes:
  • This sets the model at the start of a session only. There is no command to change a running/existing session's model; switch it inside the agent (claude
    /model
    , codex/pi
    /model
    picker).
  • new --agent codex
    is unsupported regardless (no pre-assignable id), but
    delegate --agent codex --model …
    works.
Agent binary location via
[agents]
— override where sesh looks for each agent's CLI binary. By default sesh resolves
claude
/
codex
/
pi
against the daemon's PATH augmented with common version-manager shim dirs (mise/asdf,
~/.local/bin
,
~/.cargo/bin
, …). If your binary lives somewhere exotic — or the daemon's PATH lacks the shims dir holding it (the spawn-works / resume-fails asymmetry) — declare the path explicitly:
toml
[agents]
claude = "/opt/tools/claude"
codex  = "/home/me/.local/share/mise/shims/codex"
pi     = "/home/me/bin/pi"
Precedence:
[agents].<agent>
config path (if set and an executable file) > PATH/shim-dir heuristic >
loud not-found error. A configured path that is NOT an executable file is a loud error naming the path (no silent fallback) — fix or remove the override.
sesh new
sesh delegate
支持
--model
参数以指定Agent启动时使用的模型。该参数映射到各Agent自身的参数(
claude/codex/pi --model
;codex使用
-m
),因此请使用对应Agent支持的模型名称:
bash
sesh new --agent claude --model opus              # 别名或完整ID(sonnet、opus、claude-opus-4-8)
sesh new --agent pi --model sonnet:high           # pi的模型格式:provider/id、别名、:<thinking>
sesh delegate --agent codex --model gpt-5.4 "…"   # codex模型ID
通过
~/.sesh/config.toml
设置默认模型
——可为每个Agent设置默认模型(可选全局 fallback),无需每次都传递
--model
参数:
toml
[models]
default = "opus"          # 当Agent无特定默认模型时使用的全局 fallback
claude  = "opus"
codex   = "gpt-5.5"
pi      = "anthropic/claude-opus-4-7"
优先级:
--model
参数 >
[models].<agent>
配置 >
[models].default
配置 >
Agent自身的内置默认值(未传递参数时)。
--list-models
(pi)/
claude --help
/codex文档列出了所有有效模型名称。
范围说明:
  • 仅在会话启动时设置模型。没有命令可以修改正在运行/已存在会话的模型;请在Agent内部切换模型(claude使用
    /model
    ,codex/pi使用
    /model
    选择器)。
  • 无论如何
    new --agent codex
    都不被支持(无法预分配ID),但
    delegate --agent codex --model …
    可以正常工作。
通过
[agents]
配置Agent二进制文件路径
——覆盖sesh查找各Agent CLI二进制文件的位置。默认情况下,sesh会在守护进程的PATH中查找
claude
/
codex
/
pi
,并补充常见版本管理器的shim目录(mise/asdf、
~/.local/bin
~/.cargo/bin
等)。如果你的二进制文件位于特殊位置——或守护进程的PATH中缺少包含该文件的shim目录(启动正常但恢复失败的不对称问题)——请显式声明路径:
toml
[agents]
claude = "/opt/tools/claude"
codex  = "/home/me/.local/share/mise/shims/codex"
pi     = "/home/me/bin/pi"
优先级:
[agents].<agent>
配置的路径(如果已设置且为可执行文件) > PATH/shim目录启发式查找 >
明确的未找到错误。如果配置的路径不是可执行文件,会直接报错并显示该路径(无静默 fallback)——请修复或移除该配置。

Driving the agent

驱动Agent

bash
sesh send <uuid> <message>           # send a message and return the agent's reply (two-way; see below)
sesh send <uuid> <message> --no-wait # deliver only; don't await or print a reply
bash
sesh send <uuid> <message>           # 发送消息并返回Agent的回复(双向交互;参见下文)
sesh send <uuid> <message> --no-wait # 仅发送消息;不等待或打印回复

An empty/whitespace-only <message> is rejected up-front with "message is empty".

空消息或仅包含空白字符的消息会被直接拒绝,提示“message is empty”。

sesh await <uuid> [--timeout D] # block until the turn completes (busy → idle), print the status (D=0 means no limit; a negative D is rejected) sesh abort <uuid> # abort current operation (pi-only) sesh compact <uuid> # trigger context compaction (pi-only) sesh autoname <uuid> # auto-generate a name via
pi -p
sesh autoname --all # auto-name every nameable session in the mesh; un-nameable ones (no transcript yet) are skipped, the rest still named sesh autoname-toggle <uuid> [--on|--off]

`send`/`abort`/`compact` (and the mutations and transcript reads above) route
to the owning machine through the one owner-routing seam, so they work on a
session anywhere in the mesh (not just local).

**`send` is two-way for all three agents** — by default it blocks until the
agent finishes its turn and prints the reply. How the reply is obtained
depends on the agent and whether the session is live in a tmux pane:

- **pi** — delivered over its socket; returns the streamed reply (works even
  when detached/headless).
- **claude / codex, live in a pane (attached)** — the message is typed into
  the live pane (so a human watching sees it, and the conversation isn't
  forked), then `send` waits for the turn to finish and returns the last
  assistant message.
- **claude / codex, detached (no live pane)** — the session is resumed
  **headlessly** (`claude -p --resume` / `codex exec resume`) and the reply
  is returned. (codex runs read-only with no approval prompts; claude resume
  is cwd-scoped, so the session's recorded `cwd` must still exist.)

> Caveat (exp14): never headless-resume a claude/codex session that is also
> live in a pane — it forks the in-memory conversation. `sesh` avoids this
> automatically by typing into the pane whenever one is live; the headless
> path is taken only for detached sessions.

**`--no-wait`** makes `send` fire-and-forget: it delivers the message and
returns immediately without awaiting the turn or printing a reply (it still
errors if *delivery* fails). For a detached claude/codex this launches the
headless turn in the background, so turn-time errors are logged by the
daemon, not surfaced to the caller. Use it when you just want to nudge an
agent and not block.

**`await`** is a pure read on the mesh-synced `turnStatus`, so it works for a
session on any machine with no forwarding; an already-idle session returns
immediately. It's mostly useful for observing a turn you didn't start (a
human-driven session, or one nudged with `send --no-wait`) — a plain `send`
already waits. Caveat: if a human is also driving the session, `await`
returns on whichever turn finishes first. `--timeout 0` (the default) waits
forever; a *negative* `--timeout` is rejected with a clear error rather than
silently behaving like "no limit".

**`autoname --all`** auto-names every nameable non-archived session across the
mesh (renames forward to each owner). A session that can't be named yet — most
commonly a freshly-registered one with no transcript on disk — is *skipped*
(reported on stderr) and the rest are still named; the batch does not abort on
the first such session. Naming a single explicit `<uuid>` still surfaces its
error.
sesh await <uuid> [--timeout D] # 阻塞直到会话完成当前轮次(忙碌→空闲),打印状态(D=0表示无时间限制;负数D会被拒绝) sesh abort <uuid> # 中止当前操作(仅适用于pi) sesh compact <uuid> # 触发上下文压缩(仅适用于pi) sesh autoname <uuid> # 通过
pi -p
自动生成会话名称 sesh autoname --all # 为网格中所有可命名的会话自动生成名称;无法命名的会话(尚无转录内容)会被跳过,其余会话仍会被命名 sesh autoname-toggle <uuid> [--on|--off]

`send`/`abort`/`compact`(以及上文提到的修改操作和转录读取操作)通过单一源节点路由层转发到所属机器,因此可在网格中的任意机器上操作会话(不仅限于本地)。

**`send`对所有三种Agent都是双向交互**——默认情况下会阻塞直到Agent完成当前轮次并打印回复。获取回复的方式取决于Agent类型以及会话是否在tmux窗格中处于活跃状态:

- **pi**——通过其套接字传递;返回流式回复(即使会话处于分离/无头状态也能工作)。
- **claude / codex,且在窗格中活跃(已连接)**——消息会输入到活跃窗格中(因此人类观察者可以看到,对话不会分叉),然后`send`等待轮次完成并返回最后一条助手消息。
- **claude / codex,且处于分离状态(无活跃窗格)**——会话会以**无头模式**恢复(`claude -p --resume` / `codex exec resume`)并返回回复。(codex以只读模式运行,无确认提示;claude恢复操作基于工作目录,因此会话记录的`cwd`必须仍然存在。)

> 注意(exp14):永远不要以无头模式恢复同时在窗格中活跃的claude/codex会话——这会导致内存中的对话分叉。`sesh`会自动避免这种情况:只要存在活跃窗格,就会直接在窗格中输入消息;仅当会话处于分离状态时才会使用无头模式。

**`--no-wait`参数**让`send`成为“即发即弃”模式:发送消息后立即返回,不等待轮次完成或打印回复(如果**发送**失败仍会报错)。对于分离状态的claude/codex,这会在后台启动无头轮次,因此轮次执行过程中的错误会被守护进程记录到日志中,不会反馈给调用者。当你只想触发Agent操作而不想阻塞时使用该参数。

**`await`**是对网格同步的`turnStatus`的纯读取操作,因此可在任意机器上操作会话,无需转发;如果会话已处于空闲状态,会立即返回。该命令主要用于观察你未启动的轮次(人类驱动的会话,或通过`send --no-wait`触发的会话)——普通的`send`已经包含等待逻辑。注意:如果同时有人类在驱动会话,`await`会在任意一方完成轮次时返回。`--timeout 0`(默认值)表示无限等待;**负数**`--timeout`会被明确拒绝,而非静默视为“无时间限制”。

**`autoname --all`**为网格中所有可命名的未归档会话自动生成名称(重命名操作会转发到各源节点)。暂时无法命名的会话——最常见的是刚注册但磁盘上尚无转录内容的会话——会被**跳过**(在标准错误输出中报告),其余会话仍会被命名;批量操作不会因第一个无法命名的会话而中止。为单个明确的`<uuid>`命名仍会显示其错误。

Daemon & peers

守护进程与对等节点

bash
sesh daemon status [--json]    # machine, uptime, sessions, peers, schema version
sesh daemon start | stop | restart      # restart = the reliable way to pick up a redeployed binary
sesh daemon ensure             # idempotent start (supervisor entrypoint)
sesh peer ...                  # manage peer-daemon connections (~/.sesh/peers.json)
sesh doctor                    # diagnose agents/tmux/daemon/config
The daemon is normally supervised (supervisord/launchd on servers; a nohup leaf on termux). If supervised, restart via the supervisor, not
sesh daemon restart
, so they don't race.
sesh daemon start
(and the
start
half of
restart
) refuses with an error if a daemon is already running, rather than spawning a duplicate — so a stray manual start can't clobber the supervised instance (the guard is an exclusive flock on the pidfile, so even concurrent starts can't both win). If a background start FAILS, the client surfaces the daemon's real error (e.g. missing
SESH_MACHINE
) and captures its stderr to
~/.sesh/daemon.log
.
bash
sesh daemon status [--json]    # 机器信息、运行时间、会话数、对等节点数、架构版本
sesh daemon start | stop | restart      # 重启是获取重新部署的二进制文件的可靠方式
sesh daemon ensure             # 幂等启动(监控进程入口)
sesh peer ...                  # 管理对等守护进程连接(~/.sesh/peers.json)
sesh doctor                    # 诊断Agent/tmux/守护进程/配置
守护进程通常由监控进程管理(服务器上使用supervisord/launchd;Termux上使用nohup)。如果由监控进程管理,请通过监控进程重启,而非
sesh daemon restart
,避免竞争。
sesh daemon start
(以及
restart
中的启动步骤)如果检测到守护进程已在运行,会拒绝执行并报错,而非启动重复进程——因此意外的手动启动不会覆盖监控进程管理的实例(通过pid文件的独占锁实现,即使并发启动也不会同时成功)。如果后台启动失败,客户端会显示守护进程的真实错误(例如缺少
SESH_MACHINE
),并将标准错误输出捕获到
~/.sesh/daemon.log

Maintenance

维护操作

bash
sesh backup        # import transcripts into a single SQLite file (idempotent)
sesh restore       # reconstruct transcripts from a backup
sesh import        # one-shot import of v1 ~/.sesh/sessions.json
sesh copy <uuid> <dest>   # copy a session's transcript elsewhere (same-agent)
restore
notes:
  • --from <file>
    must point at an EXISTING backup; a missing/typo'd path errors
    no such backup file
    (it will not silently create an empty DB).
  • restore [uuid]
    accepts a full UUID or a short prefix (like
    copy
    ), resolved against the backup's stored transcripts; an unknown or ambiguous prefix is a loud error, not a silent no-op.
  • Default target is
    --to native
    (reconstruct at the agent's real path). Only claude has a deterministic native path; pi/codex filenames embed a timestamp, so a native restore skips them and reports them as "unsupported" (restore those with
    --to <dir>
    ). A mixed-agent backup still restores its claude entries — it does not abort partway.
copy
notes:
  • Cross-machine
    copy <uuid> --to <machine>
    restores
    --to native
    on the peer, so it only works for claude sessions; copying a pi/codex session cross-machine errors loudly up front (use
    --to-dir <dir>
    locally instead). A failed remote restore now propagates a nonzero exit (it no longer reports a false "copied" success).
sesh import
writes SQLite directly (the daemon normally owns writes), so it refuses with an error if a daemon is live on the socket — running it then would corrupt the daemon's in-memory origin-seq counter. Stop the daemon first (
sesh daemon stop
, or via your supervisor) and re-run. Pass
--force
only if you will restart the daemon immediately after (a restart re-seeds the counter from the new DB max).
bash
sesh backup        # 将转录内容导入到单个SQLite文件(幂等操作)
sesh restore       # 从备份文件重建转录内容
sesh import        # 一次性导入v1版本的~/.sesh/sessions.json
sesh copy <uuid> <dest>   # 将会话的转录内容复制到其他位置(同Agent类型)
restore
说明:
  • --from <file>
    必须指向已存在的备份文件;路径不存在或输入错误会报错“no such backup file”(不会静默创建空数据库)。
  • restore [uuid]
    接受完整UUID或短前缀(与
    copy
    相同),基于备份文件中存储的转录内容解析;未知或歧义前缀会明确报错,而非静默无操作。
  • 默认目标是
    --to native
    (在Agent的真实路径重建)。只有claude拥有确定的原生路径;pi/codex的文件名包含时间戳,因此原生恢复会跳过这些会话并报告“unsupported”(请使用
    --to <dir>
    恢复)。包含多种Agent的备份文件仍会恢复其中的claude会话——不会中途中止。
copy
说明:
  • 跨机器
    copy <uuid> --to <machine>
    会在对等节点上执行
    --to native
    恢复,因此仅适用于claude会话;跨机器复制pi/codex会话会直接报错(请在本地使用
    --to-dir <dir>
    )。远程恢复失败现在会返回非零退出码(不再错误报告“copied”成功)。
sesh import
直接写入SQLite(通常守护进程拥有写入权限),因此如果套接字上有活跃的守护进程,会拒绝执行并报错——此时执行会破坏守护进程的内存中origin-seq计数器。请先停止守护进程(
sesh daemon stop
,或通过监控进程),然后重新运行。仅当你会在导入后立即重启守护进程时才使用
--force
参数(重启会从新数据库的最大值重新初始化计数器)。

Common flags & environment

通用参数与环境变量

  • Global flags:
    --machine <name>
    (target a machine; default all/local),
    --json
    (machine-readable),
    --socket <path>
    (daemon socket, default
    ~/.sesh/daemon.sock
    ).
  • new
    /
    delegate
    flags:
    --model <name>
    (launch model; see "Model selection") among the per-command flags above.
  • Config:
    ~/.sesh/config.toml
    [models]
    sets default launch models and
    [agents]
    overrides each agent binary's path (both under "Model selection"). The mesh/peers live in
    ~/.sesh/peers.json
    , not here.
  • Env:
    SESH_HOME
    (state dir, default
    ~/.sesh
    ),
    SESH_MACHINE
    (origin identity — required; the daemon refuses to start without it, no hostname fallback),
    SESH_TMUX_SOCKETS
    (override walker socket discovery),
    SESH_CWD_FORMATTER
    (a command to relabel the TUI cwd column).
  • Exit codes for the picker (
    pick
    /
    tui
    ):
    0
    selected,
    130
    cancelled,
    3
    nothing to select.
  • 全局参数:
    --machine <name>
    (目标机器;默认所有/本地)、
    --json
    (机器可读格式)、
    --socket <path>
    (守护进程套接字,默认
    ~/.sesh/daemon.sock
    )。
  • new
    /
    delegate
    参数:
    --model <name>
    (启动模型;参见“模型选择”),以及上文提到的各命令专属参数。
  • 配置:
    ~/.sesh/config.toml
    中的
    [models]
    设置默认启动模型,
    [agents]
    覆盖各Agent二进制文件的路径(均在“模型选择”部分说明)。网格/对等节点信息存储在
    ~/.sesh/peers.json
    中,不在此配置文件中。
  • 环境变量:
    SESH_HOME
    (状态目录,默认
    ~/.sesh
    )、
    SESH_MACHINE
    (源节点标识——必填;守护进程启动时必须设置,无主机名 fallback)、
    SESH_TMUX_SOCKETS
    (覆盖遍历器的套接字发现逻辑)、
    SESH_CWD_FORMATTER
    (用于重新标记TUI工作目录列的命令)。
  • 选择器(
    pick
    /
    tui
    )的退出码:
    0
    已选择、
    130
    已取消、
    3
    无可选内容。

Picker emit contract

选择器输出约定

pick
/
tui
(without
--enter
) print the selection on stdout as
--format json
(default),
nul
, or
kv
. JSON fields:
action
(goto|resume),
uuid
,
machine
,
agent
,
cwd
,
name
, and
tmux
(
socket
/
session
/
window
/
pane
). A wrapper reads this and navigates.
action
is auto-derived from the row's liveness —
goto
for a live session (has a tmux pane),
resume
for a detached one — consistently for both
pick
and
tui
. Pass
--action <verb>
to override it (e.g.
send
).
--cursor <uuid>
on
tui
pre-positions the highlight on a row (full UUID or a short prefix, like every other
<uuid>
arg); an unresolvable prefix is a loud error, not a silent no-op.
pick
/
tui
(不带
--enter
参数)会在标准输出打印选择结果,格式为
--format json
(默认)、
nul
kv
。JSON字段:
action
(goto|resume)、
uuid
machine
agent
cwd
name
以及
tmux
socket
/
session
/
window
/
pane
)。包装脚本可读取该输出并实现导航。
action
由行的活跃状态自动推导——活跃会话(有tmux窗格)为
goto
,分离会话为
resume
——
pick
tui
的推导逻辑一致。可通过
--action <verb>
参数覆盖(例如
send
)。
tui
--cursor <uuid>
参数可将高亮光标预定位到指定行(接受完整UUID或短前缀,与其他
<uuid>
参数相同);无法解析的前缀会明确报错,而非静默无操作。