The ClankerBar CLI
This is the human operator's guide to the command-line driver. You do not need it
to use ClankerBar - an agent you start by hand works the backlog perfectly well over
MCP. The CLI is for the case where you want the backlog
drained while you are not there.
The console gives your agents work to pull. Something still has to start an agent, and
a single terminal session eventually stops - it fills its context, or hits a usage limit,
or you close the laptop. clankerbar is a small local program that keeps starting fresh
ones: each iteration is a new harness session told to work the backlog, and when it ends,
the driver spawns another. On a usage limit it pauses and waits for the reset rather than
dying.
It runs on your machine, drives your coding agent, and holds your credentials -
so it is open source and auditable: github.com/lecstor/clankerbar-cli.
ClankerBar itself never runs your code; that does not change here.
Pre-1.0. Releases are
v0.xsemver tags, and a breaking change may land on a minor
bump - pin a version if you automate against it. Breaking changes are never silent: they
carry a!in the commit and are hoisted to the top of the release notes.
1. Install
Every release ships prebuilt binaries for macOS and Linux, amd64 and arm64. No Go
toolchain, no package manager. Pick your platform's archive from the
releases page, then:
# Set VERSION to the latest release, and OSARCH to your platform:
# darwin_arm64 (Apple silicon), darwin_amd64, linux_amd64, linux_arm64.
VERSION=0.1.0
OSARCH=darwin_arm64
curl -fsSLO "https://github.com/lecstor/clankerbar-cli/releases/download/v${VERSION}/clankerbar_${VERSION}_${OSARCH}.tar.gz"
curl -fsSLO "https://github.com/lecstor/clankerbar-cli/releases/download/v${VERSION}/checksums.txt"
shasum -a 256 --ignore-missing -c checksums.txt # Linux: sha256sum --ignore-missing -c
tar -xzf "clankerbar_${VERSION}_${OSARCH}.tar.gz"Do not run it yet - section 2 is the half that checks it is ours, and running an
unverified binary first makes that check decorative. The archive also contains the README
and licence.
Download with curl, not the browser. The binaries are not notarized, so a
browser-downloaded archive is quarantined by macOS and the first run is refused with
"cannot be opened because the developer cannot be verified". Clear it withxattr -d com.apple.quarantine clankerbar, or use the curl route above, which never
sets the attribute.
Or build from source, if you have Go 1.26+:
go install github.com/lecstor/clankerbar-cli/cmd/clankerbar@latestA source build reports 0.0.0-dev rather than a version number, so clankerbar version
naming a real one - clankerbar 0.1.0, no v - is how you know you are on a release
archive.
2. Check where it came from
The checksum above proves the download arrived intact. It does not prove it is ours - it
is served from the same release page as the archive, so whoever could swap one could swap
both.
Every release is signed with build provenance: a
Sigstore attestation held by GitHub, recording that these exact bytes came out of this
repo's release workflow. Verify it with the GitHub CLI (you need
to have run gh auth login):
gh attestation verify "clankerbar_${VERSION}_${OSARCH}.tar.gz" \
--repo lecstor/clankerbar-cli \
--signer-workflow lecstor/clankerbar-cli/.github/workflows/release.yml--signer-workflow is the half that matters. --repo alone accepts an attestation from
any workflow in the repo; naming the workflow pins it to the one that publishes releases.
This binary holds your API key and runs shell commands on your machine, so it is worth the
extra line.
Read the exit code, not the output. gh attestation verify writes its "Verification
succeeded" banner to the terminal, and prints nothing at all when its output is piped
or redirected. A silent command here is a pass; a failure is loud and non-zero either way.
Once it verifies, put the binary somewhere on your PATH (/usr/local/bin is fine) and
check it runs - this should print the version you downloaded:
./clankerbar version3. Give it a key and a working directory
The driver needs two things: a way to read your backlog, and a directory to start sessions
in.
A key. An account key (mint at /account/api-keys) is the normal choice - it works
across every project you are a member of, so one loop instance can drive several. Put it in
the environment as CLANKERBAR_API_KEY. A project-scoped key works too.
A working directory - where the harness runs, and where your agent's .mcp.json lives.
That file is what gives spawned sessions their ClankerBar tools, and it is where the driver
reads your project slug from. Point the CLI at your checkout, not at a clone of the CLI
repo.
Configuration lives in ~/.config/clankerbar/config.json, or any file you name with--config. A minimal one:
{
"harness": "claude",
"model": "opus",
"workdir": "~/dev/my-project",
"config_dir": "~/.claude"
}harness is claude, codex, or opencode. config_dir is the one people forget: an
unattended session started from cron or launchd has none of your skills, plugins, or login
unless you point it at the same config directory your interactive terminal uses.
A clankerbar.json sitting in the working directory is not merely ignored - it is
refused, and the command exits non-zero telling you so. Name it explicitly with--config ./clankerbar.json if it is yours, or move it to ~/.config/clankerbar/. That is
deliberate: a config file controls the prompt, the child environment, the permission policy
and where your API key is sent, and the working directory is a checkout the sessions
themselves can write. Refusing is louder than skipping, which is the point - but it does
mean a repo that happens to contain that filename will stop a cron run until you name it.
4. Preflight with doctor
Most of what ruins an unattended run shows up as degraded behaviour hours in - a rejected
key quietly drops the loop into blind mode, a missing binary kills the first session, an
unreachable plane looks exactly like an empty queue. doctor turns that into one cheap
answer before you start:
clankerbar doctor
clankerbar doctor --config ./clankerbar.json --harness codexIt prints one PASS / WARN / FAIL line per check with a one-line remedy under anything
that is not a PASS, and exits non-zero if any check FAILs - so it gates a run:
clankerbar doctor && clankerbar run --harness=claudeIt checks the config, the harness binary, the harness config dir, your backlog wiring (with
a separate check per project), the driver's own state directory, each working directory,
the permission policy, whether any MCP server starts a local process in every session, the
build toolchains your repos need, whether the machine will stay awake, and your budget
ceilings.
Three of those exist because of failure modes that cost real overnight runs whole hours. A
queue reporting nothing claimable while the work is actually sitting behind your
unanswered question - an empty queue and a queue you have blocked look identical in the
counts, and only one of them is fine. A session spawned in a multi-repo parent directory,
which loads none of the conventions from the repos beneath it. And a build tool the harness
policy never granted, so go test is refused with no prompt reaching you and the task
ships written but never compiled.
5. Run it
clankerbar run --harness=claude
clankerbar run --harness=claude --model=opus --max-iterations=10With no --max-iterations it is a daemon: when the queue is dry it idle-polls instead of
exiting, and picks work up as you file it. Flags are GNU-style long options; --config
(-c) and --help (-h) are the only short aliases.
The driver logs milestones as it goes - spawning, queue state, tokens and cost, usage-limit
pauses, retries - and the agent's own output streams through live. Each attempt is also
captured to its own log file in the driver's state directory, which lives outside your
repo: ~/.local/state/clankerbar/loop/<workdir>-<hash> by default ($XDG_STATE_HOME if you
set one), or wherever state_dir in your config points. The hash is derived, so do not try
to guess the path - run clankerbar doctor, which prints the resolved one on itsstate_dir line.
6. Stopping it
Three ways, in rough order of how far away you are:
| How | What it does |
|---|---|
| Ctrl-C | Ends the run. |
touch <state-dir>/STOP | Stops gracefully, responsive even mid-wait. doctor prints the state dir (section 5). |
| Pause, in the console | Per project, from Settings -> Loop. |
The console pause is the remote control: a paused project stops getting new sessions while
your other projects keep draining, and the loop idle-polls until you resume. It is honoured
between iterations, so it never kills a session mid-task. It rides on the driver's ordinary
backlog poll, which means it needs a key and a reachable plane - a loop draining blind
cannot see the flag, and the local STOP marker is the fallback there.
7. Not getting locked out
The loop spends the same subscription quota you do, and no coding-agent harness lets a
headless caller read how much of it is left - so clankerbar cannot stop at a tidy "80% of
the window". Two things that do work:
- Separate credentials. Run the loop under a different account or API key than your interactive agent use, so it physically cannot spend your daytime quota. This is the only option that cannot be wrong.
- A budget ceiling. Set
budget.max_cost_usd(preferred - it comes from the harness's own cost accounting),max_tokens, ormax_wall_clock, and the loop stops itself. Note thatmax_wall_clockcounts hours spent waiting out a usage limit, in which nothing is billed at all; keep it as an outer bound on how late a run may go, not as a spend limit.
On a laptop: clankerbar run holds a no-idle-sleep assertion for its own lifetime on
macOS, but nothing overrides clamshell sleep, and plugging in later does not wake a Mac that
already slept. Start the run on AC, with the lid open.
8. Further reading
The README is the full reference - every
config field, the multi-project setup, the retry and hand-back behaviour, and the reasoning
behind each. This page is the path from nothing to a running loop.