Database Schema Reference
Overview
The OpenClaw Dashboard uses PostgreSQL 13+ with the uuid-ossp extension. The schema is defined in schema/openclaw-dashboard.sql and extended through 21 migration files in schema/migrations/.
Tables by Functional Area
Core: Projects & Workflows
workflows
Defines the state machine (pipeline) for tasks.
| Column | Type | Constraints | Description |
|---|---|---|---|
id |
UUID |
PK, default uuid_generate_v4() |
|
name |
TEXT |
NOT NULL | Workflow name |
states |
TEXT[] |
NOT NULL | Ordered array of state names |
is_default |
BOOLEAN |
NOT NULL, default false |
Whether this is the default workflow |
project_id |
UUID |
FK → projects(id) ON DELETE CASCADE, nullable |
Project scope (NULL = global) |
created_at |
TIMESTAMPTZ |
NOT NULL, default NOW() |
|
updated_at |
TIMESTAMPTZ |
NOT NULL, default NOW() |
Auto-updated via trigger |
projects
Container for tasks with configuration.
| Column | Type | Constraints | Description |
|---|---|---|---|
id |
UUID |
PK, default uuid_generate_v4() |
|
name |
TEXT |
NOT NULL | Project name |
description |
TEXT |
NOT NULL, default '' |
|
status |
TEXT |
NOT NULL, default 'active' |
active, paused, archived |
tags |
TEXT[] |
NOT NULL, default '{}' |
|
default_workflow_id |
UUID |
FK → workflows(id), NOT NULL |
Default workflow for tasks |
metadata |
JSONB |
NOT NULL, default '{}' |
|
qmd_project_namespace |
TEXT |
NOT NULL, UNIQUE | QMD namespace identifier |
created_at |
TIMESTAMPTZ |
NOT NULL, default NOW() |
|
updated_at |
TIMESTAMPTZ |
NOT NULL, default NOW() |
Auto-updated via trigger |
Indexes: GIN on tags, GIN on metadata
Core: Tasks
tasks
The primary work items.
| Column | Type | Constraints | Description |
|---|---|---|---|
id |
UUID |
PK, default uuid_generate_v4() |
|
project_id |
UUID |
FK → projects(id) ON DELETE CASCADE, NOT NULL |
|
title |
TEXT |
NOT NULL | Task title |
description |
TEXT |
NOT NULL, default '' |
|
status |
TEXT |
NOT NULL, default 'backlog' |
See status values below |
priority |
TEXT |
NOT NULL, default 'medium' |
low, medium, high, critical |
owner |
TEXT |
nullable | Agent name or human identifier |
due_date |
DATE |
nullable | |
start_date |
DATE |
nullable | |
estimated_effort |
NUMERIC |
nullable | Hours or story points |
actual_effort |
NUMERIC |
nullable | |
parent_task_id |
UUID |
FK → tasks(id) ON DELETE CASCADE, nullable |
Parent for subtasks |
dependency_ids |
UUID[] |
NOT NULL, default '{}' |
Array of blocking task IDs |
labels |
TEXT[] |
NOT NULL, default '{}' |
|
created_at |
TIMESTAMPTZ |
NOT NULL, default NOW() |
|
updated_at |
TIMESTAMPTZ |
NOT NULL, default NOW() |
Auto-updated via trigger |
completed_at |
TIMESTAMPTZ |
nullable | |
recurrence_rule |
TEXT |
nullable | Cron-like syntax |
metadata |
JSONB |
NOT NULL, default '{}' |
|
execution_lock |
TIMESTAMPTZ |
nullable | Lock timestamp |
execution_locked_by |
TEXT |
nullable | Agent holding lock |
blocker_type |
TEXT |
nullable | (004) waiting_on_agent, waiting_on_approval, waiting_on_external_service, content_failed_qa, other |
blocker_description |
TEXT |
nullable | (004) Free-text blocker details |
active_workflow_run_id |
UUID |
FK → workflow_runs(id) ON DELETE SET NULL, nullable |
(001) Linked workflow run |
archived_at |
TIMESTAMPTZ |
nullable | (20260216) Soft archive timestamp |
deleted_at |
TIMESTAMPTZ |
nullable | (20260216) Soft delete timestamp |
retry_count |
INTEGER |
NOT NULL, default 0 |
(20260216) Quick-access retry counter |
Constraints:
valid_priority CHECK (priority IN ('low', 'medium', 'high', 'critical'))
tasks_status_check CHECK (status IN (
-- Original
'backlog', 'ready', 'archived', 'review', 'completed', 'in_progress', 'blocked',
-- Content workflow queues (002)
'topic_candidate', 'drafting', 'image_pending', 'image_ready',
'qa_pending', 'ready_to_publish', 'published',
-- Generic (002)
'retrying', 'failed', 'cancelled'
))
Indexes:
| Index | Columns | Type |
|---|---|---|
idx_tasks_project_id |
project_id |
B-tree |
idx_tasks_parent_task_id |
parent_task_id |
B-tree |
idx_tasks_status |
status |
B-tree |
idx_tasks_owner |
owner |
B-tree |
idx_tasks_due_date |
due_date |
B-tree |
idx_tasks_priority |
priority |
B-tree |
idx_tasks_project_status |
project_id, status |
B-tree |
idx_tasks_completed_at |
completed_at |
B-tree |
idx_tasks_dependency_ids |
dependency_ids |
GIN |
idx_tasks_labels |
labels |
GIN |
idx_tasks_metadata |
metadata |
GIN |
idx_tasks_active_workflow_run_id |
active_workflow_run_id |
B-tree (001) |
idx_tasks_blocker_type |
blocker_type |
B-tree (004) |
idx_tasks_status_archived |
status, archived_at |
B-tree (20260216) |
idx_tasks_deleted_at |
deleted_at |
B-tree (20260216) |
idx_tasks_updated_at |
updated_at |
B-tree (20260216) |
Audit
audit_log
Tracks all significant changes to tasks.
| Column | Type | Constraints | Description |
|---|---|---|---|
id |
UUID |
PK, default uuid_generate_v4() |
|
task_id |
UUID |
FK → tasks(id) ON DELETE CASCADE, nullable |
Nullable for system-level entries |
actor |
TEXT |
NOT NULL | User or agent name |
action |
TEXT |
NOT NULL | create, update, delete, claim, release, move, import, etc. |
old_value |
JSONB |
nullable | Field snapshot before change |
new_value |
JSONB |
nullable | Field snapshot after change |
timestamp |
TIMESTAMPTZ |
NOT NULL, default NOW() |
|
entity_type |
TEXT |
default 'task' |
Entity type for non-task audit entries |
correlation_id |
UUID |
nullable | Groups related changes |
Indexes: task_id, timestamp, actor, action (20260216), (actor, action) (20260216)
Workflow Engine
workflow_runs
Tracks execution instances of workflows.
| Column | Type | Constraints | Description |
|---|---|---|---|
id |
UUID |
PK, default uuid_generate_v4() |
|
board_id |
UUID |
FK → projects(id) ON DELETE CASCADE, nullable |
|
task_id |
UUID |
FK → tasks(id) ON DELETE CASCADE, nullable |
|
workflow_type |
TEXT |
NOT NULL | e.g., affiliate-article, code-change |
owner_agent_id |
TEXT |
NOT NULL | Agent name |
initiator |
TEXT |
nullable | Who/what started the run |
status |
TEXT |
NOT NULL, default 'queued' |
See status values below |
current_step |
TEXT |
nullable | Current step name |
started_at |
TIMESTAMPTZ |
nullable | |
finished_at |
TIMESTAMPTZ |
nullable | |
last_heartbeat_at |
TIMESTAMPTZ |
nullable | Agent heartbeat |
retry_count |
INTEGER |
NOT NULL, default 0 |
|
max_retries |
INTEGER |
NOT NULL, default 3 |
|
last_error |
TEXT |
nullable | |
last_error_at |
TIMESTAMPTZ |
nullable | |
input_payload |
JSONB |
NOT NULL, default '{}' |
Task parameters |
output_summary |
JSONB |
NOT NULL, default '{}' |
Results, artifacts, URLs |
gateway_session_id |
TEXT |
nullable | Linked gateway session |
gateway_session_active |
BOOLEAN |
NOT NULL, default false |
|
created_at |
TIMESTAMPTZ |
NOT NULL, default NOW() |
|
updated_at |
TIMESTAMPTZ |
NOT NULL, default NOW() |
|
error_details |
JSONB |
default '{}' |
(020) Structured error info |
service_request_id |
UUID |
FK → service_requests(id) ON DELETE SET NULL, nullable |
(011) |
department_id |
UUID |
FK → departments(id) ON DELETE SET NULL, nullable |
(011) |
run_priority |
TEXT |
nullable | (011) |
approval_state |
TEXT |
nullable | (011) |
outcome_code |
TEXT |
nullable | (011) |
operator_notes |
TEXT |
nullable | (011) |
expected_artifact_count |
INTEGER |
NOT NULL, default 0 |
(011) |
actual_artifact_count |
INTEGER |
NOT NULL, default 0 |
(011) |
value_score |
NUMERIC |
nullable | (011) |
customer_scope |
TEXT |
nullable | (011) |
blocker_detected_at |
TIMESTAMPTZ |
nullable | (014) |
blocker_source |
TEXT |
nullable | (014) manual, detector, operator |
blocker_metadata |
JSONB |
NOT NULL, default '{}' |
(014) |
escalation_status |
TEXT |
nullable | (014) escalated, acknowledged, resolved |
escalated_at |
TIMESTAMPTZ |
nullable | (014) |
escalated_to |
TEXT |
nullable | (014) |
escalation_reason |
TEXT |
nullable | (014) |
paused_at |
TIMESTAMPTZ |
nullable | (014) Operator pause |
paused_by |
TEXT |
nullable | (014) |
pause_reason |
TEXT |
nullable | (014) |
resumed_at |
TIMESTAMPTZ |
nullable | (014) |
resumed_by |
TEXT |
nullable | (014) |
dispatched_at |
TIMESTAMPTZ |
nullable | (021) |
claimed_at |
TIMESTAMPTZ |
nullable | (021) |
claimed_by |
TEXT |
nullable | (021) |
claim_session_id |
TEXT |
nullable | (021) |
dispatch_attempts |
INTEGER |
NOT NULL, default 0 |
(021) |
input_tokens |
BIGINT |
nullable | (022) Prompt/input tokens consumed by the run |
output_tokens |
BIGINT |
nullable | (022) Completion/output tokens produced by the run |
cached_tokens |
BIGINT |
nullable | (022) Tokens served from cache (subset of input) |
model_id |
TEXT |
nullable | (022) Primary model used for this run |
cost_estimate |
NUMERIC(12,6) |
nullable | (022) Estimated cost of the run |
currency |
TEXT |
default 'USD' |
(022) ISO 4217 currency code for cost_estimate |
reported_at |
TIMESTAMPTZ |
nullable | (022) When usage/cost was last reported |
blocker_type |
TEXT |
nullable | (004) |
blocker_description |
TEXT |
nullable | (004) |
Constraint:
valid_workflow_run_status CHECK (status IN (
'queued', 'dispatched', 'claimed', 'running',
'waiting_for_approval', 'blocked', 'retrying',
'completed', 'failed', 'cancelled', 'timed_out'
))
Indexes: board_id, task_id, owner_agent_id, status, workflow_type, started_at, last_heartbeat_at, gateway_session_id, GIN on input_payload, GIN on output_summary, GIN on error_details, (status, dispatched_at), (status, last_heartbeat_at), claim_session_id, blocker_detected_at, escalation_status, escalated_to, paused_at
workflow_steps
Individual steps within a workflow run.
| Column | Type | Constraints | Description |
|---|---|---|---|
id |
UUID |
PK, default uuid_generate_v4() |
|
workflow_run_id |
UUID |
FK → workflow_runs(id) ON DELETE CASCADE, NOT NULL |
|
step_name |
TEXT |
NOT NULL | |
step_order |
INTEGER |
NOT NULL | |
status |
TEXT |
NOT NULL, default 'pending' |
(025) Step-native: pending, in_progress, completed, failed, skipped; plus dispatcher-vocabulary mirrored by agents onto their current step: queued, dispatched, claimed, running, waiting_for_approval, blocked, retrying, cancelled, timed_out. Writers must go through updateStep, which validates against the same list |
started_at |
TIMESTAMPTZ |
nullable | |
finished_at |
TIMESTAMPTZ |
nullable | |
output |
JSONB |
NOT NULL, default '{}' |
|
error_message |
TEXT |
nullable | |
created_at |
TIMESTAMPTZ |
NOT NULL, default NOW() |
|
updated_at |
TIMESTAMPTZ |
NOT NULL, default NOW() |
Constraint (025):
valid_workflow_step_status CHECK (status IN (
'pending', 'in_progress', 'completed', 'failed', 'skipped',
'queued', 'dispatched', 'claimed', 'running',
'waiting_for_approval', 'blocked', 'retrying',
'cancelled', 'timed_out'
))
Chosen vocabulary = step-native lifecycle (001) ∪ dispatcher v2 run statuses (021). Reality check: gateway sessions mirror run-level states (timed_out observed live 2026-08-25) onto their current step; the original five-value CHECK either rejected those writes or had never applied on drifted deployments (CREATE TABLE IF NOT EXISTS skips existing tables). Unknown status strings are rejected at the API layer (WORKFLOW_STEP_STATUSES in workflow-runs-api.js), not silently mapped.
Indexes: workflow_run_id, status, step_order
workflow_templates
Reusable workflow definitions.
| Column | Type | Constraints | Description |
|---|---|---|---|
id |
UUID |
PK, default uuid_generate_v4() |
|
name |
TEXT |
UNIQUE, NOT NULL | e.g., affiliate-article |
display_name |
TEXT |
NOT NULL | Human-readable name |
description |
TEXT |
NOT NULL, default '' |
|
default_owner_agent |
TEXT |
NOT NULL | Default agent for runs |
steps |
JSONB |
NOT NULL, default '[]' |
Ordered step definitions; canonical entry shape {name, display_name, required} (025 lifts bare strings on write + backfill) |
required_approvals |
JSONB |
NOT NULL, default '[]' |
Steps needing approval |
success_criteria |
JSONB |
NOT NULL, default '{}' |
Completion criteria |
category |
TEXT |
NOT NULL, default 'general' |
content, publishing, maintenance, incident, development, quality |
is_active |
BOOLEAN |
NOT NULL, default true |
|
department_id |
UUID |
FK → departments(id) ON DELETE SET NULL, nullable |
(011) |
service_id |
UUID |
FK → service_catalog(id) ON DELETE SET NULL, nullable |
(011) |
input_schema |
JSONB |
NOT NULL, default '{}' |
(011) |
artifact_contract |
JSONB |
NOT NULL, default '{}' |
(011) |
blocker_policy |
JSONB |
NOT NULL, default '{}' |
(011) |
escalation_policy |
JSONB |
NOT NULL, default '{}' |
(011) |
runbook_ref |
TEXT |
nullable | (011) |
ui_category |
TEXT |
NOT NULL, default 'general' |
(011) |
created_at |
TIMESTAMPTZ |
NOT NULL, default NOW() |
|
updated_at |
TIMESTAMPTZ |
NOT NULL, default NOW() |
Indexes: category, is_active, department_id, service_id, ui_category
workflow_artifacts
Trackable deliverables produced by workflow runs.
| Column | Type | Constraints | Description |
|---|---|---|---|
id |
UUID |
PK, default uuid_generate_v4() |
|
workflow_run_id |
UUID |
FK → workflow_runs(id) ON DELETE CASCADE, NOT NULL |
|
task_id |
UUID |
FK → tasks(id) ON DELETE SET NULL, nullable |
|
artifact_type |
TEXT |
NOT NULL | e.g., image, published_url, draft |
label |
TEXT |
NOT NULL | |
uri |
TEXT |
NOT NULL | URL or path |
mime_type |
TEXT |
nullable | |
status |
TEXT |
NOT NULL, default 'generated' |
generated, attached, approved, rejected, archived |
metadata |
JSONB |
NOT NULL, default '{}' |
|
created_by |
TEXT |
nullable | |
created_at |
TIMESTAMPTZ |
NOT NULL, default NOW() |
|
updated_at |
TIMESTAMPTZ |
NOT NULL, default NOW() |
Indexes: workflow_run_id, task_id, artifact_type, status, created_by, created_at DESC
workflow_approvals
Approval gates for workflow steps.
| Column | Type | Constraints | Description |
|---|---|---|---|
id |
UUID |
PK, default uuid_generate_v4() |
|
workflow_run_id |
UUID |
FK → workflow_runs(id) ON DELETE CASCADE, NOT NULL |
|
step_name |
TEXT |
NOT NULL | Workflow step requiring approval |
approver_id |
TEXT |
NOT NULL | User or agent who should approve |
status |
TEXT |
NOT NULL, default 'pending' |
pending, approved, rejected, cancelled |
decision |
TEXT |
nullable | Notes from approver |
decided_at |
TIMESTAMPTZ |
nullable | |
requested_by |
TEXT |
NOT NULL | Requester |
requested_at |
TIMESTAMPTZ |
NOT NULL, default NOW() |
|
metadata |
JSONB |
NOT NULL, default '{}' |
|
approval_type |
TEXT |
NOT NULL, default 'step_gate' |
(013) |
artifact_id |
UUID |
FK → workflow_artifacts(id) ON DELETE SET NULL, nullable |
(013) |
due_at |
TIMESTAMPTZ |
nullable | (013) |
expires_at |
TIMESTAMPTZ |
nullable | (013) |
escalated_at |
TIMESTAMPTZ |
nullable | (013) |
escalated_to |
TEXT |
nullable | (013) |
escalation_reason |
TEXT |
nullable | (013) |
required_note |
BOOLEAN |
NOT NULL, default true |
(013) |
decided_by |
TEXT |
nullable | (013) |
created_at |
TIMESTAMPTZ |
NOT NULL, default NOW() |
|
updated_at |
TIMESTAMPTZ |
NOT NULL, default NOW() |
Indexes: workflow_run_id, status, approver_id, artifact_id, due_at, expires_at, escalated_to
workflow_agent_routing
Maps workflow types to agents for dispatching. (021)
| Column | Type | Constraints | Description |
|---|---|---|---|
workflow_type |
VARCHAR(100) |
PK | Workflow type name |
agent_id |
VARCHAR(100) |
NOT NULL | Target agent |
priority |
INTEGER |
NOT NULL, default 0 |
Routing priority |
max_concurrent |
INTEGER |
NOT NULL, default 1 |
Concurrent run limit |
timeout_minutes |
INTEGER |
NOT NULL, default 60 |
Run timeout |
created_at |
TIMESTAMPTZ |
NOT NULL, default NOW() |
Indexes: agent_id, priority DESC
Organization
departments
Organizational groups for agents and workflows. (006)
| Column | Type | Constraints | Description |
|---|---|---|---|
id |
UUID |
PK, default gen_random_uuid() |
|
name |
VARCHAR(255) |
UNIQUE, NOT NULL | |
description |
TEXT |
nullable | |
color |
VARCHAR(7) |
default '#6366f1' |
Hex color for UI |
icon |
VARCHAR(50) |
default 'folder' |
Lucide icon name |
sort_order |
INTEGER |
default 0 |
|
is_active |
BOOLEAN |
default true |
|
metadata |
JSONB |
default '{}' |
|
created_at |
TIMESTAMPTZ |
default NOW() |
|
updated_at |
TIMESTAMPTZ |
default NOW() |
Indexes: sort_order, is_active
agent_profiles
Agent definitions linked to departments. (007)
| Column | Type | Constraints | Description |
|---|---|---|---|
id |
UUID |
PK, default gen_random_uuid() |
|
agent_id |
VARCHAR(255) |
UNIQUE, NOT NULL | Matches openclaw.json agent.id |
department_id |
UUID |
FK → departments(id) ON DELETE SET NULL, nullable |
|
display_name |
VARCHAR(255) |
NOT NULL | |
role |
VARCHAR(100) |
nullable | orchestrator, specialist, pipeline |
model_primary |
VARCHAR(255) |
nullable | Primary model from openclaw.json |
capabilities |
JSONB |
default '[]' |
e.g., ["coding", "vision"] |
status |
VARCHAR(50) |
default 'active' |
active, inactive, deprecated |
workspace_path |
TEXT |
nullable | Agent workspace directory |
metadata |
JSONB |
default '{}' |
|
last_heartbeat |
TIMESTAMPTZ |
nullable | |
created_at |
TIMESTAMPTZ |
default NOW() |
|
updated_at |
TIMESTAMPTZ |
default NOW() |
Indexes: agent_id, department_id, status
Service Catalog
service_catalog
Available service types that can be requested. (008)
| Column | Type | Constraints | Description |
|---|---|---|---|
id |
UUID |
PK, default gen_random_uuid() |
|
name |
VARCHAR(255) |
NOT NULL | |
slug |
VARCHAR(100) |
UNIQUE, NOT NULL | URL-friendly identifier |
description |
TEXT |
nullable | |
department_id |
UUID |
FK → departments(id) ON DELETE SET NULL, nullable |
|
default_agent_id |
VARCHAR(255) |
nullable | |
workflow_template_id |
UUID |
nullable | FK → workflow_templates(id) |
intake_fields |
JSONB |
default '[]' |
Form field definitions |
sla_hours |
INTEGER |
default 72 |
Service level agreement |
is_active |
BOOLEAN |
default true |
|
sort_order |
INTEGER |
default 0 |
|
metadata |
JSONB |
default '{}' |
|
created_at |
TIMESTAMPTZ |
default NOW() |
|
updated_at |
TIMESTAMPTZ |
default NOW() |
Indexes: slug, department_id, is_active
service_requests
Individual service requests. (009)
| Column | Type | Constraints | Description |
|---|---|---|---|
id |
UUID |
PK, default gen_random_uuid() |
|
service_id |
UUID |
FK → service_catalog(id) ON DELETE CASCADE, NOT NULL |
|
project_id |
UUID |
FK → projects(id) ON DELETE SET NULL, nullable |
|
task_id |
UUID |
FK → tasks(id) ON DELETE SET NULL, nullable |
|
requested_by |
VARCHAR(255) |
NOT NULL | |
requested_for |
VARCHAR(255) |
nullable | |
title |
TEXT |
NOT NULL | |
description |
TEXT |
default '' |
|
status |
VARCHAR(50) |
NOT NULL, default 'new' |
new, triaged, planned, running, waiting_for_approval, blocked, completed, failed, cancelled |
priority |
VARCHAR(50) |
NOT NULL, default 'medium' |
low, medium, high, critical |
target_department_id |
UUID |
FK → departments(id) ON DELETE SET NULL, nullable |
|
target_agent_id |
VARCHAR(255) |
nullable | |
input_payload |
JSONB |
default '{}' |
|
routing_decision |
JSONB |
default '{}' |
|
created_at |
TIMESTAMPTZ |
default NOW() |
|
updated_at |
TIMESTAMPTZ |
default NOW() |
Indexes: service_id, status, priority, target_department_id, target_agent_id, project_id, created_at DESC
Metrics
department_daily_metrics
Daily KPI snapshots per department. (015)
| Column | Type | Constraints | Description |
|---|---|---|---|
id |
UUID |
PK, default gen_random_uuid() |
|
department_id |
UUID |
FK → departments(id) ON DELETE CASCADE, NOT NULL |
|
metric_date |
DATE |
NOT NULL | |
metrics |
JSONB |
NOT NULL, default '{}' |
Structured scorecard payload |
created_at |
TIMESTAMPTZ |
NOT NULL, default NOW() |
|
updated_at |
TIMESTAMPTZ |
NOT NULL, default NOW() |
Unique: (department_id, metric_date)
Indexes: department_id, metric_date DESC
Observability
agent_heartbeats
Agent liveness tracking. (20260216)
| Column | Type | Constraints | Description |
|---|---|---|---|
agent_name |
TEXT |
PK | |
last_seen_at |
TIMESTAMPTZ |
NOT NULL, default NOW() |
|
status |
TEXT |
NOT NULL, default 'online' |
online, offline, error |
metadata |
JSONB |
NOT NULL, default '{}' |
Index: last_seen_at
task_runs
Execution attempt log for agent observability. (20260216)
| Column | Type | Constraints | Description |
|---|---|---|---|
id |
UUID |
PK, default uuid_generate_v4() |
|
task_id |
UUID |
FK → tasks(id) ON DELETE CASCADE, NOT NULL |
|
agent_name |
TEXT |
NOT NULL | |
attempt_number |
INTEGER |
NOT NULL | |
status |
TEXT |
NOT NULL | pending, running, success, failure |
started_at |
TIMESTAMPTZ |
NOT NULL, default NOW() |
|
completed_at |
TIMESTAMPTZ |
nullable | |
error_summary |
TEXT |
nullable | |
output_summary |
TEXT |
nullable |
Indexes: task_id, agent_name, started_at DESC, (task_id, agent_name, attempt_number)
cron_job_runs
Cron job execution history. (20260216)
| Column | Type | Constraints | Description |
|---|---|---|---|
id |
UUID |
PK, default uuid_generate_v4() |
|
job_id |
TEXT |
NOT NULL | |
started_at |
TIMESTAMPTZ |
NOT NULL, default NOW() |
|
finished_at |
TIMESTAMPTZ |
nullable | |
exit_code |
INTEGER |
nullable | |
output |
TEXT |
nullable | |
status |
TEXT |
NOT NULL, default 'running' |
running, success, failure |
duration_ms |
INTEGER |
nullable | |
created_at |
TIMESTAMPTZ |
NOT NULL, default NOW() |
Indexes: job_id, started_at DESC, status
Saved Views
saved_views
User-saved filter/sort combinations. (20260216)
| Column | Type | Constraints | Description |
|---|---|---|---|
id |
UUID |
PK, default uuid_generate_v4() |
|
project_id |
UUID |
FK → projects(id) ON DELETE CASCADE, NOT NULL |
|
name |
TEXT |
NOT NULL | |
filters |
JSONB |
NOT NULL, default '{}' |
|
sort |
TEXT |
nullable | |
created_by |
TEXT |
NOT NULL | |
created_at |
TIMESTAMPTZ |
NOT NULL, default NOW() |
|
updated_at |
TIMESTAMPTZ |
NOT NULL, default NOW() |
Indexes: project_id, created_by
Migration Tracking
schema_migrations
Records which migrations have been applied. (005)
| Column | Type | Constraints | Description |
|---|---|---|---|
id |
SERIAL |
PK | |
migration_name |
TEXT |
UNIQUE, NOT NULL | Migration file name |
applied_at |
TIMESTAMPTZ |
NOT NULL, default NOW() |
|
checksum |
TEXT |
nullable |
Views
| View | Purpose |
|---|---|
task_graph |
Tasks with project info, filtered to active projects |
blocked_tasks |
Tasks with unmet dependencies |
active_workflow_runs |
In-progress runs with task/project context and timing |
stuck_workflow_runs |
Runs that are stale, session-inactive, or max-retries-exceeded |
Triggers
All tables with updated_at columns have auto-update triggers:
| Trigger | Table | Function |
|---|---|---|
update_projects_updated_at |
projects |
update_updated_at_column() |
update_tasks_updated_at |
tasks |
update_updated_at_column() |
update_workflows_updated_at |
workflows |
update_updated_at_column() |
update_workflow_runs_updated_at |
workflow_runs |
update_updated_at_column() |
update_workflow_steps_updated_at |
workflow_steps |
update_updated_at_column() |
update_workflow_templates_updated_at |
workflow_templates |
update_updated_at_column() |
update_workflow_approvals_updated_at |
workflow_approvals |
update_updated_at_column() |
update_workflow_artifacts_updated_at |
workflow_artifacts |
update_updated_at_column() |
update_saved_views_updated_at |
saved_views |
update_saved_views_updated_at() |
update_department_daily_metrics_updated_at |
department_daily_metrics |
update_department_daily_metrics_updated_at() |
Time Travel
state_snapshots
Records full entity state at each mutation for point-in-time recovery and undo.
| Column | Type | Constraints | Description |
|---|---|---|---|
id |
UUID |
PK, default uuid_generate_v4() |
|
entity_type |
TEXT |
NOT NULL | 'task', 'project', 'workflow', 'view', 'setting', 'system' |
entity_id |
UUID |
NOT NULL | Entity UUID |
action |
TEXT |
NOT NULL | create, update, delete, move, archive, restore, revert, import |
state |
JSONB |
NOT NULL | Full entity state at this point |
actor |
TEXT |
NOT NULL, default 'system' |
Who made the change |
correlation_id |
UUID |
nullable | Links related snapshots |
created_at |
TIMESTAMPTZ |
NOT NULL, default NOW() |
Indexes: (entity_type, entity_id), created_at DESC, action, correlation_id
Spaces / Workspaces
workspaces (extended)
Multi-workspace support with per-space configuration.
| Column | Type | Constraints | Description |
|---|---|---|---|
id |
UUID |
PK, default gen_random_uuid() |
|
name |
VARCHAR(255) |
NOT NULL | Display name |
slug |
VARCHAR(100) |
NOT NULL, UNIQUE | URL-safe identifier |
icon |
TEXT |
default '📁' |
Emoji icon |
color |
TEXT |
default '#0078d4' |
Brand color |
description |
TEXT |
default '' |
What the space is for |
settings |
JSONB |
default '{}' |
Per-space settings |
is_default |
BOOLEAN |
default false |
Cannot be deleted |
sort_order |
INT |
default 0 |
Display order |
created_at |
TIMESTAMPTZ |
default NOW() |
|
updated_at |
TIMESTAMPTZ |
default NOW() |
Auto-updated via trigger |
Referenced by: tasks.workspace_id, cron_jobs.workspace_id
Migration History
| # | Migration | Date | Description |
|---|---|---|---|
| 001 | 001_add_workflow_runs.sql |
2026-03-11 | Add workflow_runs, workflow_steps, workflow_templates tables, views, seed templates |
| 002 | 002_add_workflow_queues.sql |
2026-03-11 | Extend task status constraint with workflow queue states |
| 003 | 003_add_approvals.sql |
2026-03-11 | Add workflow_approvals table |
| 004 | 004_add_blocker_classification.sql |
2026-03-11 | Add blocker_type and blocker_description to tasks and workflow_runs |
| 005 | 005_add_migration_tracking.sql |
— | Add schema_migrations table |
| 006 | 006_add_departments.sql |
— | Add departments table, seed 9 departments |
| 007 | 007_add_agent_profiles.sql |
— | Add agent_profiles table, seed 40+ agents |
| 008 | 008_add_service_catalog.sql |
— | Add service_catalog table, seed 8 services |
| 009 | 009_add_service_requests.sql |
— | Add service_requests table |
| 010 | 010_harmonize_service_catalog.sql |
— | Link services to workflow templates, add 8 more services |
| 011 | 011_extend_workflow_business_context.sql |
— | Add business context columns to templates and runs, backfill from services |
| 012 | 012_add_workflow_artifacts.sql |
— | Add workflow_artifacts table, backfill from output_summary URLs |
| 013 | 013_extend_workflow_approvals.sql |
— | Add due dates, escalation, artifact linking to approvals |
| 014 | 014_add_workflow_run_blocker_intelligence.sql |
— | Add blocker metadata and operator pause/resume to workflow_runs |
| 015 | 015_add_department_daily_metrics.sql |
— | Add department_daily_metrics table |
| 020 | 020_add_error_details_to_workflow_runs.sql |
2026-03-21 | Add error_details JSONB column to workflow_runs |
| 021 | 021_add_workflow_agent_routing.sql |
2026-03-22 | Add workflow_agent_routing table, dispatch/claim columns |
| 022 | 022_add_run_token_cost_tracking.sql |
2026-08-23 | Add per-run token/cost tracking columns to workflow_runs (roadmap Phase 0) |
| 20260216a | 20260216_add_agent_observability.sql |
2026-02-16 | Add agent_heartbeats and task_runs tables, retry_count on tasks |
| 20260216b | 20260216_add_archive_deleted_to_tasks.sql |
2026-02-16 | Add archived_at and deleted_at to tasks |
| 20260216c | 20260216_add_audit_log_search_indexes.sql |
2026-02-16 | Add action and (actor, action) indexes to audit_log |
| 20260428a | 20260428_add_state_snapshots.sql |
2026-04-28 | Add state_snapshots table, extend audit_log with entity_type, correlation_id |
| 20260429a | 20260429_extend_workspaces.sql |
2026-04-29 | Extend workspaces with icon, color, description, is_default, sort_order |
| 20260216d | 20260216_add_cron_job_runs.sql |
2026-02-16 | Add cron_job_runs table |
| 20260216e | 20260216_add_saved_views.sql |
2026-02-16 | Add saved_views table |
| 20260216f | 20260216_add_updated_at_index_to_tasks.sql |
2026-02-16 | Add updated_at index to tasks for incremental sync |
| 20260429b | 20260429_spaces_constraints.sql |
2026-04-29 | Enforce single default workspace via partial unique index on workspaces.is_default |
| 022 | 022_add_run_token_cost_tracking.sql |
2026-08-23 | Add per-run token/cost tracking to workflow_runs: input_tokens, output_tokens, cached_tokens, model_id, cost_estimate, currency, reported_at |
| 023 | 023_add_budget_ledger.sql |
2026-08-24 | Add budgets rules + budget_events append-only audit trail (budget ledger slice 1) |
| 024 | 024_add_action_receipts.sql |
2026-08-24 | Add action_receipts idempotency latch + persisted operator-action receipts (one-click actions slice 1) |
| 025 | 025_add_workflow_normalization.sql |
2026-08-25 | Debt D1 normalization: widen workflow_steps status CHECK to step-native ∪ dispatcher-vocabulary (14 values); lift string-only workflow_templates.steps into {name, display_name, required} objects (idempotent, order-preserving) |
| 20260826a | 20260826_audit_log_task_id_nullable.sql |
2026-08-26 | Make audit_log.task_id nullable — task-less system events (MCP adoption telemetry, workflow-graph events) append rows with task_id NULL; aligns canonical DDL with prod reality + docs (drift fix) |
Budget Ledger Tables
budgets (023)
Named spending rules; spend is derived from workflow_runs (migration 022) at evaluation time, never stored twice.
| Column | Type | Notes |
|---|---|---|
id |
UUID |
PK, default gen_random_uuid() |
name |
TEXT |
NOT NULL — operator-facing label |
scope |
TEXT |
NOT NULL, CHECK: agent | department | project | fleet |
scope_id |
TEXT |
nullable — agent id / department id / workflow_type; NULL only for fleet |
period |
TEXT |
NOT NULL, CHECK: daily | weekly | monthly |
cap_usd |
NUMERIC(12,6) |
nullable — XOR with cap_tokens (table CHECK) |
cap_tokens |
BIGINT |
nullable — over input_tokens + output_tokens; XOR with cap_usd |
action_on_exceed |
TEXT |
NOT NULL, CHECK: warn | pause_new_runs | hard_stop |
active |
BOOLEAN |
NOT NULL, default true |
created_at |
TIMESTAMPTZ |
NOT NULL, default now() |
Indexes: partial unique uq_budgets_active_scope_period (scope, COALESCE(scope_id, ''), period) WHERE active — one active budget per scope+period; idx_budgets_scope_period (scope, period, active).
budget_events (023)
Append-only enforcement audit trail. UNIQUE (budget_id, period_key, event_kind) is the idempotency latch (ON CONFLICT DO NOTHING) so repeated dispatcher ticks never duplicate an event.
| Column | Type | Notes |
|---|---|---|
id |
BIGSERIAL |
PK |
budget_id |
UUID |
NOT NULL, FK → budgets(id) ON DELETE CASCADE |
period_key |
TEXT |
NOT NULL — e.g. 2026-08-24 / 2026-W35 / 2026-08 |
event_kind |
TEXT |
NOT NULL, CHECK: warned | paused | hard_stopped | recovered |
detail |
JSONB |
nullable — spend at breach, affected run ids, actor |
created_at |
TIMESTAMPTZ |
NOT NULL, default now() |
Indexes: unique (budget_id, period_key, event_kind); idx_budget_events_budget_created (budget_id, created_at DESC).
Action Receipts Tables
action_receipts (024)
One receipt per executed operator action (one-click actions slice 1). The primary key IS the idempotency latch: a replayed client-minted action_id returns the stored row (duplicate:true) instead of re-executing; the same action_id with a different params_hash is a stale retry (HTTP 409) and never executes.
| Column | Type | Notes |
|---|---|---|
action_id |
TEXT |
PK — client-minted UUID, one per confirmed intent; retries reuse it, a deliberate repeat mints a new one |
kind |
TEXT |
NOT NULL, CHECK: task.assign | run.dispatch | approval.decide | run.cancel | run.redispatch |
target_id |
TEXT |
NOT NULL — task / approval / run id per kind |
params_hash |
TEXT |
NOT NULL — sha256 over canonical JSON (sorted keys) of params; staleness guard |
actor |
TEXT |
NOT NULL, default 'dashboard-operator' |
outcome |
TEXT |
nullable, CHECK: executed | rejected_governance | blocked_budget | failed | duplicate; NULL while executing (latch inserted before the side effect). Budget-blocked refusals are answered pre-latch and intentionally leave NO receipt so the action stays retryable after a cap raise |
rollback_hint |
TEXT |
nullable — human-readable recovery move shown before confirm and in the tray; hints only, nothing auto-reverts |
detail |
JSONB |
nullable — executor result ids (e.g. new run_id), governance verdict, error text |
created_at |
TIMESTAMPTZ |
NOT NULL, default now() |
Indexes: idx_action_receipts_created (created_at DESC) for the recent-receipts feed. Every completed receipt is mirrored into audit_log (action = 'action.<kind>') in the same transaction that stamps the outcome.
Seeded Data
Workflow Templates (7)
| Name | Category | Default Agent |
|---|---|---|
affiliate-article |
content | affiliate-editorial |
image-generation |
content | comfyui-image-agent |
wordpress-publish |
publishing | 3dput |
site-fix |
maintenance | 3dput |
incident-investigation |
incident | main |
code-change |
development | coder |
qa-review |
quality | qa-auditor |
Departments (9)
Core Platform, Content & Publishing, Bug Fix Pipeline, Security Pipeline, Feature Development, Web Properties, Media & Vision, Research & Analysis, Automation.
Service Catalog (16)
Bug Report, Security Issue, Feature Request, Content Creation, Data Research, Image Generation, Website Update, General Request, Affiliate Article, Image Pack, WordPress Publish, Site Fix, Incident Investigation, Code Change, QA Review, Topic Research.