docs: add README, licence WTFPL et documentation

- README.md : vision, installation, commandes, aperçu fonctionnement
- LICENSE : WTFPL v2
- docs/architecture.md : composants, flux de données, index des fichiers
- docs/i3-integration.md : config i3bar, switch, focus, dépannage
- .gitignore : exclure .direnv/

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
This commit is contained in:
Pierre Martin
2026-05-21 17:57:51 +02:00
parent 001c453462
commit f6881c1619
5 changed files with 314 additions and 0 deletions

2
.gitignore vendored
View File

@@ -1 +1,3 @@
vmux vmux
.direnv/

13
LICENSE Normal file
View File

@@ -0,0 +1,13 @@
DO WHAT THE FUCK YOU WANT TO PUBLIC LICENSE
Version 2, December 2004
Copyright (C) 2004 Sam Hocevar <sam@hocevar.net>
Everyone is permitted to copy and distribute verbatim or modified
copies of this license document, and changing it is allowed as long
as the name is changed.
DO WHAT THE FUCK YOU WANT TO PUBLIC LICENSE
TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION
0. You just DO WHAT THE FUCK YOU WANT TO.

113
README.md Normal file
View File

@@ -0,0 +1,113 @@
# vmux
Cockpit pour le vibe coding. vmux surveille toutes vos sessions Claude Code actives, détecte leur état (travaille / attend input / idle), et vous notifie quand l'une d'elles a besoin de vous.
**Problème résolu :** savoir instantanément quelle session Claude Code attend votre attention, sans scanner manuellement vos workspaces i3.
## Aperçu
```
2-vmux[W] 3-api[⚡ 2m] 5-front[?]
```
Chaque bloc i3bar représente une session. Les indicateurs :
- `[W]` vert — Claude travaille
- `[⚡ 2m]` rouge — attend une permission (depuis 2 min)
- `[?]` rouge — attend une réponse
- `[I]` gris — idle
## Prérequis
- Linux avec i3 WM
- Go 1.22+ (build uniquement)
- `notify-send` (paquet `libnotify`)
- X11
## Installation
```sh
# Cloner et builder
git clone https://gitea.example.com/pieMusic/vmux
cd vmux
make build
# Installer le binaire
install -m755 vmux ~/.local/bin/vmux
# Configurer les hooks Claude Code (idempotent)
vmux setup
```
`vmux setup` injecte des hooks dans `~/.claude/settings.json` pour les événements `Notification`, `Stop`, `PostToolUse` et `PreToolUse`. Redémarrez vos sessions Claude Code après.
## Configuration i3
Ajoutez `vmux i3bar` comme `status_command` dans votre config i3 :
```
bar {
status_command vmux i3bar
...
}
```
Puis rechargez i3 : `$mod+Shift+r`.
## Commandes
| Commande | Description |
|---|---|
| `vmux list` | Lister les sessions actives |
| `vmux switch <query>` | Basculer vers le workspace i3 de la session |
| `vmux label <id> <texte>` | Assigner un label à une session |
| `vmux focus <minutes>` | Couper les notifications pendant N minutes |
| `vmux stop` | Arrêter le daemon |
| `vmux setup` | Configurer les hooks Claude Code |
| `vmux i3bar` | Lancer la sortie i3bar (usage : config i3) |
### Exemples
```sh
# Voir l'état de toutes les sessions
vmux list
# Switcher vers la session "vmux" ou "api"
vmux switch vmux
vmux switch api
# Nommer une session (accepte un UUID partiel)
vmux label abc123 "refacto auth"
# Couper les notifs 30 minutes (focus session de travail)
vmux focus 30
vmux focus 0 # réactiver immédiatement
```
## Comment ça marche
Le daemon (`~/.vmux/vmux.sock`) tourne en arrière-plan, lancé automatiquement par la première commande `vmux`. Il :
1. **Scrute `/proc`** toutes les 5s pour détecter les processus `claude`
2. **Lit les fichiers JSONL** de `~/.claude/projects/` pour obtenir l'état et le contexte de chaque session
3. **Reçoit les hooks** de Claude Code sur `localhost:3119` pour des mises à jour temps réel
4. **Résout les workspaces i3** via IPC + X11 (quel workspace contient quel terminal)
5. **Envoie une notification** `notify-send` quand une session passe de "Working" à "Needs Input"
Voir [docs/architecture.md](docs/architecture.md) pour le détail technique.
## Développement
```sh
# Environnement Nix
nix-shell
# Build + watch
make watch
# Tests
make test
```
## Licence
WTFPL — Do What The Fuck You Want To Public License.

