CLI reference
Every terminalhire subcommand, grouped by what it's for. th works as a
short alias everywhere you see terminalhire. terminalhire --help prints a
shorter list in the terminal; this page is the full one.
Account — profile and sync are covered in Privacy
| Command | What it does |
|---|---|
init |
One-command onboarding — start here |
login |
Sign in with GitHub (enriches your profile instantly) |
logout |
Clear the stored GitHub token |
link |
Connect this terminal to your terminalhire account |
link --logout |
Revoke this terminal's linked session |
profile --show |
Display your encrypted local profile |
profile --edit |
Set display name, contact email, remote-only, comp floor |
profile --delete |
Wipe your profile and encryption key from disk |
config --show |
Print current config |
refresh |
Fetch the latest index + re-match, update the local cache |
sync --push |
Opt-in: send your profile to staqs — consent in the browser |
sync --enable |
The same thing under another name |
sync --status |
Show whether you've consented (local read) |
sync --delete |
Hard-delete your synced profile (revocation) |
update |
Update to the latest release (--check, --force) |
feedback |
Send feedback; --full asks the longer form |
Matching — see Getting started
| Command | What it does |
|---|---|
jobs |
Fetch the index, browse roles matched to your profile |
jobs --all / --page N / --limit N |
Page through the full ranked list |
jobs --status <s> |
Filter by applied/saved/dismissed/clicked/unactioned |
jobs --remote-only |
Drop anything that is not remote |
jobs --stable |
Hold the ordering steady between runs |
jobs mark <id> <status> |
Track your funnel — see Job statuses |
save <jobId> / saved / unsave <jobId> |
Save, list, or remove a saved job |
Credential — see Proof of Work
| Command | What it does |
|---|---|
trajectory |
Trajectory from your local Claude Code corpus |
trajectory --export |
Write a derived score + Markdown locally |
trajectory --push |
Opt-in: link your trajectory to your dashboard (typed-yes) |
trajectory --inward |
Read your own corpus without sending anything |
trajectory --push --unlink (or --delete) |
Unlink a pushed trajectory from your dashboard |
contribute |
Feed of credential-building open issues (on by default; opt out with contributeEnabled: false) |
contribute <owner/repo> |
Open, unassigned issues in ONE project you name, ranked to your stack; and, when this terminal is linked, adds the repo to the shared index |
Postings — see Postings and claims
| Command | What it does |
|---|---|
work [--priced] |
Paid tasks: first-party postings by default; --priced adds scraped paid open-source supply |
bounties [--priced] |
Same as work |
claim preview <id|url> |
Read-only preview of a posting before claiming |
claim record <id|url> [--start|--no-start] |
Claim a paid task locally; a first-party posting is also registered server-side, to the GitHub account you proved in the browser |
claim start <id|url> [--watch] |
The one-verb path: records if unrecorded, then provisions — OSS forks + clones; a first-party posting delivers your workspace, --watch waiting out a pending approval |
claim attach <id> --worktree … --branch … |
Link a claim to your working branch |
claim slice <id> |
First-party postings: deliver the workspace — the whole repository at the posted commit, or a file copy if the poster chose a narrower tier (claim start runs this for you) |
claim update <id> <state> |
Move a claim along by hand — ready is the one a non-interactive submit needs first |
claim note <id> --body "…" |
Send a note to the poster and print the text that went out. Turn it on once in the dashboard settings first |
claim audit <id> [--remember] |
Your PR's lifecycle — opened, response, rounds, merged. No score, and nothing kept unless you pass --remember |
claim --push / claim --push --revoke |
Turn the poster's "active N minutes ago" signal on, or off and revoke it |
claim submit [id] |
Open the PR from your fork — or, on a first-party posting, submit the patch over HTTP (no fork) and, with --screenshots <file>, up to six PNGs you took of the change. From the claim’s worktree the id is optional |
claim runs <id> |
First-party postings: read the poster’s own CI verdict on your submitted patch (none on a poster-reviewed posting) |
claim status [<id>] |
Check poster approvals or poll source PR merge state |
claim list [--active] |
Your claims + accepted-PR rate |
claim release <id> |
Give up a claim on this machine. terminalhire is not told, so the poster hears nothing |
claim resolve <id> --reason <r> [--note …] |
Hand a claim back and tell the poster why. Some reasons take the posting off the market until they act; the rest hand it on. --help lists which is which |
claim notes [--json] |
Read what the poster wrote on your claims. Clears the 📝 statusline badge |
decline --forget |
Revoke the consent the bounties list remembered when you passed on a posting with d<number> |
protocol register / unregister / status |
Wire (or unwire) th://claim/<token> links on this machine — see Claim links |
terminalhire claim <token> with no verb records the claim that token names — that is
what a th:// link runs.
claim start takes --here to use the directory you are in, --fork / --assign /
--no-assign to choose what happens on the GitHub side, and --intent "…" / --eta "…"
to say what you are doing and by when. claim submit takes --yes, --title <t>,
--body-file <path> / --no-body, --no-closes, and, on a first-party posting,
--screenshots <file>: a JSON list of up to six PNGs with captions, shown to the poster
beside the verification run's own pictures (see
Verifying your work).
claim start and claim slice both take --dir <path>, which names where the
workspace lands, and --open <agent>, which hands that directory to claude,
codex, agy or cursor-agent once it is ready. A directory that already holds
files is never written into: the delivery goes to a numbered sibling and prints
where it went.
Both commands finish by leaving you in the workspace — your own shell, started
there, with exit bringing you back where you were. --open <agent> starts that
agent instead. --stay prints the cd and returns, which is also what you get
with no terminal attached, so scripts and --watch are unaffected.
Verification — see Verifying your work
| Command | What it does |
|---|---|
run |
Apply your working diff to a clean clone and run the project's tests in a container |
run --watch |
Re-run on every save |
run --keep <s> / --no-preview |
Hold the preview URL open (local runs), or skip the preview. A preview that cannot start never costs the run its verdict; a hosted run has no preview until venue ingress exists |
run --test-command <cmd> |
Disclosed override of the derived test command |
run --placement <kind> |
Where the run happens. local-docker (default) or hosted — a per-run cloud VM; needs launch credentials, and is what our dispatch worker runs once pointed at it |
run --claim <id> / --target <owner/repo> / --sha <sha> |
Name what is being verified, rather than letting the checkout say |
run --image <ref> |
Run against a named image instead of the one derived from the repo's runtime |
run --local |
Run against the checkout you are standing in |
run --json |
The run document on stdout, for a script rather than a person |
Defaults come from .th-run.json in the checkout, so a claim you run repeatedly needs no flags. Needs Docker running.
Read the exit code. 0 the tests were green. 1 we judged the work and it is not
green. 2 we rendered no verdict — our environment could not run it honestly, so
nothing was said about your work. See
how verification runs work.
Connect — see Connect
| Command | What it does |
|---|---|
devs / devs --as-project |
Rank opted-in builders locally |
project "<title>: <skills>" / project --show |
Declare or view a local project |
intro <login> / intro --list / intro --accept @<login> |
Request, list, or accept intros |
connect / connect --mute / connect --unmute |
Overview + toggle inbound nudges |
chat / chat <login> --read / --send |
Inbox, read, or send in a connection thread |
inbox |
Interactive inbox TUI |
th hub |
Full-screen TUI over claims, jobs, paid tasks, devs, profile and inbox |
Craft knowledge — your own notes on a repo
| Command | What it does |
|---|---|
th repo <owner/repo> |
Continuity, calibration and your notes for one project |
th repo note <owner/repo> "…" |
Add a private note about a repo — ten at most |
th repo sync <owner/repo> |
Backfill your merged-PR history from GitHub, when you ask |
Posting from the terminal — see Post a paid task
| Command | What it does |
|---|---|
setup [--repo owner/name] |
Poster setup: sign in with GitHub and approve a connector in your browser, then install the GitHub App, save a card from your dashboard, confirm your email, and optionally connect Claude Code. The card and email steps need "act on my behalf"; the email step needs an interactive terminal and is for first-time setup only. --repo names the repository when the App covers more than one. Re-run to resume |
setup --status |
Print what publishing still needs, and exit |
setup --reconnect |
Approve a new connector, for example one allowed to act for you. The old one keeps working until you remove it under Settings → Agent connections |
post draft --symptom "…" |
Start a draft. --title, --command and --repo are optional |
post show <id> / list / edit <id> / withdraw <id> |
Read and change drafts; none of this leaves your machine |
post submit <id> |
Interactive terminal only. Prints the exact body and sends it. After setup, the draft is saved to your account; without it, or if the server no longer accepts the stored connector (which is then removed), you get a browser link to confirm |
post publish <draft> --price <usd> |
Interactive terminal only. Needs setup with "act on my behalf" ticked. Shows what a claimant would receive and publishes only when you type yes. --repo defaults to this directory's origin; --title, --outcome, --scope, --acceptance are optional |
Audits — for TerminalHire reviewers
These work only for TerminalHire reviewers on the allowlist; the server refuses everyone else. They use the session from terminalhire link. Add --json to any of them for JSON on stdout.
| Command | What it does |
|---|---|
audits list |
Paid and delivered human audits, who holds each, and the report version |
audits show <id> |
The repository, the paid commit, what the poster asked, and, when you hold the order, a command that clones that commit through the poster's App installation with a one-hour read-only token. You are never added to the repository |
audits take <id> / release <id> |
Take an order so nobody else can, or give it back |
audits publish <id> --dir <folder> |
Reads review.md, writeup.md and findings.json from the folder (2 MB at most), runs a dry run and prints the counts, then publishes and prints the report URL and whether the poster was emailed. --dry-run stops after the counts. On terminalhire.com you type the repository name first. --notify emails again; --commit <sha> --commit-override records a different commit |
Exit codes: 0 done; 1 a usage or network failure, a server error, or HTTP 408 or 429 (try again); 2 the server refused, including an expired session (run terminalhire link).
Surfaces — see Claude Code surfaces
| Command | What it does |
|---|---|
spinner --show / --off / --mode append|replace |
Toggle and configure the spinner |
statusline --on / --off |
Toggle the status line — unread chats, intros, approved claims, poster notes, paid tasks, updates |
mcp / mcp --print-config |
Run the MCP server; print host config — see MCP |
th mcp-chat |
Opt-in reply server: lets a host answer a connection thread, off unless you start it |
config --nudge session|always|every:N |
Tune nudge frequency |
config --connect on|off |
Opt in/out of ambient peer/poster surfacing (default off) |
config set mix jobs|balanced|credential / config get mix |
Balance roles vs. contribution items on the surface (default balanced; env TH_MIX overrides) |
Spinner tips lead with claimable first-party paid tasks when available. Otherwise they favor roughly ten contribution opportunities per role; relevant public paid tasks follow the role.
Pointing the CLI somewhere other than terminalhire.com
Every command talks to https://terminalhire.com unless you say otherwise. If you
are working against the dev deployment, or against a copy of the web app running on
your own machine, a bare command asks production instead — and production answers
about a claim it has never heard of, which reads as "this work does not exist".
| Variable | What it does |
|---|---|
TERMINALHIRE_API_URL |
The deployment to talk to. Allowlisted: the apex, dev.terminalhire.com, loopback |
TERMINALHIRE_ALLOW_LOCAL_API |
Set to 1 before any http://localhost:<port> base is accepted |
TERMINALHIRE_ALLOW_LOCAL_OAUTH |
Set to 1 as well before login will open a browser sign-in against loopback |
TERMINALHIRE_DIR |
Where sessions and claims live. Unset: ~/.terminalhire, or ~/.terminalhire-dev when pointed at dev |
For the dev deployment, use thdev instead — it is the same CLI with that origin
pinned, so it needs no variable at all and works the same in PowerShell, cmd.exe and
bash. VAR=value command is a POSIX-shell one-command assignment: on Windows it does
not set anything, and the command silently reaches production.
# the dev deployment — every command, no variable
thdev claim slice <id>
thdev bounties
thdev login
# a web app running on your own machine, on whatever port it serves
TERMINALHIRE_ALLOW_LOCAL_API=1 TERMINALHIRE_API_URL=http://localhost:3000 \
terminalhire claim slice <id>
The dev deployment has its own credential store, ~/.terminalhire-dev, and
every way of pointing at dev uses it: thdev, the variable, an MCP server entry
that sets the variable. So thdev login and terminalhire login are separate
accounts on disk, neither overwrites the other, and a sign-in through one spelling
is visible to the others. Set TERMINALHIRE_DIR to choose a store yourself; it
wins over that default. Loopback keeps ~/.terminalhire and still uses the
variables above: there is no pinned binary for an arbitrary local port.
Any other host is refused outright rather than quietly falling back to production — writing a claim to the wrong environment is not something a later command can undo. The two loopback flags are separate because they grant different things: the first lets stored credentials reach a local listener, the second lets a browser sign-in happen there, and neither is implied by the other.
Your session belongs to one deployment. Signing in on production does not sign
you in on dev, so point login at the same place before anything that says a claim
is not registered to you:
thdev login
The claim page prints the right form into its own copy buttons — thdev … on dev, a
prefixed command on loopback — so a command copied from a page is already pointed at
the deployment that served it.
Not opening a browser
login, sync --push and the claim sign-in steps print the address, then try to open
it in your browser. Set TERMINALHIRE_NO_BROWSER=1 to skip that on a headless machine
and open the printed address yourself.