Kin / Use Kin

Sessions, resume & compaction

Every conversation is saved to disk as it happens, so you can quit and pick up where you left off, roll back a mistake, or trim a long context. This page covers the journal, resuming, rewinding, and compaction.

Read as Markdown

Every conversation is saved to disk as it happens, so you can quit and pick up where you left off, roll back a mistake, or trim a long context. This page covers the journal, resuming, rewinding, and compaction.

Outcome

Move between live and saved work without losing the current conversation, and know when to resume, fork, rewind, or compact.

Fast path

  1. Press ++ctrl+l++ or run /sessions.
  2. Choose a live row to switch to its process, a saved row to resume, or New session here for an independent clean conversation.
  3. Use /resume when you want only this project’s saved history.
  4. Use /fork before exploring a risky conversational branch.
  5. Quit with ++ctrl+c++; normal sessions are already journaled as they run, and Kin leaves the exact resume command in the terminal.

Kin session switcher grouping live, waiting, and saved conversations with a New session action.

The switcher presents the action implied by each state: attach to live work, inspect waiting work, resume a saved journal, or start cleanly.

Alternative entry points

At launch

kin --continue resumes the newest session for the current project. kin --resume <id> chooses an exact journal.

In the TUI

/sessions includes live local and Outpost work. /resume is the narrower saved-history picker, and /resume <id> switches directly.

Background work

/detach leaves the issuing terminal while the process keeps running. Bare kin reclaims one unattended session, opens a chooser when several are available, and kin ls lists them all.

The journal

Beam cards use hybrid persistence: the journal stores the beam/job identity at a conversation boundary, while Outpost remains the live lifecycle authority. Cards survive resume, compact, clear, rewind, and fork; their marker is clamped to a safe user-turn boundary so replay never splits a tool call from its result. This is intentionally asymmetric with context snapshots: a beam is an external-world fact worth retaining even when nearby conversation text is rewritten. Old journals contain no markers and replay exactly as before.

Each session is an append-only JSONL file. The first line is a meta record (provider, model, workdir, created time); every line after it is either a message (one entry of the provider-native history, appended at each turn boundary) or a mode change.

~/.kin/projects/<workdir-slug>/<session_id>.jsonl

The <workdir-slug> is the project’s absolute path with separators flattened to dashes, so every project keeps its own set of sessions. The id looks like s_<unix-time>_<hex>.

Append-only means crash-safe: a torn final line is skipped on load, not fatal, and each turn appends only its new messages. Provider-native history is stored verbatim—Chat flat dicts, Responses typed output items (encrypted reasoning included), or Anthropic content-block lists (thinking signatures included)—so a resumed session is faithful on the same endpoint and wire. The journal envelope remains v2; wire_api in metadata selects the decoder, while old journals without it retain their Chat-or-Messages meaning.

The projects root can be relocated. KIN_HOME moves all of ~/.kin; the KIN_SESSION_DIR environment variable or the session_dir global setting points the whole projects tree somewhere else. See Environment variables and Settings (TOML).

Resume & continue

Action How
Resume a specific session at launch kin --resume <id>
Resume the newest session for this project kin --continue
Switch sessions mid-run /resume (picker) or /resume <id>

After a clean interactive exit, Kin prints a ready-to-paste command for the conversation that was active at shutdown:

To continue this session, run:
  kin --resume s_1784570243_deadbe

If the session used a --workdir other than the shell’s current directory, the command includes that absolute, shell-quoted path. Ephemeral (--no-save), failed-to-save, and empty sessions print no hint because there is no surviving journal to resume. This is the same on the default background-session path and with --no-detach: Kin waits until the UI and terminal wrapper have both finished, then prints into the shell-visible terminal.

Headless runs (kin -p) write the same journal, so a cron run that exited 2 (needs-human) can be picked up interactively with kin --resume <id> — the id is printed on stderr and in the --output report.

