Runtimes
What a runtime is
A recipe defines your agent’s behavior, but it doesn’t run on its own. Pi runs the agent loop from that recipe. An Introspection runtime makes that combination deployable: it pins the exact recipe version Pi loads, provides an isolated sandbox, and resolves the identity, policy, bindings, and resources needed for each task.
A runtime serves one or more environment lanes (typically staging and
production) so you can move a version from test traffic to live traffic. A
lane points to one version in a runtime group, much like a Git ref points to a
commit.

Runtime groups: the lineage
Successive versions of one logical agent share a runtime group, a stable identity that ties every version of that agent together. Each new version is its own immutable runtime row; the group is the through-line across all of them.
This lineage enables:
- Experiments to route between versions: an experiment compares arms within a single group’s lineage, on one environment.
- Patterns that accumulate across versions: behavior and failure modes observed on one version stay attached to the lineage, so you can see how a recurring issue trends as the agent evolves.
A runtime is one immutable deployable version. A runtime group is the agent’s identity over time. You experiment and trend patterns across the group, then ship a single version into an environment lane.

Model credential mode
The runtime can use Introspection-managed model access or credentials you provide:
| Property | Options | Meaning |
|---|---|---|
| LLM mode | managed / bring-your-own-key | Whether the runtime uses Introspection-managed model access, or your own provider credentials. |
Recipe dependencies
Node dependencies use the recipe’s ordinary
package.json#dependencies. The managed
runtime discovers the recipe root and nested packages, installs production
dependencies with pnpm into a hoisted node_modules, and links the Pi peers
already supplied by the runtime image. devDependencies stay authoring-only
and are not installed in the sandbox.
A recipe declares
Python and system requirements
under pi.runtime. The managed runtime satisfies them while preparing the
recipe workspace, before the first model call.
For a declared Python project, the runtime:
- verifies that
pyproject.tomlanduv.lockare inside the recipe; - runs a frozen production install into
.pi/python; - reuses that environment while the project and lockfile digest is unchanged;
- runs any declared import preflights;
- activates the environment for Pi and recipe-owned processes through
VIRTUAL_ENVandPATH.
The install never modifies system Python, includes development dependencies, or resolves a newer dependency graph than the committed lock. A missing lock, incompatible interpreter, failed install, or failed import stops the runtime before the agent starts.
System requirements use versioned capability IDs such as
document.pdf-tools@1. These map to reviewed software already present in the
runtime image. Recipes cannot execute apt-get, Homebrew, or arbitrary
privileged boot scripts. If the image does not advertise a requested
capability and version, the runtime fails closed with an actionable error.
Resolution and availability
When you start a task against a runtime by name, the platform resolves that name to the version currently active for the task’s environment lane. Resolution is sticky for the task: every run in that task keeps the same version, even if the lane moves while the task is working. Start a new task to pick up the lane’s newer version.
“Pins” here means task-level runtime resolution. It is distinct from the immutable recipe source and the environment lane assignment described below.
If a version turns out to be bad, you can yank it. A yanked runtime stops
accepting new tasks while existing tasks keep their pinned version. You can
reverse the decision by unyanking it. Use
introspection runtimes update --yank / --unyank or the dashboard.
Environments and deployment
An environment is a lane shared across the platform: development, staging,
or production. Environment-scoped API keys, bindings, experiments, and memory
keep test work separate from live traffic. development is the local
introspection dev lane. Staging and
production are deployed lanes whose selected runtime versions can change
independently.
Runtime registration is manifest-driven. A canonical
.introspection/<runtime-slug>.yaml file names the runtime group, points at the
recipe path, and declares its runtime configuration:
name: support-agent
description: Customer support agent
path: apps/support-agent
runtime:
llm_mode: byok
resources:
requests:
cpu: "1"
memory: 2Gi
storage: 10Gi
limits:
cpu: "2"
memory: 4GiWorkspace repositories
runtime.github declares the repositories this runtime’s tasks may check out
into the sandbox, and how much the token minted for them may do:
runtime:
github:
repositories:
- acme/api-service
- acme/web
permissions:
contents: write
pull_requests: writerepositories is a grant, not a clone list: each entry is an owner/name slug
for a repository already registered to the project (never a URL). There is no
limit on how many may be granted — a grant clones nothing, so its length costs
nothing. Two granted repositories cannot share a name, because the checkout
always lands at workspace/repos/<repository name>.
The grant is part of the runtime version, so editing runtime.github in the
manifest changes nothing until a new version is deployed from that commit, and a
running task keeps the repositories it cloned at launch. An explicit
PATCH /v1/runtimes/{id} on config_json is the one path that does change a
live runtime’s grant, and it applies from that runtime’s next token mint.
config_json is replaced wholesale, not merged — it is the same object that
holds resources and the manifest’s runtime.config keys — so send the
runtime’s current config_json with github edited into it, or the rest is
silently dropped until the next manifest deploy rewrites the row.
A task then picks the subset it actually wants, with its ref and depth:
introspection tasks create --repository OWNER/NAME[@REF][:DEPTH] (repeatable),
or repositories: [{ repo, ref, depth }] on TaskCreateParams. That list has
no server-side count limit either, but unlike the grant it is cloned at boot
before the first turn, so its length is startup latency. An entry outside the grant is dropped by the
server rather than failing the launch.
permissions mirrors the GitHub Actions permissions: block and is the
ceiling, not the request. Every supported read is implicit, so authors declare
only write elevations. The allow-list is contents, pull_requests, issues,
checks, statuses, deployments, and discussions; keys outside it —
workflows, administration, actions, packages, pages,
security_events, repository_projects — are refused by name.
See Work with repositories for the end-to-end procedure, including registering the repository, what the agent can do with the checkout, and the review boundary that write access requires.
Resource sizing
Resource requests describe the capacity a task needs the environment to
reserve: CPU for processing time and memory for the working set. CPU and memory
limits bound how much a task may use when the target environment applies those
limits. requests.storage sizes the task’s scratch volume; storage is
request-only and is not a durable-artifact quota.
The platform parses these as portable resource quantities and resolves them against the target environment’s defaults, minimums, schedulability guards, and available capacity. The resolved values can therefore differ from the manifest. A CPU or memory limit cannot be lower than its resolved request. Size requests and limits from representative workload behavior and revise them when startup, capacity, or task behavior shows the workload needs a different allocation; do not assume the authored quantities were applied unchanged.
The filename stem is the stable runtime-group slug, so it must itself be a valid
slug: lowercase letters, digits, and single hyphens, up to 63 characters. name
is a separate display name and does not have to match it. The manifest can also
set path, description, includes, strict, runtime.kind,
runtime.llm_mode, runtime.config, runtime.resources, and
runtime.github. strict: true turns manifest keys outside the schema into
errors instead of warnings. It lives in the Git repository connected through your organization’s
GitHub integration. The first introspection runtimes create --manifest ... records
an immutable recipe pin and creates the runtime group; later commits produce
new versions in that same lineage.
Creating the first runtime is a production bootstrap, not a staging
preview. Run runtimes create from a clean, pushed main branch. The first
version immediately becomes active in both staging and production. A feature
branch or pull-request commit cannot bootstrap a staging-only runtime.
If the recipe begins on a feature branch, review and merge that pull request
first. Then check out the resulting main commit and create the runtime from
there. After the runtime group exists, pull-request commits can produce
candidate versions for staging while production continues to follow main.
Staging can follow a Git branch or pull request, or be pinned to one exact
commit. A lane that follows a moving ref advances when a new runtime version is
built from that ref. Pinning a commit freezes the lane on that immutable
version; introspection runtimes unpin returns staging to main.
Unpinned production advances with the repository’s default branch. The CLI and dashboard expose the lane controls for staging; pinning production is a Control Plane API operation.
Runtime versions themselves never change. Moving or pinning a lane only
changes which immutable version receives new work. development remains the
local introspection dev lane.
Use the dashboard or CLI to register runtimes, choose what staging serves, or withdraw a bad version. Application SDKs resolve runtimes and start tasks; they do not change deployment state.
Follow the Agent development lifecycle to register a recipe and test it in staging. See CLI → Runtimes for every runtime command.
How a managed task starts
Each managed task uses one recipe version from start to finish. Introspection loads the registered recipe path at the Git commit selected for the task’s environment. Moving an environment to another version affects new tasks, not a task that is already running.
Before the agent starts, Introspection:
- Loads the recipe source. Only the registered recipe path at the pinned commit is included.
- Prepares the recipe. Paths matched by the root
.recipeignoreare excluded. Declared production dependencies are installed or validated, and requested system capabilities are checked. - Resolves the agent. The runtime resolves the recipe’s agent definitions and uses the agent configured for the task.
- Makes task resources available. These can include recipe-provided files, restored task files, uploads, skills, memory, and environment bindings.
- Starts the agent. The task begins only after the recipe and its required resources are ready.
Runtime reads show image preparation as pending, queued, building,
ready, or failed. A failed build includes an error and may include a log
file. A completed image may also report its size.
Keep agent behavior, dependency declarations, skills, extensions, and other portable configuration in the recipe. Keep concrete secrets and endpoint URLs in environment bindings rather than recipe source.
Cloud validation distinguishes a recipe defect from a validation attempt that could not finish. An invalid recipe includes file diagnostics and cannot start a managed task. A failed validation includes an error message. The dashboard can request a fresh validation attempt; completed results are otherwise owned by the validation service.
Files and task artifacts
Files in the recipe’s conventional files/ directory become read-only task
inputs alongside restored task files and conversation uploads. Nested paths and
binary contents, such as spreadsheets, are preserved. A recipe file cannot
replace a file already restored into the task workspace. Conversation uploads
are materialized after restored task files, so use distinct paths when both
sources may contain the same filename. Files the agent creates or changes are
versioned through the Files API at checkpoints and task completion. See
Packaging a recipe for limits and authoring guidance.
What can prevent startup
Introspection does not start the agent when the registered commit or recipe path cannot be loaded, the recipe or configured agent is invalid, or a declared dependency or system requirement cannot be satisfied. Startup also fails when recipe-provided files exceed their limits, contain symlinks, or collide with a restored task file or upload. Correct the recipe version or required environment configuration before starting another task.
Related
- Recipes: the versioned behavior a runtime deploys.
- Experiments: A/B tests that route between versions in a group’s lineage.
- Observations & patterns: behavior that accumulates across a runtime group.
- Deployment: where the Control Plane and Data Plane infrastructure run.
- JavaScript SDK: resolve a runtime and open an identity-bound runner.
- API Reference: endpoint details for the published Data Plane APIs.