In-flight work from 2026-06-05 that was sitting uncommitted on feat/agent-pipeline-bridge for 10 days. Moved here to a clean branch off main so the bridge branch can stay at its committed state (the DEFERRED Phase 2a snapshot, see stwl-labs/ubiquitous-invention#3). Touched areas: - apps/web/app/(app)/[workspaceSlug]/settings/runs/page.tsx — runs page UI iteration - apps/web/server/routers/{backlog,runs}.ts — router updates - apps/web/app/(app)/[workspaceSlug]/plans/[planSlug]/[epicSlug]/[taskSlug]/page.tsx — new deep-link route - apps/web/components/backlog/workflow-prompt-section.tsx — new component - config/CursorSync.md — coordination doc tweak - docs/operations/README.md + 2026-06-05-db-drift-reconcile-oauth-tables.sql — operations ops note + reconcile script - plans/Plan-agent-coordination/Epic-task-as-runnable-unit/Task-{workflow-prompt-task-detail-ui,deep-link-runs-to-task-detail}.md — 2 task specs This is a working-tree snapshot, not a finished PR. Rebase, split, or amend as needed when picking it back up. Co-authored-by: Cursor <cursoragent@cursor.com>
5.4 KiB
| kind | slug | title | plan_slug | epic_slug | status | priority | tenant_id | owner | cursor_todo_id | updated_at |
|---|---|---|---|---|---|---|---|---|---|---|
| task | deep-link-runs-to-task-detail | Deep-link agent runs to task detail + document MCP stdio staleness | agent-coordination | task-as-runnable-unit | done | P2 | global | unassigned | null | 2026-06-03 |
Task summary
Two small follow-ups from Task-workflow-prompt-task-detail-ui so the editor surface is actually reachable, and from Task-export-db-to-markdown-frontmatter so the next operator doesn't spend an hour debugging a stale MCP process.
Description
(1) Linkify /settings/runs rows → task detail page
Today the task title cell in /settings/runs is plain text. The route I just shipped lives at /[workspaceSlug]/plans/[planSlug]/[epicSlug]/[taskSlug] but you can only reach it by typing the URL. Closing this gap unlocks the dogfood loop: claim a task via MCP → run appears in /settings/runs → click through to inspect / edit the workflow prompt.
Concretely:
runs.listRecentandruns.listForTaskalready joinmarkdown_backlog_items; addplanSlug,epicSlug, andslugto the selects.- In
app/(app)/[workspaceSlug]/settings/runs/page.tsx, wrap the task title cell in anext/link<Link>when the joined row has all three slugs andtaskKind === "task". Plans/epics don't have a detail page yet, so render those titles unlinked. - Stop the link click from also toggling the row's expand/collapse handler (e.g.
e.stopPropagation()).
(2) Document MCP stdio process staleness
Symptom: complete_task returned without an export field and the on-disk .md file stayed status: draft even though the DB row flipped to done. Direct calls to exportBacklogItemToMarkdown work fine.
Root cause: the MCP server is launched by Cursor as tsx --env-file=../../.env src/index.ts (NOT tsx watch) and lives for the duration of the chat session. tsx imports the module graph once at startup; subsequent edits to apps/mcp-server/**/*.ts or any imported library (packages/database/src/markdown-backlog/**) don't take effect until the process is killed and Cursor reconnects. Worse, multiple stale MCP processes can accumulate from prior sessions; if Cursor binds the new session to one of those, you'll be talking to even older code.
This is a process-lifecycle gotcha, not a code bug — but it bit me right after we shipped the export feature, which means the next operator will hit it too.
Document in config/CursorSync.md under a new "MCP server lifecycle" section:
- The server is spawned once per Cursor chat session via
.cursor/mcp.json. - Changes to
apps/mcp-server/**or any importedpackages/database/**library require restarting the Cursor session (or killing the staletsx ... src/index.tsprocess and starting a new chat). - How to find and kill stale processes:
pgrep -fa "apps/mcp-server.*src/index.ts". - Why we don't run
tsx watch: a process restart would drop the stdio JSON-RPC connection mid-call.
Also add a one-liner pointer from AGENTS.md (the dev-loop section) so it's discoverable without grepping.
Out of scope for this task: actually fixing the staleness (would need a graceful-reload protocol or a switch to tsx watch with reconnection logic in the client). Documenting is the cheap, correct first step.
Subtasks
- Add
planSlug/epicSlug/slugtoruns.listRecentandruns.listForTaskselects. - Wrap the task title cell in
/settings/runsin aLinkwhen all three slugs are present andtaskKind === "task". - Update
config/CursorSync.mdwith an "MCP server lifecycle" section. - Add a one-line pointer in
AGENTS.md.
Acceptance criteria
- Clicking the task title in
/settings/runsnavigates to the task detail page (and does NOT also toggle the row's expand/collapse). pnpm lint && pnpm type-check && pnpm testclean.config/CursorSync.mdexplains MCP staleness and how to recover, andAGENTS.mdpoints at it.
Implementation notes
- Selects: added
taskSlug/taskPlanSlug/taskEpicSlugto bothruns.listRecentandruns.listForTask(same shape on both for client-side reuse). - Link wiring: new
buildTaskHref()helper in the runs page returnsnullfor plans/epics, for rows missing any path segment, and during the initial render beforeworkspaceSlugis known. The cell rendersrow.taskTitleunlinked in those cases so the table doesn't flicker between linked/unlinked. - Click stop:
onClick={(e) => e.stopPropagation()}on the<Link>so the surrounding row's expand/collapse handler doesn't fire on link clicks. Verified via the AC. - One real surprise during verification:
pnpm type-checkfailed against a stale.next/types/...generated file (Next.js's per-page type validator was tripping on an unrelated pre-existingexport function formatDurationin the runs page). Removingapps/web/.next/typesand re-running cleared it. Logged because the next operator may hit it after the dev server has been running across a refactor.
Follow-ups
- The exported helper
formatDurationin the runs page should either be moved to a shared util (it's now informally part of the runs-row contract) or have itsexportkeyword dropped. Out of scope here. - Linking plan/epic titles from the runs page once a plans-tree browser exists.
Links
- Parent surface:
./Task-workflow-prompt-task-detail-ui.md - Sync contract:
../../config/CursorSync.md - Epic:
./Epic-task-as-runnable-unit.md