Skip to content

v0.9.0: TUI-first Crabby — Mission Control, workspace import, and more - #8

Merged
marioolf merged 15 commits into
mainfrom
feature/tui-first
Jul 15, 2026
Merged

marioolf merged 15 commits into
mainfrom
feature/tui-first

Conversation

@marioolf

Copy link
Copy Markdown
Owner

Turns Crabby into a terminal application. crabby opens a persistent, multi-panel
app and every day-to-day action lives inside it; the CLI keeps only version and
doctor. Bundles the 0.8.0 (TUI-first) and 0.9.0 (Mission Control + import) work.

Highlights

  • TUI-first dashboard — three columns (Workspaces | Tasks | Details), keyboard
    focus between panes, Enter attaches to Claude via tea.ExecProcess (clean step
    in/out, no shell, no leftover [detached] noise). Animated crab banner.
  • In-app flows — new workspace (dir + pack, with Tab path completion and a
    native Windows folder picker), new task, pack management (create/duplicate/edit
    via $EDITOR/delete), Settings (Packs, Diagnostics, About), Help.
  • Mission Control (F12) — a live grid of every Claude task with status, branch,
    uptime, model, tokens and a live tmux capture-pane preview (chrome stripped).
    Captures are cached per session and only refreshed on new output, so it scales.
  • Workspace import (i) — auto-scans the machine (WSL home + Windows user dev
    folders), matches CLAUDE.md/claude.md, with Found/Selected counts, a/n/space/i,
    and d to un-import.
  • Open folder (o) in the file manager, and relink (e) to fix a workspace
    whose folder was moved or renamed (flagged ⚠ missing).

Compatibility & scope

  • Data model, session storage and pack format are unchanged; existing workspaces,
    tasks and packs keep working.
  • Mission Control is an observation surface, not a terminal emulator.

Testing

make lint + make test green (new tests for pack CRUD, project.Relink, import
scanning/depth, path completion, and every TUI screen rendering). Validated live
in tmux: dashboard, attach/detach, Mission Control (incl. attach→F12→return),
import scan + un-import, relink after rename, folder open wiring.

Releases as v0.9.0.

marioolf added 15 commits July 14, 2026 21:01
Backend helpers the persistent TUI needs before the UI itself:
- pack.Create/Duplicate/Delete operate on the existing on-disk format.
- tmux.AttachCmd returns the attach command (unrun) for tea.ExecProcess,
  so Bubble Tea can release and restore the screen around a Claude session.
AttachChild now delegates to it.
Crabby becomes a terminal application. `crabby` opens a persistent
Bubble Tea app and every day-to-day action lives inside it; the shell is
no longer part of the workflow.

- Dashboard is a three-column layout: Workspaces | Tasks | Details, with
  keyboard focus moving between panes (tab / arrows) and Enter attaching
  the selected task to Claude.
- Attaching runs through tea.ExecProcess, so the screen is released for
  Claude and the dashboard restored on return — no leaving Crabby. The
  prefix-free return key (F12) is shown on screen and in Help.
- In-app flows: new workspace (directory -> pack -> create), new task,
  pack management (new / duplicate / edit via $EDITOR / delete), a
  Settings section (Packs, Diagnostics, About), and a Help screen listing
  every shortcut.
- CLI slims to the two commands that belong outside the interface:
  `version` and `doctor`. init/import/task/attach/start/ps/rm move into
  the TUI.
- Data model, session storage and pack format are unchanged; existing
  workspaces, tasks and packs keep working.

The old flat-list dashboard and shell-loop home() are removed.
- Import moves into the TUI (i): scan a folder for workspaces with a
  CLAUDE.md and pick which to adopt. The scan runs off the UI thread via a
  tea.Cmd with a Scanning… state, so a deep tree never freezes Crabby.
  This keeps the importcmd package in use rather than orphaned.
- Help columns align on display width, not byte length (arrow glyphs).
- Add smoke tests rendering every screen and asserting dashboard key
  transitions, plus unit tests for the format helpers.
- Bump VERSION to 0.8.0.
- README: new three-pane dashboard mockup and key list; workspaces/tasks,
  adopting projects, and packs sections rewritten around the in-app flows;
  Commands table trimmed to crabby / version / doctor.
- CHANGELOG: 0.8.0 (TUI-first) and the 0.7.3 mouse-wheel fix.
Attaching drops out of Crabby's alternate screen into the terminal's
normal buffer, and on detach tmux prints '[detached (from session …)]'
there. Left alone that noise piled up in the shell and the buffer switch
briefly showed the previous session or shell.

Run the attach through a tea.Exec command that clears the normal buffer
either side of it, so both transitions are clean and the shell stays
empty after quitting. The tmux session name is still passed as a single
argv element (no shell), so unusual workspace names can't be word-split.

