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
16 changes: 16 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -28,6 +28,22 @@ All notable changes to this project are documented here. The format follows
the safety floor of 0.1 held on every turn its habits allowed (least odds 0.141), and every individual ends in the state the
Python prototype of the design reaches on the same events (100 of 100 digests).

- **`probbit monitor STRAND`** (docs/persona.md §5.8, probbit-cli/src/monitor.rs): watch an individual's inner state as live
horizontal bars. It replays the strand with the rules of `live verify` (`live::Replay`, now shared by both), recomputing every
stance document from the strand alone, and draws the latest event: each trait's levels with their odds (the level taken
highlighted, its phrase), the moods with a sparkline of the last 50 events, the event's inputs and history features, the habits
in force (the bound ones marked, the violations counter), the learned deltas within their cap, the drives when a document
carries them, and the stance line. `--follow` replays appended lines within a second (a truncated or rotated strand is replayed
from the start, with a warning), `--once` prints one frame, `--plain` draws in plain ASCII. `probbit monitor --demo` plays the
tutor's scripted week (the week `live --demo week` writes, seed 2, through a temporary file it removes at once), paced 1 s per
hour and each night in 2 s. Exit 0, 1 at a line that differs (named in the frame), 2 for a bad flag or a file that is not a
strand. It changes no file and sends nothing; no dependencies.
- **`probbit monitor STRAND --serve [--port N] [--open]`** (also with `--demo`): the same board as a page in the browser. A server
on 127.0.0.1 (std `TcpListener`; it binds no other address, and refuses requests addressed to another host) follows the strand
and serves one page embedded in the binary (styles and script inline; it fetches no fonts, styles or scripts), its server-sent
events (the layout, the latest frame, then a frame per event, a heartbeat every 15 s) and `/doc/N`, event N's stance document
as `probbit live` printed it. The URL is the line on stdout; `--open` serves the same and starts the default browser, best
effort. `probbit monitor --demo --open` plays the week over and over in the browser.
### Changed
- MCP: the input schemas of `probbit_persona_turn` (`inputs`) and `probbit_live_event` (`event`) declare `goals`, so a client
that checks arguments against them passes a drives persona's goal signals.
Expand Down
20 changes: 17 additions & 3 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -518,6 +518,19 @@ A persona without the block gives the same documents as before, byte for byte. M
cues, rewards and praises fun on this persona, 100 individuals x 10,000 turns: 0 habit breaks, all 6,743 must-do turns pursued
the due chore, and the safety floor (0.1) held on every turn its habits allowed (least odds 0.141), while fun took 85 % of turns.

### Watch it live: `probbit monitor`

`probbit monitor pip.strand` replays a strand with the rules of `live verify` and draws the individual's inner state as live bars:
each trait's levels with their odds, the moods, the event's inputs, the habits that bound, the learned weights and the line, in the
terminal (`--follow` redraws as the strand grows) or as a page on 127.0.0.1 (`--serve`). It reads the strand and sends nothing
anywhere ([docs/persona.md](docs/persona.md) §5.8). No strand yet? The tutor's week, in under a minute:

```sh
probbit monitor --demo --open
```

