Files
clide/legacy/CLAUDE.md
T
jpmschweitzerandClaude Opus 4.7 a355751437 move python clide to legacy/
Clide is being rebuilt as a Flutter desktop app. The Python Textual
implementation moves wholesale into legacy/ rather than being deleted:
its pane model, panel set, git skills, and panel communication design
are real thought that should remain readable next to the new code
while the rebuild finds its shape. Git's rename tracking preserves
history, so `git log -- legacy/` still works.

The Flutter rebuild lives at the repo root alongside a Go sidecar
(the architecture claudian was heading toward, which folds into
clide as a core component rather than a separate plugin project).
Bootstrap of the new shape lands in subsequent commits.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-04-20 20:30:51 +02:00

11 KiB

CLAUDE.md

This file provides guidance to Claude Code (claude.ai/code) when working with code in this repository.

Project Overview

Clide is a TUI IDE wrapper for Claude Code CLI, designed to be Claude-centric with VSCode-familiar keybindings. See docs/tui-ide-spec.md for full specification.

Design Principles

  • Claude-centric: Claude Code is the primary workspace, always visible
  • Contextual panels: Editor/Diff/Terminal appear only when needed
  • Alt-key shortcuts: Alt-based keybindings don't interfere with input fields
  • Responsive: Works on 13" laptop to widescreen monitors
  • State preservation: Hiding panels preserves all state (never destroy widgets)

Tech Stack

Component Library Version
Runtime Python 3.12+
TUI Framework Textual latest
CLI Typer latest
Data Validation Pydantic v2 (strict mode)
Settings pydantic-settings latest
Database SQLModel + SQLite latest
Web Server FastAPI + uvicorn latest
Testing pytest + pytest-asyncio + pytest-textual-snapshot latest
Extensions pluggy latest

Development Commands

Clide (TUI)

make setup          # Create venv, install deps
make run            # Run application
make test           # Run all tests
make test-single    # Run single test (TEST=path::test_name)
make typecheck      # Run mypy
make lint           # Run ruff check
make format         # Run ruff format
make build          # Build for current platform

clide-web (Web Server)

cd clide-web/
make setup          # Create venv, install deps, run setup wizard
make run            # Run the web server (foreground)
make dev            # Run with auto-reload
make start-server   # Start systemd service
make stop-server    # Stop systemd service
make restart-server # Restart systemd service
make status-server  # Show service status
make logs-server    # Tail service logs

Panel Architecture

┌─────────────────┬─────────────────────────┬──────────────────┐
│ panel-sidebar   │ panel-workspace (60%)   │ panel-context    │
│                 │ [Editor][Diff][Terminal]│                  │
│ [Files][Git]    │ (hidden when inactive)  │ [Problems][TODOs]│
│ [Tree]          ├─────────────────────────┤ [Jira]           │
│                 │                         │                  │
│ (content area)  │ panel-claude            │ (content area)   │
│                 │ (40% when workspace     │                  │
│                 │  visible, else 100%)    │                  │
├─────────────────┤                         ├──────────────────┤
│ ⎇ main ▾       │                         │ [⚠ 3][✓12][Jira]│
└─────────────────┴─────────────────────────┴──────────────────┘

Project Structure

clide/
├── clide/                        # Package source
│   ├── __init__.py
│   ├── __main__.py
│   ├── app.py                    # Main App, layout, keybindings
│   ├── cli.py                    # Typer entry point
│   ├── controllers/              # Domain logic (no UI)
│   ├── widgets/                  # UI components
│   │   ├── panels/               # Main layout containers
│   │   └── components/           # Reusable UI pieces
│   ├── models/                   # Pydantic data models
│   ├── services/                 # Background task logic
│   ├── themes/                   # Theme system
│   ├── extensions/               # Plugin system
│   └── helpers/                  # Utility functions
│
├── tests/
│   ├── conftest.py
│   ├── harnesses/
│   │   ├── app_harness.py
│   │   └── controller_harness.py
│   ├── unit/
│   ├── integration/
│   └── snapshots/
│
├── .config/                      # User config (gitignored)
│   ├── settings.toml             # User settings
│   └── themes/                   # Custom user themes
│       └── my-theme.toml
├── docs/
│   ├── tui-ide-spec.md           # Full UI/UX specification
│   ├── web-deployment.md         # Web deployment architecture
│   └── ARCHITECTURE.md           # Framework best practices
├── pyproject.toml
└── Makefile
│
clide-web/                        # Web server package (wraps clide)
├── clide_web/
│   ├── server.py                 # FastAPI app, routes, WebSocket handler
│   ├── sessions.py               # tmux session manager
│   ├── pty_bridge.py             # PTY ↔ WebSocket bridge
│   ├── config.py                 # Pydantic settings with DB overlay
│   ├── setup_wizard.py           # Interactive first-run config
│   └── static/
│       ├── index.html            # HTML page (toolbar + xterm.js)
│       └── vendor/               # Vendored xterm.js (offline)
├── pyproject.toml
└── Makefile

