scema-tui 1.0.0

Scematica Omni TUI — the agent loop as a terminal console: observe a world, rank branches, seal and verify decision records.
# scema-tui


The Scematica Omni console: the agent loop as a full-screen terminal application. Perceive
a world, tick the signals that ground a goal, watch branches compete, read back the records
that were sealed and whether their commitments still hold.

```console
$ cargo install scema-tui
$ scema-tui                    # the current directory
$ scema-tui /path/to/project
$ scema-tui --once             # one pass as plain text, pipeable
$ scema-tui --snapshot 120x40  # one frame as text
$ scema-tui --palette          # what colour this terminal can actually carry
```

If you have `scema-cli`, `scema tui` finds this binary next to itself and hands over.

## Five tabs


| | Answers |
|---|---|
| **WORLD** | what is out there, and what could not be seen? |
| **SIMULATE** | which branch wins, and does anything measured support it? |
| **RECORDS** | what was decided, and does the record still verify? |
| **MEMORY** | what has been retained, and how well did it project? |
| **POLICY** | under whose preferences, and with which specialists? |

```
  1·WORLD │ 2·SIMULATE │ 3·RECORDS │ 4·MEMORY │ 5·POLICY │        SCEMA OMNI scema-omni/0.1.0
  which branch wins, and does anything measured support it?                         ○ idle  .
────────────────────────────────────────────────────────────────────────────────────────────
┌ SIMULATION MATRIX  ·  NOT WRITTEN (would seal as c5ac7c5e) ───────────────────────────────┐
│ #   BRANCH                                GAIN   RISK   COST UNCERT REVERS  UTILITY  MEAS │
│▸  1 take: 11 marker(s) in `scema-tools`   0.22   0.40   0.10   0.00   0.70    0.125 ▰▰▰▰▰ │
│   2 give scema-cli tests                     —   0.40   0.10   0.00   0.70    0.093 ▰▰▰▰▱ │
│                                                                                           │
│ measured across the whole matrix: 35/35  (100%)   `—` = not measured; contributed nothing.│
└───────────────────────────────────────────────────────────────────────────────────────────┘
```

## Black and violet, with soft blue for exactly one thing


Every other terminal surface in this repository has its own identity — the sniper dashboard
is black and red, `mesh-dashboard` is indigo over slate, `sdk-dashboard` is the bond
pipeline's green. Omni is black and violet, and that is not decoration: an operator with
three of these open must be able to tell at a glance which one is making a claim about their
money and which one about a decision record.

Violet specifically, because omni's whole subject is the boundary between **measured** and
**unmeasured**, and that wants a palette where the interesting distinction is luminance
first rather than hue first. A measured value glows; an unmeasured one recedes to a note in
the same family. A red/green palette would put the emphasis on good-versus-bad, which is the
wrong axis — a measured `0.00` risk and an unmeasured risk are not good and bad, they are
known and unknown.

**Azure appears in two places only**: the branch that was chosen, and a commitment that
verifies. Both are *claims the agent made*. An opportunity signal and a live provenance are
*observations* and wear their own colours, because an accent that appears on every third row
is not an accent, it is a second body colour.

## Two rules, both mechanised


**A renderer names a role, never a colour.** `theme.rs` is the only file with a hex value in
it; `view.rs` is the only file that maps a state to a role; `render.rs` places rectangles.
Same split as `alchem_link.theme` and `lib/mesh/view.ts::toneFor` — a rule that encodes a
claim about trust gets exactly one implementation.

**Colour is decoration, never the message.** `NO_COLOR`, a pipe, `--no-color` and a
16-colour terminal all produce the same *text*: `—` for unmeasured, `▸` for chosen,
`LIVE`/`STALE`/`ABSENT` for provenance, `RISK`/`OPP `/`EST?` for signals, `EXCLUDED` for a
forbidden branch. A test walks every role in `Depth::Mono` and fails if one carries neither a
modifier nor a word — a role whose entire identity is a hue disappears on a monochrome
terminal, and that is a bug in the role.

`--palette` prints what the terminal negotiated, so an operator on an unfamiliar one can
confirm that "measured" and "unmeasured" are actually distinguishable there *before* trusting
a screen full of them.

## The coverage meter is a count, not a bar


`▰▰▰▱▱`. One cell per term. A proportional bar renders `2/5` and `4/10` identically, and the
denominator is the number that matters — a utility computed on two terms out of five and one
computed on five out of five are different claims. Above twelve terms it falls back to the
`30/90` label rather than to a proportional bar, for the same reason.

An empty coverage draws `∅`, never an empty meter. An empty container reads as "measured,
and it is zero"; the true statement is "there was nothing here".

## `enter` simulates. `D` decides.


Two keys, and a confirmation on the second.

`simulate` and `decide` compute *exactly* the same thing and differ only in whether they
leave a trace. The only protection against a counterfactual later reading as a decision
somebody made is that they are not the same keystroke — so the obvious button is the one
that writes nothing, and sealing takes a capital letter and a yes.

## Grounding is ticked, never inferred


The signal list is a multi-select, and what it selects is `Goal::grounded_in`. Nothing reads
the goal text looking for a matching signal.

An earlier version of the CLI inferred grounding by keyword overlap and, on its first real
run, grounded *"add tests to the scema-cli crate"* in a marker backlog in a **different**
crate — because `scema` is a substring of every unit name in this workspace. The branch then
inherited a *measured* expected gain from evidence that had nothing to do with it, which is
exactly the laundering the simulator refuses to do on its own. A test pins that a goal naming
a signal id verbatim still does not ground it.

## `--snapshot`, and why a TUI needs one


```console
$ scema-tui --snapshot 128x38
```

Draws one frame into an off-screen buffer and prints it as text. It exists because a TUI is
otherwise untestable — its output is a terminal — so layout bugs are found by a human
noticing a column is wrong, and ratatui's layout arithmetic underflows on small rectangles.
The production failure mode is the console dying on somebody's 80-column terminal with a
backtrace instead of a screen.

The crate's own tests draw every tab at four sizes and assert on the *symbols*, not the
styles: everything here has to survive `NO_COLOR` anyway, so the text is what must be right,
and a snapshot carrying escape sequences would churn on every palette tweak until nobody read
it.

## What it does not do


**Act.** The whole workspace ends at a decision and a record. A console that quietly gained a
write path would invalidate the claim every other crate here makes about being safe to point
at a live system.

**Talk to a daemon.** It holds no token and opens no socket; it drives the loop in-process
against a local path. `scema-omnid` exists for the case where something remote needs to drive
the loop, and folding that in would mean putting the whole pairing story on screen for no
gain.

## Why a separate crate


The same split `mesh-dashboard` / `scematica-mesh` makes in the bot workspace, and for the
same reason: `scema-agent` is a library other people embed, and forcing ratatui and crossterm
on a consumer that only wants the loop would be the mistake `sdk-dashboard` exists to avoid.
The rendering lives here; the crates next door own the thinking.