Route Pi LLM providers through Tailscale Aperture

Route Pi LLM providers and MCP tools through Tailscale Aperture, a managed AI gateway on your tailnet.
Aperture handles API key injection and request routing server-side, so Pi never needs upstream provider credentials. This extension offers three capabilities:
aperture provider whose models come from the gateway.mcp__aperture__*.pi install npm:@aliou/pi-ts-aperture
After installing, run the onboarding wizard:
/aperture:onboarding
The wizard asks for your Aperture URL (with a health check), lets you pick capabilities, providers, and whether to register the gateway’s MCP tools (off by default), then saves and reloads Pi. You can change everything later with /aperture:settings.
Registers a standalone aperture provider listing the models your gateway exposes. Include all gateway providers or filter to specific ones, and each model is routed through the Pi API that matches its Aperture compatibility.
Capabilities (vision input, reasoning, thinking levels) come from the first source that knows the model: ~/.pi/agent/models.json, then Pi’s model registry, then models.dev, then safe defaults. Costs, the context window, and the output limit come from the gateway where it reports them, because they describe the route Pi calls and a reseller can cap a model below its native capacity. The resolved catalog is cached in Pi’s models store, so models load instantly on startup, even offline.
Reroutes existing Pi providers through Aperture. Each provider keeps its own model definitions and settings, and sessions resume on the same model. Aperture injects server-side credentials, or forwards Pi’s own credential for passthrough providers. OpenAI Responses passthrough routes support Pi’s Sign in with ChatGPT.
Pick providers in the Proxy tab of /aperture:settings. A local provider can target a different gateway id (for example, anthropic → anthropic-oauth), and several local providers can share one gateway target. Optional per-provider verification warns when local models are missing from the gateway; keepGatewayModelsOnly: true hides them from the model picker instead.
Aperture can expose MCP tools (GitHub, your own internal tools, …) at /v1/mcp. When enabled, this extension registers that endpoint with Pi’s built-in MCP support as the aperture server with deferred exposure: tools surface as mcp__aperture__* and stay out of the system prompt until Pi’s tool_search loads them.
Enable MCP tools in /aperture:settings; the change applies immediately, no reload needed. Manage the connection with /mcp. To pin tools (always declared to the model) or hide them, add a same-name entry to ~/.pi/agent/mcp.json — a file entry takes precedence over the extension’s registration:
{
"mcpServers": {
"aperture": {
"url": "http://ai.pango-lin.ts.net/v1/mcp",
"exposure": "deferred",
"toolExposure": {
"github_list_repos": "direct",
"github_delete_*": "hidden"
}
}
}
}
toolExposure keys are tool names or * patterns; values are direct (pin), hidden (suppress), deferred (tool_search discovery, the server default), or codemode (script-only). See pi’s tool exposure docs.
| Command | Description |
|---|---|
/aperture:onboarding | Onboarding wizard. Only available while onboarding is enabled. |
/aperture:settings | Edit connection, capabilities, and providers. |
/aperture:proxy | Shortcut for /aperture:settings on the Proxy tab. |
/aperture:dedicated | Shortcut for /aperture:settings on the Dedicated tab. |
/aperture:mcp | Shortcut for /aperture:settings on the MCP tab. |
Configuration is saved globally to ~/.pi/agent/extensions/aperture.json. The settings UI covers everything, but you can also edit the file directly. The APERTURE_BASE_URL environment variable, when set, overrides the configured baseUrl (it is not written back to the config file):
{
"baseUrl": "http://ai.pango-lin.ts.net",
"proxy": {
"enabled": true,
"upstreamProviders": [
{ "id": "anthropic", "gatewayId": "anthropic-oauth", "shouldCheckGatewayModels": true }
]
},
"dedicated": {
"enabled": true,
"providers": [
{ "id": "anthropic", "name": "Anthropic", "enabled": true },
{ "id": "openrouter", "name": "OpenRouter", "enabled": true, "api": "anthropic-messages" },
{ "id": "google", "name": "Google", "enabled": false }
]
},
"mcp": {
"enabled": false
}
}
Notes:
proxy.upstreamProviders[].id is the local Pi provider; gatewayId is the target gateway provider and is required. Existing configs gain gatewayId: id during migration. Unknown gateway targets are left unrouted with a warning. aperture is reserved and cannot be selected as a pairing target.keepGatewayModelsOnly (per proxy provider, default false) hides that provider’s local models the gateway doesn’t serve instead of letting them fail at request time.api (per provider, unset by default) forces a specific Pi API (openai-completions, anthropic-messages, openai-responses, google-generative-ai, google-vertex, bedrock-converse-stream) instead of the one picked from the gateway’s compatibility map. Use it for providers Aperture serves through more than one API. If the gateway stops serving the override, the provider falls back to auto with a warning.dedicated.providers list means all gateway providers are included. Passthrough providers are excluded: the dedicated provider never forwards a client credential./v1/systemone) appear on the aperture provider as classifiers, callable via models.classify, not as chat models. Configure them per model with model_compatibility in the Aperture config.~/.pi/agent/models.json, not in the extension config.Referer and x-session-id (the current Pi session) so the Aperture dashboard can group them. Turn them off with "shouldSendProvenanceHeaders": false or the Provenance headers toggle. They are also skipped whenever Pi telemetry is disabled (PI_TELEMETRY=0 or enableInstallTelemetry: false).http:// or https://).