Skip to content

[design] A coding session is a cache, not a thing to manage — stop asking the user to start one, and decide resume-vs-fresh #408

Description

@serge-ivo

The question

"Why do I need to press that button? Why can't it just be on forever? What even IS a session?"

Three fair questions, and the answers split cleanly into one thing with a real justification and two
without. This is the redesign; #407 is the one-call fix that should land first regardless.

What a session is, and the fact that decides the design

A session is a coding_sessions row plus a live child process on the owner's machine — the
claude CLI, spawned by the runner (HeadlessSession). Not tmux: a tmux server owns its sessions
and nothing reaps them, which is why they last forever and this does not.

The decisive fact: the engine's conversation is not in the process. Claude Code persists it to
~/.claude, and the runner re-spawns with --resume <session_id> (coding/headless.ts:45,331,363).
So a reaped session loses a process, not a memory. Re-opening restores the conversation.

That single property is what makes the current model wrong. If ending a session destroyed the work,
asking the user to manage it deliberately would be defensible. It doesn't — so the session is a
cache, and the user is being asked to manage a cache.

Keep exactly one thing

The idle reap. coding-session-sweeper.ts:63, 6 hours untouched. Its header states the cost it
prevents and the cost is real: a claude --dangerously-skip-permissions child resident forever, one
per repo, on someone's laptop. Six idle hours is generous and interaction of any kind resets it.
Not proposing to change it.

Drop two

1. The user starting sessions. ensureActiveSession already reuses / re-attaches / opens /
explains-why-not, and has exactly one caller — the Loop (#407). Every path that needs a session
should ensure one. A "Start session" button in the primary flow is the platform asking the user to
do something it can do better.

2. The user knowing sessions exist. The mental model should be repos, which are what the
owner actually chose and configured. A session becomes an implementation detail, visible only in the
🩺 diagnostics panel where it already lives. Reaping becomes invisible — the next request re-opens
and resumes.

The real cost, and the decision this ticket needs

Making resume automatic and unbounded reintroduces, in a different place, the thing the reap was
built to prevent. Today the reap is the only event that ever resets an engine's context; if every
path silently resumes, a repo's engine conversation grows for weeks, and every turn re-sends it. The
symptom moves from "a process on your laptop" to "a slow, expensive first message", which is
harder to see and paid per token.

The coding_session_fresh MCP tool exists, so the distinction is already understood — it just is not
policy.

Decide: when does an auto-opened session resume, and when does it start fresh?
Candidates, and I would take the second:

  • always resume — simplest, unbounded growth;
  • resume within N days of last activity, otherwise fresh — bounded, and the boundary is the same
    idleness the reaper already measures;
  • resume only when the reap was the reason it ended (a runner restart / laptop sleep is a different
    event from six hours of nobody caring).

Whatever is chosen must be stated to the user on the turn it happens — "resumed where we left
off" vs "started fresh; the previous conversation was N days old" is exactly the kind of fact that,
left unsaid, produces a bug report about an agent that "forgot everything".

Do

Acceptance

  • A user can go from "subscribed, repo added" to "asking about the terminal" without ever
    learning what a session is.
  • Six idle hours still reaps; the next question still works.
  • The reply says whether it resumed or started fresh, and why.
  • With the runner offline, nothing is created and the answer names the real problem.

Files: lib/coding-session-open.ts:102, lib/coding-session-sweeper.ts:63,
lib/storage-tools.ts:637,682, lib/loop-drivers.ts:181,
packages/browser-runner/src/coding/headless.ts:331-400. Supersedes nothing; extends #407.

Metadata

Metadata

Assignees

No one assigned

    Labels

    backendBackend / Worker / API workenhancementNew feature or request

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions