> ## Documentation Index
> Fetch the complete documentation index at: https://docs.komodor.com/llms.txt
> Use this file to discover all available pages before exploring further.

# Deploy an agent

> How an agent becomes a running worker — where it can run, the three values it needs, and exactly what happens on first registration.

An agent in the Komodor Agentic Operation Platform (KAOP) is a record until a worker process claims
it. Deploying is the step that connects the two: you start the worker, it registers, and the agent
goes live. This page covers where a worker can run, what it needs from you, what first registration
looks like, and how to tell a healthy deployment from a stuck one.

## Where a worker can run

The **Where it runs** step offers two homes, and the choice is about who operates the process.

<CardGroup cols={2}>
  <Card title="Komodor cloud" icon="cloud">
    Komodor runs the worker and manages its replicas. Nothing to install, nothing to keep running.
    This is the default for an agent deployed from the catalog.
  </Card>

  <Card title="Self-hosted" icon="server">
    You run the worker in your own environment. Use this when the agent needs network access or data
    locality you cannot grant from outside — and it is the default when you are authoring your own
    agent.
  </Card>
</CardGroup>

<Note>
  Some catalog agents have only one possible home. When that is the case the step does not appear and
  the target is decided by the agent itself.
</Note>

## What a worker needs from you

Exactly three values, all environment variables:

| Variable                | What it is                           |
| ----------------------- | ------------------------------------ |
| `AGENTOPS_URL`          | The control plane's base URL         |
| `AGENTOPS_AGENT_ID`     | The agent this worker runs           |
| `AGENTOPS_WORKER_TOKEN` | A worker token minted for that agent |

<Warning>
  The worker token is shown **once**, when it is generated or rotated. Store it in your own secret
  manager as you create it. If you lose it, rotate to get a new one — you cannot read the old value
  back.
</Warning>

A handful of optional variables refine the deployment rather than enable it:

| Variable                                                             | Effect                                                            |
| -------------------------------------------------------------------- | ----------------------------------------------------------------- |
| `AGENTOPS_MAX_CONCURRENT`                                            | How many runs one worker process handles at once. Defaults to `1` |
| `AGENTOPS_CLUSTER_NAME` · `AGENTOPS_NAMESPACE` · `AGENTOPS_POD_NAME` | Surface where each replica runs, so the console can show it       |
| `AGENTOPS_MODEL`                                                     | Override the model this worker uses                               |

<Note>
  Nothing else is required. The worker binds no port and serves no HTTP — it dials the control plane
  and receives work over that one outbound connection. There is no inbound firewall rule to open and
  nothing to route traffic to, which is what lets a worker run behind NAT or inside a private cluster.
</Note>

## Deploy it

