Skip to content

Shard / hybrid orchestration

mini-tui · mini-agent-rs

How does `mini-agent-rs orchestrate` split one coding task into many small jobs that run at the same time, and still end with code that builds?

A coordinator written in ordinary code (no AI model planning) works out which files the task is about. It prepares ONE shared conversation (the whole repo plus the task) and starts one worker per file. Each worker is a copy of that conversation plus an instruction: change only your file. If a model call is slow, a backup copy of it starts and whichever good answer arrives first is used. A simple check sends suspicious answers back for another try. Files are saved as answers arrive, then the code is formatted and checked; if the check fails, only the files named in the error are repaired.

Every box is a real piece of the code, drawn like a UML class: «stereotype» and name, then − attributes, + operations, – responsibilities. Click a box for its details and the steps it follows. Dashed arrows go back up the flow (retries and loops).

options + --hybridtask, file listtarget filesshared conversationone thread per jobup to 8 callsrequestanswer + tokensnew file contentsrejected → next copyacceptedall jobs donefailed: blamed filesformat + check againpassed / failed «entry point» Command: mini-agent-rs orchestrate Shortcut for `shard --hybrid` − task (-t): text− repo folder (--root): folder− check command (--verify): command− parallel calls (--max-inflight): number+ start the program: exit code+ hand over to the coordinator: exit code– Exit code 0 means the final check passed«coordinator · plain code» Coordinator Runs the job; never calls a model itself − backup delay: 3 s at first− repair rounds: 2− call limit: shared counter− retry wait: 1 s to 3 s− text-only answers: on+ run the whole job: exit code+ pick target files: list of files+ run the workers: results per file+ format, then check: pass or error text– Choose the files, start the workers, run the final check– Write the report stats.json (time, check result, tokens, calls)«plain code · no model» Target picker Which files get their own worker − file topics: words per file− ignored words: set of words+ find each file's topic: words per file+ find "do not touch" words: set of words+ choose the targets: list of files– A file is a target if the task names its path, or its topic word appears in the task– If nothing matches, every file is a target; the check fills any gap later«common starting point» Shared conversation Built once, copied into every worker − 1st message: system: role description− 2nd message: user: whole repo + task− 3rd message (optional): contract+ print the repo: text+ does the task spell exact names?: yes / no+ ask for a contract: contract text– Exactly the same text for every worker, so the provider can reuse its cache«job planner» Work splitter One worker per file, or small balanced groups − max files per group: 6− parallel calls: number− size of a file: bytes + 400+ split targets into jobs: groups of files– Up to 2× the parallel-calls limit → one worker per file– More files → groups of neighbouring files, balanced by size, so all jobs fit in about one round of the rate limit«speed against slow answers» Backup calls (hedging) Copies race; the first good answer wins − max calls per job: 8− answer times: list of seconds− backup delay when repairing: 2 s+ when to start a backup: seconds+ run a job with backups: answer, tokens, call count– Beat the provider's slow outliers (a 150-token answer that takes 20 s)– A failed or rejected answer starts a new copy right away«worker» Worker (copy of the conversation) Shared conversation + "change only YOUR FILE(S)" − messages: shared conversation + its own instruction− edit mode: yes / no− model settings: per call+ write its instruction: text+ ask the model: text + tokens used+ apply search-and-replace edits: new file or failure+ read the answer: new content, or "unchanged"– Do not investigate, plan or review: just carry out the instruction– Use the task's names exactly (plural of <E> = name + s)«external service» AI model service zai/glm-5.3-flash or MiniMax-M3.1-Flash − rate limit: about 10 at once (Zai)− retry wait: random ×0.5–1.5, max 3 s+ call with retries: answer or error+ ask for text only– Returns the answer text and the tokens it used«plain-code check» Answer check Sends suspicious answers back − copies that must pass: first 5− "unchanged" double-checks: 2− required texts: list+ find required texts per file: texts per file+ does the task mention this file's layer?: yes / no+ judge an answer: OK, or a reason to retry– A target file answered "unchanged" although the task names its layer → confirm with another copy– A quoted text is missing → ask again, with the reason as a note«saved results» Files on disk Saved as each job answers − changed: yes / no per file− per-call details: file, seconds, start time, calls, tokens, group+ save a result: per-file stats– Keep the repo up to date as answers arrive«verification» Final check Format the code, then run the check − check command: command− repair rounds used: up to 2+ format the Go files+ run the check: OK or error text+ find the blamed files: list of files– The only step left that runs alone: adds 2–5 s when it fails«repair» Repair round Only the files the check blames − files to fix: list− error shown: last 3000 characters of the error− backup delay: 2 s+ run workers on the blamed files: results per file– Show each worker the CURRENT repo and the check error, and have it fix its file«report» Report (stats.json) Written with -o stats.json − total time: seconds− mode: hybrid− check result: passed, failed or none− tokens: sent / not cached / received− calls: details per file– Sums up the run for benchmarks

