Conversations

Conversation access and history

Conversation access and history for people running and reviewing agents.

For: people running and reviewing agents.

Chats: yours, private by default

A conversation that a person started is that person's chat. Its owner is the account that started its first turn: a person signed in to the console, or the account a chat identity is mapped to, so a Slack or Discord thread is the chat of the person who wrote its first message. A fork is a chat of its own, owned by whoever forked it.

A conversation that an app's API key, an operator's certificate or a chat binding's service identity started has no owner: it is in nobody's list, and the tenant's members with the content permission read it as before.

Who can read a chat

A chat is visible to its owner and to the people and teams the owner shares it with, nobody else. Everyone else, a tenant's admins included, sees only facts: that the conversation exists, its agent, its turns' jobs, status and cost. A job page of someone else's chat shows no message, answer or trace content, and their chats are in no list anyone else sees: admins never browse other people's chats.

Who can decide approvals and questions

When an agent in a chat waits for an approval or asks a question, the request goes to the tenant's operators, as every approval does. The tenant's operators who hold the content permission see its details on the Approvals page (the call's arguments, or the question and its choices), since they decide it without the chat; readers see it without them. A chat waits for you when its approval or question is one you may decide; a chat that waits for a budget request or an event waits for nobody in it.

Share a chat

The owner shares a chat with a named person or a team of the tenant. A person must hold the content permission in the tenant, or the share is refused with the reason; a team's members see it while they hold it. Access is checked on every read, so someone who loses the content permission, leaves the team or loses the share loses the chat at once.

Shares are in the audit log (conversation.shared, conversation.unshared). The owner can always take a share back, also after losing the content permission. Only the owner continues their chat, and those it is shared with.

Read someone else's chat

Reading someone else's chat is possible only for someone with the content permission, by its ID, with a reason: oz0 conversation get ID --reason "...", or the reason form on the chat's job page. The read is audited as conversation.view.private with the owner and the reason (every other read of what was said in a conversation is conversation.view).

Its owner sees who read it, when and why on the chat's page, unless the tenant turned that off (oz0 tenant chat-read-notices). Whether and when an employer may read employees' chats is a question for your own legal and employee representatives; the platform keeps every such read in the audit log either way.

Chat titles

A chat is titled with its first message's first words (at most 80 characters), and its owner may rename it. Where the tenant allows it (oz0 tenant chat-titles TENANT model), the agent's own model writes the title instead, in the chat's first job, as one small extra request that is metered and traced on that job; such a title is marked as written by AI.

Manage your chat list

Pin a chat to the top of your list, archive it, mark it read, or remove it from your list. A chat is unread when it changed since you last read it.

Remove a chat from your list

Remove from my list erases nothing. Removing a chat takes it off your list only. Its turns stay under the tenant's retention, its erasure policy and any legal hold, and the people it is shared with keep it. Opening or reading it does not bring it back; pinning it, marking it read (Put it back on my list on its page) or starting a turn of it does, and someone else's turn does not.

What the chat list contains

The list holds what a list needs and nothing more: the chat's ID, title, a preview of the latest message (at most 48 characters, so twenty chats fit in 2 KB; opening a chat loads the full text), its agent, last activity, state (running, waiting for you, waiting, done, failed, cancelled), unread, pinned, archived and whether it was shared with you.

A title and a preview are what was said, so they need the content permission, and the edge keeps them sealed with the key that seals the chat's turns; see personal data. Nothing counts chats per person: no insight, overview or export says how many chats anyone has.

oz0 conversation mine                      # your chats and those shared with you, pinned first
oz0 conversation mine --archived --agent weather
oz0 conversation rename conv-5e1d… "Weekend weather"
oz0 conversation pin conv-5e1d…            # unpin, archive, unarchive, read, remove
oz0 conversation share conv-5e1d… --person kim
oz0 conversation share conv-5e1d… --team support
oz0 conversation shares conv-5e1d…
oz0 conversation unshare conv-5e1d… --person kim

The CLI acts as its operator's certificate, which owns no chats: conversation mine and the commands that change a chat answer that it is no person's until the CLI can sign in as one. The console and the API, with a person's session, have them all.

Which agents take part

An agent takes part when its input is text (input: text), or a JSON Schema a message fits: an object with a string property message and nothing else required. For those, send the message as text; the edge wraps it as {"message": "..."}.

schemas/ask.json
{"type": "object", "properties": {"message": {"type": "string"}, "tone": {"type": "string"}}, "required": ["message"]}

Flows, and agents whose schema requires more than a message, take no part: a continuation is refused with the reason, and the catalog's conversation_input says which agents take part.

How much of the conversation a turn gets

Each turn gets the turns before it: what was said and what was answered. The agent's history rules bound them:

  • With history.compact, a turn gets up to 200 earlier turns and compacts them as it compacts a long run: a summary in place of the oldest (summarize), or a note that they were left out (trim). A summarize turn hands its summary on: the next turn gets the summary instead of the turns it stands for, so a long conversation pays for one summary as it grows, not one per turn.
    conversation get says which turns carried a summary, and of how many turns. A summary goes with the tenant's retention once its oldest turn is older than the tenant keeps.
  • Without, a turn gets the newest turns that fit history.max_messages (40 when unset; two messages a turn), and a note of how many were left out.
  • Every turn carries at most 192 KiB of earlier turns, and at most 32 KiB of each input or answer; longer ones are cut, and say so.
  • No turn carries an earlier turn older than the tenant's retention period.

A Pydantic AI agent reads the earlier turns as its message history. A harness, openai-agents or remote agent gets them as a transcript before your message.

What is refused

RefusalWhy
Another tenant's jobTenants never share a conversation; the job is not found.
Another agent's conversationUnless the new agent's conversation.continue_from allows it, or the conversation's last turn was Ask's.
An agent that takes no partA flow, or an input schema that needs more than a message.
Without the content permissionThe agent is given what was said, which is content (roles).
A turn that is not the latest, in its own conversationLeave the conversation out (or name a new one) to fork it instead.
A turn that still runsContinue once it has answered. Two replies at once: one starts, the other is told to retry. Ask's hand-over is the one exception: it continues from the Ask turn it is part of.
A turn again under its own job IDThe same start again (the same request) answers with that turn, running or ended, and runs nothing; any other start under its ID is refused with already_exists, since a new run would change what later turns were built on. Retry a failed turn instead: that starts the next turn.
A job an outside event startedA webhook's or a routine's job is no conversation's turn.
A latest turn Temporal forgotA conversation continues while its latest turn is within the namespace's retention.

Personal data, retention and erasure

A chat's title and preview are a second copy of what was said, outside Temporal, so they are bounded (80 and 48 characters), sealed by the edge with the key that seals the turns (the data subject's key, else the tenant's payload key, else the vault's seal), and kept with the turn they came from: a subject's erasure and the tenant's retention remove them with that turn, and a legal hold keeps them. Management never holds them in plain text. A chat goes once all its turns have.

A conversation keeps the data subject of its first turn: started with --data-subject, every later turn is encrypted with the same person's key, even when it does not name them, and a turn may not name another. Erasing the person (personal data) erases every turn, and the conversation is gone at once. The record of which job is which turn goes with each job's summary, on erasure and when the tenant's retention period ends.

Each turn's input holds the earlier turns it was given, so what was said is also in later turns' jobs. Retention bounds that too: a turn carries no earlier turn that started before the tenant's retention period, and says how many it left out. A message therefore lives at most the tenant's retention period, plus as long as Temporal keeps the turns that carried it (the namespace's retention).

The trade-off: a thread that goes on for longer than the retention period loses its oldest turns from the agent's view. Under a legal hold, which stops retention, and in a tenant that keeps everything, turns of every age are carried.

Copyright © 2026