A vast bronze great hall with five forges arranged in a semicircle, each tended by a hooded smith with a glowing rune overhead, threads of amber light connecting their anvils into a knowledge-sharing web
Chapter 27 · Act V, Integrate

Team Coordination

Two developers running Plan Forge on the same repo at the same time hit three predictable problems: concurrent edits collide at merge time, hard-won fixes stay trapped in one developer's local .forge/, and a productive day turns every reviewer into a bottleneck. This chapter shows how Plan Forge solves all three with a single shared file and a few GitHub API calls, no SaaS backend, no shared database, no new identity system.

How it's built (v2.93 → v3.4). Five surfaces compose the team layer: forge_team_dashboard + forge_team_activity (per-developer visibility), forge_github_metrics + forge_github_status (PR throughput + validation stack), forge_delegate_review (dispatching review to Copilot's cloud agent), and forge_classifier_issue (closing the tempering audit loop by filing a GitHub issue when a classifier rule needs to land).

The "shared shop" problem

The three coordination problems in detail:

  1. Concurrent edits. Both might pick the same plan, or pick plans whose Scope Contracts touch the same files. Without visibility, you discover the conflict at merge time.
  2. Lost institutional memory. Alice solves a tricky gate-portability issue on Monday. Bob hits the same issue on Wednesday because Alice's trajectory lives in her local .forge/.
  3. Review fatigue. Plan Forge runs are productive, a single afternoon can ship 4 plans. If every plan needs a human reviewer, the bottleneck moves from "writing code" to "reviewing code".

v3.x addresses each, in order: team dashboard for visibility, shared activity ledger + memory sync for institutional memory, delegated review for the review bottleneck.

The activity ledger

Everything starts with one file: .forge/team-activity.jsonl. It is an append-only JSON Lines log that every Plan Forge operation writes to. One event per line, never edited, never compacted.

Team coordination flow: multiple developer worktrees on the left (alice/feature-auth, bob/feature-billing, carla/hotfix-db, plus N more) each append one event per slice complete to the central team-activity.jsonl ledger. On the right, four readers consume the same ledger: forge_team_dashboard renders per-developer cards with a conflict-risk score, forge_team_activity tails raw events with filters, forge_classifier_issue files GitHub issues to close the tempering audit loop, and the Dashboard Team tab provides a live view at localhost:3100. The ledger is append-only and never compacted; conflict risk is calculated as file-overlap (Jaccard) times time-window proximity.
Figure 27-1. Team coordination, many writers, one ledger, four readers
{"ts":"2026-05-17T09:14:22Z","actor":"alice@example.com","action":"plan.start","plan":"Phase-31","sha":"a1b2c3d"}
{"ts":"2026-05-17T09:18:41Z","actor":"alice@example.com","action":"slice.commit","plan":"Phase-31","slice":"2","sha":"e4f5g6h"}
{"ts":"2026-05-17T09:31:02Z","actor":"bob@example.com","action":"plan.start","plan":"Phase-32","sha":"a1b2c3d"}
{"ts":"2026-05-17T09:33:11Z","actor":"alice@example.com","action":"plan.complete","plan":"Phase-31","slices":6,"costUsd":2.41}

The file is small (typical: 50–200 KB per team-week), git-friendly (line-stable), and trivially indexable. Every team query in this chapter is a streaming read of this file.

Where it lives. By default, .forge/team-activity.jsonl is not gitignored, that's the point. Commit it. The ledger is most useful when every developer's events land in one shared history. If you don't want it in git, set team.ledger.gitignore: true in .forge.json and use a side channel (S3, shared volume) instead.

forge_team_dashboard — per-developer cards

forge_team_dashboard reduces the ledger into one card per developer, capturing the last 7 days (default; configurable):

forge_team_dashboard({ windowDays: 7 })

// Response shape (excerpt):
{
  generatedAt: "2026-05-17T14:00:00Z",
  windowDays: 7,
  developers: [
    {
      actor: "alice@example.com",
      lastActive: "2026-05-17T09:33:11Z",
      runs: 12,
      successRate: 0.917,
      costUsd: 28.40,
      plans: ["Phase-31", "Phase-30", "Phase-29"],
      activePlan: null
    },
    {
      actor: "bob@example.com",
      lastActive: "2026-05-17T09:31:02Z",
      runs: 4,
      successRate: 1.0,
      costUsd: 6.12,
      plans: ["Phase-32"],
      activePlan: "Phase-32"      // currently running
    }
  ],
  totals: { runs: 16, successRate: 0.938, costUsd: 34.52 }
}

This is what backs the Team dashboard tab, one card per developer, sorted by recency, with a visual badge for "currently running a plan". The same shape powers the pforge team-dashboard CLI command for terminal users.

The conflict-risk banner

Above the cards, the dashboard renders a conflict-risk banner computed from the active plans of any two developers running simultaneously. The risk score is derived from Scope Contract overlap:

Score Trigger Banner
none No active plans, or disjoint Scope Contracts (hidden)
low Active plans touch sibling files in the same directory "Alice and Bob are both working in src/orders/, sync up before merge."
medium Active plans share at least one file path "⚠️ Alice and Bob are both editing src/orders/repository.ts."
high Active plans share files AND share modified symbols (per forge_diff) "🚨 High collision risk. One of you should pause."

forge_team_activity — querying the ledger

Where forge_team_dashboard aggregates, forge_team_activity queries. Pass any combination of filters:

