pitroom 0.19.0 → 0.21.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "name": "pitroom",
3
3
  "description": "A free pit crew for your expensive coding agent: the superpowers development workflow, run by cheap workers. Delegate research, fixes, tests, reviews and whole plans from Claude Code, Codex or any agent to OpenCode, Codex or Claude Code workers, with receipts that prove the savings.",
4
- "version": "0.19.0",
4
+ "version": "0.21.0",
5
5
  "author": {
6
6
  "name": "TahaAtas"
7
7
  },
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "pitroom",
3
- "version": "0.19.0",
3
+ "version": "0.21.0",
4
4
  "description": "A free pit crew for your expensive coding agent: delegate research, fixes, tests, reviews and parallel investigations to cheap worker agents running your own models, with verified answers, exact diffs and cost receipts.",
5
5
  "author": {
6
6
  "name": "TahaAtas"
package/CHANGELOG.md CHANGED
@@ -1,5 +1,36 @@
1
1
  # Changelog
2
2
 
3
+ ## 0.21.0
4
+
5
+ ### Windows
6
+ - **A real git guard on Windows.** Until now the guard (a worker may not commit, reset, push, `git add`, `clean` and so on) was a `sh` script and Windows had none. Now the ref and push guard (git's own env config with a `reference-transaction` hook) is on there too, and the `git` shim runs on the `sh.exe` that Git for Windows brings (`git.cmd` for cmd.exe and PowerShell, `git` for Git Bash). A worker that starts git without a shell skips the shim and is left with the config layer. The guard tests, which were skipped on Windows, run there now; `pitroom doctor` reports the shim as ready or says what is missing.
7
+
8
+ ### Costs
9
+ - **A price catalog that keeps itself up to date (opt-in).** `"priceFeed": true` (or `PITROOM_PRICE_FEED=1`): at most once a day, in a background process after a run (a run never waits for it), Pitroom fetches the public models.dev price list (the one OpenCode reads; USD per 1M tokens of about 8,000 models) and keeps a trimmed copy (about 400 KB) in its state directory; a failed or implausible answer keeps the old copy and is not retried for an hour. It is a fallback behind your own `workerPrices`, and the receipt says which was used (`estimated from models.dev prices`). `"primary"` can then be any model id of the catalog for the savings comparison, so it no longer goes stale (before: four fixed presets). New command `pitroom prices [--refresh] [--json]`, a doctor line, and settings `priceFeedUrl` and `priceFeedHours`. **Off by default**, because until now Pitroom's own code made no network request at all: PRIVACY.md says what the request carries (nothing about you; a plain GET) and what it shows (your IP address to models.dev).
10
+ - **Prices for the CLIs that report no cost.** Codex and Gemini give tokens but no cost, so a run's `worker cost` was `n/a` and counted as free in the savings, which overstated them. The new config `"workerPrices": {"codex:gpt-6.1-sol": "1.25,10,0.125"}` (USD per 1M tokens, "in,out[,cachedIn]", keyed `backend:model` or `backend`) lets you say what they cost: the cost is then estimated from the tokens, shown as `~$0.016 (estimated from your workerPrices)` in the receipt and marked estimated in the dashboard, kept in the ledger and history, and taken off the savings. A cost the CLI reported always wins. `pitroom doctor` warns about a worker in your chain that reports no cost and has no price. Pitroom still knows no vendor prices and fetches none: the numbers are yours.
11
+
12
+ ## 0.20.0
13
+
14
+ ### Notifications
15
+ - **A desktop notification when a background run has ended.** Off by default; `"notify": true` in the config (or `PITROOM_NOTIFY=1`). A run that went to the background (`--bg`, a crew, an MCP call) says `Pitroom ✔ research done` with its task, time and changed files; a failed, timed-out or stopped one says so. Runs that went well but took less than `notifyAfter` seconds (default 15) and audits are left out (a failure is always announced), and a crew says so once, when its last run ends, judged as a whole (from its earliest start, by its worst run). A worker process that is killed outright never gets to say so. macOS (`osascript`) and Linux (`notify-send`) are built in; `notifyCommand` runs your own command in a shell with the text in `PITROOM_NOTIFY_TITLE` / `PITROOM_NOTIFY_BODY` (ntfy, a chat webhook, a sound), which is also how to get one on Windows.
16
+
17
+ ### MCP
18
+ - **A live view for MCP clients.** A run that an MCP client starts and that is still going after a few seconds starts the dashboard (`pitroom dash --detach`, reused if it is up) and the "still running" result, also from `pitroom_wait`, carries its address with the instruction to open it in the app's own browser pane (the Claude Code and Codex apps have one), else to give it to the user. Before, only the skills told an agent about the dashboard, so an agent that used the MCP tools never mentioned it. A run that finishes quickly starts nothing; the system browser is never opened. The config's `"mcpDash": false` (or `PITROOM_MCP_DASH=0`) turns it off.
19
+
20
+ ### Stats
21
+ - **Rate limits no longer count against a worker.** Runs that failed on a rate limit or quota are left out of `pitroom history stats` and the dashboard's Stats (run counts, success rates, times, tokens) and shown apart as rate-limited: they say nothing about the worker's work, and on free models they made good workers look bad (in one history, 257 of 286 failures were rate limits). The config's `"countRateLimits": true` counts them as before.
22
+ - A run records why its worker failed (`failureKind`: `rate-limited`, `model-unavailable`, `auth`, `other`); older records are recognised by the hint Pitroom adds to a rate-limit error.
23
+
24
+ ### Fixes
25
+ - **Secret-looking files are recognised in any letter case.** `ID_RSA`, `.ENV`, `PROD.ENV`, `Credentials.json`, `SECRETS.YML`, `.NETRC` were not flagged (the check was case-sensitive for those names), though on macOS and Windows they are the same files as their lower-case spellings: a read run then ran in the project instead of a clean snapshot, and the heads-up did not mention them. Found by the worker that wrote the direct tests for `secrets.ts`.
26
+ - **A dashboard card could stay on its placeholder.** The page skipped every request while the browser said the page was hidden and waited for a `visibilitychange` that embedded browsers (the browser panes of the Claude Code and Codex apps) may never send; a card opened there showed grey boxes until the next poll, ten minutes later for a finished run. The first request is now always made; only the repeated ones are skipped while hidden.
27
+ - **An audit read the answer's paths as missing.** An answer is written for you, with the paths turned back into your project's (`/Users/me/proj/src/a.ts:3`); the auditor works in a clean snapshot of its own, where that path does not exist, and disputed it ("this path does not exist in this project"). The project's paths now reach the auditor relative to its working directory, and the prompt says so. In one history, 2 of 12 non-agreeing audits were this; re-auditing them: one now agrees, the other still disputes a real claim.
28
+
29
+ ### Docs and tests
30
+ - The README's reference parts are folded into accordions (the first screen shows about half as much text; headings and links are unchanged), and the PI-Desktop benchmark says what a later audit found: of its eight answers 3 agreed and 5 were marked partly right, mostly lists that leave things out.
31
+ - Direct tests for the git guard, slots and locks, secret detection, receipts, the run store and process spawning, the MCP resources and prompts, and the doctor checks, which were only covered through the CLI; most were written by Pitroom workers in isolated copies and reviewed. A flaky MCP HTTP test was fixed at its cause (a blocked event loop reused sockets the server had closed).
32
+ - `benchmarks/outcome-prediction`: what Pitroom's own history can predict (whether a run will fail, whether an answer will be audited as right). Result so far: failures are rate-limit bursts a worker's recent record explains, and the labels about answers are too few to learn from.
33
+
3
34
  ## 0.19.0
4
35
 
5
36
  ### Doctor
package/PRIVACY.md CHANGED
@@ -6,7 +6,9 @@ Pitroom is a command-line tool and a set of agent skills that run on your own co
6
6
 
7
7
  ## What the Pitroom authors collect
8
8
 
9
- Nothing. Pitroom has no accounts, no analytics and no telemetry, and its own code makes no network requests. No data is sent to the authors.
9
+ Nothing. Pitroom has no accounts, no analytics and no telemetry, and by default its own code makes no network requests. No data is sent to the authors.
10
+
11
+ **One request you can turn on.** With `"priceFeed": true` in the config (or `PITROOM_PRICE_FEED=1`; off by default) Pitroom keeps a price list of AI models up to date: at most once a day, in a background process after a run, it sends a plain `GET` for one public file (`https://models.dev/api.json` unless you set `priceFeedUrl`) and keeps a trimmed copy in its state directory. The request carries no data about you, your code, your tasks or your runs, and no cookie or account; like any web request it shows your IP address to the server that answers it. Nothing is fetched while the feed is off, and `pitroom prices` shows what it holds.
10
12
 
11
13
  ## Data categories and purposes
12
14
 
package/README.md CHANGED
@@ -103,6 +103,9 @@ In isolate mode nothing reaches your tree until you apply it.
103
103
 
104
104
  ### And more
105
105
 
106
+ <details>
107
+ <summary>12 more features</summary>
108
+
106
109
  - **Receipts, not vibes.** Tokens the worker burned, tokens returned to your agent, compression ratio, and an estimate of what your primary model would have charged. `pitroom savings --card card.svg` makes a shareable card.
107
110
  - **Self-healing worker chain.** Free models get rate-limited or retired. List fallback workers once (`fallback`) and a run that hits "model not found", 429 or quota errors moves to the next model automatically. Still no model hardcoded: the chain is yours.
108
111
  - **A crew, not just one worker.** `pitroom crew` starts several workers at once, `pitroom watch --json` streams one line per change so your agent follows them live, `pitroom wait -g` collects every answer, `pitroom apply -g` lands isolated patches in order. Up to 20 workers run at once by default (`maxParallel`, 30 at most), the rest queue, and the fallback chain absorbs free-tier rate limits; parallel writers are refused.
@@ -116,6 +119,8 @@ In isolate mode nothing reaches your tree until you apply it.
116
119
  - **A live dashboard and a searchable history.** `pitroom dash` opens a local page of every run (the task, what the worker did step by step, its result and diff) with history and statistics, for the agent apps that show neither hooks nor a status line; `pitroom history` searches everything Pitroom ever ran. See [Dashboard](#dashboard).
117
120
  - **Small.** About 6,500 lines of TypeScript in the CLI, a ~210 KB CLI bundle (plus the ~1.9 MB of dashboard files it serves, with syntax highlighting for ten languages), zero runtime dependencies.
118
121
 
122
+ </details>
123
+
119
124
  ### How it stays safe
120
125
 
121
126
  Each run gets the worker's own safety mechanism set to the mode (for OpenCode, a permission profile injected through `OPENCODE_CONFIG_CONTENT`): no commit/push/reset/checkout/stash/clean/rebase, no bulk deletes, no `sudo`, a file-reading tool that refuses `.env` and key files (OpenCode and Claude Code workers), no web tools unless you pass `--web`, no subagents, no recursive delegation. Only `allow`/`deny` rules, so a headless run never stalls on a prompt. A **git guard** on the worker's PATH also stops `sh -c "git push"`, `env git reset`, aliases and scripts from committing, pushing, resetting, stashing or touching your index. Your `opencode.json` is never touched. These safeguards reduce risk; they are not a security boundary (see [Responsibility](#responsibility) and [SECURITY.md](SECURITY.md)).
@@ -158,6 +163,9 @@ The screenshots below show sample data (an imaginary `shop-api` project), not a
158
163
 
159
164
  <p align="center"><img src="docs/dash-live.png" width="100%" alt="The Live tab: four running workers with timers and progress bars, then finished runs with approved and needs-fixes badges, step counts, tokens and savings"></p>
160
165
 
166
+ <details>
167
+ <summary>Cards, audits, history, Stats, and Stop/Discard</summary>
168
+
161
169
  **Click a card and it grows into a panel** with the task, what the worker did step by step (files read, searches, commands, edits, with times, failed ones marked), its result, the files and diff it changed, and the details (model, tokens, cost, fallbacks, reference check).
162
170
 
163
171
  <p align="center"><img src="docs/dash-card.png" width="100%" alt="An expanded run card: the task, a ten-step activity list, the result, five changed files with one opened to its highlighted diff, and the details"></p>
@@ -174,12 +182,19 @@ The screenshots below show sample data (an imaginary `shop-api` project), not a
174
182
 
175
183
  The dashboard is a React app built once into `dist/ui` and served as two static files, so the CLI still has no runtime dependencies. It follows your system's light or dark theme (a button switches it).
176
184
 
185
+ </details>
186
+
177
187
  ---
178
188
 
179
189
  ## Benchmarks
180
190
 
181
191
  Measured on a real, public repository: [PI-Desktop](https://github.com/vastsa/PI-Desktop) at commit `c2bfe35`, 2,349 tracked files and about 419,000 lines of TypeScript and Rust. Eight questions of the kind an agent asks before it changes code, run as one read-only crew (`pitroom crew`, at most four workers at a time) on OpenCode's free `muse-spark-1.3-contributor-free` model.
182
192
 
193
+ In short: on that repository eight questions took 156 s of wall clock, and the workers read 5.5 million tokens and handed the agent 7,684 (715× less); a later audit found some of the answers incomplete. On React, Django and Kubernetes, four free models matched `gpt-6-sol` on nine bounded questions, and in a planted-bug review test almost every model found almost every bug. The tables, and what they do not show, are below.
194
+
195
+ <details>
196
+ <summary>PI-Desktop: eight questions, token savings, answer quality and an isolated change</summary>
197
+
183
198
  | Question | Worker time | Tokens processed | Returned to the agent | Compression | Refs verified |
184
199
  |---|---|---|---|---|---|
185
200
  | Where is the plugin runtime, and which functions activate and deactivate a plugin? | 37 s | 405,380 | 767 | 529× | 10/11 |
@@ -196,8 +211,15 @@ Workers read 5.5 million tokens of code and docs (96 steps, 179 tool calls) and
196
211
 
197
212
  **Were the answers right?** Checked by hand against the repository: 46 key claims across all eight answers (the cited line and what it says) were all correct, and two completeness checks held (exactly 6 invoke and 3 event window channels; no tests in `config_sync_rpc.rs`). The i18n answer lists the 12 source files that import the package and leaves out 11 test and fixture files that do too, which the question did not ask about. Pitroom's own checker marks fewer references as verified than that: ¹ those two answers cite bare file names (`transcripts.rs:651`) that it cannot resolve to a path, and it counts them as unverified although the lines are right.
198
213
 
214
+ **An audit found more than the hand check did.** Each of the eight answers was later re-checked by a second free worker (`pitroom audit`, on `space-bunny`): 3 agreed and 5 were marked partly right. The disputes are about answers that are incomplete or slightly off, not about the lines they cite: lists that leave things out (session state: more places that write it; i18n: a second, deep-import style of consumer; RPC tests: 14 tests missing), counts that are off, and a few cited lines some lines away from the declaration. One was checked by hand and the auditor was right: the RPC `mod tests` block holds 59 tests, the answer said about 40. The others were not checked by hand, and an auditor is itself a free model that can be wrong. So treat a worker's list or count as a good first answer that your agent confirms when it matters, which is what `--audit` is for.
215
+
199
216
  **A change in an isolated copy:** "add a one-line comment above `resolveUpdateMode`" finished in 16 s and 4 steps (142,491 tokens). The patch was one file and one line, the comment matched the code, and your working tree is untouched until you apply.
200
217
 
218
+ </details>
219
+
220
+ <details>
221
+ <summary>Free models against <code>gpt-6-sol</code> on React, Django and Kubernetes</summary>
222
+
201
223
  **Free models against `gpt-6-sol`, on three large repositories.** The same kind of work on React (7,252 files), Django (7,091) and Kubernetes (31,353 files), at pinned commits. Nine bounded questions, three per repository: the file and line that define a function, how many files contain a word, and which files contain it. Every answer is checked against `git grep`, not by opinion: an exact `path:line` (half a point for the right file on the wrong line), an exact count, and for the lists an F1 score that punishes both missed and invented files. Each worker ran the nine questions once, read-only, with no fallback, so a model that cannot do it fails instead of being swapped for another.
202
224
 
203
225
  | Worker and model | Score | Median time | Median tokens |
@@ -219,6 +241,11 @@ Four free models matched `gpt-6-sol` on these questions. Every model found every
219
241
 
220
242
  Only workers that ran are in the table. Models that could not answer at all (a provider error, or the shared daily quota of OpenRouter's free tier) are left out, and so are the two `gpt-oss-20b` runs that ended in a provider error; a timeout is kept.
221
243
 
244
+ </details>
245
+
246
+ <details>
247
+ <summary>Does a review find a planted bug?</summary>
248
+
222
249
  **Does a review find a planted bug?** A bug was changed into real code (an inverted check, a swapped `&&`/`||`, a flipped `return`) in React, Django, Kubernetes and Pitroom itself, committed as a bare "tidy", and `pitroom review` was asked to review the commit. 29 packages (14 with the bug alone, 15 with the bug and three comment-only edits around it). A review counts as a find when a Critical or Important finding names the changed file and either cites a line within 5 or names the changed identifier or its function; "exact line" is the strict version (within 3).
223
250
 
224
251
  | Worker and model | Bug found | Exact line | Reviews | Mean time | Slowest |
@@ -233,6 +260,8 @@ Only workers that ran are in the table. Models that could not answer at all (a p
233
260
 
234
261
  Almost every model found almost every bug, so this test separates them on speed and precision, not on whether they can review: `muse-spark` described the right bug but often quoted a wrong line number (57% exact), and `gpt-6-sol` and `muse-spark` were the fastest by a wide margin. Only three models finished all 29: the other four are scored on the reviews that ran before a provider limit (the free tier's usage limit, and the Codex plan's, which `gpt-6-sol` reached), and the rest are left out, not counted as misses, so their rows rest on 9 to 14 reviews. Every change is only 2 to 5 lines, which is easy; there is no false-alarm rate (the comment-only "clean" packages turned out to contain comments that were really wrong, so they cannot show one); and React, Django and Kubernetes may be in a model's training data. The harness and every raw review are in [`benchmarks/review-bugs`](benchmarks/review-bugs).
235
262
 
263
+ </details>
264
+
236
265
  **What this does not show**
237
266
  - One run per question and model: there is no variance here. The questions are bounded lookups that `grep` can answer, so they do not show how a model handles design questions or large edits, and four free models and `gpt-6-sol` all scoring 100% says the test is easy at the top, not that they are equal.
238
267
  - An open-ended task ("find up to five spelling mistakes in `docs/`") did not finish: it was stopped after 19 minutes and 57 tool calls. Give workers bounded tasks.
@@ -247,7 +276,7 @@ To repeat it on your own repository: `pitroom crew -d <repo> -g bench "<question
247
276
 
248
277
  macOS and Linux are the main platforms. **Windows** runs the same test suite in CI (Windows Server, Node 22 and 24, with the fake workers; the worker CLIs themselves are not run there), with these differences:
249
278
 
250
- - **No git guard.** Pitroom's shim that blocks a worker's history changes and pushes is a `sh` script and is not available on Windows; `pitroom doctor` says so. Read-only runs are still limited by each worker CLI's own rules and `--isolate` keeps edits in a copy, so prefer `--isolate` and check the patch before `apply`.
279
+ - **The git guard** is the same two layers as elsewhere, built on the `sh.exe` that Git for Windows ships: git's own config (a `reference-transaction` hook that refuses every ref update, and push URLs that go nowhere) is always on; the `git` shim (`git.cmd` for cmd.exe and PowerShell, `git` for Git Bash) adds friendly refusals and also blocks `add`, `restore`, `clean` and the rest. A worker that starts git without a shell (a plain `CreateProcess`) skips the shim, and is left with the config layer. `pitroom doctor` says which is in effect. It is verified in CI with Git for Windows, not yet with the worker CLIs on a real Windows machine.
251
280
  - **The launcher is `pitroom.cmd`** (`%USERPROFILE%\.local\bin`), started with the Node that ran `pitroom install` or the one in `PITROOM_NODE`; it does not search for another Node.
252
281
  - **Line endings.** Pitroom compares and applies patches byte for byte. Keep `core.autocrlf` off (or an `eol=lf` in `.gitattributes`, as this repository has); a checkout converted to CRLF has not been tested with `apply`.
253
282
  - A read snapshot's files are not made read-only (Windows has no POSIX modes), and a `--verify` command runs in `cmd.exe`, which reports a missing command as `is not recognized`.
@@ -317,12 +346,18 @@ or, for Cursor (`~/.cursor/mcp.json`), Claude Desktop (`claude_desktop_config.js
317
346
 
318
347
  Each tool runs the matching `pitroom` command, so every rule of the CLI applies unchanged (permission profiles, git guard, isolation, read snapshots). A run is waited for up to `waitSeconds` (default 50), then comes back as "still running" with its id for `pitroom_wait`; keep it below your client's tool timeout. The server works in the directory it is started in: the client's for stdio, or the one `-d DIR` names (Claude Desktop starts it elsewhere, so give it `"args": ["mcp", "-d", "/path/to/project"]`); the tools' `dir` argument picks another per call.
319
348
 
349
+ <details>
350
+ <summary>More about the MCP server: progress, cancellation, resources, prompts, HTTP</summary>
351
+
352
+ - **A live view.** A run that is still going after a few seconds starts the dashboard (if it is not already up) and the result carries its address: "Live view of every run: http://127.0.0.1:7878/". The server's instructions tell the agent to open it in its app's own browser pane (the Claude Code and Codex apps have one) or else give it to the user; the system browser is not opened. A run that finishes quickly starts nothing. `"mcpDash": false` in the config (or `PITROOM_MCP_DASH=0`) turns it off.
320
353
  - **Progress.** While a call waits for a run, a client that sent a progress token gets a `notifications/progress` every few seconds ("running · read · 12s · 3 steps, 2 tool calls · last: …"), and a client that resets its timeout when progress comes in (the protocol allows it; not every client does) does not give up on a long run. **Cancelling** a `pitroom_run`, `pitroom_review` or `pitroom_audit` call stops the run it started (a cancelled `pitroom_wait` only stops waiting).
321
354
  - **Resources.** The latest runs are listed as `pitroom://run/<id>` (the report) and, for runs that changed files, `pitroom://run/<id>/patch` (the exact diff), so a client can attach one to a conversation. A client can **subscribe** to a run (`resources/subscribe`) and is told when it changes state (`notifications/resources/updated`), and every client is told when the newest run changes (`notifications/resources/list_changed`), so it need not poll; over HTTP these arrive on the session's event stream (a GET).
322
355
  - **Prompts.** `research`, `implement`, `review` and `crew` say how to use Pitroom for that job (in Claude Code they appear as `/mcp__pitroom__research`, …), and every skill is a prompt of the same name (`using-pitroom`, `pitroom-research`, …), so a client without skills gets the same guidance. The server's instructions tell the agent to use the skills alongside the tools.
323
356
  - **More than runs:** `pitroom_run` takes `tasks` (independent tasks in parallel, one worker each) and `continue` (a follow-up in the same worker session); `pitroom_info` reports without changing anything, by `topic`: `runs`, `history` (find an earlier answer before asking again), `stats` and `models` (pick a worker), `savings`, `cooldown`, `config`, `doctor`; `pitroom_stop` with `cooldowns` tries rate-limited models again.
324
357
  - **Over HTTP.** `pitroom mcp --http [--port N]` (default 7117) serves the same tools at `http://127.0.0.1:7117/mcp` for clients that connect to a URL, for example `claude mcp add --transport http pitroom http://127.0.0.1:7117/mcp --header "Authorization: Bearer $(cat ~/.local/state/pitroom/mcp-token)"` (the command is printed when it starts). It is a local service: it listens on 127.0.0.1 only, needs the bearer token (made on first start, kept at `<state dir>/mcp-token` with owner-only permissions, or set with `PITROOM_MCP_TOKEN`), and refuses a Host or Origin that is not local, so a web page cannot use it. Anyone who has the token can run workers as you, so keep it private. It works in the directory it was started in (printed when it starts; `-d DIR` for another). Each client has its own session; a call that asks for progress is answered as an event stream. Ending a session or stopping the server ends the waiting, not the runs: collect them with `pitroom_wait` or the CLI. `pitroom install --mcp` registers the stdio command, which needs no token and no running process.
325
358
 
359
+ </details>
360
+
326
361
  **Any other agent (a plain shell) or just the CLI**
327
362
 
328
363
  ```bash
@@ -410,6 +445,9 @@ Long jobs: `--bg` returns immediately; `pitroom wait <id>` blocks for up to 9 mi
410
445
 
411
446
  Pitroom ships a full development methodology as skills, adapted from [superpowers](https://github.com/obra/superpowers) so that its subagents are cheap workers: your agent brainstorms and plans with you, then executes the plan task by task while workers do the typing and a second model does the reviewing.
412
447
 
448
+ <details>
449
+ <summary>The workflow, step by step</summary>
450
+
413
451
  <p align="center"><img src="docs/workflow.svg" width="100%" alt="Workflow: brainstorming, then a plan with a worker tier per task, then for every task a worker implements in an isolated copy, another model reviews, fix rounds repeat until approved, and your agent applies, tests and commits; then a whole-branch review and finishing."></p>
414
452
 
415
453
  | Step | Skill | Command |
@@ -427,6 +465,8 @@ A review package holds the diff under review with 10 lines of context, and the r
427
465
 
428
466
  Tiers map plan tasks to workers: `"tiers": {"cheap": "opencode", "standard": "codex", "capable": "claude"}`. `pitroom plan status PLAN` rebuilds where a plan stands from the run records (it survives context compaction), and `pitroom plan note` keeps completions and rulings outside the repo.
429
467
 
468
+ </details>
469
+
430
470
  ---
431
471
 
432
472
  ## Audits
@@ -440,11 +480,16 @@ pitroom run --audit "…" # re-check this run's answer when it finishes (
440
480
 
441
481
  or set `"audit": 0.1` in the config (or `PITROOM_AUDIT=0.1`) to have about one read run in ten audited, in the background, without your agent asking. The same run is always in or out of the sample.
442
482
 
483
+ <details>
484
+ <summary>Cost, limits and where the verdict shows</summary>
485
+
443
486
  - **Cost:** off by default. An audit is a read run of the auditor, so about the rate times the worker's own tokens, on the `audit` tier (else `cheap`, i.e. a free model if that is your cheap tier). It never delays the run or fails it.
444
487
  - **Never itself:** the auditor is never the worker and model that gave the answer; with no other worker configured nothing is audited (`pitroom doctor` says so). Only read runs are audited: a change has `pitroom review`.
445
488
  - **Where it shows:** the answer's card and `pitroom show` carry the verdict and the disputed claims; the Stats tab counts, per worker, how many audited answers were confirmed. Audits are not counted as runs and save nothing.
446
489
  - **A sample, not a guarantee.** The auditor is a model too: it can share a blind spot, and a few audits say little about a worker. Treat `DISAGREE` as a reason to look, and `AGREE` as one more signal.
447
490
 
491
+ </details>
492
+
448
493
  ## Crews
449
494
 
450
495
  A real crew over this repository, four questions at once on a free OpenCode Zen model:
@@ -487,6 +532,9 @@ For changes, `pitroom crew -i …` gives every worker its own isolated copy of y
487
532
 
488
533
  ## Skills
489
534
 
535
+ <details>
536
+ <summary>The 14 skills</summary>
537
+
490
538
  | Skill | Your agent uses it to |
491
539
  |---|---|
492
540
  | `using-pitroom` | see what Pitroom offers and when it pays off (injected at session start by the plugin; optional) |
@@ -504,6 +552,8 @@ For changes, `pitroom crew -i …` gives every worker its own isolated copy of y
504
552
  | `pitroom-implement` | get a one-off change made in an isolated copy |
505
553
  | `pitroom-crew` | split independent work across parallel workers and merge the results |
506
554
 
555
+ </details>
556
+
507
557
  ---
508
558
 
509
559
  ## Commands
@@ -540,6 +590,9 @@ Exit codes: `0` ok · `1` worker failed · `2` usage · `3` refused/setup · `4`
540
590
 
541
591
  ### History
542
592
 
593
+ <details>
594
+ <summary>Searching the history</summary>
595
+
543
596
  Every finished run is also written to a SQLite database (`history.db` in Pitroom's state directory; Node's built-in `node:sqlite`, nothing to install). It keeps the task, worker and model, time, tokens, savings, the steps the worker took, its answer and the diff, and it is searchable:
544
597
 
545
598
  ```bash
@@ -550,8 +603,13 @@ pitroom history stats --since 30d # runs, success rate, average time and to
550
603
 
551
604
  While a run runs, its raw event stream is a plain file (the simplest thing that survives a crash). When it ends, the stream is compressed, and the stderr log is kept only for runs that did not succeed. `pitroom clean` removes old run directories but the history keeps them: `pitroom show <run>` still prints their report, steps, and patch. Runs from before the history existed are taken in by `pitroom history import` (it also runs on the first `pitroom history` and `pitroom dash`). The files remain the source: the database can be deleted and rebuilt with `history import` for the runs still on disk.
552
605
 
606
+ </details>
607
+
553
608
  ### Seeing Pitroom at work
554
609
 
610
+ <details>
611
+ <summary>The status line and hook cards (and what the apps show instead)</summary>
612
+
555
613
  Two settings make every delegation visible, whether or not the agent mentions it. A status line shows running workers and this week's savings (`--then` keeps your own status line first); a card appears after each `pitroom` command the agent runs, once per phase (started, finished with its result, applied). The plugin registers the card hook itself; with `pitroom install`, add both to `~/.claude/settings.json`:
556
614
 
557
615
  ```json
@@ -568,6 +626,8 @@ The Claude Code and Codex **apps** show neither hook messages nor a status line.
568
626
  - `pitroom dash --detach` prints the address of a live dashboard with three tabs: **Live** (every running and recent run as an animated card; click one for the task, what the worker did step by step, its result, the diff and the details), **History** (search and filter everything Pitroom ever ran; every run opens as the same card) and **Stats** (success rate, time, tokens and savings per worker and model). It is read-only, listens on `127.0.0.1` only and stops itself after an hour without a request (`pitroom dash --stop` ends it sooner). Open it in a browser or in the app's own browser pane. The skills tell the agent to start it and give you the address when it runs workers in the background.
569
627
  - `pitroom watch -g NAME --brief` prints one card line when a worker starts and one when it ends. In Claude Code, the agent runs it through the Monitor tool and the lines appear in the app; in Codex the command's output block fills as it goes.
570
628
 
629
+ </details>
630
+
571
631
  ---
572
632
 
573
633
  ## How it works
@@ -606,6 +666,9 @@ pitroom run -m nvidia/z-ai/glm-5.3 "…" # another model on th
606
666
 
607
667
  ### Models, costs and effort
608
668
 
669
+ <details>
670
+ <summary>Models, costs and effort levels</summary>
671
+
609
672
  `pitroom models` lists what each worker offers (Codex from its own model cache, Claude Code's aliases, OpenCode's `opencode models`, Gemini CLI's built-in names), the reasoning-effort levels each model accepts, what you say it costs and what your own runs used:
610
673
 
611
674
  ```text
@@ -615,10 +678,12 @@ codex gpt-6-sol low/medium*/high/xhigh/max/ultra 1 1 24k
615
678
  claude haiku low/medium/high/xhigh/max ? - - - -
616
679
  ```
617
680
 
618
- Pitroom cannot know vendor prices and does not fetch them, so a cost is what you enter: `"costs": {"codex:gpt-6-sol": 1, "codex:gpt-6.1-sol": 2}` in the config, in any unit (they are only compared). `pitroom doctor` then prints the cost of the models in use and says when you priced a cheaper one of the same worker. A target that names only an effort (`codex:#low`) uses the model from `models`; a Codex or Claude Code worker with no pinned model gets a warning, because it would run the vendor's own default, which can change and cost more. `--effort LEVEL` sets the level for one run; your agent picks model and level from `pitroom models` (cheapest that fits: `low` for lookups, `medium` for ordinary changes, `high` for reviews).
681
+ Pitroom knows no vendor prices of its own and, unless you turn on `priceFeed` (see the config notes), fetches none, so a cost is what you enter: `"costs": {"codex:gpt-6-sol": 1, "codex:gpt-6.1-sol": 2}` in the config, in any unit (they are only compared; dollar prices for the receipts of Codex and Gemini go in `workerPrices`, see the config notes). `pitroom doctor` then prints the cost of the models in use and says when you priced a cheaper one of the same worker. A target that names only an effort (`codex:#low`) uses the model from `models`; a Codex or Claude Code worker with no pinned model gets a warning, because it would run the vendor's own default, which can change and cost more. `--effort LEVEL` sets the level for one run; your agent picks model and level from `pitroom models` (cheapest that fits: `low` for lookups, `medium` for ordinary changes, `high` for reviews).
619
682
 
620
683
  Fallbacks cross backends (e.g. `"fallback": ["codex:#low", "opencode"]`): a worker that is rate-limited, logged out or missing its model hands the task to the next. Follow-ups (`--continue`) always stay on the worker that owns the session. Writing an adapter: [docs/backends.md](docs/backends.md). A model that says "rate limited" (a daily quota used up, an overloaded provider) is remembered for the time its message gives, or a guess: the next runs skip it while a fallback is left, so they do not each wait for it to fail. `pitroom cooldown` lists what is skipped and until when, `--clear` tries it again, and `doctor` shows it too.
621
684
 
685
+ </details>
686
+
622
687
  ---
623
688
 
624
689
  ## Configuration
@@ -643,6 +708,9 @@ Fallbacks cross backends (e.g. `"fallback": ["codex:#low", "opencode"]`): a work
643
708
 
644
709
  Or put defaults in `~/.config/pitroom/config.json` (flags and env still win); `pitroom config` shows every effective value and where it came from. `pitroom init` proposes a starter config from the worker CLIs and OpenCode models you have (a fallback chain of your free models, tiers when more than one CLI is installed) and writes it only with `--yes`; it never picks your model for you. `models` gives each worker a default model for targets that name none (`-W codex`, a `"codex"` fallback); a model in the target or `-m` still wins. `tiers` names workers for `--tier` and for plan tasks' `**Worker:**` lines:
645
710
 
711
+ <details>
712
+ <summary>config.json: an example and what each setting does</summary>
713
+
646
714
  ```json
647
715
  {
648
716
  "worker": "opencode",
@@ -662,6 +730,13 @@ Or put defaults in `~/.config/pitroom/config.json` (flags and env still win); `p
662
730
  - `tiers`: `cheap`, `standard` and `capable` name the workers for plan tasks and `--tier`; an optional `review` tier names who reviews a run (by default another worker than the implementer's, `standard` first).
663
731
  - `audit`: the chance (0 to 1, default 0 = off) that a finished read run is re-checked in the background, see [Audits](#audits). The `audit` tier (else `cheap`) names who does it.
664
732
  - `costs`: your relative cost per `worker:model`, only compared with each other; `maxParallel`: workers at once (default 20, at most 30).
733
+ - `workerPrices`: USD per 1M tokens of a worker model, for the CLIs that report no cost (Codex, Gemini): `"workerPrices": {"codex:gpt-6.1-sol": "1.25,10,0.125"}` is "in,out[,cachedIn]", keyed `backend:model` (the model that ran, else the one you asked for) or `backend` alone. Without one the receipt says `worker cost n/a` and the run counts as free in the savings, which overstates them (`pitroom doctor` warns); with one the cost is estimated from the tokens, shown as `~$0.016 (estimated from your workerPrices)`, kept in the ledger, history and dashboard, and taken off the savings. Pitroom knows no vendor prices and does not fetch them, so this is your number.
734
+ - `priceFeed`: keep a price catalog up to date (default `false`; `PITROOM_PRICE_FEED=1`). The catalog is the public [models.dev](https://models.dev) list OpenCode also reads (USD per 1M tokens of about 8,000 models): at most once a day (`priceFeedHours`, default 24), in a background process after a run, never while a run waits, Pitroom sends a plain `GET` for that one file (`priceFeedUrl` / `PITROOM_PRICE_FEED_URL` to use a mirror, `priceFeedHours` / `PITROOM_PRICE_FEED_HOURS` for the interval) and keeps a trimmed copy (about 400 KB) in its state directory; a failed refresh keeps the old copy and is not retried for an hour. It is only a fallback: your `workerPrices` come first, and the receipt says which was used (`estimated from models.dev prices`). With it, `"primary": "<model id>"` can name any model of the catalog for the savings comparison (`"primary": "claude-opus-5-5"`), where without it only the four presets exist. `pitroom prices` shows the feed, the catalog and the price each worker in use gets; `pitroom prices --refresh` fetches now. What it sends: [PRIVACY.md](PRIVACY.md). The listed prices are API list prices: a worker on a subscription (Codex with a ChatGPT account) does not pay them, so for such a worker the estimate is what the same tokens would cost on the API.
735
+ - `notify`: a desktop notification when a run that went to the background (`--bg`, a crew, an MCP call) has ended, so a long job does not have to be watched (default `false`; `PITROOM_NOTIFY=1`). Runs that went well but took less than `notifyAfter` seconds (default 15; `PITROOM_NOTIFY_AFTER`) and audits are not announced (a failure always is), and a crew says so once, when its last run ends, judged as a whole. A worker process that is killed outright never gets to say so. The built-in notifier uses `osascript` on macOS and `notify-send` on Linux (none for Windows yet); `notifyCommand` runs a command of your own instead, in a shell, with the text in `PITROOM_NOTIFY_TITLE` and `PITROOM_NOTIFY_BODY` (and `PITROOM_NOTIFY_RUN`, `PITROOM_NOTIFY_STATE`): for example `"notifyCommand": "curl -s -d \"$PITROOM_NOTIFY_BODY\" ntfy.sh/my-topic"`.
736
+ - `mcpDash`: whether a run that an MCP client starts, and that is still going after a few seconds, also starts the dashboard and returns its address (default `true`; `PITROOM_MCP_DASH=0` or `"mcpDash": false` turns it off), see [the MCP server](#1-install-pick-your-agent).
737
+ - `countRateLimits`: whether runs that failed on a rate limit or quota count in `pitroom history stats` and the dashboard's Stats (default `false`: they are left out of the run counts, success rates, times and tokens and shown apart as rate-limited, since they say nothing about the worker's work; `true` counts them as not ok).
738
+
739
+ </details>
665
740
 
666
741
 
667
742
  ---