Deploying

The recipe does not change. Who supplies credentials and endpoints does.

An agent recipe carries no deployment descriptor, so nothing is rewritten when it moves. The host supplies what you set up by hand locally, and none of that local setup travels with the directory.

LocallyOn a host
Model keysEnvironment variables you exportA credential store the host passes in
MCP endpoints.pi/mcp.local.json, uncommittedBindings the host synthesizes per run
MCP authYou run the OAuth flow, once per machineThe host terminates it, once per connection
Child agentsIn-processYour own durable controller
Questions to a userA terminal dialogYour interrupt surface
What the agent seesOne headless mcp commandIdentical

Credentials

A host passes credentials to the constructor instead of leaving them to be read from the environment. Nothing in the recipe names a variable, so this needs no change to the package.

host.ts
const agent = recipe.selectAgent(agentName);

const handle = await createAgentSession({
  recipe,
  agentName,

  // Resolved per run. Omit to fall back to provider env vars.
  credentials: await myVault.credentialsFor(agent.modelSpec),

  // Transport only, validated against the model the recipe declared.
  modelOverride: myGatewayModel,
});

Construction fails closed. A provider with no resolvable credential raises RecipeCredentialError before the session exists, so a misconfigured deployment fails at startup rather than on a user's first message.

MCP endpoints

Two shapes, and the difference is where the upstream credential lives.

Bind per run

The host adapts its own connection registry into the same binding shape and passes it inline, so there is no file in the workspace at all.

host.ts
const handle = await createAgentSession({
  recipe,
  agentName,
  // The same shape as .pi/mcp.local.json, synthesized instead of read.
  mcpBindings: {
    servers: [
      {
        id: "contacts",
        transport: "streamable_http",
        url: connection.url,
        headers: { Authorization: "Bearer ${CONTACTS_MCP_TOKEN}" },
      },
    ],
  },
  // Header values stay env references, resolved in this run's environment.
  env: { ...runEnv, CONTACTS_MCP_TOKEN: await connection.freshToken() },
});

Terminate auth at the edge

Or point the binding at your own gateway and let it hold the upstream credential. The session then carries a short-lived token for your gateway and never the provider's, and the OAuth dance a local user does by hand happens once at the platform edge instead of once per workspace. Use this for multi-tenant runtimes, where per-workspace browser flows are not available.

host.ts
const handle = await createAgentSession({
  recipe,
  agentName,
  mcpBindings: {
    servers: [
      {
        id: "contacts",
        transport: "streamable_http",
        // Your gateway authenticates upstream on the session's behalf.
        url: `${gatewayUrl}/mcp/contacts`,
        headers: { Authorization: `Bearer ${runScopedToken}` },
      },
    ],
  },
  // You own provisioning, so the session must not lease the environment.
  mcpProvisioning: "host",
});

Either way the agent's instructions are unchanged, because the agent was never told how credentials arrive. It sees one rule in both worlds: MCP is headless, and a missing connection is authentication_required with an instruction to ask a human.

Agent runs

Child agents run in-process by default, which is right for a CLI and for tests. A long-lived host usually wants them durable instead: queued, observable, and able to outlive one process. Implement AgentRunController and pass it as runController, and no recipe changes. The SDK reference has the contract and its lifecycle.

Questions from a run

A recipe tool that asks the user something works in a terminal for free. In your runtime you implement the interrupt contract once, and every recipe you deploy gets a working question without knowing what your surface is. See Interactions.

What never travels

  • .pi/mcp.local.json and .pi/mcporter.json.
  • Environment variables you exported in your shell.
  • Cached OAuth tokens from your local mcporter config.
  • The workspace itself. A host provisions its own.

What Recipes owns, what the host owns

RecipesHost
Package and agent semanticsCredentials and transport
The immutable resolved graphSandbox and task lifecycle
Model, tool, skill, prompt, extension and MCP policyFiles and uploads
Pi session constructionMemory and workspace
The agent-run controller contractPersistent run artifacts
Lightweight in-process agent runsScheduling and rehydration
Session-local cleanupHistory, retries, interrupts and compaction policy
OTel provider, processors and exporters