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.
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:
- 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.
- 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/. - 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.
{"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.
.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
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
}
}
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
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.