Skip to content

feat(server): add oRPC 2 control-plane transport - #25

Merged
kodiakhq[bot] merged 5 commits into
mainfrom
feat/orpc-control-plane
Aug 10, 2026
Merged

feat(server): add oRPC 2 control-plane transport#25
kodiakhq[bot] merged 5 commits into
mainfrom
feat/orpc-control-plane

Conversation

@RedStar071

@RedStar071RedStar071 commented Aug 10, 2026

Copy link
Copy Markdown
Member

Summary

Adds apps/server: a typed oRPC 2 control-plane transport exposing health, tasks.list/get/create, and approvals.decide over a plain Node HTTP listener, plus one aggregate GET /api/dashboard endpoint for the dashboard to consume. This restores the control-plane half of the productionization work merged as PR #21 (6277cd2 in the original branch), which was stripped out of that PR before merge — main currently ships the frontend-only dashboard shell with no data source behind it.

Review follow-up (97be63c)

Control-plane mutations now fail closed behind an operator-issued access policy: AGENT_ZERO_CONTROL_PLANE_TOKENS (comma-separated name:token bearer credentials) authenticates callers, AGENT_ZERO_CONTROL_PLANE_REPOSITORIES allow-lists the paths tasks.create may target, and approval decisions record the authenticated principal's name instead of a wire-supplied actor. Reads stay open for the dashboard.

constauthenticated=procedure.use(({ context, next })=>{constprincipal=context.principal;if(!principal)thrownewORPCError('UNAUTHORIZED',{message: 'Authentication required'});returnnext({context: { principal }});});

TaskScheduler also now enforces maxQueued for per-repository-blocked submissions even while global capacity is free, so blocked work can no longer grow the queue without bound.

Review follow-up (5e838dd)

Execution modes are now part of the per-principal policy: AGENT_ZERO_CONTROL_PLANE_MODES (comma-separated name:mode|mode grants) controls which modes each principal may request, tasks.create rejects ungranted modes, and principals without a grant are limited to the non-writable observe and suggest modes, so fix and autonomous require an explicit operator grant.

Why

main's apps/dashboard has no backend: the index page renders an empty DashboardOverview with a no-op refresh. apps/server is the composition root that resolves repository policy, constructs a runner, persists task history, and schedules work — the missing piece the dashboard is meant to read from.

Ported forward rather than copied verbatim, adapted to main as it stands after #22 (runner write-anchoring/local review scope) and #23 (Node 22.18 baseline):

  • Built with tsdown like packages/cli, instead of the Nitro 3 beta + vue-tsc pipeline apps/dashboard already owns (Nitro 3/h3 v2/unstorage are all pre-release; a plain Node HTTP listener needed none of that).
  • Persistence is a KeyValueStorage contract with a filesystem implementation by default (FileKeyValueStorage), so Redis, KV, or a Nitro storage driver drop in unchanged without pulling Nitro into this package.
  • Listens on port 3001 by default (PORT env override) so aube run dev can start the dashboard (3000) and the control plane together without a port collision.

Verification

Safety and compatibility

  • Added deterministic tests for the new package: router.test.ts (ported), control-plane.test.ts (ported), rpc.test.ts, dashboard.test.ts, storage.test.ts, index.test.ts — none touch the network or depend on wall-clock timing.
  • observe stays read-only; the control plane's runTask is the same composition root the CLI uses and still resolves mayModifyRepository before constructing a runner.
  • Runtime commands and target-repository writes stay behind packages/runner; apps/server only validates, delegates, and persists.
  • Stored task records are redacted (redactSecrets) before persistence and never include review input or checkout paths.
  • Updated docs/architecture.md, AGENTS.md/CLAUDE.md, README.md, and added the orpc-server Agent Skill (with its .agents/skills symlink) describing the transport's boundaries.

