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 tray, desktop notificationsGo
CLI/TUIwatchfireCLI commands + TUI mode. Project-scoped thin clientGo + Bubbletea
GUIWatchfire.appMulti-project thin client (shows all projects)Electron

Data Flow

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

PTY and Terminal Emulation

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

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.

Network

AspectDecision
ProtocolgRPC + gRPC-Web (multiplexed on same port)
PortDynamic allocation (OS assigns free port)
DiscoveryConnection info written to ~/.watchfire/daemon.yaml (only after the gRPC port is accepting connections)
Health checkPing RPC — lightweight empty-to-empty call for connection verification
ClientsCLI/TUI use native gRPC, GUI uses gRPC-Web

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
RobustnessHandles create-then-rename pattern (common with AI tools)
Re-watch on chainWhen agents chain (wildfire/start-all), re-watches to pick up new directories
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

JSONL Transcript Logging

Session logs capture Claude Code's structured JSONL transcripts in addition to raw PTY scrollback. This provides clean, formatted conversation history for reviewing what an agent did during a session.

Transcript discovery: On agent exit, the daemon finds Claude Code's JSONL transcript at ~/.claude/projects/<encoded-cwd>/<sessionId>.jsonl by matching the customTitle field (first line of the JSONL file) against the --name session name passed to Claude. The matched JSONL file is then copied to the Watchfire logs directory.

Log viewing: The ReadLog RPC prefers the .jsonl transcript and formats it as a readable User/Assistant conversation with tool call summaries. If no JSONL transcript is available, it falls back to the .log PTY scrollback.

Both file types are stored side-by-side in ~/.watchfire/logs/<project_id>/ — see the directory structure below for details.

Restart Protection

Wildfire and start-all modes automatically stop chaining after repeated failures on the same task to prevent infinite loops caused by rate limits, crashes, or auth expiry.

AspectBehavior
TriggerSame task restarted 3+ times consecutively without reaching status: done
ActionStop wildfire/start-all chaining, start chat-mode agent instead
CounterPer-project in-memory map (reset on task progression)
ResetCounter resets when a different task is chained (successful progression) or agent is stopped by user
LoggingWarning logged with task number and restart count when limit reached

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      # PTY scrollback (fallback)
        └── <task_number>-<session>-<timestamp>.jsonl     # Claude JSONL transcript (preferred)

Log filename examples:

  • 0001-1-2026-02-03T13-05-00.log — task 1, session 1 (PTY scrollback)
  • 0001-1-2026-02-03T13-05-00.jsonl — task 1, session 1 (Claude JSONL transcript)
  • chat-1-2026-02-03T15-00-00.log — chat mode (no task)

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

<project>/
├── .watchfire/
│   ├── project.yaml    # Project configuration
│   ├── tasks/          # Task YAML files
│   │   ├── 0001.yaml
│   │   ├── 0002.yaml
│   │   └── ...
│   ├── memory.md       # Persistent project knowledge across agent sessions
│   ├── secrets/        # Secrets and setup instructions
│   │   └── instructions.md
│   └── worktrees/      # Git worktrees (one per active task)
│       └── <task_number>/
└── <project files>

On this page