Skip to content

feat(server): search/execute-routed connections & plugin skills — stop pasting them into the harness#2472

Draft
benjaminshafii wants to merge 2 commits into
devfrom
feat/search-routed-capabilities
Draft

feat(server): search/execute-routed connections & plugin skills — stop pasting them into the harness#2472
benjaminshafii wants to merge 2 commits into
devfrom
feat/search-routed-capabilities

Conversation

@benjaminshafii

Copy link
Copy Markdown
Member

What

Lands OpenWork Cloud's proven two-tool pattern (search_capabilities + execute_capability, from Den /mcp/agent) locally, so connections and plugin content stop being pasted into the harness (engine runtime config + fragile hot-add sync) and become capabilities the agent discovers and runs on demand.

Voiceover-first: the approved spec is evals/voiceovers/search-routed-capabilities.md; the passing fraimz flow is evals/flows/search-routed-capabilities.flow.mjs (8/8 frames, real Electron, real model, no mocks).

The pieces

  • routing: "search" connections — server-managed MCP entries can opt out of engine injection entirely: excluded from the OPENCODE_CONFIG runtime file and hot-add sync; flipping to search disconnects the engine client immediately. New route POST /workspace/:id/mcp/:name/routing; desktop Switch ("On-demand via search") in the connection details + "On-demand" badge.
  • Capability router (apps/server/src/capability-router.ts) — indexes local connections' tools via on-demand MCP clients (stdio + streamable HTTP, pooled with idle eviction, 60s tools/list cache, per-connection search timeouts + unavailable diagnostics) and workspace/global skills (skill:<name> executes to the SKILL.md content). Scoring mirrors den-api's lexical search.
  • Built-in OpenCode plugin (openwork-capability-router.ts) — exposes the bare canonical names search_capabilities / execute_capability (MCP tools are server-prefixed, so no collision with openwork-cloud_*). Resolves the workspace from context directory → sessionID probe → explicit workspaceId arg. Federates to cloud: unmatched queries/names forward through the openwork-cloud connection, so Den capabilities (memory bank, org capabilities) merge into the very same search surface — the Memory Bank system-prompt instructions keep working, now even routed locally.
  • Server routesGET /workspace/:id/capabilities/search, POST /workspace/:id/capabilities/execute (viewer tokens rejected).

Why

  • One search surface across local connections, plugin skills, and cloud — two tools in context instead of N×tools per connection.
  • No engine restarts / hot-add races for on-demand connections; adding a connection is a DB write.
  • Trajectory: marketplace plugins runnable without file installs; openwork-cloud itself can become search-routed (follow-up), leaving the engine with exactly two capability tools.

Testing

  • pnpm --filter openwork-server typecheck — pass
  • cd apps/server && bun test — 280 pass / 0 fail (new: capability-router unit + real stdio MCP integration tests, routing setter, engine-map exclusion, validators)
  • pnpm --filter @openwork/app typecheck — pass
  • pnpm --filter openwork-server build — bundles the new plugin
  • pnpm fraimz --flow search-routed-capabilities --cdp-url http://127.0.0.1:9826PASSED 8/8 frames against the real desktop app (dev build, seeded local Den for the cloud frame): connection flipped to on-demand in the UI → engine list provably never carries it → plain question → agent search_capabilitiesexecute_capability dials the stdio server just-in-time → real definition in the answer → plugin skill read through the same two verbs → signed-in cloud capabilities merged into the same search → still not in the harness.

Fraimz proof (frame-by-frame with voiceover + validated screenshots) posted as a comment below.

Notes / follow-ups

  • Per-tool permissions for routed executes (Den defers this too, Phase 3 there).
  • OAuth-required remotes without stored headers surface as unavailable with a reason (parity with Den's needs_connection hint is follow-up).
  • openwork-cloud sync could mark itself routing: "search" once we're confident — that's the endgame (two tools total).
  • The workspace-resolution fixes (path canonicalization + session probe) also apply latently to openwork-extensions-preview; not touched here to keep the diff minimal.

…bilities/execute_capability

Land OpenWork Cloud's two-tool pattern locally so connections and plugin
content no longer have to be pasted into the engine config:

- MCP connections can be routing:"search": stored server-side but excluded
  from the engine runtime config and hot-add sync (engine disconnects on
  flip); POST /workspace/:id/mcp/:name/routing toggles it, with a desktop
  Switch ("On-demand via search") in the connection details.
- New capability router (apps/server/src/capability-router.ts): indexes
  local connections' tools (on-demand MCP clients: stdio + streamable HTTP,
  pooled, 60s tools/list cache) and workspace/global skills, scored like
  den-api's search; executes tools just-in-time and returns skill content.
- New built-in OpenCode plugin exposes bare search_capabilities /
  execute_capability, resolves the workspace from context (directory,
  then sessionID probe, then explicit workspaceId arg), and federates
  unmatched queries/names to the openwork-cloud connection so Den
  capabilities (memory bank etc.) merge into the same surface.
- Server routes: GET /workspace/:id/capabilities/search,
  POST /workspace/:id/capabilities/execute (viewer tokens rejected).
- Voiceover-first spec (evals/voiceovers/search-routed-capabilities.md),
  passing fraimz flow, and a zero-dependency stdio MCP fixture.

Verified: openwork-server typecheck + bun test (280 pass), @openwork/app
typecheck, plugin bundles in build, fraimz 8/8 frames passed on the real
Electron app (local connection, plugin skill, and signed-in cloud
federation all through the two verbs).
@vercel

