pitwall CLI
draftpitwall reads what you can see in Pitwall and does what your API token is allowed to, through the server’s HTTP API. It is written for a terminal agent as much as for a person: every answer is JSON. Working with a terminal agent shows it in use; this page lists what it does.
Install
Section titled “Install”The server serves the binary and an install script, for linux/amd64 and darwin/arm64:
curl -fsSL <core>/api/cli/install.sh | sh -s -- <core>It installs ~/.local/bin/pitwall, or into PITWALL_INSTALL_DIR when set, after checking the download against the server’s checksum. Run it again to update. When the server runs another build than the command, every command still runs and prints one warning with that same line.
Environment
Section titled “Environment”| Variable | Holds |
|---|---|
PITWALL_URL |
The server’s address, such as https://pitwall.example.com. --url overrides it |
PITWALL_API_TOKEN |
A token created in Your settings → API tokens. Shown once; the server keeps only a hash |
Nothing else is read: there is no pitwall login and no file that holds the token. Keep it in a secrets manager and put it in the environment of the one command that needs it.
Two flags go before any command: --url URL, and --pretty, which indents the JSON.
What a token may do
Section titled “What a token may do”A token acts as the member who created it, with their role in each project: it sees what they see.
| Access | Allows |
|---|---|
| Read (always) | Every read below |
| Write (for a while) | The actions below. Allowed from Your settings → API tokens for 1 hour, 4 hours or until the end of the day; it ends on its own, or sooner when revoked |
Whatever its access, a token never:
- creates, revokes or allows writes for a token, its own included;
- merges a pull request;
- answers or sends manual tests.
A person does those in the browser. An action taken with a token shows in the activity as via token with the token’s name.
| Command | Prints |
|---|---|
whoami |
The member the token acts as, and its access now: read_only or read_write, with writes_until |
status |
The server’s version, commit and database, and the jobs running and paused now |
version |
This command’s own version and commit |
projects |
The projects you see |
tickets KEY [--status S] [--limit N] [--cursor C] |
A project’s tickets, one page |
ticket ID |
One ticket, by its id such as TLY-14 |
ticket ID --trace [--steps a,b] |
The ticket’s run in one document: every attempt with its gate verdict, jobs, model and skills, decisions and gaps, questions, documents, the AC map and the plan |
job KEY ID |
A job, its runner and the skills it loaded |
job KEY ID --events [--raw] |
Every event of the job, one per line, cut to what is worth scanning; --raw prints them whole |
document KEY PATH [--ref R] [--repository R] |
A document of a project’s repository |
milestones KEY · milestone KEY N |
A project’s milestones, or one with its phases and run |
inbox |
What waits for you |
runners |
The runners you see, their state and readiness |
activity [--project KEY] [--limit N] [--cursor C] |
The activity feed, one page |
Actions
Section titled “Actions”Each is one call to the route the web calls, and prints what it answers: the ticket filed, or the run as it stands after. Each takes --dry-run, which prints the request it would send, without the token, and sends nothing.
| Command | Does |
|---|---|
ticket create KEY --title T [--type bug|feature] [--description-file F] |
Files a ticket, a feature unless --type says otherwise |
run start ID |
Starts the ticket’s run |
run continue ID [--mode next|until|all] [--phase P] |
Continues a milestone run that waits: the next phase, until phase P, or all of them. next by default |
run resume ID |
Resumes a blocked run, giving the blocked step its attempts back |
run answer ID --question Q (--choice N | --text T) |
Answers the question the run waits on. Q is the question’s id; N a suggestion’s index from zero, as ticket ID --trace lists them |
run cancel ID |
Cancels the run |
milestone run KEY FOLDER [--mode next|until|all|close] [--phase P] |
Starts the run of the milestone in specs/FOLDER, filing its ticket the first time. FOLDER is the name alone, such as milestone-04-recurring; close takes one with every phase done to its pull request |
project hold KEY [--note TEXT] |
Marks the project as worked by hand: none of its runs starts or continues until it is released |
project release KEY |
Releases it: Pitwall reads its repositories again, then the runs queued meanwhile start |
project create --key K --name N --repository OWNER/NAME --runner R (--tech-spec FILE [--files A,B] | --existing) [--visibility private|public] |
Creates a project from a tech spec, as New project does (Creating a project): with the spec file and the files it came from, or --existing for a spec already in the repository. R is one of your runners, by name. Prints the project and KEY-1, whose run creates it |
There is no command to merge or to answer manual tests.
watch KEY follows a project’s live runs, watch ID one ticket’s run. It polls the server every --interval (10 seconds by default, at least 5) and prints one JSON line per change, never the same state twice, so a terminal agent reading it is told only when something happened:
{ "time": "2026-10-22T12:04:10Z", "kind": "gate_failed", "ticket": "TLY-14", "step": "implement", "attempt": 1, "summary": "implement attempt 1 failed 1 of its gate's checks"}| Kind | When |
|---|---|
watching |
First, once: what is followed and the state it is in |
step_started |
A step’s attempt began |
step_finished |
An attempt ended, with its outcome and its gate’s verdict |
gate_failed |
The attempt’s gate failed, with how many of its checks |
sent_back |
The step sent the run back to an earlier step, with why and its note |
question |
The run waits for an answer: the question and its id |
blocked |
The run stopped and waits for a person, with the reason |
paused · resumed |
The step’s job paused on a usage limit, until when, and went on again |
awaiting |
The run waits for a person: manual tests, a review or the merge, or a milestone run to be continued |
run_done · run_cancelled |
The run ended |
unreachable · reachable |
The server stopped answering, and answers again: one line each, however long it was away |
| Flag | Does |
|---|---|
--until-done |
Exits 0 once the ticket’s run ends, or the project has no live run left. Without it, watch runs until it is stopped |
--only problems |
Prints only what waits for someone: gate_failed, question, blocked, paused and awaiting, beside the watching, unreachable and reachable lines |
Output and exit statuses
Section titled “Output and exit statuses”Answers are JSON on standard output; a problem is one line on standard error, starting pitwall:.
| Status | Means |
|---|---|
| 0 | Done |
| 1 | Refused or failed, saying why. A read-only token’s action says to allow writes in Your settings → API tokens; an action no token may take says a person does it from the web. A command line not understood prints the usage |
| 2 | No usable token or no server to answer: a variable unset, a token unknown or revoked, or a server that cannot be reached or did not answer in time |