docs: update documentation and fix lint issues for v1.0.0

Documentation:
- Rewrite README.md with current features and git operations
- Rewrite docs/ARCHITECTURE.md with layered architecture details
- Rewrite docs/tui-ide-spec.md with Alt-key shortcuts
- Add docs/code-organization.md for component architecture
- Add docs/user-manual.md for end users
- Update TODO.md to mark completed items

Code fixes:
- Fix undefined 'event' variable in diff_pane.py (was _event)
- Use ternary operator in editor.py save_file method
- Clean up imports in claude_events.py and syntax_service.py
- Auto-fix import sorting across multiple files

Config:
- Add snapshot report path to pyproject.toml pytest options
- Exclude clide/vendor from ruff linting
- Ignore TCH002/TCH003 type-checking import rules

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
This commit is contained in:
Jeroen Schweitzer
2026-02-01 22:02:00 +01:00
co-authored by Claude Opus 4.5
parent 2d2e5f5648
commit 8b1a84e7e2
20 changed files with 1574 additions and 834 deletions
+273 -256
View File
@@ -1,11 +1,11 @@
# Clide Architecture Documentation
# Clide Architecture
Comprehensive documentation of architecture patterns, best practices, and implementation guidelines.
Technical documentation covering Clide's architecture, the frameworks it builds on, and implementation patterns.
## Table of Contents
- [Application Architecture](#application-architecture)
- [Textual TUI Framework](#textual-tui-framework)
- [Typer CLI Framework](#typer-cli-framework)
- [Pydantic Data Validation](#pydantic-data-validation)
- [Extension System](#extension-system)
- [Testing Strategy](#testing-strategy)
@@ -13,199 +13,238 @@ Comprehensive documentation of architecture patterns, best practices, and implem
---
## Application Architecture
Clide follows a layered architecture with clear separation between UI, business logic, and data.
### Layer Overview
```
┌─────────────────────────────────────────────────────────┐
│ ClideApp (app.py) │
│ Main application, layout, keybindings │
├─────────────────────────────────────────────────────────┤
│ Widgets Layer │
│ ┌─────────────┐ ┌─────────────┐ ┌─────────────┐ │
│ │ Panels │ │ Components │ │ Themes │ │
│ │ (layout) │ │ (reusable) │ │ (styling) │ │
│ └─────────────┘ └─────────────┘ └─────────────┘ │
├─────────────────────────────────────────────────────────┤
│ Controllers Layer │
│ Business logic, state management │
├─────────────────────────────────────────────────────────┤
│ Services Layer │
│ Git, files, scanning, settings, skills │
├─────────────────────────────────────────────────────────┤
│ Models Layer │
│ Pydantic data structures │
└─────────────────────────────────────────────────────────┘
```
### Data Flow
```
User Action (click, keypress)
Widget Event
Message Bubbles Up
App Event Handler
Controller Method
Service Call
Return Data/Status
Update UI State
Reactive UI Update
```
### Key Patterns
**Message-based communication** — Widgets emit messages that bubble up. Parent widgets or the app handle messages and coordinate responses.
**Reactive properties** — UI state uses Textual's `reactive` type. Changes automatically trigger `watch_*` methods.
**Background workers** — Long operations use `@work(thread=True)` to avoid blocking the UI.
**State preservation** — Hiding panels uses `display: none`, never destroying widgets. All state persists.
For detailed code organization, see [Code Organization](code-organization.md).
---
## Textual TUI Framework
Textual models TUIs as a reactive tree of widgets, similar to React's component tree but grid-based on character cells.
Textual provides the foundation for Clide's terminal UI.
### Key Concepts
### Core Concepts
**Widgets and Containers**
- Widgets are the building blocks of the UI
- Containers are widgets that hold other widgets
- Default layout stacks widgets vertically from top of screen
**Widgets** — Building blocks of the UI. Everything visible is a widget.
**Reactive Programming**
- State changes trigger automatic UI updates
- No manual refresh loops needed
- Use reactive attributes for state management
**Containers** — Widgets that hold other widgets (Vertical, Horizontal, Container).
**Event-Driven Model**
- Define callbacks for key presses, mouse clicks, timer ticks
- Actions are functions callable via keystroke or text link
**Reactive Programming** — State changes trigger automatic UI updates.
### Best Practices
**CSS Styling** — Layout and appearance defined in CSS, similar to web development.
1. **Use Immutable Objects**
- Prefer tuples, NamedTuples, or frozen dataclasses
- Easier to reason about, cache, and test
- Enables side-effect-free code
### Layout System
2. **Separate Styles**
- Keep CSS in `.tcss` files, not inline
- Python code stays clean and focused on logic
Clide uses CSS Grid for the main layout:
3. **Async-First**
- Textual is async under the hood
- Use `async`/`await` for I/O operations
- Can integrate with async libraries if needed
### Layout Management
```python
# Grid layout example
CSS = """
```css
Screen {
layout: grid;
grid-size: 3 1;
grid-columns: 1fr 2fr 1fr;
grid-columns: 20% 1fr 25%;
}
"""
```
Panels use percentage widths with minimum sizes:
```css
#panel-sidebar {
width: 20%;
min-width: 25;
}
```
### Widget Lifecycle
```python
class MyWidget(Widget):
def __init__(self):
super().__init__()
# Initialize instance variables
def compose(self) -> ComposeResult:
# Yield child widgets
yield Label("Hello")
def on_mount(self) -> None:
# Called after widget is added to DOM
# Safe to query other widgets here
def on_unmount(self) -> None:
# Cleanup when removed
```
### Event Handling
Events bubble up through the widget tree:
```python
# Define a message
class FileSelected(Message):
def __init__(self, path: Path):
self.path = path
super().__init__()
# Emit the message
self.post_message(self.FileSelected(path))
# Handle in parent (naming convention: on_<widget>_<message>)
def on_files_view_file_selected(self, event: FilesView.FileSelected):
self.open_file(event.path)
```
### Background Tasks
Use `@work` for operations that shouldn't block the UI:
```python
from textual import work
@work(thread=True)
def fetch_data(self) -> dict:
"""Runs in thread pool."""
result = expensive_operation()
return result
def on_worker_state_changed(self, event: Worker.StateChanged) -> None:
if event.state == WorkerState.SUCCESS:
self.update_ui(event.worker.result)
```
### References
- [Textual Documentation](https://textual.textualize.io/)
- [Textual Tutorial](https://textual.textualize.io/tutorial/)
- [Real Python Textual Guide](https://realpython.com/python-textual/)
- [Textual GitHub](https://github.com/Textualize/textual)
---
## Typer CLI Framework
Typer is built on Click with Python type hints for automatic argument parsing.
### Project Structure Pattern
```
app/
├── __init__.py
├── main.py # Root Typer app
├── commands/ # Subcommand modules
│ ├── users.py
│ └── tasks.py
└── helpers/ # Shared utilities
└── validate.py
```
### Best Practices
1. **Organize Commands**
- Use `add_typer()` to group commands
- Avoid giant files with dozens of commands
- Each command function should orchestrate, not contain all logic
2. **Entry Point Support**
- Add `__main__.py` for `python -m` support
- Define entry points in pyproject.toml for CLI scripts
3. **Standard Exit Codes**
- `0` for success
- Non-zero for errors
- Crucial for CI/CD integration
4. **Type Hints for Validation**
- Use Enum for dropdown-style restrictions
- Type hints provide editor autocompletion
### Subcommand Example
```python
# commands/users.py
import typer
app = typer.Typer()
@app.command()
def create(name: str):
"""Create a new user."""
...
# main.py
from commands import users
main_app = typer.Typer()
main_app.add_typer(users.app, name="users")
```
### References
- [Typer Documentation](https://typer.tiangolo.com/)
- [Typer Subcommands](https://typer.tiangolo.com/tutorial/subcommands/)
- [Building a Package](https://typer.tiangolo.com/tutorial/package/)
- [Textual Widgets](https://textual.textualize.io/widgets/)
- [Textual CSS](https://textual.textualize.io/guide/CSS/)
---
## Pydantic Data Validation
Pydantic v2 with strict mode ensures type safety and validation.
All data models use Pydantic v2 with strict mode.
### Strict Mode Configuration
### Model Configuration
```python
from pydantic import BaseModel, ConfigDict
class MyModel(BaseModel):
class GitChange(BaseModel):
model_config = ConfigDict(strict=True, frozen=True)
name: str
count: int # Will reject "123" string
path: str
status: Literal["added", "modified", "deleted"]
staged: bool
```
**strict=True** — No type coercion. `"123"` won't become `123`.
**frozen=True** — Immutable instances. Enables hashing for use as dict keys.
### Settings Management
Settings have moved to `pydantic-settings` package:
Application settings use `pydantic-settings`:
```python
from pydantic_settings import BaseSettings, SettingsConfigDict
class AppSettings(BaseSettings):
class ClideSettings(BaseSettings):
model_config = SettingsConfigDict(
env_prefix="APP_",
env_prefix="CLIDE_",
env_file=".env",
env_nested_delimiter="__",
)
database_url: str
debug: bool = False
theme: str = "summer-night"
jira_enabled: bool = False
```
### Best Practices
1. **Use `frozen=True` for Immutability**
- Prevents accidental mutation
- Enables hashing for use as dict keys
2. **Explicit Strict Types**
- `StrictInt`, `StrictStr` for field-level strictness
- Or use `model_config` for model-wide strictness
3. **Validation vs Parsing**
- Strict mode rejects type coercion
- JSON parsing allows some conversion (ISO8601 → datetime)
Settings load from (in priority order):
1. Environment variables (`CLIDE_THEME=dracula`)
2. `.env` file
3. Default values
### References
- [Pydantic v2 Documentation](https://docs.pydantic.dev/latest/)
- [Pydantic Documentation](https://docs.pydantic.dev/latest/)
- [Pydantic Settings](https://docs.pydantic.dev/latest/concepts/pydantic_settings/)
- [Pydantic Configuration](https://docs.pydantic.dev/latest/api/config/)
- [Migration Guide](https://docs.pydantic.dev/latest/migration/)
---
## Extension System
The plugin system uses Pluggy for hook-based extensibility.
Clide uses Pluggy for hook-based extensibility.
### Pluggy Concepts
### Hook Specifications
1. **Hook Specifications** - Define the interface extensions implement
2. **Hook Implementations** - Extension code implementing hooks
3. **Plugin Manager** - Discovers and calls implementations
### Architecture
Hooks define extension points:
```python
# hookspecs.py - Define hooks
# clide/extensions/hookspecs.py
import pluggy
hookspec = pluggy.HookspecMarker("clide")
@@ -213,18 +252,36 @@ hookimpl = pluggy.HookimplMarker("clide")
class ClideHookSpec:
@hookspec
def register_panel(self) -> dict: ...
def clide_startup(self, app: App) -> None:
"""Called when the app starts."""
@hookspec
def clide_on_file_changed(self, event: FileEvent) -> None:
"""Called when a file changes."""
```
### Implementing Hooks
Extensions implement hooks with the `@hookimpl` decorator:
```python
from clide.extensions import hookimpl
# extension.py - Implement hooks
class MyExtension:
@hookimpl
def register_panel(self) -> dict:
return {"name": "custom", "widget": CustomWidget}
def clide_startup(self, app: App) -> None:
app.notify("Extension loaded!")
@hookimpl
def clide_on_file_changed(self, event: FileEvent) -> None:
if event.path.suffix == ".py":
# React to Python file changes
pass
```
### Distribution
Extensions can be distributed as packages using entry points:
Extensions can be packaged and distributed via entry points:
```toml
# pyproject.toml of extension package
@@ -232,55 +289,73 @@ Extensions can be distributed as packages using entry points:
my_extension = "my_package:MyExtension"
```
### Hook Execution Order
### Available Hooks
- Multiple implementations called in LIFO (Last In, First Out) order
- Use `hookimpl(tryfirst=True)` or `hookimpl(trylast=True)` for ordering
### Alternatives
- **Stevedore** - Better for driver/extension patterns, uses entry points
- Choose Pluggy for hook-based systems (like pytest uses)
| Hook | When Called |
|------|-------------|
| `clide_startup` | App initialization |
| `clide_shutdown` | App cleanup |
| `clide_on_file_changed` | File created/modified/deleted |
| `clide_on_file_saved` | File saved in editor |
### References
- [Pluggy Documentation](https://pluggy.readthedocs.io/)
- [Stevedore Documentation](https://docs.openstack.org/stevedore/latest/)
- [Creating Plugins with Stevedore](https://docs.openstack.org/stevedore/latest/user/tutorial/creating_plugins.html)
---
## Testing Strategy
### pytest-asyncio
### Test Organization
Configure auto mode for automatic async test discovery:
```
tests/
├── unit/ # Isolated component tests
├── integration/ # Component interaction tests
└── snapshots/ # Visual regression tests
```
### Async Testing
Configure pytest-asyncio in auto mode:
```toml
# pyproject.toml
[tool.pytest.ini_options]
asyncio_mode = "auto"
```
### Async Test Patterns
Tests can be async without decorators:
```python
import pytest
# Auto mode - no decorator needed
async def test_async_operation():
result = await some_async_function()
assert result == expected
# Async fixtures
@pytest.fixture
async def database_connection():
conn = await create_connection()
yield conn
await conn.close()
```
### Async Mocking
### Snapshot Testing
Visual regression testing with pytest-textual-snapshot:
```python
def test_layout(snap_compare):
assert snap_compare(ClideApp(), terminal_size=(120, 40))
def test_with_interaction(snap_compare):
async def setup(pilot):
await pilot.press("tab", "enter")
assert snap_compare(ClideApp(), run_before=setup)
```
Update snapshots after intentional changes:
```bash
pytest tests/snapshots/ --snapshot-update
```
### Mocking
Use `AsyncMock` for async dependencies:
```python
from unittest.mock import AsyncMock
@@ -291,73 +366,43 @@ async def test_with_mock():
assert result["status"] == "ok"
```
### Snapshot Testing
Visual regression with pytest-textual-snapshot:
```python
def test_layout(snap_compare):
assert snap_compare("app.py", terminal_size=(120, 40))
def test_with_interaction(snap_compare):
async def setup(pilot):
await pilot.press("tab", "enter")
assert snap_compare("app.py", run_before=setup)
```
Update snapshots after intentional changes:
```bash
pytest tests/snapshots/ --snapshot-update
```
### Test Harness Pattern
Harnesses provide isolated test environments:
```python
class AppHarness:
async def start(self) -> tuple[App, Pilot]:
"""Start app with mocked dependencies."""
async def stop(self) -> None:
"""Clean shutdown."""
```
### Best Practices
1. **Always use `@pytest.mark.asyncio`** (or auto mode)
2. **Use async fixtures** for async setup/teardown
3. **Mock external services** - don't hit real APIs
4. **Choose appropriate fixture scopes** for performance
5. **Avoid blocking the event loop** in async tests
### References
- [pytest-asyncio Documentation](https://pytest-asyncio.readthedocs.io/en/latest/)
- [pytest-asyncio](https://pytest-asyncio.readthedocs.io/)
- [pytest-textual-snapshot](https://github.com/Textualize/pytest-textual-snapshot)
- [Textual Testing Guide](https://textual.textualize.io/guide/testing/)
- [pytest Fixtures](https://docs.pytest.org/en/stable/how-to/fixtures.html)
---
## Build and Distribution
### PyInstaller Limitations
### Development
**Critical: PyInstaller cannot cross-compile.**
- Build on the target OS
- Use CI/CD for multi-platform builds
```bash
make setup # Create venv, install deps
make run # Run application
make test # Run all tests
make typecheck # Run mypy
make lint # Run ruff
make format # Format code
```
### CI/CD Multi-Platform Build
### PyInstaller
Use Gitea Actions (or compatible CI) for multi-platform builds:
Build standalone executables:
```bash
pip install -e ".[build]"
pyinstaller clide.spec --clean
```
**Important**: PyInstaller cannot cross-compile. Build on each target platform.
### CI/CD
Multi-platform builds via Gitea Actions:
```yaml
# .gitea/workflows/build.yml
name: Build
on: [push, tag]
jobs:
build-linux:
runs-on: ubuntu-latest
@@ -371,45 +416,17 @@ jobs:
build-macos:
runs-on: macos-latest
steps:
- uses: actions/checkout@v4
- uses: actions/setup-python@v5
with:
python-version: '3.12'
- run: pip install -e ".[build]"
- run: pyinstaller clide.spec --clean
build-windows:
runs-on: windows-latest
steps:
- uses: actions/checkout@v4
- uses: actions/setup-python@v5
with:
python-version: '3.12'
- run: pip install -e ".[build]"
- run: pyinstaller clide.spec --clean
# ... same steps
```
### Optimization Tips
### Optimization
1. **Use `--onefile`** for single executable
2. **Apply `--strip`** to reduce binary size
3. **Use UPX compression** (460 MB → ~130 MB possible)
4. **Exclude unused modules** with `--exclude-module`
5. **Lazy imports** for large libraries
### Platform-Specific Output
- **Windows**: `.exe` or MSIX installer
- **macOS**: `.app` bundle in `.dmg`
- **Linux**: AppImage or native package
### Linux Compatibility
Build on the oldest target distro version. Newer systems may produce incompatible binaries.
- Use `--onefile` for single executable
- Apply `--strip` to reduce size
- Use UPX compression for further reduction
- Exclude unused modules with `--exclude-module`
### References
- [PyInstaller Documentation](https://pyinstaller.org/)
- [Building the Bootloader](https://pyinstaller.org/en/latest/bootloader-building.html)
- [Gitea Actions](https://docs.gitea.com/usage/actions/overview)
+342
View File
@@ -0,0 +1,342 @@
# Code Organization
Clide follows a layered architecture separating UI components from business logic, enabling testability and maintainability.
## Directory Structure
```
clide/
├── app.py # Main application, layout, keybindings
├── cli.py # Typer entry point
├── models/ # Pydantic data models
├── services/ # Background services and utilities
├── controllers/ # Business logic (no UI)
├── widgets/
│ ├── panels/ # Main layout containers
│ └── components/ # Reusable UI pieces
├── themes/ # Theme definitions and registry
├── extensions/ # Plugin system (hookspecs, manager)
├── templates/ # Bundled templates (skills, etc.)
└── vendor/ # Vendored dependencies (pyte)
```
## Layers
### Models (`clide/models/`)
Pure data structures using Pydantic with strict mode. Models are immutable and contain no business logic.
```python
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
```
**Key models:**
- `git.py` — Git-related types (GitBranch, GitCommit, GitChange, GitStatus)
- `config.py` — Application settings (ClideSettings, PanelConfig)
- `problems.py` — Linter output (Problem, Severity)
- `todos.py` — TODO items (TodoItem, ProjectTodoItem, TodoType)
### Services (`clide/services/`)
Stateless utilities that perform work without UI interaction. Services may be async or use background threads.
```python
class GitService:
"""Git operations via subprocess."""
def __init__(self, workdir: Path):
self._workdir = workdir
async def get_status(self) -> GitStatus:
"""Get current repository status."""
...
async def get_branches(self) -> list[GitBranch]:
"""List all branches."""
...
```
**Key services:**
- `git_service.py` — Git CLI operations
- `file_service.py` — File read/write operations
- `todo_scanner.py` — Scans codebase for TODO/FIXME comments
- `settings_service.py` — User settings persistence
- `skill_installer.py` — Claude Code skill management
- `file_watcher.py` — File system change monitoring
- `syntax_service.py` — Tree-sitter syntax highlighting
### Controllers (`clide/controllers/`)
Bridge between services and UI. Controllers contain business logic, manage state, and emit Textual messages. Controllers have no direct UI rendering.
```python
from clide.controllers.base import controller
@controller
class GitController:
"""Manages git state and operations."""
def __init__(self, workdir: Path):
self._service = GitService(workdir)
self._status: GitStatus | None = None
async def refresh_status(self) -> GitStatus:
"""Refresh and cache git status."""
self._status = await self._service.get_status()
return self._status
def stage_file(self, path: str) -> None:
"""Stage a file for commit."""
...
```
**Key controllers:**
- `git.py` — Git operations, skill integration
- `editor.py` — File editing state
- `diff.py` — Diff viewing and management
- `problems.py` — Linter integration
- `todos.py` — TODO tracking
- `jira.py` — Jira CLI integration
### Widgets (`clide/widgets/`)
UI components split into panels (layout containers) and components (reusable pieces).
#### Panels (`clide/widgets/panels/`)
Top-level layout containers that compose the application UI.
```python
class SidebarPanel(Vertical):
"""Left sidebar with Files, Git, and Tree tabs."""
class FileSelected(Message):
"""Emitted when a file is selected."""
def __init__(self, path: Path):
self.path = path
super().__init__()
def compose(self) -> ComposeResult:
with TabbedContent():
with TabPane("Files"):
yield FilesView(path=self._workdir)
with TabPane("Git"):
yield GitChangesView()
with TabPane("Tree"):
yield GitGraphView()
yield BranchStatus()
```
**Panels:**
- `sidebar.py` — Left sidebar (files, git, graph)
- `context.py` — Right sidebar (problems, todos, jira)
- `workspace.py` — Center workspace (editor, diff, terminal)
- `claude.py` — Claude Code terminal integration
#### Components (`clide/widgets/components/`)
Reusable UI pieces composed into panels.
**File browsing:**
- `files_view.py` — Project file tree
- `file_entry.py` — Single file/directory entry
**Git:**
- `git_changes.py` — Staged/unstaged file lists
- `git_graph.py` — Visual branch graph
- `branch_status.py` — Branch indicator with popout selector
**Context:**
- `problems_view.py` — Linter problems list
- `todos_view.py` — TODO/FIXME list with sub-tabs
- `jira_view.py` — Jira issue display
**Editor:**
- `editor_pane.py` — Code editor with syntax highlighting
- `diff_pane.py` — Side-by-side diff viewer
- `terminal_pane.py` — Command execution terminal
## Communication Patterns
### Message Flow
Components communicate via Textual's message system. Messages bubble up through the widget tree.
```
Component emits message
Parent panel receives and may re-emit
App handles and coordinates response
App calls controller methods
Controller updates state, may emit messages
UI updates reactively
```
**Example: File selection**
```python
# In FilesView (component)
class FileSelected(Message):
def __init__(self, path: Path):
self.path = path
super().__init__()
def on_tree_node_selected(self, event):
if event.node.data.is_file:
self.post_message(self.FileSelected(event.node.data.path))
# In SidebarPanel (panel)
def on_files_view_file_selected(self, event: FilesView.FileSelected):
# Re-emit for app to handle
self.post_message(self.FileSelected(event.path))
# In ClideApp (app)
def on_sidebar_panel_file_selected(self, event: SidebarPanel.FileSelected):
self.editor_controller.open_file(event.path)
self.show_workspace("editor")
```
### Reactive Properties
State that affects UI uses Textual's reactive system:
```python
class ClideApp(App):
# Reactive state
workspace_visible: reactive[bool] = reactive(False)
problem_count: reactive[int] = reactive(0)
current_branch: reactive[str] = reactive("main")
def watch_workspace_visible(self, visible: bool) -> None:
"""React to workspace visibility changes."""
workspace = self.query_one("#panel-workspace")
workspace.display = visible
claude = self.query_one("#panel-claude")
claude.styles.height = "40%" if visible else "100%"
```
### Background Tasks
Long-running operations use the `@work` decorator to avoid blocking the UI:
```python
from textual import work
class ClideApp(App):
@work(thread=True)
def refresh_git_status(self) -> None:
"""Refresh git status in background."""
status = self.git_controller.get_status_sync()
self.call_from_thread(self._update_git_ui, status)
def _update_git_ui(self, status: GitStatus) -> None:
"""Update UI with git status (runs on main thread)."""
sidebar = self.query_one(SidebarPanel)
sidebar.update_git_status(status.staged, status.unstaged)
```
## Extension System
Clide uses Pluggy for extensibility. Extensions implement hooks defined in `hookspecs.py`.
```python
# clide/extensions/hookspecs.py
class ClideHookSpec:
@hookspec
def clide_startup(self, app: App) -> None:
"""Called when app starts."""
@hookspec
def clide_on_file_changed(self, event: FileEvent) -> None:
"""Called when a file changes."""
# User extension
class MyExtension:
@hookimpl
def clide_on_file_changed(self, event: FileEvent) -> None:
if event.path.suffix == ".py":
# Custom logic for Python files
...
```
**Available hooks:**
- `clide_startup` — App initialization
- `clide_shutdown` — App cleanup
- `clide_on_file_changed` — File system changes
- `clide_on_file_saved` — File saved in editor
## Skills System
Clide integrates with Claude Code skills for git operations. Skills are installed to the project's `.claude/skills/` directory.
```python
# clide/services/skill_installer.py
class SkillInstaller:
def install(self, skill_name: str, scope: Literal["user", "project"] = "project"):
"""Install a skill from bundled templates."""
template_dir = TEMPLATES_DIR / skill_name
target_dir = self.project_skills_dir / skill_name
shutil.copytree(template_dir, target_dir)
```
**Bundled skills** (`clide/templates/skills/`):
- `commit` — Git commit workflow
- `stash` — Git stash operations
- `pull` — Git pull with rebase
- `push` — Git push to remote
- `branch` — Branch management
When a git action button is clicked, Clide ensures the skill is installed before sending the command to Claude.
## Testing
Tests mirror the source structure:
```
tests/
├── unit/
│ ├── test_models.py
│ ├── test_services.py
│ ├── test_controllers.py
│ ├── test_widgets.py
│ └── test_app.py
├── integration/
│ └── test_files_view.py
└── snapshots/
└── test_app_snapshots.py
```
**Unit tests** verify individual components in isolation.
**Integration tests** verify component interactions.
**Snapshot tests** catch visual regressions using pytest-textual-snapshot.
## Configuration
### Application Settings
`ClideSettings` in `clide/models/config.py` defines app configuration loaded from environment or `.config/settings.toml`.
### User Settings
`UserSettings` persisted to `~/.clide/settings.json` stores user preferences:
- Theme selection
- Panel visibility defaults
- Compact mode preference
- Jira integration settings
+155 -292
View File
@@ -1,14 +1,14 @@
# TUI IDE Specification
A terminal-based IDE built with Textual, designed to wrap Claude Code and integrate project management tooling (Jira/Confluence via CLI).
Design specification for Clide's terminal user interface. This document describes the layout, interactions, and design decisions.
## Design Principles
- **Claude-centric**: Claude Code is the primary workspace, always visible
- **Contextual panels**: Editor/Diff/Terminal appear only when needed
- **VSCode-familiar**: Keybindings and interaction patterns follow VSCode conventions
- **Responsive**: Works on 13" laptop and widescreen monitors
- **No vim magic**: Standard keyboard navigation, no modal editing
- **Claude-centric** Claude Code is the primary workspace, always visible
- **Contextual panels** Editor/Diff/Terminal appear only when needed
- **Alt-key shortcuts** — Keybindings use Alt to avoid conflicts with Claude Code input
- **Responsive** Works on 13" laptops to widescreen monitors
- **State preservation** — Hiding panels preserves all state (never destroy widgets)
---
@@ -19,112 +19,105 @@ A terminal-based IDE built with Textual, designed to wrap Claude Code and integr
```
┌─────────────────┬─────────────────────────┬──────────────────┐
│ panel-sidebar │ panel-workspace (60%) │ panel-context │
│ [Editor][Diff][Terminal]│
[Files][Git] │ (hidden when inactive) │ (content area)
│ [Tree] ├─────────────────────────┤
│ │
(content area) │ panel-claude │ │
│ (40% when workspace │
20% │ [Editor][Diff][Terminal]│ 25%
│ (hidden when inactive) │
│ [Files][Git] ├─────────────────────────┤ [Jira][TODOs]
[Tree] │ │ [Problems]
│ panel-claude │ │
(content area) │ (40% when workspace │ (content area)
│ │ visible, else 100%) │ │
├─────────────────┤ ├──────────────────┤
│ branch-status │ │[⚠ 3][✓12][Jira]
│ ⎇ main ▾ │ │ context-tabs
│ branch-status │ │
│ ⎇ main ▾ │ │
│ staged: 2 │ │ │
└─────────────────┴─────────────────────────┴──────────────────┘
```
### Panel Definitions
### Panel IDs
```python
PANELS = {
# Left sidebar
"sidebar": "panel-sidebar",
"sidebar-files": "panel-sidebar-files",
"sidebar-git": "panel-sidebar-git",
"sidebar-tree": "panel-sidebar-tree",
"branch-status": "panel-branch-status",
# Center
"claude": "panel-claude",
"workspace": "panel-workspace",
"editor": "panel-editor",
"diff": "panel-diff",
"terminal": "panel-terminal",
# Right context
"context": "panel-context",
"context-jira": "panel-context-jira",
"context-problems": "panel-context-problems",
"context-todos": "panel-context-todos",
}
```
---
## Left Sidebar (`panel-sidebar`)
## Left Sidebar
### Tabs
| Tab | Content | Widget |
|-----|---------|--------|
| Files | Project file tree | `DirectoryTree` |
| Git | Staged/Unstaged changes | `GitChangesView` (custom) |
| Tree | Merge/branch graph | `GitGraphView` (custom) |
| Tab | Content | Purpose |
|-----|---------|---------|
| Files | Project file tree | Navigate and open files |
| Git | Staged/Unstaged changes | Review and manage changes |
| Tree | Branch graph | Visualize git history |
### Git Tab Details
### Git Tab
Two collapsible sections:
- **Staged**: Files in index, ready to commit
- **Unstaged**: Modified/untracked files
Two collapsible sections showing staged and unstaged changes.
Each file item shows:
- Status icon: `+` added, `~` modified, `-` deleted, `?` untracked, `→` renamed
- File path (relative)
**File status indicators:**
- `+` Added
- `~` Modified
- `-` Deleted
- `?` Untracked
- `→` Renamed
**Interactions:**
- Click file → opens in Editor panel
- Double-click or keybind → stage/unstage file
- Right-click or keybind → show context menu (discard, diff, etc.)
**Action buttons:**
- **Commit** — Delegate to Claude with `/commit` skill
- **Stash** — Delegate to Claude with `/stash` skill
- **Pull** — Delegate to Claude with `/pull` skill
- **Push** — Delegate to Claude with `/push` skill
### Tree Tab Details
### Tree Tab
Renders `git log --graph --oneline --decorate --all` with visual styling.
Visual git graph using box-drawing characters:
**Polish item**: Consider custom rendering with box-drawing characters for a cleaner look:
```
──┬── main: Latest commit message
●── feature: Feature work
●──┴── Merge branch 'feature'
◆───── Tagged release v1.0
● main: Latest commit message
├─● feature: Feature work
●─┴ Merge branch 'feature'
◆ Tagged release v1.0
```
Use canvas or rich text with:
```python
GRAPH_CHARS = {
'commit': '',
'merge': '',
'line': '',
'branch': '├──',
'join': '┴──',
}
```
**Symbols:**
- `●` Regular commit
- `◆` Merge commit
- `│` Branch line
- `├` Branch point
- `┴` Merge point
### Branch Status Bar
Fixed at bottom of sidebar. Shows current branch with popout toggle.
Fixed at bottom of sidebar. Shows current branch and git stats.
```
┌─────────────────────────────────┐
│ ⎇ main ▾ staged: 2 unstaged: 5│
└─────────────────────────────────┘
```
Click to expand branch selector:
```
┌─────────────────┐
│ ⎇ main ▾ │ ← Click or keybind to expand
└─────────────────┘
▼ (popout overlay)
┌─────────────────┐
│ Recent branches │
main │
main │
│ ○ feature/xyz │
│ ○ develop │
├─────────────────┤
[Checkout] [New]│
│[Checkout] [New]
└─────────────────┘
```
@@ -132,232 +125,162 @@ Fixed at bottom of sidebar. Shows current branch with popout toggle.
## Center Column
### Claude Panel (`panel-claude`)
### Claude Panel
The primary workspace. Displays Claude Code interaction.
The primary workspace. Always visible.
**Default state**: 100% height of center column
**With workspace**: 40% height (bottom)
**Default state:** 100% height of center column
**With workspace:** 40% height (bottom)
**Content:**
- Streaming markdown responses (use `Markdown` or `RichLog` widget)
- Visual distinction between:
- Claude's responses
- Tool calls / file operations
- User input
- Input area at bottom
- Full PTY terminal running Claude Code CLI
- Scrollback history (1000 lines)
- Input at bottom
### Workspace Panel (`panel-workspace`)
### Workspace Panel
Tabbed container for Editor, Diff, and Terminal. **Hidden by default.**
Tabbed container for Editor, Diff, and Terminal. Hidden by default.
**Important**: Hiding is not closing. All panels retain state when hidden:
- Editor: Open files, cursor position, scroll position, unsaved changes
**Visibility principle:** Hiding is not closing. All panels retain state:
- Editor: Open file, cursor position, scroll, unsaved changes
- Diff: Current diff content, scroll position
- Terminal: Active session, command history, output buffer
Use `display: none` for visibility, never destroy/recreate widgets.
- Terminal: Command history, output buffer
**Visibility triggers:**
| Trigger | Result |
|---------|--------|
| Click file in sidebar | Show workspace, focus Editor tab |
| Claude proposes changes | Show workspace, focus Diff tab |
| User presses `` Ctrl+` `` | Show workspace, focus Terminal tab |
| User runs command | Show workspace, focus Terminal tab |
| Close all tabs / Escape | Hide workspace, Claude reclaims space |
**Height**: 60% of center column when visible
| Click file in sidebar | Show workspace, focus Editor |
| Click problem/TODO | Show workspace, focus Editor at line |
| Press `` Alt+` `` | Show workspace, focus Terminal |
| Close all content | Hide workspace, Claude reclaims space |
#### Editor Tab
- `TextArea` widget with syntax highlighting
- Language detection from file extension
- Theme: Follow terminal theme or user preference
Code editor with:
- Syntax highlighting (tree-sitter based)
- Line numbers
- Current line highlighting
#### Diff Tab
- Side-by-side or unified diff view
- Syntax highlighting for changed content
- Accept/Reject buttons for Claude-proposed changes
Side-by-side diff viewer for:
- Git changes (staged and unstaged)
- Claude-proposed edits
#### Terminal Tab
- Proper PTY integration for full terminal emulation
- Or simpler command runner with output display (decide based on complexity)
Command execution terminal:
- Working directory tied to project root
- Output preserved when panel hidden
---
## Right Sidebar (`panel-context`)
## Right Context Panel
### Content Area
### Tabs
Switches based on selected bottom tab. Shows one of:
- Jira view (default)
- Problems view
- TODOs view
| Tab | Badge | Content |
|-----|-------|---------|
| Jira | — | Jira issue display |
| TODOs | Count | TODO/FIXME from code and TODO.md |
| Problems | Count | Linter errors and warnings |
### Bottom Tab Bar (`context-tabs`)
Tab badges update reactively as counts change.
```
┌──────────────────┐
│ [⚠ 3][✓12][Jira]│
└──────────────────┘
```
### Jira Tab
Tabs show inline counts that update reactively.
Displays Jira issues via CLI integration. Manual refresh button.
| Tab | Icon | Content |
|-----|------|---------|
| Problems | ⚠ | Linter errors, warnings (count badge) |
| TODOs | ✓ | TODO/FIXME comments from codebase (count badge) |
| Jira | Jira | Output from your CLI tool (default) |
### TODOs Tab
### Jira View
Two sub-tabs:
Renders markdown output from your CLI tool. Refreshes on:
- Panel focus
- Manual refresh keybind
- Configurable interval
**Project tab:** Items from `TODO.md` (checkbox format)
**Comments tab:** TODO/FIXME/HACK/XXX comments in code
### Problems View
Click any item to jump to source location.
Aggregates from linters (eslint, ruff, etc.). Shows:
### Problems Tab
Linter output showing:
- File path
- Line number
- Severity icon
- Severity (error/warning)
- Message
Click → opens file in Editor at that line.
### TODOs View
Grep results for `TODO`, `FIXME`, `HACK`, `XXX`. Shows:
- File path
- Line number
- Comment text
Click → opens file in Editor at that line.
Click to navigate to source.
---
## Responsiveness
### CSS Breakpoints
### CSS Strategy
```css
/* Widescreen (default) */
/* Default layout */
#panel-sidebar { width: 20%; min-width: 25; }
#panel-context { width: 25%; min-width: 30; }
#panel-claude { width: 1fr; }
/* Medium terminals */
@media (width < 120) {
#panel-sidebar { width: 18%; }
#panel-context { width: 22%; }
}
/* Narrow terminals (laptop, split screen) */
@media (width < 100) {
#panel-sidebar { display: none; }
#panel-context { width: 25%; }
}
@media (width < 80) {
#panel-context { display: none; }
#panel-claude { width: 100%; }
}
```
### Compact Mode
Toggle with `Ctrl+Shift+C`. Hides both sidebars, maximizes Claude + workspace.
Toggle with `Alt+C`. Hides both sidebars:
```css
.compact #panel-sidebar { display: none; }
.compact #panel-context { display: none; }
```
### Fullscreen Mode
Any panel can go fullscreen with `F11` (when focused). Press `Escape` to exit.
```css
.fullscreen {
dock: top;
width: 100%;
height: 100%;
layer: fullscreen;
}
```
All panel state preserved when hidden.
---
## Keybindings
Following VSCode conventions where possible.
All shortcuts use `Alt` modifier to avoid conflicts with Claude Code input.
### Global
### Panel Navigation
| Action | Binding |
|--------|---------|
| Command palette | `Ctrl+Shift+P` |
| Quick open file | `Ctrl+P` |
| Toggle left sidebar | `Ctrl+B` |
| Toggle right sidebar | `Ctrl+Shift+B` |
| Toggle terminal | `` Ctrl+` `` |
| Toggle compact mode | `Ctrl+Shift+C` |
| Fullscreen focused panel | `F11` |
| Exit fullscreen | `Escape` |
| 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` |
### Navigation
### Application
| Action | Binding |
|--------|---------|
| Focus Claude panel | `Ctrl+1` |
| Focus Editor | `Ctrl+2` |
| Focus Terminal | `Ctrl+3` |
| Focus sidebar | `Ctrl+0` |
| Next tab (in tabbed panels) | `Ctrl+Tab` |
| Previous tab | `Ctrl+Shift+Tab` |
| Close current tab/editor | `Ctrl+W` |
| Command palette | `Alt+P` |
| Quick open file | `Alt+O` |
| Select theme | `Alt+T` |
| Quit | `Alt+Q` |
### Git
| Action | Binding |
|--------|---------|
| Open Git panel | `Ctrl+Shift+G` |
| Stage file | `Ctrl+Enter` (in git view) |
| Unstage file | `Ctrl+Backspace` (in git view) |
### Search & Problems
| Action | Binding |
|--------|---------|
| Find in file | `Ctrl+F` |
| Find in project | `Ctrl+Shift+F` |
| Go to problems | `Ctrl+Shift+M` |
| Next problem | `F8` |
| Previous problem | `Shift+F8` |
| Open Git panel | `Alt+G` |
### Editor
| Action | Binding |
|--------|---------|
| Save | `Ctrl+S` |
| Undo | `Ctrl+Z` |
| Redo | `Ctrl+Shift+Z` |
| Go to line | `Ctrl+G` |
| Save | `Alt+S` |
| Go to line | `Alt+L` |
| Go to problems | `Alt+M` |
---
## Panel Communication
Panels should feel connected, like a normal IDE.
### File Navigation
### File Navigation Flow
```
Sidebar file click
@@ -372,7 +295,7 @@ Editor tab focused
File loaded in Editor
```
### Problems/TODOs Navigation
### Problem/TODO Navigation Flow
```
Click problem/todo item
@@ -387,117 +310,57 @@ Editor tab focused
File opened at specific line
Line highlighted/scrolled into view
Line scrolled into view
```
### Claude Diff Flow
### Git Action Flow
```
Claude proposes file changes
Click git action button (Commit, Stash, etc.)
Workspace appears
Ensure skill installed (async, with notification)
Diff tab focused
Send /command to Claude
Changes displayed with Accept/Reject
├─► Accept: Apply changes, optionally close diff
└─► Reject: Discard, close diff
```
### Git File Actions
```
Click file in Git tab
Workspace appears
Diff tab shows unstaged changes
Stage/unstage from diff view
Claude executes git workflow
```
---
## Implementation Notes
## State Management
### Recommended Textual Widgets
| Component | Widget |
|-----------|--------|
| File browser | `DirectoryTree` |
| Claude output | `Markdown` or `RichLog` (for streaming) |
| Editor | `TextArea` (syntax highlighting built-in) |
| Tabbed panels | `TabbedContent`, `TabPane` |
| Panel switching | `ContentSwitcher` |
| Problems/TODOs list | `ListView` with `ListItem` |
| Git graph | `RichLog` or custom canvas widget |
| Command palette | `CommandPalette` (built-in) |
### Background Tasks
Use Textual's `@work` decorator for:
- Git status refresh
- Linter execution
- TODO scanning
- Jira CLI calls
### Reactive Properties
```python
@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)
```
### State Management
**Core principle**: Hiding is not closing. All panels persist state when hidden.
```python
class IDEApp(App):
current_file: reactive[str | None] = reactive(None)
class ClideApp(App):
workspace_visible: reactive[bool] = reactive(False)
problem_count: reactive[int] = reactive(0)
todo_count: reactive[int] = reactive(0)
current_branch: reactive[str] = reactive("main")
compact_mode: reactive[bool] = reactive(False)
```
**Panel visibility pattern** — toggle `display`, don't destroy:
```python
def toggle_workspace(self, visible: bool) -> None:
workspace = self.query_one("#panel-workspace")
workspace.display = visible # Retains all child state
# Adjust Claude panel height
claude = self.query_one("#panel-claude")
claude.styles.height = "40%" if visible else "100%"
```
**State to preserve per panel:**
### State Preservation
| Panel | Preserved State |
|-------|-----------------|
| Editor | Open files, cursor positions, scroll, unsaved changes, undo history |
| Diff | Current diff content, scroll position, accept/reject state |
| Terminal | PTY session, command history, output buffer, working directory |
| Sidebar tabs | Scroll position, expanded/collapsed sections, selection |
| Context tabs | Scroll position, selected item |
| Git views | Expanded sections, selected files |
| Editor | Open file, cursor, scroll, unsaved changes |
| Diff | Current diff, scroll position |
| Terminal | Session, history, output buffer |
| Sidebar tabs | Scroll, expanded sections, selection |
| Context tabs | Scroll, selected item |
---
## Future Considerations
## Themes
- **Session persistence**: Remember open files, panel sizes, last git state
- **Multiple projects**: Workspace switcher
- **Claude history**: Browse past conversations
- **Custom themes**: User-selectable color schemes
- **Plugin system**: User-defined panels/integrations
22 built-in themes with custom theme support.
**Default:** summer-night (dark theme)
Theme selection persists in user settings (`~/.clide/settings.json`).
Custom themes can be added to `~/.clide/themes/` as TOML files.
+398
View File
@@ -0,0 +1,398 @@
# Clide User Manual
Clide is a terminal-based IDE that puts Claude Code at the center of your development workflow. This manual covers installation, daily usage, and customization.
## Installation
### Requirements
- Python 3.12 or later
- Git
- Claude Code CLI installed and authenticated
### Setup
```bash
# Clone the repository
git clone <repo-url>
cd clide
# Install dependencies and create virtual environment
make setup
# Run Clide
make run
```
Or install directly:
```bash
pip install -e .
clide
```
### First Run
On first launch, Clide creates a configuration directory at `~/.clide/` for user settings. Project-specific settings are stored in `.clide/` within your project.
## Interface Overview
```
┌─────────────────┬─────────────────────────┬──────────────────┐
│ Sidebar │ Workspace │ Context │
│ │ [Editor][Diff][Terminal]│ │
│ [Files][Git] │ (appears when needed) │ [Jira][TODOs] │
│ [Tree] ├─────────────────────────┤ [Problems] │
│ │ │ │
│ │ Claude │ │
│ │ (always visible) │ │
│ │ │ │
├─────────────────┤ ├──────────────────┤
│ ⎇ main ▾ │ │ │
│ staged: 2 │ │ │
└─────────────────┴─────────────────────────┴──────────────────┘
```
### Panels
**Left Sidebar** — File browser, git changes, and branch graph
**Center** — Claude Code (always visible) and workspace panels (editor, diff, terminal) that appear when needed
**Right Context** — Jira integration, TODO list, and problems from linters
## Keyboard Shortcuts
All shortcuts use `Alt` as the modifier to avoid conflicts with Claude Code input.
### Panel Navigation
| Action | Shortcut |
|--------|----------|
| 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` |
### File Operations
| Action | Shortcut |
|--------|----------|
| Quick open file | `Alt+O` |
| Save file | `Alt+S` |
| Go to line | `Alt+L` |
### Git Operations
| Action | Shortcut |
|--------|----------|
| Open Git panel | `Alt+G` |
| Open Problems panel | `Alt+M` |
### Application
| Action | Shortcut |
|--------|----------|
| Command palette | `Alt+P` |
| Select theme | `Alt+T` |
| Quit | `Alt+Q` |
## Working with Claude
Claude Code runs in the center panel and is always visible. Type your prompts directly and Claude will respond with code suggestions, explanations, and file operations.
### Git Integration
The sidebar includes buttons for common git operations that delegate to Claude:
- **Commit** — Claude reviews staged changes and creates a well-formatted commit
- **Stash** — Claude stashes your working changes
- **Pull** — Claude pulls with rebase and helps resolve conflicts
- **Push** — Claude pushes to remote, setting upstream if needed
On first use, Clide installs the corresponding skill to your project's `.claude/skills/` directory. These skills guide Claude through each operation following best practices.
### Branch Status
The branch status bar at the bottom of the sidebar shows:
- Current branch name
- Staged and unstaged file counts
Click the branch name to open the branch selector:
```
┌─────────────────┐
│ Recent branches │
│ ● main │
│ ○ feature/xyz │
│ ○ develop │
├─────────────────┤
│[Checkout] [New] │
└─────────────────┘
```
## Left Sidebar
### Files Tab
Browse your project structure. Click a file to open it in the editor.
- Directories expand/collapse on click
- Hidden files (starting with `.`) are shown but dimmed
- Noisy directories (`.git`, `__pycache__`, `node_modules`) are filtered
### Git Tab
View staged and unstaged changes:
```
Staged (2)
+ src/new_file.py
~ src/modified.py
Unstaged (3)
~ README.md
? untracked.txt
- deleted.py
```
**Status indicators:**
- `+` Added
- `~` Modified
- `-` Deleted
- `?` Untracked
- `` Renamed
Click a file to view its diff. Use the action buttons to commit, stash, pull, or push via Claude.
### Tree Tab
Visual git graph showing branch history:
```
● main: Latest commit message
├─● feature: Feature work
●─┴ Merge branch 'feature'
```
**Commit types:**
- `` Regular commit
- `` Merge commit
## Right Context Panel
### Jira Tab
Displays Jira issues when configured. Click the refresh button to update.
Configure Jira integration in settings:
```json
{
"jira_enabled": true,
"jira_cli_path": "jira"
}
```
### TODOs Tab
Scans your codebase for TODO comments and project tasks.
**Sub-tabs:**
- **Project** — Items from `TODO.md` (checkbox format)
- **Comments** — TODO/FIXME/HACK/XXX comments in code
Click an item to jump to that location in the editor.
**Supported comment markers:**
- `TODO` — Tasks to complete
- `FIXME` — Bugs to fix
- `HACK` — Temporary solutions
- `XXX` — Dangerous or problematic code
- `NOTE` — Important notes
- `BUG` — Known bugs
### Problems Tab
Displays linter errors and warnings. Click a problem to jump to the source location.
## Workspace Panels
The workspace appears when you need to view or edit files. It contains three tabs:
### Editor
Full-featured code editor with:
- Syntax highlighting (Python, JavaScript, TypeScript, HTML, CSS, JSON, YAML, Markdown, and more)
- Line numbers
- Current line highlighting
### Diff
Side-by-side diff viewer for reviewing changes. Used when:
- Viewing git changes
- Reviewing Claude's proposed edits
### Terminal
Command-line terminal for running commands. Output is preserved when the panel is hidden.
## Themes
Clide includes 22 built-in themes. Press `Alt+T` to open the theme selector.
**Theme categories:**
| Category | Themes |
|----------|--------|
| Core | summer-night (default), summer-day |
| Popular | one-dark, one-dark-pro, one-light, dracula, nord, gruvbox-dark, gruvbox-light |
| Seasonal | winter-is-coming, monokai-winter, fall, dark-autumn |
| Halloween | all-hallows-eve, halloween |
| Christmas | christmas, santa-baby |
| Hacker | pro-hacker, hacker-style |
| Other | gamma, one-dark-teal, houston |
Your theme choice is saved and persists across sessions.
### Custom Themes
Create custom themes in `~/.clide/themes/`:
```toml
# ~/.clide/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"
```
## Configuration
### User Settings
Settings are stored in `~/.clide/settings.json`:
```json
{
"theme": "summer-night",
"compact_mode": false,
"jira_enabled": false,
"jira_cli_path": "jira"
}
```
### Project Settings
Project-specific settings in `.clide/`:
```
.clide/
├── settings.json # Project overrides
└── skills/ # Installed Claude skills
├── commit/
├── stash/
└── ...
```
### Environment Variables
Override settings with environment variables prefixed with `CLIDE_`:
```bash
CLIDE_THEME=dracula clide
```
## Compact Mode
Press `Alt+C` to toggle compact mode, which hides both sidebars for focused work. All panel state is preserved—nothing is lost when hiding panels.
## Project TODOs
Clide integrates with a `TODO.md` file in your project root. Format:
```markdown
# TODO
## Features
- [ ] Implement user authentication
- [ ] Add search functionality
- [x] Set up database connection
## Bugs
- [ ] Fix login redirect
```
Items appear in the TODOs panel, grouped by section. Click to jump to that line. Check off items directly in the file.
If no `TODO.md` exists, click "Create TODO.md" in the TODOs panel to generate a template.
## Tips
### Efficient Navigation
1. Use `Alt+1/2/3` to quickly switch between Claude, Editor, and Terminal
2. Click items in Problems or TODOs to jump directly to source
3. Use compact mode (`Alt+C`) when you need more space for Claude
### Git Workflow
1. Make changes to your code
2. Review changes in the Git tab
3. Click "Commit" to have Claude create a well-formatted commit
4. Use "Push" when ready to share
### Working with Claude
- Claude sees your project context automatically
- Use the git action buttons for consistent commit messages
- Click files in the sidebar to show Claude what you're working on
## Troubleshooting
### Claude Code not starting
Ensure Claude Code CLI is installed and authenticated:
```bash
claude --version
claude auth status
```
### Theme not applying
Check that the theme name in settings matches exactly. Theme names are case-sensitive.
### Skills not working
Skills are installed to `.claude/skills/` in your project. If a skill fails:
1. Check that the skill folder exists
2. Verify `SKILL.md` is present
3. Try removing and re-triggering the action
### Panels not updating
Try refreshing with the relevant shortcut or clicking the refresh button. File changes should update automatically via file watching.