pi-cutlery
v0.4.0
Published
Multi-session workflow toolbox for Pi, centered on session forking
Maintainers
Readme
pi-cutlery
Multi-session workflow tools for Pi.
Use it when plain Pi sessions are not enough and you want repeatable fork, move, and pane-backed child-session workflows.
pi-cutlery adds a workflow layer around Pi sessions:
- startup forking with
--fork-session - live session forking with
/forkpiandfork_pi - live session relocation with
/move - managed named child Pis with
/piandspawn_pi - managed Pi discovery and follow-up messaging with
/pisand/tell - tmux resurrect metadata handoff for tmux-backed flows
install
npm:
pi install npm:pi-cutlerygit:
pi install git:github.com/lajarre/pi-cutlerylocal path:
pi install /path/to/pi-cutlerylocal project install:
pi install -l /path/to/pi-cutleryRestart Pi after install.
For most users, install from npm. Use git or a local path when you want to track or modify the package itself.
surface map
| surface | kind | purpose |
|---|---|---|
| --fork-session <id-prefix> | startup flag | start Pi by forking another persisted session first |
| /forkpi [suffix] [v\|h] | command | fork the current live session into an adjacent pane/surface via tmux or cmux |
| fork_pi { suffix?, split? } | tool | tool form of /forkpi; requires tmux or cmux |
| /move <targetCwd> | command | move the current session to another cwd and relaunch Pi there |
| /pi [suffix] [v\|h] | command | spawn a managed named Pi in an adjacent pane/surface via tmux or cmux |
| spawn_pi { suffix?, split? } | tool | tool form of /pi; requires tmux or cmux |
| /pis | command | list known managed Pis from the local registry |
| /tell <target> <message> | command | send a follow-up message to a managed Pi via session-control |
quick examples
Startup fork by full UUID or unique leading prefix:
pi --fork-session <session-id>
pi --fork-session 7649c823
pi --session-control --fork-session 7649c823 "continue from here"Fork the current live session into an adjacent pane/surface:
/forkpi
/forkpi api
/forkpi api hMove the current session to another directory and relaunch there:
/move ../other-worktree
/move ~/src/other-repoSpawn a managed named Pi:
/pi
/pi api
/pi api hList or message managed Pis:
/pis
/tell api "run a focused experiment"
/tell 1 "summarize the findings"Agent-callable forms:
tool: fork_pi
tool: spawn_pichoosing the right surface
1. startup fork: --fork-session
Use --fork-session when you are starting a new Pi process and want its initial session file to be a fork of an existing persisted session.
Properties:
- works before the interactive session starts
- does not require tmux
- resolves the source by full UUID or unique leading prefix
- re-execs Pi on the forked session file with
--session <fork-path> - leaves the source session file unchanged
- keeps the rest of the CLI arguments except the consumed
--fork-session <id>pair
Conflict rules:
- cannot combine with
--session,--continue,--resume,--no-session, or--mode rpc|json - bypasses itself for help/version and Pi management subcommands such as
install,remove,update,list, andconfig
Resolution rules:
- look in the current cwd/session-dir scope first
- prefer a unique match whose
session.cwd === process.cwd() - if there is no local match and no Pi
--session-diroverride, fall back to global listing - fail clearly on no match or ambiguous match
When --session-control is also present and the source session has a name, cutlery derives a non-conflicting fork name such as <source>-fork1 before re-exec.
2. common pane-spawn contract
/forkpi, fork_pi, /pi, and spawn_pi share the same pane-launch contract:
- require tmux or cmux
- select the pane backend with precedence
tmux > cmux - fail clearly if neither backend is available, and do not fall through to cmux when tmux is selected but unusable
- materialize the child session in the parent after a backend is confirmed and before the pane/surface launch
- create the target pane/surface through the selected backend
- on tmux only, stamp the target pane with the child session UUID before launch
- launch the child with
pi --session <session-file> --session-control - emit a visible parent-side
cutlery:spawn-reportbefore focus moves to the child pane/surface - use native cmux commands on cmux launches rather than tmux-compat shims
- default to vertical split; pass
hfor a horizontal split
If tmux metadata handoff fails, cutlery stops before child launch.
Compatibility note: paneId remains the shared field name in reports and tool details. On tmux it is a tmux pane id; on cmux it may temporarily carry a cmux surface ref.
3. forking the current session: /forkpi and fork_pi
Use these when you are already inside Pi and want a neighboring pane with copied conversation state.
Requirements:
- tmux or cmux is available in the parent environment
- current session has a name via
/name <name> - current session file is persisted
- current session contains forkable entries
Naming behavior:
- default names are
<name>:fork1,<name>:fork2, and so on - explicit suffixes become
<name>:<suffix>after sanitization - collision checks include stored session names and existing session-control alias files
- explicit suffix collisions fail clearly instead of silently renaming the fork
Tool behavior:
fork_piaccepts{ suffix?: string, split?: "v" | "h" }- tool results include the spawned child session id in
details
4. moving the current session: /move
Use /move when the current session belongs under a different cwd bucket and you want Pi relaunched there on a moved copy of the session.
Properties:
- works inside or outside tmux
- requires a target directory argument
- requires a persisted current session
- normalizes
~and relative paths against the current session cwd - rejects missing paths and non-directories before forking
- forks the current session file into the target cwd
- clears the forked header's
parentSessionfield so the moved session does not keep stale fork ancestry - relaunches with
pi --session <moved-session-file>
/move replaces the current Pi process. Old-session cleanup is best-effort only, tmux-gated when relevant, and never hard-deletes the source file.
5. managed named Pis: /pi, spawn_pi, /pis, /tell
Use the managed-Pi family when you want fresh child Pis that are easy to address later.
This is distinct from /forkpi:
/forkpicopies current conversation state into a sibling pane/picreates a fresh child session and gives it a durable managed name plus registry entry
/pi and spawn_pi
Requirements:
- tmux or cmux is available in the parent environment
- parent session has a name via
/name <name>
Naming behavior:
- the namespace is captured from the parent session name when spawn state is first created
- default names are
<namespace>:wrkr-<n> - explicit suffixes become
<namespace>:<suffix>after sanitization - slot numbers continue increasing even when a custom suffix is used
Tool contract:
spawn_piaccepts{ suffix?: string, split?: "v" | "h" }- success keeps backward-compatible
ok: truedetails - success details also include cutlery-owned identity fields:
sessionIdsessionFilesessionNamepaneId(compatibility field name; may hold a cmux surface ref)
- failures keep
ok: falsepluserror
/pis
/pis lists the known managed-Pi registry.
Behavior:
- current namespace entries are shown first when state exists
- older entries from other namespaces remain visible
- registry entries include the compatibility
paneIdvalue, slot, and age - if no Pis are known, cutlery tells you to run
/pi
/tell
/tell sends a follow-up message to a managed Pi over session-control.
Resolution order:
- exact managed Pi name
wrkr-<n>- numeric slot
n
Delivery behavior:
- prefers the child
sessionIdwhen available - falls back to the older name-based path for legacy registry entries
- validates routing into the target child session
- does not forward child replies back into the parent session
- returns a fallback shell command when the bridge call fails
architecture
pi-cutlery is organized around one startup preflight path, one shared pane launcher with tmux > cmux backend selection, one move/relaunch path, one managed-worker state layer, and one tmux metadata helper.
architecture schematic
flowchart TD
User([user command or tool call])
ForkFlag([--fork-session])
ForkPi([/forkpi or fork_pi])
SpawnPi([/pi or spawn_pi])
Move([/move])
Tell([/tell or /pis])
User --> ForkFlag
User --> ForkPi
User --> SpawnPi
User --> Move
User --> Tell
ForkFlag --> Preflight([fork-session preflight])
ForkPi --> Launcher([shared pane launcher (tmux > cmux)])
SpawnPi --> Launcher
Move --> MovePath([move and relaunch path])
Tell --> Registry([managed worker registry])
Launcher --> Materialize([parent-side session materialization])
Launcher --> Metadata([tmux metadata helper (tmux only)])
Launcher --> Report([parent-side spawn report])
Launcher --> Focus([child pane/surface focus])
MovePath --> Metadata
MovePath --> Relaunch([pi --session moved-session-file])
Metadata --> PaneOption([resurrect metadata pane option])
Metadata --> PaneTitle([cosmetic pane title])
SpawnPi --> ManagedState([naming state plus managed child metadata])
ManagedState --> Registry
Registry --> Bridge([session-control bridge])
Tell --> Bridgelauncher contract
For pane launches, cutlery does this in order:
- confirm a supported pane backend with precedence
tmux > cmux - materialize the child session in the parent
- create the target pane/surface
- on tmux only, write
@resurrect-metadata-pi-session=<child-uuid>onto that pane as tmux resurrect metadata - best-effort update the tmux pane title
- send
pi --session <session-file> --session-controlinto the pane/surface - emit the parent-side
cutlery:spawn-reportmessage - focus the child pane/surface
cmux launches use native cmux new-split, cmux send, cmux focus-pane, and best-effort cmux close-surface commands rather than tmux-compat shims.
cmux surface lifecycle
cmux distinguishes surfaces from panes. Cutlery creates and sends input to the child surface, but focuses the owning pane. The launcher therefore keeps two cmux handles for successful cmux launches:
- caller context: stable workspace and caller-surface refs derived from
CMUX_WORKSPACE_IDandCMUX_SURFACE_ID - child surface ref: returned by
cmux new-split - child pane ref: resolved with
cmux identifyagainst the child surface and used for final focus
When the env-provided cmux handles are UUIDs or order-sensitive numeric indexes, cutlery resolves them through cmux --id-format both tree --all --json before creating the child surface. If that resolution is required and fails, launch fails instead of reusing unstable indexes.
sequenceDiagram
participant Parent as parent Pi session
participant Backend as selectPaneBackend
participant Cmux as cmux CLI
participant Child as child Pi surface
Parent->>Backend: read CMUX_WORKSPACE_ID and CMUX_SURFACE_ID
alt env IDs need stable refs
Backend->>Cmux: cmux --id-format both tree --all --json
Cmux-->>Backend: workspace:<n> and surface:<n>
else env already stable refs
Backend-->>Parent: use caller context as-is
end
Parent->>Parent: materialize child session file
Parent->>Cmux: new-split right/down --workspace <workspace> --surface <caller>
Cmux-->>Parent: child surface ref
Parent->>Cmux: identify --workspace <workspace> --surface <child-surface>
Cmux-->>Parent: child pane ref
Parent->>Cmux: send --workspace <workspace> --surface <child-surface> "pi --session ...\n"
Parent->>Parent: emit cutlery:spawn-report
Parent->>Cmux: focus-pane --pane <child-pane> --workspace <workspace>
Cmux-->>Child: child surface receives focus
Note over Parent,Cmux: Before report success, identify/send/report failures close the child surface and keep the session file for recovery.For restore correctness, the tmux pane metadata option is authoritative. Pane titles are cosmetic only.
prerequisites and limits
Prerequisites:
- Pi with package/extension support
- tmux or cmux for
/forkpi,fork_pi,/pi, andspawn_pi - when both are present, pane launching uses
tmux > cmux - a persisted current session for
/forkpiand/move - a parent session name for
/piandspawn_pi - an existing persisted session id for
--fork-session
Current limits:
- pane-launch surfaces fail clearly outside tmux or cmux; there is no non-pane fallback
- there is no message-level fork primitive
- there is no session browsing UI
- this package does not replace Pi's session-control API; it builds on it
provenance and licensing
pi-cutlery is MIT-licensed.
Adapted third-party sources:
move-session.tsis adapted fromdot314/extensions/move-session.tssrc/move-session/normalize-target-cwd.tsis adapted fromdot314/extensions/_shared/normalize-target-cwd.ts- upstream repository:
w-winter/dot314 - upstream license: MIT
First-party provenance:
/pi,/pis,/tell, andspawn_piare adapted frompi-extensions/spawn-worker.ts- cutlery keeps that provenance in code comments and docs while owning the runtime surface locally
For shipped notice text, see THIRD-PARTY-NOTICES.md.
Deeper design history lives under doc/feature/. Those feature folders intentionally keep durable specs and summaries alongside archival planning and review artifacts.