vercel Bot commented Jul 4, 2026

Copy link
Copy Markdown
Contributor

The latest updates on your projects. Learn more about Vercel for GitHub.

Project Deployment Actions Updated (UTC)
openwork-app Ready Ready Preview, Comment Jul 4, 2026 1:45pm
openwork-den Ready Ready Preview, Comment Jul 4, 2026 1:45pm
openwork-den-worker-proxy Ready Ready Preview, Comment Jul 4, 2026 1:45pm
openwork-landing Ready Ready Preview, Comment, Open in v0 Jul 4, 2026 1:45pm

@benjaminshafii

Copy link
Copy Markdown
Member Author

fraimz — ✅ PASSED

1 passed · 0 failed · 0 skipped — run 2026-07-04T07-59-38-429Z

Full frame proof with validated screenshots: evals/results/2026-07-04T07-59-38-429Z/fraimz.html (re-run: pnpm fraimz --flow search-routed-capabilities)

✅ search-routed-capabilities — Connections and plugins are found and run via search_capabilities/execute_capability — never pasted into the harness

User-facing flow demo

  • ✅ URL hash includes "/settings/extensions/mcp"
  • ✅ Visible text includes "On-demand via search"
  • ✅ Visible text includes "The agent finds this connection with capability search when it needs it, instead of loading its tools into every session."
  • 📸 search-routed-capabilities-01-frame-1-routing-switch.png — 5 validations passed

A server-managed MCP connection can be switched to on-demand capability search

  1. A server-managed MCP connection can be switched to on-demand capability search
    • ✅ URL hash includes "/settings/extensions/mcp"
    • ✅ Visible text includes "On-demand"
    • 📸 search-routed-capabilities-02-frame-2-engine-absence.png — 5 validations passed

The search-routed connection remains saved in OpenWork but absent from the OpenCode engine MCP list

  1. The search-routed connection remains saved in OpenWork but absent from the OpenCode engine MCP list
    • 📸 search-routed-capabilities-03-frame-3-plain-question.png — 5 validations passed

A plain glossary question is composed without naming tools, connections, or search

  1. A plain glossary question is composed without naming tools, connections, or search
    • 📸 search-routed-capabilities-04-frame-4-capability-search.png — 5 validations passed

The agent searches capabilities and receives the glossary MCP tool as a match

  1. The agent searches capabilities and receives the glossary MCP tool as a match
    • ✅ Visible text does not include "Something went wrong"
    • 📸 search-routed-capabilities-05-frame-5-definition-answer.png — 5 validations passed

execute_capability runs the glossary MCP tool just-in-time and the answer includes the definition

  1. execute_capability runs the glossary MCP tool just-in-time and the answer includes the definition
    • 📸 search-routed-capabilities-06-frame-6-plugin-skill.png — 5 validations passed

A plugin-namespaced release runbook skill is found and executed through the same capability router

  1. A plugin-namespaced release runbook skill is found and executed through the same capability router
    • ✅ Visible text does not include "Something went wrong"
    • 📸 search-routed-capabilities-07-frame-7-cloud-capability.png — 5 validations passed

When OpenWork Cloud Control is connected, capability search includes cloud matches in the same surface

  1. When OpenWork Cloud Control is connected, capability search includes cloud matches in the same surface
    • ✅ URL hash includes "/settings/extensions/mcp"
    • ✅ Visible text includes "On-demand"
    • 📸 search-routed-capabilities-08-frame-8-still-not-in-harness.png — 5 validations passed

Connections and plugin skills remain search-discovered capabilities, not engine config pasted into every session

  1. Connections and plugin skills remain search-discovered capabilities, not engine config pasted into every session
    • ✅ Script frame 1 narrated: "This is OpenWork. I'm adding my team's glossary connection — but instead of loading its "
    • ✅ Script frame 2 narrated: "The connection is saved, and here's the difference — the agent's engine config never pic"
    • ✅ Script frame 3 narrated: "I start a chat and ask a plain question — what does "blue-forty" mean in our glossary. I"
    • ✅ Script frame 4 narrated: "The agent searches its capabilities, and the glossary tool comes back as a match — found"
    • ✅ Script frame 5 narrated: "It executes the match. OpenWork dials the connection just-in-time, runs the real tool, a"
    • ✅ Script frame 6 narrated: "The same two verbs cover plugins too — I ask about our release runbook, and the skill th"
    • ✅ Script frame 7 narrated: "And because I'm signed into OpenWork Cloud, that same search reaches my organization's c"
    • ✅ Script frame 8 narrated: "That's the whole change: connections and plugins stop being config you paste into the ha"

PR comments can't reference local screenshot paths, so [ELIFECYCLE] Command failed with exit code 1.
was posting frame-by-frame proof with no actual images — just filenames.

postPrComment now uploads every frame screenshot to Vercel Blob first
(zero-dependency plain fetch, same approach as the upload-photo skill,
deterministic pathname openwork-fraimz/<runId>/<file>) and embeds the
public URL as an <img> in the comment. Missing BLOB_READ_WRITE_TOKEN or
a failed upload degrades gracefully (comment still posts, just without
that image) rather than blocking the run.

Verified for real: re-posted the search-routed-capabilities fraimz proof
on PR #2472 — all 8 screenshots uploaded, embedded, and confirmed publicly
served (200, image/png) at their blob.vercel-storage.com URLs. Replaced
the earlier image-less comment.
Sign up for free to 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