Skip to content

feat(tui): replace Textual with a Go/Bubble Tea interface - #941

Merged
0xallam merged 79 commits into
usestrix:mainfrom
kusonooyasumi:feat/go-tui-provider-setup
Aug 4, 2026
Merged

feat(tui): replace Textual with a Go/Bubble Tea interface#941
0xallam merged 79 commits into
usestrix:mainfrom
kusonooyasumi:feat/go-tui-provider-setup

Conversation

@kusonooyasumi

@kusonooyasumi kusonooyasumi commented Jul 30, 2026

Copy link
Copy Markdown
Contributor

Summary

Replaces the Textual interactive interface with a Go/Bubble Tea TUI that runs as a sidecar process, and makes it the only interactive interface — no fallback, no opt-out env var.

The split is: Python owns the scan (orchestration, controller state, protocol projection), Go owns the screen (rendering, input, selection, clipboard, images). They talk over a socketpair with a versioned JSON protocol:

python backend ──socketpair(STRIX_TUI_FD)── strix-tui (Go)
   hello/ready handshake (protocol v3, capability set must match)
   backend → sidecar: snapshot + collection bootstrap/delta frames
   sidecar → backend: commands (start, steer, quit, mount answer, ...)

All TUI code lives under strix/interface/tui/: backend/ (controller, projection, server, live view), sidecar.py + runtime.py (process lifecycle), and the Go module (cmd/strix-tui, internal/app, internal/protocol, internal/render).

Notable behavior beyond the port:

  • Start screen is a prompt, not a config form. A bare prompt launches a scan; with no target it offers to mount the working directory (confirmed by the user, persisted so resume restores it, kept out of targets_info). Modeled on opencode's home screen.
  • Two-tier tool output. Only output-heavy tools collapse (exec_command, write_stdin, view_request, repeat_request, view_sitemap_entry, apply_patch) to a 10-line preview with click-to-expand; everything else always renders in full.
  • Real images, or none. view_image renders actual pixels through the kitty graphics protocol using Unicode placeholders so it survives Bubble Tea's scrolling viewport. Support is decided by a runtime handshake (1×1 a=q query bounded by DA1), the same one viuer and yazi use — no env allowlist, and no low-fidelity block-art fallback in terminals that can't do it. The local viewer renders the same payload as an <img>.
  • Mouse selection and copy inside the TUI (drag to select, copy on release, selection clears with a toast), with image placeholder cells excluded from the copied text.
  • Rendering perf with many images: chat blocks, image placements and the bordered trace pane are memoized per event/width. Post-update frame on a 20-image trace went 33.3ms → 7.7ms (~30 → ~130 FPS); benchmarks are committed.
  • Markdown emphasis follows CommonMark flanking rules, so ls *.py *.go, a * b, and snake_case no longer render as italics.

Packaging: every wheel and the frozen build bundle a platform strix-tui; a source checkout runs the sidecar from source with go run.

Two fixes worth calling out because they are invisible in the diff's shape:

  • Graphics detection used os.Stdin.SetReadDeadline, which returns file type does not support deadline on a tty — a terminal that never answered the query hung the sidecar forever and the backend failed the handshake, so the packaged binary showed only a generic "setup unavailable" panel. The read now goes through a non-blocking fd bounded by the deadline (POSIX) / is only attempted when deadlines work (Windows), and the CLI surfaces the real launch error instead of a generic one.
  • docker-py's exec_start never closes the urllib3 responses behind sandbox terminal streams; their finalizers hit the torn-down socket at interpreter exit and printed ValueError: I/O operation on closed file spam. A narrowly-scoped sys.unraisablehook drops exactly that case and delegates everything else.

Verification

  • uv run pytest (764 passed), ruff check, mypy strix, pre-commit across all files
  • gofmt, go vet ./..., go test ./...; cross-compiled for windows and darwin
  • Built the release binary via scripts/build.sh and confirmed the packaged strix-1.4.1-linux-x86_64 boots into the start screen (this is what caught the detection hang above)

Link to Devin session: https://app.devin.ai/sessions/477b26e9b6e24ca48f260b7a71ed87f1
Requested by: @0xallam

@kusonooyasumi
kusonooyasumi marked this pull request as ready for review July 30, 2026 21:47
@greptile-apps

greptile-apps Bot commented Jul 30, 2026

