t3-code

Identity

T3 Code is an app that runs other agents. It owns the conversation (threads, queues, approvals routing, questions, schedules, delegated tasks, checkpoints, pull request links) and drives Claude Code, Codex or Pi to do the model work. Each backing harness writes its own native transcript.
  • Native format: t3code-statev2-sqlite. One SQLite database per T3 environment (~/.t3/userdata/statev2.sqlite): an event store of whole-entity snapshots (orchestration_events) and projection tables. Raw provider protocol frames are kept in rotating logs (logs/provider/events.<threadId>.log), which can serve as native files.
  • Session ID: the T3 thread ID, verbatim. Namespace: required for every T3 stream: the T3 environment ID (~/.t3/userdata/environment-id). Derived thread IDs (import:codex:<id>, thread:delegated-task:…) repeat across installations.
  • Session references: thread IDs can contain : and %, which session references encode (ASR-059). The delegated-task thread thread:delegated-task:command%3Amcp%3A9f2c in environment 6f1d2c3a-5b7e-4c21-9a0d-3e8f1b2c4d5e is t3-code:6f1d2c3a-5b7e-4c21-9a0d-3e8f1b2c4d5e:thread%3Adelegated-task%3Acommand%253Amcp%253A9f2c.
  • Streams: One stream per T3 thread and one per backing session, converted under that agent’s own registry entry. nativeThreadRef supports lineage.executedBy only when the provider kind, namespace and native ID that T3’s adapter recorded identify that agent’s session. A strength of strong alone does not establish identity. Pi file paths and Claude workflow keys containing :agent:<n> stay in codes.t3/nativeThreadRef or codes.t3/nativeTaskRef; never inspect arbitrary paths to recover identity. A switch of backing session adds an entry by declaration. state.executedBy.turnId uses nativeTurnRef.nativeId only under a documented provider-turn correspondence (Codex); weak or generated turn refs remain in _meta.
  • Entity keys: turnId is the run ID (run:thread:<threadId>:ordinal:<n>). messageId is the T3 message ID. callId is nativeItemRef.nativeId only when the provider contract identifies it as the invocation ID. Otherwise use the T3 turn item ID. Strength alone never establishes cross-source correspondence. requestId is the runtime request ID. T3 records no model calls: there are no inference records (declare inference).
  • Copies and originality: A recorded link showing which provider thread owns an item can establish copiedFrom at session level only, with proof: native_field. Add record only when a unique nativeItemRef.nativeId has a documented native record correspondence in that backing session. Adapter strength alone is insufficient, and callId= cannot name a tool result. T3-owned prompts, approvals, questions, triggers, notices and checkpoints are not copies merely because the thread has a backing session. Usage covers backing calls (ASR-425).
  • Who wrote a message: take author and origin from T3, not from the backing transcript, which shows every prompt T3 inserted as an ordinary user prompt. The mapping is in the table below.
  • Tools: T3 drops the provider’s tool name for command_execution, file_change, web_search and file_search items: capture.name: absent (the backing stream has the name). dynamic_tool keeps toolName. MCP identity: unknown in the T3 stream (the Codex backing stream has it exactly). A “Workspace ready” command item is a setup script T3 ran: hook with event: workspace_setup. Background commands and monitors (pendingBackgroundTasks with kind command or monitor) → terminal with kind: shell or monitor and awaited; kind subagent → subagent.
  • Approvals: approval_request items and runtime requests → permission. decision: accept → allow_once, acceptForSession → allow_session, acceptAlways → allow_always, decline → reject_once, cancel → cancelled. status: pending → pending, resolved → resolved, expired → expired, cancelled → resolved with decision: cancelled. feedback → feedback; fullAccessOverride → reason. t3_pending_request_respond answers questions only. Its opaque mcp:<uuid> receipt does not identify who resolved an approval: leave decider absent. acceptForSession maps to allow_session in option kinds as well as decisions. The native cancel option maps to option kind cancel.
  • Questions: user_input_request items → input_request with mode: questions: question id, header, question → text, options with label, value and description, multiSelect, allowCustomAnswer → allowOther; answers → answers; blocking; an answer given later as a message (responseMode: message) → answerRef only when an explicit recorded message ID qualifies the link; responseMode alone does not. secret_request → input_request with one question marked secret; secretStatus saved → answered, declined, cancelled, pending. The secret goes to an owner-only file and is never recorded (ASR-283). mcp-elicitation runtime requests → mode: form or url.
  • Turns: run status → state: queued → queued; running → running; waiting → requires_action; completed → idle with stopReason: end_turn; interrupted and cancelled → idle with stopReason: cancelled; failed → idle with stopReason: error; rolled_back → a rewind with reason: rollback. Run attempts → state.attempt {n, reason} (initial, steering_restart, retry, provider_recovery). Run snapshots retain restartContinuationOfRunId → continuationOf. usageLimitContinuationOfRunId and manualContinuationOfRunId can map only when their authoritative dispatch commands survive; otherwise preserve native evidence and declare _codes.t3/continuation_history. Error items → state.error with class, retryable, resetAt and retry {attempt, maxAttempts, delayMs} (from retryDelayMs).
  • Checkpoints and changes: checkpoint.captured → checkpoint with kind: git_ref, ref (the hidden ref), status, files and turnId. A run’s diff between two checkpoints → file_change with basis: net and endpoints. checkpoint.rollback-requested → rewind with reason: rollback and restoreRequested.
  • Pull requests: a pull request link whose source is created → vcs pr_open with evidence: observed; links with source agent, manual or stack → vcs pr_link with evidence: reported.
  • Notes: compaction items record token counts but not the replaced range: compaction with replaces: {state: unknown}, tokens, reason from idleCompaction, and kind _codes.t3/compaction (T3 does not record the kind). Reasoning with no recorded visibility uses reasoning.text with visibility absent; readers must not label it full reasoning. Plans: todo_list → planType: items; proposed_plan → planType: document; provider goals → planType: goal with status, budget and used. Archive, pin and soft delete → session_info.flags; projects → session_info.project; a generated title → titleSource: model. Guest roster entries can declare participants with role: guest; assign from only through a qualified recorded guest identity, never the roster or display name alone. notification items → notice messages. Declare inference, revision_history and tool_result.content (T3 keeps display output only).
