# Integrate Team Agents with your own systems

Understand what an integration is, which public library does what, the four ways to run approved prompts from your own runtime, and how to pick one.

A Team Agent is the bridge between prompts your team approved in AirPrompter and the application that actually runs them. AirPrompter keeps the history, the reviews, and the decision about what an environment _may_ run. Your system pulls a signed release, verifies it, keeps a local copy, calls your own model with your own keys, and reports content-free counters back. Nothing in AirPrompter opens a connection to you, reads your end users’ text, or makes a release live on a host you have locked.

**What travels, and what never does**

**Out to you:** a signed release (prompt text, the pinned model, inference settings, rollout arms, and a lease). **Back to AirPrompter:** one row per minute per prompt with counts, token totals, a latency histogram, error classes, and declared feedback signals. The row shape has no field for prompt text, model output, or an end-user identifier, so those cannot leave your host by accident.

## What an integration is

An integration is a runtime you own that does four things:

1. **Pulls** the release promoted to one environment (`dev`, `staging`, or `prod`) using an Agent key, or receives that release through a store you control.
2. **Verifies** it against a root public key you pinned when you set the runtime up, then keeps it encrypted on disk so a restart, or a network outage, keeps serving the last good release.
3. **Renders** a prompt by its key in code (the tag) with your variables and calls the model your release pinned, with your provider credentials.
4. **Reports** content-free measurements, and, optionally, feedback signals tied to a run reference.

AirPrompter never sits on your request path. `render()` is a local, in-memory operation; with the network gone, the last verified release keeps serving until its lease policy says otherwise.

## The library map

Every public package lives in the open-source `airprompter/airprompter-agent-sdk` repository (BSD-3-Clause). Install what you use; the packages share one version and one protocol version.

| You need to                                                                  | TypeScript (npm)                                                                  | Python                                                         | Notes                                                                      |
| ---------------------------------------------------------------------------- | --------------------------------------------------------------------------------- | -------------------------------------------------------------- | -------------------------------------------------------------------------- |
| Run prompts in a long-lived process with one call                            | `@airprompter/agent-sdk` (`AirPrompterAgent`)                                     | `airprompter-agent` (`AirPrompterAgent`)                       | The facade; re-exports everything below. Start here.                       |
| Verify manifests, open a bundle, render a template, with no I/O              | `@airprompter/agent-core`                                                         | `airprompter-agent-core`                                       | Pure protocol code; the CI test kit lives under its `testing` entry point. |
| Pull and verify releases in a job, or hold them in the encrypted store       | `@airprompter/agent-sync` (`pullBundle`, `SlotStore`)                             | `airprompter-agent-sync` (`pull_bundle`)                       | The fleet puller uses this.                                                |
| Render and attribute over a release you already hold; wrap a provider client | `@airprompter/agent-runtime` (`ReleaseResolver`, `wrapClient`, `aiSdkMiddleware`) | `airprompter-agent-runtime` (`ReleaseResolver`, `wrap_client`) | No store, no network of its own.                                           |
| Write the content-free spool yourself, or ship it                            | `@airprompter/agent-telemetry` (`SpoolWriter`, `SpoolUploader`)                   | `airprompter-agent-telemetry`                                  | Any process, in any language, can write the spool format.                  |
| Send the counters to your OpenTelemetry collector instead of AirPrompter     | `@airprompter/otel-bridge` (`otlpUploadSink`)                                     | `airprompter_agent_telemetry.otel` (`OtlpUploadSink`)          | Optional; no Agent key needed on that path.                                |
| Operate hosts from a shell or a service manager                              | `airprompter` CLI and `airprompterd`                                              | the same binaries                                              | Signed single-file executables; Python users never install Node.           |