Copy link
Copy Markdown
Contributor

Greptile Summary

Replaces the Textual interface with a Go/Bubble Tea sidecar architecture.

  • Adds a versioned socket protocol and Python backend for scan orchestration, projection, and command handling.
  • Adds Go-based rendering, setup, input, selection, clipboard, image, and vulnerability-report views.
  • Updates CLI setup, resume behavior, packaging, release builds, and tests to support the bundled sidecar.
  • Removes the legacy Textual implementation and dependency.

Confidence Score: 5/5

The PR appears safe to merge because no eligible unresolved failure remains in this follow-up review.

No blocking failure remains.

Important Files Changed

Filename Overview
strix/interface/tui/backend/server.py Implements the Python side of the sidecar protocol, including handshake, snapshots, collection updates, and command dispatch.
strix/interface/tui/backend/controller.py Coordinates scan setup, lifecycle, resume behavior, and sidecar commands.
strix/interface/tui/runtime.py Manages sidecar discovery, launch, socket inheritance, handshake, shutdown, and launch-error reporting.
strix/interface/tui/internal/app/update.go Implements Bubble Tea event handling and interactive state transitions.
strix/interface/tui/internal/app/view.go Renders the primary Go TUI screens, panes, prompts, status information, and cached trace content.
strix/interface/tui/internal/render/image_detect.go Adds bounded runtime detection of terminal graphics support.
strix/interface/main.py Refactors the CLI entrypoint around extracted argument, environment, scan-setup, and interactive-launch modules.
scripts/tui_sidecar_hook.py Adds a strict Hatchling build hook that compiles and embeds a platform-specific Go sidecar in wheels.
.github/workflows/build-release.yml Builds platform wheels and frozen releases with the Go sidecar and verifies its inclusion.
strix/interface/viewer/frontend/src/components/live/tool-renderers/ViewImageRenderer.tsx Updates the local viewer to render image tool payloads as actual images.

Reviews (3): Last reviewed commit: "build: drop the ruff exemption for a mod..." | Re-trigger Greptile

5hy7xz92nd-oss

This comment was marked as spam.

