Skip to main content

Gastown OTel Data Model

All Gastown telemetry events are OTel log records exported via OTLP (GT_OTEL_LOGS_URL). Every record carries a run.id attribute — a UUID generated once per agent spawn — so all records from a single agent session can be retrieved and correlated.


1. Identity hierarchy

1.1 Instance

The outermost grouping. Derived at agent spawn time from the machine hostname and the town root directory basename.

AttributeTypeDescription
instancestringhostname:basename(town_root) — e.g. "laptop:gt"
town_rootstringabsolute path to the town root — e.g. "/Users/pa/gt"

1.2 Run

Each agent spawn generates one run.id UUID. All OTel records for that session carry the same run.id.

AttributeTypeSource
run.idstring (UUID v4)generated at spawn; propagated via GT_RUN
instancestringhostname:basename(town_root)
town_rootstringabsolute town root path
agent_typestring"claudecode", "opencode", …
rolestringpolecat · witness · mayor · refinery · crew · deacon · dog · boot
agent_namestringspecific name within the role (e.g. "wyvern-Toast"); equals role for singletons
session_idstringtmux pane name
rigstringrig name; empty for town-level agents

2. Events

agent.instantiate

Emitted once per agent spawn. Anchors all subsequent events for that run.

AttributeTypeDescription
run.idstringrun UUID
instancestringhostname:basename(town_root)
town_rootstringabsolute town root path
agent_typestring"claudecode" · "opencode" · …
rolestringGastown role
agent_namestringagent name
session_idstringtmux pane name
rigstringrig name (empty = town-level)
issue_idstringbead ID of the work item assigned to this agent
git_branchstringgit branch of the working directory at spawn time
git_commitstringHEAD SHA of the working directory at spawn time

session.start / session.stop

tmux session lifecycle events.

AttributeTypeDescription
run.idstringrun UUID
session_idstringtmux pane name
rolestringGastown role
statusstring"ok" · "error"

prime

Emitted on each gt prime invocation. The rendered formula is emitted separately as prime.context (same attributes plus formula).

AttributeTypeDescription
run.idstringrun UUID
rolestringGastown role
hook_modebooltrue when invoked from a hook
formulastringfull rendered formula (prime.context only)
statusstring"ok" · "error"

prompt.send

Each gt sendkeys dispatch to an agent's tmux pane.

AttributeTypeDescription
run.idstringrun UUID
sessionstringtmux pane name
keysstringprompt text (opt-in: GT_LOG_PROMPT_KEYS=true; truncated to 256 bytes)
keys_lenintprompt length in bytes
debounce_msintapplied debounce delay
statusstring"ok" · "error"

agent.event

One record per content block in the agent's conversation log. Only emitted when GT_LOG_AGENT_OUTPUT=true.

AttributeTypeDescription
run.idstringrun UUID
sessionstringtmux pane name
native_session_idstringagent-native session UUID (Claude Code: JSONL filename UUID)
agent_typestringadapter name
event_typestring"text" · "tool_use" · "tool_result" · "thinking"
rolestring"assistant" · "user"
contentstringcontent truncated to 512 bytes (set GT_LOG_AGENT_CONTENT_LIMIT=0 to disable)

For tool_use: content = "<tool_name>: <truncated_json_input>" For tool_result: content = <truncated tool output>


agent.usage

One record per assistant turn (not per content block, to avoid double-counting). Only emitted when GT_LOG_AGENT_OUTPUT=true.

AttributeTypeDescription
run.idstringrun UUID
sessionstringtmux pane name
native_session_idstringagent-native session UUID
input_tokensintinput_tokens from the API usage field
output_tokensintoutput_tokens from the API usage field
cache_read_tokensintcache_read_input_tokens
cache_creation_tokensintcache_creation_input_tokens

bd.call

Each invocation of the bd CLI, whether by the Go daemon or by the agent in a shell.

AttributeTypeDescription
run.idstringrun UUID
subcommandstringbd subcommand ("ready", "update", "create", …)
argsstringfull argument list
duration_msfloatwall-clock duration in milliseconds
stdoutstringfull stdout (opt-in: GT_LOG_BD_OUTPUT=true)
stderrstringfull stderr (opt-in: GT_LOG_BD_OUTPUT=true)
statusstring"ok" · "error"

mail

All operations on the Gastown mail system.

