Skip to content

Add swarm dispatch scope and dispatch-mode benchmark harness - #199

Open
khaliqgant wants to merge 1 commit into
mainfrom
claude/multi-agent-factory-benchmarks-rkja61
Open

Add swarm dispatch scope and dispatch-mode benchmark harness#199
khaliqgant wants to merge 1 commit into
mainfrom
claude/multi-agent-factory-benchmarks-rkja61

Conversation

@khaliqgant

@khaliqgant khaliqgant commented Jul 25, 2026

Copy link
Copy Markdown
Member

Change

Adds a new swarm triage scope alongside single/team: a lead + workers share one checkout and a live relay channel (agent-relay MCP messaging — already fully plumbed via AgentSpec.channel -> SpawnInput.channel, just previously unpopulated) instead of team's isolated parallel fan-out. Opt-in only via the agent:swarm label, never inferred heuristically, so existing single/team behavior is unchanged. renderAgentTask now briefs the lead/workers with their coordination channel and each other's names.

Also adds benchmark/ machinery to actually measure whether team/swarm beat a single agent, and whether swarm's live collaboration beats team's isolated fan-out: a task corpus schema + loader, a resumable (task x mode x repeat) matrix builder, a real-dispatch runner (gh + factory dispatch + verify.sh scoring) behind a testable DispatchRunner interface, and a markdown report generator grouped by coordination-benefit difficulty tier. Pure logic is unit-tested; the real-IO adapter is proven by running it (not by mocking child_process) — see benchmark/README.md for what's still required operationally before a real run (a disposable sandbox repo, authored tasks, a live workspace). Includes a SWE-bench Verified adapter script, tested live against 2 real instances, for an externally-comparable subset, with loud caveats about repointing to a controlled fork before dispatching.

Verification

  • Required package check passed on the current head SHA.
  • factory-e2e-<head-sha> attestation artifact was inspected.
  • All actionable review threads are resolved.

Verification tier: Tier 1 (package boundary) — this PR adds new opt-in surface area (a new label-gated scope, a standalone benchmark/ tooling package) with no change to default single/team dispatch behavior; no live/load evidence applies.

Head SHA tested: 42b5a86

Adapter/preview evidence: N/A — no adapter or preview surface touched.

Live canary issue / PR / run: N/A — swarm scope requires an explicit agent:swarm label to activate, so there is no live canary path until a real workspace opts in; benchmark/run.ts is the intended live-canary vehicle for a future run against a real sandbox repo, not run in this PR.

Failure-injection or load evidence: N/A — no runtime/infra behavior change for existing scopes.

Cleanup receipt: N/A — no disposable resources created; npm run verify:e2e's packed-consumer install/tarball are cleaned up by the script itself.


npx tsc -p tsconfig.build.json --noEmit, npx tsc -p benchmark/tsconfig.json --noEmit, and npx vitest run all pass (1422/1428, the 6 failures are pre-existing/environmental — git-sandbox remote-parsing issues and a missing dist/ fixture — unrelated to this diff and reproduce on main).


Generated by Claude Code


Summary by cubic

Adds a new swarm dispatch scope (lead + workers share one checkout and a live relay channel) gated by the agent:swarm label, and introduces a benchmark harness to measure single vs team vs swarm with real tasks and reports.

  • New Features

    • Swarm dispatch:
      • Opt-in via agent:swarm; never inferred.
      • Lead + workers share the same clone and relay channel; reviewer unchanged.
      • renderAgentTask briefs roles and names; AgentSpec.channel and swarmRole set.
      • Orchestrator uses only the first matched repo label for swarm; members capped by triage.maxImplementers.
    • Benchmark harness (benchmark/):
      • Task schema/loader, matrix builder, sequential orchestrator, JSONL results, markdown report.
      • Real runner wires gh + factory dispatch and verifies via task verify.sh (benchmark/run.ts).
      • SWE-bench Verified adapter to seed tasks with caveats; pure logic covered by unit tests.
      • Added script: npm run benchmark.
  • Migration

    • No changes to default single/team/workflow behavior.
    • To try swarm: add agent:swarm to an issue and ensure triage.maxImplementers > 1.
    • To run benchmarks: add tasks under benchmark/tasks/ targeting a disposable sandbox repo, then run npm run benchmark -- --config ./factory.config.json (use --only-task, --only-mode, --repeats to narrow).

Written for commit 42b5a86. Summary will update on new commits.

Review in cubic

