--- kind: task slug: runs-table-and-trpc-router title: Runs table, tRPC router, and minimal recent-runs UI plan_slug: agent-coordination epic_slug: task-as-runnable-unit status: ready priority: P2 tenant_id: global owner: unassigned cursor_todo_id: null updated_at: "2026-06-01" --- # Task summary Every agent session against a task gets a `runs` row. Add the table, a tRPC router for reads, and a minimal UI to see recent runs. ## Description ### Schema New table `agent_runs`: - `id` uuid pk - `workspace_id` uuid not null (indexed) - `backlog_item_id` uuid not null references `markdown_backlog_items.id` on delete cascade - `actor_user_id` uuid null references `users.id` (null = anonymous / dev session) - `started_at` timestamptz default now (not null) - `finished_at` timestamptz null - `outcome` varchar null — one of `succeeded`, `failed`, `cancelled`, `stalled` (matches Symphony's normalized vocabulary) - `error` text null - `tokens_input` integer null - `tokens_output` integer null - `tokens_total` integer null - `notes` text null — short string the agent (or operator) can write to summarize the run - `metadata` jsonb null — extensible; keep small - Indexes: `(workspace_id, started_at desc)` for the recent-runs query, `(backlog_item_id, started_at desc)` for the per-task history. ### tRPC router New `apps/web/server/routers/runs.ts`: - `runs.listRecent({ workspaceSlug, limit?: number })` — workspace-scoped, default limit 25. - `runs.listForTask({ workspaceSlug, backlogItemId })` — workspace-scoped + verify the item belongs to the workspace. - `runs.summary({ workspaceSlug })` — counts by `outcome` for the last 7 days, plus aggregate `tokens_total`. Mirror the shape of Symphony's `GET /api/v1/state` snapshot but adapted to our domain. ### UI 1. **Workspace settings**: new route `/[workspaceSlug]/settings/runs` showing the last 25 runs, paginated, with task title, started, finished, outcome, token total. Filter by outcome. 2. **Task detail panel**: a "Recent runs" sub-section listing the last 5 runs for the current task. 3. **Workspace home (after `Task-wire-workspace-home-dashboard`)**: add a small "Agent runs this week" card sourced from `runs.summary`. ### What this task does NOT do - It does *not* implement `claim_task` / `complete_task` (next epic). Those are the *write path* for these rows. This task is read-side + storage only. - It does not implement an orchestrator. Rows can be inserted manually for testing. ### Token accounting note Mirror Symphony's lesson: prefer absolute thread totals (`tokens_total`) over per-call deltas, and avoid double-counting. Since this table is written by the MCP tools (next epic), the agent reports a single `tokens_total` at close-out time, not incremental deltas. ## Subtasks - [ ] Schema + migration for `agent_runs`. - [ ] tRPC router with the 3 procedures. - [ ] Settings runs view with pagination + outcome filter. - [ ] Task detail panel "Recent runs" section. - [ ] Hook the workspace-home "Agent runs this week" card (skip if the home dashboard task hasn't landed yet — file a follow-up). ## Owner or assignee Unassigned ## Status ready ## Estimation M ## Acceptance criteria - [ ] Inserting a synthetic `agent_runs` row makes it appear in all three UI surfaces. - [ ] All queries filter by `workspace_id` and verify membership. - [ ] Outcome filter works on the settings view. - [ ] Pagination doesn't show >25 rows per page. ## Links to related Epic / Plan - Epic: `./Epic-task-as-runnable-unit.md` - Plan: `../Plan-agent-coordination.md`