Ctrl K
ComunidadGuías…

docs/tui.md

Rama main · réplica de lectura del repositorio original.

Archivo original ↗Preguntar a KiBot
<!-- authority:non-specification -->

# The Exomem terminal UI (`exomem tui`)

A persistent, keyboard-first surface over the same product commands the CLI,
MCP, and REST doors expose. One long-lived process (no per-command Python
startup), guided access to capture, recall, review, adoption, packs, and
diagnostics — and an honest face for the engine's own signals: warming lanes,
degraded retrieval, structured errors with remediations.

The TUI is a thin client. Every knowledge read and write goes through the
unified command registry via the same invocation seam as the CLI
(`src/exomem/product_invoke.py`): identical coercion, vault resolution, owner
principal, writer lease, and governance egress. It adds no second storage or
retrieval path and never writes vault files directly.

## Install

The UI stack is an optional extra so lean and server installs never carry it:

    uv sync --extra tui              # source checkout
    pip install 'exomem[tui]'        # package install

Without the extra, `exomem tui` prints a one-line install hint and exits
non-zero. Snapshot/interaction tests additionally need the dev group:

    uv sync --extra tui --group tui-dev

Supported platforms: Linux, WSL, macOS, and Windows Terminal (Textual renders
on all four). An interactive terminal is required — a piped invocation exits
with status 2.

## Launch

    exomem tui                       # uses $EXOMEM_VAULT_PATH
    exomem tui --vault /path/to/vault

With no resolvable vault, first run opens.

## First run is a ledger

Setup is a short conversation on one screen. Each answer collapses into a line
you can read back — `✓ vault  created ~/Exomem — 28 files, plain markdown` —
and the active question sits below the lines already recorded. Four steps:
vault, packs, a first capture, and asking for what you just captured. Under two
minutes, and the last step is the product demo built from your own words.

Three promises the screen keeps:

- **Nothing is written until a line says so.** Creating a vault shows exactly
  what will be created — the folder, its governed layer, the file count — and
  writes only after you choose it.
- **`esc` rewinds one line.** Lines that recorded a write are pinned: you
  cannot un-create a folder, and the screen says so instead of pretending.
- **Everything but the vault is skippable** (`s`), and skipping leaves its own
  line. "Skip for now" on the first question lands on a working, vault-less
  Home where every path stays reachable.

Pointing "Create a fresh vault" at a folder that already holds a Knowledge Base
connects to it rather than failing. Choosing "Scan a folder first" inserts a
read-only report before any decision.

First run never reopens once a vault is connected.

## Screens

| Key (from Home) | Screen | What it is |
|---|---|---|
| 1 | Continue | local continuation checkpoints from the client hooks, rendered as copyable resume packets |
| 2 | Ask | measured recall with evidence — results cite source pages; deep-context packet copyable; degradation announced at the results |
| 3 | Capture | thought (immutable source) or insight (governed note); title derived from the first line; no folder decisions |
| 4 | Review | the Epistemic Inbox queue with the exact supported triage: dismiss, snooze (dated), reopen; deeper flows point at the Review Studio |
| 5 | Adopt | read-only scan of any folder (works pre-init); write modes are separate confirmed steps; originals never rewritten |
| 6 | Packs | multi-select over the built-in catalog, persisted like `setup` does; packs guide interpretation, never folder structure |
| 7 | Status | doctor preflight, resources, warm state, hooks, install provenance — each warning with its remediation |
| 8 | Settings | compute mode (quiet/normal/performance, persisted), theme toggle, vault identity |

Ask presents *measurements*, not generated prose: Exomem is a pure substrate —
the server measures, your model reasons. The copyable context packet exists
precisely to hand that evidence to a reasoning model.

## How to read the screen

Everything that happened reads as a **receipt**: a glyph, a word, then what
actually happened — `● ready`, `▲ warming`, `✓ saved`, `✗ not saved`. Status is
always a glyph *and* a word, so nothing depends on color; `NO_COLOR` and
ASCII-only terminals lose nothing but hue.

Amber marks live state only — the current step, the `▸ retrieved` header, live
wikilinks in a preview, the cursor, focus, and the selected row's `▌` bar. It
is never decoration and never an error.

