Skip to content

Move ask-user tool to Pi extension with workspace-aware session bridge #56

@hachej

Description

@hachej

Context

@hachej/boring-ask-user currently has two package surfaces:

  • boring.front → workspace UI: Questions pane/provider/surface resolver.
  • boring.server → workspace backend: routes, file store, bridge publisher, runtime, and the ask_user agent tool via WorkspaceServerPlugin.agentTools.

That works today because boring-workspace collects server plugin agentTools and passes them to boring-agent as host-injected extraTools. The boring-agent Pi harness adapts those tools with the active boring workspace sessionId, so ask_user can block the correct chat session and open/update the correct Questions UI.

But conceptually, chat-callable tools belong on the Pi/agent surface, especially for package plugins and hot reload:

{
  "boring": {
    "front": "dist/front/index.js",
    "server": "dist/server/index.js"
  },
  "pi": {
    "extensions": ["dist/agent/index.js"]
  }
}

Target package shape:

plugins/ask-user/
  src/front/   # workspace UI plugin
  src/server/  # workspace HTTP routes, store, bridge publisher/runtime
  src/agent/   # Pi extension registering ask_user

Problem

Moving ask_user directly from WorkspaceServerPlugin.agentTools to package.json#pi.extensions would lose important boring-workspace context.

Native Pi extension tools receive Pi's ExtensionContext, but not the boring-agent/web session id currently injected by the host tool adapter:

adaptToolsForPi(opts.tools, input.sessionId)

ask_user needs that session id to call the ask-user runtime correctly:

runtime.ask({ ...input, sessionId })

It also needs a clean way to reach the workspace ask-user backend/runtime/bridge from the Pi extension. Without an explicit seam, a Pi-native ask_user tool would need hidden globals, brittle HTTP assumptions, or would route questions to the wrong/default session.

End goal

Add a workspace-aware Pi extension bridge for package agent surfaces, then migrate ask_user to the Pi extension path.

Desired end state:

  • ask_user is registered by plugins/ask-user/src/agent/index.ts via pi.registerTool().
  • plugins/ask-user/package.json#pi.extensions points to that agent entry.
  • plugins/ask-user/src/server no longer contributes agentTools; it owns only routes/store/runtime/bridge publishing.
  • /reload hot reloads the ask-user tool through Pi's native extension loader.
  • The tool still receives/derives the correct boring workspace session id and can safely talk to the ask-user server/runtime.

Possible design directions

One of these seams is likely needed:

  1. Workspace session metadata in Pi tool context

    • Extend boring-agent's Pi harness integration so package Pi tools can read the active boring workspace sessionId from tool execution context or a documented helper.
  2. Workspace agent bridge/client for Pi extensions

    • Provide a small helper usable from src/agent/index.ts, e.g. createWorkspacePluginAgentClient(ctx), that can call plugin server routes with the correct session context.
  3. Ask-user-specific agent client

    • Provide createAskUserAgentExtension(...) that registers the Pi tool and delegates to the ask-user server route/runtime using a supported context channel.

Avoid hidden globals if possible. The bridge should be explicit, typed, testable, and compatible with hot reload.

Acceptance criteria

  • Define/document the three package surfaces: front, server, agent.
  • Add the workspace-aware Pi extension context/client seam.
  • Migrate @hachej/boring-ask-user:
    • add src/agent/index.ts that registers ask_user using Pi's extension API;
    • add pi.extensions in package.json;
    • remove agentTools from createAskUserServerPlugin();
    • keep server routes/store/bridge behavior intact.
  • Add tests proving:
    • package scan exposes the ask-user Pi extension path;
    • ask_user is available through Pi extension loading, not server agentTools;
    • tool execution uses the correct boring workspace session id;
    • /reload picks up changes to the ask-user agent extension.
  • Update docs/templates to describe the 3-surface plugin layout:
    • front: workspace UI contributions;
    • server: workspace backend/routes/stores/bridge;
    • agent: Pi extensions/tools/skills loaded via package.json#pi.

Non-goals

  • Do not force every plugin to have all three surfaces.
  • Do not remove WorkspaceServerPlugin.agentTools immediately; keep it for static/host-composed tools and backwards compatibility.
  • Do not try to make workspace plugins use Pi's imperative API wholesale. Workspace front/server contribution introspection should remain declarative where possible.

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions