> ## Documentation Index
> Fetch the complete documentation index at: https://docs.automagik.dev/llms.txt
> Use this file to discover all available pages before exploring further.

# State Management

> Wish state machine, agent registry, teams, mailbox, team chat, boards, and projects

# State Management

Genie tracks state primarily in PostgreSQL via the embedded [pgserve database](/genie/architecture/postgres). Wishes, tasks, boards, projects, agents, teams, mailboxes, and team chat all live in PG tables. Legacy JSON file state has been replaced by database-backed equivalents.

## Wish State Machine

Wish execution is tracked in PostgreSQL via the task service. A wish becomes a parent task, and each execution group becomes a child task with dependency edges.

### State Transitions

```text theme={"dark"}
blocked → ready → in_progress → done
                       ↓
                     failed
```

| State         | Meaning                                    |
| ------------- | ------------------------------------------ |
| `blocked`     | Waiting for dependencies to complete       |
| `ready`       | All dependencies satisfied, can be started |
| `in_progress` | An agent is actively working on this group |
| `done`        | Group completed successfully               |

### Dependency Resolution

When a group completes, `completeGroup()` recalculates all dependent groups. If every dependency of a blocked group is now `done`, that group transitions to `ready`.

```typescript theme={"dark"}
// Schemas from wish-state.ts
const GroupStatusSchema = z.enum(['blocked', 'ready', 'in_progress', 'done']);

const GroupStateSchema = z.object({
  status: GroupStatusSchema,
  assignee: z.string().optional(),
  dependsOn: z.array(z.string()).default([]),
  startedAt: z.string().optional(),
  completedAt: z.string().optional(),
});
```

The wish state machine stores state in the PG `tasks` + `task_dependencies` tables. PG handles concurrency natively — no file locks are needed for wish state.

## Board State

Boards provide project-scoped Kanban pipelines. Each board has ordered columns with gate types and action skills:

| Table             | Purpose                              |
| ----------------- | ------------------------------------ |
| `boards`          | Board definitions with project scope |
| `board_templates` | Reusable pipeline blueprints         |

Tasks are assigned to board columns via `column_id`. Use `genie board reconcile` to fix orphaned column references after pipeline changes.

## Project State

Projects group boards and tasks into named scopes:

| Table      | Purpose                                       |
| ---------- | --------------------------------------------- |
| `projects` | Named task boards for multi-repo organization |

Tasks scope to projects via `project_id`. When running `genie task list` inside a repo, it auto-scopes to that repo's project.

## Agent Registry

Every spawned agent is tracked in the PostgreSQL `agents` table. The registry stores provider metadata, transport info, and lifecycle state.

### Agent States

```text theme={"dark"}
spawning → working → idle → done
              ↓        ↓
           error    suspended
              ↓
           permission
              ↓
           question
```

| State        | Meaning                                   |
| ------------ | ----------------------------------------- |
| `spawning`   | Agent process being created               |
| `working`    | Actively producing output                 |
| `idle`       | At prompt, waiting for input              |
| `permission` | Waiting for permission approval           |
| `question`   | Waiting for user answer                   |
| `done`       | Task completed                            |
| `error`      | Encountered an error                      |
| `suspended`  | Pane killed, session preserved for resume |

### Agent Record

Each agent record includes:

```typescript theme={"dark"}
interface Agent {
  id: string;            // Unique ID (e.g., "wish-42")
  paneId: string;        // tmux pane ID (e.g., "%16")
  session: string;       // tmux session name
  worktree: string | null; // Git worktree path
  state: AgentState;     // Current lifecycle state
  repoPath: string;      // Repository this agent operates in
  provider?: ProviderName; // "claude" or "codex"
  transport?: TransportType; // Always "tmux"
  role?: string;         // "engineer", "reviewer", "qa", "fix"
  team?: string;         // Team membership
  claudeSessionId?: string; // For session resume
  wishSlug?: string;     // Associated wish
  groupNumber?: number;  // Execution group
}
```

PostgreSQL handles concurrency natively — no file locks needed.

## Team Management

Teams are stored in the PostgreSQL `teams` table. Each team owns an isolated clone of the repository.

### Team Lifecycle

```text theme={"dark"}
created → in_progress → done
                ↓
             blocked
```

### Isolation Model

Teams use `git clone --shared` instead of `git worktree` to avoid a known bug where Claude Code agents can flip `core.bare=true` on the parent repo via shared `.git` metadata, silently corrupting it.

```typescript theme={"dark"}
interface TeamConfig {
  name: string;           // Also the git branch name
  repo: string;           // Source repository path
  baseBranch: string;     // Branch created from (e.g., "dev")
  worktreePath: string;   // Absolute path to clone
  leader?: string;        // Team leader agent name
  members: string[];      // Member agent names
  status: TeamStatus;     // "in_progress" | "done" | "blocked"
  nativeTeamsEnabled?: boolean; // Claude Code native IPC
}
```

## Mailbox

Messages persist to the PostgreSQL `mailbox` table before any push delivery attempt. This ensures durability — even if tmux delivery fails, the message is stored in the database.

### Message Format

```typescript theme={"dark"}
interface MailboxMessage {
  id: string;          // Unique message ID
  from: string;        // Sender worker ID or "operator"
  to: string;          // Recipient worker ID
  body: string;        // Message text
  createdAt: string;   // ISO timestamp
  read: boolean;       // Whether recipient has read this
  deliveredAt: string | null; // null = pending delivery
}
```

Delivery is state-aware: messages are queued and pushed to tmux panes only when the agent is idle (not mid-turn). A sent message log is also kept in an append-only JSONL outbox file.

<Warning>
  Mailbox delivery is best-effort. Messages are persisted to PostgreSQL (durable), but tmux pane injection is not retried. If a pane dies, the message stays with `deliveredAt: null`.
</Warning>

## Team Chat

Each team has a group chat stored in the PostgreSQL `team_chat` table.

```typescript theme={"dark"}
interface ChatMessage {
  id: string;        // Unique message ID
  sender: string;    // Agent name
  body: string;      // Message text
  timestamp: string; // ISO timestamp
}
```

Team chat is scoped per team — each team maintains its own chat history in the database.
