Skip to content

Remove Textual TUI, keep launcher-only surface (v0.9.0) #2

Description

@foundev

Context

This repository was extracted from the BrokkAi/brokk monorepo via git filter-repo --subdirectory-filter brokk-code to host the launcher / CLI surface of the former "brokk-code" Python project. The interactive Textual TUI is deprecated; brokk-cli continues to ship as the launcher for:

  • brokk acp — headless ACP server over stdio (native Java ACP via mcp_launcher.run_acp_server)
  • brokk bifrost --workspace . — Rust MCP server bootstrap
  • brokk login / brokk logout / brokk github login|logout|status
  • brokk install <editor> — Neovim / Zed / IntelliJ / Codex integration installers
  • brokk issue create|diagnose|solve, brokk pr create|review, brokk commit, brokk exec
  • brokk mcp, brokk mcp-core, brokk version
  • Java executor JAR download/lifecycle and bifrost binary management

This issue removes every TUI-only file/dependency in a single PR. Total reduction: ~7500 LOC + the textual runtime dependency.

Bumps the version to 0.9.0 (breaking: TUI surface removed) and tags v0.9.0 to trigger the first PyPI publish from this repo.

Acceptance criteria

  • All TUI source files and directories listed below are deleted.
  • All TUI-only test files listed below are deleted.
  • pyproject.toml no longer declares textual as a runtime dependency.
  • brokk_code/__main__.py no longer imports BrokkApp or dispatches to the Textual app for any subcommand (or no subcommand).
  • brokk_code/__init__.py bumped to __version__ = \"0.9.0\".
  • README.md, AGENTS.md, CLAUDE.md rewritten to describe the launcher-only role (no Textual, no widgets/modals/styles, no interactive chat).
  • uv sync --group dev && uv run ruff check && uv run ruff format --check && uv run pytest -q -n auto passes locally.
  • CI passes on ubuntu-latest, macos-latest, windows-latest (Python 3.11).
  • PR squash-merged into master.
  • PyPI trusted publisher pre-configured for BrokkAi/brokk-cli workflow pypi.yml env pypi (see https://pypi.org/manage/project/brokk/settings/publishing/).
  • Tag v0.9.0 pushed; pypi.yml publish succeeds; pip install brokk==0.9.0 works in a fresh venv.

Step 1 — Branch

git checkout master && git pull --ff-only
git checkout -b feat/remove-tui

Step 2 — Delete TUI source files and directories

git rm brokk_code/app.py                # 184K, ~4600 LOC, sole Textual App
git rm brokk_code/settings_modal.py     #  40K, Textual ModalScreen
git rm brokk_code/prompt_history.py     # 4K,  history persistence consumed only by BrokkApp
git rm brokk_code/session_persistence.py # 8K, session zip/resume, BrokkApp-only
git rm brokk_code/welcome.py            # 4K,  TUI splash text + braille icon
git rm -r brokk_code/widgets/           # 15 files, 436K — chat panel, token bar, status line, task list, etc.
git rm -r brokk_code/modals/            # 4 files, 28K — Textual ModalScreen subclasses
git rm -r brokk_code/styles/            # 2 .tcss files, 24K — Textual stylesheet

Confirm with grep -rln '^from textual\\|^import textual' brokk_code/ that no import of textual remains in brokk_code/. Today every match is inside the files above.

Step 3 — Delete TUI-only tests (29 files)

git rm tests/test_app_cost.py \\
       tests/test_autocommit_toggle.py \\
       tests/test_brokkapp_shutdown.py \\
       tests/test_chat_panel.py \\
       tests/test_chat_panel_layout.py \\
       tests/test_footer_removed.py \\
       tests/test_mode_toggle.py \\
       tests/test_model_command_menu.py \\
       tests/test_model_selector.py \\
       tests/test_reasoning_selector.py \\
       tests/test_review_panel.py \\
       tests/test_sessions_command.py \\
       tests/test_sessions_startup.py \\
       tests/test_settings_modal.py \\
       tests/test_startup_queue.py \\
       tests/test_status_line.py \\
       tests/test_status_line_rendering.py \\
       tests/test_tasklist_commands.py \\
       tests/test_tasklist_execution.py \\
       tests/test_tasklist_navigation.py \\
       tests/test_tasklist_polling.py \\
       tests/test_token_bar.py \\
       tests/test_tui_context_actions.py \\
       tests/test_tui_context_visibility.py \\
       tests/test_tui_prompt_history.py \\
       tests/test_tui_resubmit.py \\
       tests/test_tui_session_autoname.py \\
       tests/test_tui_session_resume.py \\
       tests/test_welcome.py

KEEP (launcher / shared):
`test_api_key_relaunch.py`, `test_avante_config.py`, `test_bifrost_launcher.py`, `test_cli_modes.py`, `test_commit_command.py`, `test_cwd_isolation.py`, `test_dependency_name_derivation.py`, `test_executor_*.py`, `test_github_auth.py`, `test_intellij_config.py`, `test_login_logout_commands.py`, `test_mcp_config.py`, `test_mcp_integration.py`, `test_mcp_launcher.py`, `test_nvim_config.py`, `test_nvim_init_patch.py`, `test_openai_auth.py`, `test_pr_command.py`, `test_rust_acp_install.py`, `test_settings.py`, `test_worktree.py`, `test_zed_config.py`.

Step 4 — Edit `pyproject.toml`

Remove the textual>=0.47.0 line from the dependencies array. Keep httpx>=0.25.0 (used by executor.py) and agent-client-protocol>=0.9.0 (used by mcp_launcher.py).

Current state:
```toml
dependencies = [
"textual>=0.47.0",
"httpx>=0.25.0",
"agent-client-protocol>=0.9.0",
]
```

Target state:
```toml
dependencies = [
"httpx>=0.25.0",
"agent-client-protocol>=0.9.0",
]
```

Then uv lock to refresh uv.lock.

Step 5 — Strip TUI dispatch from `brokk_code/main.py`

Today this file mixes CLI dispatch with the conditional fall-through to the Textual app. Concrete edits:

a) Remove TUI subparsers (lines 887-895)
```python

DELETE:

resume_parser = subparsers.add_parser("resume", help="Resume a specific session")

... (resume_parser arguments through end of resume_parser block)

sessions_parser = subparsers.add_parser("sessions", help="List and switch between sessions")

... (sessions_parser arguments)

```

