# AI credentials on a device

Source: https://codeherder.com/docs/device-ai-credentials/

Give a device more than one Claude credential, cap how much of one it may use, and see how a session picks between them.

A device usually runs on one Claude credential. But you can give it several — each with its own label — so a burst of work doesn’t all lean on a single subscription’s usage window. This page covers adding, inspecting, and managing a device’s credential pool.

This is a device-local feature: every command here talks directly to the `ch device-server` process running on the machine you run it from, not to CodeHerder’s API. Run these commands on the device itself, with its device server already running.

## Why add a second credential

Every device probes its Claude credential for usage every few minutes, and CodeHerder pauses new placements on that device once the credential runs out of headroom — see [AI usage limits](https://codeherder.com/docs/ai-usage-limits/) for the full picture. A device with only one credential shares its exhaustion with every agent running on it.

Add a second, labelled credential to the same device, and CodeHerder starts choosing between them for each new session. One credential running low no longer stops the device from taking work. It’s a lighter lift than registering a second machine when what you actually need is more Claude capacity on the one you already have.

## Adding a credential

```
ch device credential create <label> --from-file <path|->
```

`<label>` is a short name you choose — lowercase letters, digits, and hyphens, same rule as any other short identifier in CodeHerder. `--from-file` reads the credential from a file, or from standard input when you pass `-`:

```
ch device credential create night-shift --from-file ~/night-shift-token.txt
echo "$TOKEN" | ch device credential create overflow --from-file -
```

The command validates the credential, adds it as a new, enabled entry, and prints its fingerprint — never the credential itself. It’s for a Claude Code OAuth subscription token by default; pass `--harness codex` to add a Codex credential to Codex’s own pool instead, giving the whole contents of that harness’s `auth.json` file.

The label `default` is reserved: `ch device claude-token set` writes that entry, so `create` and `delete` both refuse it. You can’t reuse a label already in the pool either. A harness’s pool holds at most 16 entries; past that, `create` refuses until you `delete` one.

(`add` and `remove` still work as older names for `create` and `delete`, for scripts or habits built around them.)

## Capping how much of a credential a device may use

Adding a credential to the pool doesn’t have to mean handing over the whole thing. If you’re contributing an account you also use elsewhere, cap it so the device can only draw down a slice of its usage — a per-window ceiling below the credential’s own real limit.

Set a cap when you add the credential:

```
ch device credential create night-shift --from-file ~/night-shift-token.txt --max-5h 50 --max-7d 25
```

`--max-5h` and `--max-7d` each take a percentage of that credential’s own limit for that window — greater than 0, up to 100. Leave one out and that window stays uncapped: the example above caps the 5-hour window at 50% and the 7-day window at 25%, and leaves everything else uncapped. Only the 5-hour and 7-day windows take a cap; the per-minute throughput meters don’t.

Change or clear a cap on a credential you’ve already added with `set-limit`:

```
ch device credential set-limit night-shift --max-5h 80
ch device credential set-limit night-shift --clear
```

Here, an omitted `--max-5h` / `--max-7d` leaves that window’s existing cap as it is, rather than uncapping it — so setting just `--max-5h` above changes nothing about the 7-day cap. `--clear` removes every cap on the credential, back to fully uncapped; you can’t combine `--clear` with either `--max` flag in the same call.

The `default` entry can take a cap too — `create` and `delete` are the only commands that refuse that label. `ch device claude-token set` has no cap flags of its own, so cap `default` after the fact with `set-limit`:

```
ch device credential set-limit default --max-5h 50
```

## Listing what’s added

```
ch device credential list
```

Prints a row per entry: label, fingerprint, STATE, its 5-hour and 7-day usage, and when it was last used. If the device has a `default` entry, it appears here too, alongside every other label. The list never prints the credential material itself, and the CLI has no command to read one back. The pool is plain files on the device. In process mode and `--docker` mode, an agent running as the same user can read them. See [Isolating agents on a device](https://codeherder.com/docs/agent-isolation/).

STATE is one of five values:

- **enabled** — healthy and available for a new session to pick.
- **capped** — at or over its own cap, but still under its real limit. Raise the cap (or wait for the window to reset) to make it available again.
- **exhausted** — at its real, uncapped limit. Wait for the window to reset.
- **disabled** — you turned it off with `ch device credential disable`.
- **auth_rejected** — Claude itself refused the credential, not just a usage limit. No session picks it, and supplying the same token again doesn’t clear it — see **Recovering a rejected credential**, below.

The 5H and 7D columns read as `<usage>/<cap>` — for example `45%/50%` means the credential has used 45% of that window and its cap sits at 50%. A dash in place of the usage means the window hasn’t been probed yet. When the window is also uncapped, the whole column is just a dash; when it’s capped but unprobed, the column reads `—/50%`. LAST USED reads `never` for a credential no session has picked yet.

## Taking a credential out of rotation, and putting it back

```
ch device credential disable <label>
ch device credential enable <label>
```

Disabling a credential stops new sessions from picking it, without deleting it — useful if you know a credential is about to run low, or you’re rotating it out. This works on the `default` entry too, the same as any other label. CodeHerder refuses to disable the last enabled credential for a harness, since that would leave nothing to select from, and `default` counts toward that total like any other entry.

## Removing a credential

```
ch device credential delete <label>
```

Deletes the entry outright. `default` is the one label `delete` refuses, the same as `create`. If you’re just pausing a credential rather than retiring it, `disable` is usually the better choice — it’s reversible without adding the credential back from scratch.

## Recovering a rejected credential

A credential moves to **auth_rejected** when Claude turns down the token itself, not when it just runs out of usage. That means waiting for a window to reset won’t help, unlike **exhausted** or **capped** — the credential isn’t short on usage, it’s no longer accepted. Supplying the exact same token again doesn’t clear it either. The rejection stays until you provide different, working credential material.

For a labelled entry, delete it and add it back with a fresh token:

```
ch device credential delete night-shift
ch device credential create night-shift --from-file ~/night-shift-token.txt
```

For the `default` entry, run `ch device claude-token set` with a new token in its place, since `create` and `delete` both refuse the `default` label.

## How a session picks a credential

A Claude subscription’s 5-hour and 7-day allowance doesn’t carry over once its window resets, so an unused allowance about to reset is worth using before it disappears. When more than one enabled credential has a current usage reading, CodeHerder picks the one whose 7-day window resets soonest, and keeps sending new sessions there until it’s running low on room. Only then does the next credential take over. A credential that’s disabled, at its real limit, at its own cap, or rejected by Claude is never picked.

This holds until a credential has no current usage reading — either it hasn’t been probed recently, or it can’t report a 5-hour/7-day window at all. Every Codex credential falls in this group, since Codex reports usage on a different pair of windows. Among credentials without a reading, CodeHerder spreads sessions that start close together across different entries instead of picking one repeatedly, so a burst of new work doesn’t all land on the same untested credential.

If every enabled credential in the pool is at its own cap, none of them wins selection — raise a cap with `set-limit`, add another credential, or wait for a window to reset.

Placement takes the same signal into account when it’s choosing which device should run a task in the first place: given a choice between two eligible devices, it leans toward the one with more Claude headroom.

## `ch device claude-token set` and the pool

A device also has a single-credential command: `ch device claude-token set`. It writes the pool’s `default` entry — a shorter path to one credential, for when you don’t need a label of your own.

The `default` entry is an ordinary pool member once it’s written. A new session picks it on the same terms as any other enabled entry. Setting it doesn’t pause the rest of the pool, and it doesn’t take priority over the credentials you add yourself.

If the device already held a Claude credential before you added any to the pool, CodeHerder carries it into the `default` entry for you. This happens automatically, the next time you start or restart its device server.

## When a running session’s credential runs out

If the credential a live session is using becomes exhausted, capped, disabled, or removed from the pool while the session is working, CodeHerder moves that session onto the pool’s best healthy entry and it carries on the same conversation. Sending the session a message prompts a retry right away if the move hasn’t already happened. If nothing in the pool has room, the session stays put until a credential frees up — see [AI usage limits](https://codeherder.com/docs/ai-usage-limits/) for what that wait looks like.

## Where a label shows up

Once a device has more than one Claude credential, its detail page shows one **AI limits** card per credential, each labelled with the name you gave it when you added it. A capped credential’s card carries a **Capped** badge, and each capped window’s meter shows the cap alongside its usage. See [Managing your devices](https://codeherder.com/docs/devices/) for where that section is and what each card shows.

## Related guides

- [Managing your devices](https://codeherder.com/docs/devices/) — where AI limits cards appear and what they show
- [AI usage limits](https://codeherder.com/docs/ai-usage-limits/) — what the meters mean and what pauses a device
- [Choosing the coding-agent CLI your agents run](https://codeherder.com/docs/harnesses/) — Claude, Codex, and the other harnesses a device can run
- [Running the device server as a service](https://codeherder.com/docs/running-the-device-server/) — keep the device server running so these commands have something to talk to