Source: agent-rs/src at perf/hybrid-shard-clones 062b27f (PR #96); shard core merged in #94 and #95

Node by node

«entry point»

Command: mini-agent-rs orchestrate

agent-rs/src/main.rs:396

Shortcut for `shard --hybrid`

Attributes

  • task (-t): text— What to change. If it spells exact names (in `backticks`, {braces} or "quotes"), those names are the contract to follow.
  • repo folder (--root): folder— The repository to edit (only files tracked by git).
  • check command (--verify): command— The final check, e.g. go build ./... && go vet ./...
  • parallel calls (--max-inflight): number— How many model calls may run at once (8 on Zai/Zhipu, 24 on other providers).

Operations

  • start the program: exit code— Loads the .env settings, sets up Ctrl+C handling and adds the --hybrid option (main.rs).
  • hand over to the coordinator: exit code— Calls the coordinator (shard::client) with --hybrid added.

Responsibilities

  • Exit code 0 means the final check passed

What it does inside

  1. Loads the settings file (.env) and sets up clean shutdown on Ctrl+C.
  2. Passes everything to the coordinator with --hybrid added. The older design from speed7 (a planning model first) is still available with `shard --clones`.

«coordinator · plain code»

Coordinator

agent-rs/src/shard.rs:711

Runs the job; never calls a model itself

Attributes

  • backup delay: 3 s at first— How long a call may run before a backup copy starts; adapts later
  • repair rounds: 2— Maximum attempts to fix a failing check
  • call limit: shared counter— Never more than the parallel-calls limit in flight, across all workers
  • retry wait: 1 s to 3 s— Min and max wait after a "too many requests" (429) error
  • text-only answers: on— Models reply with plain text, no tool calls (no tool list at all on GLM)

Operations

  • run the whole job: exit code— shard::client
  • pick target files: list of files— scope()
  • run the workers: results per file— hybrid::run
  • format, then check: pass or error text— gofmt, then the check command

Responsibilities

  • Choose the files, start the workers, run the final check
  • Write the report stats.json (time, check result, tokens, calls)

What it does inside

  1. Reads the list of tracked files and the model settings, and switches to text-only answers.
  2. Sets short retry waits (1 s to 3 s): every call already has backups, so a rejected call should be retried quickly.
  3. Creates the shared call limit, picks the target files and hands them to the workers.
  4. Adds any new files the workers created to the format and repair lists, then formats the code, runs the check and, if needed, the repair rounds.

«plain code · no model»

Target picker

agent-rs/src/shard.rs:659

Which files get their own worker

Attributes

  • file topics: words per file— MenuList.tsx → "menu". A word that appears in many file names (like "list") is treated as a suffix, not a topic
  • ignored words: set of words— Words from sentences that say keep / unchanged / do not touch

Operations

  • find each file's topic: words per file— subjects()
  • find "do not touch" words: set of words— excluded()
  • choose the targets: list of files— scope()

Responsibilities

  • A file is a target if the task names its path, or its topic word appears in the task
  • If nothing matches, every file is a target; the check fills any gap later

What it does inside

  1. Wanted words = words of the task, minus the "do not touch" words.
  2. A file is a target when the task quotes its path or one of its topic words is wanted.
  3. All files are still shown to the model as background; only the number of workers shrinks (task t09: 20 → 4 workers).

«common starting point»

Shared conversation

agent-rs/src/hybrid.rs:243

Built once, copied into every worker

Attributes

  • 1st message: system: role description— "You are the lead engineer … workers that are copies of this conversation apply the change"
  • 2nd message: user: whole repo + task— Every tracked file printed out, then the task
  • 3rd message (optional): contract— Only when the task does not spell out exact names

Operations

  • print the repo: text— dump()
  • does the task spell exact names?: yes / no— Yes if it has `backticks`, { or a quote
  • ask for a contract: contract text— The only optional step that runs on its own, before the workers

Responsibilities

  • Exactly the same text for every worker, so the provider can reuse its cache

What it does inside

  1. Conversation = [role description, repo + task].
  2. If the task does not spell out its contract, one model call writes it (names, function signatures, JSON field names, status codes) and it is added to the conversation.
  3. The conversation is shared read-only by all worker threads (no copy per thread).

«job planner»

Work splitter

agent-rs/src/hybrid.rs:360

One worker per file, or small balanced groups

Attributes

  • max files per group: 6— Tried 15: one file was missed in 7 of 8 calls
  • parallel calls: number
  • size of a file: bytes + 400— The extra 400 covers the minimum cost of answering any file

Operations

  • split targets into jobs: groups of files— units()

Responsibilities

  • Up to 2× the parallel-calls limit → one worker per file
  • More files → groups of neighbouring files, balanced by size, so all jobs fit in about one round of the rate limit

What it does inside

  1. Files are taken in path order, so related files stay together (all types/*.ts, all components).
  2. A group closes when its size passes total ÷ parallel calls, or when it reaches 6 files.
  3. Each group runs on its own thread.

«speed against slow answers»

Backup calls (hedging)

agent-rs/src/shard.rs:299

Copies race; the first good answer wins

Attributes

  • max calls per job: 8— The first call plus its backups
  • answer times: list of seconds— How long answers took in this round
  • backup delay when repairing: 2 s— Used by the repair rounds

Operations

  • when to start a backup: seconds— The starting delay until ¼ of the round has answered (at least 3), then 2× the typical (median) time, kept between 1.5 s and the starting delay
  • run a job with backups: answer, tokens, call count— hedged()

Responsibilities

  • Beat the provider's slow outliers (a 150-token answer that takes 20 s)
  • A failed or rejected answer starts a new copy right away

What it does inside

  1. Takes a free slot and starts the first call.
  2. Looks every 250 ms or less; when the newest call is older than the backup delay and a slot is free, starts a backup copy.
  3. Good answer → records how long it took and returns it. Error or rejected → starts another copy, up to 8 calls.
  4. Calls that lost the race simply free their slot when they finish.

«worker»

Worker (copy of the conversation)

agent-rs/src/hybrid.rs:280

Shared conversation + "change only YOUR FILE(S)"

Attributes

  • messages: shared conversation + its own instruction
  • edit mode: yes / no— First call on a file over 600 bytes: answer with search-and-replace edits; backups send the whole file
  • model settings: per call— GLM: thinking off, no tools; backup calls get their own extra settings

Operations

  • write its instruction: text— clone_order()
  • ask the model: text + tokens used
  • apply search-and-replace edits: new file or failure
  • read the answer: new content, or "unchanged"

Responsibilities

  • Do not investigate, plan or review: just carry out the instruction
  • Use the task's names exactly (plural of <E> = name + s)

What it does inside

  1. Copies the conversation and adds the instruction for its file(s), plus a note when a previous copy was rejected.
  2. One file: edits (first call, file over 600 bytes) or the whole file between <<<FILE … FILE>>> markers. Several files: one block, or `UNCHANGED <path>`, per file.
  3. If an edit cannot be applied, it counts as an error, and a backup copy answers with the whole file.

«external service»

AI model service

agent-rs/src/models/http.rs:308

zai/glm-5.3-flash or MiniMax-M3.1-Flash

Attributes

  • rate limit: about 10 at once (Zai)— Above that: error 429, code 1302
  • retry wait: random ×0.5–1.5, max 3 s— So parallel calls never retry all at the same moment

Operations

  • call with retries: answer or error— with_retry()
  • ask for text only— Tells the model not to use tools, or sends no tool list (models/wire.rs:78)

Responsibilities

  • Returns the answer text and the tokens it used

What it does inside

  1. Retries "too many requests" (429) and server (5xx) errors, waiting a bit longer each time with some randomness, up to the limit in MINI_AGENT_RETRY_MAX_WAIT.
  2. The provider caches the shared start of the conversation: extra workers mostly pay only for their instruction and answer.

«plain-code check»

Answer check

agent-rs/src/hybrid.rs:215

Sends suspicious answers back

Attributes

  • copies that must pass: first 5— Later copies are accepted as they come
  • "unchanged" double-checks: 2
  • required texts: list— Exact message texts the task quotes for this file

Operations

  • find required texts per file: texts per file— required()
  • does the task mention this file's layer?: yes / no— layer_named()
  • judge an answer: OK, or a reason to retry— doubt()

Responsibilities

  • A target file answered "unchanged" although the task names its layer → confirm with another copy
  • A quoted text is missing → ask again, with the reason as a note

What it does inside

  1. A rejected answer is reported as an error ("doubted: …"), so the backup mechanism starts the next copy, whose instruction includes the reason.
  2. A wrong suspicion never blocks a file: after 5 copies, answers are accepted.

«saved results»

Files on disk

agent-rs/src/shard.rs:523

Saved as each job answers

Attributes

  • changed: yes / no per file
  • per-call details: file, seconds, start time, calls, tokens, group

Operations

  • save a result: per-file stats— Writes the new content only if it differs, and returns the file's numbers (record())

Responsibilities

  • Keep the repo up to date as answers arrive

What it does inside

  1. An "unchanged" answer leaves the file as it is.
  2. For a group of files, tokens and call count are counted on the first file only.

«verification»

Final check

agent-rs/src/shard.rs:859

Format the code, then run the check

Attributes

  • check command: command— go build / go vet / gofmt in the benchmark
  • repair rounds used: up to 2

Operations

  • format the Go files— gofmt -w on every tracked .go file
  • run the check: OK or error text
  • find the blamed files: list of files— Files named in the error; if none, every file

Responsibilities

  • The only step left that runs alone: adds 2–5 s when it fails

What it does inside

  1. No check command → counts as passed.
  2. Fails → a repair round on the blamed files, then format and check again, at most 2 times.

«repair»

Repair round

agent-rs/src/shard.rs:871

Only the files the check blames

Attributes

  • files to fix: list— The files blamed by the error
  • error shown: last 3000 characters of the error
  • backup delay: 2 s

Operations

  • run workers on the blamed files: results per file— Same one-shot workers as the main round (wave())

Responsibilities

  • Show each worker the CURRENT repo and the check error, and have it fix its file

What it does inside

  1. Instruction added: "The repo above is the CURRENT state. The check fails with: … Fix this file so the check passes."
  2. Uses the same workers as the first round, also with backup calls.

«report»

Report (stats.json)

agent-rs/src/shard.rs:896

Written with -o stats.json

Attributes

  • total time: seconds
  • mode: hybrid
  • check result: passed, failed or none
  • tokens: sent / not cached / received
  • calls: details per file

Responsibilities

  • Sums up the run for benchmarks

What it does inside

  1. Prints one line: files, targets, files written, check result, repair rounds, total seconds.