Skip to content

Sessions: picking up where you left off

A session is a stream of work you can come back to, like a cloud Claude session: the agent's conversation and the repo state are kept; the sandbox is not. Design: spec 0010.

# Monday
hangar session new onboarding "build the onboarding flow; start with the signup form" -e early-signal -w
hangar session send onboarding "use the existing Button component" -w

# ...30 idle minutes later hangar checkpoints it and releases the sandbox (costs storage only)...

# Wednesday
hangar session list
hangar session send onboarding "now add the email verification step" -w   # boots, restores, resumes the conversation

What is kept

Kept How
The agent's conversation (Claude Code, Codex, pi) The harness's own session files; the next turn runs claude --resume <id> / codex exec resume <id> / pi --session-id <id>
Commits on the session branch (hangar/session/<name>, or a custom branch) A git bundle, even if nothing was pushed
Uncommitted changes and untracked files A binary diff and a tarball (respects .gitignore)
Not kept: running processes (dev servers, tmux windows), ignored files such as .venv/node_modules They are rebuilt by the environment

Checkpoints are taken:

  • after every agent turn;
  • every 10 minutes while something changes;
  • when the session suspends;
  • before its sandbox is destroyed for any reason, including expiry.

Checkpoints are encrypted with the vault key.

All four agents resume their own conversation: Claude Code, Codex, pi and Antigravity (agy --conversation <id>). If you switch a session to a different agent, the next prompt starts with a short account of the earlier turns instead (a handoff).

Staying open while you work

A session never suspends while it's in use. Any of these keeps it up:

  • an agent turn running, or any agent run started in its sandbox (run_agent) that hasn't finished;
  • a terminal open on it (dashboard or hangar sb attach);
  • anything using the sandbox through hangar: commands (for their whole run), files, reading terminals, following an agent.

A job's session is held for the whole turn, delivery included, and across a control-plane restart until the job picks it up again.

It suspends only after it has been idle for its idle time: 30 minutes by default. To change that:

hangar session keep onboarding --idle 240   # four hours
hangar session keep onboarding --idle 0     # stay up until I suspend it

Commands

CLI MCP What it does
hangar session new NAME [MESSAGE] -e ENV [--repo URL] new_session Start a session (and a first turn, given a message)
hangar session list list_sessions Streams of work, most recently active first
hangar session send NAME MESSAGE send_to_session Continue: resumes the session if suspended, then runs a turn
hangar session open NAME open_session Boot and restore without running the agent: work in the sandbox yourself
hangar session keep NAME --idle MIN keep_session Idle time before suspending (0 = never)
hangar session suspend NAME suspend_session Checkpoint and release the sandbox now
hangar session get NAME get_session Turns, summaries, checkpoints, and resume_command
hangar session archive NAME Drop the checkpoints (the record stays)
hangar session events NAME [--follow] get_events What the agent did: messages, commands, file changes, errors, usage (activity)
hangar session new NAME MESSAGE --from-local new_session(context=…) Continue your local checkout in the cloud: its unpushed commits and uncommitted changes go with the first turn
--file PATH, --text TEXT, --schema FILE on new and send context, output_schema Attachments, and a JSON Schema for a structured result
wait_for_turn Block until the turn ends, with progress notifications; returns result, question, artifacts
hangar session artifacts NAME [--get PATH] get_artifact Files the agent handed back
hangar session patch NAME get_session_patch The session's work as one patch against its base
hangar session pull NAME [--checkout] Its commits onto local branch hangar/NAME, plus (with --checkout) its uncommitted changes
hangar session fork NAME [MESSAGE] -n N fork_session Branch it into N sessions (forks)
hangar session steer NAME MESSAGE (or send) steer_turn Tell the running agent something; it reads it at its next step (steering)
hangar session interrupt NAME [MESSAGE] steer_turn(interrupt=true) Stop the running turn, or stop and carry on with a new message
hangar session approvals NAME [--allow ID \| --deny ID] answer_approval Tool calls the agent waits on under --approvals ask

