docs: update documentation for clide-web and v1.2.0

- CHANGELOG: add v1.2.0 with clide-web, database layer, workspace tabs,
  and ttyd/zellij removal
- CLAUDE.md: add clide-web to tech stack, dev commands, and project
  structure
- web-deployment.md: document /projects/<name> routing, setup wizard,
  auto-respawn, database schema, and make targets
- install-clide-web.sh: update URLs to path-based routing

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
This commit is contained in:
2026-02-24 17:06:12 +01:00
co-authored by Claude Opus 4.6
parent a14f15d675
commit 30b8cf7db9
4 changed files with 161 additions and 90 deletions
+25
View File
@@ -5,6 +5,31 @@ All notable changes to this project will be documented in this file.
The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.1.0/),
and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html).
## [1.2.0] - 2026-02-24
### Added
- **clide-web**: Python web server replacing ttyd + zellij for browser access
- FastAPI + uvicorn with WebSocket ↔ PTY bridge via tmux
- Project switching via `/projects/<name>` URL routing
- Vendored xterm.js (no CDN, works on disconnected LAN)
- Auto-respawn on Clide exit (tmux `pane-died` hook)
- Setup wizard for first-run configuration (`clide-web-setup`)
- Service management make targets (start-server, stop-server, etc.)
- **SQLite database layer**: SQLModel tables (Project, Session, UserPreference, ConnectionLog) shared between clide and clide-web
- **Dynamic tabbed workspace**: Multi-file editor and multi-terminal support with closable tabs
### Changed
- Context panel (Jira, TODOs, Problems) backgrounds now match sidebar (`$surface`)
- Makefile uses `printf` instead of `echo` for consistent ANSI color rendering
- Full PTY terminal emulator with pyte replaces simple terminal widget
- Nerd Font support and clipboard paste in terminal
### Removed
- **ttyd** (C binary fork with Nerd Font) — replaced by clide-web
- **zellij** (Rust binary for session persistence) — replaced by tmux
- `clide-launcher` shell script — logic absorbed into clide-web
- `update-ttyd.sh` build script
## [1.0.0] - 2026-02-01
### Added
+32
View File
@@ -22,11 +22,15 @@ Clide is a TUI IDE wrapper for Claude Code CLI, designed to be Claude-centric wi
| 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)
```bash
make setup # Create venv, install deps
make run # Run application
@@ -38,6 +42,20 @@ make format # Run ruff format
make build # Build for current platform
```
### clide-web (Web Server)
```bash
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
```
@@ -89,9 +107,23 @@ clide/
│ └── 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
+2 -2
View File
@@ -40,5 +40,5 @@ ss -tlnp | grep 8888 || echo "Warning: Port 8888 not listening yet"
echo ""
echo "Access:"
echo " Local: http://localhost:8888"
echo " Direct: http://localhost:8888?project=clide"
echo " External: https://code.schweitz.net?project=clide"
echo " Direct: http://localhost:8888/projects/clide"
echo " External: https://code.schweitz.net/projects/clide"
+102 -88
View File
@@ -1,11 +1,11 @@
# Web Deployment
Clide runs in a browser via a three-layer stack:
Clide runs in a browser via a two-layer stack:
```
Browser (code.schweitz.net)
└─ ttyd (web terminal server, port 8888)
└─ zellij (session persistence only)
└─ clide-web (FastAPI + uvicorn, port 8888)
└─ tmux (session persistence)
└─ clide (Textual TUI)
└─ claude code (embedded PTY)
```
@@ -14,9 +14,9 @@ Browser (code.schweitz.net)
| Layer | Purpose | Config |
|-------|---------|--------|
| **ttyd** | Serves terminal over WebSocket | systemd service on port 8888 |
| **zellij** | Session reconnection (detach/reattach) | Locked mode, bare layout, no UI |
| **clide** | TUI IDE wrapper around Claude Code | Zellij's default shell |
| **clide-web** | FastAPI server: HTML page, WebSocket ↔ PTY bridge, REST API | systemd service on port 8888 |
| **tmux** | Session persistence (detach/reattach on browser disconnect) | Managed by clide-web |
| **clide** | TUI IDE wrapper around Claude Code | Spawned by tmux |
## Installation
@@ -26,93 +26,113 @@ From the clide project root:
sudo bash deploy/install-clide-web.sh
```
This installs:
1. `ttyd` binary to `/usr/local/bin/`
2. `zellij` binary to `/usr/local/bin/`
3. `clide-launcher` script to `/usr/local/bin/`
4. Zellij config to `~/.config/zellij/` (locked mode + bare layout)
5. `clide-web.service` systemd unit
6. Enables and starts the service
This:
1. Installs `clide-web` Python package into the clide venv
2. Installs `clide-web.service` systemd unit
3. Enables and starts the service
### First-Run Setup
After installing, run the setup wizard to configure projects directory and clide binary path:
```bash
clide-web-setup
```
Settings are stored in `~/.clide/clide.db` as UserPreference records.
### Prerequisites
- Python 3.12+ with clide venv set up (`make setup`)
- `tmux` installed (`sudo dnf install tmux` / `sudo apt install tmux`)
### Reverse Proxy
For external access, configure your reverse proxy (e.g., Nginx Proxy Manager) to:
- Proxy `code.schweitz.net``localhost:8888`
- Enable WebSocket support (required for ttyd)
- Enable WebSocket support
## Architecture
### ttyd
### clide-web
Web terminal server. Runs `clide-launcher` for each browser connection.
FastAPI application serving:
- `GET /` — HTML page with xterm.js terminal + toolbar
- `GET /projects/{name}` — Project terminal page
- `WS /projects/{name}/ws` — WebSocket terminal bridge
- `GET /api/projects` — List available git repos
- `GET /api/sessions` — List active tmux sessions
- `GET /health` — Health check for reverse proxy
**Service:** `/etc/systemd/system/clide-web.service`
**WebSocket Protocol:**
Key flags:
- `-p 8888` — port
- `-W` — writable (allows input)
- `-a` — allows URL arguments (passes `?project=X` to the launcher)
- `-t fontSize=14` — terminal font size
| Prefix | Direction | Purpose |
|--------|-----------|---------|
| `0` | both | Terminal data |
| `1` | both | Control message (JSON) |
| `2` | client→server | Resize: `cols,rows` |
### clide-launcher
### tmux
Entry point script at `/usr/local/bin/clide-launcher`. Handles:
Managed programmatically by clide-web. One session per project (`clide-<project>`).
1. **Project selection** parses `?project=NAME` from the URL
2. **Session management** — creates or reattaches to a Zellij session named `clide-<project>`
3. **Fallback UI** — shows a project selector if no project specified
- Browser disconnect → tmux session persists, reconnect shows current state
- Clide exit (Alt+Q) → `pane-died` hook auto-respawns a fresh Clide instance
- Status bar hidden for clide-web sessions only (user's other tmux sessions unaffected)
- Full environment inherited (HOME, PATH, etc.)
**URL patterns:**
- `code.schweitz.net` — shows project selector
- `code.schweitz.net?project=clide` — opens/attaches to the clide project
### Keybindings
### Zellij
All keys pass through directly to Clide — no intermediate layer captures keys.
No keybinding conflicts (unlike the previous Zellij-based setup).
Used **only** for session persistence (reconnecting after browser close/refresh). All UI features are disabled.
### Database
**Config:** `deploy/zellij/config.kdl`
SQLite database at `~/.clide/clide.db` shared between clide and clide-web.
Uses SQLModel (Pydantic-native ORM by FastAPI's creator).
Key settings:
- `default_mode "locked"` — all keys pass through to Clide except `Ctrl+G`
- `default_layout "bare"` — no tab bar, no status bar
- `pane_frames false` — no pane borders
- `default_shell` — points to the clide binary
- `show_startup_tips false`
Tables:
- **Project** — name, path, theme, last_accessed
- **Session** — tmux session name, status, last_activity
- **UserPreference** — key/value settings (projects_dir, clide_bin, port, etc.)
- **ConnectionLog** — client IP, connect/disconnect timestamps
**Layout:** `deploy/zellij/bare.kdl` — single pane, zero chrome.
## Configuration
### Keybinding Layering
Settings priority: environment variables > database preferences > defaults.
Since the stack is deeply nested, keybindings are carefully layered:
Environment variables (prefix `CLIDE_WEB_`):
| Key | Layer | Action |
|-----|-------|--------|
| `Ctrl+G` | Zellij | Unlock Zellij (only key Zellij captures in locked mode) |
| `Ctrl+Q` | Clide | Quit Clide |
| `Ctrl+B` | Clide | Toggle sidebar |
| `Ctrl+P` | Clide | Quick open |
| `Ctrl+S` | Clide | Save file |
| All others | Clide → Claude | Pass through to Clide, then to Claude Code |
| Variable | Default | Description |
|----------|---------|-------------|
| `CLIDE_WEB_HOST` | `0.0.0.0` | Server bind address |
| `CLIDE_WEB_PORT` | `8888` | Server port |
| `CLIDE_WEB_PROJECTS_DIR` | `/mnt/media/Projects` | Directory containing git repos |
| `CLIDE_WEB_CLIDE_BIN` | `clide` | Path to clide binary |
| `CLIDE_WEB_DB_PATH` | `~/.clide/clide.db` | SQLite database path |
**To detach a session** (e.g., before service restart):
1. `Ctrl+G` — unlock Zellij
2. `Ctrl+O` — session mode
3. `d` — detach
## URL Patterns
Or just close the browser tab — Zellij detaches automatically.
- `code.schweitz.net` — auto-selects first project
- `code.schweitz.net/projects/clide` — opens/attaches to the clide project
The toolbar dropdown allows switching projects. URL updates via `history.pushState`.
## Operations
### Service Management
```bash
# Status
# Using make targets (from clide-web/ directory)
make start-server # Start the systemd service
make stop-server # Stop the systemd service
make restart-server # Restart the systemd service
make status-server # Show service status
make logs-server # Tail service logs
# Or directly with systemctl
systemctl status clide-web
# Restart (disconnects all sessions)
sudo systemctl restart clide-web
# Logs
journalctl -u clide-web -f
```
@@ -120,40 +140,34 @@ journalctl -u clide-web -f
```bash
# List sessions
zellij list-sessions
tmux list-sessions
# Kill stuck sessions
zellij delete-all-sessions --force --yes
# Kill a specific session
tmux kill-session -t clide-myproject
# Clear serialized session cache (if ghost sessions persist)
rm -rf ~/.cache/zellij/*/session_info/clide-*
# Kill all clide sessions
tmux list-sessions | grep ^clide- | cut -d: -f1 | xargs -I{} tmux kill-session -t {}
```
### Troubleshooting
**Service stuck in `deactivating`:** A child process (usually `claude`) didn't respond to SIGTERM.
```bash
sudo systemctl kill -s SIGKILL clide-web
sudo systemctl start clide-web
```
**Old sessions ignore config changes:** Zellij serializes sessions. Delete them and restart:
```bash
zellij delete-all-sessions --force --yes
rm -rf ~/.cache/zellij/*/session_info/clide-*
sudo systemctl restart clide-web
```
**Keys not reaching Clide:** Zellij may be in normal mode. Press `Ctrl+G` to toggle back to locked mode. The status bar being visible is a sign you're unlocked (bare layout hides it in locked mode).
## Files
```
clide-web/ # Python package
├── 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 configuration
│ └── static/
│ ├── index.html # HTML page (toolbar + xterm.js)
│ └── vendor/ # Vendored xterm.js (no CDN dependencies)
├── pyproject.toml
└── Makefile
deploy/
├── install-clide-web.sh # Installation script (run with sudo)
── clide-launcher # Session launcher (ttyd → zellij → clide)
├── clide-web.service # systemd unit file
── zellij/
├── config.kdl # Zellij config (locked mode, no UI)
└── bare.kdl # Bare layout (single pane, no chrome)
├── install-clide-web.sh # Installation script (run with sudo)
── clide-web.service # systemd unit file
clide/
── models/db.py # SQLModel table definitions (shared)
└── services/database.py # SQLite engine and session factory
```