Before you start
Four things have to be on the machine. Each line below prints a version if the tool is there and an error if it is not — run them rather than assuming, because the failure two steps later is much harder to read than the failure here.
python3 --versionPython 3.12.0 # 3.12 or neweruv --versiongit --versionclaude --version
If uv is missing, it is a one-line install from
astral-sh/uv. If
claude is missing, install the Claude Code CLI with
npm install -g @anthropic-ai/claude-code. no_human drives that CLI
and deliberately does not bundle it, so it has to exist on its own.
You also need a Claude credential of your own. no_human runs on
the credential you give it and bills nothing through anyone else. The default is
an OAuth token from claude setup-token — a personal subscription or
an enterprise one both work. Auth and billing covers the
alternative.
macOS today. Windows and Linux are not ready. The first signed build is macOS only.
And one repo you already work in, with its tests runnable locally. no_human works against your checkout — it does not need a special project.
Install
Three commands. The third one is a wizard and does the part that would otherwise be a page of setup instructions.
# replace the URL with the clone URL that came with your invitegit clone YOUR_CLONE_URL/no_human.git && cd no_humanuv syncuv run nh init
YOUR_CLONE_URL is a placeholder. Substitute it before you
press return — pasted literally, that first line fails with a repository-not-found
error that reads like a permissions problem and is not one. The repository is
private while the first release is prepared; the clone URL arrives with the
invite.
nh is not on your PATH after uv sync. The entry
point is installed into the project's .venv, so every command on this
page is written uv run nh …. A bare nh gives you
command not found. If you would rather type nh, activate
the virtualenv first — but uv run is what works from a clean shell.
What nh init does
It is a guided wizard, and it is safe to run again — it never overwrites an
existing config, secret or database. It checks the prerequisites above, creates
~/.no_human/ with tight permissions, walks you through
claude setup-token, writes
~/.no_human/config.yaml with your git identity, and offers to onboard
your first repo.
Two locations are worth knowing from the start, because everything else is derived from them:
~/.no_human/config.yamlEvery setting, generated with defaults on first run. Your values are deep-merged over the defaults, so anything you do not set stays at the default. Never holds a credential.~/.no_human/.envSecrets only, chmod 600, gitignored. Loaded into the process environment at startup, never read from or written to your repo, never logged.uv run nh config pathuv run nh auth status# prints the active profile and which profiles hold a token — never a token value
Teach it your repo (optional, recommended)
nh onboard reads a repo's own declarations to work out how it
installs, tests and lints — then proves each command by running it
and asks you to confirm the result. A profile only drives a task once you have
confirmed it and its test command was proven to run, so a wrong guess cannot
quietly become the thing your tasks depend on. Derivation covers the common
declarations — pytest, npm test, Maven; anything else you configure by
hand, and --agent turns on a read-only recon pass for nonstandard
repos.
uv run nh onboard ~/git/my-repo# derive, prove, propose — then, if the proposal is right:uv run nh onboard ~/git/my-repo --confirm
Your first task
Pick something small and real in a repo of yours — a bug with a clear reproduction, a missing test, a rename you have been putting off. Then start the board and the worker, and add one task.
Start the board and a worker
uv run nh startboard + worker on http://127.0.0.1:8420
One command runs the web board, a worker that picks up new tasks, and the watcher
that resumes parked ones. It ships serial — one task at a time. --workers 3
raises that; --no-open keeps it from opening a browser. Stop it later
with uv run nh stop.
Add the task
Describe it in plain English, or point at an issue you already wrote.
--repo is required — it is the checkout the work happens in.
# plain Englishuv run nh task add --title "Fix the flaky timeout in the upload retry" --repo ~/git/my-repo# or from an issue you already wroteuv run nh task add https://github.com/org/repo/issues/42 --repo ~/git/my-repo
Useful flags on the first run:
--criteria "…"An acceptance criterion. Repeatable. The single highest-value thing you can add — it is what the reviewer checks against.--description "…"The longer version of the ticket, if the title cannot carry it.--external-id PROJ-42Stamp your tracker's id onto the task. This is how a ticket number gets attached — a bare id is not a source you can pass in on its own.--approve-planStop after planning and wait for you, before a single implementation token is spent. Worth using the first time.--no-runStage the task without running it.--linked-repo PATHAn additional checkout, for a change that spans two repos. Repeatable.Be concrete. The limit is clarity, not the kind of work — features, bugs, refactors and investigations are all in scope. What comes back with a question instead of a diff is a ticket nobody could make specific. A vague task does not fail quietly; it parks and asks you something.
Watch it work
The board at 127.0.0.1:8420 is the comfortable view. From a terminal,
these four answer most questions:
uv run nh statuscounts by lane: queued / running / parked / doneuv run nh task listthe whole board as a tableuv run nh agentswhich tasks are being worked right nowuv run nh logs TASK_IDturns, tokens, result and failure reason for each attempt
nh watch is not a viewer. Despite the name, it
runs a staged task in a foreground TUI. Point it only at a task that is
staged and not already being worked, or the task runs twice. To look at something
already in flight, use nh status, nh logs, or the
board.
Every task carries an enforced spend cap, and nh logs shows real
spend against it. When the cap is reached the task stops and reports; it does not
keep going overnight.
Review the pull request
When a task finishes, it lands in awaiting approval with a pull request open on its own branch. This is the point the whole thing exists to reach. Three commands, in this order:
uv run nh review TASK_IDthe reviewer's pass/fail checklist, each finding citing file and lineuv run nh diff TASK_IDthe diff it wants to shipuv run nh approve TASK_IDrecords your approval — you merge the PR yourself
Read the checklist before the diff. It is a fresh-context reviewer's attempt to refute the claim that the work is done, so it is the fastest way to find the part worth your attention — and every finding names a file and a line, so you can check it in seconds.
If it is not right, send it back with a reason rather than fixing it yourself. The reason reaches the next attempt:
uv run nh reject TASK_ID --reason "The retry needs a backoff, not a fixed sleep"
nh approve does not merge. It records that you approved.
The merge is a thing you do, with your own hands, in your own tools — see
the merge ban for what stops the agent doing it for
you.
You can also point the reviewer at a pull request that has nothing to do with
no_human. nh review <PR or MR URL> queues a standalone review
task that fetches the diff, runs the same adversarial reviewer, and posts its
cited findings.
The pipeline
What happens between nh task add and the pull request. Every stage
runs on your machine, against your checkout, on your credential.
A failed review loops back to implement. Branching, committing and pushing are done by no_human's own git code rather than by the model, under a distinct commit identity. Implementation runs behind a pre-tool hook that enforces forbidden paths, protected branches, the merge ban and a destructive-shell circuit breaker. During review the backend is read-only.
Tickets come from a GitHub or GitLab issue URL, or a plain-English
--title. Jira is supported as an opt-in server-side poller, not as an
argument to nh task add. CI results from GitLab CI, GitHub Actions,
Jenkins or CircleCI can gate the loop; that integration is off until you turn it
on.
The gates before you see a diff
Four checks run between the code being written and the pull request reaching you. Two are deterministic and involve no model judgement at all, which is what makes them worth trusting.
A fresh session with read-only tools, on a different model from the implementer by default, told to refute "done". It returns a checklist of findings with file, line and severity, and a boolean verdict — never a score. Three things make that verdict hard to game: every cited location is checked against the real tree, and a finding pointing at a location that does not exist is demoted to advisory; the pass/fail is recomputed deterministically from the checklist rather than taken on the model's word; and a reviewer that crashes, times out, or emits nothing parseable fails closed.
Test files are diffed separately from product code. A net drop in test or
assertion count, a net increase in skip or xfail markers, a real assertion
replaced by a tautology, or a behaviour-faking autouse fixture appearing in a
conftest.py all fail the attempt. No model judgement is involved.
It covers Python, JS/TS, Java and the end-to-end tree.
The tests offered as evidence are copied into a worktree at the merge base and must fail there and pass on the new tree. A bug fix whose test also passes on the unfixed code has proved nothing.
Ruff runs over the changed Python files and the findings are attached to the review context, so the reviewer judges against machine output instead of reading the diff cold. It uses your repo's ruff config and attaches nothing if your repo has none — no_human does not impose its style on yours. It cannot block on its own.
What these gates do not cover
Stated plainly, because a gate you think you have is worse than one you know you don't:
- The pipeline ends at an open pull request. There is no deploy step.
- The reproduction gate is pytest-only. A change in another language gets the reviewer and the tamper guard, but not the fail-at-merge-base proof.
- Different models for implementer and reviewer is a default, not an invariant. You can configure both to the same model; nothing stops you, and the separation is the point.
- No size cap ships. There is no default limit on files or lines changed — you are the gate. Set one if you want the agent to stop and ask instead.
No catch-rate figure is published for the reviewer. The last full measurement was taken on a model that is no longer the shipping one, so quoting it would describe something you would not be running. The method is written down and shipped with the product; the number waits for a re-run.
When it can't finish
The loop is bounded and it is allowed to give up. Three implement-and-review attempts per loop, a turn ceiling inside each attempt, and a lifetime cap across resumes. An identical tool call repeated in a circle, or the same error signature seen twice, trips stuck detection — which resets the context rather than stacking another correction onto a confused session.
When it runs out, it does not invent a plausible diff. It classifies what stopped it and either parks with a machine-checkable wake condition or escalates to you with one specific question. Work in progress is committed first, so nothing is lost.
MISSING_ACCESSA credential or permission it does not have. Escalates immediately, naming the exact key to set.AMBIGUITYThe ticket admits more than one reading. Asks one question and waits for you.SCOPE_EXPLOSIONThe work is bigger than the ticket. Escalates with a smaller scope proposed.IMPOSSIBLEIt cannot be done as asked. Escalates with the evidence.QUOTAParks quietly; the watcher resumes it when quota refreshes.DEPENDENCY_WAITWaiting on something external. Parks with a wake condition the watcher polls.TRANSIENT_INFRAAuto-retries, then escalates if it keeps failing. Silent until then.NOVEL_UNKNOWNSomething it cannot categorise. Escalates with the full report.An escalation is never "I'm stuck". It is a six-part report you can act on in about a minute: goal · what happened, with evidence · why it is blocked · what it tried · what it needs from you · state and how to resume. If confidence in its own diagnosis is low, an otherwise-parkable blocker escalates instead — unsure what is wrong means ask, not thrash.
uv run nh blockedeverything parked, and the one question each needs answereduv run nh blocked --fullthe full six-part report for eachuv run nh reply TASK_ID "use the existing retry helper, don't add one"records the answer and resumes from the checkpoint
When the question came with options, answer by number with
uv run nh reply TASK_ID --choose 2, which applies that option's
action rather than leaving the agent to interpret prose. nh unblock
resumes a task without answering anything, and nh unblock --fail
abandons it.
On resume the task re-enters in a fresh session seeded with the prior diagnosis and your reply — not the stale, bloated context that got it stuck. A parked task also has a maximum park duration and escalates when it expires, so nothing is quietly abandoned. A task waiting on you never auto-resumes on a timer; only your reply moves it.
Configuration
Everything lives in ~/.no_human/config.yaml, generated with defaults
on first run. Your values are deep-merged over the defaults, so a file with three
lines in it is a perfectly normal file.
uv run nh config show# the whole thing, pretty-printeduv run nh config show --key git# just one section, dot-separateduv run nh config edit# open it in $EDITORuv run nh config path
The settings most installs touch
llm.auth_modesubscription — OAuth, the default. Or api_key for your own metered key.llm.primary_modelclaude-sonnet-5 — the implementer.llm.review_modelclaude-opus-5 — the fresh-context reviewer. A different model from the implementer, by default.bounds.max_attempts3 — implement-and-review cycles in one loop.bounds.max_turns_per_attempt500 — agent turns before an attempt is cut off.server.port8420 — the board's bind port.concurrency.enabledfalse — parallel workers, each in its own git worktree. Off until you turn it on.ci.enabledfalse — trigger and poll GitLab CI, GitHub Actions, Jenkins or CircleCI.Turning concurrency on does not open the floodgates: max_workers
starts at 2, and you raise it deliberately. Serial is the default and the
best-tested path; the known issues that come with running more than one worker are
written down in docs/KNOWN_ISSUES.md rather than left for you to
find.
The config file never holds a credential. In every auth mode, keys and
tokens live only in ~/.no_human/.env. Loading rejects an API key
found in config.yaml. Only the mode is a config value.
A repo can also carry its own settings in a .no_human.yml at its
root, so per-project choices travel with the project instead of living in your home
directory.
Auth and billing
One run bills exactly one path, and it records which. That is the whole design: the failure mode being engineered against is a stray environment variable silently routing your work onto a bill you did not choose.
Subscription — the default
llm.auth_mode: subscription runs on a
CLAUDE_CODE_OAUTH_TOKEN in ~/.no_human/.env, created with
claude setup-token. Personal and enterprise OAuth tokens are both
first-class. In this mode a present ANTHROPIC_API_KEY
aborts startup rather than being silently ignored — quietly
scrubbing it would hide a misconfiguration that costs real money. Bedrock and
Vertex variables are scrubbed too.
Bring your own API key — opt in
llm.auth_mode: api_key is for installs that would rather pay Anthropic
directly. Your ANTHROPIC_API_KEY goes in ~/.no_human/.env
and becomes the chosen billing path; every other metered route is scrubbed,
so the run still bills exactly one thing.
Profiles
If more than one credential could pay, name which one does. A single run never spans two profiles, and every run stamps the profile it actually billed.
uv run nh auth statusthe active profile, and which profiles hold a token — never a token valueuv run nh auth use personaluv run nh stop && uv run nh start# switching the profile requires a server restart to take effect
Your code stays on your machine. no_human runs locally, against your checkout, on the credential you configured. What leaves is what you send Claude: prompts and the context gathered for them. Nothing is billed through anyone else, and there is no server of ours in the request path.
One exception worth naming rather than burying: a once-a-day version check
fetches a version string from the public package index. Turn it off with
updates.enabled: false or NH_NO_UPDATE_CHECK=1.
The merge ban
The agent opens a pull request and stops. This is enforced in code in several independent places rather than asked for in a prompt:
gh pr merge,glab mr mergeand their REST equivalents are denied before they execute.- Pushes to
main,masterandrelease/*are refused at the git layer. - Approval is always required before a merge, and auto-merge-on-approval is off — the board's Approve button records your decision and tells you to merge it yourself.
- Git is driven by no_human's own code under a distinct commit identity, not by the model — so the agent's commits are always distinguishable from yours.
- During review the backend has read-only tools.
nh approve records your decision. The merge itself stays a human
action, taken in your own tools.
Command reference
The commands this page uses. uv run nh --help lists the full set, and
every command takes --help.
Setup
nh initSet up from scratch: prerequisites, token, config, first repo. Safe to run again — never overwrites what exists.nh onboard REPODerive a repo's install, test and lint commands from its own declarations and prove them by running each. --confirm accepts the proven profile.nh config show|edit|pathShow, edit, or locate the config file. --key for one dot-separated section.nh auth statusThe active profile and which profiles hold a token. Never prints a token.nh auth use PROFILEPin the profile future runs bill. Needs a server restart.nh doctorLiveness check: which guarded mechanisms have actually ever fired. Written because the worst bugs here were silences, not crashes.Running work
nh startBoard, worker and wake watcher in one command. --workers N, --port, --no-open.nh stopStop the running server. Graceful, then forceful if it is wedged.nh task add [SOURCE]From a GitHub or GitLab issue URL, or from --title. --repo required.nh task listThe whole board as a table.nh task show IDOne task's requirements, attempts and evidence.nh statusCounts by lane across every project.nh agentsWhich tasks are being worked right now. --all includes recently finished.nh logs IDPer-attempt turns, tokens, result and failure reason.nh investigateStart a read-only investigation — root cause, no diff.nh test [fast|full|slow]Run the test suite locally. Zero LLM tokens: it shells out to pytest.Deciding
nh review IDThat task's review checklist. Given a PR or MR URL instead, queues a standalone review of someone else's pull request.nh diff IDThe diff for the latest attempt's commit.nh approve IDRecord your approval. You merge the PR.nh reject ID --reason "…"Send it back with feedback; the next attempt gets the reason.nh blockedParked and escalated tasks, with each one's question. --full for the six-part reports.nh reply ID "answer"Answer and resume from the checkpoint. --choose N picks a numbered option and applies its action.nh unblock IDResume without answering. --fail abandons the task.The shipped docs
This page is the short path. The long version ships with the product, in
the docs/ directory of your checkout, and it is the version that stays
correct — it is pinned to the code by the test suite, so a default that changes in
code and not in the docs fails the build.
docs/quickstart.mdZero to first task.docs/configuration.mdEvery setting, every default, every .env key and when you need it.docs/verification.mdThe gates, the bounded loop, and an explicit list of what this does not do.docs/security.mdThe auth boundary, the never-merge rule, and what to check before trusting an unattended run.docs/blockers.mdThe full taxonomy, the routing table, and the wake watcher.docs/adapters.mdIntake, context, VCS and CI backends.docs/eval.mdThe golden set, replay scoring and shadow mode.docs/KNOWN_ISSUES.mdOpen defects, reproduced and written down — including what running more than one worker exposes.The repository is private while the first release is prepared, so these paths are relative to your own checkout rather than links. Access arrives with the invite.