Data flow
frites has two surfaces over one shared engine, and they have distinct end-to-end flows. The gateway intercepts every prompt and synthesizes the assistant turn; the MCP worktree path runs N competing full implementations and reconciles them into one vetted diff. This page traces both.
The two flows differ at the front but share the same core shape: request → continuation/fan-out decision → children → oracle/synthesis → result.
Gateway request flow
The gateway sees one inbound request per host turn (POST /v1/messages for Claude Code, POST /v1/responses for Codex). Its flow:
Classify the traffic. Background/utility calls (host haiku traffic for title generation, summarization, classification) are pinned to a single child and never fan out.
Detect continuation. A turn is a tool-loop continuation when the request carries a tool result back: an Anthropic
tool_resultin the last user message, or a Responsesfunction_call_output. This is stateless: it is read from the request shape alone, so it is correct across restarts and concurrent sessions with no server-side session memory.Decide whether to fan out.
fanOutScope(defaultfirst-turn) bounds which turns even get the question: fan out on the substantive request turn, then drive the mechanical tool-loop continuations with a single agent.fanOutPolicy(always | auto | necessary | never) decides whether an allowed turn is worth fanning out; underautoa heuristic short-circuits trivial prompts and an LLM fan-out judge makes the final call. See Fan-out scope.Run the council.
Answer turns call
runAnswerCouncil: N children answer independently and concurrently (collected withPromise.all; a failed child becomes a textual failure block so the synthesizer still gets a complete input set), then the synthesizer adjudicates one final answer.Coding turns call
runActionCouncil: N children each propose exactly one next action as JSON, hallucinated tool names are rejected against the host allowlist, and the synthesizer selects one action verbatim.
Stream the result. Over SSE: for answer turns only the synthesizer streams into the final answer block; on a coding turn the gateway encodes the selected action as a host-executed
tool_use(stop_reason: "tool_use"). The host executes the tool under its own permission model and returns the result, which arrives as the next continuation turn (step 2). Each turn carries per-turn cost telemetry and a closing council recap line.
The synthesizer is config.defaultAgents[0] invoked with role: "synth"; children round-robin the same array. The reconciliation rules are canonical in Synthesis & reconciliation. The proxy design is in Gateway.
MCP / worktree implementation flow
The worktree path is candidate selection over complete implementation attempts, not answer synthesis. Starting from the normal session:
Invoke. User in normal Claude Code says "use frites to implement X" → the host calls
frites_implement {task, repoPath, n?, agents?}.Set up. The engine resolves the base commit, decides N, and creates N isolated git worktrees. The
EnvSandboxbuilds an allowlist env per child (auth kept, base-URLs scrubbed,FRITES_DEPTHincremented).Execute children.
AgentRunnerspawns detached headless children that edit in isolation concurrently. The engine streamsnotifications/progress("agent 2 editing app.ts / running tests").Capture diffs. Each candidate's work is captured as
git diff --staged.Oracle-filter. Run the configured or auto-detected oracle commands (build, lint, test) per candidate. Candidates that errored, timed out, were empty, or touched no files are dropped.
Reconcile.
One passing candidate → recommend it.
Zero passing candidates → surface the closest near-miss via
heuristicJudge(or one grounded feedback round, then re-filter).Multiple passing candidates → tie-break with
heuristicJudge(smallest changed-line count, then fewest files).
Optional synthesis. When
synthesisModeis"passing-only"(default) and at leastsynthesisMinCandidatescandidates pass, a synthesizer agent integrates the passing deltas in a fresh worktree seeded with the best passing candidate's diff, then the result is re-run through the same oracle and preferred only if it passes and stays withinsynthesisMaxBlastFactor ×the combined input size. See Synthesis & reconciliation.Present. Return
structuredContentplus aresource_linkto each diff; the caller persists diffs and run metadata. The user reviews the recommended diff and per-candidate comparison.Apply.
frites_apply {runId}lands the diff on a fresh branch (git switch -c frites/<runId> && git apply --3way), the one mandatory human gate. It accepts acandidateIdto land a tighter passing child instead.
How the two flows relate
Both flows follow request → continuation/fan-out decision → children → oracle/synthesis → result, but the verification depth differs:
Children produce
One proposed answer or next action each
A complete implementation (diff) each
Verifier
Host tool loop executes the selected action and returns the result next turn
Repo build/lint/test oracle runs against each candidate
Reconciliation
LLM synthesis (answers) / verbatim selection (actions)
Oracle filter + deterministic smallest-diff tie-break + optional gated synthesis
Result
Streamed assistant turn
Recommended diff + comparison, applied on approval
The gateway keeps everyday interaction friction low; the worktree path provides the strongest correctness signal because candidates are actual diffs tested against real commands. See Risks & tradeoffs for the "better output, slower" tradeoff.
Related pages
Gateway: the proxy surface.
MCP worktree mode: the worktree surface.
Core engine: the shared engine state machine and event model.
Fan-out scope: which turns fan out.
Synthesis & reconciliation: how outputs are reconciled.
Last updated