Skip to content

A Conversation Log is a shared append-only JSONL of every message, tool call, and mutation across agents in a multi-agent session — tailed (not fully read) at task start so agents stay coordinated without duplicating each other's work.

Primitive

Conversation Log

The artifact

JSONL. One event per line. No multi-line entries.

.pi/multi-team/sessions/abc/conversation.jsonl

JSONL

10:00:00{agent:orchestrator, type:message, body: "Classifying to engineering-lead"}

10:00:02{agent:orchestrator, type:tool_call, tool: delegate, args: {...}}

10:00:05{agent:engineering-lead, type:message, body: "backend-dev will handle"}

10:00:20{agent:backend-dev, type:mutation, kind: tilldone-done, task_id: "jwt"}

Chosen so tail -n 20 conversation.jsonl | jq . works from the shell. Humans and agents read the same format.

Fixed vocabulary

Four event types. Extending them requires updating every reader.

message

Agent said something. The body field is the text. What the orchestrator speaks, what a lead replies, what a worker reports.

tool_call

Agent invoked a tool. Tool name + args. Captures delegation, read, write, bash — every non-text action.

tool_result

Tool returned. Paired with a tool_call. The return value (truncated if large); enables tail-readers to see outcomes.

mutation

Session state changed. Task marked done, skill activated, agent spawned. The log becomes authoritative for state — not just transcript.

Why agents don't read the whole log

Tail N entries. Not N × session_length.

ignored — old historyLAST 20 ✓

turn 1turn 500now

Full-log reads grow unboundedly with session length. Tail reads are O(N) regardless of total size. The active-listener skill enforces this: every agent tails the last N before responding, getting awareness without blowing the context budget.

The single-source-of-truth rule

If UI and log disagree, the log wins.

invariant

Mutations outside the log → divergence.

anything that changes session state

MUST write a mutation event

If a worker marks a task done by updating some internal field without emitting a {type: mutation}, the UI says pending, the log says nothing — and nobody knows the truth. The log is where state events go, not just where messages go. Make this rule early; breaking it is expensive to fix later.

What breaks

Four failure modes. All predictable.

Multi-line entries

Tail reading becomes stateful — must find entry boundaries. Fragile. Pretty-printed JSON breaks the whole contract.

Agents reading the full log

Context budget blown on history that doesn't matter for the current turn. The whole design assumes bounded reads.

Mutations outside the log

State divergence. UI shows X, log says Y. Nobody knows which is authoritative.

Shared logs without session scoping

Concurrent sessions' lines interleave. Tail reads surface irrelevant context from other sessions.

The discipline

One log. Tail-read, mutation-aware, session-scoped.

JSONL so tail + jq is the whole reader. Fixed vocab so extending the log is a deliberate act, not accidental drift. Mutations go through the log so the log is authoritative, not decorative. The log is how five agents in a room stay coordinated without each of them reading the other four's minds.