![probbit monitor: the tutor's week in the browser, the bars moving with every event](docs/probbit-monitor.gif)

## After any judge: `probbit evaluate`

Decision models (TypeSafe's Jev, Cloudflare's Clef and Clef-flash, local System One servers) are judges: content in, a
Expand Down Expand Up @@ -701,7 +714,8 @@ or Windows.
- Hardware backend through `probbit-ir` when a p-bit fabric is available.

## Documentation map
- [docs/CHEATSHEET.md](docs/CHEATSHEET.md): one page: the verdicts, the tiers, `bound`, the exit codes, every persona and live command.
- [docs/CHEATSHEET.md](docs/CHEATSHEET.md): one page: the verdicts, the tiers, `bound`, the exit codes, every persona, live and
monitor command.
- [BENCHMARKS.md](BENCHMARKS.md): every number, with machine, load and `N`.
- [USE-CASES.md](USE-CASES.md): what the measurements support, by problem shape and by industry.
- [docs/probbit-ir-json.md](docs/probbit-ir-json.md): the `probbit-ir` JSON v1 wire format, instructions, resource controls, limits.
Expand All @@ -710,8 +724,8 @@ or Windows.
- [docs/agents.md](docs/agents.md): calling probbit from a shell, Python, Node, PowerShell, MCP agents and a browser, and
`probbit evaluate` after a decision model.
- [docs/persona.md](docs/persona.md): `probbit persona`, the individuality layer: the persona file, the compilation, the stance and
state documents, the canonical JSON, testing a character, bounded learning and `probbit live` (§2.8, §5.7), what a persona can
not do; [examples/persona/](examples/persona/): three personas + goldens.
state documents, the canonical JSON, testing a character, bounded learning, `probbit live` and `probbit monitor` (§2.8, §5.7,
§5.8), what a persona can not do; [examples/persona/](examples/persona/): three personas + goldens.
- [python/](python/): `probbit.py`, a zero-dependency subprocess wrapper (with `evaluate`, the persona functions and a stdlib mock
judge), its tests and three examples.
- [playground/](playground/): one static page that runs probbit in a browser (`probbit-wasm`, built by `playground/build.sh`).
Expand Down
5 changes: 4 additions & 1 deletion docs/CHEATSHEET.md
Original file line number Diff line number Diff line change
Expand Up @@ -36,6 +36,7 @@ The exact tiers run before the sampler:
- `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.

## `probbit persona <sub> PERSONA`
| sub | does |
Expand All @@ -52,12 +53,14 @@ The exact tiers run before the sampler:
| `compile --state STATE [--inputs ...]` | the turn's probbit-ir program |
| `describe` | traits, moods, inputs, habits, agenda |

## `probbit live`
## `probbit live`, `probbit monitor`
| command | does |
|---|---|
| `live PERSONA [--seed N \| --state FILE] [--strand FILE] [--events FILE]` | JSONL events in, one stance per event out |
| `live PERSONA --demo week [--seed N] [--plain]` | a scripted week: learning to a cap, a night, rules that hold |
| `live verify STRAND` | replay a strand; the earliest line that differs |
| `monitor STRAND [--follow] [--plain] [--serve] [--open] [--port N]` | the strand replayed as live bars: the terminal, or a page on 127.0.0.1 |
| `monitor --demo [--open]` | the tutor's week, paced, in under a minute |

## Testing a character
- `lint`: contradicting habits; with `--props`, every rule proved or fuzzed;
Expand Down
4 changes: 3 additions & 1 deletion docs/agents.md
Original file line number Diff line number Diff line change
Expand Up @@ -98,7 +98,9 @@ commands' own documents and return the commands' own JSON, byte for byte:

The persona and live tools run in the server's process and keep nothing between calls: pass the returned state back on the next
turn and put `stance.line` into the model's prompt (after any cached prefix). A refused or fallback stance is an answer; a bad
persona, state, input or event is a tool error with the `{"error": {"code": "persona", ...}}` object.
persona, state, input or event is a tool error with the `{"error": {"code": "persona", ...}}` object. A person can watch the
individual behind a `strand_path` as it grows: `probbit monitor STRAND --serve --open` (a page on 127.0.0.1) or `--follow` in a
terminal ([persona.md](persona.md) §5.8).

`flags` are the command's flags without the dashes: `{"budget_ms": 200, "seed": 3, "summary": true}`; `summary: true`
returns the compact answer (README, "First five minutes"). `infeasible` and `refused` / `declined` are answers; bad input
Expand Down
55 changes: 53 additions & 2 deletions docs/persona.md
Original file line number Diff line number Diff line change
Expand Up @@ -19,7 +19,8 @@ This document is normative for the file format, the compilation, the stance docu
`probbit persona` (probbit-cli/src/persona.rs and yaml.rs, no dependency) and served on every surface with the same documents: the
CLI, `probbit mcp` (tools `probbit_persona_init`, `probbit_persona_turn`), the Python wrapper (`probbit.persona_init`,
`persona_turn`, `persona_replay`) and the browser module (probbit-wasm ops 4 and 5). `probbit live` (section 5.7, live.rs) keeps an
individual running on a clock, with learning (section 2.8) and a replayable log. The example personas and their goldens are in
individual running on a clock, with learning (section 2.8) and a replayable log; `probbit monitor` (section 5.8, monitor.rs)
draws its inner state live from that log. The example personas and their goldens are in
[examples/persona/](../examples/persona/). An independent reference implementation of this format (Python) gives the same
documents byte for byte on every example turn (section 5.3).

Expand Down Expand Up @@ -687,6 +688,55 @@ Exit codes: `live` 0 when every event got its stance; 2 for a bad persona, state
prints one `{"error"}` object on stdout, changes nothing and the run goes on). `verify` 0 when every line replays, 1 at a line
that differs, 2 for a bad flag or an unreadable file.

### 5.8 Monitor: watch an individual's inner state

`probbit monitor STRAND` draws an individual's inner state as live horizontal bars, in the terminal or as a page in the browser.
It replays the strand with the rules of `live verify` (the two share one replay), recomputing every stance document from the
strand alone: it needs no other log, works for any strand on any machine, and says "replay verified" while every line checks,
or names the line that differs.

```sh
probbit monitor pip.strand --follow # bars in the terminal, redrawn as the strand grows
probbit monitor pip.strand --open # the same board as a page at http://127.0.0.1:PORT/, in the browser
probbit monitor --demo --open # the tutor's week, paced, for someone without a strand yet
```

**What it shows.** The latest event. A header: persona and version, seed, the individual's digest, the event number, the hours
since the event before, the replay badge. The stance: one row per trait, its levels as segments sized by their odds, the level
taken in colour and the phrase it says. The moods, with a sparkline of the last 50 events. The senses: the event's inputs as the
turn used them (flags lit, numbers as bars, levels by name, the clock) and the history features against their caps. The habits
in force, the ones that bound in colour, and the violations counter (0 by construction, section 2.5). The learned deltas per
level as centred bars within ±total_cap (with a learning block, section 2.8). The drives, when a document carries `pursue` or
`drives`: documents without them draw no row, so a strand of a later engine lights them up. The stance line, and why.

**Terminal.** `--once` prints one frame and exits (the default without `--follow`). `--follow` polls the file every 100 ms and
draws appended lines within a second (a line counts once its newline is written; a truncated, removed or rotated strand is
replayed from the start, with a warning); `--fps N` caps the redraws. While a long strand replays from its header (10,000
events: about 3.5 s on an Apple M4), the board is drawn every 250 ms with a note, at a terminal and on the page. `--plain`
draws plain ASCII; colour follows the rules of the other commands (`NO_COLOR`, `PROBBIT_THEME=plain`, `TERM=dumb`).

**Browser.** `--serve` follows the strand and binds 127.0.0.1 (std `TcpListener`; port 0, a free one, unless `--port N`) and no
other address: there is no host flag. The URL is the line it prints on stdout; `--open` serves the same and starts the default
browser (`BROWSER` if set, else `open`, `cmd /c start` or `xdg-open`), best effort. It answers GET requests addressed to
`127.0.0.1:PORT` or `localhost:PORT`, and refuses others (403), so a page of another site whose name resolves to 127.0.0.1
cannot read the documents:

| route | answer |
|---|---|
| `/` | the page: one file embedded in the binary (about 21 KB, styles and script inline; it fetches no fonts, styles or scripts), with a Content-Security-Policy that lets it connect to its own server and nowhere else |
| `/events` | server-sent events: `meta` (the layout: the strand, the engine, the persona, its traits, moods, inputs and history features in the persona's order), the latest `frame`, then a frame per event: `{n, doc, given, learned, spark, diverges, note}`, that is the stance document, the inputs as the strand logs them, the learned deltas, the moods' recent positions, the line that differs and a warning; a heartbeat comment after 15 quiet seconds; events that land within one poll (100 ms), or while a page falls behind, come as the latest frame |
| `/doc/N` | event N's stance document, canonical JSON and a newline, as `probbit live` printed it (its sha256 is the `stance` digest of the strand's line N + 1); the latest 10,000 are kept |

The page draws the terminal's board in a dark theme, the bars moving as the odds do (`prefers-reduced-motion` respected), from
360 px wide up. No file is changed, and nothing leaves the machine.

**Demo.** `probbit monitor --demo` replays the week of `probbit live examples/persona/tutor.yaml --seed 2 --demo week` (section
5.7; the week is written to a temporary file, read back and removed), paced 1 s per hour and each night in 2 s, under a minute:
at a terminal, or with `--serve`, over and over. `--demo --once`, or a pipe, prints its last frame.

Exit codes: 0 when every line replays, 1 at a line that differs (the frame names it and shows the event before it), 2 for a bad
flag, a port that cannot be had, or a file that cannot be read or is not a strand.

## 6. What a persona can NOT do

- It does not write, read or check text. Text-level rules (banned phrases, exact formats, facts) stay in the prompt or in
Expand Down Expand Up @@ -725,9 +775,10 @@ store the new state. On `refused` or `fallback`, use the line as given (habits o
| `probbit live PERSONA [--seed N \| --state FILE] [--strand FILE] [--events FILE [--watch]] [--clock real\|fixed]` | a resident individual: JSONL events in, one stance per event out, `elapsed_hours` stamped by the clock, the life logged to a strand (section 5.7); `--state` is rewritten after every event |
| `probbit live PERSONA --demo week [--seed N] [--strand FILE] [--plain]` | one individual's scripted week on the fixed clock: learning to its cap, a quiet night, habits that hold (section 5.7) |
| `probbit live verify STRAND` | replay a strand from its header alone: ok, or the earliest line that differs (exit 1) |
| `probbit monitor STRAND [--follow] [--once] [--plain] [--fps N] [--serve] [--open] [--port N]`, `probbit monitor --demo [...]` | watch an individual's inner state: the strand replayed as live bars in the terminal, or as a page on 127.0.0.1 (section 5.8) |

A script is a JSON list of per-turn input objects (or `{"turns": [...]}`; a turn may be `{"inputs": {...}, ...}`). Exit codes
(`live`'s are in section 5.7):
(`live`'s are in section 5.7, `monitor`'s in section 5.8):
0 done (every turn status is an answer), 1 `lint` found an unresolved contradiction, `fuzz` a counterexample or `prove` an
unknown rule, 2 a bad persona, state, input, script or rule
(ONE `{"error": {"code": "persona", "path", "message"}}` object on stdout) or a bad flag (stderr). The engine's resource controls
Expand Down
Binary file added docs/probbit-monitor.gif
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file added docs/probbit-monitor.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Loading