diff --git a/.planning/phases/01-session-discovery/01-RESEARCH.md b/.planning/phases/01-session-discovery/01-RESEARCH.md
new file mode 100644
index 0000000..62323ac
--- /dev/null
+++ b/.planning/phases/01-session-discovery/01-RESEARCH.md
@@ -0,0 +1,377 @@
+# Phase 1: Session Discovery - Research
+
+**Researched:** 2026-03-23
+**Domain:** Linux process inspection + Claude Code JSONL parsing
+**Confidence:** HIGH
+
+## Summary
+
+La Phase 1 est un CLI one-shot (`vmux list`) qui scanne les processus Claude Code actifs via `/proc`, croise les PID avec les fichiers JSONL dans `~/.claude/projects/`, et affiche l'etat de chaque session.
+
+Le format JSONL de Claude Code est bien documente et stable. Chaque message contient des metadonnees riches (sessionId, cwd, gitBranch, version). L'heuristique d'etat se base sur le `stop_reason` du dernier message `assistant` et le nom de l'outil si `stop_reason=tool_use`.
+
+**Decouverte critique :** `sessions-index.json` n'est plus genere par les versions recentes de Claude Code (derniere MAJ: 2026-02-03). Seulement 13 des 91 dossiers projets en ont un. Il faut lire les metadonnees directement depuis le JSONL (chaque entree contient `sessionId`, `cwd`, `gitBranch`, `version`).
+
+**Recommandation principale :** Ne pas dependre de `sessions-index.json`. Parser la premiere et la derniere entree du JSONL pour obtenir toutes les informations necessaires.
+
+
+## User Constraints (from CONTEXT.md)
+
+### Locked Decisions
+- **D-01:** Scanner `/proc` pour trouver les PID des processus Claude Code actifs, puis enrichir avec les fichiers JSONL dans `~/.claude/projects/`. Un JSONL sans PID correspondant = session terminee, ignoree.
+- **D-02:** Utiliser `sessions-index.json` (present dans chaque dossier projet sous `~/.claude/projects/`) comme source de metadonnees riches (sessionId, gitBranch, projectPath, summary, created, modified). Format verifie sur le poste.
+- **D-03:** Le matching PID -> session se fait via le cwd du processus (`/proc/PID/cwd` -> readlink) croise avec le `projectPath` du sessions-index.
+- **D-04:** Se baser uniquement sur le JSONL (tail-read de la derniere entree) pour determiner l'etat. Pas de lecture CPU en Phase 1.
+- **D-05:** Heuristique d'etat basee sur le dernier message JSONL (voir details dans CONTEXT.md).
+- **D-06:** Les JSONL peuvent faire > 100 Mo. Toujours tail-read, jamais charger le fichier entier.
+- **D-07:** Couleurs activees par defaut pour l'etat (vert = Working, rouge/jaune = Needs Input, gris = Idle).
+
+### Claude's Discretion
+- Format d'affichage : tableau compact ou blocs detailles, libre de proposer un format hybride.
+- Gestion du `--no-color` pour la compatibilite pipe.
+
+### Deferred Ideas (OUT OF SCOPE)
+None
+
+
+
+## Phase Requirements
+
+| ID | Description | Research Support |
+|----|-------------|------------------|
+| DISC-01 | vmux detecte automatiquement les processus Claude Code actifs sur le poste | Scan `/proc/*/cmdline` pour trouver les processus `claude`. Verifie: 6 processus actifs trouves. |
+| DISC-02 | vmux identifie le cwd et le worktree git de chaque session | `readlink /proc/PID/cwd` donne le cwd. Worktree git via `git rev-parse --show-toplevel` ou parsing `.git`. |
+| DISC-03 | vmux affiche le nom de la branche git de chaque session | Champ `gitBranch` present dans chaque entree JSONL. Alternative: `git -C branch --show-current`. |
+| STATE-01 | vmux detecte l'etat de chaque session : travaille / attend input / idle | Heuristique basee sur `stop_reason` + `content[].type` du dernier message assistant. Voir section "Architecture Patterns". |
+| STATE-02 | vmux affiche un apercu des dernieres lignes de sortie de chaque session | Champ `content[].text` du dernier message assistant type `text`. Aussi `summary` dans sessions-index.json quand disponible. |
+
+
+## Standard Stack
+
+### Core
+| Library | Version | Purpose | Why Standard |
+|---------|---------|---------|--------------|
+| Go | 1.25.7 | Langage | Deja utilise par piaire. Disponible via `nix-shell -p go`. |
+| Go stdlib (os, encoding/json, path/filepath, fmt) | - | Tout le runtime | Aucune dependance externe necessaire pour Phase 1. /proc se lit avec os.ReadFile/os.Readlink. |
+
+### Supporting
+| Library | Version | Purpose | When to Use |
+|---------|---------|---------|-------------|
+| Aucune | - | - | Phase 1 = stdlib uniquement. Pas de CLI framework, pas de TUI, pas de deps. |
+
+### Alternatives Considered
+| Instead of | Could Use | Tradeoff |
+|------------|-----------|----------|
+| stdlib os pour /proc | prometheus/procfs | Over-engineered pour lire cmdline + cwd. API instable (WARNING dans leur doc). |
+| stdlib flag | cobra/urfave | Over-engineered pour une seule commande `list`. flag suffit. |
+| Reverse-read maison | hpcloud/tail | tail est pour le mode follow (Phase 2+). Pour un one-shot, un seek+read depuis la fin suffit. |
+
+**Installation:**
+```bash
+# Rien a installer. Go stdlib uniquement.
+nix-shell -p go --run "go mod init github.com/pieMusic/vmux"
+```
+
+## Architecture Patterns
+
+### Recommended Project Structure
+```
+vmux/
+├── main.go # Point d'entree, parsing des args
+├── proc.go # Scan /proc pour les processus Claude
+├── proc_test.go
+├── session.go # Lecture JSONL + matching PID->session
+├── session_test.go
+├── state.go # Heuristique d'etat (Working/NeedsInput/Idle)
+├── state_test.go
+├── display.go # Formatage et affichage (couleurs, layout)
+├── display_test.go
+├── go.mod
+└── shell.nix # Environnement de dev NixOS
+```
+
+### Pattern 1: Scan /proc pour les processus Claude
+**What:** Lister tous les PID dont `/proc/PID/cmdline` contient `claude`.
+**When to use:** Au demarrage de `vmux list`.
+**Verification sur machine:** Les processus Claude Code apparaissent comme `claude` ou `claude -c` dans cmdline.
+
+```go
+// Verifie sur la machine : /proc/PID/cmdline contient "claude\x00" ou "claude\x00-c\x00"
+func findClaudeProcesses() ([]Process, error) {
+ entries, err := os.ReadDir("/proc")
+ // Pour chaque entree numerique, lire /proc/PID/cmdline
+ // Si le premier argument est "claude", c'est un processus Claude Code
+ // Lire aussi /proc/PID/cwd via os.Readlink pour obtenir le cwd
+}
+```
+
+### Pattern 2: Encoding du chemin projet
+**What:** Convertir un cwd en nom de dossier `~/.claude/projects/`.
+**Verification:** `/home/pierre/Code/vibe/vmux` -> `-home-pierre-Code-vibe-vmux`. Les `/` et `.` sont remplaces par `-`.
+
+```go
+func encodePath(cwd string) string {
+ // Remplacer / et . par -
+ result := strings.ReplaceAll(cwd, "/", "-")
+ result = strings.ReplaceAll(result, ".", "-")
+ return result
+}
+```
+
+### Pattern 3: Tail-read JSONL (lecture depuis la fin)
+**What:** Lire les N dernieres lignes d'un JSONL sans charger le fichier entier.
+**When to use:** Pour chaque session, lire la derniere entree pour determiner l'etat.
+
+```go
+func tailReadJSONL(path string, n int) ([]json.RawMessage, error) {
+ f, err := os.Open(path)
+ // Seek vers la fin du fichier
+ // Lire des blocs de ~8KB en arriere jusqu'a trouver n lignes completes
+ // Parser chaque ligne comme JSON
+}
+```
+
+### Pattern 4: Heuristique d'etat
+**What:** Determiner l'etat d'une session a partir du dernier message JSONL.
+**Verification sur machine (resultats reels) :**
+
+| Dernier message | stop_reason | content_types | Etat |
+|-----------------|-------------|---------------|------|
+| `type=assistant` | `end_turn` | `['text']` | **Needs Input** (Claude a fini, attend l'utilisateur) |
+| `type=assistant` | `tool_use` | `['tool_use']` avec `name=AskUserQuestion` | **Needs Input** (Claude pose une question) |
+| `type=assistant` | `tool_use` | `['tool_use']` avec autre outil | **Working** (outil en cours d'execution) |
+| `type=progress` | - | `data.type=agent_progress` | **Working** (subagent actif) |
+| `type=progress` | - | `data.type=hook_progress` | **Working** (hook en cours) |
+| `type=user` avec `content[].type=tool_result` | - | - | **Working** (resultat de tool envoye, Claude va repondre) |
+| Aucun message recent (> seuil) | - | - | **Idle** |
+
+**Important :** le `stop_reason` est dans `message.stop_reason`, pas au top-level.
+
+### Pattern 5: Matching PID -> JSONL (REVISE par la recherche)
+**What:** Trouver le bon JSONL pour un PID donne.
+**Algorithme revise :**
+1. Lire le cwd du PID via `readlink /proc/PID/cwd`
+2. Encoder le cwd pour obtenir le nom du dossier dans `~/.claude/projects/`
+3. Lister les fichiers `.jsonl` dans ce dossier (exclure le sous-dossier `subagents/`)
+4. Prendre le fichier JSONL le plus recemment modifie (= session active)
+5. **NE PAS dependre de `sessions-index.json`** (absent dans 85% des projets recents)
+
+### Anti-Patterns to Avoid
+- **Charger un JSONL entier en memoire :** Les fichiers peuvent depasser 100 Mo. Toujours tail-read.
+- **Dependre de sessions-index.json :** Obsolete depuis ~fev 2026. Seulement 13/91 projets en ont un.
+- **Utiliser `ps aux` via exec :** Lire `/proc` directement est plus fiable et ne depend pas du format de sortie de `ps`.
+- **Ignorer les subagents :** Le dossier `/subagents/` contient des JSONL de sous-agents. Ne pas les confondre avec les sessions principales.
+
+## Don't Hand-Roll
+
+| Problem | Don't Build | Use Instead | Why |
+|---------|-------------|-------------|-----|
+| Parsing des args CLI | Framework CLI (cobra, urfave) | `flag` stdlib | Une seule commande, pas besoin de framework |
+| Couleurs terminal | Lib de couleurs (fatih/color) | Codes ANSI directs | 5 couleurs max, pas besoin d'une dependance |
+| Lecture /proc | Lib procfs | `os.ReadFile` + `os.Readlink` | 3 fichiers a lire par PID, trivial |
+
+**Insight :** Phase 1 est volontairement zero-dependency. La complexite est dans la logique metier (heuristique d'etat, tail-read), pas dans les outils.
+
+## Common Pitfalls
+
+### Pitfall 1: sessions-index.json absent
+**What goes wrong:** Le code essaie de lire sessions-index.json et echoue silencieusement, pas de metadonnees.
+**Why it happens:** Claude Code ne genere plus ce fichier depuis ~fevrier 2026.
+**How to avoid:** Lire les metadonnees directement depuis les entrees JSONL (chaque entree contient sessionId, cwd, gitBranch, version).
+**Warning signs:** 85% des projets recents n'ont pas de sessions-index.json.
+
+### Pitfall 2: JSONL > 100 Mo charge en memoire
+**What goes wrong:** OOM ou lenteur extreme pour une commande one-shot.
+**Why it happens:** Les sessions longues generent des JSONL volumineux (max observe: 23 Mo pour un subagent).
+**How to avoid:** Tail-read : `Seek(0, io.SeekEnd)` puis lire en arriere par blocs de 8-16 Ko.
+**Warning signs:** Temps de reponse > 1s pour `vmux list`.
+
+### Pitfall 3: Race condition sur le JSONL
+**What goes wrong:** Le JSONL est en cours d'ecriture par Claude Code pendant la lecture.
+**Why it happens:** Fichier append-only, ecriture concurrente.
+**How to avoid:** Lire la derniere ligne **complete** (terminee par `\n`). Ignorer une derniere ligne tronquee.
+**Warning signs:** Erreur JSON parse sur la derniere ligne.
+
+### Pitfall 4: Processus Claude != session active
+**What goes wrong:** Un PID Claude existe mais aucun JSONL recent ne correspond.
+**Why it happens:** Claude Code peut etre en phase de demarrage, ou le dossier projet n'existe pas encore.
+**How to avoid:** Afficher le processus avec un etat "Unknown" si aucun JSONL n'est trouve.
+**Warning signs:** PID sans dossier encode correspondant dans `~/.claude/projects/`.
+
+### Pitfall 5: Confusion subagent / session principale
+**What goes wrong:** Des JSONL de subagents sont affiches comme des sessions separees.
+**Why it happens:** Structure `/subagents/agent-*.jsonl` dans le dossier projet.
+**How to avoid:** Ne lister que les `*.jsonl` directement dans le dossier projet, pas dans les sous-dossiers.
+**Warning signs:** Sessions fantomes qui apparaissent et disparaissent.
+
+### Pitfall 6: Double-dash dans l'encoding des chemins avec des points
+**What goes wrong:** `/home/user/.config` s'encode en `-home-user--config` (double dash). Le code d'encoding rate la correspondance.
+**Why it happens:** Les `.` sont remplaces par `-`, ce qui cree un `--` quand un dossier commence par `.`.
+**How to avoid:** L'encoding est simple : remplacer `/` ET `.` par `-`. Verifie sur la machine.
+
+## Code Examples
+
+### Lecture de /proc/PID/cmdline
+```go
+// Source: verification directe sur /proc/13736/cmdline
+func readCmdline(pid int) ([]string, error) {
+ data, err := os.ReadFile(fmt.Sprintf("/proc/%d/cmdline", pid))
+ if err != nil {
+ return nil, err
+ }
+ // cmdline est separe par des null bytes
+ parts := strings.Split(strings.TrimRight(string(data), "\x00"), "\x00")
+ return parts, nil
+}
+```
+
+### Structure d'un message JSONL assistant
+```json
+{
+ "parentUuid": "...",
+ "isSidechain": false,
+ "message": {
+ "role": "assistant",
+ "content": [
+ {"type": "text", "text": "..."},
+ {"type": "tool_use", "name": "Read", "id": "toolu_..."}
+ ],
+ "stop_reason": "tool_use"
+ },
+ "type": "assistant",
+ "uuid": "...",
+ "timestamp": "2026-03-23T11:38:18.236Z",
+ "cwd": "/home/pierre/Code/vibe/vmux",
+ "sessionId": "3a0e1bbb-...",
+ "version": "2.1.81",
+ "gitBranch": "HEAD"
+}
+```
+
+### Structure d'un message progress (subagent)
+```json
+{
+ "type": "progress",
+ "data": {"type": "agent_progress"},
+ "timestamp": "2026-03-23T12:00:43.006Z",
+ "sessionId": "...",
+ "cwd": "..."
+}
+```
+
+### Structure d'un message progress (hook)
+```json
+{
+ "type": "progress",
+ "data": {"type": "hook_progress", "hookEvent": "...", "hookName": "..."},
+ "timestamp": "..."
+}
+```
+
+### Structure d'un message system (fin de tour)
+```json
+{
+ "type": "system",
+ "subtype": "turn_duration",
+ "durationMs": 82049,
+ "timestamp": "...",
+ "sessionId": "...",
+ "cwd": "...",
+ "gitBranch": "HEAD"
+}
+```
+
+## State of the Art
+
+| Old Approach | Current Approach | When Changed | Impact |
+|--------------|------------------|--------------|--------|
+| `sessions-index.json` pour les metadonnees | Metadonnees dans chaque entree JSONL | ~fev 2026 | Ne plus dependre de sessions-index.json |
+| Claude Code v2.0.x | Claude Code v2.1.81 | mars 2026 | Champ `slug` ajoute, `agent_progress` pour les subagents |
+
+## Validation Architecture
+
+### Test Framework
+| Property | Value |
+|----------|-------|
+| Framework | Go testing (stdlib) |
+| Config file | Aucun (convention Go par defaut) |
+| Quick run command | `go test ./...` |
+| Full suite command | `go test -v -race ./...` |
+
+### Phase Requirements -> Test Map
+| Req ID | Behavior | Test Type | Automated Command | File Exists? |
+|--------|----------|-----------|-------------------|-------------|
+| DISC-01 | Detecter les processus Claude actifs | unit | `go test -run TestFindClaudeProcesses -v` | Wave 0 |
+| DISC-02 | Identifier cwd et worktree git | unit | `go test -run TestProcessCwd -v` | Wave 0 |
+| DISC-03 | Afficher la branche git | unit | `go test -run TestGitBranch -v` | Wave 0 |
+| STATE-01 | Detecter l'etat (Working/NeedsInput/Idle) | unit | `go test -run TestDetectState -v` | Wave 0 |
+| STATE-02 | Afficher un apercu de la sortie | unit | `go test -run TestExtractPreview -v` | Wave 0 |
+
+### Sampling Rate
+- **Per task commit:** `go test ./...`
+- **Per wave merge:** `go test -v -race ./...`
+- **Phase gate:** Full suite green before `/gsd:verify-work`
+
+### Wave 0 Gaps
+- [ ] `proc_test.go` -- couvre DISC-01, DISC-02 (testable avec des fixtures /proc simulees)
+- [ ] `session_test.go` -- couvre DISC-03, STATE-02 (fixtures JSONL)
+- [ ] `state_test.go` -- couvre STATE-01 (fixtures JSONL avec differents patterns)
+- [ ] `display_test.go` -- couvre le formatage de sortie
+- [ ] `go.mod` + `shell.nix` -- infrastructure de base
+
+### Strategy TDD
+Les tests pour `/proc` et JSONL doivent utiliser des fixtures (fichiers temporaires) plutot que de lire le vrai `/proc`. Cela permet :
+- Executer les tests en CI sans processus Claude actifs
+- Tester les cas limites (JSONL corrompu, processus zombie, etc.)
+- Reproductibilite totale
+
+## Environment Availability
+
+| Dependency | Required By | Available | Version | Fallback |
+|------------|------------|-----------|---------|----------|
+| Go | Build & run | oui | 1.25.7 (via nix-shell) | - |
+| /proc filesystem | Process detection | oui | procfs Linux 6.19 | - |
+| git | Branch detection | oui | standard NixOS | Fallback sur gitBranch du JSONL |
+
+**Missing dependencies with no fallback:** Aucune.
+
+## Open Questions
+
+1. **Seuil Idle**
+ - Ce qu'on sait : D-05 mentionne "Derniere activite > seuil -> Idle" sans definir le seuil.
+ - Ce qui est flou : 30s ? 60s ? 5min ?
+ - Recommandation : Commencer a 60s. Configurable plus tard. En Phase 1, un const suffit.
+
+2. **Sessions-index.json obsolete vs D-02**
+ - Ce qu'on sait : D-02 mentionne sessions-index.json comme source. La recherche montre qu'il est absent dans 85% des cas recents.
+ - Ce qui est flou : Faut-il quand meme le lire quand il existe (pour le champ `summary`) ?
+ - Recommandation : Lire sessions-index.json en bonus si present (pour `summary`), mais ne JAMAIS en dependre. Le JSONL est la source primaire.
+
+3. **Multiple sessions par cwd**
+ - Ce qu'on sait : Pas observe sur la machine actuelle (6 PID, 6 cwd differents).
+ - Ce qui est flou : Est-ce possible d'avoir 2 processus Claude dans le meme repertoire ?
+ - Recommandation : Prendre le JSONL le plus recemment modifie. Si 2 PID partagent le meme cwd, afficher 2 sessions separees pointant vers les memes JSONL (cas rare, accepter l'imprecision en v1).
+
+## Sources
+
+### Primary (HIGH confidence)
+- Inspection directe de `/proc/*/cmdline`, `/proc/*/cwd` sur la machine (6 processus Claude actifs)
+- Lecture directe de `~/.claude/projects/` : 91 dossiers projets, 13 avec sessions-index.json
+- Analyse de fichiers JSONL reels (format des messages assistant, user, progress, system)
+- Structure verifiee : `/subagents/agent-*.jsonl` pour les sous-agents
+
+### Secondary (MEDIUM confidence)
+- Stack research (CLAUDE.md) : Go 1.25.7 verifie, Bubble Tea v2 pour phases futures
+
+### Tertiary (LOW confidence)
+- Encoding exact des chemins (verifie sur ~10 exemples, peut-etre des cas speciaux non couverts avec des caracteres Unicode ou des espaces)
+
+## Metadata
+
+**Confidence breakdown:**
+- Standard stack: HIGH - Go stdlib uniquement, verifie sur machine
+- Architecture: HIGH - Format JSONL et /proc verifies par inspection directe
+- Pitfalls: HIGH - sessions-index.json obsolete decouvert par inspection reelle (13/91)
+
+**Research date:** 2026-03-23
+**Valid until:** 2026-04-23 (format JSONL stable, /proc stable)