At launch, resume reuses the saved provider, endpoint, model, and sampling configuration from the journal’s meta unless you override a backend flag on a saved-only conversation. Secrets are never stored in the journal: Kin reattaches the current provider_keys[<id>] credential only when that provider still describes the saved endpoint. Older journals without a provider id use a unique endpoint and auth match, so existing history remains resumable; a changed or ambiguous custom endpoint is never handed a guessed per-provider key. If the saved provider doesn’t match the backend you launch with, resume fails closed (it refuses rather than replaying into the wrong wire); it does not silently start a fresh session. A bare --resume (no --mode flag and no KIN_MODE) also keeps the session’s saved permission mode rather than re-applying your global default, so a strict-mode session you resume doesn’t silently reopen in auto.

Conversation identity also protects live work. If --continue or --resume ID names a conversation already owned by a managed process, Kin attaches to that process, even if another terminal is already viewing it. If you also supplied provider/model/sampling/mode or another launch-only override, Kin refuses: attach without overrides, change configuration in-session, or /fork first. This prevents both ignored flags and two live writers appending to one journal.

In-session, bare /resume opens a picker of this project’s sessions (newest first, with a one-line title, age, turn count, and model); /resume <id> switches directly. The switch is non-destructive — the current session’s journal is left intact on disk — so it needs no confirmation. You can’t switch while a turn or a compaction is running, or while another modal is open.

Forking

/fork branches the current session: it copies the on-disk journal to a fresh session id — everything after the meta line copied byte-for-byte — then switches you onto the copy via the exact same path /resume uses. The fork becomes the live session; the source is left exactly as it was at the moment you forked, untouched and resumable with /resume <old-id> later. This is the reversible way to explore a branch without losing the original: fork, go try something, and if it doesn’t pan out, /resume back to where you started.

There’s no separate “fork back” verb — a fork is just a session like any other, and /resume already gets you to any session by id. /fork refuses (with a notify) while a turn or a compaction is running, the same as /export.

This human command is distinct from the model tool fork_agent. /fork switches the human onto a copied root session. fork_agent(prompt=…) leaves the root session in place and spawns a supervised child with conversation context through the current user request; see Subagents.

Subagent journals are hidden

Every retained subagent spawned by task or fork_agent writes its own journal next to the root session’s (same project dir), with the spawning session’s id recorded as parent_session_id in its meta. These child journals are deliberately hidden from every root-session enumeration surface/resume, --continue, and /sessions list only root sessions, so a busy session that spawned a dozen subagents doesn’t drown the picker and --continue always resumes the root, not whichever subagent happened to finish last. An explicit kin --resume <child-id> still loads one (a deliberate act; the id isn’t advertised). Subagent transcripts are read live through the agent panel (Ctrl+O) and the agent_output tool, not through resume.

Session titles

Each session’s picker row starts with a default title — its first user message. After a session sits idle for ~120 seconds with no new turn, kin generates a short (3–6 word) title from the conversation via a one-off bounded model side-call (the same pattern compaction uses — it doesn’t touch your history or the context meter) and saves it to the journal. The timer resets on every new turn, so an active session is never interrupted, and a resumed historic session picks up a title after the same idle gap. The generated title is a title record in the journal — persisted like mode, so it survives /compact, /clear, /rewind, and a /providers swap — and is what the /resume picker prefers over the raw first message.

By default the side-call runs on the main model. Assigning the utility job moves it to a lightweight route so a title request can never disturb the main endpoint’s prompt cache; if that route is busy or the call fails, kin simply keeps the fallback title.

See Slash commands for the full command list and CLI reference for the launch flags.

Background sessions (detach & reattach)

Resume covers the case where the kin process is gone. Background sessions cover the other one: the process is fine — you just want to leave. Close the terminal window, drop an SSH connection, step away mid-turn — kin keeps running in the background and you land back in the live conversation later, mid-turn included. No replay: the process never died.

On by default when tmux is available — every interactive launch runs as a background session. Opt out per launch, per machine, or per project:

How What
kin --no-detach this launch only — a plain, non-background run
KIN_DETACH=0 this shell / machine (env)
detach = false in ~/.kin/settings.toml every launch in this project / globally
kin --detach force it ON where you’d opted out

If tmux is missing or too old, kin runs plainly and silently (no nagging — a default shouldn’t); kin doctor reports whether background sessions are available.

