Skip to Content
Platform
GuidesConnecting an agent

Connecting an agent

Take a Git-backed recipe to a completed staging task. Start with the JavaScript SDK, or select the CLI tab to follow the same workflow from a terminal.

Connecting an agent establishes four linked pieces:

Recipe (git-backed behavior) → Runtime version (deployable execution) → Staging lane + bindings (where and with what it runs) → Task → Conversation (work and its captured record)
  • A recipe is the agent behavior—agents, instructions, skills, and judges—pinned to an exact Git commit.
  • A runtime version combines that immutable recipe with the execution policy and resources needed to run it. Related versions share one stable runtime group.
  • An environment lane selects which version and bindings serve development, staging, or production traffic.
  • A task is one durable execution. Its conversation is the evidence used by observations, judges, and experiments later in the loop.

Before you start

You need a project whose GitHub integration already has access to the repository. Runtime bootstrap also requires a clean checkout of pushed main: HEAD must equal origin/main, and origin must be that GitHub repository.

npm install -g @introspection-ai/cli npm install @introspection-sdk/introspection-node introspection login introspection whoami git status --short git branch --show-current git rev-parse HEAD origin/main

Stop if the two SHAs differ or the status is not empty. whoami must identify the intended project and include the runtime/task scopes used below.

Runtime bootstrap, staging selection, and bindings are operator mutations and remain CLI-only. Task execution is available through both surfaces, so that step uses SDK/CLI tabs.

1. Validate and bootstrap

The manifest is the repository-level declaration that connects the recipe package to its runtime defaults. Its filename is the stable runtime-group slug, so later commits become new versions of the same logical agent instead of unrelated runtimes. This example assumes .introspection/support-agent.yaml points at the recipe package in the same repository.

introspection recipes validate --profile publish introspection runtimes create \ --manifest .introspection/support-agent.yaml > runtime.json export RUNTIME_ID=$(jq -r '.id' runtime.json) export RUNTIME_GROUP_ID=$(jq -r '.runtime_group_id' runtime.json) export RECIPE_ID=$(jq -r '.recipe_id' runtime.json) test "$RUNTIME_ID" != null test "$RUNTIME_GROUP_ID" != null test "$RECIPE_ID" != null

Success means validation exits 0 and all three IDs are present. Image creation is asynchronous; wait at most five minutes for readiness:

for attempt in {1..60}; do introspection runtimes get "$RUNTIME_ID" > runtime-current.json IMAGE_STATUS=$(jq -r '.image_status' runtime-current.json) [ "$IMAGE_STATUS" = ready ] && break [ "$IMAGE_STATUS" = failed ] && { jq . runtime-current.json; exit 1; } sleep 5 done test "$IMAGE_STATUS" = ready

2. Point staging at the version

Staging is the fast iteration lane. Tracking main advances it as the repository integration creates new versions; pinning freezes it on one exact version for a controlled test.

introspection runtimes staging track "$RUNTIME_ID" --git-ref main introspection runtimes versions "$RUNTIME_ID" -o table

Use staging pin instead when staging must remain on this exact version while new commits arrive.

3. Satisfy declared bindings

Bindings provide environment-specific configuration without placing secrets in the recipe. A recipe declares what it needs; the operator connects concrete endpoints, readable variables, and write-only credentials at the project, runtime-group, runtime, or environment scope.

Skip this step when the recipe uses the managed model and declares no external bindings. For a declared MCP server named linear, keep the secret out of argv:

export LINEAR_TOKEN='replace-me' introspection bindings credentials create \ --name LINEAR_TOKEN \ --value-env LINEAR_TOKEN \ --runtime-group "$RUNTIME_GROUP_ID" \ --environment staging introspection bindings mcp connect \ --recipe "$RECIPE_ID" \ --mcp-server-id linear \ --name Linear \ --endpoint-url https://mcp.example.com/mcp \ --header 'Authorization=Bearer ${LINEAR_TOKEN}' \ --runtime-group "$RUNTIME_GROUP_ID" \ --environment staging introspection bindings mcp list \ --recipe "$RECIPE_ID" \ --runtime-group "$RUNTIME_GROUP_ID" \ --environment staging

Success means every required declaration is connected and no row reports a missing required binding. See introspection bindings mcp connect --help when the endpoint needs credential-backed headers.

4. Create and follow the first task

Running the runtime opens a sandbox under an end-user identity. Starting a task creates the first run; later prompts or interrupt responses create additional runs on the same durable task.

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: "docs-smoke-1" }, }); const handle = await runner.tasks.start({ prompt: "Reply with the word ready.", }); for await (const event of handle.stream()) { console.log(event.event, event.data); } await runner.close();

Use a staging-scoped INTROSPECTION_TOKEN. For only the final text, replace the stream loop with const reply = await handle.text().

In the CLI tab, follow emits one AG-UI event per JSONL line and returns when the run settles. Preserve the highest numeric sequence if you reconnect; pass it back with --since. A resume_gap event means the bounded replay window no longer contains every missing event, so refetch the task and conversation instead of assuming a complete stream.

If the run pauses for input, inspect metadata.pending_interrupts in task-final.json, answer the complete batch, then follow the new current run:

introspection tasks resume "$TASK_ID" \ --interrupt-id <id-from-metadata> \ --payload '{"answer":"approved"}' introspection tasks follow "$TASK_ID" --run current --since 0 introspection tasks get "$TASK_ID" > task-final.json jq -e '.status == "idle" or .status == "completed"' task-final.json

resume rejects partial batches. Provide each pending interrupt exactly once, using --cancel-interrupt for any answer you intentionally cancel.

Done when

  • runtimes get returns the expected immutable version and runtime group.
  • Required staging bindings are connected.
  • tasks follow settles without an unhandled interrupt.
  • tasks get ends at idle or completed; failed, cancelled, and awaiting_user are not success.

Keep RUNTIME_ID, RUNTIME_GROUP_ID, and TASK_ID; the next guide uses them.

Next

  • CLI: complete command and output semantics.
  • Bindings: endpoint, variable, and credential precedence.
Last updated on