CodeHerderSearch⌘KRequest access →

← All docs

Managing your devices

How to keep devices Online, give one a friendlier name than its hostname, inspect load, adjust concurrency, monitor AI subscription usage limits, pause (drain) a device, retire a device, force a stuck device to release worktree slots, and troubleshoot a device that isn't picking up work.

A device is a machine running ch device-server for CodeHerder. The device runs the actual agent processes — checking out branches, executing the configured AI binary, and reporting the results. Every session happens on a device.

This page covers day-to-day device management. For the first-time steps — connecting a device, minting a token, and assigning an agent — see How do I add a device? for the focused version, Launch a device on AWS if you’d rather not run one yourself, or the Quickstart for the full path from a fresh account.

Online and Offline

A device shows Online when its ch device-server process is running and connected to CodeHerder. Stop or kill that process and the device goes Offline. The engine places no new work on an Offline device; tasks that were waiting for a slot on that device queue until the device comes back Online.

The current state of each device is visible under Set up → Devices in the sidebar.

Naming a device

By default, a device is identified by its hostname — whatever its operating system reports. That works fine for a laptop or a named server, but it’s not much help on a --docker fleet device (see Docker container (host-isolated)), where the hostname is just a generated container ID.

Give a device a name of your own choosing at any time — it’s safe to do even while the device is busy. Renaming only changes the label: the device keeps its ID, its connection, its workspace links and agent assignments, and anything already running on it keeps running without interruption.

ch device rename <deviceId> "prod-runner-1"

The name replaces the hostname as the label a device is shown under — the devices list, a device’s detail page, session and sandbox listings, and anywhere else ch or the web app prints a device. It replaces the hostname as a CLI reference too: once a device has a name, use that name (not its hostname) with ch device show, ch agent assign, and anywhere else you’d point at it by name. See Referring to things on the command line — and keep names distinct, since two devices sharing a name makes that reference ambiguous the same way any other duplicate name does.

The Devices page’s search box is the one place both still work: it matches on either the name or the hostname, so a device stays findable by its old hostname even after you’ve named it.

A name is trimmed of surrounding whitespace and capped at 128 characters. Clear it to go back to displaying the hostname:

ch device rename <deviceId> --clear

Web app: open the device’s detail page (Set up → Devices → [the device]) and edit the Name field directly. The Hostname field below it always shows the raw reported hostname, named or not.

Only the device’s owner or a workspace admin can rename a device — the same rule that applies to draining or deleting one.

Device health and readiness checks

In addition to the Online/Offline connection state, CodeHerder continuously checks whether a device is actually ready to run work. These readiness checks run on the device every few minutes and report back to the platform.

Health states

Each device has one of three health states, shown as a badge in the Health column in Set up → Devices:

State Badge colour What it means
healthy green All checks are passing — the device is ready for new sessions.
degraded amber At least one check is in a warning state, or has failed in a way that doesn’t block work. Nothing here prevents the device from running tasks.
unhealthy red At least one check has failed in a way that blocks new work. The engine will not assign new sessions to this device until it recovers.

When a device is unhealthy, a grey not staffable chip appears next to the health badge. This means the engine is actively withholding new tasks from the device — the chip is tied to the unhealthy state and disappears as soon as the failing check is resolved.

Viewing the health snapshot

Click anywhere on a device row in Set up → Devices to expand it. The Health snapshot panel appears below the row showing:

  • The current health state and when the snapshot was last taken.
  • Any failing or warning checks, each with a short summary, detail text, and a remediation tip.
  • A collapsible list of all passing checks.

If no health snapshot is available yet (the device has just been registered and has not reported its first check), the panel shows a message to that effect — the device is not unhealthy, it just has not reported yet.

Readiness checks

The device server runs the following checks and reports the results to the platform. The Check column uses the exact label shown in the Health snapshot panel.

Check What it verifies Blocks new work?
Device registration The device’s device token is present, valid, and accepted by CodeHerder. Yes
Session root The session-root directory is configured, exists, and is writable. Yes
Git credentials Git can authenticate to each repository the workspace uses (one row per repo). Yes
Gh auth The GitHub CLI (gh) is installed and signed in. No — warns if missing or not signed in, but does not block work.
Harness ready At least one of Claude, Codex, Cursor, or OpenCode is installed — see Choosing the coding-agent CLI your agents run for the full list of harnesses and how this check differs from Pi. Yes
Harness auth At least one installed harness is actually signed in, not just present. Warns instead when a signed-in credential is close to expiring. Yes, unless at least one installed harness is signed in
Disk headroom Free space on the session-root filesystem. Warns when free space is low; fails when critically low. Only when critically low
Session capacity How many session-worktree slots — and, if a disk budget is configured, how much session disk — are in use against the device’s limits. Yes, once a limit is reached
Worktree slots Whether the slots counted as in use are still tied to a running session, or left over from one that has already ended. Only if left-over slots persist for a long time despite automatic clean-up — see Reclaiming stuck worktree slots below.
Docker ready Devices that run each stage in its own container (how to enable) only: the Docker daemon is reachable and the task image is available locally. Yes
Tunnel connected The device’s live connection to CodeHerder is up. Yes
Clock skew The device’s clock stays close to CodeHerder’s. No — warns, but does not block work.
Spawn probe A brief test process launches cleanly through the same machinery real sessions use. Yes, on failure
Version current The running ch version matches the latest published release. No — warns if an update is available, but does not block work.