Everything else looks and feels exactly like a normal launch — colors, mouse, keys, and tab titles all pass through unchanged. The terminal tab title names the workspace folder and shows a slow dot spinner while kin works; it becomes a static ● … needs input when an approval or question is waiting. Reduced-motion mode keeps the busy title static, and KIN_ASCII=1 uses line-style frames.

  • Leave: /detach. The terminal returns to your shell with a note that the session is still running; any in-flight turn keeps going.
  • Come back: run bare kin in the same folder. With exactly one unattended healthy process, you land directly in it. With several, Kin opens a launch chooser. With none, it creates a new unique process. A one-shot kin --detach remains recoverable even if background persistence is otherwise opted out. Closing the terminal window or losing SSH is equivalent to detaching: the process survives.
  • Start alongside: kin --new forces a fresh conversation and process. It still follows your detach setting; kin --new --detach forces persistence, while kin --new --no-detach is fresh but unwrapped.
  • Quit for real: /exit (or /quit) works exactly as always — the current process ends and its journal remains resumable.

Two terminals can attach to the same session at once — both mirror the same screen (sized to the most recently active one), which is handy for peeking at a long run from a second window. Mirroring is explicit: select an open in another terminal row in the launch chooser, select the live row in /sessions, or resume its exact live conversation. /detach releases only the terminal that issued it; if Kin cannot identify that client safely, it warns and detaches nobody.

What a launch does

Launch state Result
Bare kin, no unattended session Create a new unique instance
Bare kin, exactly one unattended session Reattach it
Bare kin, multiple unattended sessions Open the launch chooser
--new, --bg, --agent, or provider/model/sampling/preset/mode/no-save flags Create a fresh instance
--continue / --resume ID targeting a live conversation Attach its existing process
--continue / --resume ID targeting saved-only work Create a managed instance resuming it
--no-detach, headless mode, or a launch inside your own tmux Run plainly, without Kin’s wrapper

The launch chooser labels every instance available, open in another terminal, or crashed, shows its title (or a short identity), state, and age, and ends with Start new session. The newest available row is focused. Escape cancels the launch. If a selected process vanishes, the board refreshes instead of guessing.

The fine print:

  • Mechanism & requirement: background sessions are provided by a managed, invisible tmux session (version ≥ 3.2 on PATH; ≥ 3.4 recommended — kin doctor reports what it found). Your own tmux config and server are never touched, and nothing tmux-shaped is visible: no status bar, no prefix key. If tmux is missing or too old, kin runs plainly and silently (the default never nags; an explicit kin --detach prints one line). If anything ever wedges, the rescue command is tmux -L kin kill-server; /exit from inside always works.
  • Inside your own tmux (or with kin -p): kin never nests multiplexers and never wraps a headless run — those launches run exactly as today, and your own tmux detach already covers the leave-it-running story.
  • --continue / --resume ID map by live conversation identity, not merely by folder. An older live process without that identity must be attached with bare kin before an exact resume; Kin refuses to risk a duplicate journal writer.
  • --workdir, --detach, and --no-detach shape location/lifecycle rather than model configuration, so they do not make an otherwise bare launch non-bare. --new conflicts with resume/continue. --bg always creates a fresh instance and also conflicts with resume/continue.
  • A reboot ends the process — that’s what the journal is for: kin --continue / /resume recover the conversation, as ever.
  • A crash freezes the pane with the traceback on screen instead of vanishing — press q to close it. If it is the folder’s only managed instance, the next launch prints the saved traceback and removes it. If it has siblings, it remains an inspectable crashed row until you end it or ordinary cleanup reaps it.

Sessions share the same files

Independent Kin processes in one workspace have independent screens and journals, but they read and edit the exact same working tree. Their file changes can conflict. Use separate Git worktrees when you need filesystem isolation; Kin does not create worktrees or add edit locks automatically.

Working across folders

One terminal, N projects: spin up sessions across folders and jump between them. Everything below builds on the persistent-session mechanism above.

/sessions — the switcher

