Tall stone watchtower at dusk with amber lantern-eyes scanning a foggy valley dotted with distant forge fires, read-only observation of other projects' forge runs
Act III, Guard · Chapter 19

The Watcher

A second pair of eyes on a running forge. Read-only by design.

New here? Read this first. You kick off a long Plan Forge run, maybe an hour of work across 30 slices, and you want to watch it happen without distracting the AI that's doing the work. The Watcher is exactly that: open a second VS Code window, point it at the running project, and ask “how's it going?” The Watcher reads the live event stream and tells you. It cannot edit, commit, or change anything in the project being watched, that's a safety guarantee, not a feature gap.
  • Snapshot mode, instant point-in-time read. Free. “Slice 12 of 30, no errors, $4 spent so far.”
  • Analyze mode, same data but with an AI summary. Costs a few cents. “Run is healthy but Slice 8 retried twice on a flaky test, worth investigating.”
  • Live tail, short streaming window (default 60 seconds). Useful when you suspect something is hanging.
Read-only watcher. The Watcher runs in a separate VS Code Copilot session with Plan-Forge as the workspace and points at another project that's executing a plan. It cannot modify anything in the target, it only reads.

Why a Watcher?

When you execute a long plan (pforge run-plan) the executor session is focused on one thing: building the next slice. It's not a good place to also answer "how's it going?" for a second human, or to notice anomaly patterns across multiple runs. The Watcher is the operational counterpart, it tails the run, reads event streams, and summarizes state.

Two-session topology: Session 1 (Build/Target) runs pforge run-plan in a VS Code window, with its own WebSocket hub on port 3101 and append-only files in .forge/runs/. Session 2 (Watcher) runs in a second VS Code window with its own working directory and uses forge_watch (snapshot, file reads only, $0) and forge_watch_live (bounded window WebSocket subscription with polling fallback). Watcher writes only to its own .forge/watch-history.jsonl, never to the target. The watcher's input schema exposes no write paths to the target.
Figure 19-1. Two-session topology

Two modes, one tool:

  • Snapshot (forge_watch), file-reads only, zero AI cost. Returns slice counts, token usage, gate errors, anomalies.
  • Analyze (forge_watch with mode=analyze), invokes a frontier model (default claude-opus-4.7) to produce narrative advice from the snapshot.

Live Tail — forge_watch_live

For near-live observation, forge_watch_live tails the event stream for a bounded window:

  • WebSocket mode, connects to the target's hub if running (.forge/server-ports.json).
  • Polling fallback, tails events.log when the hub isn't up.
  • Default window: 60 seconds. Range: 1 s – 1 hr.
  • Captures up to 500 events in the response payload.
Snapshot vs Live Tail comparison table: Data source (file reads vs WebSocket/log tail), Cost ($0 always vs $0 baseline + frontier model in analyze mode), Window (point-in-time vs bounded durationMs default 60s), Returns (counts/anomalies/advice/cursor vs event stream up to 500 events), Best for (spot checks vs live debugging), History (watch-history.jsonl vs cursor chaining).
Figure 19-2. Snapshot vs Live Tail comparison table
Typical usage from the Watcher session
forge_watch {
  targetPath: "E:/GitHub/Rummag",
  mode: "snapshot"
}

forge_watch_live {
  targetPath: "E:/GitHub/Rummag",
  durationMs: 30000
}

Anomaly Rules

The snapshot watcher runs heuristic rules over the run state and surfaces anomalies automatically. Examples:

  • review-queue-backlog, independent reviewer slices piling up.
  • tempering-run-failed, a Tempering run returned non-zero.
  • mutationBelowMinimum / flakyCount / perfRegressionCount, Tempering quality thresholds breached.
  • Crucible funnel stalls, ideas stuck in Crystallized with no hardener handoff.

Anomalies are emitted as watch-anomaly-detected hub events and appear in the dashboard's Watcher tab.

Distributed teams or remote runs? The Watcher only observes what's on the same machine. To watch a forge running on another host, or to forward anomalies to phones, Slack, or Discord, pair it with the companion Chapter 20 — The Remote Bridge.

Watch History

When recordHistory=true (the default in v2.35+), each snapshot is appended to the Watcher session's own .forge/watch-history.jsonl, never the target's. Pair with sinceTimestamp (pass the previous report's cursor) for gap-free continuous monitoring across multiple invocations.

Dashboard Watcher Tab

The dashboard's Watcher tab consumes two event types:

  • watch-snapshot-completed, emitted when forge_watch builds a snapshot.
  • watch-anomaly-detected, emitted when one or more anomaly rules fire.

Chip rows surface Tempering state, Crucible funnel state, and a Home chip showing in-flight runs / open incidents / open bugs, all without touching the target project.

Security Model

Read-only by contract. The Watcher's input schema exposes no write paths. It reads .forge/runs/<runId>/ and emits events to its own hub. History writes go only to the Watcher's cwd. Verified by the read-only subscriber test in pforge-mcp/tests/.

Pairing the Watcher With the Remote Bridge

A natural pairing: the Watcher runs headless on a long run, and the Remote Bridge (Chapter 20) forwards hub events to Telegram, Slack, Discord, or OpenClaw so you can check progress from your phone. The Watcher never pushes, it just observes; the Remote Bridge decides what to surface.