Skip to content

Conversations

NimbleBrain automatically persists every conversation. Each conversation is stored as a JSONL file owned by the user who created it, and you can resume, rename, fork, and delete conversations through the web UI or CLI.

Conversations are partitioned by workspace and authorized by their owner. Every conversation lives under the workspace it ran in and the user who created it, keyed by its ID:

~/.nimblebrain/workspaces/ws_3f9a1c7e0b2d4856/conversations/user_abc123/conv_a1b2c3d4e5f67890.jsonl

The path is the authority: workspaces/<wsId>/conversations/<ownerId>/<convId>.jsonl. The owner (ownerId) is the single authorization principal — only they can read or resume the conversation — while the workspace (workspaceId) is where it is stored and which tools the agent could reach when a turn ran.

Conversations are stored as append-only JSONL (JSON Lines) files using event sourcing:

  • Line 1 — immutable conversation metadata (written once, never rewritten)
  • Lines 2+ — append-only conversation events
{
"id": "conv_a1b2c3d4e5f67890",
"createdAt": "2026-03-25T10:30:00.000Z",
"updatedAt": "2026-03-25T10:42:00.000Z",
"title": "Weekly meeting summary",
"lastModel": "anthropic:claude-sonnet-4-6",
"ownerId": "user_abc123",
"workspaceId": "ws_3f9a1c7e0b2d4856",
"format": "events"
}

Each conversation has exactly one owner (ownerId), the single authorization principal. Token totals and cost are not stored in line 1 — they are derived at read time by scanning llm.response events, which avoids drift between a cached total and what re-aggregating the events would produce.

Events are appended chronologically. Key event types:

EventDescription
user.messageA user sent a message
run.startThe agent engine started processing
llm.responseThe model returned a response (token counts, model, content)
tool.startA tool call began
tool.doneA tool call completed (result, latency)
run.doneThe agent engine finished processing
run.errorThe agent engine encountered an error

Example user message event:

{
"ts": "2026-03-25T10:30:00.000Z",
"type": "user.message",
"content": [{"type": "text", "text": "Summarize my meetings from this week"}]
}

Open Conversations from the sidebar to see your history. Each conversation shows:

  • Title — auto-generated from your first message
  • Timestamp — when the conversation last had activity

Click any conversation to load it in the chat panel and continue where you left off. The agent has the full context of everything discussed previously.

Select a conversation from the sidebar list in the web UI. The full message history loads, and new messages continue the conversation. Through the API, pass conversationId in the chat request body to continue an existing conversation.

NimbleBrain generates a conversation title automatically after the first assistant response. The title is stored in the metadata line of the JSONL file and shown in the web UI sidebar and conversation list.

Click New conversation in the chat panel header, or type /clear in the input. Your previous conversation is saved — you can always return to it.

For long-running conversations, NimbleBrain can compact older history to keep the context window manageable. This is opt-in and disabled by default. Enable it with the compaction feature flag in nimblebrain.json:

nimblebrain.json
{
"features": {
"compaction": false
}
}

When enabled, the runtime summarizes earlier turns once a conversation grows large, preserving the gist while freeing room for new context. With it off (the default), the full event history is replayed every turn.

By default the CLI uses event-sourced JSONL storage under the work directory. You can point storage elsewhere in nimblebrain.json:

{
"store": {
"type": "jsonl",
"dir": "/custom/path/to/conversations"
}
}

For ephemeral, in-memory storage with no persistence:

{
"store": {
"type": "memory"
}
}
  • Chat — how conversations are created during chat
  • Multi-Agent Delegation — child agents run in their own conversations
  • Automations — scheduled agent runs that produce deliverables