b) Remove the --resume top-level flag (lines 877-882, the one with dest=\"resume_session\").

c) In _main_dispatch (starts line 1983), remove the BrokkApp lazy-import and start block (~lines 2487-2645). The block currently looks like:
```python
try:
from brokk_code.app import BrokkApp
except ImportError:
print("Error: Could not import BrokkApp. Is app.py missing?")
return 1

resume_session = getattr(args, "resume_session", False)

if args.command == "resume":
...
resume_session = False
elif args.command == "sessions":
...
resume_session = False

... configuration / option parsing ...

app = BrokkApp(
...
resume_session=resume_session,
)
app.run()
```

Replace the entire block with a clean exit when no subcommand was given:
```python
parser.print_help()
return 2
```

(Or parser.error(\"a subcommand is required\") if you prefer the argparse-style error.)

d) Sanity grep: after edits, grep -n 'BrokkApp\\|from brokk_code.app' brokk_code/__main__.py must return zero matches.

Step 6 — Version bump

`brokk_code/init.py`:
```python
version = "0.9.0"
```

Hatch reads this via the [tool.hatch.version] block in pyproject.toml; no other version edit is needed.

Step 7 — Rewrite docs

`README.md` — currently describes the TUI. Rewrite the overview to describe brokk-cli as the launcher for the Brokk Java executor + ACP + bifrost MCP. Keep the install/quickstart sections. Drop screenshots and any reference to chat/context/task panels, sessions, model picker, etc. Add a line: "The interactive Textual TUI was removed in v0.9.0; for the previous TUI use pip install brokk==0.8.10."

`AGENTS.md` / `CLAUDE.md` — currently say "Python (Textual) terminal UI client". Rewrite to: "Python CLI launcher for the Brokk Java executor and related sidecars (ACP, bifrost MCP, editor integrations)." Remove the app.py / widgets/ / styles/ entries from the project structure section. Drop the "Key Dependencies: textual" line. Keep references to executor.py, mcp_launcher.py, mcp_config.py. Keep ACP, install, login/logout sections.

Step 8 — Local validation

```
uv sync --group dev
uv run ruff check
uv run ruff format --check
uv run pytest -q -n auto --no-header
```

Expected: green. Some test_mcp_config.py cases hit https://raw.githubusercontent.com/BrokkAi/brokk/master/claude-plugin/... over the network — this is intentional (see #1).

Step 9 — PR + merge

```
git push -u origin feat/remove-tui
gh pr create --base master --head feat/remove-tui \
--title "feat: remove Textual TUI, keep launcher-only surface" \
--body "Closes #2. See issue for full rationale and file list."
```

Wait for the 3 OS matrix to go green (master is protected with required status checks), then squash-merge into master.

Step 10 — Release v0.9.0

Prerequisite (manual, one-time): on https://pypi.org/manage/project/brokk/settings/publishing/, add a Trusted Publisher with:

  • Owner: `BrokkAi`
  • Repository: `brokk-cli`
  • Workflow: `pypi.yml`
  • Environment: `pypi`

Keep the existing `BrokkAi/brokk` publisher in place until the first publish from this repo succeeds.

Then:
```
git checkout master && git pull --ff-only
git tag -a v0.9.0 -m "Remove Textual TUI; launcher-only release"
git push origin v0.9.0
```

Watch `pypi.yml` in the Actions tab. On success, smoke-test from a clean venv:
```
python -m venv /tmp/brokk-smoke && /tmp/brokk-smoke/bin/pip install brokk==0.9.0
/tmp/brokk-smoke/bin/brokk version # prints 0.9.0
/tmp/brokk-smoke/bin/brokk install --help
/tmp/brokk-smoke/bin/brokk acp --help
```

Once green, remove the old `BrokkAi/brokk` trusted publisher from the PyPI dashboard.

After this issue closes

Open the monorepo cleanup issue in BrokkAi/brokk ("Remove brokk-code/, extracted to BrokkAi/brokk-cli") which deletes the now-orphaned brokk-code/ subdirectory and its two CI workflows. That issue is blocked until v0.9.0 publishes successfully.

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions