Watchfire
Concepts

Architecture

Understand Watchfire's architecture — a daemon orchestrates coding agents while thin clients connect over gRPC.

Architecture

Watchfire follows a daemon + thin client architecture. A single daemon process (watchfired) manages all orchestration, while lightweight clients (CLI/TUI and GUI) connect over gRPC to display state and accept user input.

Components

ComponentBinaryRoleTech
DaemonwatchfiredOrchestration, PTY management, terminal emulation, git workflows, gRPC server, system trayGo
CLI/TUIwatchfireCLI commands + TUI mode. Project-scoped thin clientGo + Bubbletea
GUIWatchfire.appMulti-project thin client (shows all projects)Electron

Data Flow

User → CLI/TUI or GUI → gRPC → Daemon → PTY → Coding Agent (Claude Code)

                              Git Worktrees
                              File Watching
                              Sandbox (macOS)

The daemon is the single source of truth. Clients are stateless views that subscribe to updates.

Network

AspectDecision
ProtocolgRPC + gRPC-Web (multiplexed on same port)
PortDynamic allocation (OS assigns free port)
DiscoveryConnection info written to ~/.watchfire/daemon.yaml
ClientsCLI/TUI use native gRPC, GUI uses gRPC-Web

PTY and Terminal Emulation

Watchfire uses a real PTY (pseudo-terminal) to run coding agents, with terminal emulation to parse escape codes:

sandbox-exec (macOS sandbox)
       ↓ contains
Coding Agent (e.g., Claude Code)
       ↓ runs inside
     PTY (github.com/creack/pty)
       ↓ raw output with escape codes
   vt10x (github.com/hinshun/vt10x)
       ↓ parsed into
   Screen Buffer (rows × cols grid)
       ↓ streamed via
     gRPC to clients

The screen buffer is a 2D grid of cells, each with character, foreground/background color, and style attributes (bold, italic, underline, inverse). The cursor position is also tracked.

File Watching

The daemon uses fsnotify to watch for changes to task files:

AspectBehavior
Mechanismfsnotify with debouncing
Global watched~/.watchfire/projects.yaml
Per-project watched.watchfire/project.yaml, .watchfire/tasks/*.yaml
Polling fallbackTask-mode agents poll task YAML every 5s as safety net
ReactionFile changes trigger real-time updates to connected clients

Crash Recovery

ScenarioBehavior
Daemon crashes mid-taskOn restart, user must manually restart task
Agent crashesDaemon detects PTY exit, stops task

Directory Structures

Global (~/.watchfire/)

~/.watchfire/
├── daemon.yaml         # Connection info (host, port, PID)
├── agents.yaml         # Running agents state
├── projects.yaml       # Projects index
├── settings.yaml       # Global settings
├── installation_id     # Stable UUID for analytics
└── logs/               # Session logs
    └── <project_id>/
        └── <task_number>-<session>-<timestamp>.log

Per-Project (<project>/.watchfire/)

<project>/
├── .watchfire/
│   ├── project.yaml    # Project configuration
│   ├── tasks/          # Task YAML files
│   │   ├── 0001.yaml
│   │   ├── 0002.yaml
│   │   └── ...
│   └── worktrees/      # Git worktrees (one per active task)
│       └── <task_number>/
└── <project files>

On this page