Skip to content

feat: delete the curses TUI and the console layer that only it could open (#541) - #554

Merged
eaitbrahim merged 1 commit into
mainfrom
feat-541-delete-tui
Aug 25, 2026
Merged

feat: delete the curses TUI and the console layer that only it could open (#541)#554
eaitbrahim merged 1 commit into
mainfrom
feat-541-delete-tui

Conversation

@eaitbrahim

Copy link
Copy Markdown
Contributor

Closes #541. Last issue in the Web UI milestone.

keel tui is gone, and with it the eight console modules reachable from nowhere else.
keel/commands/: 24,709 → 13,606 lines. Whole change: +297 / −23,448.

The issue estimated 9,432 lines. The real number is the finding.

The issue reasoned: "tui.py imports from keel.commands.{activity,admission,status} — it is a
front-end over the shared report builders, not their owner."
True about the web UI, and half
the picture about the module: nine modules imported from tui.py (ScreenLine, _blank,
_message_style, CTRL_C_DISCLOSURE, _market_session_style, _human_dt), and the whole console
layer sat on them.

Then the decisive fact: there is no keel console command. The console was reachable only from
inside the dashboard. Deleting tui.py alone would have left 6,009 lines of source and 8,276 of
tests that nothing could open — still type-checked, still pinned, still maintained.

I checked every runtime import of the console layer from outside itself. There was exactly one:
keel/mcp/tools.py reading the research corpora. Those four things are now keel/corpus.py, moved
rather than reimplemented, so the MCP server reads exactly what the console read. Everything else
that looked like a dependency — rules.py, withdrawals.py, update.py, brokers.py, cli.py
was prose in a comment.

Gate 2: enumerated, not assumed

keel capabilities listed eleven actions. Seven [cli], one [tui], three [console] — and each
of the four non-CLI rows named the CLI command it mirrored. Every one of those commands is still
here (keel autonomy on, keel resume/resume-entries, keel withdrawals attest --enabled,
keel rules promote --force). No capability became unreachable.

The registry is seven rows now, all [cli], all behind the typed terminal gate — a cleaner
statement than the mix it replaced: every capability increase in this build is a CLI command run by
a person at a terminal, and the browser can perform none of them.

One absence looks like a regression and is not. keel rules promote --force skips the whole
gauntlet and is not in the registry. It never was: this is an inventory of gate call sites, and
that flag has none — rules.py records why ("the CLI's --force is a flag the operator already
typed at a terminal"). The console's retry flow did run a typed gate before calling with
force=True, which is why a force-promote row existed at all; the row described the console's
ceremony, not the CLI's flag, and it went with the console. Flagging it because the registry now
lists no bypass, and that is a fact about the registry's scope rather than about the bypass.

Dead code that had already become wrong

update.py still carried build_relaunch_argv/relaunch_tui — an execv whose only caller was
the console's Account-menu update view. With no argv to carry they rebuilt [keel, "tui"], so a
relaunch would have exec'd into Error: No such command 'tui'after installing the new
build. Deleted, and keel update now names keel serve as the thing to restart.

Verification

ruff, mypy and the full suite are green (4262 passed, 3 skipped) — the suite is smaller because
11,892 lines of tests for deleted code went with it, and nothing is skipped that used to run.

Smoked against a snapshot of the live 155 MB database: keel tui"No such command";
keel status unchanged; keel capabilities → seven; keel serve opens and all seven views render
with no console errors; and keel.corpus reads the research corpus the MCP server depends on
(3 documents, 312 lines from the first).

What moved rather than died

  • The runbook's TUI-console section is now the browser's, and tests/test_runbook_console.py pins
    that one — same job, new subject, including the two facts most expensive to get wrong: what the
    browser cannot do, and where a headless operator goes (ssh -L 8765:127.0.0.1:8765).
  • test_console_thinness.py globbed *console*.py; it is keel/web/*.py alone now, and asserts
    the console stems are absent so a module cannot reappear under a familiar filename outside
    the rules.
  • test_brokers.py lost nine Venues-browser rendering tests; the service they rode on is untouched
    and still covered, and keel brokers list is the surface that remains.
  • windows-curses needed no removal — it was never declared (the desktop PRD said so), and no
    import curses remains anywhere.

🤖 Generated with Claude Code

https://claude.ai/code/session_01T6yA5khYnJ2qzheArRToQ2

…open (#541)

The last issue in the Web UI milestone. `keel tui` is gone, and with it the eight
console modules that were reachable from nowhere else. `keel/commands/` goes from
24,709 lines to 13,606; the whole change is +297 / -23,448.

── THE ISSUE SAID 9,432 LINES, AND THE REAL NUMBER IS THE FINDING ─────────────

"`tui.py` imports from `keel.commands.{activity,admission,status}` -- it is a
front-end OVER the shared report builders, not their owner." True about the web
UI, and half the picture about the module: nine modules imported FROM `tui.py`
(`ScreenLine`, `_blank`, `_message_style`, `CTRL_C_DISCLOSURE`,
`_market_session_style`, `_human_dt`), and the whole console layer sat on them.

Then the decisive fact: there is no `keel console` command. The console was
reachable only from inside the dashboard. Deleting `tui.py` alone would have left
6,009 lines of source and 8,276 of tests that nothing could open -- still
type-checked, still pinned, still maintained.

Every runtime import of the console layer from outside itself was checked. There
was exactly one: `keel/mcp/tools.py` reading the research corpora. Those four
things are now `keel/corpus.py`, moved rather than reimplemented, so the MCP
server reads exactly what the console read. Everything else that looked like a
dependency was prose in a comment.

── GATE 2: ENUMERATED, NOT ASSUMED ────────────────────────────────────────────

`keel capabilities` listed eleven actions. Seven were `[cli]`. One was `[tui]`
and four were `[console]`; each named the CLI command it mirrored, and every one
of those commands is still here. **No capability became unreachable.**

The registry is seven rows now, all `[cli]`, all behind the typed terminal gate,
and that is a cleaner statement than the mix it replaced: every capability
increase in this build is a CLI command run by a person at a terminal, and the
browser can perform none of them -- a property of the server, which implements no
verb that would reach one.

One absence is worth stating because it looks like a regression and is not.
`keel rules promote --force` skips the whole gauntlet and is NOT in the registry.
It never was: this is an inventory of GATE CALL SITES, and that flag has none --
`rules.py` records why ("a flag the operator already typed at a terminal"). The
console's retry flow DID gate it, which is why a force-promote row existed; the
row described the console's ceremony, not the CLI's flag.

── DEAD CODE THAT HAD ALREADY BECOME WRONG ────────────────────────────────────

`update.py` still carried `build_relaunch_argv`/`relaunch_tui` -- an `execv` for
one caller, the console's update view. With no argv to carry they rebuilt
`[keel, "tui"]`, so a relaunch would have exec'd into `No such command 'tui'`,
AFTER installing the new build. Deleted, and `keel update` now names `keel serve`
as the thing to restart.

── WHAT MOVED RATHER THAN DIED ────────────────────────────────────────────────

The runbook's TUI-console section is now the browser's, and
`tests/test_runbook_console.py` pins that one instead -- same job, new subject,
including the two facts most expensive to get wrong: what the browser cannot do,
and where a headless operator goes (`ssh -L 8765:127.0.0.1:8765`).

`test_console_thinness.py` globbed `*console*.py`; it is `keel/web/*.py` alone
now, and asserts the console stems are ABSENT so a module cannot reappear under a
familiar filename outside the rules.

`windows-curses` needed no removal: it was never declared. The desktop PRD said
so, and no `import curses` remains anywhere.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01T6yA5khYnJ2qzheArRToQ2
@eaitbrahim
eaitbrahim merged commit 28c934e into main Aug 25, 2026
4 checks passed
@eaitbrahim
eaitbrahim deleted the feat-541-delete-tui branch August 25, 2026 23:30
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

Delete the curses TUI — after parity, never before

1 participant