AttributeTypeDescription
run.idstringrun UUID
operationstring"send" · "read" · "archive" · "list" · "delete" · …
msg.idstringmessage identifier
msg.fromstringsender address
msg.tostringrecipient(s), comma-separated
msg.subjectstringsubject
msg.bodystringmessage body (opt-in: GT_LOG_MAIL_BODY=true; truncated to 256 bytes)
msg.thread_idstringthread ID
msg.prioritystring"high" · "normal" · "low"
msg.typestringmessage type ("work", "notify", "queue", …)
statusstring"ok" · "error"

Use RecordMailMessage(ctx, operation, MailMessageInfo{…}, err) for operations where the message is available (send, read). Use RecordMail(ctx, operation, err) for content-less operations (list, archive-by-id).


agent.state_change

Emitted whenever an agent transitions to a new state (idle → working, etc.).

AttributeTypeDescription
run.idstringrun UUID
agent_idstringagent identifier
new_statestringnew state ("idle", "working", "done", …)
hook_beadstringbead ID the agent is currently processing; empty if none
statusstring"ok" · "error"

mol.cook / mol.wisp / mol.squash / mol.burn

Molecule lifecycle events emitted at each stage of the formula workflow.

mol.cook — formula compiled to a proto (prerequisite for wisp creation):

AttributeTypeDescription
run.idstringrun UUID
formula_namestringformula name (e.g. "mol-polecat-work")
statusstring"ok" · "error"

mol.wisp — proto instantiated as a live wisp (ephemeral molecule instance):

AttributeTypeDescription
run.idstringrun UUID
formula_namestringformula name
wisp_root_idstringroot bead ID of the created wisp
bead_idstringbase bead bonded to the wisp; empty for standalone formula slinging
statusstring"ok" · "error"

mol.squash — molecule execution completed and collapsed to a digest:

AttributeTypeDescription
run.idstringrun UUID
mol_idstringmolecule root bead ID
done_stepsintnumber of steps completed
total_stepsinttotal steps in the molecule
digest_createdboolfalse when --no-digest flag was set
statusstring"ok" · "error"

mol.burn — molecule destroyed without creating a digest:

AttributeTypeDescription
run.idstringrun UUID
mol_idstringmolecule root bead ID
children_closedintnumber of descendant step beads closed
statusstring"ok" · "error"

bead.create

Emitted for each child bead created during molecule instantiation (bd mol pour / InstantiateMolecule). Allows tracing the full parent → child bead graph for a given molecule.

AttributeTypeDescription
run.idstringrun UUID
bead_idstringnewly created child bead ID
parent_idstringparent (wisp root / base) bead ID
mol_sourcestringmolecule proto bead ID that drove the instantiation

Other events

All carry run.id.

Event bodyKey attributes
slingbead, target, status
nudgetarget, status
doneexit_type (COMPLETED · ESCALATED · DEFERRED), status
polecat.spawnname, status
polecat.removename, status
formula.instantiateformula_name, bead_id, status (top-level formula-on-bead result)
convoy.createbead_id, status
daemon.restartagent_type
pane.outputsession, content (opt-in: GT_LOG_PANE_OUTPUT=true)

run.id, instance, town_root, session_id, rig, role, agent_type,
event_type, msg.thread_id, msg.from, msg.to

4. Environment variables

VariableSet byDescription
GT_RUNtmux session env + subprocessrun UUID; correlation key across all events
GT_OTEL_LOGS_URLdaemon startupOTLP logs endpoint URL
GT_OTEL_METRICS_URLdaemon startupOTLP metrics endpoint URL
GT_LOG_AGENT_OUTPUToperatoropt-in: stream Claude JSONL conversation events (content truncated to 512 bytes by default)
GT_LOG_AGENT_CONTENT_LIMIToperatoroverride content truncation in agent.event; set 0 to disable (experts only)
GT_LOG_BD_OUTPUToperatoropt-in: include bd stdout/stderr in bd.call records
GT_LOG_PANE_OUTPUToperatoropt-in: stream raw tmux pane output
GT_LOG_MAIL_BODYoperatoropt-in: include mail body in mail records (truncated to 256 bytes)
GT_LOG_PROMPT_KEYSoperatoropt-in: include prompt text in prompt.send records (truncated to 256 bytes)
GT_LOG_PRIME_CONTEXToperatoropt-in: log full rendered formula in prime.context records

GT_RUN is also surfaced as gt.run_id in OTEL_RESOURCE_ATTRIBUTES for bd subprocesses, correlating their own telemetry to the parent run.