A few of these only appear once a condition is met — their absence isn’t a problem, it just means the condition hasn’t happened yet:

  • Docker ready shows up only on devices that run each stage in its own container; a device that runs sessions as host processes has no Docker row at all.
  • Clock skew and Spawn probe appear only after the device has connected to CodeHerder and completed its first check of that kind — before that, the row is simply not present yet.
  • Harness auth appears only once at least one harness is installed; if none is, Harness ready is already failing and covers the problem.
  • Harness ready and Harness auth don’t check for Pi. A device with only Pi installed fails both checks and is marked not staffable — keep at least one of Claude, Codex, Cursor, or OpenCode installed alongside it.

Checks run automatically on the device; you do not need to trigger them manually. Most checks re-run roughly every five minutes (or immediately on restart), so a fixed issue is usually reflected in the platform within a few minutes. Spawn probe is the exception — it’s a heavier canary that runs about once an hour, so give it a bit longer to pick up a fix.

Starting the device server

The device server is the long-running supervisor that accepts agent work and keeps CodeHerder informed of the device’s health:

ch device-server

Run this command once per device in a dedicated terminal, or configure it as a persistent background service that starts at login and survives reboots — see Running the device server as a service for step-by-step instructions for Linux (systemd) and macOS (launchd). To run the device server inside Docker instead — keeping it isolated from the rest of the machine — see Docker container (host-isolated) in the same guide. By default it also reports device metrics — CPU, RAM, and disk load — automatically every 30 seconds. Pass --no-metrics if you prefer to opt out of metrics reporting entirely.

Leave the server running for as long as you want the device to be available for agent work.

The device server also checks for updated versions of ch automatically — roughly once an hour — and restarts itself with the new binary when a newer release is found. By default, running agent sessions are not interrupted during an auto-update. See Updating the CLI for how to tune the cadence, disable auto-update, change that session behavior, or troubleshoot a device that’s stuck on an old version.

Inspecting your devices

List all devices

ch device list

This shows all devices in your workspace with their current Online/Offline state, name and hostname, CPU and RAM readings, and the team they belong to.

Show one device in full

ch device show <deviceId>

Prints every field for a single device — name and hostname, workspace and team, drain state, CPU/RAM readings, and the last time metrics were reported.

Check recent load

ch device metrics
ch device metrics <deviceId> --minutes 60

Shows a min/avg/max/now breakdown of CPU, RAM, and disk load over a recent window (default: 30 minutes). With no target it reports your own device. Useful when the device is Online but tasks seem slow or are queuing unexpectedly.

Concurrency and capacity

CodeHerder runs more than one task on a device at the same time, up to a configurable limit. The effective number of concurrent sessions on a device is the smaller of two values:

  • The per-device limit you set on the device’s detail page: Set up → Devices → [the device] → Capacity → Max concurrent sessions (default 8). Raising this allows more parallel work on that machine; lowering it frees resources for other processes.
  • A platform-wide ceiling (default 4) controlled by whoever operates your CodeHerder server. On the hosted cloud this ceiling is 4. Because the running cap is the smaller of the two, raising the per-device value above the platform ceiling has no practical effect until the operator also raises the ceiling.

On a stock server, a device therefore runs at most 4 sessions at once regardless of its per-device value — which is what the Capacity panel’s own note tells you.

When a device reaches its effective limit, additional tasks queue automatically and start as soon as a running agent finishes. No manual intervention is required.

If you run a self-managed device server, it also enforces a local cap on how many session worktrees it holds on disk and where they are stored — see Running the device server as a service for the flags that control this.

Reclaiming stuck worktree slots

Each running session on a device occupies one of its session-worktree slots. A slot normally frees within moments of its session ending, and the next queued task claims it right away — most of the time there is nothing to do here.

Occasionally a slot does not free automatically — for example, if the device restarted while a session was still running. When enough of these build up, the device can look fully busy even though nothing is actually running on it, and tasks that should start just sit queued.

