Skip to content

hdprajwal/quackcode

Repository files navigation

quackcode

A Rust + GPUI terminal workspace experiment. It opens folders as workspaces, hosts multiple PTY-backed terminals per workspace in a single window, ships with the full GitHub Primer theme family, and persists user settings to disk. The project is structured as a small, modular application under src/app/ rather than a monolith, with an architectural plan that incrementally adds a Chromium-driven dev-server preview pane and a Claude Code session manager alongside the terminals.

The codebase is intentionally small — roughly 2.8k lines of Rust split across one file per responsibility — and is meant to be read end-to-end. If you want to understand how a GPUI application wires a PTY, an alacritty terminal grid, a theme system, and a settings pane together without a framework hiding the seams, this is a useful read.

Project Status

quackcode is an active experiment, not a finished product. The terminal core and chrome are usable for day-to-day terminal work; large feature areas (browser preview, Claude session management, in-terminal text selection) are designed but not yet implemented. Each major feature lives in its own plan file under docs/, and docs/PLAN.md is the ordered backlog with a completion marker on each entry.

Today, completed work covers the application skeleton, workspace folder picker, multi-terminal model per workspace, the full keyboard input pipeline (xterm modifier escapes, bracketed paste, image-clipboard handling), the Zed v0.1.0 theme runtime with bundled and user-supplied themes, a settings pane with live UI font scaling, persistence of theme and UI font, and bell notifications with desktop sound. Outstanding work is enumerated in the Roadmap section.

Quick Start

Prerequisites are listed in detail in the Prerequisites section. Once they are satisfied:

git clone git@github.com:hdprajwal/quackcode.git
cd quackcode
cargo run --release

The binary is named quackcode and is set as the crate's default-run, so no --bin flag is required. Release installs also add qcode as a shorter command alias. The release profile is recommended because GPUI's debug builds render noticeably slower.

On first launch the application:

  1. Opens a main window sized by GPUI defaults.
  2. Treats the current working directory as the initial workspace.
  3. Spawns one PTY-backed terminal rooted at that directory using your login shell.
  4. Loads your saved theme (or falls back to the bundled default) and your saved UI font size.

There is no first-run wizard. Configuration happens via the settings pane (described below) and via direct edits to ~/.config/quackcode/config.json.

Releases

Pre-built Linux x86_64 binaries are published to GitHub Releases by the Release workflow on every v* tag.

To install the latest release into ~/.local/bin:

curl -fsSL https://raw.githubusercontent.com/hdprajwal/quackcode/main/install.sh | bash

Pass options through bash -s -- to choose a different install directory or version:

curl -fsSL https://raw.githubusercontent.com/hdprajwal/quackcode/main/install.sh | bash -s -- --install-dir /usr/local/bin --version 0.1.0

If you prefer to install manually:

  1. Open the Releases page and download quackcode-<version>-x86_64-unknown-linux-gnu.tar.gz along with the matching .sha256 file.

  2. Verify the archive:

    sha256sum -c quackcode-<version>-x86_64-unknown-linux-gnu.tar.gz.sha256
  3. Extract and run:

    tar -xzf quackcode-<version>-x86_64-unknown-linux-gnu.tar.gz
    cd quackcode-<version>-x86_64-unknown-linux-gnu
    ./quackcode

The archive contains the stripped release binary, a qcode symlink alias, LICENSE, README.md, and the bundled themes under assets/themes/. The runtime prerequisites listed under Prerequisites — JetBrainsMono Nerd Font Mono, paplay, the freedesktop sound theme, and a notification daemon — still need to be present on the host.

macOS and Windows binaries are not currently published; build from source via Building From Source.

Features

Workspaces

