6e4aca9c67
## Thinking Path > - Paperclip is the open source app people use to manage AI agents for work > - The `pi-local` adapter runs the Pi coding agent, including inside remote/sandboxed execution targets; Pi resolves `--provider P --model M` by an exact (provider, id) match against its model registry, and it has no base-url CLI flag or env var: a `models.json` in its agent config dir (`$PI_CODING_AGENT_DIR`, falling back to `$HOME/.pi/agent`) is its only mechanism for custom or OpenAI/Anthropic-compatible endpoints > - Deployments increasingly put an LLM gateway between the harness and the model for cost, governance, or data-residency reasons: LiteLLM, OpenRouter, Portkey, Kong, a corporate proxy, self-hosted models (vLLM/Ollama), or region-pinned/sovereign endpoints. Today there is no supported way to get such provider config into Pi's registry for orchestrated runs > - The opencode adapter gained the equivalent capability in #7837 and codex in #7919; this pull request is the Pi analogue, so the harness layer stays gateway-agnostic regardless of which CLI an agent uses; nothing here is specific to one hosting setup > - This pull request reads `PAPERCLIP_PI_PROVIDERS` (Pi's `models.json` `providers` shape), materialises a managed `models.json` in a temp agent-config dir, points `PI_CODING_AGENT_DIR` at it, and ships it to remote execution targets with the run > - The benefit is Pi works behind any compatible gateway with config only; with no env set, behavior is unchanged ## Linked Issues or Issue Description No existing issue; describing in-PR (feature / adapter enhancement). - **Gap:** there is no supported way to register custom/gateway providers + models for `pi-local`. Pi's only custom-endpoint mechanism is a `models.json` in its agent config dir, and orchestrated (especially sandboxed) runs have no way to provision one declaratively. - Related: #7837 (the opencode-local analogue, same env-driven gateway-routing pattern) and #7919 (the codex-local analogue). Searched for duplicate or related PRs: no existing pi-local gateway/provider-routing PR found. > Note on ROADMAP: this is adapter-level, opt-in config (defaults unchanged) that *enables* gateway routing for one harness; it is not the core "Cloud / Sandbox agents" platform work itself. ## What Changed - New `packages/adapters/pi-local/src/server/runtime-config.ts`: `preparePiRuntimeConfig()` reads `PAPERCLIP_PI_PROVIDERS` (a JSON object in pi's `models.json` `providers` shape) from the run env, then `process.env`. When set, it expands `{env:VAR}` placeholders (run env first, then process env; unresolvable placeholders left intact), writes `{"providers": ...}` to a managed temp dir as `models.json`, and returns env with `PI_CODING_AGENT_DIR` pointing at it plus a cleanup handle. - `execute.ts`: the prepared dir ships to remote execution targets as the managed-runtime asset `agentConfig` (same mechanism as opencode's `xdgConfig`), and `PI_CODING_AGENT_DIR` is repointed to the in-target path; cleanup runs in `finally`. - Misconfiguration is visible, not silent: a set-but-unusable `PAPERCLIP_PI_PROVIDERS` (invalid JSON, not an object, no provider objects) surfaces an explanatory note instead of proceeding unconfigured into an opaque model-not-found failure later, and provider entries with non-object values are skipped with a note naming them. Unset/empty stays a silent no-op (feature off). - Defaults unchanged: with `PAPERCLIP_PI_PROVIDERS` unset, the adapter behaves byte-for-byte as before, for local runs and for every existing sandbox provider. ## Verification - All pi-local tests green against this base (new: providers written verbatim, `{env:VAR}` expansion from run env/process env/unresolvable, no-op when unset, `PI_CODING_AGENT_DIR` set and shipped, the misconfiguration notes incl. skipped non-object entries, remote asset sync + env repoint). Typecheck and build clean. - Production end-to-end evidence (our deployment, used as verification, not as the scope of the change): a pi agent in a Kubernetes gVisor sandbox resolved a custom provider from the shipped `models.json`, completed an assigned issue through an Anthropic-compatible gateway, and landed a billed usage row. ## Risks Low. The entire feature is opt-in behind one env var; the only behavior change when it is set is the intended one. The managed dir replaces the host agent dir for the run by design (credentials travel inside the provider config or via env-key indirection), which is the correct posture for orchestrated runs. No migration/UI impact. ## Model Used Claude Opus 4.8 (`claude-opus-4-8`, 1M context), extended thinking + tool use, via Claude Code. ## Checklist - [x] I have included a thinking path that traces from project context to this change - [x] I have specified the model used (with version and capability details) - [x] I have checked ROADMAP.md (adapter-level opt-in config enabling gateway routing; not the core sandbox-platform work, noted above) - [x] I have searched GitHub for duplicate or related PRs and linked them above (#7837 and #7919 are the opencode/codex analogues; no pi-local duplicate found) - [x] I have either (a) linked existing issues OR (b) described the issue in-PR following the relevant issue template - [x] I have run tests locally and they pass - [x] I have added or updated tests where applicable - [ ] If this change affects the UI, I have included before/after screenshots (n/a, no UI) - [ ] I have updated relevant documentation to reflect my changes (env var documented inline; no central doc references the adapter env yet) - [x] I have considered and documented any risks above - [x] All Paperclip CI gates are green (green on the previous head; re-running on the final note-copy polish commit) - [x] Greptile is 5/5 with no open P2s, recommendations, or follow-ups (both prior review findings are fixed at head: the indirect notes-based guard is now an explicit `agentConfigDir` handle, and a failed `models.json` write no longer leaks the temp dir; a re-review is requested for the note-copy polish) - [x] I will address all Greptile and reviewer comments before requesting merge 🤖 Generated with [Claude Code](https://claude.com/claude-code) --------- Co-authored-by: Claude Opus 4.8 (1M context) <noreply@anthropic.com>