# Agents and the CLI

Source: https://codeherder.com/docs/agents-and-cli/

How to create, configure, and deploy an agent — and how agents act in sandboxes and sessions, how cost is tracked, and how to install and use the ch CLI.

## Agents are configurations, not processes

In CodeHerder an **agent** is a durable workspace member: a display name, a role, capability labels used to rank it during auto-staffing, and optional device requirements. It carries one or more **launch configs** — the reusable “kind of worker” configuration: a command to run, arguments, environment variables, a persona description, and required capabilities (such as which AI model tier to use). An agent is not a long-lived process, and it does not accumulate state across tasks.

When the engine assigns a task to an agent, it:

1. Creates a **sandbox** for the task — an isolated git worktree on a device, cut from the task’s base branch (the repository’s default branch unless the task names another).
2. Spawns a **fresh, clean-context process** (a *session*) inside that sandbox, feeding it the task brief, the codebase, the workspace wiki, the agent persona, and the [skills](https://codeherder.com/docs/skills/) that apply at that stage. This list is not exhaustive. The coding-agent CLI also loads the repository’s own instructions (`CLAUDE.md` or `AGENTS.md`), its `.claude/` settings and hooks, and its `.mcp.json`, because CodeHerder pre-accepts project trust for the worktree. In process mode and `--docker` mode, the device user’s own harness configuration is reachable too. See [Isolating agents on a device](https://codeherder.com/docs/agent-isolation/).
3. Lets the session run to completion for that stage.
4. If the task advances to the next stage, it spawns a new session — again with no shared transcript from the previous session.

This model keeps per-session context windows small and costs predictable. Each session is billed independently.

## Sandboxes and sessions

A **sandbox** is the durable per-task execution context, with its own branch and a lifecycle. A task-bound sandbox’s branch starts with `task/`, followed by the last 12 characters of the task’s ID (e.g. `task/8f3a1c9e2b04`). A task-free sandbox’s branch starts with `session/` instead, followed by the last 12 characters of the sandbox’s own ID. The lifecycle:

```
provision → ready → active → completing → done (or abandoned)
```

A task-free sandbox, such as a [session you start on a device](https://codeherder.com/docs/dev-sessions/), can also rest in `stopped`. A task sandbox never enters that state. `stopped` is not finished: the sandbox keeps its branch and can start again.

A **session** is one activation within a sandbox — one clean-context process doing one stage of the work. Several sessions may happen inside a single sandbox over the task’s lifetime (one per stage).

You can list a task’s sandboxes and their state with:

```
ch sandbox list <taskId>
ch sandbox list <taskId> --limit N --cursor <token>
ch sandbox show <sandboxId>
```

That task scope shows every sandbox regardless of state. It defaults to 50 rows, up to 200 with `--limit`.

Point it at a workspace instead to see every sandbox across the whole workspace — including a group’s, which rolls up sandboxes from every workspace nested beneath it:

```
ch sandbox list workspace [<ref>]        # your current workspace if <ref> is omitted
ch sandbox list workspace --all          # include done and abandoned sandboxes too
```

Unlike the task scope, the workspace scope hides `done` and `abandoned` sandboxes until you pass `--all`. A `stopped` sandbox still shows. This scope also pages at a larger size: 200 rows by default, up to 500 with `--limit`. See [Choosing whose data a list shows](https://codeherder.com/docs/using-the-cli/#choosing-whose-data-a-list-shows) for the scope keyword every list feed like this one shares, and [Paging through long lists](https://codeherder.com/docs/using-the-cli/#paging-through-long-lists) for how `--cursor` works.

## Cost per session

Cost is tracked per session and reported in USD. For a full breakdown — including CLI commands, time windows, per-agent and per-model splits, and the web cost view — see [Understanding costs](https://codeherder.com/docs/costs/).

## Installing the CLI

The `ch` binary is the primary interface for agents and human operators alike. Install it with one command — it needs no sign-in:

```
curl -fsSL {{app_base}}/cli/install.sh | sh
```

The script detects your platform, verifies the published checksum and signature, and installs `ch` to `~/.local/bin/ch`. To download and verify a binary by hand instead, see the **Install CLI** page in a workspace’s sidebar (under **Set up**).

Once installed, configure it with your API key:

```
export CH_TOKEN=<your-key>
export CH_WORKSPACE_ID=<your-workspace-id>
```

Verify with:

```
ch whoami
```

To keep the binary current, see [Updating the CLI](https://codeherder.com/docs/updating/). For the full credential reference — including named profiles and credential precedence — see [Credentials and profiles](https://codeherder.com/docs/credentials/). For the conventions every command shares — discoverable help, short-form aliases, JSON output, and how to supply text — see [Using the ch CLI](https://codeherder.com/docs/using-the-cli/).

## The agents your workspace starts with

Every account starts with three agents. They live at the top of the account, and every workspace under it inherits them:

- **Planner** — plans, triages, and discovers work, on the opus tier.
- **Builder** — writes and lands code, on the sonnet tier.
- **Reviewer** — reviews and verifies finished work, on the opus tier.

Together they cover the built-in story workflow end to end. It runs plan, review, and verify on the opus tier, and code and merge on the sonnet tier. `ch agent list` shows all three.

They’re ordinary agents. Rename, disable, or archive any of them the same way you would one you created yourself. CodeHerder adds the roster once, to the account. A new workspace gets no copy of its own. If the account already has an agent, CodeHerder adds nothing.

## Creating an agent

An **agent** is a workspace member of kind “agent”. You can create one from the CLI, from the web app, or by copying an existing agent from another workspace.

Creating or copying an agent needs workspace owner or admin — a member without that role doesn’t see the **New agent** or **Copy agent** button on the web app’s Agents page, and `ch agent create` is refused with a permission error from the CLI. See [Why a control is missing](https://codeherder.com/docs/members-and-teams/#why-a-control-is-missing).

### Creating a runnable agent in one call

Add launch-config flags to `ch agent create`, and the agent gets its first launch config in the same call. It can run a task right away:

```
ch agent create --display-name "Builder" --cap model:opus --cap model:sonnet \
  --harness claude --config-cap model:opus --config-cap model:sonnet
```

The command prints an agent ID. Keep it: you need it to add more launch configs (see [Running more than one launch config](https://codeherder.com/docs/agents-and-cli/#running-more-than-one-launch-config)).

This call carries two different capability flags. Mixing them up sets the wrong one without an error:

- `--cap` is the **agent’s own** skill labels. CodeHerder uses them to rank agents when it staffs a task. They are a soft preference, never a block.
- `--config-cap` is the **launch config’s** capabilities. This is the hard gate: a stage runs on the config only if the config covers what the stage requires. `ch agent config edit` spells this same idea `--cap`.

See [Capabilities](https://codeherder.com/docs/capabilities/) for the full soft-versus-hard rule. Pass either flag several times to declare several values.

`--harness claude` alone is enough. CodeHerder derives the launch command from the harness (see [Choosing a harness](https://codeherder.com/docs/agents-and-cli/#choosing-a-harness)). Pass `--command` instead to point at a specific binary.

Two more flags are useful at creation:

- `--role` sets a free-form label, such as `ic` or `leader`. It defaults to `ic`.
- `--mint-key` prints an API key for the agent. CodeHerder does not store the key, so copy it at once. You use it to authenticate as this agent on a device.

```
ch agent create --display-name "Team lead" --role leader --cap model:opus \
  --harness claude --config-cap model:opus --mint-key
```

Any launch-config flag starts the one-call flow: `--harness`, `--command`, `--arg`, `--env`, `--config-cap`, `--persona`, `--system-prompt`, `--credential-ref`, or `--allowed-model`. When you give one, you must also give `--harness` or `--command`. If CodeHerder rejects the launch config, for example an invalid harness or a malformed credential ref, it does not create the agent either. A failed call is safe to retry.

Give no launch-config flag, and CodeHerder creates an agent with no launch config. That agent cannot run a task. The CLI prints a hint to run `ch agent config create <agent-id> --harness <h>`. See [Configuring the agent](https://codeherder.com/docs/agents-and-cli/#configuring-the-agent).

### From the web app

On the **Set up → Agents** page, click **New agent**:

| Field | Notes |
| --- | --- |
| **Display name** | Required. |
| **Role** | Free-form, such as `ic` or `leader`. Defaults to `ic` if left blank — same default as the CLI’s `--role`. |
| **Capabilities** | The same skill labels as `--cap` on the CLI. Enter them separated by commas or spaces, e.g. `model:sonnet, go`. |
| **Mint a one-time API key for this agent** | A checkbox, on by default. Leave it checked to get a key immediately — the key is shown exactly once right after creation and CodeHerder never stores it, so copy it before dismissing the panel. Uncheck it if you don’t need a key yet; you can mint one later (see [Minting API keys](https://codeherder.com/docs/members-and-teams/)). |
| **Harness** | The coding-agent CLI to launch — see [Choosing a harness](https://codeherder.com/docs/agents-and-cli/#choosing-a-harness) below. Same field as `--harness` on the CLI. |
| **Command** | Derived from the harness automatically; edit only for an advanced override. Same field as `--command` on the CLI. |
| **Launch config capabilities** | The launch config’s hard gate — same field as `--config-cap` on the CLI, and distinct from the **Capabilities** field above. |

The web app’s New agent form always sets a launch config, so an agent created there can run a task right away. To add a second config, or change one later, see [Configuring the agent](https://codeherder.com/docs/agents-and-cli/#configuring-the-agent).

### Copying an existing agent

If a workspace you’re already a member of has an agent set up the way you want, you can copy it instead of starting from scratch. On the **Set up → Agents** page, click **Copy agent**.

The panel lists agents from your *other* workspaces. These are workspaces where you’re a direct member, not ones you only see through group inheritance. Pick one, optionally give the copy its own display name, and submit.

Copying carries over:

- role and capabilities,
- the source agent’s first enabled launch config (or its first config, if none is enabled): harness, command and args, capabilities, persona, system prompt, allowed models, and device requirements,
- environment variable **keys**, and any **secret references** (an env var bound to a workspace secret keeps pointing at that same secret).

Copying takes one launch config, even if the source agent has several. A credential ref carries over only if the target workspace can use that secret. Plain (non-secret) environment variable values are left blank on the copy, so you re-enter them afterward. Copying does not mint an API key. Add one later like any agent created without one (see [Minting API keys](https://codeherder.com/docs/members-and-teams/)).

If the source config’s args hold a value that looks like a credential — an API key, a token, a JWT, a connection string with a password in it — the copy is refused outright. See [Keeping credentials out of a launch config](https://codeherder.com/docs/agents-and-cli/#keeping-credentials-out-of-a-launch-config) below for what counts and how to fix it.

After the copy completes, you land on the new agent’s detail page, where you can fill in its launch config and any environment values the copy left blank.

### Editing an agent

Update an agent’s own fields — as opposed to its launch config, covered below — with:

```
ch agent edit <agent> --display-name "Builder v2" --role leader --cap model:opus --cap go
```

`--cap` **replaces** the agent’s whole capability set — include every capability you want to keep. `--clear-caps` empties it instead; the two flags are mutually exclusive. A launch config’s own `--cap` follows the same rule: pass it, and it replaces the config’s whole capability list (see [Flag reference](https://codeherder.com/docs/agents-and-cli/#flag-reference) below).

An agent can rename itself — `--display-name` is the one field a session running as that agent may change on its own agent record. Changing its role, capabilities, or device requirements needs workspace **owner or admin**, the same as creating or copying an agent.

`--device-requirement` and `--clear-device-requirements` set which devices the agent is allowed to run on — see [Capabilities](https://codeherder.com/docs/capabilities/#agent-device-requirements--hard) for what a device requirement is and how it’s enforced. Like `--cap`, `--device-requirement` replaces the full set on each call.

Pausing an agent — stopping it from picking up new work without touching its configuration — is its own pair of commands, not part of `edit`; see [Monitoring your agents](https://codeherder.com/docs/monitoring-agents/#pausing-and-resuming-an-agent).

### Archiving an agent

```
ch agent archive <agentRef>
ch agent restore <agentRef>
```

Archiving is a reversible retire: it revokes the agent’s API keys and its claude.ai/ChatGPT connector grants in the same step, and the agent stops picking up new work. Its history — sessions, costs, messages, wiki pages — is kept, and so are its launch configs. Restoring clears the archived state, but it does **not** re-issue the revoked API keys or connector grants — mint a fresh key afterward (see [Minting API keys](https://codeherder.com/docs/members-and-teams/#minting-api-keys)).

There is no `ch agent delete`. Typing it prints `Did you mean: ch agent archive ?` and runs nothing.

**Web app:** the **Set up → Agents** page has an Archive/Restore control on each agent’s row, and the same control appears again on the agent’s own detail page.

Archiving needs workspace **owner** or **admin**. The call must come from a human’s own credential, not from inside a running session. An agent’s session credential is refused.

`ch agent archive` refuses while any session of that agent is still live. Run `ch session list agent <agentRef> --active` to see which sessions are still running, and stop those first.

**Finding an archived agent:** `ch agent list` hides archived agents by default. Pass `--archived` to see only the archived ones, or `--all` for every agent, active and archived together — its **STATE** column reads `active`, `disabled (since <when>)`, or `archived (since <when>)`. See [Listing archived records](https://codeherder.com/docs/using-the-cli/#listing-archived-records) for how this flag works across CodeHerder. `ch agent list` also takes `--enabled` / `--disabled`, narrowing on that same STATE column instead — see [Listing enabled and disabled records](https://codeherder.com/docs/using-the-cli/#listing-enabled-and-disabled-records). In the web app, the Agents page carries both as pickers — Enabled / Disabled / All, and Live / Archived / All; archived rows appear dimmed with an **Archived** badge.

## Configuring the agent

Every agent needs a **launch config** — the settings the device uses to start the coding-agent CLI for each stage — before it can run tasks. The web app’s New agent form always sets one at creation time; `ch agent create` sets one too when you pass the launch-config flags (see [Creating an agent](https://codeherder.com/docs/agents-and-cli/#creating-an-agent) above), but makes a config-free agent if you omit them. Use the commands below to inspect the current config, change it later, or add one to an agent that doesn’t have one yet. Inspect the current config with:

```
ch agent config show <agent-id>
```

Set or update the config with any combination of these flags — pass only the ones you want to change:

```
ch agent config edit <agent-id> \
  [--harness claude] \
  [--cap model:opus --cap model:sonnet] \
  [--arg <argument>] \
  [--env KEY=VALUE] \
  [--credential-ref ENV_VAR=<secretId>] \
  [--persona "A senior Go engineer focused on correctness"] \
  [--system-prompt "Always write tests first."]
```

`--harness` or `--command` is required only when the agent doesn’t have a launch config yet — an edit to an existing one can name any single flag on its own. See [What each edit actually changes](https://codeherder.com/docs/agents-and-cli/#what-each-edit-actually-changes) below for the full rule.

### Choosing a harness

The **harness** selects which coding-agent CLI CodeHerder launches on the device. Use `--harness` with one of:

| Harness | CLI launched |
| --- | --- |
| `claude` | `claude` (default) |
| `codex` | `codex` |
| `cursor` | `cursor-agent` |
| `opencode` | `opencode` |
| `pi` | `pi` |

When you set `--harness`, CodeHerder derives the launch command automatically — you do not need to provide `--command`. The selected CLI must be installed on the device that runs the agent.

The five harnesses aren’t interchangeable in every respect — see [Choosing the coding-agent CLI your agents run](https://codeherder.com/docs/harnesses/) for what actually changes (placement, cost tracking, conversation continuity on rework, and device readiness checks) when you switch.

### Flag reference

Each flag accepted by `config edit` (`config set` also works for `edit`):

| Flag | Purpose |
| --- | --- |
| `--harness` | Coding-agent CLI to launch (`claude`, `codex`, `cursor`, `opencode`, `pi`) — derives `--command`; required only when the agent has no launch config yet |
| `--command` | Advanced override: absolute path or binary name the device runs; only needed if you’re not passing `--harness` |
| `--cap` | Stage-gate capability label — the engine only runs a stage on this config if its caps fully cover what the stage requires; repeat for multiple |
| `--arg` | Extra argument passed to the command — repeat for multiple |
| `--env KEY=VALUE` | Environment variable set on each launch — repeat for multiple. A [variable](https://codeherder.com/docs/variables/) set at group, workspace, device, or agent scope also reaches the session; a config’s own `--env` value wins if the same key is set both ways. |
| `--credential-ref ENV_VAR=<secretId>` | Bind a workspace secret to an env var name — repeat for multiple; the value is resolved and injected only when a session spawns, never passed through the CLI. See [Secrets](https://codeherder.com/docs/secrets/) |
| `--persona` | Short description of this agent’s role, included in each task brief |
| `--system-prompt` | Instruction prepended to every session; inline text, or `--system-prompt-file <path>` (or `-` for stdin) to read it from a file |
| `--allowed-model` | Model this config is allowed to run — repeat for multiple; see [Which model your agents run](https://codeherder.com/docs/agent-models/) |

### What each edit actually changes

`config edit` is a **partial update**: it changes only the fields whose flag you actually pass, and leaves every other field exactly as it was stored. Run `config edit --persona "..."` on its own and only the persona changes — the command, args, environment, and capabilities all stay put.

The one thing to watch is that five of these flags are **repeatable lists** — `--arg`, `--env`, `--cap`, `--credential-ref`, and `--allowed-model`. Pass any of them on a call and it replaces that field’s whole list. For example, if a config currently has two `--arg` values and you run `config edit --arg --model --arg claude-sonnet-4-6`, the config ends up with exactly those two arguments — the old ones are gone. So whenever you touch a list flag, include every value in that list you want to keep, not just the new one.

To clear a list field entirely without touching anything else, pass the flag once with an empty value, for example `--arg ""` or `--env ""`. The field still changes — it ends up empty rather than untouched.

`--harness` on its own switches the coding-agent CLI and re-derives `--command` for it, while leaving args, environment, capabilities, persona, and system prompt untouched. `--command`, `--persona`, `--system-prompt` are plain single-value fields: pass one and it’s set; omit it and the stored value stays.

Running `config edit` with no flags at all is refused — pass at least one launch-config flag. `--harness` or `--command` is required only when the write **creates** the agent’s first launch config (a fresh agent, or `ch agent create` with any launch-config flag); editing a config that already exists needs neither.

For guidance on what to put in each field and how they affect sessions, see [Agent personas and system prompts](https://codeherder.com/docs/agent-personas/).

Adding or editing a launch config needs workspace owner or admin — see [Who can manage a launch config](https://codeherder.com/docs/agents-and-cli/#who-can-manage-a-launch-config) below for the full split.

For an API key or other credential you don’t want to hard-code in `--env`, create a workspace secret and bind it to an env var with `--credential-ref` instead — see [Secrets](https://codeherder.com/docs/secrets/) for creating a secret and adding a Credential ref. See [Keeping credentials out of a launch config](https://codeherder.com/docs/agents-and-cli/#keeping-credentials-out-of-a-launch-config) below for what happens if you try to put one in `--arg` or `--env` directly.

### Keeping credentials out of a launch config

CodeHerder refuses to save a launch config whose `--arg` or `--env` carries a value that looks like a live credential — an API key or token under a name like `*_TOKEN`, `*_KEY`, `*_API_KEY`, `*_SECRET`, `*_PASSWORD`, or `*_DSN` (including well-known ones like `GITHUB_TOKEN` or `DATABASE_URL`), a connection string with a password embedded in it (`user:password@host`), or a value shaped like a JWT. This applies to `ch agent config create`, `ch agent config edit`, inline config flags on `ch agent create`, and copying an existing agent (see [Copying an existing agent](https://codeherder.com/docs/agents-and-cli/#copying-an-existing-agent) above) — any write that would leave a literal credential sitting in a launch config is refused.

An `@secret:` reference (see [Secrets on a device](https://codeherder.com/docs/device-secrets/)) and an empty value both pass through fine — only a literal secret-shaped value is refused.

Instead, keep the credential out of the config text entirely:

- **`--credential-ref ENV_VAR=<secretId>`** binds a workspace-held secret to an environment variable — see [Secrets](https://codeherder.com/docs/secrets/).
- **`@secret:<key>`** in an `--env` value defers to a value stored only on the device itself — see [Secrets on a device](https://codeherder.com/docs/device-secrets/).
- **A secret variable** set at group, workspace, device, or agent scope reaches the session without ever being typed into the config — see [Variables](https://codeherder.com/docs/variables/).

If a config already holds a literal credential, an edit that leaves it in place is refused, even an edit to an unrelated field like the persona. Replace the offending `--arg` or `--env` value in the same call, using one of the options above, and the edit goes through.

## Running more than one launch config

An agent can carry an **ordered list of launch configs** — each with its own harness, capabilities, environment, and credentials. This lets one agent run different coding-agent CLIs for different stages, or hold a primary config and a fallback.

`config show` and `config edit` always target the **top config** (position 1, the first one in the list). To manage multiple configs, use the dedicated subcommands from the `ch` CLI:

```
ch agent config list <agent-id>              # show all configs in order
ch agent config create <agent-id> --harness codex --cap model:sonnet  # add a new config at the next position
ch agent config reorder <agent-id> <configId> <configId> ...    # reorder by listing IDs
ch agent config enable <agent-id> <configId> # make a config selectable again
ch agent config disable <agent-id> <configId> # skip a config without deleting it
ch agent config delete <agent-id> <configId> # delete a config (alias: rm)
```

You can also manage the full list of configs from the web app: the **Launch configs** panel on the agent detail page lists every config in order and lets you add, edit, reorder (drag or move up/down), enable/disable, and remove configs — the same set of operations available through the CLI above.

**How selection works:** when CodeHerder places a task stage, it picks each agent’s first **enabled** config whose capabilities cover what the stage requires. It skips a config whose harness no linked device can run. Ordering and enabling controls which config — and which harness and credentials — actually runs. To switch an agent between configurations, reorder or enable/disable; to take a config temporarily out of rotation, disable it rather than deleting it.

Reordering or disabling configs never overrides a device-wide pause from an exhausted Claude usage window or spend cap — selection doesn’t look at live usage, so switching configs on the *same* paused device won’t get work moving there again. See [AI usage limits](https://codeherder.com/docs/ai-usage-limits/).

### Who can manage a launch config

Every launch-config write needs workspace owner or admin: adding one (`config create`, or `config edit` on an agent with none yet), editing one, enabling or disabling one, reordering with `config reorder`, and removing one with `config delete`. Being the human who created the agent doesn’t grant any of this on its own. In the web app, the **Launch configs** panel shows a member without that role a read-only list, with no add, edit, reorder, enable/disable, or remove controls.

Reading is looser than writing, but not fully open: a member below owner or admin can still run `config show` and `config list`, but sees every argument and every environment variable value replaced with `[redacted]`. The count of arguments and the set of environment variable names are unchanged. One exception: an `@secret:` reference in an environment value, under a name that doesn’t look like a credential, stays visible. It names only a device-side key, not a value.

## Capabilities and routing

[Capabilities](https://codeherder.com/docs/capabilities/) owns the full picture across agents, launch configs, stages, and tasks. In short, there are two rules:

- **Agent skills (`ch agent create --cap`) are a soft preference.** They rank agents when CodeHerder places an unassigned task. They never block placement.
- **Launch config capabilities (`--cap` on `ch agent config edit`, `--config-cap` on `ch agent create`) are a hard gate.** A stage runs only on a config that covers what the stage requires. If no enabled launch config covers a stage, the stage is **unstaffable**, and tasks that reach it queue and never start.

By default, the built-in `feature`, `story`, and `bug` workflows need **both** model tiers. Their plan, review, and verify stages require `model:opus`, and their code and merge stages require `model:sonnet`. For `bug`, triage is the plan step. See [How work flows](https://codeherder.com/docs/how-work-flows/) for what each stage does. A launch config with only one tier can staff part of the pipeline, so a task can stall partway through. Give one config both tiers, or run two configs, one per tier (see [Running more than one launch config](https://codeherder.com/docs/agents-and-cli/#running-more-than-one-launch-config)).

To close a gap, add the missing capability to a config. Name every capability you want to keep, because `--cap` replaces the whole list:

```
ch agent config edit <agentId> --harness claude --cap <existing-cap> --cap <missing-cap>
```

The **Capability gap** callout on the **Set up → Agents** page lists each stage that no enabled launch config covers (see [Monitoring your agents](https://codeherder.com/docs/monitoring-agents/#capability-gap-warning)). A task can still stall when its own required capabilities, or its device placement, rule out every config. See [Why isn’t my task moving?](https://codeherder.com/docs/task-not-moving/).

## Where an agent runs

Agents run on **devices** — machines running `ch device-server`. There’s no separate step to put an agent on a device: any device linked to the agent’s workspace (or an ancestor group) is a candidate, and the engine picks the best eligible one — online, enabled, and covering the config’s required capabilities — each time it places work.

Throughout this section, `<agent-id>` also accepts the agent’s display name, and `<device-id>` also accepts the device’s name — its hostname, unless you’ve [set one](https://codeherder.com/docs/devices/#naming-a-device) — see [Referring to things on the command line](https://codeherder.com/docs/using-the-cli/#referring-to-things-on-the-command-line) for the full rule.

To check which devices an agent could actually run on right now, and why any others are excluded:

```
ch agent placement <agent-id>
```

This lists every device linked to the agent’s workspace, whether it’s eligible, and — for an ineligible one — the reason. It checks the agent’s devices, not any one task, so it leaves out checks that depend on a task, such as the git-host sign-in a task needs. It also doesn’t read live device health. See [The Placement report](https://codeherder.com/docs/placement/) for how to read it in full, including every reason and what to do about each.

Authenticating a device’s own sessions runs through the device’s own [device token](https://codeherder.com/docs/device-tokens/), minted once per device — there’s no separate per-(agent, device) credential to mint or rotate. For the first-time setup flow — registering a device end to end — see the [Quickstart](https://codeherder.com/docs/quickstart/). For ongoing device management, see [Managing your devices](https://codeherder.com/docs/devices/).

## Core CLI verbs

**Tasks**

```
ch task create --title "My task" --type story --parent <epicId>
ch task list [--status code] [--created-by me]
ch task show <taskId>
ch task status <taskId> <stage>   # move to a named pipeline stage
ch task comment <taskId> --from-file notes.md
ch task edit <taskId> --acceptance-file criteria.md  # set any field, native or per-task
ch task field <taskId> acceptance         # read one field back
ch task fields <taskId>                   # list every field and whether it's writable now
```

For the full `ch task list` filter set — status, priority, type, limit, and more — see [Finding and tracking your work](https://codeherder.com/docs/tracking-work/).

**Dependencies and blockers**

```
ch task depends-on <taskId> <upstreamId>
ch task block <taskId> "Waiting on upstream API"
ch task unblock <blockerId>
```

**Sessions and agents**

```
ch sandbox list <taskId>              # a task's sandboxes, or `workspace [<ref>]` scope instead
ch session list <taskId>              # a task's sessions, or `agent`/`device`/`workspace` scope instead
ch session show <sessionId>
ch agent create --display-name "Builder" --harness claude   # flags: see above
ch agent edit <agent-id> --display-name "Builder v2"
ch agent config show <agent-id>
ch agent config edit <agent-id> --persona "..."
ch agent config list <agent-id>
ch agent placement <agent-id>
```

The other `ch agent config` verbs (`create`, `reorder`, `enable`, `disable`, `delete`) are in [Running more than one launch config](https://codeherder.com/docs/agents-and-cli/#running-more-than-one-launch-config).

For the full `ch session` surface — `tail`, `stop`, `input`, `attach`, all four list scopes, and who can use each one — see [Sessions from the command line](https://codeherder.com/docs/session-cli/). For how to read `ch agent placement` ’s output — and its task-scoped sibling `ch task placement` — see [The Placement report](https://codeherder.com/docs/placement/).

**Workspace wiki**

```
ch wiki list
ch wiki show <slug|id>
ch wiki write --slug <slug> --title "<title>" --body-file learning.md
```

**Messages**

```
ch msg send <name-or-workspace> --from-file message.md
ch msg send session:<sessionId> --from-file message.md  # addresses one live session
ch msg inbox --unread
```

See [Messages and your inbox](https://codeherder.com/docs/messages/#sending-to-one-live-session) for the full rundown on addressing one session instead of an agent as a whole.

## The current-task default (CH_TASK_ID)

Most of the commands above take a task ID as their first argument — and copying a 36-character UUID around gets old fast. `CH_TASK_ID` is the task-level equivalent of `CH_WORKSPACE_ID` (see [Credentials and profiles](https://codeherder.com/docs/credentials/)): set it once, and task-scoped commands pick it up automatically.

Set it for the rest of your shell session:

```
export CH_TASK_ID=<taskId>
```

Or set it for a single command inline:

```
CH_TASK_ID=<taskId> ch task show
```

With `CH_TASK_ID` exported, you can drive a task’s whole lifecycle without naming it again:

```
export CH_TASK_ID=<taskId>
ch task show
ch task comment --from-file handoff.md
ch task status code
```

Task-scoped `ch task` verbs (`show`, `status`, `comment`, `field`, `watch`, `blockers`, `deps`, and most others), `ch sandbox list`, and the bare/task-ID form of `ch session list` all default their task argument from `CH_TASK_ID` when you omit it. An explicit task ID on the command line always overrides `CH_TASK_ID`.

Two commands carry a free-text body. Each defaults its task ID only when you supply that body as a flag:

- `ch task block` defaults from `CH_TASK_ID` when you pass the reason with `--reason` or `--from-file`, and pass nothing else — as in `ch task block --reason "Waiting on upstream API"`.
- `ch task comment` defaults from `CH_TASK_ID` when you pass the body with `--from-file`, and pass nothing else.

The first plain argument is always read as the task ID. So name the task ID yourself whenever you write the reason or body as a plain argument instead.

## Auto-staffing

Every built-in type is eligible for auto-staffing: initiative, epic, feature, bug, story, task, and auto. When you create an unassigned task of one of these types, CodeHerder moves it from To do to its first working stage and staffs it with a suitable idle agent. You can create a story, set its acceptance criteria, and it reaches an agent with no further action from you. See [Assigning work](https://codeherder.com/docs/assigning-work/#auto-staffing-the-default) for how the choice works.

`task` is the lightweight to-do type. Use it for yourself, or direct it to a specific person with the **Assignee** dropdown. An unassigned `task` starts on its own, like every other type.

## Monitoring your fleet

Once your agents are set up and running, you’ll want to know whether they’re healthy and picking up work. [Monitoring your agents](https://codeherder.com/docs/monitoring-agents/) covers the web Agents page (the agent list and its columns, the capability-gap warning), pausing an agent with Disable/Enable, and the CLI commands for workload snapshots (`ch agent workload`) and per-agent event feeds (`ch activity agent <agentId>`).
