06 — Sessions
The state model. Every interaction with the agent is a session. Sessions persist, resume, fork, and replay. The CLI and the Mac app read the same session store on this Mac. Attach to a running Mac thread from the terminal. Optional account sync lets you read a session on another device and continue it there as a new session. Branch a session to explore an alternate approach. Replay sessions as a debugging tool or for sharing with teammates.
Session model
A session (a *thread* in the Mac app) is one conversation with the agent in one folder, stored as an event log. picasso list and picasso search <query> find sessions; picasso resume [id], picasso -c and picasso --resume <id> reopen one with its full history; picasso fork [id] branches one; picasso replay <id> prints its events as JSON lines; picasso share [id] writes or revokes a redacted share file. In the TUI: /sessions, /continue, /search, /fork, /undo, /rewind [files|chat|both] [turn], /replay, /share, /export.
- A worktree per thread. In a git repo a new thread runs in its own git worktree by default (setting
worktreeDefault:neworcurrent;--worktree new|current|<path>per run). The Mac chip row reads "New worktree (default)" or "Current checkout", and you can pick an existing worktree. - Fork, undo and rewind say where you are.
/forkanswers "You're now in the fork; the original is unchanged. Back to the original: /continue <id8>"; forks and the turn after an/undokeep the session's permission mode. - Goal sessions are titled by their objective and show "Goal round N of M" cards, live and on resume.
- Mode locks after the first turn in the Mac app; "New thread in <mode>" starts a fresh one in another mode.
Inbox zero and archive
Threads group by what they need from you: Needs you (an approval or a question is waiting), Working (a turn is running) and Settled (folded by default). Mac sidebar rows carry a badge (Approval, Input, Done, Working Nm, or the age). The TUI resume picker groups the same way, with a Recent group between Working and Settled.
Archive is one click with Undo: ⌘⌫ archives and ⌘Z brings it back, ⌥⌘⌫ deletes, on the Mac; e archives and u undoes in the TUI picker. The thread header shows a "project / title" breadcrumb; clicking the project opens Threads narrowed to it ("Show all projects" clears it).
The librarian
Threads started without a project are filed into the right project after their first turns by one subagent, the librarian. It has its own daily token budget (when spent it waits until local midnight), can be paused, and can be asked to look at every thread without a project. It shows what it will look at next and what it filed recently.
| Surface | How | ||||
|---|---|---|---|---|---|
| Mac | The Librarian page (sidebar or ⌘K): Pause, Look at everything, Next / Recent. | ||||
| TUI | `/librarian [pause \ | resume \ | look-all \ | budget <tokens>]` | |
| CLI | `picasso librarian status\ | pause\ | resume\ | look-all\ | budget <tokens> [--json] (for example picasso librarian budget 300k`) |
The librarian runs inside a running engine (the Mac app or an open TUI); the CLI commands read and change its shared state.
My Work
My Work lists the files your sessions made or presented, newest first, and starts a similar one ("Make another like this: <name>").
- Mac: the My Work page (sidebar or ⌘K), and Make a similar one in an artifact card's ⋯ menu and the Artifacts tab.
- TUI:
/work [--project <folder>|here] [--type <type>] [--page <n>], then/work open <n>,/work copy <n>or/work similar <n> [prompt]. - CLI:
picasso work list [--project <folder>] [--type <type>] [--limit <n>] [--offset <n>] [--json]andpicasso work similar <artifact> [--prompt <text>] [--model <id>] [--provider <route>] [--permission-mode <mode>] [--dry-run].
Context timeline
What entered a thread's context, turn by turn: the additions each turn made, compaction, per-step cache hit or miss, and subagent lanes. It reads the session log only (no engine start, no model call); missing data reads "No usage reported" or "Size not recorded" rather than a guess.
- Mac: the Context tab's Overview / Timeline switch.
- TUI:
/context timeline. - CLI:
picasso context timeline [thread] [--last] [--json].
Pull request wake-ups
picasso pr watch <pr> (a number, owner/repo#N or a URL) watches a pull request for a session; one combined update wakes the thread when checks finish, a review arrives or the branch conflicts. picasso pr status lists what a session watches. In the TUI, /pr watch <n> and /pr unwatch <n>.
Keeping threads running
With Settings › General › "Keep threads running when Picasso quits" (Mac, off by default) or picasso service install (CLI, macOS), a resident runner (a LaunchAgent) keeps running turns and schedules going after the app or terminal closes. It restarts only at a quiet moment and refuses to start, saying why in Settings › General, when a plugin or identity check fails. picasso service status shows its pid and engine version; picasso service uninstall removes it. Schedules are described in 09-hooks-and-commands.md.
Importing history
picasso import [claude|codex|opencode|all] [--dry-run] [--status] [--json], /import and Settings › Import bring past Claude Code, Codex and OpenCode sessions in as read-only threads. See history-import.md.
Shared on one Mac
- The CLI, the TUI and the Mac app's engine all use the OS account's real
~/.picassoand the engine home inside it,~/.picasso/dsh-home, which holds the engine's session store (the Mac app is not sandboxed). A session started in either surface shows up in the other. picasso listincludes sessions that exist only in the engine store (for example ones the Mac app created);--jsonprints asurfacefield for each row (runtimefor those engine-only rows).- One writer at a time: resuming a session another process is writing fails with
SessionLeaseHeldErrorinstead of interleaving two writers. Index writes go through the shared file lock (@picasso/shared-home/lock).
Attach to a running Mac thread
While Picasso for Mac is running, picasso attach --mac reads the discovery file ~/.picasso/run/mac-helper.json (0600) and joins a running thread over the app's loopback relay: it streams the thread's events, sends prompts, cancels, and answers approvals and questions. The file carries a per-launch local-attach token that works only from loopback and only on the thread and interaction routes; it cannot create threads or grant "always allow". Turning off Settings › Engine › "Allow terminal attach" in the Mac app stops the file from being written. Nothing is synthesized when the app is not running: the command says so and exits. See docs/mac-relay.md §2b–2c.
Optional account sync
- Off by default. Turn it on with
picasso settings set sync.cloudSessions on(the sharedsettings.sync.cloudSessionsflag in~/.picasso/settings/settings.json). It needs a signed-in account; signed out, sync is skipped. - When it is on, the CLI uploads the session's events after each run (
PUT /v1/sessions/:id/sync), and the Mac app uploads a session each time a turn finishes. An upload failure is recorded (acloud-session-sync-failedsession event in the CLI, the last-upload line in Settings on the Mac) and never fails the run. - Merging is by event identity: the server keeps the union of events keyed by
(deviceId, seq), under a row lock. If two devices continued the same session from the same point, the second device's divergent tail is kept as a fork with id<id>-fork-<dev4>(the first four alphanumeric characters of its device id) instead of being interleaved. - Another signed-in machine with cloud sync on can list, read and continue the account's synced sessions. List them with
picasso session list --cloud(GET /v1/sessions). Read one withpicasso session cloud show <id>, which prints the redacted transcript (GET /v1/sessions/:id, owner-only; another account gets 404). Continue one withpicasso session cloud continue <id> [prompt]. That starts a new local session in the current folder: its first turn carries the transcript, and acloud-session-importedevent recordsforkedFrom: <id>. The other machine's engine log is never copied. On the Mac, Settings › General › Synced sessions has the toggle ("Sync sessions to your account"), the list, a read-only View for each session, and Continue here, which opens the new thread. - Continue here refuses a transcript it can't carry over exactly, and nothing is created. That covers a missing event, a session two machines changed from the same point, a message without text, no conversation, or more than 200,000 characters. Such a session can still be read.
- Synced session events travel over TLS and are stored by the API on the account; unlike synced memory, they are not end-to-end encrypted.
Runtime note
The Picasso session store persists LoopEvent-derived session events from the engine adapter, and the Picasso session id is the engine's session id. See architecture.