forge_team_activity({
  actor:   "alice@example.com",   // optional, who
  plan:    "Phase-31",            // optional, what
  action:  "slice.commit",        // optional, kind
  since:   "2026-05-10T00:00:00Z",// optional, when
  limit:   100,                   // bounded; default 50, max 1000
  cursor:  null                   // pagination
})

// Response:
{
  events: [ /* event objects */ ],
  total: 47,
  hasMore: false,
  cursor: null
}

This is the tool to reach for when answering questions like "what did Alice work on last week?" or "show me every slice that Phase-31 took and who ran which retry". It is also the data source for the pforge team-activity CLI and the GET /api/team/activity REST endpoint.

forge_github_metrics + forge_github_status

The activity ledger captures everything that happens inside Plan Forge. forge_github_metrics and forge_github_status capture everything that happens around it: PR throughput, review latency, CI validation results.

forge_github_metrics

Pulls PR-level analytics from the GitHub API:

  • PRs opened / merged / closed in window
  • Time-to-first-review per PR (median + p95)
  • Time-to-merge per PR (median + p95)
  • Review iteration count distribution
  • Per-author breakdown matching the team ledger's actor identities

The dashboard's GH Metrics tab is a thin renderer over this tool's response.

forge_github_status

The validation stack on a single PR. Given a PR number, returns:

  • Required and optional checks with their current state
  • Review status (approved / changes-requested / pending) by reviewer
  • Mergeable state including conflicts
  • Branch protection rule violations (if any)
  • Linked issues + their open/closed status
Composable pattern: chain forge_team_activity({ action: "plan.complete" }) → for each plan, find its PR → forge_github_status({ pr: N }). This gives you a single-pane view of "what shipped last week and what state is each PR in".

forge_delegate_review — dispatching to Copilot

Plan Forge's reviewer step (the Reviewer Gate) is independent, a fresh session reads the plan's Scope Contract and audits the diff. By default it runs locally. forge_delegate_review dispatches the same audit task to the GitHub Copilot cloud coding agent, so the review happens server-side and the result lands as a PR comment.

forge_delegate_review({
  pr: 247,
  plan: "docs/plans/Phase-31-PLAN.md",
  scope: "scope-contract",   // or "full-plan" | "diff-only"
  blockOn: "critical"        // file CHANGES_REQUESTED on critical findings
})

// Response:
{
  ok: true,
  jobId: "copilot-job-7f3a...",
  dispatched: "2026-05-17T14:22:11Z",
  pr: 247,
  estimatedCompletion: "2026-05-17T14:27:00Z"
}

Configuration lives under cloudAgentValidation in .forge.json:

{
  "cloudAgentValidation": {
    "enabled": true,
    "agent": "copilot",              // current option: copilot
    "trigger": "post-slice-commit",  // when to dispatch
    "blockOn": "critical",
    "timeoutMinutes": 15,
    "fallback": "local-reviewer"     // if cloud dispatch fails
  }
}
Why "delegate" and not "replace"? The local Reviewer Gate is faster and cheaper (your tokens, your machine). The cloud agent is asynchronous, shareable, and produces a PR comment that everyone on the team sees. Use the local reviewer in tight inner-loop iterations; use delegation when shipping for human-team review.

forge_classifier_issue — closing the audit loop

The tempering subsystem (Audit Loop chapter) audits classifier output and finds false-positive findings or missed-detection rules. Once tempering has confirmed a rule is needed, forge_classifier_issue files a structured GitHub issue against the rule repository so the rule lands in code, not in a side note.

forge_classifier_issue({
  classifier:  "audit",
  ruleId:      "audit-stub-detection",
  category:    "missed-detection",      // or "false-positive"
  evidence:    [ /* before/after finding pairs */ ],
  severity:    "high",
  rationale:   "Three sweeps in a row missed inline TODO markers in JSX comments."
})

// Response:
{
  ok: true,
  issueNumber: 312,
  issueUrl: "https://github.com/.../issues/312",
  deduped: false,
  hash: "sha256:..."
}

The tool deduplicates against open issues with the same rule + category hash within 14 days, so repeated audit findings don't spam the tracker. This is the official "self-repair" path for classifier rules, analogous to forge_meta_bug_file for plan/orchestrator/prompt defects.

Where to find this in the dashboard

Tab Backed by Surfaces
Team forge_team_dashboard Per-developer cards, conflict-risk banner, "currently running" badges
Team Activity forge_team_activity Timeline view of the ledger with filter chips
GH Metrics forge_github_metrics PR throughput, review latency, per-author breakdown
PR Status (drill from any PR link) forge_github_status Required checks, reviewers, mergeability

CLI summary

pforge team-dashboard              # per-developer cards in the terminal
pforge team-dashboard --json       # machine-readable
pforge team-activity --since=7d    # query the ledger
pforge team-activity --actor=alice@example.com --action=slice.commit
pforge gh-metrics --window=30d     # PR throughput
pforge gh-status --pr=247          # validation stack for one PR
pforge delegate-review --pr=247 --plan=docs/plans/Phase-31-PLAN.md
See also: The Audit Loop for how tempering produces the findings that forge_classifier_issue dispatches. Chapter 26 — The Copilot Integration Trilogy for how shared memory hints close the "Bob hits Alice's bug" gap. Chapter 7 — The Dashboard for the full tab tour.