# Agents as code

> Keep your agents in a repository, and deploy them the way you deploy everything else.

An agent's whole definition — its prompt, configuration, voice, languages and analysis — is one
document you can read, keep in a repository, change, and put back. It is the console's own export
format, so a file exported from an agent's menu works here too.

## The key it needs

Make a **live** key with **Change agents** (`agents:write`). It reads an agent's prompt and changes
what agents say to real callers, so it is ticked on its own, never part of a starting point. A
test key reads definitions and changes nothing. A key limited to some agents cannot make new ones.

## Read a definition

```sh
node aigently.mjs agents retrieve-definition 8a1f3c2e-… > front-desk.json
```

`GET /v1/agents/{id}/definition` answers with `format`, the `agent` itself, and `references`:
every tool, MCP server, knowledge base, calendar and callback agent it uses, **by name**. Nothing travels as
an id, and nothing secret travels at all — no credential, no phone number, no domain.
`GET /v1/agents/{id}/versions/{version}/definition` reads a published version the same way.

## Create one

`POST /v1/agents` with a `project_id` and a `definition` makes a **draft** in that project. Each
name in `references` is looked up there; what has no match is left out and listed in `unbound`,
with what the agent does without it — so a definition from staging lands in production without
binding to the wrong tool. Leave out `name` to use the definition's own, made free in the project;
a name you give that is taken is refused with `agent_name_taken`.

## Change one

```sh
node aigently.mjs agents replace-definition 8a1f3c2e-… --definition @front-desk.json
```

`PUT /v1/agents/{id}/definition` puts a definition back: the prompt, the configuration, and the
tools, MCP servers and knowledge bases it names. Its kind and direction must be the agent's own. **On a
published agent the change is live at once**, as an edit in the console is, and the agent shows
changes not yet published until the next publish freezes them. An `agent.updated` event says when
the agent's fields moved.

Putting back what you read leaves the agent as it was. A model, a voice or a background your
organization added itself is named in `references.voice_rows` rather than written in `voice`, and
the agent keeps it while the definition still names it and leaves that `voice` field at its
default. To move to another, set the field in `voice`. A recorded greeting is never in a
definition, and the agent keeps it. Leave out `surfaces` and the agent keeps its own.

A definition is checked as an edit in the console is: the prompt, the description and the knowledge
settings have the console's limits, and `surfaces` lists each surface once. A callback agent must
be an inbound agent that takes phone calls, and one your key reaches; otherwise it is listed in
`unbound`.

## Publish

`POST /v1/agents/{id}/publish`, with an optional `note`, runs the console's own Publish check — the
prompt, tools and their credentials, models, transfer destinations, and the agent's rehearsals —
and either freezes the agent as its next version or refuses with `agent_not_publishable`, every
reason in `errors`. The version's history in the console names the key that published it.

The tools and credentials an agent uses can be put in place the same way
([Tools and credentials](/guides/tools)), and its saved conversations rehearsed before you publish
([Evaluations in your pipeline](/guides/evaluations)). A deploy step in your pipeline is then three
requests: replace the definition, publish, and pin your integrations to the version it answered
with ([Pin a version](/guides/variables#pin-a-version)).

## Delete

`DELETE /v1/agents/{id}` takes the agent off the air and into the trash. The console can restore it
for 30 days, with its conversations and recordings; then it is gone for good.
