The seven database tables: companies, agents, issues, heartbeat_runs, cost_events, approvals, activity_log. ERD walkthrough, primary/foreign key relationships, and the company_id boundary.
The seven database tables that power Paperclip, how they relate to each other, and what every field means.
companies
│ 1:N
├── agents (with self-ref reports_to)
│ │ 1:N
│ └── heartbeat_runs
│ │ 1:N
│ └── cost_events
├── issues (self-ref parent_id)
├── approvals
└── activity_log
Every table except activity_log has a company_id foreign key. This is the multi-tenancy boundary — a query for one company can never accidentally return another company's data.
The root entity. Everything belongs to a company.
| Column | Type | Description |
|---|---|---|
id |
uuid | Primary key |
name |
text | Display name |
timezone |
text | e.g. America/New_York — drives heartbeat windows |
monthly_budget_usd |
decimal | Global ceiling across all agents |
metadata |
jsonb | Arbitrary config (webhook URLs, custom fields) |
created_at |
timestamptz | — |
An agent is a named AI worker with a role, execution config, and budget.
| Column | Type | Description |
|---|---|---|
id |
uuid | Primary key |
company_id |
uuid → companies | Data boundary |
name |
text | e.g. "Senior Engineer" |
role |
text | Role description used in prompts |
system_prompt |
text | Full system prompt for this agent |
adapter_type |
enum | claude_code \| openai \| http \| shell |
adapter_config |
jsonb | Adapter-specific settings (model, url, etc.) |
reports_to |
uuid → agents | Self-referential FK for org chart |
status |
enum | active \| paused \| terminated |
cron_schedule |
text | When heartbeats fire, e.g. 0 9 * * * |
monthly_budget_usd |
decimal | Max spend per calendar month |
created_at |
timestamptz | — |
Tasks. The core unit of work in Paperclip.
| Column | Type | Description |
|---|---|---|
id |
uuid | Primary key |
company_id |
uuid | Data boundary |
parent_id |
uuid → issues | Self-ref for subtask nesting |
assigned_agent_id |
uuid → agents | Who should work on this |
title |
text | Short task title |
description |
text | Full task details, context, requirements |
status |
enum | open \| in_progress \| blocked \| completed \| failed |
priority |
integer | Higher = more urgent. Default 0 |
metadata |
jsonb | Agent-to-agent message passing |
created_at |
timestamptz | — |
updated_at |
timestamptz | Auto-updated on any change |
One record per agent work cycle. The primary observability surface.
| Column | Type | Description |
|---|---|---|
id |
uuid | Primary key |
agent_id |
uuid → agents | Which agent ran |
company_id |
uuid | Data boundary |
issue_id |
uuid → issues | Which task was worked on |
started_at |
timestamptz | When the adapter was invoked |
completed_at |
timestamptz | When the adapter returned |
status |
enum | running \| completed \| failed \| dry_run |
tokens_used |
integer | Input + output tokens combined |
cost_usd |
decimal | Computed from model pricing |
output_summary |
text | Truncated agent output for the dashboard |
error_message |
text | Set on failure |
Immutable spend record. One per heartbeat run (or per API call for granular adapters).
| Column | Type | Description |
|---|---|---|
id |
uuid | Primary key |
company_id |
uuid | Data boundary |
agent_id |
uuid → agents | Who spent |
run_id |
uuid → heartbeat_runs | Which run caused this cost |
model |
text | e.g. claude-3-5-sonnet-20241022 |
input_tokens |
integer | Prompt tokens |
output_tokens |
integer | Completion tokens |
amount_usd |
decimal | Exact cost in USD |
created_at |
timestamptz | — |
Pending human decisions that block agent actions.
| Column | Type | Description |
|---|---|---|
id |
uuid | Primary key |
company_id |
uuid | Data boundary |
action_type |
text | hire_agent \| terminate_agent \| strategy_change \| budget_increase |
payload |
jsonb | The full context for the decision |
status |
enum | pending \| approved \| rejected \| expired |
created_at |
timestamptz | — |
resolved_at |
timestamptz | When a human acted |
Append-only audit trail. Never updated, only inserted.
| Column | Type | Description |
|---|---|---|
id |
uuid | Primary key |
company_id |
uuid | Data boundary |
actor_type |
text | agent \| human \| system |
actor_id |
uuid | Agent or user who performed the action |
action |
text | e.g. issue.status_changed, agent.paused |
entity_type |
text | issue \| agent \| company \| approval |
entity_id |
uuid | The affected record |
before |
jsonb | Snapshot before the change |
after |
jsonb | Snapshot after the change |
created_at |
timestamptz | — |
reports_to column on agents used for?heartbeat_runs and cost_events?activity_log append-only?