/sessions (or ctrl+l) opens a browser of every session, grouped:

  • running — every live instance across all folders, including independently identifiable siblings in the same folder; the current one first, needs-you sessions next (oldest wait first), then working, then idle. Enter jumps to one; switching is instant (it moves your terminal, not the process). x ends a session — an idle one dies immediately, a mid-turn one asks first (the conversation stays in /resume).
  • this folder — saved — resumable conversations for the current project (the same rows /resume shows). If another live instance owns the selected journal, Kin switches to its process instead of resuming it in-process. A plain unwrapped client refuses that duplicate-writer case.
  • start new session in… — always includes New session here, plus known folders; enter creates a fresh background instance and jumps to it.
  • on Outpost — remote jobs; enter peeks at active work or beams a terminal job back. Needs-you jobs are counted in the group header.

Switching only works from a persistent launch (it moves the managed terminal between sessions); a plain launch shows a one-line note instead. Resuming a saved conversation works from any launch.

kin ls — list background sessions

When Outpost is configured, kin ls adds a separate on Outpost: block after local sessions. --no-cloud skips that fetch. An unreachable service is shown explicitly rather than hidden, and the shell wait is capped at 2.5 seconds.

The /sessions switcher likewise has an on Outpost group. Active rows open a read-only job view; terminal rows run /beam back. Remote needs-human work contributes to the same needs-you badge as local sessions and raises one edge toast. Ambient cloud state refreshes every 45 seconds: one failed poll holds the badge, while two consecutive failures drop the cloud contribution. See Beam work to Outpost.

kin ls lists every live instance across folders — folder, status (working / needs you / idle / crashed), and age — with a marker on the ones that need you. When a workspace has siblings, each row also includes its conversation summary or short identity. It’s read-only (it never cleans anything up). Run it from any shell; with no tmux or no live sessions it just says “no background sessions”.

--bg — start work in the background

kin --bg "refactor the auth module" begins the work in a persistent session without opening the UI, then returns you to the shell. Check on it with bare kin in the same folder (directly when it is the only available process, otherwise through the launch chooser) or kin ls. It’s scriptable — cron and shell scripts can fire it (it doesn’t need a terminal). --bg needs a prompt and can’t combine with -p (headless-now vs background-later are opposite promises), --continue, or --resume. Every invocation creates a distinct fresh same-workspace instance; its shell confirmation names how many siblings are already active.

Cross-session attention

While you work in one session, a sibling that needs you (an approval, a question, a plan to review) raises a one-time toast — “~/other needs your approval — /sessions to jump” — using its summary or short identity when several rows share that workspace. The status bar wears a standing ● N needs you · /sessions badge until it’s resolved. It works whether or not your current launch is itself persistent.

Cleanup

Background sessions are tidied at launch time so zombies don’t pile up — the conversation journals are append-only, so a cleaned-up session loses only its live process state and stays fully resumable. Two knobs (both in ~/.kin/settings.toml or via env), tuned per-project if you like:

Setting Env Default Meaning
session_ttl_days KIN_SESSION_TTL_DAYS 7.0 idle/crashed sessions past this age are cleaned up (0 = never)
session_cap KIN_SESSION_CAP 10 over this many unattended sessions, the oldest idle ones are cleaned up (0 = uncapped)

A needs-you session is never cleaned up on age alone — a parked human decision shouldn’t vanish silently. A mid-turn session is never cleaned up by the cap. kin ls annotates a session that’s near its TTL (· cleans up in 2d).

Rewind & retry

/rewind [n] [conversation|files|both] rolls back the last n completed user turns (default 1) — the conversation, the on-disk files, or both. A bare /rewind or /rewind <n> behaves exactly as before: it rolls back the conversation and repaints the transcript from the truncated history. The cut is always taken at a real user-turn boundary, so a tool round is never split. Internal end-of-run memory reflection is canonical model history, but it is not a human turn and never consumes a rewind count or appears in the picker. Its memory-only workspace checkpoint is likewise ineligible for /rewind files, so a turn with no workspace edits remains a clean no-op. The journal is rewritten to match, so a resumed session reflects the rewound state.

  • /rewind files restores on-disk file state to a checkpoint taken just before the rewound turn’s first edit — without touching the conversation. If those turns made no edits (or the workdir isn’t a git repo, or the snapshot safety net was off), it’s a clean no-op: “no file changes to rewind.”
  • /rewind both restores files first, then rolls back the conversation to match — only if the file restore succeeds. A failed restore leaves the conversation untouched (files-first, so you never lose the record of what happened without also getting your files back).

