---
name: deploy-create
description: "Put an Introspection agent (Recipe) on the platform: choose its repository with the owner (an existing one first), push and land the reviewed branch, create the runtime from `main` and wait for its version. Use after deploy-connect has connected the Recipe's required servers, or when the owner asks to deploy a Recipe that already exists. Needs `introspection login`; deploy-test follows."
metadata:
  min-cli-version: "0.73.0"
---

# Deploy: runtime

Take the agent from this machine to a running version on the platform, with the owner saying yes to each step that leaves this machine.

## Before you start

- **Read only what you need.** Every `introspection` command takes `--query` (JMESPath), so ask for the fields a step uses rather than whole records: `runtimes get <slug> --query image_build_status`, `runtimes versions <slug> --query "[0].[id, git_commit_sha]"`, `runtimes list --query "[].[slug, id]"`, `repositories list --query "[].name"`, `whoami --query "[member_name, project_id]"`. A single string prints quoted: strip it with `| tr -d '"'` when you capture it in a variable.
- You need the `introspection` CLI (`npm i -g @introspection-ai/cli`) and git. Check it's new enough before the first command: `introspection --version` must be at least this skill's `metadata.min-cli-version`, and `which -a introspection` must list only one. Otherwise stop and tell the owner what to run (`npm i -g @introspection-ai/cli@latest`, and remove an older build from their `PATH`). Use the CLI for the platform and git for pushing: the CLI has no push of its own, and login sets git up for the platform's repositories.
- **Check the stage.** After build: approved cases in `evals/cases/` and `docs/PULL_REQUEST.md` committed on `pr/<name>`; if either is missing, go back to build-review. An existing Recipe the owner asks to deploy needs neither: run `introspection check` in it, and if it passes, say in one line what it lacks (no cases, no pull request) and carry on from `main`.
- **Check the login:** `introspection whoami`. If it isn't signed in, ask the owner to run `introspection login` in their own terminal, then carry on. If it, `runtimes list` or `repositories list` fails with anything else (a 404, a connection refused, a server error), stop and show the owner the error: every later step depends on reading the platform, and a choice made without that reading can duplicate a runtime or a repository.
- <!-- rule: R-deploy-scopes-stop-before-register --> **Check its scopes** in the `whoami` output: creating a runtime needs `recipes:write`, `repositories:read` and `runtimes:write`, and pushing to a hosted repository needs `git:push`. If one is missing, name it and stop before creating anything.
- **Find out whether the agent already has a runtime:** `introspection runtimes list -o table`, for one named as in `.introspection/<name>.yaml`. A first deploy has none.

## Steps

Every step that leaves this machine (creating a repository, a push, creating a runtime) needs the owner's yes in this session: ask with the question tool, saying what happens and what it changes, one decision per question: a choice (which manifest, which repository) and the go-ahead to act on it are two questions, the choice first, and picking an option isn't a yes. [The record](references/record.md) keeps each approval.

