Skip to content

Session modes: keep-warm vs fresh-per-message, plus a Fresh-session operator action - #168

Merged
xmiksay merged 1 commit into
masterfrom
165-session-modes-keep-warm-vs-fresh-per-message-plus
Jul 13, 2026
Merged

xmiksay merged 1 commit into
masterfrom
165-session-modes-keep-warm-vs-fresh-per-message-plus

Conversation

@xmiksay

@xmiksay xmiksay Bot commented Jul 13, 2026

Copy link
Copy Markdown

Summary

  • Add a per-project session_mode (keep_warm default, fresh_per_message): keep_warm is today's behavior (resume/warm-idle via claude -r); fresh_per_message runs every trigger in a brand-new claude session and never stays warm between turns.
  • Add a "Fresh session" operator action (POST /api/tasks/{id}/fresh_session) available in any mode: clears session_id and restarts the task so the next turn starts a new claude session in the same worktree. Refuses while a live agent is attached or the task is pending; works even when no session was ever captured.
  • jobs::control::continue_task and fresh_session now share a restart_task(task_id, clear_session) core.
  • confirm_task resolves the owning project's mode into resume_session_id (resolve_resume_session_id, unit-tested); the turn loop skips warm-idle parking entirely in fresh mode.
  • SPA: "Session mode" card on ProjectDetail, "Fresh session" button on TaskDetail's control row.
  • Split src/jobs/runner.rs's stdio/channel wiring into src/jobs/session_io.rs to make room for the session-mode threading without crossing the 400-line file cap.
  • Docs: docs/architecture.md (module map, projects table, HTTP surface, turn-loop paragraph), .claude/CLAUDE.md/.env.example/README.md note WARM_IDLE_TIMEOUT_SECS is keep_warm-only.

Test plan

  • cargo check --all-targets, cargo clippy --all-targets -- -D warnings, cargo fmt --check all clean
  • cargo test against both SQLite and a live Postgres (make test equivalent) — 265 lib tests + all integration tests pass on both backends, including new project::mode, jobs::store::resolve_resume_session_id_matrix, and jobs::lifecycle::fresh_session_* tests
  • npm run typecheck and npm run test (102 frontend tests) pass
  • Manual click-through of the new "Session mode" card and "Fresh session" button in a running instance

Closes #165

…) + Fresh session action

What: add a per-project session_mode (keep_warm default, fresh_per_message)
plus a "Fresh session" operator action available in any mode.

Why: context accumulation is usually right, but sometimes the operator wants
a clean slate — on demand when a session goes down a wrong path, or as a
per-project policy when every trigger should be judged fresh (#165).

How: tasks.session_id stays the single resume key (populated -> claude -r,
null -> fresh session), so no tasks schema change. New projects.session_mode
column + src/project/mode.rs (SessionMode enum, update_session_mode). confirm_task
resolves it into resume_session_id (resolve_resume_session_id, unit-tested);
fresh mode always spawns null. The turn loop skips warm-idle parking in fresh
mode (drain-or-close immediately), so a fresh session never holds an admission
slot between turns. jobs::control::continue_task and the new fresh_session
generalize into restart_task(task_id, clear_session), sharing the existing CAS
guard (#159 H2). New route POST /api/tasks/{id}/fresh_session and
PUT /api/projects/{id}/session_mode; SPA gets a Session mode card on
ProjectDetail and a Fresh session button on TaskDetail. Split
src/jobs/runner.rs's stdio wiring into src/jobs/session_io.rs to make room for
the session_mode threading without crossing the 400-line cap.
@xmiksay
xmiksay merged commit 656437e into master Jul 13, 2026
2 checks passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

Session modes: keep-warm vs fresh-per-message, plus a Fresh-session operator action

1 participant