Skip to Content
Living documentation — last reviewed 2026-05-28
FeaturesSpotter AgentSpotter Agent — Data Model

Spotter Agent — Data Model

All Spotter tables live in libs/db/src/lib/schema/agent.ts and libs/db/src/lib/schema/ai-cache.ts.

ai_conversations

ColumnTypeNotes
iduuid PK
organization_iduuid FK → organizations.id (cascade)Scope.
user_iduuid FK → users.id (cascade)Conversation owner.
membership_iduuid FK → memberships.id (set null)Snapshots the membership at start.
titlevarchar(255) nullableHaiku-generated from first user message.
pinnedboolean default falseUX affordance.
archived_attimestamp tz nullableSoft archive.
summarytext nullableCompaction summary text.
summary_embeddingvector(1024)Voyage embedding of summary. HNSW index.
last_message_attimestamp tzUsed for sort.
total_input_tokensintLifetime tokens.
total_output_tokensint
total_cache_read_tokensint
total_cache_creation_tokensint
cost_usd_microsbigintLifetime cost.
modelvarchar(64)DEFAULT_MODEL at creation.
created_at, updated_attimestamp tz

Indexes:

  • (organization_id, user_id, last_message_at DESC) — list query.
  • HNSW on summary_embedding (vector_cosine_ops).

ai_messages

ColumnTypeNotes
iduuid PK
conversation_iduuid FK (cascade)
roleenum aiMessageRoleuser, assistant, tool_result, system_note.
contentjsonbAnthropic content block array, verbatim. Allows lossless replay.
previewtext nullableFirst 200 chars for the list panel.
page_contextjsonb nullable{ pathname, selection } snapshot. Also used by compaction to record summarizedThroughMessageId.
stop_reasonvarchar(32) nullableend_turn, tool_use, max_tokens, …
input_tokens / output_tokens / cache_read_tokens / cache_creation_tokensint nullablePer-turn usage from Anthropic.
modelvarchar(64) nullable
created_attimestamp tz

Index: (conversation_id, created_at) for replay.

Why content is jsonb

Anthropic’s content blocks (text, tool_use, tool_result, thinking) are stored byte-for-byte. The orchestrator re-feeds them on resume so token counting, citation positions, and tool_use ids stay stable across turns.

ai_tool_executions

ColumnTypeNotes
iduuid PK
conversation_iduuid FK (cascade)
message_iduuid FK → ai_messages.id (cascade)The assistant message that emitted the tool_use.
tool_use_idvarchar(64)Anthropic’s tool_use id.
routervarchar(64)e.g. workouts.
actionvarchar(64)e.g. create.
inputjsonbValidated args payload.
outputjsonb nullableSet on succeeded.
statusenum aiToolStatuspending, running, succeeded, failed, rejected_by_user.
error_code / error_messagevarchar(64) / text nullableOn failure / rejection.
duration_msint nullableWall-clock per ToolRunner.execute.
resource_idvarchar(255) nullableExtracted from output.id when present.
audit_log_iduuid FK → audit_logs.id nullableLinked when write tool emits an audit row.
created_attimestamp tz

Indexes:

  • UNIQUE (conversation_id, tool_use_id) — dedupe / lookup.
  • (resource_id) — find tool runs by resource.
  • (conversation_id, created_at) — replay order.

ai_usage_daily

ColumnTypeNotes
iduuid PK
organization_iduuid FK (cascade)
user_iduuid FK (cascade)
daydateUTC day bucket.
messagesintTurn count.
input_tokens / output_tokens / cache_read_tokens / cache_creation_tokensint
cost_usd_microsbigint

UNIQUE (organization_id, user_id, day).

AgentCostTracker.recordTurn upserts via SQL increments to avoid lost updates on concurrent turns.

ai_cache (ai-cache.ts)

ColumnTypeNotes
iduuid PK
modelvarchar(100)e.g. voyage-multilingual-2.
input_hashvarchar(64)SHA hash of input.
operationvarchar(50)embedding or enrichment.
resulttextJSON-serialized result.
created_attimestamp tz
expires_attimestamp tz nullableOptional TTL.

Index: (model, input_hash) — lookup.

Used by AiCacheService to memoize Voyage embeddings and exercise enrichment (the LLM-generated movement metadata). Not the same as Anthropic’s prompt cache — that’s transient per-request cache_control markers.

Audit linkage

  • Every write tool that defines meta.audit writes to audit_logs post-success with metadata.agent: true.
  • ai_tool_executions.audit_log_id points at the audit row so admin views can pivot.

Retention posture

  • No automatic deletion. ai_messages and ai_tool_executions grow with usage.
  • AgentStorageSnapshotService emits a daily agent.storage.snapshot event so growth is monitored.
  • A retention policy is on the backlog; cold rows beyond N days could move to a _archive table or be dropped after summarization.