1. **Choose the repository with the owner, an existing one first.** Recommend in the order below, never a new repository over one the owner named or one that already exists. When the build already asked (`build-review` records the choice in Part B's change log), use that choice and don't ask again; a repository the owner named that the organization's GitHub integration doesn't reach yet needs the GitHub App installed on its organization first, so say so and stop. Otherwise offer, in this order: the repository the clone already pushes to (`git remote -v`), one the project already has (`introspection repositories list -o table`), one the organization's GitHub integration already reaches (`introspection integrations repositories --type github`), and only if none fits a new private one the platform hosts. Never pick one yourself, and create or register it only once they've chosen, as [the repository reference](references/repository.md) says. A hosted one is ready to push when `repositories list` shows it `ready`.
2. **Push and land on `main`,** once the owner says yes. A runtime follows `main`: production serves it, and each push to it builds a version. After build, land the reviewed branch with a push, `git push origin pr/<name> pr/<name>:main`: a login can push but can't call the merge API (`repositories merge` needs `repositories:write`). An existing Recipe already on `main` needs no push. On the owner's machine, push with their own git access first: when `ssh -T git@github.com` authenticates (it exits 1 with a greeting), point `origin` at the repository's SSH URL (`git@github.com:<owner>/<name>.git`). Otherwise, or in a cloud session, run `introspection git-credential configure` once, and git takes a short-lived token from the organization's GitHub integration; if that push is still refused, stop and ask the owner, showing the exact error and the two ways to fix it: add an SSH key to their GitHub account, or give the organization's GitHub App access to the repository. Don't ask how to connect before trying: what works on this machine decides, not whether the repository is private. If git refuses the push to `main`, stop and show the owner the exact error. Never force-push or rewrite history.
3. **Connect the required MCP servers first, then create the runtime from `main`.** A required server connected project-wide before the runtime exists serves its first version, so that version can be ready; created first, it fails until someone connects the server. So when the Recipe declares a required server the project hasn't connected (`introspection bindings mcp list`), go to `deploy-connect` for those servers first, then come back and create. Two exceptions need the runtime first, so create, then connect straight after: BYOK, whose LLM binding attaches to the runtime, and a chat connector such as Slack (`requires_runtime: true` in `introspection connectors get`), whose connection names the agent that answers. If a runtime was created before its servers were connected, expect its first version to fail; that says nothing is wrong with the Recipe: connect, then make a new version.
   - <!-- rule: R-first-runtime-prod-bootstrap --> **A first runtime:** ask the owner which LLM model provider to use first (Introspection managed or BYOK) ([before the first runtime](references/repository.md#before-the-first-runtime)). Then `git fetch origin && git checkout -B main origin/main && git remote set-head origin --auto`, check again that `runtimes list` has none, and run `introspection runtimes create --yes` (`--manifest .introspection/<name>.yaml --yes` when the Recipe has several manifests: ask the owner which, as [the repository reference](references/repository.md#before-the-first-runtime) says). Its first version is `main`'s commit, live in staging and production at once: there's nothing to pin. If it warns that it couldn't read the default branch, the clone isn't on `main` with its head set: fix that and create again.
   - <!-- rule: R-no-second-runtime-group --> **An agent with a runtime** (a later change, or improve-propose's branch): later versions come from git, never from another `runtimes create`, which would split the agent's history, and never from a push to `main`, which goes live in production at once. Push only the branch (`git push origin pr/<name>`); the owner lands it through its pull request. Wait until `introspection runtimes versions <slug>` lists a version built from the branch's head commit with `image_build_status: ready`, then pin staging to it: `introspection runtimes pin <version-id> --sha <head-commit>`. The pin is to that exact commit, so after every later push to the branch, wait for the new head commit's version and pin it the same way. If none appears, stop and tell the owner; never push to `main` to get one. deploy-test then runs on that exact version (`--runtime-id <version-id>`). Once the owner has landed the pull request, `introspection runtimes unpin <version-id>` returns staging to following `main`.
4. **Wait for the version:** `introspection runtimes get <slug>` until `image_build_status` is `ready`; if the build failed, read its reason (`introspection runtimes get <slug> --query '[image_build_status, image_build_error_message]'`), show the owner that message and stop. "warmup was not delivered" means the platform couldn't reach the data plane when the version was created: once the data plane is up, make a new version (a push to `main`, or a retry from the Runtime's page). If it is still `pending` with no build metadata after about five minutes, the version hasn't started: stop polling and tell the owner, since on a local platform that usually means the data plane's worker isn't running. On a local platform a push to a GitHub repository makes a new version only while the webhook relay runs (`make dev-relay`); when a push adds no version, say so rather than waiting. Note the runtime, the version id (`introspection runtimes versions <slug>`) and the commit it was built from in [the record](references/record.md).
   - <!-- rule: R-registration-not-readiness --> A version can be ready while connections its Recipe needs are missing: deploy-connect is next for that.
5. **Show the owner the new runtime:** once a first runtime's version is ready, `introspection_open` with `{kind: "runtime", runtime: "<slug>"}` and `wait: true`, reason "Your agent is live: open it to chat with it", on its own in a turn, instead of a link in your reply. Carry on when they come back.
6. **Hand over to `deploy-test`,** or first back to `deploy-connect` for anything that needed the runtime (BYOK's LLM binding, a chat connector, a per-environment binding).

## Guardrails

- **The owner chooses every target:** the repository, its name, whether to push, the runtime. You propose; they decide.
- **Deploy what was reviewed:** push the branch as it is. A change found here goes back through draft and review.
- **Never force-push, rewrite history or delete a branch.** A file that shouldn't have been committed is removed with a new commit, and the owner is told.
- **Never handle credentials:** login holds them; a step that needs one the platform doesn't have is the owner's to set up.
- <!-- rule: R-runtime-resources-from-observation --> **Leave runtime resources unset** unless a run showed a need.

## Done when

- The Recipe is on `main` in the repository the owner chose.
- A runtime serves it, its version's image is ready, and the record names the runtime, version and commit.
