Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions .github/workflows/release.yml
Original file line number Diff line number Diff line change
Expand Up @@ -102,6 +102,7 @@ jobs:
GH_TOKEN: ${{ github.token }}
run: |
set -euo pipefail
cp docs/probbit.1 dist/ # the manual page (`probbit man`), also inside every archive under docs/
ls -la dist
if gh release view "$GITHUB_REF_NAME" > /dev/null 2>&1; then
gh release upload "$GITHUB_REF_NAME" dist/* --clobber
Expand Down
16 changes: 16 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,15 @@ All notable changes to this project are documented here. The format follows
persona-confidence hold, an engine-unreleased trait and a lost connection. It works for any persona read from the strand.
The page is embedded in the binary with no external assets; the terminal view (`--once`, `--follow`, `--plain`) is unchanged.
The monitor's layout gains `caps.prediction_error` from the persona's `expectation.pe_cap`. docs/persona.md §5.8.
- `probbit help [COMMAND [SUBCOMMAND]]`: the same text as `COMMAND [SUBCOMMAND] --help`; `probbit help` alone is
`probbit --help`. The persona and live subcommands have their own help (usage, flags, exit codes).
- Did-you-mean: an unknown command or subcommand names the closest one (`unknown command "persna"; did you mean
"persona"?`, Damerau-Levenshtein distance up to 2, or a unique prefix). The exit code stays 2.
- `probbit completions bash|zsh|fish`: a static completion script with every command, subcommand and flag.
- `probbit man` and `docs/probbit.1`: the manual page. Releases attach it; `install.sh` installs it to
`~/.local/share/man/man1/` (`PROBBIT_MAN_DIR` to choose), never failing the install over it.
- `--json` on every command: errors as one JSON object on stdout even at a terminal, for a bad command or flag too
(code `flag`, or `command` with a `suggestion`).

### Changed
- `persona lint` with rules (`--never RULE` / `--props FILE`) no longer reports green on a rule it could not settle. When
Expand All @@ -25,6 +34,13 @@ All notable changes to this project are documented here. The format follows
read on a number input to the grid (as a fraction of that input's max, after the given points, each once; `search.grid` lists
them). A rule in force only between two default grid points (for example stakes 0.7 to 0.8) is now reached by the random
search too. Personas whose rules and habits read no number thresholds off the grid get the same search, byte for byte.
- One command table in the CLI renders every help screen, the completions and the man page, and the parser reads its flags
from it: what is documented is what is accepted.
- Help fits 100 columns: `probbit --help` starts with the version, groups the commands and ends with examples;
`monitor --help` has usage, modes, flags and demo sections; the terminal hero screen fits 100 columns.
- Errors: one human line on stderr, always. A bad input's `{"error"}` object goes to stdout when stdout is not a terminal (as
before for every program and wrapper) or with `--json`; at a terminal without `--json` only the line is printed, no longer
both (docs/CHEATSHEET.md "Errors").

### Fixed
- `install.sh`: when the install directory is not on `PATH`, the hint names the file the user's shell reads: `~/.zshrc` for
Expand Down
4 changes: 4 additions & 0 deletions CONTRIBUTING.md
Original file line number Diff line number Diff line change
Expand Up @@ -24,6 +24,10 @@ and clean-prefix shell, PowerShell 5.1/7 and npm installs using locally packaged
`node --test npm/test-wrapper.cjs` needs no npm dependencies. Set `PROBBIT_BIN` to the release executable and run
`python3 -m unittest discover -s python -p 'test_*.py'` for the integration contracts.

The command table in `probbit-cli/src/main.rs` (`COMMANDS`) is the one source of every `--help`, `probbit help`, the shell
completions and the man page; the parser reads its flags from it. After changing it or bumping the version, regenerate the
committed man page: `cargo run -p probbit-cli -- man > docs/probbit.1` (test `committed_man_page_is_generated`).

## Ground rules

- **No external crates on the shipped path.** `cargo build` must keep working offline.
Expand Down
17 changes: 16 additions & 1 deletion README.md
Original file line number Diff line number Diff line change
Expand Up @@ -128,6 +128,20 @@ there are no external crates.

At a terminal, `install.sh` ends with probbit's own hero screen. Platform notes and the installer tests: [PORTABILITY.md](PORTABILITY.md).

`install.sh` also installs the manual page (`man probbit`) to `~/.local/share/man/man1/` (`PROBBIT_MAN_DIR` to choose; a
failure there installs the binary all the same); every archive carries it as `docs/probbit.1`, and `probbit man` prints it.
Shell completions come from the binary itself:

| shell | command |
|---|---|
| bash | `probbit completions bash > ~/.local/share/bash-completion/completions/probbit` |
| zsh | `probbit completions zsh > ~/.zfunc/_probbit` (with `fpath=(~/.zfunc $fpath)` before `compinit` in `~/.zshrc`) |
| fish | `probbit completions fish > ~/.config/fish/completions/probbit.fish` |

`probbit --help` lists every command by group; `probbit help COMMAND [SUBCOMMAND]` (the same as `probbit COMMAND --help`)
gives a command's flags with their defaults, its exit codes and examples. A mistyped command gets a suggestion:
`probbit persna` -> `unknown command "persna"; did you mean "persona"?` (exit 2).

## 60-second tour

```
Expand Down Expand Up @@ -323,7 +337,8 @@ Problem:
}
```
- The document is checked strictly (types, unknown fields, duplicate ids, empty domains; finite numbers only): bad input exits 2
with one `{"error":{"code","path","message"}}` object on stdout ([docs/probbit-ir-json.md](docs/probbit-ir-json.md) "Input contract").
with one `{"error":{"code","path","message"}}` object on stdout ([docs/probbit-ir-json.md](docs/probbit-ir-json.md) "Input contract"),
whenever stdout is not a terminal (any program calling probbit) or with `--json`; at a terminal, only the stderr line.
- `scores`: finite numbers with |x| <= 1e9 (natural-log odds; docs/probbit-ir-json.md "Numeric contract"), one per worker the task may go to (log-odds from your judge, an LLM, a heuristic, a price).
A worker missing from `scores` is not allowed unless listed in `allowed` (then it enters with score 0).
- `allowed` (optional): hard rule. `cap`: hard per-worker quota. `clamp` (optional): force this task to one worker (what-if).
Expand Down
25 changes: 24 additions & 1 deletion docs/CHEATSHEET.md
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,17 @@

The CLI's own help and docs, shortened; `probbit <command> --help` has every flag.

## Help, completions, the manual page
| command | does |
|---|---|
| `probbit --help` | every command by group (persona, live, monitor, decide/run, mcp, other), the exit codes, six examples |
| `probbit help COMMAND [SUBCOMMAND]` | the same text as `probbit COMMAND [SUBCOMMAND] --help`: usage, flags with defaults, exit codes |
| `probbit completions bash\|zsh\|fish` | a completion script for the shell (commands, subcommands, flags); install lines in its `--help` |
| `probbit man` | the manual page (roff); `install.sh` puts it in `~/.local/share/man/man1/`, so `man probbit` works |

Help, completions and the man page all come from one command table, so they list exactly the flags the parser accepts. A
mistyped command or subcommand exits 2 with the closest name: `did you mean "persona"?`.

## Verdicts (`decide`, `run`, `evaluate`; a persona turn's `engine.verdict`)
| verdict | means | exit |
|---|---|---|
Expand Down Expand Up @@ -32,12 +43,24 @@ The exact tiers run before the sampler:

## Exit codes
- `decide`, `run`, `evaluate`: 0 answer (exact | diagnostics_passed | partial), 1 infeasible (a proof), 2 bad input (one
`{"error"}` object on stdout) or bad flag (stderr), 3 refused / declined / non-finite result.
`{"error"}` object on stdout, see Errors) or bad flag (stderr), 3 refused / declined / non-finite result.
- `persona`: 0 done; 1 lint found an unresolved contradiction or (with rules) a counterexample, fuzz found a counterexample or
prove left a rule unknown; 2 bad persona / state / inputs / script / rule, or bad flag.
- `live`: 0 done; 1 verify: a line differs; 2 a bad persona, state, event or flag.
- `monitor`: 0 every line replays; 1 a line differs; 2 a bad flag, a port that cannot be had, or a file that is not a strand.

## Errors
One channel, the same for every command (0.8.2):
- **stderr**: one human line, always: `probbit: bad JSON: expected string at byte 1`.
- **stdout**, bad input (a document, persona, state, event; numeric failures; live refusals): one
`{"error": {"code", "path", "message"}}` object when stdout is **not a terminal** (a pipe, a file, every wrapper: Python, MCP,
npm, the examples), or with **`--json`**. At a terminal without `--json`: the line only, never both.
- **stdout**, bad command or flag (unknown command, subcommand or flag; a bad flag value): nothing, so a piped caller tells it
from bad input by an empty stdout. With `--json`: `{"error": {"code": "flag", ...}}`, or for an unknown command or
subcommand `{"error": {"code": "command", ..., "suggestion": "persona"}}` (`null` when nothing is close).
- `--json` is accepted by every command; it changes no answer (for `persona fuzz` / `prove` it also selects the JSON report).
- An unknown command or subcommand names the closest one: `probbit: unknown command "persna"; did you mean "persona"?`

## `probbit persona <sub> PERSONA`
| sub | does |
|---|---|
Expand Down
2 changes: 1 addition & 1 deletion docs/agents.md
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,7 @@ an agent harness with a shell tool. No server, no bindings, no network. The docu
|---|---|---|
| 0 | an answer: verdict `exact`, `diagnostics_passed` or `partial` | act on `released`; escalate `escalated` (empty unless `partial`) |
| 1 | `infeasible`: no plan satisfies the rules (a proof) | relax a rule or a cap; it is an answer, not a crash |
| 2 | bad input: one `{"error": {"code", "path", "message"}}` object on stdout; a bad flag prints one line on stderr instead | fix the document or the flag |
| 2 | bad input: one `{"error": {"code", "path", "message"}}` object on stdout (piped, as an agent runs it; `--json` at a terminal); a bad flag prints one line on stderr instead | fix the document or the flag |
| 3 | `refused` / `declined` (the gate or a cap said no), or `{"error": {"code": "numeric"}}` | escalate the whole decision; any retained candidate plan is diagnostic only |

Decision documents that carry a `plan` also carry `plan_status` (`released`, `partial`, or `diagnostic`)
Expand Down
3 changes: 2 additions & 1 deletion docs/probbit-ir-json.md
Original file line number Diff line number Diff line change
Expand Up @@ -121,7 +121,8 @@ number that is not a finite double, nesting deeper than 256, more than 65,535 va
size limits in "Limits in v1", stdin above `--max-input-mb`). Unreadable stdin and invalid UTF-8 are `schema` errors too
(0.2.1; they printed a stderr line only). `path` locates
the offending field (`""` = the whole document, as for JSON syntax errors and non-finite numbers, whose message gives the byte
offset). Flag errors keep their convention: exit 2, a message on stderr, nothing on stdout. The same strict reader parses
offset). The object goes to stdout when stdout is not a terminal or with `--json` (0.8.2; at a terminal the stderr line alone). Flag
errors keep their convention: exit 2, a message on stderr, nothing on stdout (with `--json`: one object, code `flag`). The same strict reader parses
both front-ends (`probbit-cli/src/json.rs`; CLI test `input_contract_rejects_malformed_documents`, which includes the 2026-09-30 external
review's cases: `"allowed": "A"` used to enable every scored worker and answer `exact`; a cap object where the caps array
belongs was dropped; duplicate value names emitted duplicate keys).
Expand Down
Loading
Loading