Current published versions: the npm packages are at **0.2.9** and speak protocol **0.3.3**. The Python distributions exist at the same version in the repository and are **coming to PyPI**; until then, install from a built wheel. See [Python](https://airprompter.com/docs/integrations/python).

## The four shapes

[**Resident SDK**One process holds an Agent key, pulls on a timer, renders locally, and uploads its own counters. ](https://airprompter.com/docs/integrations/typescript)[**Fleet with your own database**One puller holds the key and writes sealed release rows; every runtime boots from the newest row with only a distribution key. ](https://airprompter.com/docs/integrations/fleet)[**Hosted, compatible endpoints**No SDK of ours: point the OpenAI or Anthropic SDK at a hosted environment and name the prompt as the model. ](https://airprompter.com/docs/integrations/hosted)[**Offline and air-gapped**Carry a signed update file across; apply it with the CLI; carry the telemetry file back.](https://airprompter.com/docs/integrations/cli)

### 1. Resident SDK

The default. `AirPrompterAgent.start(...)` reads the local store before any network call, syncs in the background (checking a few hundred bytes at a CDN edge first, so idle instances cost almost nothing), and serves every render from memory. Available in [TypeScript](https://airprompter.com/docs/integrations/typescript) and [Python](https://airprompter.com/docs/integrations/python). A serverless variant (`on_invoke` sync mode) syncs around each invocation and flushes its counters before the handler returns.

### 2. Fleet pattern with your own database

When you would rather not put an Agent key on every host, one **puller** job holds it. It pulls, verifies, seals the release to a distribution key you generated, and writes a row per generation into your database (SQLite, Postgres, DynamoDB; the shape is the point, not the engine). Every **runtime** holds only the distribution private key, boots from the newest row, and hands a newer row to `applyBundle()`. Details in [The fleet pattern](https://airprompter.com/docs/integrations/fleet).

### 3. Hosted environment through compatible endpoints

An environment can run hosted: AirPrompter runs the promoted version on the organization’s model access and meters it. You call it with the OpenAI or Anthropic SDK you already use by changing the base URL and the key, and naming the prompt as the model (`model: "slot:support.triage"`). The release owns the system prompt and the inference settings; the call cannot add instructions, add tools, or pick a model. Details in [Hosted environments](https://airprompter.com/docs/integrations/hosted).

### 4. Offline and air-gapped

For hosts with no route to AirPrompter, the environment’s Settings offers **Download update file**: the promoted release sealed to your registered distribution key. `airprompter verify` and `airprompter apply` run the same verification chain a runtime runs; `airprompter export-telemetry` packs the counters into one file to carry back. Details in [The CLI and the daemon](https://airprompter.com/docs/integrations/cli).

## How to pick

| Situation                                                                          | Shape                                   | Why                                                                                         |
| ---------------------------------------------------------------------------------- | --------------------------------------- | ------------------------------------------------------------------------------------------- |
| One service, or a few, each able to reach AirPrompter over outbound HTTPS          | Resident SDK                            | Least moving parts; the SDK owns sync, store, upload, and health.                           |
| Many hosts, or a policy that keeps Agent keys off application hosts                | Fleet pattern                           | One key in one job; runtimes read rows and hold only a distribution key.                    |
| Several processes on one host that would otherwise each pull and each hold a store | Resident SDK attached to `airprompterd` | One sync loop and one store per host; processes attach over a local socket and need no key. |
| You do not want to run models yourself, and the prompt takes one user turn         | Hosted environment                      | The provider SDK you already use, unchanged at the call site.                               |
| Hosts that never reach the internet                                                | Offline                                 | A file in, a file out; the verification chain is identical.                                 |
| Prompts already instrumented by your own code, in any language                     | Write the spool directly                | The spool format is a published contract that `airprompterd` uploads.                       |

You can mix shapes per environment: `dev` on a resident SDK against a workstation, `prod` on the fleet pattern with change control. The prompt’s key in code never changes between them.

## Before you integrate

You need:

- a workspace with **Team Agents** and at least one agent whose board has a prompt promoted to the environment you will run;
- the agent’s **organization id** and **agent id** (shown on the agent’s Settings tab);
- an **Agent key** for that environment from the agent’s **Settings → Keys**, stored in a secret manager and exposed to the runtime as an environment variable (`AIRPROMPTER_AGENT_KEY`); it is never passed on a command line and never printed;
- the **root public key** for the AirPrompter deployment you talk to (the public service is `prod`), shown on the same Settings tab and pinned in your project as a JSON Web Key file; and
- a provider credential for the model your release pins, handled by your own secret management.

An Agent key is read-only for governance: it can fetch its own agent’s release for its own environment and write telemetry under its own prefix. It cannot seal, promote, unlock, or countersign anything.

**Keys travel by environment variables only**

Every sample in this section reads the Agent key from the process environment. Do not paste a key into source control, a shell history, a container image, a log line, or a support ticket. Rotate in the console with overlap: mint the second key, roll your fleet, revoke the first.

## Make the smallest proof

1. Promote one prompt to `dev` from the agent’s board.
2. Mint a `dev` Agent key and export it as `AIRPROMPTER_AGENT_KEY` in a terminal you will close afterwards.
3. Run the TypeScript or Python quick start against `dev` with a fresh state directory.
4. Render the prompt once and print only its `versionId`, `arm`, and `model`, never its text.
5. Open the agent’s **Fleet** tab and confirm your instance appears with the generation you just served.

**Expected result:** the runtime reports the promoted generation, the Fleet tab shows one instance on it, and the prompt renders with the release’s pinned model. From here, the same code serves your real work day-to-day: change the prompt in AirPrompter, promote, and watch the generation move without a deploy.

## Troubleshooting

### `start()` fails with `no_verified_release`

The message names the cause. A 404 means no release is promoted to that environment yet; promote one from the board. A 401 is the key; a 403 carries the server’s code (commonly a key bound to another agent or environment). A transport failure carries the base URL it tried.

### The runtime serves, but the Fleet tab shows nothing

Heartbeats go out every five minutes by default (`heartbeatSeconds`). Check `ap.status().heartbeat.lastRefusal` for a refused heartbeat; a refusal is logged as `heartbeat_refused` with the server’s message.

### Renders refuse with `disabled`

Someone froze the environment, the agent, or a slot from the console. The runtime honours a freeze from any manifest whose signature verifies, even one left staged. Lift the freeze; the next sync clears it.

## Completion checklist

- You know which of the four shapes each environment will use.
- The Agent key reaches the runtime only through the environment.
- The root public key is pinned in your project, not fetched at runtime from an unverified place.
- Your runtime appears on the Fleet tab on the promoted generation.
- Nothing you print or log is prompt text or model output.

## Next steps

Build the resident shape in [TypeScript](https://airprompter.com/docs/integrations/typescript) or [Python](https://airprompter.com/docs/integrations/python), or plan a fleet with [your own release store](https://airprompter.com/docs/integrations/fleet). To understand what leaves your host, read [Telemetry](https://airprompter.com/docs/integrations/telemetry) first.

---

Canonical: https://airprompter.com/docs/integrations