files and both always ask for confirmation, even for a single turn — restoring the worktree is destructive, and a protective snapshot of the CURRENT state is taken automatically before either one runs, so a restore you didn’t mean to do is itself reversible.

/retry re-sends the last user message — useful after an error or an interrupt. It still works after a /rewind, because the last user turn is recomputed from the truncated history.

When the first model request in a turn ends in a backend hard-error (the endpoint was unreachable or rejected the request), the error note is followed by a focusable ↻ retry button — click it, or Tab to it and press Enter. Unlike /retry, this first removes the failed turn from history, so the model sees exactly one fresh copy of your message (no duplicate). If the failure lands after tools have already run, Kin shows the error without a retry button: replaying the whole turn could repeat side effects, and splitting the saved tool-call/result pair would corrupt provider history. Send a new follow-up to continue safely. The retry note’s guidance distinguishes a recoverable failure (a dead/unreachable endpoint — worth retrying as-is) from a rejected request (a bad api key / model id / base url — fix it first, then retry).

Neither /rewind nor /retry (nor the retry button) runs while a turn or a compaction is in flight.

Double-Esc rewind picker

Press ++escape++ twice within about a second — on an empty composer, with no modal open, and no turn running — to open a picker instead of typing /rewind by hand: it lists your recent turns (newest first, with a short preview of each), then asks for a scope (conversation / files / both) once you pick one. ++up++ / ++down++ navigate, ++enter++ selects, ++escape++ backs out with no action at either stage. The picker dispatches through the exact same /rewind <n> <scope> path described above, so files/both still confirm before touching your worktree.

A single ++escape++ keeps its normal meaning everywhere (interrupting a running turn, closing a menu, exiting cursor mode) — the picker only appears on a second tap while kin is otherwise idle.

Export

/export [path] dumps the current session’s saved transcript to a markdown file — a keepsake, not a second live copy. It reads the ON-DISK journal (the same one resume/rewind read), so it always reflects what’s actually durable, and renders ## You / ## Kin sections with tool calls as fenced blocks and tool results elided to a one-line summary (a full tool result — a read_file dump, a shell command’s stdout — would make the export unreadable). Bare /export writes kin-export-<session-id>.md into the workdir; an explicit path wins, and overwrite is allowed with no confirm (unlike /clear//rewind, this is additive, not destructive). Refuses with a notify while a turn or a compaction is running. The exported file carries your conversation verbatim, with no sanitization — it’s a file you asked for, not something rendered back at you.

File snapshots

In a git workspace, kin takes a lightweight checkpoint of your files before the first edit of every turn — a git commit-tree recipe under refs/kin-snapshots/, invisible to your real index, HEAD, or worktree (it never stages, commits, or moves a branch you’d see in git status or git log). This is what /rewind files//rewind both restore from. The checkpoint is taken once per turn (a turn that edits three files gets one checkpoint, not three), and a session keeps its 20 most recent checkpoints (older ones are pruned automatically).

The safety net is on by default (KIN_SNAPSHOTS=0 or snapshots = false in settings.toml turns it off) and degrades to a silent no-op outside a git repo — no checkpoint, no error, /rewind files just reports nothing to restore.

What it does not cover: a shell command or run_code script that writes a file directly (bypassing kin’s own write_file/edit_file tools) is invisible to this safety net — the checkpoint only fires on kin’s own EDIT-kind tool calls. For those, git status/git diff (or your own snapshot habits) are still the tool.

Terminal notifications

kin gives your terminal a walk-away signal: a bare bell (\x07) always, plus — on a terminal it recognizes as capable (Ghostty, iTerm2, WezTerm, or kitty) — an OSC 9 escape sequence that surfaces a native desktop notification (dock bounce / banner) even when the tab isn’t focused.

It fires on two moments:

  • A turn finishes that ran 15 seconds or longer (a fast turn doesn’t need a walk-away signal). Pressing esc to interrupt never notifies — you were right there.
  • kin needs your input — an approval prompt, a question, a plan or settings-proposal review, or a sandbox-override confirmation.

Repeated notifications are debounced to at most one every 10 seconds. If your terminal reports focus events, the bell is suppressed while the app is actually focused (a terminal that never reports focus never goes silent — kin only suppresses once it has proven the terminal tells it who has focus).

