Architecture

Purpose

This document provides a high-level architectural overview of fab, showing how its components fit together to supervise coding agents across multiple projects.

System Overview

┌─────────────────────────────────────────────────────────────────────────────┐
│                                fab daemon                                    │
│  ┌─────────────┐  ┌─────────────────────────────────────────────────────┐   │
│  │   IPC       │  │  Supervisor                                         │   │
│  │  (Unix      │◄─┤  - Project registry                                 │   │
│  │   socket)   │  │  - Orchestrators (per-project)                      │   │
│  └──────┬──────┘  │  - Planner agents                                   │   │
│         │         │  - Manager agents                                   │   │
│         │         │  - Permission handling                              │   │
│         │         └─────────────────────────────────────────────────────┘   │
│         │                           │                                        │
│         ▼                           ▼                                        │
│  ┌─────────────┐    ┌──────────────────────────────────────────────────┐   │
│  │ CLI / TUI   │    │  Agents (stream-json)                             │   │
│  │ commands    │    │  ┌─────────┐ ┌─────────┐ ┌─────────┐              │   │
│  └─────────────┘    │  │ Claude  │ │ Claude  │ │ Claude  │ ...         │   │
│                     │  │ Code    │ │ Code    │ │ Code    │              │   │
│                     │  └─────────┘ └─────────┘ └─────────┘              │   │
│                     └──────────────────────────────────────────────────┘   │
└─────────────────────────────────────────────────────────────────────────────┘

Agent Types

All agent types support both Claude and Codex backends via the agent-backend, planner-backend, and coding-backend config keys.

Task Agents

Standard agents that work on issues. Each runs in an isolated worktree and:

Planner Agents

Specialized agents for design and exploration work:

Manager Agents

Interactive agents for user coordination:

Agent Host Protocol

Each agent runs in a host process with its own Unix socket at ~/.fab/hosts/<agent-id>.sock. This allows the daemon to restart and reattach to running agents.

┌───────────────────────────────────────────────────────────────────────┐
│                           fab daemon                                   │
│                                                                        │
│  fab.sock ◄──────────────────────────────────────────────────────┐    │
│      │                                                            │    │
│      ▼                                                            │    │
│  Supervisor ──────► Orchestrator                                  │    │
│                          │                                        │    │
└──────────────────────────┼────────────────────────────────────────┘    │
                           │                                             │
                           ▼                                             │
     ┌─────────────────────────────────────────────────────┐            │
     │              Agent Host Process                      │            │
     │                                                      │            │
     │  hosts/<id>.sock ◄───────────────────────────────────┼────────────┘
     │       │                                              │
     │       ▼                                              │
     │  ┌──────────────────────────────────────┐           │
     │  │         Claude Code                  │           │
     │  │         (subprocess)                 │           │
     │  └──────────────────────────────────────┘           │
     └─────────────────────────────────────────────────────┘

Protocol version: 1.0 (defined in internal/agenthost/protocol.go)

Message types:

Socket path resolution:

  1. FAB_AGENT_HOST_SOCKET_PATH environment variable (exact path)
  2. FAB_DIR/hosts/<agent-id>.sock (base dir override)
  3. ~/.fab/hosts/<agent-id>.sock (default)

Project & Worktree Model

Registry (~/.config/fab/config.toml):

[[projects]]
name = "myapp"
remote-url = "git@github.com:user/myapp.git"
max-agents = 3
issue-backend = "tk"  # or "github", "gh", "linear"
autostart = true
permissions-checker = "manual"  # or "llm"
allowed-authors = ["user@example.com"]
agent-backend = "claude"  # or "codex" (fallback for all agent types)
planner-backend = "claude"  # or "codex" (for planning agents)
coding-backend = "claude"  # or "codex" (for coding/task agents)
merge-strategy = "direct"  # or "pull-request"
linear-team = ""  # Linear team ID (required for "linear" backend)
linear-project = ""  # Linear project ID (optional)

Project directory structure (~/.fab/projects/<name>/):

myapp/
├── repo/                    # Cloned git repository
│   └── .tickets/            # Issue files (tk backend)
├── worktrees/               # Agent worktrees
│   ├── wt-abc123/           # Agent worktree
│   └── wt-def456/           # Another agent worktree
└── manager/                 # Manager agent worktree
    └── wt-manager/

Worktree pool behavior:

IPC Protocol

Daemon Protocol

Unix socket server at ~/.fab/fab.sock with JSON request/response messaging.

Message categories:

Request/Response Envelope

// Request
{
  "type": "host.ping",
  "id": "req-123",
  "payload": { ... }
}

// Response
{
  "type": "host.ping",
  "id": "req-123",
  "success": true,
  "payload": { ... }
}

Stream events (sent to attached clients):

{
  "type": "output",
  "agent_id": "abc123",
  "offset": 1024,
  "timestamp": "2024-01-15T10:30:00Z",
  "data": "..."
}

Dependencies

require (
    github.com/BurntSushi/toml v1.6.0
    github.com/charmbracelet/bubbles v0.21.0
    github.com/charmbracelet/bubbletea v1.3.10
    github.com/charmbracelet/lipgloss v1.1.0
    github.com/spf13/cobra v1.10.2
)

Verification

Build and run the test suite:

$ go build ./...
$ go test ./...
ok      github.com/tessro/fab/internal/...

Check that the daemon starts successfully:

$ fab server start
🚌 fab daemon started
$ fab status
Daemon: running

Examples

Basic workflow

Start the daemon, add a project, and launch the TUI:

fab server start
fab project add git@github.com:user/repo.git --name myproject
fab project start myproject
fab tui

Agent claiming a ticket

From within an agent worktree:

fab issue ready           # List available issues
fab agent claim 42        # Claim issue #42
fab agent describe "Implementing feature X"
# ... do work ...
fab agent done            # Signal completion

See Also