To tell which situation you are in, expand the device’s row in Set up → Devices and check the Worktree slots check in the Health snapshot panel (see Device health and readiness checks above). Its summary reports how many slots are orphaned or reclaimable:

  • None reported — the device is genuinely busy. Tasks queue and start as soon as a running session finishes; no action needed.
  • Some reported — those slots belong to sessions that have already ended. Force an immediate clean-up instead of waiting for the next automatic pass:
ch device reclaim <deviceId>

This is fire-and-forget: the command only confirms CodeHerder accepted the request, and the device clears the affected slots in the background. Check the Worktree slots check again a few minutes later to confirm the counts dropped.

A few things to know before you run it:

  • The device must be Online and connected — see Online and Offline above. Reclaim has nothing to act on when the device is Offline.
  • If the command reports that the device does not support on-demand reclaim, the device is running an older version — update ch there; see Updating the CLI.
  • Only the device’s owner or a workspace admin can trigger a reclaim; other members are refused.
  • It is a CLI-only action — there is no equivalent button in the web app.

AI limits

When a device runs agents on a subscription-based AI plan (such as a Claude Max or Pro plan), the device server probes the AI provider for current usage every few minutes and reports the data to CodeHerder. The AI limits section appears on the device detail page when usage data has been received.

Viewing AI limits

Open Set up → Devices, click on the device row to open its detail page, and look for the AI limits section. For each AI provider, the section shows:

  • The provider name with a plan badge (for example, claude with a max badge).
  • A usage meter for each rate-limit window — the percentage consumed and, when available, how long until the window resets.
  • An Extra usage line, when the plan has pay-as-you-go overflow enabled, showing how much of that extra allowance has been used.

Meter values refresh as the device server probes the provider, approximately every five minutes by default.

The section only appears when the device has reported usage data. If you do not see it, the device server may not have signed-in credentials for any AI provider on that machine.

How subscription limits affect task placement

When a Claude subscription usage window reaches 100% utilization before it has had a chance to reset, CodeHerder stops routing new tasks to that device — for every agent on it — until the window resets. The device stays Online and healthy; sessions already running are not interrupted. Placement resumes automatically once the window resets and the next probe reports headroom.

If tasks aimed at a device stop starting and nothing else seems wrong, check the AI limits section: a usage window showing 100% with a future reset time is the signal. For the full picture — why the pause is device-wide, why switching launch configs doesn’t help, and how to keep work moving on a second device before the reset — see AI usage limits.

Disabling or tuning the probe

The usage probe runs automatically alongside the device server. To disable it entirely, set the environment variable CH_AI_LIMITS_PROBE=0 before starting the device server. To change how often it checks, set CH_AI_LIMITS_PROBE_INTERVAL to a Go duration (for example, CH_AI_LIMITS_PROBE_INTERVAL=10m for every ten minutes). See Running the device server as a service for how to apply environment variables to a service-managed device server.

Running more than one device

A workspace can have several devices registered at once. When the engine places a new task, it picks any Online device that:

  1. is assigned to an agent that has a free slot, and
  2. has the tooling the work requires (such as the git-host CLI for code and merge stages).

Adding more devices (or raising per-device limits on existing ones) increases the number of tasks that can run in parallel. The engine spreads work across all eligible devices automatically — you do not need to route tasks to specific machines manually.

Sharing a device across workspaces

A device is owned by the person whose ch device-server first registered it and can be linked to several workspaces at once — useful when you own more than one workspace and want them all to share the same hardware instead of running a separate device server per workspace.

A device serves a workspace when it is linked to that workspace. If CH_WORKSPACE_ID (or --workspace) is set when ch device-server self-registers on first run, that workspace becomes the device’s first — and primary — link; self-registering with no workspace set leaves the device unlinked until you link it explicitly. Either way, you add further links yourself with the command below. A device you launched on AWS always starts unlinked, so it won’t appear in ch device list until you attach it — use Attach existing on the Devices page, or ch device link-workspace below.

Use the ch CLI. This command needs the device’s full UUID from ch device list — the device isn’t in the target workspace yet, so there’s no name there to match. Refer to the workspace by its name, slug, slug path, or UUID (from ch workspace list):

ch device link-workspace <deviceId> --workspace <workspace>

For example, to let a device also serve the FreeTier workspace:

ch device link-workspace 019e58e6-3f9a-7b12-a845-2c3d4e5f6789 --workspace FreeTier

Once linked, the engine treats the device as a candidate for that workspace’s tasks exactly as it does for any other linked workspace — placement, staffing, and the tunnel all honour the link. The device then appears in ch device list --workspace <workspace> for the newly-linked workspace, and the device’s detail page in the app lists every workspace it is linked to.

You do not need to restart or reconfigure ch device-server — linking takes effect immediately on the server side.

ch device unlink-workspace <device> --workspace <workspace>

You cannot unlink a device’s last remaining workspace — it must always stay linked to at least one. Any other workspace link can be removed at any time.