The message text is always one of a fixed set of static strings (kin — turn complete, kin — needs your input, …) — it never includes any model or server output. On by default; KIN_NOTIFY=0 or notify = false in settings.toml turns it off. See kin -p for the headless-run equivalent — the same bell fires to stderr at process completion when stderr is a real terminal.

Compaction

As history grows toward the context window, compaction replaces the older portion with one synthetic summary message and keeps the most recent turns verbatim. Run it manually with /compact; add a focus to bias the summary:

/compact the auth refactor and the failing tests

The summarizer flattens the old history to plain text and produces a structured summary (task overview, current state, discoveries, next steps, context to preserve). The result is a single <summary>…</summary> user message followed by the verbatim recent turns — the cut is taken at a user-turn boundary so no tool round is split and retained thinking-signature blocks are untouched. After a compact, the journal is rewritten and the context meter re-baselines.

Proactive fractional auto-compaction is off by default. It runs only when you set KIN_COMPACT_THRESHOLD (env) or compact_threshold (settings), a fraction of the window clamped to 0.1–0.98. Hard prompt admission remains on: Kin reserves the backend’s configured max_tokens before a countable request, plus a small framing margin, so a long reasoning response still has room inside the advertised context window. The effective compact trigger is whichever comes first: the configured fraction or that hard prompt limit.

Kin checks exact prompt tokens before every model round when the backend can count them. Ordinary compaction keeps recent turns verbatim and applies to root and child sessions. At a new-turn boundary, if retaining the configured number of recent turns still leaves the prompt too large, Kin may summarize only the history completed before the new input; the live input and its same-turn reminders remain verbatim. If a completed tool round makes a continuation too large, Kin may compact that completed history and retry once. It never silently summarizes an oversized live user input: if the preserved input itself cannot fit, that request is refused intact with the measured prompt/output split so you can rewind it or change the cap. The number of recent turns kept verbatim defaults to 4 and is tunable via KIN_COMPACT_KEEP_TURNS / compact_keep_turns.

Context usage

/tokens shows where your context is going. On the Anthropic wire it breaks the total into system prompt, tool definitions, and history (real counts via the wire’s token counter); on the OpenAI-compat wire, which doesn’t expose a counter, it reports the live metered total only. The component figures are approximate — each includes per-request framing, so they sum to slightly more than the measured total. The top bar shows live usage continuously as you work. Its denominator is the effective prompt budget, and /tokens separately shows the model context, output reservation, hard prompt limit, and earlier auto-compact trigger when configured. Exact count probes refresh this meter but do not increment Kin’s generated-token spend meter.

Ephemeral runs

Launch with --no-save to run without writing a journal. Nothing is persisted, so the session can’t be resumed, rewound, or listed — useful for a throwaway question you don’t want recorded.

Suppressing empty sessions

Sessions that never receive a user submission — you launch kin and quit without typing anything — leave no journal file on disk. The journal

  • tasks-DAG sidecar pair is created in memory, but Session.aclose deletes them before tearing down the bg subsystems when the per-session turn counter is still zero. A resumed session that doesn’t get a new turn keeps its file (its history preceded this launch — there’s something to resume). A mode-only change (/mode strict then quit) is also suppressed — no user submission, nothing worth recording.

--no-save / KIN_NO_SAVE continue to skip persistence entirely; the suppression only applies on the default save path.

Old tool names in old journals

The tool registry keeps dispatch-only aliases for view_fileread_file, view_notebookread_notebook, and exit_plan (the pre-plan-lifecycle tool) so journals written before these renames still resume — the replay sees the old name, the alias routes it to the current tool, and the model on the next turn only ever sees the new names. The aliases are not advertised to the model; they’re a backwards-compat seam only. See Tools for the full tool surface.

Troubleshooting

  • A session is not listed: saved rows are project-scoped. Check the launch workspace; subagent journals and --no-save sessions are intentionally absent.
  • Switching is refused: wait for the active turn or compaction to settle and close any modal.
  • A resumed provider differs: saved provider-native history fails closed across incompatible wires unless you explicitly choose a supported conversion.
  • Context is still crowded after a long run: use /compact; use /fork first when you want a reversible checkpoint.

Reference