Documentation menu

Sessions and forking

Every run is a session: an id, a target directory, a model, a title, and an ordered transcript of messages. Findings, evidence, verdicts, memory and compaction journals all hang off that same session. Nothing is thrown away when a run ends, which is what makes "resume from memory", the fifth invariant, mechanical rather than aspirational.

Where sessions are stored

~/.locac/projects/<repo-name>-<hash>/sessions.db

A single SQLite file per target repository. The name is the target's directory name (sanitised, capped at 32 characters) plus a 12-character prefix of the SHA-256 of its absolute path, so two checkouts named api never collide.

$LOCAC_HOME replaces ~/.locac if it is set. --db <path> overrides the whole thing.

The database lives outside the target repository on purpose. Sandboxed target code has write access to the target root, and a session store the target can rewrite is a store you cannot trust to tell you what the last run found.

Older builds wrote to <target>/.lecter/sessions.db. If that file still exists, locac prints a one-line pointer at startup and tells you how to open it explicitly with --db. It never adopts it silently, and that is exactly the file the move was designed to distrust.

Listing sessions

locac sessions
2f1c9b40-...  2026-07-31T09:41:12.004Z  audit the archive extraction path
9a05e7d1-...  2026-07-30T18:02:55.881Z  (untitled)

One line per session: id, last-updated timestamp in ISO-8601 UTC, then the title. Sessions are listed most-recently-updated first. Titles default to the first 80 characters of the opening prompt, or interactive when the run started with no prompt.

locac sessions --db <path> reads a different database; --cwd <dir> picks the per-project database for another target.

Continuing and resuming

locac -c "now check the sibling handlers"    # the most recently used session
locac resume <session-id> ""                # a specific session

-c picks the first row of the session list: the most recently updated session for this target. With no prompt on a real terminal it opens that session in the TUI, idle, with the prior transcript repainted; off a TTY a prompt is required:

continue needs a prompt (or --tui): locac -c "<prompt>"

resume needs both an id and a prompt. Resuming loads the full history, appends your message, and re-drives the loop over the whole transcript, so findings, scratchpad and memory from the earlier turns are all still in scope.

All model and run flags work on resume, which is how you raise a budget after an exit code 2:

locac resume <session-id> "continue where you stopped" --max-tokens 4000000

Renaming and deleting

locac sessions rename <id> a clearer title for this audit
locac sessions delete <id>

rename takes the rest of the command line as the title, so quoting is optional.

delete removes a leaf session only. A session that has been forked is the parent of its branches, and deleting it would orphan them, so the delete is refused with an explanatory message and exit code 1.

Forking

A fork branches a session at a transcript position and continues in the branch. The source session is untouched. The point of a fork is retrying a step differently, not throwing the first attempt away.

locac fork <session-id> <seq>
Forked 2f1c9b40-… @seq 24 → 7be31c05-…
Resume it: locac resume 7be31c05-… "<your corrected next step>"

Message sequence numbers are contiguous from 0, so <seq> is simply the index of the last message you want to keep: messages 0..seq are copied and everything after is dropped. The boundary is then pulled back to the last balanced point: a fork must never copy a tool call whose tool result was left behind, because every request such a transcript makes is rejected as a bad request and the session becomes permanently unresumable. So the branch may keep slightly fewer messages than you asked for, and the number in the fork's own title is the boundary that was actually used.

The new session records its lineage, parent id and copied boundary, which is what lets sessions delete refuse to orphan a branch.

Use a fork when a run went down a wrong path and you want to re-decide from a known-good point without re-doing the reconnaissance that led there.

Inside the TUI, /fork opens a picker of the branchable turns and switches the live session to the new branch in place; /resume switches back to the original. Once a project has forks of forks, /tree is the picker to reach for: same list, but each session is drawn under the one it branched from, so you can see which attempt a branch came out of before you resume it.

Session state in the TUI

Five slash commands move the live session while the TUI is open:

CommandEffect
/newStart a fresh session with the same target, model and provider
/resumePick an existing session and repaint its transcript
/treeThe same picker, drawn as the fork tree — children indented under their parent
/forkBranch the live session at a picked turn and continue in the branch
/name <title>Retitle the live session
/sessionPrint the live session's id, message count, tokens and cost

Each of the first three detaches the compaction journal, because a recall seq=<N> marker only points at a real message while the conversation on screen is the persisted session. After a swap or a renumbering fork it would name a row in the wrong transcript.

Next

Other commands covers config, skills, web, eval and selftest.