Based on claude-code-tools TmuxCLIController, this refactor: - Added DockerTmuxController class for robust tmux session management - Implements send_keys() with configurable delay_enter - Implements capture_pane() for output retrieval - Implements wait_for_prompt() for pattern-based completion detection - Implements wait_for_idle() for content-hash-based idle detection - Implements wait_for_shell_prompt() for shell prompt detection Also includes workflow improvements: - Pre-task git snapshot before agent execution - Post-task commit protocol in agent guidelines Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
168 lines
6.2 KiB
Markdown
168 lines
6.2 KiB
Markdown
# Luzia Cockpit - Human-in-the-Loop Claude Sessions
|
|
|
|
## Overview
|
|
|
|
Cockpit provides **pausable Claude agent sessions** using Docker containers with tmux.
|
|
The key innovation is that `docker stop/start` freezes/resumes the entire session state,
|
|
and Claude sessions persist via `--session-id` and `--resume` flags.
|
|
|
|
## Architecture
|
|
|
|
```
|
|
┌─────────────────────────────────────────────────────────────────┐
|
|
│ luzia cockpit │
|
|
├─────────────────────────────────────────────────────────────────┤
|
|
│ │
|
|
│ ┌─────────────────────────────────────────────────────────┐ │
|
|
│ │ Docker Container │ │
|
|
│ │ ┌──────────────────────────────────────────────────┐ │ │
|
|
│ │ │ tmux session │ │ │
|
|
│ │ │ ┌──────────────────────────────────────────┐ │ │ │
|
|
│ │ │ │ Claude CLI │ │ │ │
|
|
│ │ │ │ --session-id / --resume │ │ │ │
|
|
│ │ │ └──────────────────────────────────────────┘ │ │ │
|
|
│ │ └──────────────────────────────────────────────────┘ │ │
|
|
│ │ │ │
|
|
│ │ Mounts: │ │
|
|
│ │ - /workspace → project home │ │
|
|
│ │ - ~/.claude → credentials + sessions │ │
|
|
│ │ - /var/cockpit → state files │ │
|
|
│ └─────────────────────────────────────────────────────────┘ │
|
|
│ │
|
|
│ docker stop → FREEZE (all state preserved) │
|
|
│ docker start → RESUME (continue conversation) │
|
|
│ │
|
|
└─────────────────────────────────────────────────────────────────┘
|
|
```
|
|
|
|
## Commands
|
|
|
|
### Start a Cockpit
|
|
```bash
|
|
luzia cockpit start <project>
|
|
```
|
|
Starts (or resumes) a cockpit container for a project.
|
|
|
|
### Stop (Freeze) a Cockpit
|
|
```bash
|
|
luzia cockpit stop <project>
|
|
```
|
|
Stops the container, freezing all state. Can be resumed later.
|
|
|
|
### Remove a Cockpit
|
|
```bash
|
|
luzia cockpit remove <project>
|
|
```
|
|
Permanently removes the container and state.
|
|
|
|
### Send a Message
|
|
```bash
|
|
luzia cockpit send <project> <message>
|
|
```
|
|
Sends a message to Claude. First message creates the session,
|
|
subsequent messages continue it.
|
|
|
|
### Respond to a Question
|
|
```bash
|
|
luzia cockpit respond <project> <answer>
|
|
```
|
|
Alias for send - used when Claude is waiting for input.
|
|
|
|
### Get Output
|
|
```bash
|
|
luzia cockpit output <project>
|
|
```
|
|
Shows recent output from the tmux session.
|
|
|
|
### Check Status
|
|
```bash
|
|
luzia cockpit status [project]
|
|
```
|
|
Shows all cockpits or a specific one, including session ID and
|
|
whether Claude is waiting for a response.
|
|
|
|
### Attach Interactively
|
|
```bash
|
|
luzia cockpit attach <project>
|
|
```
|
|
Shows the command to attach to the tmux session for interactive work.
|
|
|
|
## Session Persistence
|
|
|
|
Claude sessions are stored in the mounted `~/.claude/` directory:
|
|
```
|
|
~/.claude/projects/{workspace-path}/{session-id}.jsonl
|
|
```
|
|
|
|
The cockpit tracks:
|
|
- `session_id` - UUID for the Claude conversation
|
|
- `session_started` - Whether first message has been sent
|
|
- `awaiting_response` - If Claude asked a question (detected by "?" at end)
|
|
- `last_question` - The question Claude asked
|
|
|
|
## Example Workflow
|
|
|
|
```bash
|
|
# Start a cockpit for musica project
|
|
luzia cockpit start musica
|
|
# → Started cockpit, Session: abc-123-def
|
|
|
|
# Send a task
|
|
luzia cockpit send musica "Fix the track component loading bug"
|
|
# → Claude analyzes and responds
|
|
|
|
# Claude asks a question - FREEZE the session
|
|
luzia cockpit stop musica
|
|
# → Container paused, queue can continue with other projects
|
|
|
|
# Later, human comes back with answer - RESUME
|
|
luzia cockpit start musica
|
|
luzia cockpit respond musica "Use lazy loading, target is 200ms"
|
|
# → Claude continues with the answer
|
|
```
|
|
|
|
## Integration with Queue
|
|
|
|
When Claude is waiting for human input:
|
|
1. Set project queue to `awaiting_human` status
|
|
2. Other projects continue processing
|
|
3. On human response, resume project queue
|
|
|
|
## Docker Image
|
|
|
|
Built from `/opt/server-agents/orchestrator/docker/cockpit/Dockerfile`:
|
|
- Base: `debian:bookworm-slim`
|
|
- Node.js 20 LTS
|
|
- Claude CLI (`@anthropic-ai/claude-code`)
|
|
- tmux with 50000 line history
|
|
- Mouse support for human attach
|
|
|
|
## State Files
|
|
|
|
```
|
|
/var/lib/luz-orchestrator/cockpits/
|
|
├── admin.json
|
|
├── musica.json
|
|
└── overbits.json
|
|
```
|
|
|
|
Each JSON file contains:
|
|
```json
|
|
{
|
|
"project": "musica",
|
|
"session_id": "abc-123-def",
|
|
"status": "running",
|
|
"session_started": true,
|
|
"awaiting_response": false,
|
|
"last_question": null
|
|
}
|
|
```
|
|
|
|
## Benefits
|
|
|
|
1. **True Pause/Resume** - `docker stop/start` freezes everything
|
|
2. **Conversation Memory** - Claude remembers via session persistence
|
|
3. **Non-blocking Queue** - Projects don't block each other
|
|
4. **Human Attachment** - Can attach tmux for direct interaction
|
|
5. **Credential Isolation** - Each project uses shared credentials safely
|