Adds a new 'swarm' triage scope alongside single/team: a lead + workers
share one checkout and a live relay channel (agent-relay MCP messaging,
already fully plumbed via AgentSpec.channel -> SpawnInput.channel) instead
of team's isolated parallel fan-out. Opt-in only via the agent:swarm label,
never inferred heuristically. renderAgentTask now briefs the lead/workers
with their coordination channel and each other's names.

Adds benchmark/ machinery to actually measure whether team/swarm beat a
single agent, and whether swarm's live collaboration beats team's isolated
fan-out: a task corpus schema + loader, a resumable (task x mode x repeat)
matrix builder, a real-dispatch runner (gh + factory dispatch + verify.sh
scoring) behind a testable DispatchRunner interface, and a markdown report
generator grouped by coordination-benefit difficulty tier. Pure logic is
unit-tested; the real-IO adapter is proven by running it, not by mocking
child_process. Includes a SWE-bench Verified adapter script (tested live
against 2 real instances) for an externally-comparable subset, with loud
caveats about repointing to a controlled fork before dispatching.

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01H1jnbLuMdTR2hTWv9EUnkq
@cursor

cursor Bot commented Jul 25, 2026

Copy link
Copy Markdown

Bugbot is not enabled for your account, so this pull request was not reviewed.

Enable Bugbot in the Cursor dashboard to get automatic reviews on future PRs.

@coderabbitai

coderabbitai Bot commented Jul 25, 2026

Copy link
Copy Markdown

Warning

Review limit reached

@khaliqgant, you've reached your PR review limit, so we couldn't start this review.

Next review available in: 47 minutes

Enable usage-based reviews in Billing to review now. Otherwise, wait until the next included review is available.
You're only billed for reviews past your plan's rate limits ($0.25/file).

How can I continue?

After more reviews become available, a review can be triggered using the @coderabbitai review command as a PR comment. Alternatively, push new commits to this PR.

To avoid repeated limits, reduce automatic review volume by pausing incremental auto-reviews earlier, using label-based review opt-in, excluding WIP or generated PR titles, or requesting reviews manually when the PR is ready. If your team needs uninterrupted high-volume reviews, an organization admin can enable usage-based reviews.

How do review limits work?

CodeRabbit enforces per-developer PR review limits for each organization. Most developers receive the normal plan review availability.

For paid Pro and Pro+ PR reviews, CodeRabbit uses adaptive limits for sustained high-volume activity. When a developer's recent PR review activity reaches the 95th percentile or higher among CodeRabbit users, additional reviews become available more gradually as earlier reviews age out of the rolling window.

Please refer docs for additional details.

Review details
⚙️ Run configuration

Configuration used: Organization UI

Review profile: CHILL

Plan: Pro Plus

Run ID: 6e4e51e9-70e8-4bc9-a1cd-9a8e6068de26

📥 Commits

Reviewing files that changed from the base of the PR and between 1b9b748 and 42b5a86.

📒 Files selected for processing (32)
  • benchmark/README.md
  • benchmark/cli-dispatch-runner.ts
  • benchmark/dispatch-runner.ts
  • benchmark/matrix.test.ts
  • benchmark/matrix.ts
  • benchmark/orchestrate.test.ts
  • benchmark/orchestrate.ts
  • benchmark/report.test.ts
  • benchmark/report.ts
  • benchmark/results-store.test.ts
  • benchmark/results-store.ts
  • benchmark/run.ts
  • benchmark/schema.ts
  • benchmark/swe-bench-adapter.mjs
  • benchmark/tasks/.gitkeep
  • benchmark/templates/multi-service-feature/task.json
  • benchmark/templates/multi-service-feature/verify.sh
  • benchmark/templates/single-file-fix/task.json
  • benchmark/templates/single-file-fix/verify.sh
  • benchmark/tsconfig.json
  • package.json
  • src/dispatch/templates.test.ts
  • src/dispatch/templates.ts
  • src/orchestrator/factory.test.ts
  • src/orchestrator/factory.ts
  • src/ports/fleet.ts
  • src/triage/heuristic.ts
  • src/triage/index.ts
  • src/triage/schema.ts
  • src/triage/triage.test.ts
  • src/types.ts
  • vitest.config.ts
✨ Finishing Touches
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Commit unit tests in branch claude/multi-agent-factory-benchmarks-rkja61

Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share

Comment @coderabbitai help to get the list of available commands.

@chatgpt-codex-connector chatgpt-codex-connector Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