Remove the now-unused tmux.AttachChild.
The new-workspace directory field now helps you find the folder:
- Tab completes the typed path to the matching sub-directory (shell-style),
  and matching sub-directories are listed live as you type — both
  directory-only, using stdlib, no new dependencies.
- Ctrl+O opens the native Windows folder dialog (WSL) via PowerShell and
  converts the result with wslpath, as a convenience for Windows-side
  folders. It runs off the UI thread so the interface stays responsive.
- The banner crab now sways within a fixed-width lane and cycles between
  resting, claw-wave and blink poses, driven by a separate 500ms redraw
  tick that only rebuilds the view (no disk/tmux reads) — negligible cost.
  The lane is fixed width, so only the crab moves; wordmark and support
  line stay put.
- Wordmark is now 'CRABBY' (letters together) instead of 'C R A B B Y'.

Banner() stays still for CLI help; BannerFrame(t) is the animated variant.
- The sway is now symmetric around zero (−2…+2), so the crab rests centred
  over the CRABBY wordmark instead of biased to one side. Verified: at
  sway 0 the claws' centre matches the wordmark's exactly.
- Redraw the banner by centring every line manually rather than via
  JoinVertical, so the crab's horizontal position is exact and independent
  of lipgloss padding semantics.
- Give the crab legs and animate them: the poses now move claws (wave),
  legs (kick) and eyes (blink) together.
- Legs no longer animate: every pose uses the same legs, so only the claws
  (wave) and eyes (blink) move.
- The animation cycle now starts at sway 0 and swings symmetrically, so the
  crab both opens and rests centred over the wordmark instead of starting at
  the left extreme. Verified: t=0 offset is 0, sway is symmetric ±2.
center() uses lipgloss.PlaceHorizontal, which centres each line by its own
width. The manual banner layout left-padded lines only, so lines of
differing widths were re-centred independently and the wordmark and tagline
drifted right of the crab and support line.

Make every banner line exactly bannerWidth wide (pad both sides), so the
block centres as a unit — the same shape JoinVertical produced. Verified:
crab, CRABBY, tagline and support line now share one centre.
Pressing i now scans straight away instead of asking for a path:
- importcmd.DiscoverDefault walks the WSL home and the common project
  folders under each Windows user on the mounted drives (/mnt/<drive>/
  Users/*), in parallel, depth-capped so a deep tree can't stall it.
- Matches CLAUDE.md and claude.md; prunes deps (now incl. build/dist) and
  hidden directories, so ~/.claude, ~/.config packs and caches stay out.
- The pick list shows 'Found N' and a live 'Selected: N', with space to
  toggle, a/n to select all/none, i (or enter) to import, r to rescan.
  Already-imported workspaces are flagged and locked.
F12 toggles the dashboard and a new Mission Control view (mission.go), a
grid of cards, one per task. Each card shows its status (working activity /
Waiting / Attached / Idle / Stopped), branch, uptime, model and tokens, and
a short live preview of the session's pane.

- Previews come from tmux capture-pane, reduced to the last few lines that
  actually carry words — box art, blank lines and Claude's persistent status
  chrome are stripped, so the card shows recent output and the current
  prompt, not the whole terminal.
- Captures are cached per session and only refreshed when the session's
  window-activity advances, so idle tasks cost nothing and the view scales
  to dozens.
- Arrow/Tab keys move between cards (focused card highlighted); Enter attaches
  to that session and leaving it returns to Mission Control.
- Kept entirely separate from the dashboard's rendering.
- README: rewrite the import section for the automatic machine scan, add a
  Mission Control section with a captured mockup, and surface F12 / mission
  control in the everyday-use keys.
- CHANGELOG: 0.9.0 (Mission Control + auto-scan import).
- VERSION -> 0.9.0.
Press o on the dashboard to open the selected workspace's directory in the
file manager — Windows Explorer on WSL, via wslpath (a Linux path opens over
\\wsl.localhost). Launched fire-and-forget off the UI thread, with the
result shown in the status bar. Saves copying and pasting the path when
adding files to a workspace.
Crabby can't auto-detect a folder rename — the old path is gone and nothing
links it to the new location — so instead:
- refresh() flags a workspace whose directory no longer exists as missing;
  the dashboard shows '⚠ missing' and o explains it rather than failing.
- e opens a relink flow (same path completion as new-workspace) that points
  the workspace at its new folder via project.Relink, updating name and path
  while keeping tasks (their session names are stored, so they still match).
- d in the import screen un-imports an already-imported workspace, so a
  mistaken or stale import can be undone without leaving the view.

The space toggle in import was verified working; the confusion was that
already-imported rows are locked — d now gives them an action.
@marioolf
marioolf merged commit a962b2a into main Jul 15, 2026
1 check passed
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.

1 participant