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

# Command lifecycle

> How gateway commands move from UI action to runner execution.

Commands are rows in `agent_commands`. They represent every instruction the UI gives to a gateway — provisioning agents, approving pairings, connecting providers, restarting services, and more.

## State machine

```text theme={null}
pending  →  leased  →  running  →  done
                    ↘          ↘  failed
```

<Steps>
  <Step title="UI inserts a command">
    A server action writes a row to `agent_commands` with `status = 'pending'`.
  </Step>

  <Step title="Runner leases the command">
    The runner daemon picks it up via Realtime subscription or polling, then calls `lease_command(p_gateway_slug)` to atomically claim it.
  </Step>

  <Step title="Runner executes">
    The runner maps the command action to a shell operation (e.g. `add-agent.sh` for provision) and runs it.
  </Step>

  <Step title="Runner reports results">
    On completion, the runner writes `stdout`, `stderr`, `exit_code`, and final `status` (done or failed) back to the row.
  </Step>
</Steps>

## RPC lifecycle calls

The runner uses four RPCs to manage command state:

| RPC                                                                    | Called when                                                                                                                      |
| ---------------------------------------------------------------------- | -------------------------------------------------------------------------------------------------------------------------------- |
| `lease_command(p_gateway_slug, p_lease_seconds)`                       | Runner atomically claims a pending command. Returns the command row or nothing. Lease duration = `COMMAND_TIMEOUT + 60` seconds. |
| `start_command(p_command_id)`                                          | Runner marks the command `running` just before executing it.                                                                     |
| `complete_command(p_command_id, p_exit_code, p_stdout, p_stderr)`      | Command exited 0.                                                                                                                |
| `fail_command(p_command_id, p_exit_code, p_stdout, p_stderr, p_error)` | Command failed (non-zero exit, timeout, or validation error).                                                                    |

Connection actions (`auth_*`) call `start_command` and `complete_command`/`fail_command` themselves — they don't go through the standard shell-command path.

## Durability

Commands are never deleted after completion. They persist as a full history of every operation — viewable from Settings → System → Commands.

<Tip>
  If a command is stuck in `leased` or `running` for more than 5 minutes, the runner likely crashed or lost its lease. Check `docker compose logs runner` for details.
</Tip>

See [Command actions](/reference/command-actions) for the full list of supported actions and their payload schemas.