<Steps>
  <Step title="Get a worker token">
    From the wizard's final step, from **Settings → Agents**, from the agent's panel in Fleet, or
    with `POST /api/v1/agents/worker-token`.
  </Step>

  <Step title="Run the worker">
    Start it however you run software, with the three variables set. For a Kubernetes deployment the
    wizard renders the values file and the matching `helm install` command for you — the release name
    is the agent's own name.
  </Step>

  <Step title="Watch it register">
    The console polls for the agent's first heartbeat and reports when it arrives. The agent moves
    from **draft** to **online**.
  </Step>

  <Step title="Confirm the round trip">
    Use the agent's self-check to make the control plane ask the worker a question and wait for its
    answer. A worker that is offline, too old, or unresponsive still resolves — as a failure with a
    reason, rather than hanging.
  </Step>

  <Step title="Run it once">
    Press **Run agent** and read the run. See [Reading the first run](#reading-the-first-run).
  </Step>
</Steps>

## What happens on first registration

Worth understanding once, because it explains every symptom you will ever debug here.

```mermaid theme={null}
sequenceDiagram
  participant W as Worker
  participant CP as Control plane
  W->>CP: register (manifest, skills)
  CP-->>W: acknowledged — agent goes live
  W->>CP: open the outbound channel
  CP-->>W: channel established
  W->>CP: pull boot secrets
  CP-->>W: secrets for this agent
  CP-->>W: work available
  W->>CP: claim the run
  CP-->>W: run payload, secrets, session state
```

<Steps>
  <Step title="It registers itself">
    The worker sends one registration message carrying the agent's manifest — its card, its skills,
    its declared triggers and labels. This is the only thing a worker ever says about *itself*, it is
    sent once per process, and it is retried until it lands.
  </Step>

  <Step title="The agent becomes real">
    The control plane records the agent, ensures its identity as a principal, reconciles its declared
    triggers and channel routes, and clears the draft. The agent's status changes from **draft** to
    **online** and it appears in Fleet.
  </Step>

  <Step title="It opens its channel">
    The worker holds an outbound connection open for work notifications. Until registration has
    landed, opening that channel is refused — the SDK treats this as the expected start-up race and
    simply retries, so a refusal in the first seconds of a worker's life is normal, not a fault.
  </Step>

  <Step title="It pulls its boot secrets">
    After registering and before its first run, the worker fetches the credentials bound to its
    agent that it needs at start-up.
  </Step>

  <Step title="It waits for work">
    When a run is available the control plane rings a doorbell rather than pushing the payload.
    Workers respond by claiming the run, and the one that wins the claim receives the input, the
    secrets, and any session state.
  </Step>
</Steps>

<Info>
  The claim model is why work is never lost to a dead worker. Ownership is decided by the claim, not by
  the delivery, so if a worker dies mid-run the run is requeued for another one rather than
  disappearing into a process that is no longer there.
</Info>

### What "enabled" means at this point

A newly registered agent is **enabled**, so its declared triggers can fire as soon as it is healthy.
If that is not what you want on the first deployment, disable the agent before you start the worker
and enable it once you have read a manual run. See
[Manage a deployed agent](/manage-your-agents/build/manage-a-deployed-agent).

## Reading online and offline

| Status      | Meaning                                             |
| ----------- | --------------------------------------------------- |
| **Draft**   | The agent exists but no worker has ever reported in |
| **Online**  | A worker reported in recently                       |
| **Offline** | No worker has reported in for 90 seconds            |

Presence is the control plane's question, not the worker's claim: it pings each open channel every 30
seconds and the worker's reply is what keeps it present. An idle worker sends nothing on a timer of
its own.

<Note>
  Two consequences worth knowing. A worker that dies without closing its connection takes up to 90
  seconds to show as offline, so the badge lags reality slightly. And an idle worker that has gone
  quiet is indistinguishable from one that died — by design.
</Note>

## Replicas

One worker process runs one agent, but an agent can be backed by several replicas, and each is
tracked separately: its own identity, its own busy-or-idle state, and the cluster, namespace, and pod
it runs in.

* Run more replicas when the agent's queue is growing. Read **Queued** and **Oldest queued** on the
  agent to decide.
* For a self-hosted agent, the **Scaling** step can declare autoscaling bounds — minimum and maximum
  replicas, and the queue depth each replica should absorb.
* For an agent Komodor hosts, replica count is managed for you.

Because a replica identity is minted per process, an agent accumulates an entry per restart. Read
the instance counts rather than the length of the list.

## Reading the first run

Open the run from the agent's **Run history**. What you are checking, in order:

1. **It started.** A run that never leaves the queue means no worker claimed it — check that the
   agent is online.
2. **It could see what it needed.** Missing tool calls, or tool calls that failed on
   authentication, point at a connection that is not attached or a credential that is not bound.
3. **It returned both channels.** Structured fields for automation, and readable text for a person.
4. **It cost what you expected.** Token usage is recorded per run, so a surprise here is visible
   immediately rather than at the end of the month.

## When it does not come up

| Symptom                                                 | Likely cause                                                                                                                                    |
| ------------------------------------------------------- | ----------------------------------------------------------------------------------------------------------------------------------------------- |
| Agent stays **draft**                                   | The worker never registered — check `AGENTOPS_URL` is reachable from where the worker runs, and that the token is the one minted for this agent |
| Registration refused, worker exits                      | The token was revoked or rotated, or it does not match the agent id the worker declares                                                         |
| Agent flips to **offline** while the process is running | The worker cannot maintain its outbound connection — check egress from its network to the control plane                                         |
| Online, but runs stay queued                            | The agent may be disabled, or every replica is busy. Check the queue depth                                                                      |
| Runs start and fail on tool access                      | The connection or credential the handler needs is not attached to this agent                                                                    |

See [Troubleshooting](/reference/troubleshooting).

## Next steps

<CardGroup cols={2}>
  <Card title="Manage a deployed agent" href="/manage-your-agents/build/manage-a-deployed-agent">
    Enable, disable, edit, archive, and read its activity.
  </Card>

  <Card title="Triggers & schedules" href="/manage-your-agents/build/triggers-schedules">
    Give it a recurring schedule now that it is live.
  </Card>

  <Card title="Credentials & secrets" href="/manage-your-agents/build/credentials-secrets">
    Bind the secrets it resolves at boot and per run.
  </Card>

  <Card title="Runs & evidence" href="/manage-your-agents/run/runs-evidence">
    Read the evidence trail behind that first run.
  </Card>
</CardGroup>


## Related topics

- [Deployment methods](/get-started/deployment-methods.md)
- [Use specialized agents](/manage-your-agents/build/use-specialized-agents.md)
- [Install](/get-started/on-prem/install.md)
- [Marketplace](/manage-your-agents/build/marketplace.md)
- [Kubernetes RCA](/manage-your-agents/build/catalog/kubernetes-rca.md)
