# Architecture

This document explains how Legionnaire's components work together to orchestrate git worktrees, tmux sessions, and LLM agents.

## Overview

Legionnaire coordinates three systems:

```mermaid
graph LR
    L[Legionnaire] --> G[Git Worktrees]
    L --> T[tmux Sessions]
    L --> A[LLM Agents]

    G --> B[Branches]
    T --> W[Windows]
    A --> P[Processes]
```

## The Two-Layer Model

Legionnaire uses a parent/child hierarchy:

```mermaid
graph TD
    subgraph "Parent: feature-x"
        PW[Parent Worktree<br/>feature-x/parent]
        PS[tmux Session<br/>:feature-x]
    end

    subgraph "Child: task-a"
        CW1[Child Worktree<br/>feature-x/task-a]
        TW1[tmux Window<br/>:task-a]
        AG1[Agent Process]
    end

    subgraph "Child: task-b"
        CW2[Child Worktree<br/>feature-x/task-b]
        TW2[tmux Window<br/>:task-b]
        AG2[Agent Process]
    end

    PW --> CW1
    PW --> CW2
    PS --> TW1
    PS --> TW2
    TW1 --> AG1
    TW2 --> AG2
```

### Parent

The parent provides:

- **Integration workspace**: A worktree where child work is merged
- **tmux session**: Container for all windows
- **Base point**: Children branch from parent's HEAD

### Children

Each child provides:

- **Isolated worktree**: Independent working directory
- **Feature branch**: Based on parent's HEAD at creation
- **tmux window**: Terminal in the parent's session
- **Agent process**: LLM CLI running in the window

## Component Interaction

### Initialization Flow

```mermaid
sequenceDiagram
    participant User
    participant CLI
    participant Git
    participant tmux
    participant Agent

    User->>CLI: legion init parent child
    CLI->>Git: Create parent worktree + branch
    CLI->>tmux: Create session
    CLI->>tmux: Create parent window
    CLI->>Git: Create child worktree + branch
    CLI->>tmux: Create child window
    CLI->>Agent: Launch in child window
    CLI->>User: Done
```

### Removal Flow

```mermaid
sequenceDiagram
    participant User
    participant CLI
    participant Agent
    participant tmux
    participant Git

    User->>CLI: legion remove parent child
    CLI->>Agent: SIGTERM (then SIGKILL)
    CLI->>tmux: Kill window
    CLI->>Git: Remove worktree
    CLI->>Git: Delete branch
    CLI->>User: Done
```

## Stateless Design

Legionnaire maintains minimal state:

| Component | State Location |
|-----------|---------------|
| Worktrees | Git's worktree registry |
| Branches | Git's ref store |
| Sessions | tmux server |
| Windows | tmux server |
| Agents | PID file in worktree |

The only file Legionnaire writes is `.legion-agent.pid` in each child worktree.

### Discovery

Instead of maintaining a manifest, Legionnaire discovers state from:

1. `git worktree list --porcelain` - Find worktrees
2. `git for-each-ref` - Find branches
3. tmux server - Find sessions and windows
4. PID files - Find agent processes

This makes the system robust: partial states can be reconciled by running `init` again.

## tmux Integration

### Session Ownership

Legionnaire marks its sessions with:

```
@legion_managed=1
```

This prevents accidentally modifying user sessions with the same name.

### Window Ordering

Windows are kept in deterministic order:

1. Parent window at index 0
2. Children at indices 1..N in lexicographic order

This ensures consistent navigation across sessions.

### Color Scheme

Colors are assigned by position in sorted order:

```
Parent: Red (colour196)
Child 0: colour27
Child 1: colour33
Child 2: colour39
...
```

This provides visual consistency across sessions.

## Agent Management

### Process Lifecycle

```mermaid
stateDiagram-v2
    [*] --> Launching: init with --agent
    Launching --> Running: Process started
    Running --> Running: Working
    Running --> Stopped: Process exits
    Stopped --> Running: Re-init
    Running --> Terminated: remove
    Terminated --> [*]
```

### PID Tracking

The PID file enables:

- **Status checking**: `os.kill(pid, 0)`
- **Graceful shutdown**: SIGTERM then SIGKILL
- **Idempotency**: Don't relaunch if running

### Launch Strategy

Agents are launched via bash to ensure correct PID tracking:

```bash
bash -lc 'echo $$ > .legion-agent.pid; exec claude'
```

The `exec` replaces the bash process, so the recorded PID is the agent's.
