skip to content
all docs

CLI reference

Every terminalhire subcommand, grouped by what it's for. th works as a short alias everywhere you see terminalhire. Run terminalhire --help for the live, in-terminal version of this list.

Account

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, preferences
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 (typed-yes consent)
sync --status Show whether you've consented (local read)
sync --delete Hard-delete your synced profile (revocation)

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 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)
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; also adds the repo to the shared index

Postings — see Postings and claims

Command What it does
bounties [--priced] First-party postings by default; --priced adds scraped paid open-source supply
claim preview <id|url> Read-only preview of a posting before claiming
claim record <id|url> Claim work locally; a first-party posting is also registered server-side to your verified identity
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: fetch the shared file slice, contents included — no clone, no credential (claim start runs this for you)
claim submit [id] Open the PR from your fork — or, on a first-party posting, submit the patch over HTTP (no fork). 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
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
protocol register / unregister / status Wire (or unwire) th://claim/<token> links on this machine — see Claim links

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 hosted terminal run needs --no-preview until venue ingress exists — without it, it refuses at the preview step
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

Defaults come from .th-run.json in the checkout, so a claim you run repeatedly needs no flags. Needs Docker running.

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

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 connection-only status line
mcp / mcp --print-config Run the MCP server; print host config — see MCP
config --nudge session|always|every:N Tune nudge frequency
config --connect on|off Opt in/out of ambient peer/poster surfacing
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 work when available. Otherwise they favor roughly ten contribution opportunities per role; relevant public bounties 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.