Skip to content

04 β€” pi.dev runner (pi)Β #524

Description

@gewenyu99

πŸ”„ Re-spec β€” 2026-06-26 (a RUNNERS entry; selected by the existing wizard-runner flag)

The pi runner is a leaf engine registered into RUNNERS (see #521), not a mode. It is reached when a
route resolves the runner to pi or the existing wizard-runner=pi flag overrides it. It consumes the
resolved pair's model as an input (model: string) rather than hardcoding one. Built on pi.dev
(@earendil-works/pi-coding-agent); the earlier @openai/agents build was scrapped (PRs #586/#587/#590
closed). Pi uses typebox, not zod β€” re-evaluate/revert the zod-4 bump that existed only for
@openai/agents.

Epic: #520 Β· Behavior change: none (wizard-runner default-off) Β· Depends on: #521, #522

Summary

Implement the pi runner on pi.dev β€” a Claude-Code-style coding agent that owns its own tool loop and
ships Read/Write/Edit/Bash. It speaks the PostHog gateway directly via a registered anthropic-messages
provider, runs the same commandments + skills as anthropic, and streams onto the shared TUI bridge.

Scope

  • Deps: @earendil-works/pi-coding-agent, @earendil-works/pi-ai. No @openai/agents, no aisdk adapter.
  • Register into RUNNERS as pi, implementing AgentRunner.run(inputs & { model }).
  • Gateway provider β€” registerProvider(name, { baseUrl: getLlmGatewayUrlFromHost(host), apiKey: <posthog token>, api: 'anthropic-messages', headers: <Bedrock-fallback + wizard metadata/flags> }) (reuse
    02 — Shared runner contract + adapters (gateway, MCP, prompt, tools, stream→TUI) #522's header builder). Resolve the model from the pair's model input (getModel(provider, id)), not
    a local constant β€” so a future pi + opus differs only by the resolved pair.
  • Session β€” createAgentSession({ model, resourceLoader: new DefaultResourceLoader({ systemPromptOverride: <commandments> }), customTools, cwd: <install dir>, sessionManager: <in-memory> }); run via
    session.prompt(prompt).
  • Stream β†’ TUI β€” map session.subscribe events onto 02 β€” Shared runner contract + adapters (gateway, MCP, prompt, tools, streamβ†’TUI)Β #522's bridge (status, todos, markers) and the log.
  • Errors β€” terminal/loop errors β†’ AgentErrorType; honor [ABORT]. Degrade gracefully when a
    dependency (e.g. local MCP) is unavailable.

Acceptance criteria

  • A text-only and a tool-using run complete end-to-end through the registered provider when
    wizard-runner=pi (or a route resolves the runner to pi).
  • Streaming + markers + todos reach the TUI.
  • wizard-runner stays default anthropic; anthropic unaffected.
  • Unit tests for runner wiring (mocked provider) incl. the abort/stop guard.

Open questions

  • Does Pi's provider append /v1/messages to baseUrl, or is the full path needed?
  • How does Pi resolve a custom-provider model without interactive auth in headless/CI runs?

Files

  • src/lib/agent/runner/backends/pi/

Notes

Skills load via Pi's native file-based discovery β€” drop the resolved framework SKILL.md into a Pi-scanned
dir (.pi/skills/.agents/skills) before the run. Wizard capabilities ride as defineTool custom tools.
Per-tool gating (canUseTool + YARA) is #525.

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type

    Fields

    No fields configured for issues without a type.

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions