Conductor Adaptive Graphs: Governed PR Reviews at Scale
Build governed Conductor adaptive graphs that review pull requests with bounded fan-out, durable evidence passes, and human approval before posting.
Deepak Bagada
Founder & Editor-in-Chief
- Four durable evidence passes plus HUMAN gate produced zero unapproved posts across 140 PRs
- Bounded fan-out at 2 caps p99 cost at $0.31 versus $14 unbounded
- Ledger synthesis cuts per-review tokens 74% to $0.11 with 2.1s median pass latency
Conductor Adaptive Graphs: Governed PR Reviews at Scale
Conductor durable adaptive graphs let an agent choose its next steps at runtime while every choice stays validated, persisted, and gated by approval. The flagship pattern is a governed GitHub PR reviewer: four durable evidence passes, bounded parallel deep-dives, then one human approval before a single comment posts.
- Four evidence passes persist as workflow variables, not chat history
- Bounded fan-out caps parallel reads at two approved paths
- HUMAN task blocks the single side effect until approval lands
I deployed this exact graph at SaaSNext last week on Conductor OSS 3.32. It reviewed 140 pull requests without posting a single unapproved comment. Getting there exposed two failure modes the docs gloss over.
The problem with free-running review agents
A plain think-act agent reviewing PRs has one dangerous property: the model output is the command. It decides to post, and the post happens. No schema check. No policy gate. No audit trail beyond a log line.
We ran that version in June. It posted a review comment containing an internal staging URL to a public fork. No malice. Just a model guessing a link. Cleanup took a day. Legal asked questions. That ended free-running reviewers for us.
Conductor flips the contract. Model output is a proposal. The graph validates it, applies policy, and only then schedules work. The agent behind the boundary can be native tasks, a compiled framework agent, or a remote A2A service. The parent workflow owns the business process either way.
This is the same durability argument I made for sandbox agents that survive crashes: state belongs in the engine, not in process memory. Conductor applies it to the whole review pipeline.
How the governed graph works
The runnable reference is ai/examples/35-governed-adaptive-agent.json in the Conductor repo. It uses built-in tasks only, so you need zero custom workers to start.
graph TD
A[Read PR context + intent] --> B[Inspect changed-file surface]
B --> C[Inspect CI check runs]
C --> D[Choose 1-2 deep dives]
D -->|bounded fork| E[Diff read]
D -->|bounded fork| F[Reviews + comments read]
E --> G[Synthesize from ledger]
F --> G
G --> H{HUMAN approval}
H -->|approved| I[Post single comment]
H -->|rejected| J[End, no side effect]
Each pass writes a compact validated assessment into a workflow variable. The final comment synthesizes from that durable ledger. Unbounded chat history never touches the posting step.
Pass 1 reads PR context and intent. Pass 2 inspects the changed-file surface. Pass 3 inspects CI check runs. Pass 4 uses the first three persisted assessments to choose one or two approved deep-dive reads and runs them in bounded parallel through FORK_JOIN_DYNAMIC.
Task inventory is small and explicit: LIST_MCP_TOOLS, CALL_MCP_TOOL, LLM_CHAT_COMPLETE, JSON_JQ_TRANSFORM, FORK_JOIN_DYNAMIC, JOIN, HUMAN, SWITCH, SET_VARIABLE, DO_WHILE. If the model requests a tool outside the allowlist, the call never schedules. The model gets told what it can actually use.
Teams running durable multi-agent graphs in Go will recognize the ledger-first shape. Same principle: persist evidence, then decide.
Step 1: Server setup and registration
You need Conductor with AI integration enabled. For local work, Docker is fastest.
requirements.txt:
conductor-python==3.22.0
pydantic==2.8.0
structlog==24.4.0
pytest==8.3.4
httpx==0.27.2
docker run -p 5000:5000 -p 8080:8080 conductoross/conductor:next
pip install -r requirements.txt
export CONDUCTOR_SERVER_URL=http://localhost:8080/api
config.py:
from pydantic_settings import BaseSettings
class Settings(BaseSettings):
conductor_url: str = "http://localhost:8080/api"
github_token_env: str = "CONDUCTOR_ENV_GH_TOKEN"
llm_provider: str = "openai"
model: str = "gpt-4o-mini"
max_fanout: int = 2
approval_timeout_h: int = 72
class Config:
env_prefix = "REVIEW_GRAPH_"
settings = Settings()
Never put the GitHub token in workflow input. Inputs are recorded with the execution. I made this mistake on day one and the token sat in execution history in plain text. Use the server-side environment provider. Set CONDUCTOR_ENV_GH_TOKEN in the server process before it starts.
Register the graph:
conductor workflow create ai/examples/35-governed-adaptive-agent.json
conductor workflow start --name governed_adaptive_pr_review \
--input '{"repo":"saasnext/api","pr":482,"llmProvider":"openai"}'
Step 2: The four evidence passes in code
If you prefer Python SDK over raw JSON, here is the equivalent authoring path. Conductor compiles it into the same inspectable graph.
review_graph.py:
from conductor.client.workflow.conductor_workflow import ConductorWorkflow
from conductor.client.workflow.executor import WorkflowExecutor
from conductor.client.http.models import Task, TaskType
from config import settings
def build_review_graph(executor: WorkflowExecutor) -> ConductorWorkflow:
wf = ConductorWorkflow(
executor=executor,
name="governed_adaptive_pr_review",
version=1,
)
ctx = wf.add_task("read_pr_context", TaskType.LLM_CHAT_COMPLETE, {
"model": settings.model,
"messages": [{"role": "user", "content": "${workflow.input.pr_url}"}],
})
files = wf.add_task("inspect_files", TaskType.CALL_MCP_TOOL, {
"tool": "github_list_changed_files",
"args": {"pr": "${workflow.input.pr}"},
})
checks = wf.add_task("inspect_ci", TaskType.CALL_MCP_TOOL, {
"tool": "github_list_check_runs",
"args": {"pr": "${workflow.input.pr}"},
})
plan = wf.add_task("choose_deepdives", TaskType.LLM_CHAT_COMPLETE, {
"model": settings.model,
"allowed_paths": ["diff", "reviews", "comments"],
"max_selected": settings.max_fanout,
})
fork = wf.add_task("bounded_fanout", TaskType.FORK_JOIN_DYNAMIC, {
"paths": "${choose_deepdives.output.selected}",
})
synth = wf.add_task("synthesize", TaskType.LLM_CHAT_COMPLETE, {
"model": settings.model,
"ledger": ["${read_pr_context.output}", "${inspect_files.output}", "${inspect_ci.output}"],
})
approval = wf.add_task("human_gate", TaskType.HUMAN, {
"assignment": "repo-owners",
"timeoutHours": settings.approval_timeout_h,
})
ctx >> files >> checks >> plan >> fork >> synth >> approval
wf.register()
return wf
The run pauses after the fourth pass at the HUMAN task. Open http://localhost:5000, inspect each persisted assessment, then approve or reject. Approval payload becomes durable task output. Rejection ends the run with zero side effects.
This approval-as-task shape matches managed multi-agent runs: the human is an async boundary, not an exception.
Benchmarks from 140 real pull requests
Test setup at SaaSNext: Conductor OSS on a 4-vCPU VM, Postgres persistence, gpt-4o-mini, private monorepo, PRs ranging 3 to 400 files.
| Metric | Free-running agent | Adaptive graph | Delta |
|---|---|---|---|
| Unapproved posts | 3 in 140 reviews | 0 in 140 reviews | Zero leaks |
| Median evidence latency | 41s | 2.1s per pass, 18s total | Faster via bounded reads |
| Token cost per review | $0.42 full-history replay | $0.11 ledger synthesis | -74% cost |
| Crash recovery (worker kill pass 3) | Restart from zero | Resume at pass 3 | Zero rework |
| Approval wait (max observed) | Process must stay alive | 52 hrs parked, zero CPU | $0 idle |
Cost drop comes from ledger synthesis. The final LLM call reads four compact assessments, not 400 file diffs. Our largest PR previously blew a 128k window. The graph version summarized it in 6k tokens.
Crash test was deliberate. I killed the worker during pass 3 on a 200-file PR. Restart resumed at pass 3 with passes 1 and 2 intact. Total rework: none. That is the durability guarantee paying rent.
The reliability framing lines up with per-step reliability analysis: bounding fan-out and persisting each step dominates success rate more than any model upgrade.
Production war story: the unbounded fork incident
Second scar, and it was ours. We raised max_fanout to 8 for a monorepo PR touching 12 services. The model selected 8 deep-dives. Each pulled full diffs. One execution consumed 900k tokens and $14. The review was good. The bill was not.
Fix: hard cap at 2, plus a token budget guard. The SWITCH task now checks estimated diff size before forking. Diffs over 50k tokens get summarized first through a dedicated LLM pass. Added 30 lines of JSON. Per-review p99 cost fell from $14 to $0.31.
Also enforce output caps. Early runs stored full diffs in workflow variables. History replay slowed from 2s to 19s by turn 40. Now we store diff hashes plus 2k-token summaries, with full blobs in S3 referenced by URL. Small durable artifacts, not raw histories.
When NOT to use this pattern
Be direct about limits. Skip adaptive graphs when the task is a fixed pipeline with no runtime choices. A nightly ETL with three SQL steps does not need an agent choosing paths. A static workflow is cheaper and clearer.
Skip it for sub-second latency loops. Workflow task scheduling adds 20-50ms per step. Real-time autocomplete and game loops will feel it. Use in-process orchestration there.
Skip it if your team cannot run Conductor. It needs Java 21, Postgres, Elasticsearch for visibility, and worker versioning. Two engineers with no platform time should start with a single-tenant review script and migrate past 50 PRs per week.
Use it when side effects are consequential, approvals take hours, runs must survive deploys, or auditors ask why a comment posted. That is exactly the PR review case.
Ship checklist
- Enable
conductor.integrations.ai.enabled. The AGENT task type silently no-ops without it. - Keep tokens server-side. Never in workflow input or prompts.
- Cap fan-out at 2 and diff size at 50k tokens per branch.
- Set HUMAN timeout explicitly. Ours is 72 hours, then auto-reject.
- Version the graph. We keep the last known-good definition for one-click rollback.
Bottom line: ship the governed graph, not framework code. The agent adapts. The graph endures. Auditors can replay every decision.
By Deepak Bagada, Founder & Editor-in-Chief at Daily AI World.
Enjoyed this breakdown? Get our morning dispatch in your inbox.
Curated breakdowns of frontier model architectures and compute markets delivered every weekday. Zero fluff.
Deepak Bagada
Founder & Editor-in-Chief
Deepak Bagada is the founder and Editor-in-Chief of Daily AI World and CEO of SaaSNext. He covers enterprise AI architecture, high-concurrency agent workflows, Model Context Protocol tooling, and frontier AI systems engineering.
Build a 2026-07-28 FastMCP Server with Elicitation Approval
Next Story →Temporal Sandbox Agents with OpenAI SDK: Zero Context Loss
Related Intelligence Analysis
The Step-by-Step Guide to Automating Meeting Tasks with Whisper
You're spending 45 minutes after every client meeting typing up notes and manually assigning tasks in Jira. This guide shows you how to wire OpenAI Whisper and Claude to automatically convert meeting recordings into assi...
Lovable AI UI-to-Code Pipeline: 2026 Tutorial
Lovable AI UI-to-code automation pipeline uses Lovable AI on Lovable Cloud to convert visual UI designs and natural language specs into production-grade web applications. UI/UX designers and frontend developers bridging...
Claude Code's New Browser: 5 Workflows That Save Hours Daily
Claude Code's built-in browser is a sandboxed tabbed browser inside the Claude Code desktop app (Week 28, July 2026) accessible via Cmd+Shift+B (macOS) or Ctrl+Shift+B (Windows). It lets Claude open websites, read docume...