A workspace in quackcode is a folder that anchors one or more terminal sessions. The mental model is closer to "project" than to "tab group" — terminals belong to a workspace, switching workspace also switches the visible terminal list in the sidebar, and the application remembers which workspaces you have open within the session.

  • The native OS folder picker handles workspace selection. There is no in-app file browser.
  • The picker accepts directories only; files are rejected by the OS dialog.
  • One workspace per pick. Multi-select is intentionally not supported — see docs/workspaces.md for the rationale.
  • If you pick a folder that is already an open workspace, the application switches to that workspace instead of creating a duplicate.
  • Opening a new workspace automatically creates a fresh terminal session rooted at that folder; you do not need to also press the "new terminal" shortcut.
  • The path the picker resolves is canonicalized (fs::canonicalize) before comparison, so symlinked paths to the same destination deduplicate correctly.

Workspaces are stored in memory for the lifetime of the application process. There is no persistence of "last open workspaces" across restarts yet — that would be a natural future enhancement.

Terminal Sessions

Each terminal is a real PTY driven by alacritty_terminal 0.26, the same emulator core used by Alacritty itself.

  • Default initial grid is 100 columns by 30 rows. The grid resizes live as you resize the window or adjust the UI chrome.
  • The PTY child is your login shell. On Unix the shell is discovered through alacritty_terminal::tty::Options, which respects $SHELL.
  • Each session carries an unread flag that is set when the terminal rings the bell while the session is not focused; switching to the session clears the flag.
  • Terminal output is buffered through alacritty_terminal's event loop on a dedicated thread; the rendering thread reads grid snapshots without holding the terminal lock. This is enforced by paint.rs deliberately copying the visible cells into owned data before drawing.
  • Closing a session sends a shutdown message to the alacritty event loop on drop; child processes are cleaned up via PTY close.

Multiple terminals per workspace are first-class: the sidebar lists them under their workspace, and keyboard shortcuts switch between them by index.

Keyboard Input Pipeline

The keyboard pipeline in src/app/input.rs does three jobs in order: it routes app shortcuts before anything terminal-bound, it consumes settings-pane navigation when the settings pane is visible, and it translates remaining keystrokes into the byte sequences a Unix terminal expects.

