Any role can be staffed by Claude through Anthropic's API. On api.anthropic.com darkmux speaks Anthropic's native Messages API, so prompt caching covers every turn of the agent loop: each turn reads the conversation before it from the cache instead of sending it again at full price. darkmux reports tokens; the rate is between you and Anthropic.
Put the API key in the Keychain. Only the item's name goes in any file.
security add-generic-password -a "$USER" -s darkmux-anthropic -w
Declare the endpoint once under endpoints in ~/.darkmux/profiles.json, and a profile whose model names it:
{ "endpoints": {
"claude": { "url": "https://api.anthropic.com/v1",
"auth": { "type": "bearer", "keychain": "darkmux-anthropic" } } },
"profiles": {
"claude-seat": { "models": [ { "id": "claude-sonnet-5-5", "n_ctx": 200000, "endpoint": "claude" } ] } } }
Then point a role at the seat. Any role works; this one makes Claude the reviewer:
darkmux config set role_profiles.reviewer claude-seat
darkmux doctor -v lists the endpoint with the dialect it resolved. Captured on the operator's machine, trimmed to one endpoint:
✓ endpoints `claude-sonnet`: unmanaged, api.anthropic.com, messages, credential from
Keychain `darkmux-anthropic`; limits 100000000 tokens per 30d · waits at most
30m; calls run one at a time (no limits.concurrent_calls); budget wait, early
warning at 80%: spent 38492046 tokens in 1613 calls over the last 30d
messages is the part that matters. You do not declare it: an endpoint on api.anthropic.com with no dialect gets it. Declaring another dialect there sends the OpenAI-compatible layer, which neither caches nor reports caching, and doctor warns with the edit to undo it.
Two things, both automatic. The system prompt and the tool definitions carry their own cache breakpoint, so every dispatch of a role shares them. The conversation is cached as it grows, so each turn of a dispatch reads everything before it from the cache and pays full input price only for what is new. An agent loop resends its whole conversation every turn, which is why the second part is most of the effect.
Anthropic keeps an entry for five minutes after its last use, so turns and dispatches that follow each other closely keep reading it. A long pause starts a fresh entry.
A budget sits on the endpoint, beside url and auth. The numbers are yours; darkmux ships none.
"limits": { "window": { "period": "30d", "tokens": <tokens> },
"policy": "wait", "max_wait": "30m", "warn_at": 0.8 }
window counts tokens over the last period, rolling, with no calendar reset.wait pauses calls to that endpoint until the window has room, then resumes. max_wait fails a call at once, naming when there would be room, instead of holding it longer than its caller can outlive (a CI job's timeout, say). warn only warns.Every model call writes a telemetry.tokens flow record. prompt_tokens is every input token the call sent, cached_tokens the part read from the cache, and cache_write_tokens the part written to it. One dispatch, turn by turn:
jq -r --arg s review-1791622322-7977d4.adhoc.reviewer.test-gap-u-0001 \
'select(.action=="telemetry.tokens" and .session_id==$s)
| [.payload.turn_seq, .payload.prompt_tokens, .payload.cached_tokens] | @tsv' \
~/.darkmux/flows/2026-10-10.jsonl
1 11475 7112
2 27260 11471
3 30783 27258
4 29455 11471
Verbatim, captured 2026-10-10: a Claude Sonnet 5.5 reviewer unit in a PR review.
Turn 1 read the shared system prompt and tools. Turns 2 and 3 read everything before them. Turn 4 read only the head, because something earlier in its conversation changed and the cache matches an exact prefix. A dispatch's --json envelope carries cached_tokens summed over its calls, and the fleet view's token readout shows cached tokens beside the rest. Multiply by your own rates to see what that is worth to you.