Sessions
A session is a continuous sequence of events: a conversation with an AI agent, including tool calls, thinking, and responses. Sessions provide audit trails, enable resumption, and persist as markdown files.
Architecture
Sessions follow Crucible’s “plaintext first” philosophy:
- Markdown is truth — Each session saves as a markdown file
- Daemon manages state — the daemon tracks active sessions via RPC
- Resume anytime — Pick up previous sessions with
cru session open
Daemon Integration
Sessions are managed by the daemon (cru daemon serve):
┌─────────────────┐ ┌─────────────────────┐│ cru chat │◄───────►│ cru daemon serve ││ │ JSON-RPC│ ││ TUI/CLI client │ │ SessionManager ││ │ │ AgentManager │└─────────────────┘ └─────────────────────┘RPC Methods:
session.create— Start new sessionsession.list— List all sessionssession.get— Get session detailssession.load— Load a persisted session from storage into daemon memorysession.pause— Pause a running sessionsession.unpause— Unpause a paused session (programmatic, no TUI)session.resume— Resume a session in the TUI (interactive)session.end— End sessionsession.send_message— Send a message and stream the responsesession.configure_agent— Configure the agent for a sessionsession.subscribe/session.unsubscribe— Event streamingsession.archive— Archive a session (remove from active list)session.unarchive— Restore an archived session to activesession.delete— Permanently delete a session
CLI naming vs RPC methods: The daemon RPC methods are
session.resume(open in TUI) andsession.unpause(reactivate programmatically). The CLI commands use clearer names:cru session openmaps tosession.resume, andcru session resumemaps tosession.unpause. The oldcru session unpausestill works as a deprecated alias. Scripts should usecru session resume; humans picking up a conversation should usecru session open.
Session Storage
Sessions are saved under the daemon’s data root — ~/.crucible/sessions/ by
default — not inside a kiln. A session attaches kilns as its knowledge
scope; where it is filed is a separate question from what it can read.
~/.crucible/sessions/├── chat-2026-01-02T1430-a1b2c3/│ ├── meta.json # kilns, workspace, agent, state│ ├── session.jsonl # append-only event log│ └── session.md # human-readable transcript└── chat-2026-01-21T0900-c3d4e5/Because transcripts live outside kilns, a kiln can be shared, synced, or committed to git without carrying your conversations with it.
Where your old sessions went
Sessions used to live in {kiln}/.crucible/sessions/. The first daemon start
after upgrading moves them to the layout above, and this happens once,
automatically, for every kiln the daemon knows about (your config’s kilns and
every registered project’s).
Two cases worth knowing:
- Id collisions. Two kilns could each hold a session with the same id. The
first keeps its id; the other is republished as
{id}--{8 hex}, derived from the kiln it came from, so it is stable across re-runs. Both survive — nothing is overwritten. - Sessions the move could not complete. If a session cannot be relocated
(unreadable, or both the id and its disambiguated name are taken) it is left
where it is and logged as skipped. It stays on disk in
{kiln}/.crucible/sessions/, butcru session listandcru session searchread only the new root, so it will not appear until you move it by hand.
Run the daemon with RUST_LOG=info on the first start after upgrading if you
want to see the migration report.
Session Log Format
Sessions are readable markdown when exported:
---session_id: chat-20250102-1430-a1b2workspace: /home/user/projectmodel: claude-3-5-sonnetstarted: 2025-01-02T14:30:00Z---
# Chat Session
## UserFind all notes tagged #project and summarize them
## AssistantI'll search for notes with the project tag.
### Tool Call: search_by_tags```json{"tags": ["project"]}Tool Result
Found 12 notes matching #project.
Let me read through these and create a summary…
User
Tell me more about Project Beta
## CLI Commands
Crucible provides a full set of session subcommands. They split into two groups: **user-facing** commands for everyday use, and **daemon** commands for programmatic session control.
### User-Facing Commands
#### List Sessions
```bashcru session listShows recent sessions with ID, workspace, and timestamp.
Search Sessions
cru session search "rust"Search sessions by title or content.
Show Session Details
cru session show chat-20250102-1430-a1b2Display details for a specific session, including model, message count, and timestamps.
Open a Session (Interactive TUI)
cru session open chat-20250102-1430-a1b2Opens the session in the interactive TUI. The conversation history loads and you can continue chatting. This is the command humans use to pick up where they left off.
Export Session
cru session export chat-20250102-1430-a1b2 -o session.mdExport a session to a standalone markdown file.
Cleanup Old Sessions
cru session cleanup # only sessions sharing the invoking kilncru session cleanup --all-kilns # every session on this machineRemove old sessions. Every session on the box lives in one flat root now, so the
scope is stated rather than implied: without --all-kilns only sessions that
share a kiln with the invoking one are eligible, which is also why --all-kilns
is the only way a kiln-less session is ever collected.
cru session reindex is retired — sessions no longer live inside a kiln, so
there is no per-kiln session corpus to rebuild.
Daemon Commands
These commands control sessions at the daemon level. They’re designed for scripts, automation, and multi-client workflows rather than interactive use.
Create a Session
cru session create # Basic creationcru session create --agent researcher # With an agent cardcru session create --acp claude # With an external ACP agentcru session create --title "Auth refactor" --workspace /path/to/projectID=$(cru session create -q) # Capture session ID for scriptingcru session create -f json # Structured JSON outputCreate a new daemon session. The -q/--quiet flag prints only the session ID, which is handy for capturing in shell variables. Use --title to give the session a human-readable name and --workspace to pin it to a specific project directory.
--agent and --acp name different things and cannot be combined. --agent
runs the built-in internal agent with an agent
card‘s prompt, model, tool policy and MCP servers layered over your config
defaults. --acp instead launches an external agent subprocess by profile name
(claude, gemini, codex, cursor, opencode, or anything under
[acp.agents.*]).
cru agents list shows both. Either way the daemon resolves the name before
the session exists, so an unknown one fails without leaving a session behind.
--agent named an ACP profile in earlier versions. It names a card now, so
that it agrees with cru agents; passing a profile name to it reports the
mismatch and points at --acp.
Pause a Session
cru session pause chat-20250102-1430-a1b2Pause a running daemon session. The session stays in memory but stops processing.
Resume a Session (Daemon)
cru session resume chat-20250102-1430-a1b2Reactivate a paused daemon session without opening a TUI. Use this in scripts and automation workflows. For interactive use, prefer cru session open instead. The old cru session unpause still works as a deprecated alias.
End a Session
cru session end chat-20250102-1430-a1b2End a daemon session. The session is finalized and persisted.
Send a Message
cru session send chat-20250102-1430-a1b2 "Analyze the auth module"# Or with env var:CRU_SESSION=chat-20250102-1430-a1b2 cru session send "Analyze the auth module"# Or pipe from stdin:echo "Analyze the auth module" | cru session send chat-20250102-1430-a1b2Send a message to a session and stream the response. Both the session ID and message are positional arguments. If you set CRU_SESSION, you can omit the ID entirely.
Configure Agent
cru session configure chat-20250102-1430-a1b2 -p openai -m gpt-4oConfigure the agent backend for a session: provider, model, and endpoint. For runtime parameter tweaks (model, thinking budget), use cru set instead:
cru set chat-20250102-1430-a1b2 thinkingbudget=highLoad a Session
cru session load chat-20250102-1430-a1b2Load a persisted session from storage into daemon memory. This doesn’t open a TUI; it just makes the session available for daemon operations like send, pause, or configure.
Scripting Patterns
A full programmatic lifecycle, start to finish:
# Create, configure, use, and tear down a sessionID=$(cru session create -q --title "Code review" --acp claude)cru session configure "$ID" -p anthropic -m claude-sonnet-4-20250514cru session send "$ID" "Review the auth module for security issues"cru session pause "$ID"# ... later ...cru session resume "$ID"cru session send "$ID" "Now check the database layer"cru session end "$ID"All lifecycle commands accept -f json for structured output, which pairs well with jq:
cru session pause "$ID" -f json | jq .previous_statecru session list -f json | jq '.sessions[].session_id'cru session search "auth" -f json | jq '.[].session_id'Environment Variables
| Variable | Purpose |
|---|---|
CRU_SESSION | Default session ID for send and cru set when no positional ID is given |
Start a New Chat
cru chat # Auto-creates a new sessionRunning cru chat starts a fresh session. If there’s a recent session for the current workspace, it may auto-resume.
In-TUI Session Management
Resume on Send
When you start cru chat, if there’s a recent session for the current workspace, it auto-resumes. Your first message continues the previous conversation.
Switch Sessions
Use the :session command:
:session list # Show available sessions:session new # Start fresh sessionSession Archiving
Sessions have two states: active and archived. Active sessions appear in session.list by default. Archived sessions are hidden unless you explicitly ask for them.
Active vs Archived
| Active | Archived | |
|---|---|---|
Visible in session.list | Yes | Only with include_archived: true |
| Can receive messages | Yes | No (must unarchive first) |
| Counts toward “recent sessions” | Yes | No |
| Data preserved | Yes | Yes |
| Can be resumed | Yes | Yes (after unarchive) |
Archiving doesn’t delete anything. It moves the session out of the active view so your session list stays manageable. Unarchive brings it back.
Manual Archive and Unarchive
Use the session.archive and session.unarchive RPC methods. Both require session_id and kiln parameters:
# Archive a sessioncru session archive chat-20250102-1430-a1b2
# Unarchive it latercru session unarchive chat-20250102-1430-a1b2Deleting Sessions
To permanently remove a session, use session.delete. This cleans up both the daemon state and the agent resources. Requires session_id and kiln parameters:
cru session delete chat-20250102-1430-a1b2Deletion is irreversible. The session’s JSONL file and any associated daemon state are removed.
Listing Archived Sessions
By default, session.list only returns active sessions. Pass include_archived: true to see everything:
cru session list --all # includes archived sessionsAuto-Archive
The daemon automatically archives stale sessions. A background sweep runs every 30 minutes, checking for sessions that have been inactive (no messages, no subscribers) beyond a configurable threshold.
Default threshold: 72 hours of inactivity.
Configure it in ~/.config/crucible/config.toml:
[server]auto_archive_hours = 72 # default; set to 0 to disableThe sweep skips sessions that have active subscribers (connected clients). It also re-checks activity timestamps before archiving to avoid race conditions where a session receives new activity between the staleness check and the archive operation.
Auto-archived sessions can be unarchived at any time. No data is lost.
Session Configuration
Session behavior is configured through the [chat] section in ~/.config/crucible/config.toml. The daemon manages session persistence automatically; sessions always save under the daemon data root (~/.crucible/sessions/), never inside a kiln.
[chat]# Default chat model (can be overridden per session)# model = "llama3.2"
# Show thinking/reasoning tokens from models that support it# show_thinking = falseAgent Configuration per Session
Each session tracks agent configuration:
- Model — LLM model (e.g.,
claude-3-5-sonnet,gpt-4o) - Thinking Budget — Token budget for extended thinking
- Temperature — Response randomness
- Tools — Available MCP tools
Change mid-session via :set or :model:
:set model claude-3-5-sonnet:set thinkingbudget 8000:model gpt-4o # Opens model pickerChanges persist for the session and sync across connected clients.
Events
Sessions emit events that can be subscribed to via RPC:
| Event | Description |
|---|---|
stream_start | Response streaming begins |
stream_chunk | Text chunk received |
stream_end | Response complete |
tool_call | Tool invocation |
tool_result | Tool completed |
thinking | Thinking/reasoning tokens |
error | Error occurred |
Subscribe from external tools:
cru session subscribe <session-id>