0xallam added 5 commits August 2, 2026 16:34
Resolves conflicts with the lazy-import startup (usestrix#920) and mounted local targets (usestrix#958): drops the redundant --mount plumbing (local directories are now always mounted), keeps main.py model imports lazy, and routes the TUI /mount command through mountable-dir validation.
The Go/Bubble Tea TUI is now the only interactive interface. Deletes the
Textual app, its renderers and stylesheet, drops the textual dependency,
and removes the PR-added ci.yml workflow. The shared Textual-free
TuiLiveView projection stays for the Go backend and viewer.
Keep only the Go sidecar wheel build, sidecar presence verification, and
wheel artifact upload in the release workflow.
First-principles layout: the Go/Bubble Tea source (cmd/, internal/, go.mod)
moves from top-level tui-go/ into strix/interface/tui/, the sidecar launcher
becomes strix.interface.tui.runtime (was go_tui.py), and tui_backend becomes
strix.interface.tui.backend. Go rendering is split out of the 1.9k-line
render.go into an internal/render package with one file per tool renderer
(terminal, file edit, report, dependency, notes, todo, agents graph, proxy,
simple tools, registry), mirroring the old Python renderers layout.
Wheel builds exclude the Go source; the compiled sidecar still ships as
strix/bin/strix-tui.
@0xallam
0xallam force-pushed the feat/go-tui-provider-setup branch from ad52570 to 03c6ab5 Compare August 2, 2026 17:31
devin-ai-integration Bot and others added 15 commits August 2, 2026 17:44
respond_to_user, wait_for_agents, list_reports, and get_report had dedicated
renderers in the old Textual UI but fell through to the generic dump in Go
(the agent-graph switch matched the nonexistent wait_for_message tool).
Also drops the unused width parameter from render.Chat/render.Tool and adds
table-driven coverage for every dispatch case.
Target resolution, run preparation, model preflight, and start telemetry
move from strix/interface/main.py into strix/interface/scan_setup.py, so
the TUI runtime no longer imports private helpers from the CLI entry
point (and the main -> interactive -> runtime -> main import cycle is
gone). clone_repository now raises ValueError instead of printing a
panel and calling sys.exit, so SystemExit is no longer used as control
flow in the setup path; main() renders the error panel itself.
…unts state

setup.select_provider, setup.save_api_key, and setup.add_custom_provider
now all return _provider_record() (the same shape as providers.list), and
the Go model folds them in through one applyProviderRecord helper.
The controller's parallel mounts list is gone: /mount just adds the
directory as an ordinary local target, matching the CLI's semantics, so
snapshots no longer carry mounts/mount_count.
parse_arguments now establishes the full startup-state schema
(needs_setup, setup_invalid_provider/guidance, targets_info,
local_sources, diff_scope, run_name) in one place, so the TUI
controller and runtime read attributes directly instead of probing
with getattr defaults. main()'s interleaved 'if not setup_mode'
blocks are folded into _detect_provider_setup_need() and
_bootstrap_scan(), leaving a single linear flow.
Parses the Go protocol declaration shipped in the tree and asserts the
version and capability list match the Python backend's constants, so
the duplicated wire declarations cannot drift silently.
model.go (3.6k lines) is now model.go (types/Model/Update loop entry),
update.go (key/mouse/modal input), wire.go (protocol envelope and
collection handling), picker.go, setup.go (setup wizard commands and
views), view.go (main/chat/sidebar/stats views), agents.go, and
vulnerabilities.go. Pure file moves; no logic changes.
- tui/backend/projection.py: wire-safe state/collection projections,
  provider record serializer, and size limits, out of controller.py
- tui/sidecar.py: sidecar process launch, credential-scrubbed child
  environment, and socket authentication, out of runtime.py
- interface/cli_args.py: argument parsing and resume-state loading,
  out of main.py
- interface/environment.py: environment validation and Docker image
  management, out of main.py
- config/provider_detection.py: pure credential/environment detection
  predicates, out of config/providers.py

Pure moves plus import updates; no behavior changes.
Sidecar resolution is now deterministic: a source checkout with Go runs
the TUI via 'go run'; otherwise the packaged wheel binary is used.
…v-binary lookup

The hidden --tui-protocol-smoke flag, Go --handshake-smoke mode, and
ProtocolSmoke client path existed only for the release smoke checks
that were removed from the release workflow. STRIX_TUI_LOG debug
redirection and the build/sidecar dev-binary lookup in binary_command
were optional escape hatches; sidecar resolution is now: go run in a
source checkout, else the packaged wheel binary.
Wheels are platform wheels with the compiled sidecar; the universal
sidecar-free wheel path and its STRIX_REQUIRE_TUI_SIDECAR gate are gone,
so a missing Go toolchain fails the build instead of shipping an install
without an interactive interface. Editable installs still need no Go.
The hook now lives in build_hooks/tui_sidecar.py, and the redundant
tui-run make target is removed.
Interactive launches now open the Bubble Tea UI first and run the model
preflight, run preparation and telemetry behind a visible 'Preparing scan'
state, so the agent loop can never start before the interface is up. A
rejected saved key drops the live session into setup instead of exiting.
Also moves the wheel build hook next to the other build scripts.
Dragging in the chat trace highlights text (reverse video) and copies the
plain-text selection to the clipboard on release, tmux-style, since terminal
mouse capture prevents native selection. Selection coordinates are anchored
to content lines so scrolling keeps the highlight in place.
0xallam and others added 15 commits August 4, 2026 00:39
The prompt from the start screen, --instruction and --instruction-file all
reach the agent folded into its task, which the transcript does not show, so
the user's own words never appeared anywhere. They now open it as their first
message.

The text is captured before prepare_run prefixes the diff-scope preamble onto
args.instruction, so the message is what was typed rather than the assembled
task, and it is persisted in the run record. Reading it back in
hydrate_from_run_dir covers a live scan, a resumed one, and the viewer from
one place: it is stamped with the run's start so it sorts ahead of replayed
history, and held until the root agent exists, since a fresh scan has none
yet. Repeated agent syncs do not repeat it.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
The Go TUI does not use the base projection directly: the backend subclass
overrides upsert_agent to report whether anything changed, and reimplements it
rather than calling back. Hooking the opening message there meant it never
ran, so nothing appeared.

It is posted from flush_user_instruction instead, called where the agent graph
is refreshed - the resume and viewer path after hydration adds the agents, and
the live path from the runtime's periodic sync, which folds the result into
its changed flag so the event is pushed. The test now runs against the
subclass the TUI actually uses, which is what would have caught this.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Quitting ran two beacons with a 10 second requests timeout each, and that
timeout covers connect and read separately, so an endpoint blackholed by a
firewall stalled the exit in connect for far longer than anyone waits. Both
now share a short (connect, read) cap: against a blackholed address each call
gives up in 2s instead of 10.

Because they reach the network on the way out, a second Ctrl-C landed inside
requests and escaped the finally block as a traceback. They are now
best-effort: an interrupt there abandons them and exits cleanly.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
It belongs in its own change rather than riding along with the interface
work. Out go the /provider and /model commands, the provider, model, API-key
and custom-provider pickers, and the seven commands behind them
(providers.list, models.list, setup.select_provider, setup.save_api_key,
setup.disconnect_provider, setup.add_custom_provider, setup.select_model)
along with their protocol types, the paged-models capability, and the model
listing paging.

strix/config keeps everything it gained: the scan bootstrap still runs its
model preflight and still reports provider auth failures, and the launch
screen still shows the model it will use. Configuring one is back to
STRIX_LLM or the config file, which is what the no-model hint now says. The
scan-mode picker stays, since it configures the scan rather than the LLM.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
These are the fresh-run controls: /mode, /budget, /turns, /scope, /mount,
/target-list and /prompt-file, with their backend commands and the
setup-run-controls capability. Every one has a CLI flag, so the run is
configured on the command line and the start screen is left to do one thing:
take a prompt or a target and launch.

/mode was the last thing that opened a picker, so the picker goes with it -
its modes, search input, view, mouse handling and the model fields behind
them. optionWindow moves to setup.go, which still needs it for the command
menu. What remains under a slash is interaction rather than configuration:
/target, /prompt, /clear, /start, /help, /quit.

Docs that described the removed commands, the model and provider pickers, the
custom-provider flow and the paged model listing are updated to point at the
flags and STRIX_LLM instead.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
The interactive provider and model setup is gone, so the machinery behind it
goes too. strix/config/providers.py and strix/config/provider_detection.py are
deleted, and config/__init__.py, config/loader.py and config/models.py return
to what they were: load_settings + apply_config_override + persist_current, a
credential-mirroring StrixProvider, and LLM_API_KEY as the documented key.
core/runner.py, llm/compaction.py and report/dedupe.py go back to passing
settings.llm.extra_headers instead of per-route headers.

Two call sites needed rewiring rather than reverting. preflight_model_connection
keeps verifying the configured route before a named-target scan, but through
StrixProvider() with no credential overrides, and an ordinary exception now
propagates instead of being classified as a credential rejection. The startup
gate that diverted a launch into setup whenever a provider looked unconfigured
is removed - with nothing in setup able to fix that, it only produced a screen
the user could not leave. validate_environment reports missing LLM_API_KEY and
LLM_API_BASE again.

The provider snapshot field, the setup_invalid_provider/setup_guidance argument
pair and the messages they produced are gone, as are the providers.list and
models.list result names the Go client still special-cased.

Kept, because neither belongs to the provider work: the codex.py fix that closes
its HTTP response, and repr=False on the credential settings fields so keys stay
out of reprs and tracebacks.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
The two contributing guides still told people to export OPENAI_API_KEY. That
came from the provider work, which is gone, so they go back to LLM_API_KEY like
every other page.

Also drop two start-screen asides that were left behind in the provider and CLI
pages; the flags and STRIX_LLM already say what those pages need to say.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
The page documents flags. What the start screen does and how sidecar activation
fails are not flags, and nothing on the page refers to them.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Installing from a wheel is what the page covers, and that needs no Go. The
contributing guide already tells source checkouts what they need.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Nothing links to it, and the protocol it describes is defined in the code the
two sides share.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
The agent tree drew a per-row gutter accent for the selected node, dimmed
labels by depth, and used ⏷/⏵ for the toggles. The stylesheet it was ported
from asks for exactly that, but those selectors - .tree--node, .tree--node-label,
.tree--node.-selected - are not Textual Tree component classes, so they never
matched anything. The tree on screen is Textual's own: one label color, dim
guides, a filled block cursor behind the label, and ▼/▶ toggles that a leaf
does not get at all. ⏷ and ⏵ are also missing from most terminal fonts and
render as tofu. Verified against Textual 6.2.1 by rendering both.

Scrollbars took two columns - a gap plus a │ track - and a #737373 thumb, so a
scrolling panel gained a bright rule down its edge. They now take one column
with a blank track and the thumb color each panel asks for: #1a1a1a in the
trace, #404040 in the tree, #333333 in the findings list.

The confirm dialogs came out two columns too wide, because Width() sets the
content box and the border is added outside it. Their buttons were also
centered as a pair and only padded while focused, so moving the choice shifted
the row. Both buttons now hold fixed columns and only repaint a background,
which is what a Textual Button grid does. Same two fixes for the mount prompt.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Pressing enter with nothing that can launch - no model configured, no target -
logged the attempt and its error again every time, so four tries filled all six
rows the launch column keeps with two alternating lines. Snapshot messages were
already deduplicated on the way in; command errors were not, and they are what a
misconfiguration produces.

A line that is already in the log now moves to the end rather than being
appended a second time. Repeating an attempt leaves the log as it was, a
distinct message still lands after it, and the log still reads oldest first.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Every one of them was already reachable without a slash. submitSetupPrompt reads
free text the way a coding agent does: tokens that look like a target are added
as targets, the rest becomes the instruction, and enter launches. So /target,
/prompt and /start restated what typing already does, /clear had nothing to
clear - a submit launches immediately, so targets never accumulate - /quit
duplicated ctrl+c, and /help was a no-op that pointed at the menu listing it.

Gone with them: the command table, the live menu above the composer and its
keyboard selection, the menu's fit rules and the surface-row helper it needed,
and setup.clear_targets on the backend, which nothing else called. A leading
slash is now ordinary prompt text, so "/etc/passwd is world readable" reads as a
path plus an instruction instead of an unknown command.

The composer placeholder and the key hint row no longer advertise commands.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Focusing the agent tree or the findings list dropped their border to #1a1a1a,
which is near-black, so the panel outline vanished at the moment it became the
active one. That came from the stylesheet's Tree:focus rule, but a type-plus-
pseudo selector loses to the #agents_tree id selector that sets #333333, so the
rule never applied and the border never changed. Both panels now hold #333333
whatever has focus. The chat and the composer keep their green focus borders,
which are set on ids and do apply.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Tab reaches four panels and only two of them said so. The chat and the composer
take a green border when focused; the agent tree and the findings list took
nothing, because the stylesheet's only rule for the tree asked for near-black and
lost to an id selector anyway. Both now use the same green as the other two, so
whichever panel is active looks active.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
@devin-ai-integration

Copy link
Copy Markdown
Contributor

Review of the 21 new commits (49a048f..18b134c)

Ran locally on the pulled branch: gofmt clean, go vet clean, go test ./... green, uv run pytest 764 passed, ruff clean, mypy clean (91 files). No dangling references left from the removed provider layer (provider_for_model, providers.list, pickerNone, paged-models/setup-run-controls capabilities are all gone from both sides), and strix/config/loader.py + models.py are now byte-identical to main.

1. Blocking: the working-directory mount bypasses check_mountable_dir

TuiController._start sets pending_workspace_mount = str(Path.cwd()) and, once confirmed, attach_workspace_mount() appends it to local_sources, which build_bind_mounts turns into a writable bind mount (read_only: False, only .git/.agents/.codex remounted read-only).

Every other local-directory path in the codebase goes through check_mountable_dir() first — the guard that refuses /, $HOME, /etc, and credential dirs (.ssh, .aws, .gnupg, .config, …). The new path never calls it, so cd ~ && strix → confirm → the agent gets the user's whole home directory mounted writable inside the sandbox. tests/test_local_sources.py::test_workspace_mount_is_mounted_without_becoming_a_target currently encodes that behavior with $HOME as the mount.

Suggested fix: run check_mountable_dir(Path.cwd()) in _start before setting pending_workspace_mount, and surface the refusal as a setup-log error ("run Strix from your project directory, or give it a target"). Keeping the resume path exempt is fine — that directory was already confirmed.

2. ctrl+c does nothing while a modal is open

updateModal handles esc/arrows/enter only, so ctrl+c is swallowed by the quit, stop and the new mount-confirm prompts. Given the recent "quit must be immediate" changes, the mount prompt in particular should treat ctrl+c as decline-and-quit rather than ignoring it.

3. syncMountPrompt can steal an open modal

case m.snapshot.PendingMount != "" && m.modal != modalConfirmMount: m.openModal(modalConfirmMount) replaces whatever modal is up (help/vulnerability detail). In practice the prompt only appears at launch, so this is a nit — but re-raising it on every snapshot while another modal is open would also reset modalChoice.

4. composerHeight measures through a by-value copy of the textarea

probe := input; probe.SetValue(line) copies textarea.Model, which holds a *memoization.MemoCache pointer — the probe's SetValue/LineInfo writes into the real composer's cache. Correctness looks fine (the value slice is reallocated), but it pollutes the memo cache for the actual composer on every keystroke on a wrapping line. Measuring with ansi.StringWidth(line)/width arithmetic, or a package-level scratch textarea, avoids that.

Non-blocking observations

  • The PR description is now badly stale: it still advertises the Textual fallback, STRIX_TEXTUAL_TUI, provider/model setup, /budget, /turns, /scope, /mount, /target-list, /prompt-file, setup-run-controls, and "889 passed" — all removed. Worth rewriting before merge.
  • _is_internal_agent_turn matches exact prefixes taken from strix.core.*; those strings now have a second consumer with no test-level coupling to their sources. A shared constant (or a test that asserts the producer strings still start with these prefixes) would keep them from silently drifting.
  • setupLogAppend de-duplicates by moving an identical line to the end, which reorders the log rather than showing a repeat count; intentional, just noting the trade-off.

@devin-ai-integration

Copy link
Copy Markdown
Contributor

@greptile

0xallam and others added 2 commits August 4, 2026 04:20
The kitty graphics probe asked for a 500ms budget through
os.Stdin.SetReadDeadline, which a terminal descriptor does not support: it is
blocking, so the runtime never registers it with the poller and the call fails
with "file type does not support deadline". The error was discarded and the read
became unbounded, so a terminal that ignored the query stalled the TUI before
the handshake and before the alt screen - nothing on screen, nothing to press
but ctrl-c. Verified on a pty: the old code never returns, the new code gives up
in 500ms.

The wait is now poll(2), which does work on a blocking descriptor. Windows has
no console equivalent worth carrying and no terminal there implements the
protocol, so it reports no support instead.

The reply is also drained before cooked mode returns. The DA1 trails a kitty
answer, so recognizing the answer left the DA1 in the input buffer for the shell
to echo, which is what printed "^[[?62;52;c".

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
The query puts the terminal in raw mode, and raw mode clears ISIG, so ctrl-c is
delivered as an ETX byte rather than a signal. The read consumed it as terminal
noise and kept waiting, which is why ctrl-c did nothing while startup was stuck
here: there was no signal to receive.

ETX now ends the wait, and the interrupt is raised once the terminal is restored,
so the process exits the way the user asked. Confirmed on a pty with a
controlling terminal: the byte is recognized and the process dies of SIGINT
instead of running on.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
@devin-ai-integration devin-ai-integration Bot changed the title feat(tui): add Bubble Tea interface with provider setup feat(tui): replace Textual with a Go/Bubble Tea interface Aug 4, 2026
The frozen spec still collected textual data files, listed textual
hidden imports and packaged .tcss stylesheets that no longer exist, and
named config modules that were renamed. Surface the underlying launch
error in the CLI panel instead of a fixed wheel/Go message, and trim the
README install notes about the sidecar.
@0xallam

0xallam commented Aug 4, 2026

Copy link
Copy Markdown
Member

@greptile

@0xallam
0xallam merged commit 5bb9fe8 into usestrix:main Aug 4, 2026
1 check passed
khangpanarnd pushed a commit to khangpanarnd/strix that referenced this pull request Aug 6, 2026
Resolve conflicts after main's large refactor:
- usestrix#725: adopt main's --mount design (usestrix#958); drop branch's default-mount
  changes in utils.py/main.py and the orphaned test_fast_local_import.py.
- TUI: accept main's replacement of the Python/Textual TUI with the Go/Bubble
  Tea implementation (usestrix#941); drop the obsolete batched event-pump fix
  (app.py, event_pump.py, test_event_pump.py).
- Keep and reconcile the self-contained HTML report feature onto main's
  refactored report layer (writer.py/state.py/settings.py).
- Keep the viewer 'Past Runs without email verification' change; auth.is_verified
  reconciled with main's reworked viewer/auth.py.
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.

3 participants