hangar session new takes a per-turn budget (--max-cost, --max-tokens, --max-minutes; budget in the API). A turn that crosses it is stopped with outcome over_budget. get shows each turn's usage and the session's total.

If the agent asks a question (hangar-agent ask), the turn ends as needs_input and the session shows it in needs_input; your next send answers it. How context moves in and out of a session is in context exchange.

In the dashboard, the Sessions page does all of this:

  • Resume a session;
  • message the agent;
  • Talk to the agent here, which opens a terminal in the agent's own conversation;
  • open a shell;
  • set the idle time.

To work alongside the agent interactively from a terminal:

  1. Open the session and attach to its sandbox: hangar sb attach <sandbox_id>.
  2. Run the resume_command that get shows, for example claude --resume 3f2a…. You're now in the same conversation the agent had.

Thawed from a harness lock

hangar harness thaw team-default@r14 --env python "fix the flaky test" (or harness_lock on POST /api/sessions) starts a session from a harness lock: the lock's harness, its concrete model and its approval mode, on the CLI version harnesses.lock.yaml pins (a lock on another version is refused, with what to do). Its turn 1 is checked against the lock; SessionTurn.drift lists what differed ([]: nothing), with a harness.drift event and a warning on the turn. Under HANGAR_HARNESS_DRIFT=fail turn 1 stops with outcome failed, reason harness_drift. Later turns aren't checked: what the agent changes is its behaviour. A thawed session can't switch harness; start another session for another lock.

Settings

Variable Default
HANGAR_FORK_MAX 8 Most forks per fork_session call
HANGAR_CACHE auto Prompt-cache TTL (auto, 5m, 1h, off) when neither the session nor its environment sets one
HANGAR_CACHE_STAGGER_SECONDS 15 How long best-of-N attempts and forks hold back for the first sibling to answer (0 = no wait)
HANGAR_SESSION_IDLE_MINUTES 30 Suspend after this long idle (0 = never); per session with --idle
HANGAR_SESSION_CHECKPOINT_MINUTES 10 Periodic checkpoint while changed
HANGAR_SESSION_KEEP_CHECKPOINTS 5 Per session
HANGAR_SESSION_MAX_UNTRACKED_MB / _MAX_PART_MB 20 / 100 Larger parts are skipped with a warning
HANGAR_SESSION_TURN_TIMEOUT_MINUTES 120
HANGAR_HARNESS_REPO, HANGAR_HARNESS_DRIFT unset, warn Sessions thawed from a harness lock (below)
HANGAR_SESSION_STORE data volume gs://bucket[/prefix] for durable checkpoints on GKE (terraform output session_bucket)

Cost and speed

  • Suspended session: a few MB on the control plane's volume.
  • Resume: a sandbox start plus the restore (seconds for typical sizes). That's about 10 s from a warm pool, or 30–60 s cold when the image is built and a node is up.
  • Keeping a sandbox running overnight instead: it pins a sandbox node, roughly $280/month on demand for an n2-standard-8.
  • Faster cold starts on GKE (opt-in, recreates the sandbox nodes): terraform image_streaming = true starts pods before the image is fully pulled, and sandbox_disk_gb = 100 lets more nodes fit the default 500 GB SSD quota. Suspend sessions before applying; they resume from their checkpoints.
  • Durability: with HANGAR_SESSION_STORE=gs://…, checkpoints survive the control plane's disk. Uploads retry on throttling and server errors. The bucket has no age-based deletion unless you set session_retention_days.

Moved from this page

Section Now on
Forks and best-of-N Forks and best-of-N
Fork at a step Forks and best-of-N
Prompt caching Prompt caching in sessions
TTL policy Prompt caching in sessions
One model per session Prompt caching in sessions
Best-of-N and forks share one cache write Prompt caching in sessions
Keeping the cache warm: not done Prompt caching in sessions