docs: complete project research
This commit is contained in:
385
.planning/research/ARCHITECTURE.md
Normal file
385
.planning/research/ARCHITECTURE.md
Normal file
@@ -0,0 +1,385 @@
|
||||
# Architecture Research
|
||||
|
||||
**Domain:** Process monitoring + desktop integration (Claude Code sessions + i3 WM)
|
||||
**Researched:** 2026-03-23
|
||||
**Confidence:** HIGH
|
||||
|
||||
## System Overview
|
||||
|
||||
```
|
||||
┌─────────────────────────────────────────────────────────────────┐
|
||||
│ Presentation Layer │
|
||||
│ ┌──────────────┐ ┌──────────────┐ ┌──────────────────────┐ │
|
||||
│ │ TUI (Charm) │ │ i3bar/polybar│ │ Desktop Notifications│ │
|
||||
│ │ Dashboard │ │ Status Line │ │ (notify-send) │ │
|
||||
│ └──────┬───────┘ └──────┬───────┘ └──────────┬───────────┘ │
|
||||
│ │ │ │ │
|
||||
├─────────┴─────────────────┴──────────────────────┴──────────────┤
|
||||
│ Core Daemon (vmuxd) │
|
||||
│ ┌────────────┐ ┌──────────────┐ ┌────────────┐ ┌───────────┐ │
|
||||
│ │ Session │ │ State │ │ i3 │ │ Event │ │
|
||||
│ │ Registry │ │ Machine │ │ Bridge │ │ Bus │ │
|
||||
│ └─────┬──────┘ └──────┬───────┘ └─────┬──────┘ └─────┬─────┘ │
|
||||
│ │ │ │ │ │
|
||||
├────────┴───────────────┴───────────────┴──────────────┴─────────┤
|
||||
│ Data Sources │
|
||||
│ ┌───────────────┐ ┌────────────────┐ ┌───────────────────┐ │
|
||||
│ │ Claude Hooks │ │ ~/.claude/ │ │ i3 IPC Socket │ │
|
||||
│ │ (HTTP POST) │ │ projects/ │ │ (Unix Domain) │ │
|
||||
│ └───────────────┘ └────────────────┘ └───────────────────┘ │
|
||||
└─────────────────────────────────────────────────────────────────┘
|
||||
```
|
||||
|
||||
## Architecture Decision: Hook-First, File-Watch Fallback
|
||||
|
||||
La decouverte cle de cette recherche : Claude Code expose un systeme de hooks HTTP depuis debut 2026. Un hook HTTP permet a chaque session Claude Code de POSTer ses evenements (Stop, Notification, PreToolUse, PostToolUse) vers un serveur local. Cela change fondamentalement l'architecture.
|
||||
|
||||
**Strategie retenue : Push via hooks + Pull via fichiers JSONL**
|
||||
|
||||
- **Push (primary):** Chaque session Claude Code envoie ses changements d'etat au daemon via HTTP hooks. Pas de polling, pas de latence.
|
||||
- **Pull (fallback):** Pour les sessions existantes au demarrage du daemon, ou si les hooks ne sont pas configures, on lit les fichiers JSONL de `~/.claude/projects/`.
|
||||
|
||||
Cette approche est superieure au file-watching pur (fsnotify) car :
|
||||
1. Les hooks fournissent des donnees structurees (session_id, cwd, transcript_path, tool_name)
|
||||
2. Pas de parsing JSONL en continu
|
||||
3. Detection immediate du changement d'etat (vs polling toutes les N secondes)
|
||||
|
||||
## Component Responsibilities
|
||||
|
||||
| Component | Responsibility | Implementation |
|
||||
|-----------|----------------|----------------|
|
||||
| **vmuxd** (daemon) | Processus central, orchestre tout | Go binary, lance au login (systemd user unit) |
|
||||
| **HTTP Hook Server** | Recoit les evenements Claude Code | `net/http` sur `localhost:7483`, endpoints par event type |
|
||||
| **Session Registry** | Maintient la liste des sessions actives + leur etat | Map en memoire, pas de DB necessaire |
|
||||
| **State Machine** | Determine l'etat d'une session (Working / Needs Input / Waiting / Inactive) | Transitions basees sur les hooks recus |
|
||||
| **i3 Bridge** | Associe sessions aux workspaces, switch workspace | `go.i3wm.org/i3/v4` (lib officielle) |
|
||||
| **Event Bus** | Distribue les changements d'etat aux consumers (TUI, notifications) | Channels Go internes |
|
||||
| **JSONL Scanner** | Scan initial + fallback pour sessions sans hooks | Lecture `~/.claude/projects/` au demarrage |
|
||||
| **TUI** | Interface principale, dashboard des sessions | Charm Bubbletea ou simple ANSI output |
|
||||
| **Notifier** | Alerte quand une session passe a "Needs Input" | `notify-send` / libnotify |
|
||||
|
||||
## Recommended Project Structure
|
||||
|
||||
```
|
||||
vmux/
|
||||
├── cmd/
|
||||
│ ├── vmuxd/ # Daemon principal
|
||||
│ │ └── main.go
|
||||
│ └── vmux/ # CLI client (query le daemon)
|
||||
│ └── main.go
|
||||
├── internal/
|
||||
│ ├── daemon/ # Lifecycle du daemon, signal handling
|
||||
│ │ └── daemon.go
|
||||
│ ├── hooks/ # HTTP server pour recevoir les hooks Claude
|
||||
│ │ ├── server.go
|
||||
│ │ └── handlers.go
|
||||
│ ├── session/ # Session registry + state machine
|
||||
│ │ ├── registry.go
|
||||
│ │ ├── state.go
|
||||
│ │ └── session.go
|
||||
│ ├── scanner/ # JSONL file scanner (fallback)
|
||||
│ │ └── scanner.go
|
||||
│ ├── i3bridge/ # Integration i3 WM
|
||||
│ │ ├── bridge.go
|
||||
│ │ └── workspace.go
|
||||
│ ├── notify/ # Desktop notifications
|
||||
│ │ └── notify.go
|
||||
│ └── events/ # Event bus interne
|
||||
│ └── bus.go
|
||||
├── go.mod
|
||||
├── go.sum
|
||||
└── flake.nix # NixOS packaging
|
||||
```
|
||||
|
||||
### Structure Rationale
|
||||
|
||||
- **cmd/ split (vmuxd + vmux):** Le daemon tourne en permanence, le CLI est ephemere (query/switch). Separation nette.
|
||||
- **internal/:** Tout est interne, pas de lib publique a exposer.
|
||||
- **hooks/ separe de scanner/:** Deux sources de donnees distinctes avec des lifecycles differents.
|
||||
- **i3bridge/ isole:** La dependance a i3 est contenue. Si Pierre migre vers Sway un jour, seul ce package change (Sway utilise le meme protocole IPC).
|
||||
|
||||
## Architectural Patterns
|
||||
|
||||
### Pattern 1: Event-Driven State Machine
|
||||
|
||||
**What:** Chaque session Claude Code est modelisee comme une state machine. Les transitions sont declenchees par les hooks HTTP ou le scan JSONL.
|
||||
|
||||
**States:**
|
||||
|
||||
```
|
||||
┌──────────┐
|
||||
hook:Stop │ │ hook:PreToolUse
|
||||
┌──────────>│ Waiting │<──────────┐
|
||||
│ │ │ │
|
||||
│ └────┬─────┘ │
|
||||
│ │ │
|
||||
│ hook:Notification │
|
||||
│ (idle_prompt) │
|
||||
│ │ │
|
||||
│ ┌────v─────┐ ┌────┴──────┐
|
||||
│ │ Needs │ │ Working │
|
||||
│ │ Input │ │ │
|
||||
│ └──────────┘ └───────────┘
|
||||
│ ^
|
||||
│ ┌──────────┐ │
|
||||
│ │ Inactive │───────────┘
|
||||
│ │ │ hook:SessionStart
|
||||
│ └──────────┘ ou process detecte
|
||||
│ ^
|
||||
└────────────────┘
|
||||
timeout / process mort
|
||||
```
|
||||
|
||||
**Trade-offs:** Simple et previsible. Le risque est de manquer un evenement (hook timeout, daemon restart). La mitigation est le scan JSONL periodique (toutes les 30s) qui reconcilie l'etat.
|
||||
|
||||
### Pattern 2: Daemon + CLI Client via Unix Socket
|
||||
|
||||
**What:** vmuxd expose un socket Unix local. vmux (CLI) s'y connecte pour query/commander.
|
||||
|
||||
**When to use:** Pour toutes les interactions utilisateur : lister les sessions, switcher de workspace, afficher le dashboard.
|
||||
|
||||
**Trade-offs:** Plus propre qu'un HTTP API local pour du tooling CLI. Le socket est dans `$XDG_RUNTIME_DIR/vmux.sock`.
|
||||
|
||||
```go
|
||||
// vmux CLI query
|
||||
conn, _ := net.Dial("unix", "/run/user/1000/vmux.sock")
|
||||
json.NewEncoder(conn).Encode(Request{Action: "list"})
|
||||
json.NewDecoder(conn).Decode(&sessions)
|
||||
```
|
||||
|
||||
### Pattern 3: i3 Workspace Mapping via Window Tree
|
||||
|
||||
**What:** Associer une session Claude Code a un workspace i3 en matchant le PID du processus Claude avec les fenetres i3 (via `GetTree()`).
|
||||
|
||||
**When to use:** Au demarrage et quand un hook arrive avec un `cwd` inconnu.
|
||||
|
||||
**Mapping strategy:**
|
||||
1. Le hook fournit `cwd` (ex: `/home/pierre/Code/front-commerce/worktrees/feature-x`)
|
||||
2. `GetTree()` retourne l'arbre des fenetres avec leur PID
|
||||
3. On matche le `cwd` du hook avec le `cwd` du processus terminal (via `/proc/PID/cwd`)
|
||||
4. La fenetre terminale est dans un workspace i3 => association trouvee
|
||||
|
||||
**Trade-offs:** La resolution via `/proc/PID/cwd` est Linux-specific (OK pour NixOS). Le matching peut echouer si le terminal a change de repertoire depuis.
|
||||
|
||||
## Data Flow
|
||||
|
||||
### Flow 1: Hook-Driven State Update (primary path)
|
||||
|
||||
```
|
||||
Claude Code session (hook: Stop)
|
||||
│
|
||||
│ HTTP POST localhost:7483/hooks/stop
|
||||
│ Body: { session_id, cwd, last_assistant_message, transcript_path }
|
||||
│
|
||||
v
|
||||
HTTP Hook Server
|
||||
│
|
||||
│ Parse, validate, extract session_id + cwd
|
||||
│
|
||||
v
|
||||
Session Registry
|
||||
│
|
||||
│ Update session state: Working -> Waiting
|
||||
│ Resolve i3 workspace (if not cached)
|
||||
│
|
||||
v
|
||||
Event Bus
|
||||
│
|
||||
├──> Notifier: "Session X attend dans workspace 3"
|
||||
├──> TUI: refresh dashboard
|
||||
└──> i3bar: update status line
|
||||
```
|
||||
|
||||
### Flow 2: Initial Discovery (startup)
|
||||
|
||||
```
|
||||
vmuxd starts
|
||||
│
|
||||
├──> Scan ~/.claude/projects/*/ # Find JSONL files
|
||||
│ Parse last N lines of each # Determine state
|
||||
│ Check /proc for matching processes # Alive or dead?
|
||||
│
|
||||
├──> i3.GetTree() # Map windows to workspaces
|
||||
│ i3.GetWorkspaces() # List workspace names
|
||||
│
|
||||
└──> Build Session Registry
|
||||
Emit initial state to Event Bus
|
||||
```
|
||||
|
||||
### Flow 3: Workspace Switch (user action)
|
||||
|
||||
```
|
||||
User selects session in TUI (or `vmux switch <session>`)
|
||||
│
|
||||
v
|
||||
vmux CLI ──> Unix Socket ──> vmuxd
|
||||
│
|
||||
v
|
||||
Session Registry: lookup workspace for session
|
||||
│
|
||||
v
|
||||
i3 Bridge: i3.RunCommand("workspace 3")
|
||||
│
|
||||
v
|
||||
i3 focuses workspace 3
|
||||
```
|
||||
|
||||
### Flow 4: Notification on state change
|
||||
|
||||
```
|
||||
Hook: Notification (type: permission_prompt)
|
||||
│
|
||||
v
|
||||
State Machine: session -> Needs Input
|
||||
│
|
||||
v
|
||||
Event Bus
|
||||
│
|
||||
v
|
||||
Notifier: notify-send "Claude Code attend votre input"
|
||||
"--hint=string:x-canonical-private-synchronous:vmux"
|
||||
"Session: front-commerce/feature-x (workspace 3)"
|
||||
```
|
||||
|
||||
## Integration Points
|
||||
|
||||
### External Services
|
||||
|
||||
| Service | Integration Pattern | Notes |
|
||||
|---------|---------------------|-------|
|
||||
| **Claude Code** | HTTP hooks (Push) + JSONL files (Pull) | Hooks configurees dans `~/.claude/settings.json` |
|
||||
| **i3 WM** | `go.i3wm.org/i3/v4` via Unix socket | Subscribe WindowEvent + WorkspaceEvent pour mises a jour reactives |
|
||||
| **Desktop Notifications** | exec `notify-send` | Ou libnotify via cgo si besoin de callbacks |
|
||||
| **piaire** (futur) | HTTP API ou Unix socket | Integration possible mais hors scope v1 |
|
||||
|
||||
### Internal Boundaries
|
||||
|
||||
| Boundary | Communication | Notes |
|
||||
|----------|---------------|-------|
|
||||
| vmuxd <-> vmux CLI | Unix socket, JSON protocol | Unidirectionnel : CLI query, daemon repond |
|
||||
| Hook Server <-> Session Registry | Direct Go function call | Meme processus, pas besoin d'IPC |
|
||||
| Session Registry <-> Event Bus | Go channels | Fan-out vers multiple consumers |
|
||||
| Event Bus <-> TUI/Notifier/i3bar | Go channels (subscribe) | Chaque consumer recoit tous les events, filtre localement |
|
||||
| i3 Bridge <-> i3 WM | Unix socket (i3 IPC protocol) | Gere par la lib officielle, transparent |
|
||||
|
||||
### Claude Code Hook Configuration
|
||||
|
||||
A installer dans `~/.claude/settings.json` :
|
||||
|
||||
```json
|
||||
{
|
||||
"hooks": {
|
||||
"Stop": [{
|
||||
"matcher": "",
|
||||
"hooks": [{
|
||||
"type": "http",
|
||||
"url": "http://localhost:7483/hooks/stop"
|
||||
}]
|
||||
}],
|
||||
"Notification": [{
|
||||
"matcher": "",
|
||||
"hooks": [{
|
||||
"type": "http",
|
||||
"url": "http://localhost:7483/hooks/notification"
|
||||
}]
|
||||
}],
|
||||
"PreToolUse": [{
|
||||
"matcher": "",
|
||||
"hooks": [{
|
||||
"type": "http",
|
||||
"url": "http://localhost:7483/hooks/pre-tool-use",
|
||||
"async": true
|
||||
}]
|
||||
}],
|
||||
"PostToolUse": [{
|
||||
"matcher": "",
|
||||
"hooks": [{
|
||||
"type": "http",
|
||||
"url": "http://localhost:7483/hooks/post-tool-use",
|
||||
"async": true
|
||||
}]
|
||||
}]
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
**Important:** PreToolUse et PostToolUse en `async: true` pour ne pas ralentir Claude Code. Stop et Notification en synchrone (latence negligeable, et on veut la confirmation de reception).
|
||||
|
||||
## Anti-Patterns
|
||||
|
||||
### Anti-Pattern 1: Polling-Only Architecture
|
||||
|
||||
**What people do:** Scanner les fichiers JSONL toutes les secondes pour detecter les changements.
|
||||
**Why it's wrong:** Consommation CPU inutile, latence de 0-1s, parsing JSON couteux en boucle. Avec 5+ sessions, ca s'accumule.
|
||||
**Do this instead:** Hooks HTTP comme source primaire, scan JSONL uniquement au demarrage et comme reconciliation periodique (toutes les 30s).
|
||||
|
||||
### Anti-Pattern 2: Embedded Terminal / Session Injection
|
||||
|
||||
**What people do:** Tenter de lire le PTY de la session Claude Code ou d'injecter des inputs.
|
||||
**Why it's wrong:** Fragile, security issues, peut corrompre la session. Le projet le reconnait deja (out of scope).
|
||||
**Do this instead:** Observer via hooks + JSONL. Le `last_assistant_message` du hook Stop fournit l'apercu necessaire.
|
||||
|
||||
### Anti-Pattern 3: Fat Client Without Daemon
|
||||
|
||||
**What people do:** Un seul binaire CLI qui fait tout (scan, watch, display) a chaque invocation.
|
||||
**Why it's wrong:** Pas de persistance d'etat entre invocations. Chaque `vmux` doit re-scanner, re-parser, re-resoudre les workspaces. Lent et incapable de notifier.
|
||||
**Do this instead:** Daemon leger (vmuxd) qui maintient l'etat, CLI leger (vmux) qui query le daemon.
|
||||
|
||||
### Anti-Pattern 4: Over-Engineering the IPC
|
||||
|
||||
**What people do:** gRPC, protobuf, message queues entre les composants internes.
|
||||
**Why it's wrong:** vmux est un outil local single-user. La complexite du serialization/deserialization est pure overhead.
|
||||
**Do this instead:** Go channels internes + Unix socket JSON pour le CLI. Simple, debuggable.
|
||||
|
||||
## Build Order (Dependencies Between Components)
|
||||
|
||||
L'ordre de construction est dicte par les dependances :
|
||||
|
||||
```
|
||||
Phase 1: Session Registry + JSONL Scanner
|
||||
(peut fonctionner standalone, valide le concept)
|
||||
│
|
||||
Phase 2: HTTP Hook Server
|
||||
(depend du Registry, remplace le scanner comme source primaire)
|
||||
│
|
||||
Phase 3: i3 Bridge + Workspace Mapping
|
||||
(depend du Registry pour associer sessions <-> workspaces)
|
||||
│
|
||||
Phase 4: TUI Dashboard + CLI
|
||||
(depend de tout ce qui precede pour afficher et commander)
|
||||
│
|
||||
Phase 5: Notifications + Polish
|
||||
(depend de l'Event Bus et du State Machine)
|
||||
```
|
||||
|
||||
**Rationale de l'ordre :**
|
||||
1. Le Registry + Scanner valide que la detection fonctionne sans aucune config Claude Code
|
||||
2. Les hooks ajoutent la reactivite mais necessitent que le registry existe
|
||||
3. L'i3 bridge a besoin du registry peuple pour faire le mapping
|
||||
4. Le TUI/CLI est la couche de presentation, besoin de donnees
|
||||
5. Les notifications sont du polish, pas du core
|
||||
|
||||
## Scaling Considerations
|
||||
|
||||
| Scale | Approach |
|
||||
|-------|----------|
|
||||
| 1-5 sessions (usage normal) | Architecture actuelle suffit largement |
|
||||
| 5-15 sessions | Aucun changement, Go gere facilement |
|
||||
| 15+ sessions | Improbable pour un seul utilisateur. Si ca arrive, limiter la frequence des hooks async |
|
||||
|
||||
Le bottleneck n'est pas la perf mais la complexite d'affichage : au-dela de 8 sessions, le TUI doit proposer du filtrage/grouping.
|
||||
|
||||
## Sources
|
||||
|
||||
- [i3 IPC documentation](https://i3wm.org/docs/ipc.html)
|
||||
- [go.i3wm.org/i3/v4 - Official Go library](https://pkg.go.dev/go.i3wm.org/i3/v4)
|
||||
- [Claude Code Hooks reference](https://code.claude.com/docs/en/hooks)
|
||||
- [claude-sessions-monitor](https://github.com/yepzdk/claude-sessions-monitor) - Existing tool, validates the JSONL + process detection approach
|
||||
- [Real-time dashboard for Claude Code sessions](https://www.ksred.com/managing-multiple-claude-code-sessions-building-a-real-time-dashboard/)
|
||||
- [Claude Code session storage](https://milvus.io/blog/why-claude-code-feels-so-stable-a-developers-deep-dive-into-its-local-storage-design.md)
|
||||
- [fsnotify - Go filesystem notifications](https://github.com/fsnotify/fsnotify) - Considered but hooks are superior
|
||||
- [Claude Code CLI reference](https://code.claude.com/docs/en/cli-reference)
|
||||
|
||||
---
|
||||
*Architecture research for: vmux (Claude Code session cockpit + i3 integration)*
|
||||
*Researched: 2026-03-23*
|
||||
171
.planning/research/FEATURES.md
Normal file
171
.planning/research/FEATURES.md
Normal file
@@ -0,0 +1,171 @@
|
||||
# Feature Research
|
||||
|
||||
**Domain:** AI session management / desktop workspace orchestration
|
||||
**Researched:** 2026-03-23
|
||||
**Confidence:** HIGH
|
||||
|
||||
## Feature Landscape
|
||||
|
||||
### Table Stakes (Users Expect These)
|
||||
|
||||
Features users assume exist. Missing these = product feels incomplete.
|
||||
|
||||
| Feature | Why Expected | Complexity | Notes |
|
||||
|---------|--------------|------------|-------|
|
||||
| Session discovery | Sans detection automatique des sessions Claude Code, l'outil n'a aucun sens. Tous les concurrents (agent-deck, dmux, amux, agentdock) font ca. | MEDIUM | Poll des process `claude` via `/proc` + lecture des fichiers JSONL dans `~/.claude/projects/`. Refresh toutes les 2-3s. |
|
||||
| State detection (working / waiting / idle) | Le coeur de la valeur. agent-deck utilise un modele 3 etats (running/waiting/idle), amux ajoute "needs input" et "stuck". C'est le minimum pour savoir ou porter son attention. | MEDIUM | Parsing du dernier entry JSONL de la session + detection de process activity. Les hooks Claude Code (`notification` event avec `idle_prompt`, `permission_prompt`) sont la source la plus fiable. |
|
||||
| Session list with status | Tous les outils du domaine affichent une liste de sessions avec indicateur visuel de statut. Sans ca, on revient au scan manuel des workspaces. | LOW | Liste filtrable avec couleurs : vert (travaille), jaune (attend), gris (idle). |
|
||||
| Workspace association | vmux cible specifiquement i3. Chaque session doit etre associee a son workspace i3 et worktree git. C'est le lien entre "cette session" et "ou elle vit sur mon ecran". | MEDIUM | Correlation via PID du process claude -> window -> workspace i3 (via i3 IPC). Le worktree git se deduit du cwd du process. |
|
||||
| Switch to workspace | Pouvoir naviguer vers la session qui a besoin d'attention. agent-deck fait ca avec tmux (`Ctrl+b` puis numero), vmux le fait avec i3-msg. | LOW | `i3-msg workspace [name]` via IPC. Trivial une fois l'association etablie. |
|
||||
| Desktop notifications | Quand une session passe de "travaille" a "attend input", le dev doit etre prevenu. Tous les outils serieux le font : amux, agent-deck, et meme les hooks Claude Code natifs. dunst est le standard sur i3. | LOW | Notification via `notify-send` / D-Bus vers dunst. Se declenche sur transition d'etat. |
|
||||
|
||||
### Differentiators (Competitive Advantage)
|
||||
|
||||
Features that set the product apart. Not required, but valuable.
|
||||
|
||||
| Feature | Value Proposition | Complexity | Notes |
|
||||
|---------|-------------------|------------|-------|
|
||||
| i3-native integration | Aucun concurrent ne cible i3 specifiquement. dmux/agent-deck/agentdock sont tous tmux-centric. vmux est le seul a mapper sessions Claude -> workspaces i3, ce qui correspond exactement au workflow de Pierre (1 workspace = 1 sujet = 1 worktree). | MEDIUM | i3 IPC (socket Unix) pour lister workspaces, detecter les fenetres, switcher. Pas de dependance tmux. |
|
||||
| Session preview (last output lines) | Voir ce que Claude fait/demande sans switcher de workspace. amux appelle ca "peek mode", agentdock a un "live terminal". vmux peut faire plus leger : juste les dernieres lignes pertinentes. | MEDIUM | Lecture du JSONL de session pour extraire le dernier message assistant. Pas besoin de terminal complet, juste un apercu texte. |
|
||||
| Attention priority ordering | Au lieu d'une simple liste, trier les sessions par urgence : "attend input" en haut, "permission needed" en second, "working" en bas. Aucun concurrent ne fait ca explicitement. | LOW | Tri de la liste par etat. Trivial en logique, fort en UX. |
|
||||
| Multi-screen awareness | Pierre utilise 2 ecrans. vmux peut savoir sur quel ecran/output se trouve chaque workspace i3, et optimiser le placement (ex: sessions actives sur ecran 1, sessions en attente sur ecran 2). | LOW | i3 IPC expose les outputs (ecrans) et leurs workspaces. Lecture seule suffit pour l'affichage. |
|
||||
| Integration piaire | piaire gere deja le workflow (timetracking, features, MRs). vmux pourrait exposer l'etat des sessions a piaire ou consommer les infos de piaire (quel ticket = quelle session). Synergie unique a cet ecosysteme. | HIGH | Necessite une API/IPC entre les deux outils. A evaluer apres v1. |
|
||||
| Statusline i3bar widget | Au lieu d'une TUI separee, afficher le resume dans la barre i3 elle-meme : "3 sessions: 1 attend, 2 travaillent". Information passive, zero friction. | LOW | Script i3status/i3blocks qui lit l'etat des sessions. Format texte simple. |
|
||||
|
||||
### Anti-Features (Commonly Requested, Often Problematic)
|
||||
|
||||
Features that seem good but create problems.
|
||||
|
||||
| Feature | Why Requested | Why Problematic | Alternative |
|
||||
|---------|---------------|-----------------|-------------|
|
||||
| Terminal integre / repondre depuis vmux | Eviter de switcher de workspace pour repondre a Claude. Agentdock et amux le font. | Complexite enorme (terminal emulation, xterm.js, gestion input). 80% de la valeur vient de savoir *ou* aller, pas de repondre sur place. Pierre l'a deja identifie comme out of scope. | Switch rapide vers le workspace i3 en 1 touche. Le terminal natif est deja la-bas. |
|
||||
| Lancement de sessions | dmux et amux permettent de creer des sessions. Ca semble pratique. | vmux observe, ne cree pas. Lancer des sessions implique gerer worktrees, branches, contexte initial. C'est le role des skills piaire/Claude Code. Ajouter ca cree un second "lanceur" concurrent. | Rester observateur. Les sessions sont lancees par les skills existants. |
|
||||
| Auto-reponse / watchdog | amux auto-repond aux prompts de permission, auto-compacte le contexte. Semble utile pour le mode "unattended". | Dangereux. Approuver automatiquement des actions Claude Code sans review humaine. Le watchdog d'amux est pour des workloads batch, pas pour du dev interactif ou la review compte. | Notifier rapidement pour que le dev reponde lui-meme. |
|
||||
| Dashboard web | agentdock et amux proposent un dashboard web avec WebSocket. Plus joli, accessible depuis le telephone. | Over-engineering pour un outil local single-user. Ajoute Node.js/serveur web/WebSocket a la stack. vmux est un outil desktop i3, pas un SaaS. | TUI ou widget i3bar. Leger, natif, zero overhead. |
|
||||
| Support multi-agent (Cursor, Codex, Gemini...) | agent-deck et dmux supportent N agents differents. | vmux est specifiquement pour Claude Code. Supporter d'autres agents dilue le focus et complexifie la detection d'etat (chaque agent a son propre format). | Cibler Claude Code uniquement. Si le besoin emerge, generaliser plus tard. |
|
||||
| Token/cost tracking | Plusieurs outils (amux, Claude Code Usage Monitor) trackent les tokens et couts. | Deja disponible via `claude usage` et le dashboard Anthropic. Dupliquer cette feature n'apporte rien. La statusline Claude Code expose deja ces metriques. | Laisser Claude Code gerer ses propres metriques. vmux se concentre sur l'etat et la navigation. |
|
||||
|
||||
## Feature Dependencies
|
||||
|
||||
```
|
||||
[Session Discovery]
|
||||
|
|
||||
+--requires--> [State Detection]
|
||||
| |
|
||||
| +--enables--> [Desktop Notifications]
|
||||
| |
|
||||
| +--enables--> [Attention Priority Ordering]
|
||||
|
|
||||
+--requires--> [Workspace Association]
|
||||
| |
|
||||
| +--enables--> [Switch to Workspace]
|
||||
| |
|
||||
| +--enables--> [Multi-screen Awareness]
|
||||
|
|
||||
+--enables--> [Session Preview]
|
||||
|
||||
[Session List with Status]
|
||||
+--requires--> [Session Discovery]
|
||||
+--requires--> [State Detection]
|
||||
|
||||
[Statusline i3bar Widget]
|
||||
+--requires--> [Session Discovery]
|
||||
+--requires--> [State Detection]
|
||||
+--independent-of--> [Session List TUI]
|
||||
|
||||
[Integration piaire]
|
||||
+--requires--> [Session Discovery]
|
||||
+--requires--> [Workspace Association]
|
||||
+--deferred--> after v1 validation
|
||||
```
|
||||
|
||||
### Dependency Notes
|
||||
|
||||
- **Session Discovery is the foundation:** Tout depend de la capacite a trouver et monitorer les process Claude Code actifs. Sans ca, rien ne fonctionne.
|
||||
- **State Detection depends on Discovery:** On ne peut determiner l'etat d'une session qu'apres l'avoir trouvee.
|
||||
- **Workspace Association is parallel to State Detection:** Les deux enrichissent la session decouverte, mais sont independants l'un de l'autre.
|
||||
- **Notifications require State Detection:** On notifie sur les transitions d'etat, donc il faut d'abord detecter l'etat.
|
||||
- **i3bar Widget et TUI sont independants:** On peut avoir l'un sans l'autre. Le widget i3bar est plus leger et potentiellement suffisant en v1.
|
||||
|
||||
## MVP Definition
|
||||
|
||||
### Launch With (v1)
|
||||
|
||||
Minimum viable product pour valider le concept : "savoir instantanement quelle session a besoin de moi".
|
||||
|
||||
- [ ] Session discovery (detect Claude Code processes + read JSONL state files)
|
||||
- [ ] State detection (working / waiting for input / idle)
|
||||
- [ ] Workspace i3 association (PID -> window -> workspace)
|
||||
- [ ] Session list with status (TUI ou i3bar widget, au choix)
|
||||
- [ ] Switch to workspace (navigation en 1 action)
|
||||
- [ ] Desktop notifications on state transition (via dunst/notify-send)
|
||||
|
||||
### Add After Validation (v1.x)
|
||||
|
||||
Features to add once core is working.
|
||||
|
||||
- [ ] Session preview (dernieres lignes de sortie) si le simple switch ne suffit pas
|
||||
- [ ] Attention priority ordering si le nombre de sessions depasse 5+
|
||||
- [ ] Multi-screen awareness si la repartition ecran 1/ecran 2 reste un pain point
|
||||
- [ ] Statusline i3bar widget (si v1 est TUI) ou TUI (si v1 est widget)
|
||||
|
||||
### Future Consideration (v2+)
|
||||
|
||||
Features to defer until product-market fit is established.
|
||||
|
||||
- [ ] Integration piaire pour lier session <-> ticket/feature
|
||||
- [ ] Keyboard shortcuts globaux (i3 bindings) pour naviguer sans ouvrir vmux
|
||||
- [ ] Historique des sessions (quand elles ont commence, duree, etc.)
|
||||
|
||||
## Feature Prioritization Matrix
|
||||
|
||||
| Feature | User Value | Implementation Cost | Priority |
|
||||
|---------|------------|---------------------|----------|
|
||||
| Session discovery | HIGH | MEDIUM | P1 |
|
||||
| State detection | HIGH | MEDIUM | P1 |
|
||||
| Workspace i3 association | HIGH | MEDIUM | P1 |
|
||||
| Session list with status | HIGH | LOW | P1 |
|
||||
| Switch to workspace | HIGH | LOW | P1 |
|
||||
| Desktop notifications | HIGH | LOW | P1 |
|
||||
| Session preview | MEDIUM | MEDIUM | P2 |
|
||||
| Attention priority ordering | MEDIUM | LOW | P2 |
|
||||
| Statusline i3bar widget | MEDIUM | LOW | P2 |
|
||||
| Multi-screen awareness | LOW | LOW | P2 |
|
||||
| Integration piaire | MEDIUM | HIGH | P3 |
|
||||
|
||||
**Priority key:**
|
||||
- P1: Must have for launch
|
||||
- P2: Should have, add when possible
|
||||
- P3: Nice to have, future consideration
|
||||
|
||||
## Competitor Feature Analysis
|
||||
|
||||
| Feature | agent-deck | dmux | amux | agentdock | vmux (our approach) |
|
||||
|---------|-----------|------|------|-----------|---------------------|
|
||||
| Session detection | tmux-based | tmux-based | tmux-based | tmux-based | Process/JSONL + i3 IPC |
|
||||
| State detection | 3 states (run/wait/idle) | Basic | 4 states + stuck | Live terminal | 3 states via hooks + JSONL |
|
||||
| WM integration | None (tmux only) | None (tmux only) | None (web) | None (web) | Native i3 workspace mapping |
|
||||
| Notifications | tmux statusbar | None | Web + mobile push | Web | dunst/D-Bus (native desktop) |
|
||||
| Terminal embed | Yes (tmux pane) | Yes (tmux pane) | Yes (web xterm.js) | Yes (web xterm.js) | No (switch to workspace) |
|
||||
| Session creation | Yes | Yes | Yes | Yes | No (observe only) |
|
||||
| Multi-agent | Yes (10+ agents) | Yes (11 agents) | Claude Code only | Claude + Cursor | Claude Code only |
|
||||
| Git worktrees | Optional | Core feature | Optional | Core feature | Detected, not managed |
|
||||
| Overhead | Go binary | Node.js | Python + web server | Node.js + React | Go binary (lightweight) |
|
||||
|
||||
**Key differentiator:** vmux is the only tool that integrates with a tiling WM instead of wrapping everything in tmux. For a dev who already organizes work in i3 workspaces, this is more natural than a tmux-within-i3 approach.
|
||||
|
||||
## Sources
|
||||
|
||||
- [agent-deck](https://github.com/asheshgoplani/agent-deck) - Go + Bubble Tea TUI, tmux-based session manager
|
||||
- [dmux](https://github.com/formkit/dmux) - Node.js agent multiplexer with git worktrees
|
||||
- [amux](https://github.com/mixpeek/amux) - Python multiplexer with web dashboard and watchdog
|
||||
- [agentdock](https://github.com/vishalnarkhede/agentdock) - Web dashboard for parallel agents
|
||||
- [Claude Code Hooks Reference](https://code.claude.com/docs/en/hooks) - Official hook events including notification types
|
||||
- [Claude Code Notification Hooks](https://alexop.dev/posts/claude-code-notification-hooks/) - Practical guide to notification setup
|
||||
- [tmuxwatch](https://github.com/steipete/tmuxwatch) - Charmbracelet-powered tmux session dashboard
|
||||
- [Claude Code session monitoring via JSONL](https://www.ksred.com/managing-multiple-claude-code-sessions-building-a-real-time-dashboard/) - Real-time dashboard implementation details
|
||||
- [i3 IPC documentation](https://i3wm.org/docs/userguide.html) - i3 workspace and window management
|
||||
|
||||
---
|
||||
*Feature research for: AI session management / desktop workspace orchestration*
|
||||
*Researched: 2026-03-23*
|
||||
253
.planning/research/PITFALLS.md
Normal file
253
.planning/research/PITFALLS.md
Normal file
@@ -0,0 +1,253 @@
|
||||
# Pitfalls Research
|
||||
|
||||
**Domain:** Session monitoring / terminal state detection / i3 IPC integration
|
||||
**Researched:** 2026-03-23
|
||||
**Confidence:** MEDIUM-HIGH
|
||||
|
||||
## Critical Pitfalls
|
||||
|
||||
### Pitfall 1: Session state inference from JSONL is fragile and undocumented
|
||||
|
||||
**What goes wrong:**
|
||||
La structure des fichiers JSONL de Claude Code (`~/.claude/projects/<encoded-cwd>/*.jsonl`) n'est pas une API stable. Le format change entre versions sans avertissement. Les champs (`tool_use`, `tool_result`, `role`, `content.type`) peuvent etre renommes, restructures ou supprimes. Pire : un `tool_use` sans `tool_result` correspondant peut signifier "en cours" ou "plante", sans moyen de distinguer les deux.
|
||||
|
||||
**Why it happens:**
|
||||
Les fichiers JSONL sont un detail d'implementation de Claude Code, pas un contrat d'API. Les outils communautaires (claude-sessions-monitor, clog, claude-JSONL-browser) parsent tous ce format, mais aucun n'a de garantie de stabilite.
|
||||
|
||||
**How to avoid:**
|
||||
- Abstraire le parsing JSONL derriere une interface. Un seul module `session/parser.go` qui convertit le JSONL en structures internes. Un changement de format = un seul fichier a modifier.
|
||||
- Detecter l'etat "attend input" via la combinaison : dernier message est `role: "assistant"` + pas de `tool_use` en cours + le process Claude tourne encore. Ne pas se fier a un seul signal.
|
||||
- Ajouter un fallback process-based : si le JSONL est ambigu, verifier via `ps` si le process Claude ecrit encore (check du mtime du fichier JSONL).
|
||||
|
||||
**Warning signs:**
|
||||
- Les tests de parsing echouent apres une mise a jour de Claude Code.
|
||||
- L'etat affiche ("travaille") ne correspond pas a la realite observee dans le terminal.
|
||||
|
||||
**Phase to address:**
|
||||
Phase 1 (detection des sessions). Concevoir l'abstraction des le depart.
|
||||
|
||||
---
|
||||
|
||||
### Pitfall 2: Les fichiers JSONL geants font exploser la memoire
|
||||
|
||||
**What goes wrong:**
|
||||
Les sessions longues produisent des fichiers JSONL de plusieurs Go (cas documente : 3.8 Go). Charger ou scanner ces fichiers en entier pour determiner l'etat courant consomme toute la RAM disponible. Claude Code lui-meme souffre de ce probleme (issue #22365).
|
||||
|
||||
**Why it happens:**
|
||||
Les JSONL grossissent sans limite a cause des progress ticks dupliques, sorties de commandes volumineuses et accumulation de metadata de sous-agents. Un monitoring naif qui lit tout le fichier a chaque poll va reproduire le meme probleme que Claude Code.
|
||||
|
||||
**How to avoid:**
|
||||
- Ne JAMAIS charger un JSONL en entier. Lire uniquement les N dernieres lignes (tail-like) pour determiner l'etat courant. En Go : `io.SeekEnd` puis remonter jusqu'a trouver suffisamment de lignes.
|
||||
- Seuil d'alerte : ignorer ou traiter differemment les fichiers > 50 Mo.
|
||||
- Utiliser `sessions-index.json` comme source primaire de metadata (timestamps, branches, resumes) au lieu de parser chaque JSONL.
|
||||
|
||||
**Warning signs:**
|
||||
- La consommation memoire de vmux grimpe avec le temps.
|
||||
- Le temps de rafraichissement se degrade apres quelques heures.
|
||||
|
||||
**Phase to address:**
|
||||
Phase 1. Implementer le tail-read des le premier prototype, pas en optimisation tardive.
|
||||
|
||||
---
|
||||
|
||||
### Pitfall 3: i3 IPC event subscription race conditions et deadlocks
|
||||
|
||||
**What goes wrong:**
|
||||
Deux problemes documentes avec l'IPC i3 :
|
||||
1. **Deadlock si les events ne sont pas consommes** : i3 queue les messages sortants avec un timeout de 10 secondes. Si le client ne lit pas les events assez vite, la connexion est terminee. Avec la lib Go officielle (`go.i3wm.org/i3/v4`), le `EventReceiver` DOIT etre lu en boucle via `Next()` sinon i3 deadlock quand le buffer Unix socket se remplit.
|
||||
2. **Race conditions entre events et requetes** : des que l'on subscribe a un event, l'ordre de traitement des requetes n'est plus garanti. Un event `workspace` peut arriver avant la reponse a `GET_WORKSPACES`.
|
||||
|
||||
**Why it happens:**
|
||||
L'IPC i3 utilise des sockets Unix sans backpressure. Le protocole n'est pas versionne et change a chaque release. La lib Go gere le retry automatique (10s) mais l'`EventReceiver` n'est PAS thread-safe.
|
||||
|
||||
**How to avoid:**
|
||||
- Dedier une goroutine exclusivement a la consommation d'events (`recv.Next()` en boucle). Ne jamais bloquer cette goroutine.
|
||||
- Separer les sockets : un pour les requetes (get_workspaces, get_tree), un pour les subscriptions d'events. La lib Go le gere, mais il faut comprendre que `Subscribe()` cree une connexion separee.
|
||||
- Utiliser `i3.Restart()` au lieu de `RunCommand("restart")` (sinon retry infini).
|
||||
- Gerer le cas ou i3 redemarrage : tous les etats IPC sont reinitialises, toutes les subscriptions perdues sauf une socket.
|
||||
|
||||
**Warning signs:**
|
||||
- vmux se fige apres un certain temps.
|
||||
- Les events workspace ne sont plus recus apres un `i3 restart` ou `i3 reload`.
|
||||
|
||||
**Phase to address:**
|
||||
Phase 2 (integration i3). Test specifique : laisser vmux tourner, faire `i3 reload`, verifier que les events reprennent.
|
||||
|
||||
---
|
||||
|
||||
### Pitfall 4: Detection de process Claude Code non fiable par nom de process
|
||||
|
||||
**What goes wrong:**
|
||||
Claude Code peut s'installer via npm (process Node.js) ou via l'installeur natif (binaire `claude`). Selon la methode, `ps aux | grep claude` donne des resultats differents. Avec npm, le process apparait comme `node` parmi des dizaines d'autres processes Node.js. Le nom change entre versions.
|
||||
|
||||
**Why it happens:**
|
||||
Il n'y a pas d'identifiant stable pour un process Claude Code. Pas de PID file, pas de socket nommee, pas de dbus service. L'outil est concu pour etre interactif dans un terminal, pas pour etre observe de l'exterieur.
|
||||
|
||||
**How to avoid:**
|
||||
- Strategie primaire : lister les fichiers dans `~/.claude/projects/` et correler avec les processes actifs via `/proc/[pid]/cwd` pour trouver les correspondances.
|
||||
- Chercher le process par ses arguments de ligne de commande (`/proc/[pid]/cmdline`) plutot que par son nom.
|
||||
- Croiser avec le mtime des fichiers JSONL : si le fichier est ecrit recemment (< 5s), la session est probablement active.
|
||||
- Fallback : scanner les fenetres i3 dont le titre contient "claude" ou un pattern reconnaissable.
|
||||
|
||||
**Warning signs:**
|
||||
- Des sessions sont detectees comme "idle" alors qu'elles travaillent.
|
||||
- Apres une mise a jour de Claude Code, la detection casse silencieusement.
|
||||
|
||||
**Phase to address:**
|
||||
Phase 1 (detection). Implementer au moins deux signaux independants (fichier + process) pour la detection d'etat.
|
||||
|
||||
---
|
||||
|
||||
### Pitfall 5: fsnotify/inotify ne garantit pas la correction pour le watch recursif
|
||||
|
||||
**What goes wrong:**
|
||||
Le monitoring des fichiers JSONL via inotify (Go fsnotify) a des failles fondamentales :
|
||||
1. **Buffer overflow** : les events sont delivres via un buffer de taille fixe, sans mecanisme de backpressure. Des events peuvent etre perdus silencieusement.
|
||||
2. **Race TOCTTOU** : entre la reception d'un event de creation et l'ouverture du fichier, le fichier peut avoir ete supprime/renomme.
|
||||
3. **Pas d'ordering garanti entre watchers multiples** : si on watch `~/.claude/projects/` et ses sous-repertoires, l'ordre des events entre watchers differents n'est pas lineaire.
|
||||
|
||||
**Why it happens:**
|
||||
C'est une limitation fondamentale de l'API inotify Linux (documentee en detail par Andy Wingo). La perte d'events est "built-in" au design.
|
||||
|
||||
**How to avoid:**
|
||||
- Utiliser inotify comme signal de "quelque chose a change", pas comme source de verite. Toujours re-scanner l'etat apres un event.
|
||||
- Ajouter un poll periodique (toutes les 2-3 secondes) en complement de inotify. L'inotify sert a reduire la latence, le poll sert de filet de securite.
|
||||
- Ne PAS tenter un watch recursif complexe. Watcher uniquement le repertoire racine `~/.claude/projects/` et les fichiers JSONL specifiques deja identifies.
|
||||
- Attention aux limites systeme : chaque watch consomme un file descriptor. Verifier `fs.inotify.max_user_watches`.
|
||||
|
||||
**Warning signs:**
|
||||
- Des sessions apparaissent/disparaissent avec du retard ou pas du tout.
|
||||
- Le nombre de watchers augmente sans limite.
|
||||
|
||||
**Phase to address:**
|
||||
Phase 1. Choisir l'architecture "inotify + poll" des le depart. Ne pas partir sur du inotify pur en pensant migrer plus tard.
|
||||
|
||||
---
|
||||
|
||||
### Pitfall 6: Associer un process Claude a un workspace i3 est plus dur qu'il n'y parait
|
||||
|
||||
**What goes wrong:**
|
||||
La correspondance "session Claude Code <-> workspace i3" semble triviale (meme repertoire de travail) mais echoue dans plusieurs cas :
|
||||
- Un terminal peut etre deplace d'un workspace a un autre sans que le cwd change.
|
||||
- Plusieurs terminaux dans le meme workspace peuvent pointer vers des projets differents.
|
||||
- Le window title du terminal ne contient pas forcement le chemin du projet.
|
||||
- Apres un `i3 reload`, les metadata des conteneurs sont preservees mais les connexions IPC sont perdues.
|
||||
|
||||
**Why it happens:**
|
||||
i3 gere des fenetres (containers), pas des sessions applicatives. Il n'y a pas de lien natif entre un workspace i3 et un repertoire de travail. La correspondance doit etre construite manuellement.
|
||||
|
||||
**How to avoid:**
|
||||
- Approche recommandee : utiliser l'arbre i3 (`get_tree`) pour lister les fenetres, croiser le PID de la fenetre (`window_properties.instance` ou `_NET_WM_PID`) avec `/proc/[pid]/cwd` pour trouver le repertoire de travail.
|
||||
- Alternative : exploiter les conventions de nommage de Pierre (worktrees = branches = noms de workspace). Matcher le nom du workspace avec le nom de la branche git detectee dans la session.
|
||||
- Event `window::move` pour detecter les deplacements de fenetres entre workspaces.
|
||||
- Bug i3 connu (fixe en 2018) : pas d'event `window::focus` quand on switch depuis un workspace vide. Verifier la version d'i3.
|
||||
|
||||
**Warning signs:**
|
||||
- vmux affiche "workspace 3" pour une session qui est maintenant sur le workspace 5.
|
||||
- Le switch vers un workspace n'amene pas a la bonne fenetre Claude.
|
||||
|
||||
**Phase to address:**
|
||||
Phase 2 (integration i3). Tester systematiquement les cas de deplacement de fenetres.
|
||||
|
||||
---
|
||||
|
||||
## Technical Debt Patterns
|
||||
|
||||
| Shortcut | Immediate Benefit | Long-term Cost | When Acceptable |
|
||||
|----------|-------------------|----------------|-----------------|
|
||||
| Parser JSONL couple au format actuel | Rapide a implementer | Casse a chaque mise a jour Claude Code | Jamais, abstraire des le depart |
|
||||
| Polling seul (sans inotify) | Simple, correct | Latence 2-3s sur la detection d'etat | MVP Phase 1 uniquement |
|
||||
| Lecture complete du JSONL | Code simple, pas de seek | OOM sur sessions longues | Jamais |
|
||||
| Hardcoder le nom de process "claude" | Detection rapide | Casse si installation npm ou changement de binaire | Jamais |
|
||||
| Stocker l'association workspace en cache sans invalider | Moins de requetes i3 | Desynchronisation apres deplacement de fenetre | OK si invalide sur event window::move |
|
||||
|
||||
## Integration Gotchas
|
||||
|
||||
| Integration | Common Mistake | Correct Approach |
|
||||
|-------------|----------------|------------------|
|
||||
| i3 IPC events | Ne pas consommer les events assez vite | Goroutine dediee, jamais de traitement bloquant dans la boucle d'events |
|
||||
| i3 `RunCommand("restart")` | Appeler via RunCommand (retry infini) | Utiliser `i3.Restart()` de la lib Go |
|
||||
| i3 `get_tree` | Parcourir l'arbre entier a chaque refresh | Cacher le resultat, invalider sur events `window::new`, `window::close`, `window::move` |
|
||||
| Claude JSONL | Parser le fichier entier | Tail-read des N dernieres lignes |
|
||||
| `sessions-index.json` | Ignorer ce fichier et parser chaque JSONL | L'utiliser comme index primaire pour les metadonnees |
|
||||
| `/proc/[pid]/cwd` | Ne pas gerer les erreurs de permission | Les process d'autres utilisateurs retournent EACCES, gerer gracieusement |
|
||||
|
||||
## Performance Traps
|
||||
|
||||
| Trap | Symptoms | Prevention | When It Breaks |
|
||||
|------|----------|------------|----------------|
|
||||
| Scan complet de `~/.claude/projects/` a chaque tick | CPU spike periodique | Index incrementiel via inotify + rescan periodique | > 20 projets avec historique |
|
||||
| Lecture entiere des JSONL pour l'etat | RAM qui grimpe, freeze | Tail-read (derniers 4 Ko) | Fichiers > 50 Mo |
|
||||
| `get_tree` a chaque rafraichissement | Latence perceptible | Cache + invalidation par events | > 30 fenetres ouvertes |
|
||||
| Polling agressif (< 500ms) | CPU constant a 5-10% | Poll 2-3s + inotify pour la reactivite | Toujours, meme avec peu de sessions |
|
||||
| Ouverture de N watchers inotify | File descriptors epuises | Watcher sur le repertoire parent, pas par fichier | > 50 sessions/projets |
|
||||
|
||||
## Security Mistakes
|
||||
|
||||
| Mistake | Risk | Prevention |
|
||||
|---------|------|------------|
|
||||
| Lire les JSONL d'un autre utilisateur via /proc | Violation de vie privee, fuite de tokens API | vmux ne monitore QUE les sessions de l'utilisateur courant ($HOME) |
|
||||
| Afficher le contenu des messages Claude en clair | Exposition de code/secrets dans le preview | Tronquer, pas de secrets, afficher seulement le dernier message assistant |
|
||||
| Executer des commandes i3 basees sur du contenu JSONL non sanitize | Injection de commandes i3 | Ne jamais interpoler du contenu JSONL dans des commandes i3 |
|
||||
|
||||
## UX Pitfalls
|
||||
|
||||
| Pitfall | User Impact | Better Approach |
|
||||
|---------|-------------|-----------------|
|
||||
| Afficher "idle" quand la session charge (JSONL pas encore ecrit) | L'utilisateur ignore une session qui demarre | Etat "starting" base sur l'age du process vs le dernier write JSONL |
|
||||
| Notification a chaque changement d'etat, meme rapide | Spam de notifications quand Claude enchaine les tool_use | Debounce : notifier seulement apres 3s dans l'etat "attend input" |
|
||||
| Forcer le focus i3 automatiquement | Interrompt le travail en cours | Notifier + keybind pour switcher volontairement |
|
||||
| Ne pas montrer depuis combien de temps la session attend | Pas de priorisation possible | Afficher le temps d'attente relatif ("il y a 2 min") |
|
||||
| Preview trop long ou trop technique | L'utilisateur ne comprend pas ce que la session fait | Extraire le dernier message "humain" (pas tool_result), tronquer a 1-2 lignes |
|
||||
|
||||
## "Looks Done But Isn't" Checklist
|
||||
|
||||
- [ ] **Detection de sessions :** Fonctionne avec l'installeur natif ET npm. Tester les deux.
|
||||
- [ ] **Etat "travaille" :** Verifier que le process ecrit encore (mtime), pas seulement que le dernier message est `tool_use`.
|
||||
- [ ] **i3 integration :** Tester apres `i3 reload` et `i3 restart`. Les subscriptions survivent-elles ?
|
||||
- [ ] **Gros fichiers :** Tester avec un JSONL de > 100 Mo. vmux reste-il reactif ?
|
||||
- [ ] **Multi-ecran :** Le workspace est sur l'ecran 2, le switch via vmux amene bien a l'ecran 2, pas l'ecran 1.
|
||||
- [ ] **Session fantome :** Le process Claude a crash mais le JSONL n'a pas de message de fin. vmux detecte-t-il "mort" ?
|
||||
- [ ] **Nouveau projet :** Un nouveau repertoire apparait dans `~/.claude/projects/` pendant que vmux tourne. Detecte ?
|
||||
- [ ] **Latence notification :** Le delai entre "Claude attend" et la notification vmux est < 5 secondes.
|
||||
|
||||
## Recovery Strategies
|
||||
|
||||
| Pitfall | Recovery Cost | Recovery Steps |
|
||||
|---------|---------------|----------------|
|
||||
| Format JSONL change apres update Claude | LOW (si abstrait) | Mettre a jour le module parser, re-deployer |
|
||||
| Deadlock i3 IPC | LOW | Reconnexion auto via la lib Go (retry 10s) |
|
||||
| OOM sur gros JSONL | MEDIUM | Kill vmux, implementer le tail-read, relancer |
|
||||
| Desync workspace mapping | LOW | Forcer un rescan complet de l'arbre i3 (bouton/keybind refresh) |
|
||||
| inotify events perdus | LOW | Le poll periodique rattrape automatiquement |
|
||||
| Detection process cassee | MEDIUM | Ajouter un nouveau signal de detection (ex: window title) en complement |
|
||||
|
||||
## Pitfall-to-Phase Mapping
|
||||
|
||||
| Pitfall | Prevention Phase | Verification |
|
||||
|---------|------------------|--------------|
|
||||
| JSONL parsing fragile | Phase 1 (detection) | Interface abstraite, tests avec des JSONL reels |
|
||||
| JSONL memoire | Phase 1 (detection) | Benchmark avec fichier > 100 Mo, memoire < 50 Mo |
|
||||
| i3 IPC deadlock | Phase 2 (i3 integration) | Test de charge : 100 events/s pendant 60s |
|
||||
| i3 reconnexion | Phase 2 (i3 integration) | `i3 reload` pendant que vmux tourne |
|
||||
| Detection process | Phase 1 (detection) | Tester avec install native + npm, process mort |
|
||||
| inotify fiabilite | Phase 1 (detection) | Creer/supprimer des fichiers rapidement, verifier que vmux suit |
|
||||
| Mapping workspace | Phase 2 (i3 integration) | Deplacer une fenetre, verifier la mise a jour |
|
||||
| Notifications spam | Phase 3 (notifications) | Session qui enchaine tool_use : 0 notification jusqu'a idle stable |
|
||||
| UX preview | Phase 3 (UI) | Tester avec des sessions reelles, verifier la lisibilite |
|
||||
|
||||
## Sources
|
||||
|
||||
- [i3 IPC documentation](https://i3wm.org/docs/ipc.html) - Event subscription, socket buffer, reconnexion
|
||||
- [go.i3wm.org/i3/v4](https://pkg.go.dev/go.i3wm.org/i3/v4) - Lib Go officielle, EventReceiver deadlock, Restart()
|
||||
- [Missing window::focus event #3562](https://github.com/i3/i3/issues/3562) - Bug event focus depuis workspace vide (fixe)
|
||||
- [claude-sessions-monitor](https://github.com/yepzdk/claude-sessions-monitor) - Approche detection par JSONL
|
||||
- [Large JSONL issue #22365](https://github.com/anthropics/claude-code/issues/22365) - OOM sur gros fichiers session
|
||||
- [Correct or inotify: pick one](https://wingolog.org/archives/2018/05/21/correct-or-inotify-pick-one) - Limites fondamentales d'inotify
|
||||
- [fsnotify Go package](https://pkg.go.dev/github.com/fsnotify/fsnotify) - Race conditions, limites watchers
|
||||
- [Claude Code CLI reference](https://code.claude.com/docs/en/cli-reference) - Session storage structure
|
||||
- [Baeldung: View process output](https://www.baeldung.com/linux/output-process-another-session) - /proc/pid/fd, pseudo-terminal
|
||||
|
||||
---
|
||||
*Pitfalls research for: vmux - Claude Code session monitoring with i3 integration*
|
||||
*Researched: 2026-03-23*
|
||||
175
.planning/research/STACK.md
Normal file
175
.planning/research/STACK.md
Normal file
@@ -0,0 +1,175 @@
|
||||
# Stack Research
|
||||
|
||||
**Domain:** CLI/TUI session monitor for Claude Code on Linux (NixOS, i3 WM)
|
||||
**Researched:** 2026-03-23
|
||||
**Confidence:** HIGH
|
||||
|
||||
## Recommended Stack
|
||||
|
||||
### Core Technologies
|
||||
|
||||
| Technology | Version | Purpose | Why Recommended |
|
||||
|------------|---------|---------|-----------------|
|
||||
| Go | 1.25.x | Language | Deja utilise par piaire, coherence stack. Single binary, bon pour les outils CLI. Disponible via `nix-shell -p go`. |
|
||||
| Bubble Tea v2 | v2.x (charm.land/bubbletea/v2) | TUI framework | Standard de facto pour les TUI en Go (18k+ apps). Architecture Elm (Init/Update/View) qui structure bien le code. Le v2 apporte le renderer Cursed (base ncurses) et le mode 2026 (anti-tearing). |
|
||||
| go.i3wm.org/i3/v4 | v4.21+ | i3 IPC | Lib officielle du projet i3. Couvre 100% de l'API IPC. Gere automatiquement les reconnexions si i3 redemarre. Supporte les subscriptions (workspace events). |
|
||||
| fsnotify | v1.8+ | File watching | Surveiller les fichiers JSONL de `~/.claude/projects/` pour detecter l'activite des sessions. 13k+ importers, stable. |
|
||||
|
||||
### Supporting Libraries
|
||||
|
||||
| Library | Version | Purpose | When to Use |
|
||||
|---------|---------|---------|-------------|
|
||||
| Lip Gloss v2 | v2.x (charm.land/lipgloss/v2) | Styling TUI | Mise en forme du dashboard (couleurs, bordures, layout). Compose naturellement avec Bubble Tea v2. |
|
||||
| Bubbles v2 | v2.x (charm.land/bubbles/v2) | TUI components | Composants pre-faits (list, table, spinner) pour le dashboard. Evite de tout coder from scratch. |
|
||||
| esiqveland/notify | v0.11+ | Desktop notifications | Envoyer des notifs D-Bus quand une session passe de "travaille" a "attend input". Alternative legere a libnotify. |
|
||||
| encoding/json (stdlib) | - | JSON parsing | Parser les JSONL des sessions Claude Code. Pas besoin de lib externe, le format est simple. |
|
||||
| os (stdlib) | - | Process inspection | Lire `/proc/<pid>/status`, `/proc/<pid>/cmdline` pour detecter les processus Claude. Pas besoin de prometheus/procfs pour ce cas simple. |
|
||||
| hpcloud/tail | v1.0+ | File tailing | Follow les fichiers JSONL en temps reel (comme `tail -f`). Alternative a fsnotify pour le cas specifique du suivi de fichiers qui grandissent. |
|
||||
|
||||
### Development Tools
|
||||
|
||||
| Tool | Purpose | Notes |
|
||||
|------|---------|-------|
|
||||
| nix-shell | Environment dev | `nix-shell -p go gopls` pour avoir Go + LSP sans pollution globale |
|
||||
| goreleaser | Build & release | Single binary, cross-compile. Standard pour les outils Go distribues |
|
||||
| golangci-lint | Linting | Aggregateur de linters, couvre les erreurs courantes |
|
||||
|
||||
## Architecture Decision: Pas de lib pour /proc
|
||||
|
||||
Pour vmux, on a besoin de :
|
||||
1. Lister les processus `claude` (= `pgrep claude` ou scan de `/proc/*/cmdline`)
|
||||
2. Lire le PID parent pour trouver le terminal
|
||||
3. Lire le PTY associe (`/proc/<pid>/fd/0` -> `/dev/pts/X`)
|
||||
|
||||
C'est 50 lignes de Go stdlib (`os.ReadDir("/proc")` + `os.ReadFile`). Importer `prometheus/procfs` (poids lourd, API instable) ou `mitchellh/go-ps` (pas maintenu activement) n'a pas de sens.
|
||||
|
||||
## Architecture Decision: JSONL comme source primaire d'etat
|
||||
|
||||
L'analyse du systeme de fichiers revele que Claude Code stocke ses sessions dans `~/.claude/projects/<encoded-cwd>/<session-id>.jsonl`. Chaque ligne est un evenement JSON avec :
|
||||
- `type` : "user", "assistant", "file-history-snapshot"
|
||||
- `timestamp` : ISO 8601
|
||||
- `sessionId` : UUID
|
||||
- `cwd` : repertoire de travail
|
||||
- `gitBranch` : branche git courante
|
||||
- `version` : version de Claude Code
|
||||
- `message.content` : contenu du message
|
||||
|
||||
**Strategie de detection d'etat :**
|
||||
- "Travaille" = le dernier evenement est de type "assistant" et recent (< 30s), ou le processus est actif CPU
|
||||
- "Attend input" = le dernier evenement est de type "assistant" (reponse terminee) et le processus idle
|
||||
- "Idle" = pas d'activite recente
|
||||
|
||||
Le fichier `/proc/<pid>/status` confirme : `State: S (sleeping)` quand Claude attend.
|
||||
|
||||
## Architecture Decision: i3 tree comme source de mapping
|
||||
|
||||
L'i3 tree (via `get_tree`) fournit toutes les fenetres avec leur nom. Les terminaux Claude Code ont des titres distinctifs (verifies sur le poste) :
|
||||
- `Claude Code` dans le titre de la fenetre
|
||||
- Le workspace numerote est directement accessible
|
||||
|
||||
Combinaison PID process Claude -> PTY (`/proc/pid/fd/0`) -> fenetre i3 (via window properties ou titre) -> workspace.
|
||||
|
||||
## Installation
|
||||
|
||||
```bash
|
||||
# Nix shell pour le dev
|
||||
nix-shell -p go gopls goreleaser golangci-lint
|
||||
|
||||
# Init module
|
||||
go mod init github.com/pieMusic/vmux
|
||||
|
||||
# Core
|
||||
go get charm.land/bubbletea/v2
|
||||
go get charm.land/lipgloss/v2
|
||||
go get charm.land/bubbles/v2
|
||||
|
||||
# i3 IPC
|
||||
go get go.i3wm.org/i3/v4
|
||||
|
||||
# File watching
|
||||
go get github.com/fsnotify/fsnotify
|
||||
|
||||
# Notifications
|
||||
go get github.com/esiqveland/notify
|
||||
go get github.com/godbus/dbus/v5
|
||||
```
|
||||
|
||||
## Alternatives Considered
|
||||
|
||||
| Recommended | Alternative | When to Use Alternative |
|
||||
|-------------|-------------|-------------------------|
|
||||
| Bubble Tea v2 | tview (rivo/tview) | Si on veut un style "formulaire terminal" classique (menus, tables, formulaires). Mais vmux est un dashboard de monitoring, l'archi Elm de Bubble Tea convient mieux. |
|
||||
| Bubble Tea v2 | Pas de TUI (CLI simple) | Si la v1 se limite a un `vmux status` one-shot. Commencer en CLI pure, migrer vers TUI quand le dashboard prend forme. **Recommande pour le MVP.** |
|
||||
| go.i3wm.org/i3/v4 | mdirkse/i3ipc-go | Si la lib officielle manque une feature. Mais elle couvre 100% de l'API IPC, pas de raison d'utiliser un fork. |
|
||||
| go.i3wm.org/i3/v4 | Executer `i3-msg` via os/exec | Si on veut eviter la dependance. Viable pour un prototype rapide, mais la lib Go gere les reconnexions et le parsing. |
|
||||
| fsnotify | Polling periodique | Si fsnotify pose des problemes avec NixOS/inotify limits. Le polling toutes les 2s est acceptable pour le use case. |
|
||||
| stdlib /proc | prometheus/procfs | Si on a besoin de metriques systeme avancees. Pas le cas pour vmux. |
|
||||
| esiqveland/notify | os/exec + notify-send | Plus simple, zero dependance. Viable si les notifs restent basiques (pas d'actions, pas d'icones). |
|
||||
|
||||
## What NOT to Use
|
||||
|
||||
| Avoid | Why | Use Instead |
|
||||
|-------|-----|-------------|
|
||||
| Rust / Ratatui | Briserait la coherence avec piaire (Go). Le gain de perf n'a aucun interet pour un dashboard. | Go + Bubble Tea |
|
||||
| Python / Rich | Pas de single binary, runtime dependency, lent au demarrage. | Go |
|
||||
| prometheus/procfs | Trop lourd pour lire 3 champs dans /proc. API instable (WARNING dans leur doc). | Go stdlib (os.ReadFile) |
|
||||
| mitchellh/go-ps | Derniere release 2021. API minimaliste qui ne donne pas les FDs. | Go stdlib /proc scan |
|
||||
| Bubble Tea v1 | v2 est sorti, le renderer Cursed est meilleur. Pas de raison de partir sur l'ancienne version. | Bubble Tea v2 |
|
||||
| gRPC / API HTTP interne | Over-engineering pour un outil local single-user. | Channels Go internes |
|
||||
|
||||
## Stack Patterns by Variant
|
||||
|
||||
**Si standalone (recommande pour commencer) :**
|
||||
- Binary unique `vmux`
|
||||
- Config dans `~/.config/vmux/` ou flags CLI
|
||||
- Pas de serveur, pas de port
|
||||
|
||||
**Si integration piaire plus tard :**
|
||||
- vmux comme package Go importe par piaire
|
||||
- Partage du module Go, meme conventions
|
||||
- piaire expose le dashboard vmux dans son interface HTMX
|
||||
|
||||
**Si MVP CLI-first (recommande) :**
|
||||
- Phase 1 : `vmux` en one-shot, affiche l'etat des sessions en tableau
|
||||
- Phase 2 : Mode watch (`vmux -w`) avec refresh periodique
|
||||
- Phase 3 : TUI interactive avec Bubble Tea
|
||||
- Cela permet de valider la detection avant d'investir dans la TUI
|
||||
|
||||
## Version Compatibility
|
||||
|
||||
| Package | Compatible With | Notes |
|
||||
|---------|-----------------|-------|
|
||||
| Bubble Tea v2 | Go 1.22+ | Import path: `charm.land/bubbletea/v2` (pas `github.com/...`) |
|
||||
| Lip Gloss v2 | Bubble Tea v2 | Doivent etre upgrades ensemble |
|
||||
| Bubbles v2 | Bubble Tea v2, Lip Gloss v2 | Trio indissociable |
|
||||
| go.i3wm.org/i3/v4 | i3 4.x | Tags alignes sur les versions i3. v4.21+ pour i3 4.24 |
|
||||
| fsnotify v1.8 | Go 1.17+ | Utilise inotify sur Linux |
|
||||
| Go 1.25.x | NixOS current | Disponible dans nixpkgs stable |
|
||||
|
||||
## Verified on This Machine
|
||||
|
||||
| Element | Value | Source |
|
||||
|---------|-------|--------|
|
||||
| Go version (nix) | 1.25.7 | `nix-shell -p go --run "go version"` |
|
||||
| i3 version | 4.24 | `i3-msg -t get_version` |
|
||||
| Claude processes | 4 actifs (PID 6938, 10466, 13736, 16030) | `ps aux` |
|
||||
| Session storage | `~/.claude/projects/<encoded-cwd>/<uuid>.jsonl` | Verifie sur le poste |
|
||||
| JSONL fields cles | type, timestamp, sessionId, cwd, gitBranch, message | Verifie par lecture directe |
|
||||
| i3 window names | Contiennent "Claude Code" | `i3-msg -t get_tree` |
|
||||
| PTY mapping | `/proc/<pid>/fd/0` -> `/dev/pts/X` | Verifie sur PID 6938 |
|
||||
|
||||
## Sources
|
||||
|
||||
- [Bubble Tea GitHub](https://github.com/charmbracelet/bubbletea) - v2 release, 18k+ apps
|
||||
- [Bubble Tea v2 release notes](https://github.com/charmbracelet/bubbletea/releases/tag/v2.0.0) - Cursed renderer, mode 2026
|
||||
- [go.i3wm.org/i3/v4](https://pkg.go.dev/go.i3wm.org/i3/v4) - Official i3 Go package, published Mar 2025
|
||||
- [i3 IPC docs](https://i3wm.org/docs/ipc.html) - Protocol reference
|
||||
- [fsnotify](https://github.com/fsnotify/fsnotify) - Cross-platform file watcher, 13k+ importers
|
||||
- [esiqveland/notify](https://github.com/esiqveland/notify) - D-Bus notification Go library
|
||||
- [Claude Code CLI reference](https://code.claude.com/docs/en/cli-reference) - Session management docs
|
||||
- [claude-code-log](https://github.com/daaain/claude-code-log) - Confirms JSONL format structure
|
||||
- Machine locale (NixOS, i3 4.24, Go 1.25.7) - Verified by direct inspection
|
||||
|
||||
---
|
||||
*Stack research for: vmux (Claude Code session monitor)*
|
||||
*Researched: 2026-03-23*
|
||||
188
.planning/research/SUMMARY.md
Normal file
188
.planning/research/SUMMARY.md
Normal file
@@ -0,0 +1,188 @@
|
||||
# Project Research Summary
|
||||
|
||||
**Project:** vmux
|
||||
**Domain:** CLI/TUI session monitor — Claude Code + i3 WM integration
|
||||
**Researched:** 2026-03-23
|
||||
**Confidence:** HIGH
|
||||
|
||||
## Executive Summary
|
||||
|
||||
vmux est un outil de monitoring desktop pour les sessions Claude Code sous i3 WM. La recherche confirme que ce domaine est bien documenté via des outils communautaires existants (agent-deck, amux, dmux, agentdock), mais aucun d'eux ne cible un tiling WM. Tous s'appuient sur tmux ou un dashboard web. La proposition de valeur de vmux est claire : mapper les sessions Claude Code aux workspaces i3 pour permettre la navigation en une action, sans quitter le workflow natif i3.
|
||||
|
||||
L'approche recommandée est une architecture daemon + CLI avec deux sources de données. Claude Code expose des hooks HTTP (depuis début 2026) qui permettent une détection d'état push, sans polling. Les fichiers JSONL de `~/.claude/projects/` servent de source secondaire pour la découverte au démarrage et la réconciliation. Cette combinaison est supérieure à l'approche file-watching pure utilisée par la plupart des outils existants. La stack Go + Bubble Tea v2 + go.i3wm.org/i3/v4 est vérifiée sur la machine cible.
|
||||
|
||||
Les risques principaux sont la fragilité du format JSONL (API non stable), les fichiers de session qui peuvent atteindre plusieurs Go, et les deadlocks potentiels de l'IPC i3 si les events ne sont pas consommés assez vite. Ces trois risques ont des mitigations concrètes identifiées et doivent être adressés dès la Phase 1.
|
||||
|
||||
## Key Findings
|
||||
|
||||
### Recommended Stack
|
||||
|
||||
Go 1.25.7 (disponible via nix-shell) avec Bubble Tea v2 pour la TUI est la combinaison recommandée. La lib officielle i3 Go (`go.i3wm.org/i3/v4`) couvre 100% de l'API IPC et gère les reconnexions automatiquement. Tout a été vérifié sur la machine cible : 4 sessions Claude actives, format JSONL inspecté directement, titres de fenêtres i3 contenant "Claude Code" confirmés.
|
||||
|
||||
La recommandation est de commencer par un MVP CLI-first (sans TUI) pour valider la détection avant d'investir dans l'interface. La TUI et le widget i3bar sont des couches de présentation interchangeables une fois la détection validée.
|
||||
|
||||
**Core technologies:**
|
||||
- Go 1.25.7 : langage — single binary, cohérence avec piaire, disponible via nix-shell
|
||||
- Bubble Tea v2 : TUI — framework Elm, renderer Cursed anti-tearing, standard de facto
|
||||
- go.i3wm.org/i3/v4 : i3 IPC — lib officielle, reconnexion auto, 100% de l'API
|
||||
- stdlib net/http : hook server — recevoir les events push de Claude Code
|
||||
- stdlib os/io : /proc + tail JSONL — pas besoin de libs tierces pour ces cas simples
|
||||
- esiqveland/notify : notifications D-Bus — natif desktop, zero dépendance runtime
|
||||
|
||||
### Expected Features
|
||||
|
||||
**Must have (table stakes) :**
|
||||
- Session discovery (process + JSONL) — sans ça, l'outil est vide
|
||||
- State detection (Working / Needs Input / Idle) — la valeur centrale
|
||||
- Workspace i3 association (PID -> window -> workspace) — différenciateur clé vs tmux-centric
|
||||
- Session list with status — retour visuel immédiat
|
||||
- Switch to workspace — navigation en une action
|
||||
- Desktop notifications on state transition — alerte passive via dunst
|
||||
|
||||
**Should have (competitive) :**
|
||||
- Session preview (dernières lignes du dernier message assistant) — peek sans switcher
|
||||
- Attention priority ordering (sessions "attend input" en haut) — priorisation naturelle
|
||||
- Statusline i3bar widget — info passive, zero friction
|
||||
- Multi-screen awareness — Pierre a 2 écrans, détecter sur quel output est le workspace
|
||||
|
||||
**Defer (v2+) :**
|
||||
- Intégration piaire (lier session <-> ticket/feature) — haute valeur, haute complexité
|
||||
- Keyboard shortcuts globaux i3 pour naviguer sans ouvrir vmux
|
||||
- Historique des sessions
|
||||
|
||||
### Architecture Approach
|
||||
|
||||
L'architecture retenue est daemon (vmuxd) + CLI client (vmux) communiquant via socket Unix. Le daemon maintient le registre des sessions en mémoire, reçoit les hooks HTTP de Claude Code, et distribue les changements d'état via channels Go internes aux consommateurs (TUI, notifier, i3bar). Cette architecture évite les problèmes de re-scan à chaque invocation et permet les notifications asynchrones.
|
||||
|
||||
**Major components:**
|
||||
1. HTTP Hook Server — reçoit les events Claude Code (Stop, Notification, PreToolUse, PostToolUse) sur localhost:7483
|
||||
2. Session Registry + State Machine — maintient l'état de toutes les sessions, transitions Working/Needs Input/Waiting/Inactive
|
||||
3. JSONL Scanner — scan initial au démarrage + reconciliation toutes les 30s
|
||||
4. i3 Bridge — associe sessions aux workspaces via GetTree() + /proc/PID/cwd, commandes workspace
|
||||
5. Event Bus — channels Go, fan-out vers TUI, notifier, i3bar
|
||||
6. Notifier — notify-send vers dunst sur transition vers "Needs Input"
|
||||
7. TUI / CLI — couche présentation, query le daemon via socket Unix
|
||||
|
||||
### Critical Pitfalls
|
||||
|
||||
1. **JSONL parsing fragile** — abstraire derrière une interface dès le départ (un seul `session/parser.go`). Le format est un détail d'implémentation non contractuel, il changera.
|
||||
|
||||
2. **JSONL files géants (3.8 Go documenté)** — ne JAMAIS charger un fichier JSONL en entier. Toujours tail-read (io.SeekEnd + remonter). Tester avec des fichiers > 100 Mo dès la Phase 1.
|
||||
|
||||
3. **i3 IPC deadlock si events non consommés** — goroutine dédiée exclusivement à `recv.Next()`, jamais bloquante. Sockets séparés pour requêtes et subscriptions.
|
||||
|
||||
4. **Detection process non fiable par nom** — croiser cmdline `/proc/[pid]/cmdline` + mtime JSONL + titre fenêtre i3. Jamais un seul signal.
|
||||
|
||||
5. **inotify sans garantie de correction** — utiliser inotify comme signal uniquement, toujours re-scanner après event. Compléter par un poll toutes les 2-3s.
|
||||
|
||||
## Implications for Roadmap
|
||||
|
||||
L'ordre de construction est dicté par les dépendances identifiées dans ARCHITECTURE.md. Chaque phase doit être fonctionnelle de façon autonome pour valider le concept avant de construire la suivante.
|
||||
|
||||
### Phase 1: Foundation — Session Discovery et State Detection
|
||||
|
||||
**Rationale:** Tout dépend de la capacité à trouver et interpréter les sessions. Sans ça, aucun autre composant n'a de données. Valide le concept sans aucune config Claude Code.
|
||||
|
||||
**Delivers:** Binaire CLI one-shot `vmux list` qui affiche les sessions Claude actives avec leur état. Pas de daemon, pas de TUI, juste la détection.
|
||||
|
||||
**Addresses:** Session discovery, state detection (Working/Needs Input/Idle)
|
||||
|
||||
**Avoids:** JSONL parsing fragile (abstraire l'interface dès le départ), JSONL memory (tail-read obligatoire), detection process (multi-signal dès le départ)
|
||||
|
||||
### Phase 2: Daemon et i3 Integration
|
||||
|
||||
**Rationale:** La persistance d'état est nécessaire pour les notifications et le switch. L'i3 bridge a besoin du registry peuplé pour faire le mapping.
|
||||
|
||||
**Delivers:** vmuxd daemon + socket Unix + association sessions/workspaces + `vmux switch <session>` fonctionnel.
|
||||
|
||||
**Addresses:** Workspace i3 association, switch to workspace
|
||||
|
||||
**Avoids:** i3 IPC deadlock (goroutine dédiée events), mapping workspace instable (event window::move), i3 reload (tester la survie des subscriptions)
|
||||
|
||||
### Phase 3: Hook Server et Réactivité
|
||||
|
||||
**Rationale:** Les hooks remplacent le polling comme source primaire. Nécessite que le registry (Phase 1) et le daemon (Phase 2) existent.
|
||||
|
||||
**Delivers:** Réception des hooks Claude Code, transitions d'état immédiates (< 1s), plus de dépendance au polling.
|
||||
|
||||
**Addresses:** State detection améliorée, latence notification
|
||||
|
||||
**Avoids:** Polling-only architecture (anti-pattern documenté), missed events (garder le scan JSONL comme reconciliation toutes les 30s)
|
||||
|
||||
### Phase 4: Notifications et Présentation
|
||||
|
||||
**Rationale:** Couche de présentation et alertes, dépend de tout ce qui précède. Peut être TUI Bubble Tea ou widget i3bar selon les préférences après validation du core.
|
||||
|
||||
**Delivers:** Desktop notifications dunst sur transition vers "Needs Input", session list avec statut coloré, attention priority ordering.
|
||||
|
||||
**Addresses:** Desktop notifications, session list with status, attention priority ordering, session preview
|
||||
|
||||
**Avoids:** Notification spam (debounce 3s), force focus i3 automatique (notifier seulement, pas forcer), preview trop verbeux (1-2 lignes du dernier message assistant)
|
||||
|
||||
### Phase 5: Polish et Features v1.x
|
||||
|
||||
**Rationale:** Features différenciatrices une fois le core validé sur usage réel.
|
||||
|
||||
**Delivers:** Widget i3bar (si TUI en Phase 4) ou TUI (si widget en Phase 4), multi-screen awareness, historique temps d'attente.
|
||||
|
||||
**Addresses:** Statusline i3bar widget, multi-screen awareness, "il y a N min" dans la liste
|
||||
|
||||
### Phase Ordering Rationale
|
||||
|
||||
- **Phases 1 et 2 en séquence stricte** : le daemon a besoin du registry, l'i3 bridge a besoin du daemon
|
||||
- **Phase 3 après Phase 2** : les hooks alimentent le registry, donc le registry doit exister
|
||||
- **Phase 4 dernière** : c'est de la présentation, elle consomme tout ce qui est en amont
|
||||
- **Pas de TUI en Phase 1** : valider la détection avant d'investir dans l'UI (recommandation STACK.md)
|
||||
- **Notifications en Phase 4** : elles dépendent de l'Event Bus qui est en Phase 2-3
|
||||
|
||||
### Research Flags
|
||||
|
||||
Phases nécessitant une recherche approfondie lors du planning :
|
||||
- **Phase 2 (i3 Bridge):** Mapping PID -> fenêtre -> workspace a plusieurs cas limites documentés. Nécessite des tests avec des cas réels (fenêtres déplacées, terminaux multiples dans un workspace, i3 reload).
|
||||
- **Phase 3 (Hook Server):** La configuration des hooks Claude Code dans `~/.claude/settings.json` doit être validée sur la version actuelle de Claude Code installée. Le format a évolué.
|
||||
|
||||
Phases avec patterns standard (pas de recherche nécessaire) :
|
||||
- **Phase 1 (Session Discovery):** JSONL format vérifié sur la machine, /proc API stable Linux, patterns bien documentés.
|
||||
- **Phase 4 (Notifications):** notify-send + dunst est trivial, Bubble Tea v2 a une documentation complète.
|
||||
|
||||
## Confidence Assessment
|
||||
|
||||
| Area | Confidence | Notes |
|
||||
|------|------------|-------|
|
||||
| Stack | HIGH | Vérifié sur machine cible (Go 1.25.7, i3 4.24, sessions Claude actives). Versions et imports confirmés. |
|
||||
| Features | HIGH | Analyse comparative de 4+ outils concurrents. Scope bien délimité. Anti-features clairement identifiées. |
|
||||
| Architecture | HIGH | Architecture hook-first confirmée par sources officielles Claude Code (hooks depuis début 2026). Patterns Go établis. |
|
||||
| Pitfalls | MEDIUM-HIGH | 6 pitfalls critiques avec sources primaires. Certains (inotify, JSONL OOM) basés sur issues GitHub documentées. |
|
||||
|
||||
**Overall confidence:** HIGH
|
||||
|
||||
### Gaps to Address
|
||||
|
||||
- **Hook configuration format actuel :** Les hooks Claude Code sont récents (début 2026). Le format exact de `~/.claude/settings.json` doit être validé lors de la Phase 3 contre la version installée.
|
||||
- **sessions-index.json structure :** Mentionné comme source d'index dans PITFALLS.md mais son format exact n'a pas été inspecté directement. À vérifier en Phase 1.
|
||||
- **Comportement multi-PTY :** Quand plusieurs terminaux dans le même workspace pointent vers le même projet, la résolution PID -> workspace est ambiguë. Stratégie de tie-breaking à définir en Phase 2.
|
||||
|
||||
## Sources
|
||||
|
||||
### Primary (HIGH confidence)
|
||||
|
||||
- Machine locale (NixOS, i3 4.24, Go 1.25.7) — sessions Claude actives, JSONL inspecté, fenêtres i3 vérifiées, PTY mapping confirmé
|
||||
- [Claude Code Hooks reference](https://code.claude.com/docs/en/hooks) — format des hooks, events disponibles
|
||||
- [go.i3wm.org/i3/v4](https://pkg.go.dev/go.i3wm.org/i3/v4) — API officielle i3 Go, EventReceiver, Restart()
|
||||
- [i3 IPC documentation](https://i3wm.org/docs/ipc.html) — protocole, events, socket buffer
|
||||
|
||||
### Secondary (MEDIUM confidence)
|
||||
|
||||
- [agent-deck](https://github.com/asheshgoplani/agent-deck), [dmux](https://github.com/formkit/dmux), [amux](https://github.com/mixpeek/amux), [agentdock](https://github.com/vishalnarkhede/agentdock) — analyse comparative features
|
||||
- [claude-sessions-monitor](https://github.com/yepzdk/claude-sessions-monitor) — valide l'approche JSONL + /proc
|
||||
- [Real-time dashboard implementation](https://www.ksred.com/managing-multiple-claude-code-sessions-building-a-real-time-dashboard/) — patterns de monitoring JSONL
|
||||
- [Large JSONL issue #22365](https://github.com/anthropics/claude-code/issues/22365) — OOM documenté sur fichiers géants
|
||||
|
||||
### Tertiary (LOW confidence)
|
||||
|
||||
- [Correct or inotify: pick one](https://wingolog.org/archives/2018/05/21/correct-or-inotify-pick-one) — limitations inotify, contexte différent mais applicable
|
||||
- [i3 window::focus bug #3562](https://github.com/i3/i3/issues/3562) — bug fixé en 2018, vérifier non-regression sur i3 4.24
|
||||
|
||||
---
|
||||
*Research completed: 2026-03-23*
|
||||
*Ready for roadmap: yes*
|
||||
Reference in New Issue
Block a user