💡 Codex Review

Here are some automated review suggestions for this pull request.

Reviewed commit: 42b5a86ba0

ℹ️ About Codex in GitHub

Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you

  • Open a pull request for review
  • Mark a draft as ready
  • Comment "@codex review".

If Codex has suggestions, it will comment; otherwise it will react with 👍.

Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".

const channel = swarmChannel(issue)
return swarmMemberSlugs(maxImplementers).map((slug) => ({
name: agentNameForRole(issue, 'impl', { repo: route.repo, discriminator: slug }),
role: 'implementer' as const,

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

P1 Badge Gate swarm publication on lead completion

Every swarm member is registered as an ordinary implementer on the same repository, checkout, and lifecycle branch. The existing exit path publishes a PR for whichever implementer finishes first, while the publication cache and #allImplementersHaveCompletionPr checks are repository/branch-based; consequently, an early worker exit can publish the partially edited shared checkout and make every swarm member appear complete, triggering the babysitter or releasing the still-working lead. Workers need to be non-publishing/non-terminal participants, or publication must wait for the lead after all workers have reported done or blocked.

Useful? React with 👍 / 👎.

'--title', task.title,
'--body', task.issueBody,
'--label', 'factory',
'--label', label,

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

P1 Badge Dispatch more than one agent for team benchmark cells

For each single-repository benchmark task, this creates an issue with only factory and agent:team labels. GitHub mirror routing supplies one repository route, and labelDerivedDispatchDecision creates team implementers by mapping those routes, so the team cell spawns exactly one implementer—the same cardinality as single. The resulting team-versus-single measurements therefore do not test multi-agent fan-out; the runner must provide multiple assignments or use a team mode that splits one repository task among multiple implementers.

Useful? React with 👍 / 👎.

}
log(`created ${task.targetRepo}#${issueNumber} (${label})`)

await exec('node', ['bin/factory.mjs', 'dispatch', issueNumber, '--config', options.factoryConfigPath])

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

P1 Badge Check out each task's configured base revision

The runner never uses task.baseRef before dispatching, so Factory creates its lifecycle branch from the configured checkout's default base instead. This is especially corrupting for SWE-bench tasks, where the adapter records the instance's exact base_commit: agents solve and tests score whatever revision happens to be current in the fork rather than the benchmark instance. Prepare/reset the dispatch checkout at baseRef and ensure the PR uses that base for every cell.

Useful? React with 👍 / 👎.

}
log(`created ${task.targetRepo}#${issueNumber} (${label})`)

await exec('node', ['bin/factory.mjs', 'dispatch', issueNumber, '--config', options.factoryConfigPath])

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

P1 Badge Pass a repository-qualified issue to Factory

The created issue belongs to task.targetRepo, but dispatch receives only its numeric ID. When the benchmark config maps multiple target repositories—as required for a multi-repository SWE-bench subset—a bare number is rejected as ambiguous when it exists in multiple configured repos, or is resolved through repos.default to a different repository. Pass the mounted repository-qualified issue path rather than discarding targetRepo here.

Useful? React with 👍 / 👎.

Comment thread benchmark/run.ts
}

const allResults = await loadResults(RESULTS_PATH)
const rows = buildReportRows(tasks, allResults)

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

P2 Badge Record the wall-clock and cost samples used by reports

buildReportRows is always called without costSamples, and no preceding benchmark code records duration or cost, so every generated report necessarily prints n/a for both advertised metrics. This prevents the harness from measuring whether multi-agent modes improve latency or justify their extra spend; capture these values per run and pass them into the report aggregation.

Useful? React with 👍 / 👎.

Comment thread src/dispatch/templates.ts
'',
`You are a SWARM WORKER collaborating with a lead (${others}) live in this SAME checkout.`,
`Watch the shared relay channel #${swarm.channel} for direction from the lead. Announce what you're starting, ask there if scope is ambiguous, and post when a subtask is done or blocked.`,
'Do not open your own pull request or push to origin yourself — the lead integrates everyone\'s work and finishes it.',

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

P2 Badge Remove the contradictory worker push instruction

This tells a swarm worker not to push, but renderAgentTask immediately appends the common instructions Commit the implementation and tests and Push the branch to origin. Because all swarm members share the same branch and checkout, workers following the later instruction can race the lead's commits or expose an incomplete branch. Render role-specific commit/push instructions so only the lead is asked to push.

Useful? React with 👍 / 👎.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants