Skip to Content
Platform
GuidesDevelopment lifecycle

Agent development lifecycle

Start a recipe or adopt one, prove it in local Pi, exercise it through your application, check the committed version in staging, and merge it to production.
Local Pi flows to Development, Staging, Production, and Learn and repeat, which loops back to Local Pi
Text representation of the diagram:
Local Pi → Development → Staging → Production → Learn and repeat ↑ │ └──────────────────────────────────────────────────┘

A recipe is a package in the open format for vertical agents, built on Pi. It keeps agent definitions, shared instructions, skills, extensions, and declared capabilities together in Git. This guide covers its whole life: getting one, proving it locally, and moving each later change through development, staging, and production.

Start from a recipe

Skip to step 1 if the recipe already exists and has a runtime.

Install the Introspection CLI, which needs Node.js 24+ :

pnpm add --global @introspection-ai/cli

Then adopt a template, scaffold your own, or migrate an existing agent:

# Adopt a template — the clone is yours to edit and commit git clone https://github.com/introspection-recipes/template-claude introspection local --work-dir ./template-claude # Or scaffold from the starter introspection init my-agent introspection local --work-dir ./my-agent

init clones the starter template at run time and writes a runtime manifest under .introspection/, adopting the template’s own manifest when it ships one. Pass --template <repo> to scaffold from a different one. Whichever template you use, only two files are load-bearing: the smallest recipe that runs is package.json plus one agent YAML.

To migrate an agent built with another framework while preserving behavior you already trust, use the Quickstart’s migrate path.

Keep each part of the agent in the layer that owns it:

ConcernRecipe resource
Package identity and declared resourcespackage.json
Rules shared by every agentSYSTEM.md
Models, role-specific instructions, tools, and subagentsAgent definitions
Reusable domain workflows and deliverable shapesSkills & prompts
Recipe-owned code and deterministic toolsExtensions
Node modules used at runtimedependencies
Portable access to external toolsMCP declarations
Locked Python and approved system capabilitiespi.runtime
Source and files supplied to managed tasksPackaging a recipe
Durable production quality standards and your own test coverageJudges & evals

Start with the smallest recipe that handles the work you care about. Add a skill, extension, subagent, judge, or eval only when the behavior needs that boundary.

A recipe has no build step, no install store, and no publish command: distribution is Git. Push the directory to a repository and anyone with Pi and the Recipes extension can run it. Because the layout is an ordinary npm package, publishing to a registry also works when you want versioned, installable distribution — but the repository alone is enough. Sharing a recipe does not create an Introspection runtime; for a recipe’s first deployment, continue with the Quickstart.

1. Change the recipe locally

Edit the recipe’s instructions, skills, tools, or agent definitions in its repository-local package. Resolve its runtime manifest and launch the recipe with Pi. The local command validates the workspace before the session starts:

introspection local --runtime support-agent

Try the behavior you changed, important edge cases, and a few ordinary requests that should continue to work. Use fresh Pi sessions so previous context cannot hide a regression.

Stay in this loop until the change is useful and repeatable. introspection local does not require login or contact the cloud.

To run a recipe from another workspace, point manifest discovery at that workspace:

introspection local --work-dir ../support-agent

2. Test through development

Use the development runtime when the application path matters—for example, when you need to test SDK calls, end-user identity, cloud bindings, streaming, files, or reconnect behavior against the recipe you are editing.

First configure development bindings for any external services the recipe needs. Run your application with a development API key or application using the authentication method your product uses.

If needed, run introspection login again. The project resolves its development agent automatically. Then open a terminal at the repository root and run:

introspection dev --runtime support-agent

Leave the command running while you work. Changes under the support-agent recipe folder are picked up automatically.

What a save changes, and when

An edit reaches the sandbox on save, but whether the running chat behaves differently depends on when that file is read. The agent session is built once per task, so anything folded into it at construction is fixed for that chat:

You editedTakes effect
A skill body, or a script the agent runsThe next turn, in the same chat
SYSTEM.md, agent YAML, prompts, extensions, MCP declarationsA new chat
Dependencies (package.json, lockfiles)A new chat, which reinstalls them
.introspection/*.yaml (llm_mode, resources)A new runtime version — a new chat is not enough

If a change seems not to have applied, check this table before suspecting the dev attachment. Editing a system prompt and re-asking in the same chat is the common case that looks like a broken connection but is working as designed — start a new chat instead. Manifest settings are not part of the live patch and apply to the version built from your next push.

introspection dev uses cloud bindings for credentials, but it can route a declared MCP server to a local process with --mcp NAME=URL. It does not read local credential files or upload local secrets.

For example, this serves the declared contacts MCP server locally while the development binding supplies its credentials:

introspection dev --runtime support-agent \ --mcp contacts=http://127.0.0.1:8787/mcp

Run your application locally with its development credential. The credential selects the environment; there is no environment option on the SDK’s run() method.

import { IntrospectionClient } from "@introspection-sdk/introspection-node"; const client = new IntrospectionClient(); const runner = await client.runtimes("support-agent").run({ identity: { user_id: "local-developer" }, }); const task = await runner.tasks.start({ prompt: "Help me with my order.", }); console.log(await task.text()); await runner.close(); await client.shutdown();

API keys, service accounts, and federated applications use the same SDK flow. The project’s development agent selects the local overlay automatically.

Optional: route SDK traffic to one development session

Dev Targets apply only to application requests made through an Introspection SDK. You do not need one when using the development chat directly, and most SDK applications should leave the selector unset.

Use a target when several developers attach local sessions to the same development Runtime and their applications need to select one attachment. Start and name the attachment first:

# Terminal 1: keep this process running introspection dev --runtime support-agent --as John

Then configure the application process with its development credential and the exact target printed by that session before starting the application:

# Terminal 2 export INTROSPECTION_TOKEN=<development-credential> export INTROSPECTION_DEV_TARGET=John # Start your application, for example: npm run dev

The credential selects the development environment; INTROSPECTION_DEV_TARGET selects one attached session inside that environment. The target does not authenticate the caller or switch environments.

If only one attachment is active, leave the variable unset. If multiple attachments are active and the application supplies no target, the request fails because the platform cannot safely choose one. A request also fails when the supplied name does not match an active attachment—for example, after a typo or after that introspection dev process stops. Remove the selector from staging and production configuration; those environments ignore it.

When you stop introspection dev, new tasks use the committed recipe again. Your local changes have not been deployed.

3. Verify the committed version in staging

When the change is ready, commit it, push it, and open or update its pull request. The GitHub integration creates an immutable candidate runtime version from the pull-request commit; do not create another runtime group.

Find the candidate and pin staging to it:

introspection runtimes list --runtime <runtime-slug> -o table introspection runtimes pin <candidate-runtime-id>

runtimes list --runtime accepts the runtime slug or the group id, which is what you hold at this point. introspection runtimes versions <id> takes a runtime version id, not a slug, so use it once you have one row in hand and want the rest of that version’s group.

Configure any required staging bindings before sending work. Bindings are environment-specific, so a working development endpoint does not automatically configure staging.

Run a representative task through the stable runtime slug:

import { IntrospectionClient } from "@introspection-sdk/introspection-node"; const client = new IntrospectionClient({ token: process.env.INTROSPECTION_TOKEN, }); const runner = await client.runtimes("support-agent").run({ identity: { user_id: "staging-check" }, }); const task = await runner.tasks.start({ prompt: "Reply with the word ready.", }); console.log(await task.text()); await runner.close(); await client.shutdown();

Use a staging-scoped INTROSPECTION_TOKEN.

Confirm that the task used the candidate runtime version and completed without an unhandled interrupt or binding failure. Read its exact conversation rather than choosing an arbitrary recent one:

introspection tasks get <task-id> introspection conversations get <conversation-id> introspection runtimes get <candidate-runtime-id>

The runtime’s recipe commit must match the pull-request commit you intended to test.

4. Merge it to production

When the staged behavior is correct and the pull request is approved, merge it into the repository’s configured production branch. The GitHub integration creates the immutable version and activates it for production. There is no separate CLI promotion command.

Run a small production check through the stable runtime slug. Confirm that it resolves to the merged recipe commit and that the complete conversation still shows the expected behavior.

5. Learn and repeat

Production feedback, outcomes, observations, and recurring patterns show what users experience next. Follow Learn from production to inspect the exact conversations, form a hypothesis, and choose the smallest change worth making. That change returns to step 1.

Done when

  • The change behaves correctly in fresh Pi sessions.
  • Development tasks reach the local recipe through the real application path when needed.
  • Staging resolves the intended immutable runtime version and its bindings work.
  • The exact staging conversation shows the expected behavior.
  • Production resolves to the approved merged commit.
  • New production evidence can be traced back into the next focused recipe change.
Last updated on