Agent development lifecycle
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
pnpm add --global @introspection-ai/cliThen 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-agentinit 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:
| Concern | Recipe resource |
|---|---|
| Package identity and declared resources | package.json |
| Rules shared by every agent | SYSTEM.md |
| Models, role-specific instructions, tools, and subagents | Agent definitions |
| Reusable domain workflows and deliverable shapes | Skills & prompts |
| Recipe-owned code and deterministic tools | Extensions |
| Node modules used at runtime | dependencies |
| Portable access to external tools | MCP declarations |
| Locked Python and approved system capabilities | pi.runtime |
| Source and files supplied to managed tasks | Packaging a recipe |
| Durable production quality standards and your own test coverage | Judges & 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-agentTry 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-agent2. 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-agentLeave 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 edited | Takes effect |
|---|---|
| A skill body, or a script the agent runs | The next turn, in the same chat |
SYSTEM.md, agent YAML, prompts, extensions, MCP declarations | A 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/mcpRun 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 JohnThen 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 devThe 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:
JavaScript SDK
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.