The translation layer is more thorough than a typical hobby terminal:

  • Plain keys map to their UTF-8 bytes, including dead-key composition handled by GPUI.
  • Special keys (Enter, Tab, Escape, arrows, Home, End, PageUp, PageDown, Insert, Delete, Backspace) emit the canonical xterm escape sequences.
  • Ctrl-letter combinations emit the ASCII control bytes (Ctrl+A -> 0x01, ... Ctrl+Z -> 0x1A, plus Ctrl+@, Ctrl+[, Ctrl+\, Ctrl+], Ctrl+^, Ctrl+_, Ctrl+?).
  • Word-motion shortcuts are handled explicitly: Ctrl+Backspace -> 0x17 (word-delete-backward), Alt+Backspace -> ESC DEL (alternative word-delete-backward), Alt+d -> ESC d (word-delete-forward), Ctrl+Left/Ctrl+Right -> xterm-modified arrows, Alt+Left/Alt+Right -> readline ESC b / ESC f.
  • Modified navigation keys follow the xterm CSI scheme ESC [ 1 ; <mod> <key> where <mod> is 1 + shift + 2*alt + 4*ctrl. Arrows, Home, End, Insert, Delete, PageUp, and PageDown all participate.
  • Shift+Tab emits ESC [ Z.

The translation table is covered by unit tests in src/app/input.rs so future contributors don't accidentally regress shell ergonomics.

Clipboard Handling

Paste is bound to Ctrl+Shift+V. The handler is aware of three cases:

  • Text payloads are sent as-is when the terminal does not have bracketed paste mode enabled.
  • Text payloads with bracketed paste (TermMode::BRACKETED_PASTE set by the running program, typically a modern shell or editor) are wrapped with ESC [ 200 ~ ... ESC [ 201 ~ so the program can distinguish pasted input from typed input.
  • Image payloads in the clipboard trigger a Ctrl+V byte (0x16) to the PTY instead of attempting to paste binary data. This is a defensive choice — pasting a PNG into a terminal is almost never what the user meant.

Copy from the terminal is not yet implemented. It is Plan 6 in the roadmap.

Themes

quackcode parses Zed v0.1.0 theme files at runtime. This is the same schema that Zed itself uses for its bundled and user themes, so any compatible theme file can be dropped into the user themes directory and will appear in the picker.

Bundled themes. The application ships every GitHub Primer variant — GitHub Light and GitHub Dark in standard, colorblind, high-contrast, and tritanopia flavors, plus GitHub Dark Dimmed. The bundle lives in assets/themes/github_theme.json and is regenerated from the upstream Node script PyaeSoneAungRgn/github-zed-theme (the same script that produces the GitHub theme extension for Zed). See assets/themes/README.md for the regeneration recipe.

User themes. Drop additional Zed v0.1.0 theme files into:

~/.config/quackcode/themes/

Both single-theme objects and family files containing a themes: [] array are accepted. The registry rescans the user directory on startup and merges user themes alongside the bundled set; in case of a name collision the user theme wins. The currently selected theme is persisted to ~/.config/quackcode/config.json so it survives restarts.

Selection model. Themes are previewed live as you scroll through the settings pane; the previewed theme is applied immediately to all chrome and to the terminal palette so you can see the effect on real content. Pressing Enter confirms the choice and persists it; pressing Esc reverts to whatever was active before you opened the pane.

Settings Pane

The settings pane is opened with Ctrl+Shift+, or Ctrl+Shift+S. It is an overlay rendered on top of the main view, focus-trapped, and is the canonical anchored-overlay pattern in this codebase — new floating UI (right-click menus, future inline inputs) should be modeled on src/app/settings_pane.rs.

Currently being restructured. The pane is being reworked from a flat control list into a sectioned layout. The first section is Appearance (theme selection and UI font size — the controls listed below). Additional sections (terminal, keybindings, behavior) are planned but not yet implemented. The shortcut and overlay behavior described here are stable; the internal layout of the pane is in flux.

Controls available in the Appearance section today:

  • UI font size. Adjustable from 10 px to 24 px in 1 px steps. The range is enforced by UiSettings::clamp so invalid values from disk are normalized rather than rejected. The control responds to Left/Right arrows or to - and +/= keys directly.
  • Theme dropdown. Toggled with Tab or Space, navigated with Up/Down, applied live on focus change for preview, confirmed on Enter, cancelled on Esc.

The pane updates AppView's ui_settings field in real time, which propagates through GPUI re-render to sidebar text, status overlays, and other chrome. The terminal grid font is independent of the UI font and is unaffected.

Closing behavior. Pressing Esc discards changes and restores the prior state. Pressing Enter persists changes to ~/.config/quackcode/config.json via save_app_settings. While the pane is visible, all keyboard input is consumed by the pane — keystrokes do not fall through to the terminal.

Settings persistence covers two keys today:

{
  "theme": "GitHub Dark Dimmed",
  "ui_font_size_px": 14.0
}

The file is created lazily on the first save; missing keys fall back to defaults; the file is parsed leniently so a partially corrupt file does not lock you out (it is silently replaced on the next save).

Bell And Notifications

When a terminal session emits the BEL byte (0x07):

  • If the session is not the active session, an unread dot is set on its sidebar entry until the user switches to it.
  • If the main window is not focused, a desktop notification is shown via notify-rust with the offending terminal's title in the body.
  • A short audio cue is played by spawning paplay against the configured bell sound (/usr/share/sounds/freedesktop/stereo/bell.oga by default — adjust the constant in src/app/config.rs or replace the file on your system).

The bell pipeline runs entirely through a flume channel that is consumed by a dedicated cx.spawn task, so an aggressive process that bells in a tight loop cannot block the renderer.

Sidebar

The sidebar is a fixed-width chrome panel (200 px) listing workspaces and the terminal sessions under each. Workspaces appear in open order; sessions are rendered under their workspace in creation order. The active session and active workspace are visually highlighted using the theme's accent and selection colors.

Mouse affordances available today:

  • Click the + row to open the native folder picker (equivalent to Ctrl+Shift+O).
  • Click a workspace to switch to it.
  • Click a session to switch to it.
  • Closing a session is currently keyboard-only via Ctrl+Shift+W.

Right-click context menus are not yet implemented; they are tracked in docs/claude-sessions-plan.md phase 0 because that feature drove the requirement.

Painting And Performance

The render flow is:

  1. AppView::render resizes the active terminal to the current viewport using the measured cell width and the configured cell height (currently 20 px line / 15 px font for the terminal grid).
  2. paint::snapshot_for_session captures an owned snapshot of the visible grid cells — the terminal lock is released before painting begins.
  3. paint::terminal_canvas renders the snapshot to a GPUI canvas, drawing per-cell background fills, cursor block, and glyphs using the active theme.
  4. sidebar::build_sidebar renders the workspaces and sessions chrome.
  5. If the settings pane is visible, it is rendered on top of everything.

Snapshotting before painting is the most important performance and correctness property: it means a long-running paint pass never blocks the alacritty event loop, and it means the terminal lock contention stays predictable regardless of how busy the PTY is.

Keyboard Shortcuts

All app shortcuts use the Ctrl+Shift prefix to avoid colliding with terminal-bound chords like Ctrl+C. The full set today:

App Shortcuts

Shortcut Action
Ctrl+Shift+O Open a workspace folder via the native folder picker
Ctrl+Shift+T Create a new terminal in the active workspace
Ctrl+Shift+W Close the active terminal
Ctrl+Shift+1 ... Ctrl+Shift+9 Switch to the terminal at that index (1-based) in the active workspace
Ctrl+Shift+V Paste from system clipboard, with bracketed-paste if the program supports it
Ctrl+Shift+, Open the settings pane (Appearance section by default)
Ctrl+Shift+S Open the settings pane (alias of Ctrl+Shift+,)

Settings Pane

Shortcut Action
Up / Down Move focus between settings rows
Left / - Decrease the focused numeric value (UI font size)
Right / + / = Increase the focused numeric value (UI font size)
Tab / Space Toggle the theme dropdown when the theme row is focused
Enter Confirm the current value and persist to disk
Esc Cancel and restore the prior state
Ctrl+Shift+, / Ctrl+Shift+S Close the pane (treated as cancel)

Forwarded Terminal Shortcuts

The input pipeline forwards a deliberate set of terminal-side chords. These are sent through to the running program as the canonical byte sequences:

Shortcut Bytes Typical use
Ctrl+Backspace 0x17 Word delete backward (readline / shell)
Alt+Backspace ESC DEL Word delete backward (alternative)
Ctrl+Delete ESC [ 3 ; 5 ~ Word delete forward (programs that read xterm-modified)
Alt+Delete ESC [ 3 ; 3 ~ Word delete forward (alternative)
Alt+d ESC d Word delete forward (readline)
Ctrl+Left ESC [ 1 ; 5 D Word backward
Ctrl+Right ESC [ 1 ; 5 C Word forward
Alt+Left ESC b Word backward (readline)
Alt+Right ESC f Word forward (readline)
Shift+Tab ESC [ Z Reverse-tab / focus-previous

Arrows, Home, End, Insert, Delete, PageUp, and PageDown with any combination of Shift/Ctrl/Alt also emit xterm-modified escape sequences via the standard CSI 1 ; mod scheme.

Configuration

All configuration lives under ~/.config/quackcode/. There is no project-local configuration today. Existing ~/.config/quackcode-rs/ settings and themes are still read as a legacy fallback.

config.json

{
  "theme": "GitHub Dark Dimmed",
  "ui_font_size_px": 14.0
}
  • theme — The name of the theme to load on startup. Must match a theme bundled in assets/themes/github_theme.json or present in ~/.config/quackcode/themes/. If the value is missing or refers to an unknown theme, the registry falls back to a sensible default.
  • ui_font_size_px — UI chrome font size in pixels. Clamped to [10.0, 24.0] on load.

The file is written by the settings pane on save; you can edit it directly when the app is closed.

themes/

Any Zed v0.1.0 theme file dropped in this directory is picked up at startup. Both single-theme objects and family files containing a top-level themes: [] array are accepted. Filenames are not significant — themes are addressed by the name field inside the JSON.

Constants

A handful of behaviors are still compile-time constants rather than runtime settings. They live in src/app/config.rs:

  • Initial grid: INITIAL_COLS = 100, INITIAL_ROWS = 30.
  • Terminal font and cell: FONT_SIZE_PX = 15.0, CELL_H_PX = 20.0, FALLBACK_CELL_W_PX = 9.0.
  • UI chrome font and line height defaults: DEFAULT_UI_FONT_SIZE_PX = 14.0, DEFAULT_UI_LINE_HEIGHT_PX = 18.0.
  • Sidebar width: SIDEBAR_W_PX = 200.0.
  • Window padding: PADDING_PX = 4.0.
  • Font family: JetBrainsMono Nerd Font Mono. If the font isn't installed, GPUI falls through the platform font cascade.
  • Bell sound: /usr/share/sounds/freedesktop/stereo/bell.oga (the freedesktop sound theme path).

Promoting any of these to runtime settings is a small refactor — copy the pattern already used for ui_font_size_px in src/app/settings.rs.

Prerequisites

quackcode is developed and tested on Linux. macOS and Windows are likely to work since GPUI itself is cross-platform, but several conveniences are Linux-specific.

  • Rust — A current stable toolchain. The crate targets edition 2021; build with the version of rustc matching the Cargo.lock checked into the repository.
  • GPUI build dependencies — GPUI requires the platform's GPU stack and windowing system headers. On Linux that typically means a recent Wayland or X11 environment with Vulkan support; refer to GPUI's own build documentation for specifics.
  • JetBrainsMono Nerd Font Mono — Strongly recommended for proper glyph rendering, especially of Powerline / Nerd Font icons used by many shell prompts. If absent, GPUI falls back to the platform's default monospace, which will work but will look different.
  • paplay — For the audio bell cue on Linux. Part of the pulseaudio-utils package on most distributions.
  • freedesktop sound theme — The default bell sound path is /usr/share/sounds/freedesktop/stereo/bell.oga. If your distribution does not install this theme by default, either install it (sound-theme-freedesktop on Debian-family) or change BELL_SOUND in src/app/config.rs.
  • A desktop notification daemon — Required for the bell-while-unfocused desktop notifications. Any org.freedesktop.Notifications-compatible daemon will do (most desktop environments install one by default).

Building From Source

# Clone
git clone git@github.com:hdprajwal/quackcode.git
cd quackcode

# Build (release recommended for actual use)
cargo build --release

# Or build and run in one step
cargo run --release

# Run the test suite
cargo test

# Check formatting (required for clean PRs)
cargo fmt --check

# Auto-format
cargo fmt

# Lint (not enforced in CI yet, but useful locally)
cargo clippy --all-targets --all-features -- -D warnings

The first build downloads and compiles GPUI, alacritty_terminal, and their transitive dependencies; expect a few minutes on cold cache. Subsequent builds are fast because the codebase itself is small.

Project Layout

.
├── Cargo.toml              # Crate manifest, single binary `quackcode` (default-run)
├── Cargo.lock
├── README.md               # This file
├── install.sh              # GitHub Releases installer for Linux x86_64
├── AGENTS.md               # Instructions for AI coding agents working in the repo
├── implementation-notes.html  # Running notebook of design decisions, deviations, tradeoffs, open questions
├── assets/
│   └── themes/             # Bundled Zed v0.1.0 theme files (GitHub Primer family)
├── docs/
│   ├── architecture.md         # Module-by-module architecture overview
│   ├── PLAN.md                 # Sequenced backlog (each item marked completed or open)
│   ├── workspaces.md           # Workspace folder picker behavior and rationale
│   ├── preview-pane-plan.md    # Multi-phase plan for the Chromium dev-server preview pane
│   └── claude-sessions-plan.md # Multi-phase plan for the Claude Code session manager
└── src/
    ├── main.rs             # Thin binary entrypoint that calls `app::run`
    └── app/
        ├── mod.rs                 # `app::run`, Application setup, channels, consumer tasks
        ├── app_view.rs            # `AppView` state, render composition, top-level actions
        ├── assets.rs              # Bundled asset access
        ├── config.rs              # Compile-time constants and ID type aliases
        ├── input.rs               # Key routing, settings-pane keys, xterm modifier translation
        ├── paint.rs               # Grid snapshot, terminal canvas painting
        ├── picker.rs              # Anchored overlay primitive (legacy theme picker scaffolding)
        ├── project.rs             # `Project { id, name, root_path }`
        ├── session.rs             # PTY creation, alacritty session ownership, resize, shutdown
        ├── settings.rs            # `UiSettings`, `AppSettings`, persistence to `config.json`
        ├── settings_pane.rs       # Settings pane state and rendering (canonical overlay pattern)
        ├── sidebar.rs             # Sidebar UI: workspaces, sessions, `+` row
        └── theme/
            ├── mod.rs             # Theme module facade
            ├── color.rs           # Color helpers, ANSI palette translation
            ├── registry.rs        # Bundled + user-dir theme registry
            ├── settings.rs        # Persisted selected theme
            └── zed.rs             # Zed v0.1.0 schema parsing

Architecture Highlights

Read docs/architecture.md for the full module map. A few seams are worth calling out here because they are reused by every new feature:

  • Channel topology. src/app/mod.rs allocates three foundational flume channels at startup: dirty_tx/dirty_rx for redraw notifications, bell_tx/bell_rx for terminal bells, and exited_tx/exited_rx for PTY exit. Each has a dedicated cx.spawn consumer task that drains the receiver and updates AppView. New cross-thread events follow the same pattern — the planned preview pane and Claude session features each add one more channel pair plus a consumer task in app::run.
  • Flat lists on AppView. Entities such as projects, sessions, and the planned previews / claude_sessions live as flat Vec<T> on AppView with a next_X_id: T_Id counter. Association is by project_id on the child entity, not by nesting children inside Project.
  • App shortcuts first, terminal forward last. input::handle_key is the single keyboard entrypoint. It pops settings-pane navigation first, then app shortcuts, and only forwards to the PTY if nothing matched. This ordering is deliberate and is the reason app shortcuts can never be eaten by a misbehaving program.
  • Snapshot before paint. Already discussed under Painting And Performance. This invariant is the project's most important rule for the terminal pipeline.
  • One responsibility per file. New features either extend an existing module or get a new module directory (e.g. src/app/claude/ or src/app/preview/). The codebase has no god-module and is structured to keep it that way.

Testing

The current test surface is modest and lives next to the code under test:

  • src/app/input.rs — keyboard translation tests covering word-deletion, word-navigation, and the basic plain-key path.
  • src/app/settings.rs — UI font clamping and default behavior tests.

Run them all with:

cargo test

There are no integration tests for the GPUI render path or for the alacritty event loop yet. Those would require either a headless GPUI test harness (not currently exposed by the public crate) or a process-level smoke test that drives the binary with simulated input.

Documentation

The docs/ directory contains the canonical product and architecture references:

  • docs/architecture.md — Module map, key seams, render flow, guidance on extending the application.
  • docs/PLAN.md — Ordered backlog. Each plan has a status marker (Completed or open).
  • docs/workspaces.md — Workspace folder picker behavior and the single-folder rationale.
  • docs/preview-pane-plan.md — Detailed eight-phase plan for adding a Chromium-based dev-server preview pane driven by the Chrome DevTools Protocol.
  • docs/claude-sessions-plan.md — Detailed plan for adding Claude Code session management to the sidebar, including right-click Fork / Resume / Rename / Reveal-transcript / Delete actions.

The repo root also contains:

  • AGENTS.md — Instructions for AI agents working in the repo. Specifies the implementation-notes discipline, project conventions, allowed commands, and explicit boundaries (always-do / ask-first / never-do).
  • implementation-notes.html — A running, human-readable notebook of design decisions, deviations from the spec, tradeoffs considered, and open questions. Agents and humans are expected to add a section per meaningful change.

Roadmap

Active and planned work, in roughly the priority order documented in docs/PLAN.md and the per-feature plan files.

Open Plans In docs/PLAN.md

  • Plan 5 — Terminal font size shortcut. Add Ctrl+Shift+= (and the canonical Ctrl+Shift++ form) to enlarge the terminal grid font, with corresponding shrink and reset shortcuts. Touches src/app/input.rs (shortcut routing before terminal forwarding), src/app/config.rs (terminal font as runtime metric), src/app/paint.rs (re-measure cell width), and src/app/session.rs (PTY resize with new cell dimensions). Settings persistence is a stretch goal within this plan.
  • Plan 6 — Terminal text selection and copy. Implement mouse-driven cell-range selection backed by alacritty_terminal::selection::Selection, render the selection background using the active theme, bind Ctrl+Shift+C to copy the selection to the system clipboard via GPUI's clipboard API, and define the clear-selection triggers (any PTY-bound keypress, fresh mouse-down without modifier, terminal resize, theme change). Drag-scroll while selecting past the viewport edge is in scope; double-click word and triple-click line are explicit follow-ups.

Larger Planned Features

  • Side-by-side dev-server preview via Chromium + CDPdocs/preview-pane-plan.md. Spawns a dedicated Chromium window per workspace via the Chrome DevTools Protocol, keeps it positioned beside the GPUI window, and surfaces navigation, reload, console-tail, and dev-server URL auto-detection in a pane next to the terminal. The plan is split into eight commit-sized phases ending with full lifecycle and config persistence. Out of scope: rendering the page inside the GPUI window itself.
  • Claude Code session managerdocs/claude-sessions-plan.md. Treats a Claude Code conversation as a first-class object in the sidebar with right-click actions (Fork, Resume, Rename, Copy session ID, Reveal transcript, Delete). Sessions outlive their hosting terminal — closed terminals become Idle records that can be resumed into a new PTY. Includes a phase 0 generic context-menu primitive (modeled on settings_pane.rs) that the preview pane plan also intends to consume. Five phases plus stretch items.

In Flight

  • Settings pane restructure. Migrating the flat control list into a sectioned layout. Appearance (theme + UI font) is the first section; terminal, keybindings, and behavior sections are planned. Shortcut is moving to Ctrl+Shift+, with Ctrl+Shift+S as an alias.

Smaller Quality-Of-Life Items (Not Yet Planned)

These are obvious next steps that would naturally fit somewhere on the backlog. They are not yet captured as numbered plans but are worth listing for transparency:

  • Persist open workspaces across restarts. Today AppView rebuilds with only the cwd as a workspace on launch; a workspaces: [] array in config.json plus a restore-on-startup pass would give continuity.
  • Draggable splitter between sidebar and terminal. The sidebar is a fixed 200 px wide today.
  • Mouse-driven session close. Currently keyboard-only (Ctrl+Shift+W). A small x button on hover would help mouse-driven users.
  • Search inside the scrollback. Alacritty has a regex-search facility; surfacing it through a small overlay would be a clean addition.
  • Per-workspace shell override. Today every PTY is the user's $SHELL. Allowing a per-workspace command override would unlock language-specific REPLs as the primary session.
  • Linux-only assumptions. The bell sound path and the paplay invocation are Linux-specific. macOS and Windows ports of the bell stack are pending.

If you want to pick one of these up, drop a numbered plan into docs/PLAN.md first — the project follows a "plan before code" discipline so that diffs stay focused and reviewable.

Contributing

There is no formal contribution process yet, but the project has clear conventions that apply equally to human contributors and to AI agents.

  • Read the plan first. Every multi-file change should be preceded by a plan, either in docs/PLAN.md (for small, numbered work) or as a dedicated docs/<feature>-plan.md (for multi-phase features). Plans are cheap to write and save rework.
  • Match existing module patterns. Cross-thread events use flume channels with cx.spawn consumers, ID types live in config.rs, new lists hang flat off AppView, floating UI follows the settings_pane.rs overlay pattern. Don't invent parallel patterns.
  • Format and test before declaring done. cargo fmt --check and cargo test are the bar. cargo clippy is recommended.
  • Keep the implementation notebook current. implementation-notes.html at the repo root is the running log of design decisions, deviations, tradeoffs, and open questions. Append a new dated <section> whenever you make a judgment call; see AGENTS.md for the exact shape.
  • No Co-Authored-By: trailers in commits. This project does not use them.
  • No --no-verify or destructive git operations (reset --hard, push --force, branch -D) without explicit instruction in the conversation.

See AGENTS.md for the full set of boundaries and conventions.

Continuous Integration

Two GitHub Actions workflows live under .github/workflows/.

  • ci.yml — runs on every push to main and on every pull request. Installs the Linux build dependencies, then executes cargo fmt --all -- --check, cargo clippy --all-targets -- -D warnings, cargo test --locked, and cargo build --locked. PRs should be green before merge.
  • release.yml — see Releasing below.

Both workflows target ubuntu-latest and use Swatinem/rust-cache so the GPUI dependency tree is not recompiled on every run.

Releasing

Releases are cut from GitHub Actions when a v* tag is pushed.

  1. Bump the version in Cargo.toml (and run cargo build to refresh Cargo.lock), then commit on main.

  2. Tag the commit and push the tag:

    git tag -a v0.1.0 -m "v0.1.0"
    git push origin v0.1.0
  3. The Release workflow:

    • builds quackcode with cargo build --release --locked against x86_64-unknown-linux-gnu,
    • strips the binary,
    • stages it alongside the qcode alias, LICENSE, README.md, and assets/ into quackcode-<version>-x86_64-unknown-linux-gnu.tar.gz,
    • writes a matching .sha256 file,
    • and creates a GitHub Release with auto-generated notes and both files attached.

The workflow can also be invoked manually from the Actions UI via workflow_dispatch. Manual runs build and upload the archive as a workflow artifact but do not create a GitHub Release — useful for smoke-testing the packaging path before tagging.

macOS and Windows targets are not currently part of the release matrix; they can be added when those platforms are actually tested against GPUI's runtime requirements.

Dependencies

Direct dependencies are deliberately few:

  • gpui — UI toolkit and rendering, originally from Zed.
  • alacritty_terminal — PTY and terminal emulation, the same crate Alacritty itself uses.
  • flume — Channels for cross-thread event delivery.
  • notify-rust — Desktop notifications for the bell pipeline.
  • serde and serde_json — Theme schema parsing and settings persistence.
  • dirs — Platform config directory discovery.

The planned preview-pane and Claude-session features will add chromiumoxide, uuid, notify, which, and url. None of these are present today.

Acknowledgements

License

Released under the MIT License. Copyright (c) 2026 HD Prajwal.

About

A personal AI coding agent, because I'm tired of waiting for official releases

Resources

License

Stars

Watchers

Forks

Packages

 
 
 

Contributors