Anything that fails, comes back empty, or runs degraded renders the same way:
what happened, a dim line stating what was and was not changed, then a list of
next actions you can select. No screen dead-ends, and no traceback reaches the
terminal.

## Key map

Global: `ctrl+p` command palette · `?` help overlay · `u` refresh this screen ·
`esc` back (guarded — non-empty input is never silently discarded) · `ctrl+q`
quit (confirmed). Home: `1`–`8` open screens · `enter` opens the highlighted
row. Lists: arrows and `j/k` · `enter` opens · the selected row carries `▌`.
Ask: `enter` submit · `u` re-run · `esc` steps back one layer (results → the
query, which is kept → back) · `e` evidence preview · `y` copy context packet ·
`w` save an insight. Capture: `ctrl+s` save · `tab` cycle thought/insight ·
`e` edit the derived title · `esc` back with your typing kept. Review: `enter`
context · `d` dismiss · `s` snooze · `o` reopen · `v` cycle state view. Adopt:
`m` save manifest · `c` copy as sources (both confirmed). First run: `esc`
rewind one line · `s` skip an optional step.

## Governed write-back

Saving an insight (`w` on Ask, or Capture's insight kind) writes through
`create_note`. Two governed rules are handled for you, visibly:

- every compiled note needs at least one semantic unit — the editor pre-fills
  an editable `## Observations` line, and if a draft has none, one is appended
  restating the title;
- a new page without a qualifying typed relation needs an explicit relation
  disposition — the TUI runs the validate→commit draft flow and records your
  confirmation as a `reviewed_none` disposition with an audit reason. Connect
  the note properly later via `exomem connect` or the Review Studio.

## Local vs Hosted

This TUI operates the local engine in-process. A Hosted/remote connection is
not part of this surface today; `exomem doctor --profile remote` and the
connector docs cover remote posture, and the Status screen shows local install
provenance and the managed-service version when one is configured.

## Limitations

- Long-lived process, no file watcher: out-of-band edits (e.g. Obsidian)
  refresh lexical search via mtime checks, but the semantic sidecar drifts
  until a server or `exomem index` pass. The Ask screen's refresh action
  (`u`) clears in-process caches.
- Binary media import (`/upload`, `media.process`) is not in the TUI yet —
  capture text, or use adoption for markdown folders.
- Review depth: proposal-first flows (supersede, compile, accept relations)
  deliberately live in the browser Review Studio; the TUI links to it (the
  Studio requires the http transport to be serving).
- Cooperative cancellation: a cancelled ask stops affecting the UI
  immediately; the underlying computation may finish in the background.

## Troubleshooting

- `exomem tui` exits 2 with "needs an interactive terminal": stdin/stdout is
  piped or redirected — run it in a real terminal.
- Install hint on launch: the `tui` extra is missing — `uv sync --extra tui`.
- "partial results — still warming": the background warm hasn't finished;
  results are lexical-only until it does. `exomem warm` pre-loads models
  explicitly.
- Ask shows skipped lanes on a lean install: expected — without the
  `embeddings` extra retrieval runs keyword/BM25 only, and the TUI disables
  the model lanes at startup so this is not reported as degradation.
- Writes reporting `MUTATION_BUSY`/`WRITER_LEASE_REQUIRED`: another process
  (usually the running server) holds the mutation boundary — retry after it
  finishes; reads stay available.

## Running the TUI tests

    uv run --frozen --extra tui --group tui-dev python -m pytest tests/tui tests/test_tui_entry.py -q

Snapshot goldens live in `tests/tui/__snapshots__/` and render exclusively
from the deterministic fake backend with synthetic paths (the committed SVGs
are scanned by the public-artifact privacy gate — never regenerate them
against a real vault). Intentional regeneration:

    uv run --frozen --extra tui --group tui-dev python -m pytest tests/tui/test_snapshots.py --snapshot-update

To review layout as a character grid without a terminal (development aid; it
drives the same deterministic fake):

    uv run --extra tui python scripts/tui_frames.py home first-run ask

The lean matrix (no `tui` extra) skips `tests/tui` entirely; `tests/test_tui_entry.py`
and `tests/test_product_invoke.py` run everywhere.