Skip to content

Pi ​

pi is fullsend's second agent runtime, opt-in per org or repo. It reaches models Claude Code cannot — Grok and Gemini alongside Claude — through the same sandbox, credentials and egress policy.

bash
fullsend run triage --runtime pi --model xai-vertex/xai/grok-4.6

Selecting it, and how it compares to Claude Code, is in Agent runtimes. This page is what changes once you are on it.

Models and providers ​

A model on pi is provider/id. Aliases and bare ids still work — opus/sonnet/haiku resolve through fullsend's table, and a bare id gets the provider from FULLSEND_PI_PROVIDER (default anthropic-vertex).

ModelSpecProvider
Claudeanthropic-vertex/claude-opus-4-6vendored extension
Geminigoogle-vertex/gemini-3.7-flashpi built-in
Grokxai-vertex/xai/grok-4.6vendored extension

Grok's spec has three segments on purpose. pi sends the model id on the wire verbatim and Vertex wants the publisher-qualified xai/grok-4.6, so the id keeps its slash. Use the full xai-vertex/xai/grok-4.6; a bare xai/grok-4.6 would otherwise reach pi's built-in xai provider, which talks to xAI's own API and wants XAI_API_KEY. fullsend normalises the short form and a bare id under FULLSEND_PI_PROVIDER=xai-vertex, case-insensitively, so both land on the canonical spec.

Because harness model: cannot contain / (validModelName is ^[a-zA-Z0-9_.@-]+$), a harness selects a pi provider with a bare model: plus FULLSEND_PI_PROVIDER.

Each provider has its own GCP project ​

Every Vertex provider on pi resolves its own project variable, so one run can reach models that live in different projects. That matters because Model Garden availability is per-project — Grok may well be enabled somewhere other than Claude.

Loading diagram...

ADC supplies the identity for all three — only the project differs, so one credential covers them. A pi run leaves an explicitly-set XAI_VERTEX_PROJECT_ID alone and only defaults it to the fleet's Vertex project, so Grok can be pointed at a project where it is actually enabled.

Endpoints and regions. anthropic-vertex uses CLOUD_ML_REGION (then GOOGLE_CLOUD_LOCATION). xai-vertex is fixed to the global endpoint — Vertex serves Grok only there, and regional endpoints answer FAILED_PRECONDITION — so region variables are deliberately ignored for it.

At a glance ​

CredentialsSame WIF external_account + refreshed OIDC token as Claude Code. ANTHROPIC_* unset on the Claude provider, XAI_API_KEY unset on the Grok one, so a stray key cannot shadow a Vertex provider
UnattendedNo approval prompts, stdin closed, bounded retries; a missing credential exits 1
Artifactsoutput.jsonl, transcripts/<agent>-<ts>_<id>.jsonl, metrics.json with runtime: pi, plus pi-debug.log with --debug
Extra knobsFULLSEND_PI_PROVIDER (prefix for bare ids), FULLSEND_PI_BASH_ALLOWLIST=enforce
Not supportedSub-agents, fallback chains, plugins:, Bedrock/Azure providers

Running it locally? See Run a minimal agent on the pi runtime — no fleet repo required.

Behaviour differences worth knowing ​

  • No permission system. pi's posture is "run in a container". The sandbox, its egress policy and credential placeholders are the boundary (ADR 0027); fullsend's hook adapter is defense-in-depth on top.
  • Reads AGENTS.md natively — no CLAUDE.md bridge is injected.
  • The agent body is appended to pi's own system prompt rather than replacing it, so pi's default tool guidance stays. Claude Code's --agent replaces it.
  • --tools is enforced strictly, unlike Claude Code. Bash(a,b) becomes a first-token allowlist that is advisory by default; FULLSEND_PI_BASH_ALLOWLIST=enforce makes it block.
  • Failed tool calls are sanitized too — pi fires its post-tool event on failures, which Claude Code does not, so redaction and unicode normalization apply on both paths.
  • Fast release cadence (~weekly minors, with wire-format changes inside a minor) — versions are pinned exactly and the stream-parser fixtures are tied to the pinned version.

Not yet exercised ​

runtime: pi is selectable and has been run end to end, but no fleet lifecycle run on Vertex is recorded yet. Pilot on a disposable org with triage/prioritize before code/fix. review and retro are unsupported — they need sub-agents, and would run in a single context without per-persona models. extension_error events are not mapped.

Troubleshooting ​

The model is not found, or the provider is missing. A pi provider comes from an extension loaded with -e, and a failed extension is dropped silently — it simply does not appear. Re-run with --debug and read pi-debug.log, which captures pi's stderr including extension load errors.

No API key found for <provider>. The provider is registered but its credentials did not resolve. For Vertex providers that means ADC — check the project variable for that provider in the table above, not a shared one.

403 PERMISSION_DENIED on a Vertex call. The credentials work but the model is not enabled in that project's Model Garden, or the provider resolved a different project than you expect.

The model says it is a different model than you selected. Do not trust the reply — a model asked about itself will often repeat whatever the conversation history said. metrics.json records the model that actually served the run, and the session JSONL under transcripts/ records the provider and model per message.

See also ​

Content