What else a shared workspace needs

Linking the device is only the hardware half. For the engine to actually run a workspace’s tasks on a shared device, that workspace also needs:

  • An agent with capabilities matching the work (agents are created per workspace — see the agents guide).
  • The repository registered in that workspace, and the device set up with git credentials and the host CLI — see What the device needs in Connecting repositories.

When all three are in place — a linked device, a capable agent, and a reachable repo — tasks filed in the shared workspace start running on the device automatically.

Pausing a device

Sometimes you want to stop new work landing on a device without touching anything already running on it — before a reboot, a maintenance window, or while you look into an issue. Draining a device does exactly that: new placements stop immediately, while any sessions already running there keep going until they finish. The device’s Online state and health badge do not change; only new placement pauses.

Web app: In Set up → Devices, click Disable on the device’s row. A disabled chip appears on the row once it takes effect. Click Enable on the same row to resume placement.

CLI:

ch device drain <deviceId>
ch device undrain <deviceId>

Draining prints a confirmation and, since the whole point is to leave running work alone, also lists anything still in flight there:

drained device my-device — no new sessions will be placed here
no live sessions on this device

ch device drain <deviceId> --off does the same thing as ch device undrain <deviceId>.

To check whether a device is currently paused, look at the DRAINED column in ch device list, or run ch device show <deviceId> — a paused device prints drained: yes (since <when>).

Pausing is fully reversible: undrain (or click Enable) whenever you’re ready, and the device resumes taking new work. Contrast this with Delete device below, which permanently removes the device and cannot be undone.

Retiring a device

When you stop using a device in a workspace — or want to decommission the machine entirely — CodeHerder gives you two distinct removal paths. Choose based on how completely you want to remove it.

Remove from workspace

Removes the device from one workspace while leaving its links to any other workspaces intact. The device is not deleted, and the removal is reversible — you can re-add the device to the workspace at any time with ch device link-workspace.

Web app: In Set up → Devices, click Remove from workspace on the device’s row. On the device’s detail page you can also click the × next to any workspace chip in the Workspaces row.

CLI:

ch device unlink-workspace <device> --workspace <workspace>

If the workspace you are removing is the device’s last remaining link, the operation is blocked — a device must always stay linked to at least one workspace. To fully retire the device, use Delete device instead.

Delete device

Permanently removes the device from every workspace at once. When you delete a device, its device tokens, agent assignments, run history, and metrics are all removed with it. This action cannot be undone.

Delete device is available from the device’s detail page only — there is no CLI command for this operation. Open Set up → Devices, click on the device to open its detail page, then click Delete device at the top of the page.

Two things to check before you delete:

  • Stop any live sessions first. CodeHerder blocks the deletion while sessions are running on the device. Stop the running sessions, then retry.
  • You must be the device’s owner or a workspace admin. Members without one of those roles cannot delete a device.

Once you confirm, the device is removed immediately from all workspaces.

Troubleshooting

The device shows Offline. Start or restart ch device-server on that machine. The device switches to Online as soon as the server connects.

The device is Online but no agent is picking up work. Check the following:

  1. Is an agent assigned and approved? An agent must be both assigned to the device (ch agent assign <agentId> <deviceId>) and approved (ch agent approve <agentId> <deviceId>) before the device can run it. Approving is enough on its own — the device picks up the assignment immediately and doesn’t need a restart. See Quickstart and Agents and the CLI for the full setup steps.
  2. Is the device at its capacity limit? Open the device’s detail page (Set up → Devices → [the device]) and check the Capacity panel for its per-device Max concurrent sessions limit — see Concurrency and capacity above for how that combines with the platform-wide ceiling. If the device is full, tasks queue until a slot opens — that is normal, and no action is needed while sessions are genuinely running there. If it stays full with nothing actually running, some slots may be stuck rather than in use — see Reclaiming stuck worktree slots below.
  3. Does the device have the tooling the work requires? Some workflow stages need specific host tools — for example, the code and merge stages need the git-host CLI (gh for GitHub, glab for GitLab) to open and land pull requests. If the device is missing a required tool, the engine cannot run that stage there. Install the missing tool on the device; the device picks it up on its next connection. For a full explanation of stage capability gaps and how to fix them, see Agents and the CLI and Why isn’t my task moving?.
  4. Is the device paused (drained)? A paused device stays Online and healthy, but the engine skips it for new placements. Check the DRAINED column in ch device list, then resume placement with ch device undrain <deviceId> or the Enable button in Set up → Devices. See Pausing a device above.
CodeHerder

Round up your herd.

Bring every human and every agent onto one table. Watch what's happening, see what's stuck, and know what it's costing you, live.

Try "pricing", "connect a device", or "who reviews the code"

↑↓ move · ↵ open · esc close