Reviewer notes

  • oRPC pinned to 2.0.0-beta.26 (same version the original branch used) since 2.x is still in beta; @orpc/server's stable 1.x line predates the context-based procedure API this router relies on.
  • packages/runner's 2 failing tests are unrelated to this PR — they fail identically on main at c3642cf on this Windows environment and are out of scope here.

View with [code]smith
Need help on this PR? Tag @codesmith-bot with what you need. Autofix is enabled.

Confidence Score: 5/5

No blocking failure remains.

No accepted blocking findings remain after the scheduler capacity scenario was exercised against the current implementation.

T-Rex T-Rex Logs

What T-Rex did

  • Prepared a narrow authorization harness for anonymous task creation and approvals, then attempted a focused RPC test, but the run could not start because the Aube package manager is unavailable.
  • Used a self-contained Node harness to exercise the repository queue path before and after the change; before the change a third repository-A submission with active=1 and queued=1 grew the queue to two, but after the change the same submission was rejected with TaskQueueQuotaError and the queue remained at one.
  • Documented that rpc.ts applies authenticated middleware to mutations, derives the approval actor from context.principal.name, rejects ungranted modes, and that approvalInput does not accept an actor field; the executable harness failed to load due to module resolution for @orpc/server and the missing Aube dependency blocked the focused test.
  • Compared the pre- and post-change queue states and observed the quota-bound behavior: the pre-change run accepted a third submission (active=1, queued=1, queue became 2) while the post-change run rejected with TaskQueueQuotaError and left the queue at active=1, queued=1; initial Vitest execution could not run due to missing dependencies and Aube, but the self-contained harness exercised the scheduler path.

View all artifacts

T-Rex Ran code and verified through T-Rex

Reviews (3): Last reviewed commit: "fix(server): validate mode grants with a..." | Re-trigger Greptile

Add apps/server: a typed oRPC 2 router (health, tasks.list/get/create,
approvals.decide) over a plain Node HTTP listener, plus one aggregate
GET /api/dashboard endpoint for the operational dashboard to consume.
The router validates at the boundary with Zod and delegates to runTask,
the single composition root that resolves repository policy and
constructs a runner; procedures never execute a shell or touch a
checkout directly. Task history persists through a narrow
KeyValueStorage contract (filesystem by default; Redis, KV, or Nitro
storage drop in unchanged), is redacted before it is written, and never
stores review input or checkout paths. TaskScheduler bounds concurrency
globally and per repository and rejects work once its queue is full.
This restores the control-plane half of the productionization work
merged as #21, adapted to main as it stands after #22 and #23: built
with tsdown like the other apps instead of the Nitro/vue-tsc pipeline
apps/dashboard already owns, and listening on 3001 by default so `aube
run dev` can start the dashboard and the control plane together without
a port collision.
Refs #10
Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
@socket-security

socket-securityBot commented Aug 10, 2026

Copy link
Copy Markdown

Review the following changes in direct dependencies. Learn more about Socket for GitHub.

DiffPackageSupply Chain
Security
VulnerabilityQualityMaintenanceLicense
Addedesbuild@​0.28.2921007392100
Added@​orpc/​server@​2.0.0-beta.269310010096100
Added@​agent-zero/​github@​0.3.0N/AN/AN/AN/AN/A

View full report

Comment threadapps/server/src/rpc.ts Outdated
Comment threadapps/server/src/control-plane.ts Outdated
…ked queueing
Co-authored-by: Codesmith <codesmith-bot@users.noreply.github.com>
Comment threadapps/server/src/rpc.ts
RedStar071and others added 3 commits August 10, 2026 11:58
Co-authored-by: Codesmith <codesmith-bot@users.noreply.github.com>
Co-authored-by: Codesmith <codesmith-bot@users.noreply.github.com>
@kodiakhq
kodiakhqBot merged commit 9a657a1 into mainAug 10, 2026
14 checks passed
@kodiakhq
kodiakhqBot deleted the feat/orpc-control-plane branch August 10, 2026 12:09
Sign up for freeto join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant

@RedStar071