Roadmap — June 2026 (~4 weeks)
Four parallel threads coming out of the May session, sequenced so each week builds on the last. Estimates use Fibonacci story points (1, 2, 3, 5, 8) calibrated to ~10–15 points/week of capacity for one engineer.
Threads at a glance
| Thread | Scope | Total points |
|---|---|---|
| A. Close the Linear loop | 3 PRs | 8 |
| B. Quinn PR autonomy (close_pr / close_issue) | 2 PRs | 5 |
| C. Clawpatch on any repo (worktree checkouts) | 4 PRs | 13 | | D. Dashboard phase 3 (trace view + layout + drawer) | 3 PRs | 13 | | E. Cleanup + release hygiene | 4 small PRs | 5 | | Total | 16 PRs | 44 |
Week 1 (~13 pts) — Unblock the autonomous loop
Focus: get Quinn to a fully self-sufficient review loop AND wire Linear inbound to its first consumer. Both are short, both unblock follow-on work.
B1 — pr_inspector close_pr action (3 pts)
Root cause of the #556 cascade was Quinn deciding to file an issue asking someone else to close a PR because she had no close_pr tool herself. Add it.
- Files:
src/api/pr-inspector.ts,src/executor/executors/deep-agent-executor.ts(tool schema),workspace/agents/quinn.yaml(toolbelt + prompt) - Actions:
close_pr,close_pr_as_not_planned,reopen_pr - Auth: same
@protoquinn[bot]App identity already in use for reviews - Test plan: smoke a self-PR close on a draft test PR
B2 — pr_inspector close_issue action — ✅ SHIPPED (PR #787)
Same shape as B1, but for issues. Quinn's bug_triage skill was filing issues asking for issue closure because she couldn't close them herself.
- Files: extend the route from B1 + tool schema
- Actions:
close_issue,close_issue_as_not_planned,reopen_issue,comment_on_issue - Prompt update:
bug_triageresolves "already_fixed" / "duplicate" / "stale" by closing directly with a linking comment instead of filing a meta-issue
Shipped as
lib/github-issues.tscloseIssue()+IssueCloserPlugin. The close-the-loop landed as an event-driven consumer that closedrepo#githubIssueNumberwith a linking comment rather than a Quinn-drivenpr_inspectoraction. (That completion-event consumer belonged to the board integration, since removed; the underlyingcloseIssue()helper remains reusable for the agent-drivenbug_triageresolution path described above.)
A1 — Wire linear.* inbound to Ava (2 pts)
Webhooks → bus is done (May session). channels.yaml Linear routes are still commented out. Uncomment them + map to Ava with skill hint linear_handle. Smallest possible change to make events stop falling into the void.
- Files:
workspace/channels.yaml(uncomment + reshape),workspace/agents/ava.yaml(addlinear_handleskill + tools) - Skill hint: messages →
agent.skill.requestwithtargets: [ava], skill: linear_handle - Test plan: trigger a Linear comment, observe Ava dispatching
A2 — AppUserNotification handler in Ava (3 pts)
The Agent SDK envelope shape we landed in #545 publishes message.inbound.linear.agent.{action}. Ava needs to know what to do with each — issueMention and issueCommentMention reply via linear.reply.{issueId}, issueAssignedToYou triages.
- Files:
workspace/agents/ava.yaml(newlinear_agent_respondskill withsystemPromptOverridefor each notification type) - Tools scoped to:
linear_list_issues,linear_get_issue,linear_add_comment(already exists),chat_with_agentfor fleet-agent delegation
E1 — Apply publish.yml to release-tools (1 pt)
Copy the protoPatch publish workflow to protoLabsAI/release-tools. Same pattern, no surprises.
E2 — Apply publish.yml to protoCLI (1 pt)
Same as E1 for protoLabsAI/protoCLI. Makes future proto releases follow the same git tag → publish flow.
E3 — Restore A2A agents in /api/agents/runtime (1 pt)
The new endpoint groups by (agentName ?? executor.type) but A2A executors register via registerDefault (not per-skill), so protopen and ORBIS are missing from the dashboard. Extend ExecutorRegistry to expose default registrations too, or pull from the existing /api/agents yaml as a fallback for the dashboard.
- Files:
src/executor/executor-registry.ts(addlistDefault()?),src/api/agents-runtime.ts
Week 1 deliverable: Quinn never files a "please close this" issue again. Ava starts reacting to Linear comments. Three more repos publish on git tag.
Week 2 (~10 pts) — Linear close-the-loop + release hygiene cleanup
A3 — Board done → Linear comment (3 pts) — GitHub analog ✅ SHIPPED (PR #787)
This item belonged to the board integration, since removed. The GitHub analog — close-the-loop via
IssueCloserPlugin(PR #787) — did ship: a completion event closed the originatingrepo#githubIssueNumberwith a comment linking the shipped PR. The Linear-specific bridge side was never wired and is moot now that the board integration is gone.
E4 — Trusted Publishing migration for protoPatch (2 pts)
Replace the Classic Automation token with OIDC-based Trusted Publishing per npm's docs. Required because:
- Trusted Publishing has no secret to leak or rotate
- Provenance attestation is stronger (workflow identity tied to repo+branch)
- Sets the pattern other published packages migrate to
- Steps: configure on npmjs.com/package/@protolabsai/protopatch/access; remove
env: NODE_AUTH_TOKENfrompublish.yml; verify next publish succeeds without the token; finally delete the org-levelNPM_TOKEN - Reference: https://docs.npmjs.com/trusted-publishers
E5 — Trusted Publishing for release-tools + protoCLI (2 pts)
Same migration as E4 for the other two packages now that they publish.
A3.5 — Linear webhook delivery logs surface (1 pt)
Smaller follow-on: add [linear] event=issueCommentMention delivered to <agent> to the per-event log line so we can debug routing without grep-ing for the topic name.
Reserve: 2 pts for spillover from week 1 (B1/B2/A2 are agent-side and may bleed)
Week 2 deliverable: Linear is fully bidirectional. Quinn dispatches on Linear @mentions land back in Linear as comments. All three packages publish without token credentials.
Week 3 (~13 pts) — Clawpatch on any repo
The biggest single thread. Today clawpatch_review only works for repos hard-coded in the built-in mount map (protoWorkstacean / protoCLI / mythxengine). Adding on-demand checkout makes Quinn's structural review work for every repo she reviews.
C1 — Design doc + RFC (2 pts)
Write docs/explanation/clawpatch-checkouts.md covering:
- Source of truth: GitHub tarball API (
GET /repos/{owner}/{repo}/tarball/{ref}) - Cache:
/data/checkouts/<owner>-<repo>/<sha>/— content-addressed by ref - Cache invalidation: LRU eviction at 5 GB or 50 entries (whichever first)
- Security: enforce
repoagainstworkspace/projects.yamlallow-list (same ascreate_github_issue); no symlink traversal in tarball extract - Concurrency: per-(repo, sha) mutex so the same PR head doesn't extract twice
- TTL: rebuild if checkout is older than 24h (lets us pick up base branch drift even with the same sha)
Get sign-off before implementing.
C2 — Implement on-demand fetch + extract (5 pts)
src/api/clawpatch.ts extends resolveRepoPath():
- If
repois in the built-in mount map → use it (today's behavior) - Else: extract
<repo>@<since>to/data/checkouts/<repo>-<sha>/ - Return the extracted path to clawpatch
- Files:
src/api/clawpatch.ts, newlib/checkout-cache.ts - Uses
makeGitHubAuth()for the tarball download (same App credentials as everything else) - Unit tests on the cache helpers (LRU eviction, content-address shape, tarball-vs-symlink rejection)
C3 — Cache cleanup ceremony (3 pts)
Daily ceremony at 03:00 UTC that prunes the checkout cache to the LRU limit + deletes anything older than 7 days. Lives in workspace/ceremonies/clawpatch-cache-cleanup.yaml as a function executor (no agent needed — pure janitorial).
C4 — Quinn prompt update + drop the built-in mount map (3 pts)
- Quinn's
pr_reviewprompt removes the "v1 only handles protoWorkstacean / protoCLI / mythxengine" caveat src/api/clawpatch.tsremoves theBUILT_IN_REPO_PATHSmap (everything goes through the checkout cache)- Documented migration: keep the built-in paths as the cache's fast path for the three already-mounted repos
Week 3 deliverable: Quinn's structural review works against escape-from-qud, protoContent, homelab-iac, anything in the managed-repos allowlist.
Week 4 (~13 pts) — Dashboard phase 3
Now that /system shows the live system, phase 3 turns it into a debugger.
D1 — Skill-trace view (5 pts)
/system/trace/:correlationId — for any agent.skill.request we've seen in the WS history buffer, render the full causal chain:
10:42:01.123 message.inbound.github.opened.534 github
↓
10:42:01.180 agent.skill.request router
↓ targets=[quinn]
10:42:01.215 agent.runtime.activity.skill.start skill-dispatcher
↓ skill=pr_review
10:42:01.530 deep-agent:quinn tool calls=[pr_inspector, clawpatch_review]
↓
10:42:04.213 agent.runtime.activity.skill.complete (3098ms)
↓
10:42:04.290 agent.skill.response.{corrId} skill-dispatcherLangfuse-style waterfall. Click-to-jump to Langfuse for the LLM call detail.
- Files:
dashboard/src/components/SkillTrace.tsx, new bus-history endpointGET /api/bus/history?correlationId=...that returns the last N msgs matching that ID - Bus-history backend: in-memory ring buffer in
src/event-bus/history-recorder.ts, capped at 10k events with 30-min TTL
D2 — Force-directed layout (3 pts)
Concentric rings break down at >30 nodes. Swap to a force-directed layout via @xyflow/elk or dagre. Keep the visual hierarchy (agents attractor in center, services repel to perimeter).
- Files:
dashboard/src/components/SystemGraph.tsx - Layout reruns on topology change but not on activity change (otherwise nodes jitter when an agent dispatches)
D3 — Edge inspection drawer (5 pts)
Click a pulsing edge → side panel opens showing the last N messages that traveled on that topic with payload preview + jump-to-trace.
- Files:
dashboard/src/components/MessageDrawer.tsx, extend the WS subscription to retain history per-topic - "Jump to trace" → routes to
/system/trace/:correlationIdfrom D1
Week 4 deliverable: /system is the primary debugging surface. docker logs is the fallback, not the front line.
Cross-thread principles
- One PR per phase. Don't batch — each PR ships independently green.
- Bus contract changes go via plugin
publishes/subscribesdeclarations. No silent topic introductions. - Activity events are best-effort. A failed bus publish must never break a running skill (#565 set this rule — keep it).
- All new endpoints declared in the plugin's contract. Phase 3 will probably show "endpoints with no consumer" cleanly.
- Roadmap is a guide, not a contract. If a thread reveals real architectural change needed, file it as a separate roadmap doc and re-sequence.
Out of scope for this roadmap
- GraphQL on top of the bus (interesting but big — separate quarter)
- Multi-node BusBridgePlugin to NATS/Redis (only when actually needed)
- Quinn voice / Discord-native PR review surface (different shape entirely)