Skip to content
View as .md

Record types

Schemas for the new record types the system needs to host external resources, tools, activation policies, runs, artifacts, and memory. Written against the polymorphic records substrate that has since been replaced by per-entity tables — landing them today means new tables, not new type discriminants. Read as design intent for the shapes themselves.

resource parent: house {kind: discord-channel|github-repo|sandbox|durable-stream|...,
external_id, config} — open enum on kind
tool parent: house|null {name, kind: builtin|mcp|http, schema?, config?}
null parent = global platform capability
activation-policy parent: agent {trigger: cron|interval|webhook|stream-event|github-event
|mention|ambient,
config, resource_ids?, tool_ids?, enabled}
replaces trigger_mode + ambient_delay_ms on AgentContent
run parent: house {status: queued|dispatching|running|waiting|completed|failed|aborted,
task_ref?, agent_id, sandbox_ref?, session_id?, activation_id?,
started_at?, finished_at?, failure_phase?}
artifact parent: house {kind: message|file|url|commit|screenshot|log-ref|...,
label?, external_id?, mime_type?, byte_ref?,
source_run_id?, source_session_id?, resource_id?, metadata?}
memory parent: agent|house {kind: fact|preference|commitment|reference,
text, confidence?, source_ref?, supersedes?, tags?}

Resources are scoped to houses (the right permission boundary — a house admin controls which external targets are available). They do not carry secret references — many resources may share one credential, one resource may need several; credential binding is a separate concern. Tools are records with x permission gating invocation; global tools are platform capabilities, house-scoped tools are integrations specific to that house. Activation policies own their agent (parent: agent_id) — resource_ids / tool_ids say what the policy cares about; the runtime still permission-checks the agent against those tools and resources before executing.

Run records are created in the substrate when work crosses a shared boundary (remote dispatch, external resource, multi-agent); local-only repo work stays in SQLite. Artifacts live under a durable scope (house/project) because they outlive the runs and sessions that produced them — provenance goes in content where it can be queried without polluting the ownership tree. Memory: agent-level memories are private to that agent; house-level memories are shared knowledge within the house. The permission model handles both via parent_id chain-walking.

Room extends with optional kind: 'conversation'|'session', status: 'active'|'idle'|'blocked'|'errored'|'completed', sandbox_ref, started_at, last_activity_at. A query for active sessions becomes where type='room' and content->>'kind'='session' and content->>'status' in ('active','idle','blocked').

Secrets are explicitly not a record type. They live in a dedicated secrets table backed by Supabase Vault — see system/secrets. The earlier secret-binding record type with a vault_key indirection was designed before Vault was in scope.

@arbe/core changes when these land: add the schemas + content schemas + mutation builders (createResource, createTool, createActivationPolicy, createArtifact, createRun, createMemory); extend RoomContentSchema; add runtime helpers resolveCapabilities(agentId, db), resolveActivationPolicies(agentId, db), resolveSecrets(agentId, resourceIds, db); remove trigger_mode + ambient_delay_ms from AgentContentSchema — they move to activation-policy records. The mutation executor already handles arbitrary record types — new types mostly need content validation, not new executor logic.

Open: full JSON Schema vs lighter shape for tool input schemas (heavyweight but future-proof — start light); should constraint records exist from day one, or run “capability = tool permission ∩ resource permission” until it breaks (start without; add when a real use case demands narrowing).

See: thinking/capabilities, thinking/activation, thinking/memory, thinking/sequencing.