101
docs/architecture.md Normal file
View File

@@ -0,0 +1,101 @@
# Architecture
## Vue d'ensemble
vmux suit une architecture **daemon + CLI** classique. Un daemon unique tourne en arrière-plan ; toutes les commandes `vmux` communiquent avec lui via une Unix socket.
```
Claude Code session
│ hooks (HTTP localhost:3119)
┌─────────────┐
│ Daemon │◄── /proc scan (5s)
│ │◄── JSONL reader (~/.claude/projects/)
│ registry │◄── i3 IPC + X11 (workspace resolution)
└──────┬──────┘
│ Unix socket (~/.vmux/vmux.sock)
vmux list / switch / label / focus / i3bar
```
## Composants
### Daemon (`daemon.go`)
- Écoute sur `~/.vmux/vmux.sock` (Unix socket)
- Lance un hook server HTTP sur `localhost:3119`
- Maintient un `SessionRegistry` en mémoire (map sessionID → SessionInfo)
- Poll `/proc` toutes les **5s** (ou **20s** si des hooks arrivent activement)
### Détection des processus (`proc.go`)
Scrute `/proc/*/cmdline` pour trouver les processus dont la commande contient `claude`. Pour chaque processus trouvé, lit :
- `/proc/<pid>/cwd` — répertoire de travail courant
- `/proc/<pid>/fd/0` — PTY associé (pour la résolution workspace)
### Lecture JSONL (`session.go`)
Claude Code écrit un fichier JSONL par session dans `~/.claude/projects/<encoded-cwd>/<uuid>.jsonl`. vmux associe un PID au bon fichier par correspondance du `cwd`, puis lit les messages pour extraire :
- `sessionId`, `gitBranch` — identité de la session
- `type: "assistant"` — dernier message Claude (pour le state et le preview)
### Détection d'état (`state.go`)
| État | Critère |
|---|---|
| `Working` | Dernier event hook = `PreToolUse` ou `PostToolUse` |
| `Needs Input` | Dernier event hook = `Notification` ou `Stop` |
| `Idle` | Aucun event récent, dernier message JSONL vieux de plus de 30s |
Les hooks Claude Code sont prioritaires sur la détection JSONL : ils arrivent en temps réel.
### Hooks Claude Code (`hook.go`)
Claude Code appelle `vmux hook` à chaque événement (via la config `~/.claude/settings.json`). Le binaire lit le JSON sur stdin et le transmet au daemon via la socket. Le daemon met à jour le registry et déclenche une notification si la session passe de `Working` à `Needs Input`.
### Résolution workspace i3 (`workspace.go`, `i3bridge.go`, `x11_resolver.go`)
1. `i3.GetTree()` — récupère l'arbre des fenêtres i3
2. Pour chaque fenêtre avec "Claude Code" dans le titre : lit son PID via `_NET_WM_PID` (X11)
3. Remonte la chaîne `/proc/<pid>/fd/0` → PTY → processus parent → PID Claude
4. Associe le PID Claude au numéro de workspace i3
Dégradation gracieuse : si i3 ou X11 est indisponible, les workspaces restent vides (pas de crash).
### i3bar (`i3bar.go`)
Implémente le [protocole i3bar](https://i3wm.org/docs/i3bar-protocol.html). Tourne en boucle infinie, interroge le daemon toutes les 2s, écrit du JSON sur stdout.
### Notifications (`notify.go`)
Appelle `notify-send` avec `--urgency=critical` quand une session passe de `Working` à `Needs Input`. Le mode focus (`vmux focus <minutes>`) supprime les notifications pendant la durée donnée.
## Fichiers
| Fichier | Rôle |
|---|---|
| `main.go` | Entrypoint, routing des commandes CLI |
| `daemon.go` | Daemon, registry, label store |
| `proc.go` | Scan /proc pour les processus claude |
| `session.go` | Lecture des fichiers JSONL Claude Code |
| `state.go` | Détection d'état (Working/NeedsInput/Idle) |
| `hook.go` | Réception et traitement des hooks Claude Code |
| `workspace.go` | Résolution workspace via i3 tree |
| `i3bridge.go` | Abstraction i3 IPC (testable) |
| `x11_resolver.go` | Lecture _NET_WM_PID via XGB |
| `i3bar.go` | Protocole i3bar |
| `notify.go` | Notifications desktop (notify-send) |
| `focus.go` | Timer de mode focus |
| `display.go` | Affichage `vmux list` |
| `client.go` | Client Unix socket |
| `protocol.go` | Types Request/Response partagés |
| `setup.go` | Injection des hooks dans settings.json |
| `types.go` | Types de données (Session, SessionState…) |
## Données persistées
| Chemin | Contenu |
|---|---|
| `~/.vmux/vmux.sock` | Unix socket du daemon |
| `~/.vmux/labels.json` | Labels assignés par l'utilisateur |
| `~/.claude/settings.json` | Hooks Claude Code (modifié par `vmux setup`) |

85
docs/i3-integration.md Normal file
View File

@@ -0,0 +1,85 @@
# Intégration i3
## i3bar
Ajoutez `vmux i3bar` comme `status_command` dans votre `~/.config/i3/config` :
```
bar {
status_command vmux i3bar
position top
...
}
```
Rechargez i3 (`$mod+Shift+r`). vmux démarre le daemon automatiquement si nécessaire.
### Format des blocs
Un bloc par session active, trié par numéro de workspace :
```
3-vmux[W] 5-api[⚡ 45s] 7-front[? 3m]
```
- `3-vmux` — workspace i3 + nom (label ou dernier composant du cwd)
- `[W]` vert — Working
- `[⚡ 45s]` rouge — Needs Input, type permission, en attente depuis 45s
- `[?]` rouge — Needs Input, type question
- `[!]` rouge — Needs Input, autre type
- `[I]` gris — Idle
- `[?]` gris — état inconnu
Si le daemon est offline : `vmux: offline`.
Si aucune session détectée : `vmux: no sessions`.
## Commande switch
Basculez vers le workspace d'une session depuis votre terminal :
```sh
vmux switch vmux # cherche une session dont le cwd ou label contient "vmux"
vmux switch api
```
La correspondance est fuzzy : le premier mot du workspace/label/cwd qui contient la query gagne.
Vous pouvez aussi lier cette commande à un raccourci i3 :
```
bindsym $mod+F1 exec vmux switch feature-1
bindsym $mod+F2 exec vmux switch feature-2
```
## Notifications desktop
vmux envoie une notification `notify-send` quand une session passe de `Working` à `Needs Input`. Assurez-vous qu'un daemon de notification tourne (`dunst`, `mako`, etc.).
### Mode focus
Pour couper les notifications temporairement :
```sh
vmux focus 30 # supprimer 30 minutes
vmux focus 0 # réactiver immédiatement
```
## Dépannage
**Le workspace n'apparaît pas dans `vmux list`**
vmux résout les workspaces via i3 IPC et X11. Vérifiez que `DISPLAY` est défini dans l'environnement du daemon. Si le daemon est lancé depuis un service systemd, il peut ne pas hériter de `DISPLAY`.
**Les hooks ne fonctionnent pas**
1. Vérifiez que `vmux setup` a été lancé et que `~/.claude/settings.json` contient les hooks
2. Redémarrez les sessions Claude Code après `vmux setup`
3. Le hook server écoute sur `localhost:3119` — vérifiez qu'aucun autre processus n'occupe ce port
**`vmux list` ne voit aucune session**
Le daemon scrute `/proc` pour les processus dont la commande contient `claude`. Vérifiez :
```sh
ps aux | grep claude
```
Si aucun processus n'apparaît, Claude Code n'est pas détecté. Vérifiez le nom du binaire sur votre système.