How T3 fields map to author and origin: A user message’s text is what the person typed: displayContent, with content empty and capture.content: absent, because T3 wraps first prompts and inlines handoff text before sending them.

Position basis

  • Order: Compaction deletes earlier snapshots, and with them the positions at which items were created. Use a new capture, with safe-integer seq taken from the surviving items’ ordinal and the store’s documented serialization order. Keep immutable audit logs in their own sequence order, current rows in the capture tail, and declare order and revision_history. Preserve IDs backed by stable T3 identity; use idScope: capture only for purely positional IDs.
Use only positions established by the stated format and mapping evidence. Current-state rows without transcript positions form the snapshot tail. A protocol commit boundary takes precedence over physical EOF; uncommitted bytes are not a gap.

Destinations

T3 Code: native facts without a standard field

  • Lineage: thread.created.lineage.relationshipToParent: subagent → spawnedBy and scope: subagent; fork → forkedFrom, with record from the fork point when T3 records it. A thread created with create_threads gets spawnedBy and scope: primary only when its recorded lineage.parentThreadId and creation relation identify the creator. Delegated tasks → subagent in the parent (agent from the child’s driver, model, awaited, and status revisions from subagent.updated). Context handoffs → the rendered message has derivedFrom (from the handoff’s item list); a fork whose context arrived as a summary has inherits.mode: rendered. Provider-native subagent threads (creationSource: provider, items but no runs) are read-only copies of a Claude Code subagent transcript: authority: mirror and executedBy naming claude-code:<agentId>. root may be claimed for a thread whose thread.created event has no lineage and no forkedFrom, and that was not imported.
These contracts apply to 4a95cee9b8, server 0.1.3-nightly.

Usage

After applying revisions, aggregate ProviderTurn.turnTokenUsage components known not to overlap once per T3 run and counter. Write the aggregate as usage_summary with scope: turn, cumulative: false, coverage: partial, and usage.input.total with includesCache: true. Preserve components at codes.t3/providerUsage; components with no run use the documented vendor scope _codes.t3/provider_turn. Do not add overlapping components; tokenUsage → contextWindow. Select one report per native accounting identity only when this entry establishes that identity. Keep unjoinable or overlapping reports as native evidence. Declare incomplete semantic coverage. Schema defaults and placeholder zeros are not reported usage. Rules about what the backend includes in usage counts require evidence; do not infer them from a model name.

Lane and unassigned facts

Facts without established session ownership use manifest _meta["codes.t3/unassigned"] with the common shape. Selection may retain these facts with any session subset, including an empty subset, but must not imply session ownership. State the selection policy in the export report.

Losses

Declare every applicable loss under ASR-157. Missing model rendering, accounting joins, lineage or exact context boundaries remain losses when this entry does not qualify them. Unknown ownership is not itself lost data. Omitted unassigned facts use a documented vendor loss or report, not a new core category.

Evidence

Basis: source (fork main at 4a95cee9b8, server 0.1.3-nightly), and observed (one local event store). The reverse-DNS name follows the product domain t3.codes and is provisional. Evidence applies only to the named formats and explicit mappings above. A real capture covers only exercised behavior. A writer probe run without a model covers persistence, not model or tool execution. Authored tests do not qualify an agent version. Unlisted formats and link mappings remain unqualified.