Key Patterns

Panel Visibility (Hide, Don't Destroy)

def toggle_workspace(self, visible: bool) -> None:
    workspace = self.query_one("#panel-workspace")
    workspace.display = visible  # Preserves all child state

    claude = self.query_one("#panel-claude")
    claude.styles.height = "40%" if visible else "100%"

Background Tasks

Use @work decorator for non-blocking operations:

@work(thread=True)
def refresh_git_status(self) -> None:
    result = subprocess.run(["git", "status", "--porcelain"], ...)
    self.call_from_thread(self.update_git_view, result.stdout)

Reactive State

class ClideApp(App):
    current_file: reactive[str | None] = reactive(None)
    workspace_visible: reactive[bool] = reactive(False)
    problem_count: reactive[int] = reactive(0)
    todo_count: reactive[int] = reactive(0)
    compact_mode: reactive[bool] = reactive(False)

Pydantic Models (Strict + Frozen)

from pydantic import BaseModel, ConfigDict

class GitChange(BaseModel):
    model_config = ConfigDict(strict=True, frozen=True)
    path: str
    status: Literal["added", "modified", "deleted", "untracked", "renamed"]
    staged: bool

Controller → Widget Communication

Controllers emit Textual messages; widgets subscribe:

# In controller
class GitStatusUpdated(Message):
    def __init__(self, status: GitStatus) -> None:
        self.status = status
        super().__init__()

self.post_message(GitStatusUpdated(status))

# In widget
def on_git_status_updated(self, event: GitStatusUpdated) -> None:
    self.refresh_view(event.status)

Theme System

Default Theme: Summer Night

Based on jackw01/summer-night-vscode-theme:

SUMMER_NIGHT = ThemeColors(
    primary="#00a3d2",      # cyan
    secondary="#00a9b9",    # teal
    accent="#fa5f8b",       # pink
    background="#21262f",   # mono_8
    surface="#393e48",      # mono_7
    panel="#292e38",
    foreground="#e2e8f5",   # mono_1
    success="#00ab9a",      # green
    warning="#d08447",      # orange
    error="#f06c6f",        # red
)

Built-in Themes (22 total)

Category Themes
Core summer-night (default), summer-day
Popular one-dark, one-dark-pro, one-light, dracula, nord, gruvbox-dark, gruvbox-light
GitKraken one-dark-teal, gamma
Seasonal - Winter winter-is-coming, monokai-winter
Seasonal - Fall fall, dark-autumn
Seasonal - Halloween all-hallows-eve, halloween
Seasonal - Christmas christmas, santa-baby
Hacker pro-hacker, hacker-style
Bonus houston

Theme Definition

class ThemeColors(BaseModel):
    model_config = ConfigDict(strict=True, frozen=True)
    primary: str       # Main accent
    secondary: str     # Secondary accent
    accent: str        # Highlight accent
    background: str    # Main background
    surface: str       # Elevated surfaces
    panel: str         # Panel backgrounds
    foreground: str    # Primary text
    success: str       # Success/green
    warning: str       # Warning/yellow
    error: str         # Error/red

class ThemeDefinition(BaseModel):
    name: str          # Identifier (e.g., "summer-night")
    display_name: str  # Human-readable name
    dark: bool         # Dark or light theme
    colors: ThemeColors

Custom Themes

Users can add themes in .config/themes/:

# .config/themes/my-theme.toml
name = "my-theme"
display_name = "My Custom Theme"
dark = true

[colors]
primary = "#007acc"
secondary = "#3c3c3c"
accent = "#0e639c"
background = "#1e1e1e"
surface = "#252526"
panel = "#2d2d30"
foreground = "#d4d4d4"
success = "#4ec9b0"
warning = "#dcdcaa"
error = "#f44747"

Theme Switching

  • Keybinding: Ctrl+K Ctrl+T
  • Settings: theme = "summer-night" in ClideSettings
  • Runtime: app.theme = "dracula"

Keybindings (Alt-based)

Action Binding
Quit Alt+Q
Command palette Alt+P
Quick open Alt+O
Toggle left sidebar Alt+B
Toggle right sidebar Alt+Shift+B
Toggle terminal Alt+`
Focus Claude Alt+1
Focus Editor Alt+2
Focus Terminal Alt+3
Toggle compact mode Alt+C
Git panel Alt+G
Problems panel Alt+M
Select theme Alt+T
Save file Alt+S

Configuration

Settings are loaded from multiple sources (in priority order):

  1. Environment variables (CLIDE_*)
  2. .config/settings.toml
  3. Defaults in ClideSettings
class ClideSettings(BaseSettings):
    model_config = SettingsConfigDict(
        env_prefix="CLIDE_",
        env_file=".env",
        extra="ignore",
    )

    theme: str = "summer-night"
    jira_enabled: bool = False
    jira_cli_path: str = "jira"

    panels: PanelConfig = PanelConfig()
    keybindings: KeybindingsConfig = KeybindingsConfig()

Core Stack

Testing

Extensions

Build

Theme References