← Back to Blog

LLM Panel Orchestration in OpenClaw: Config-Backed Routing, Timeout Classes, and Honest Dissent Without Chaos

April 3, 2026 | By Jingxiao Cai | Updated August 23, 2026
Tags: openclaw, ai-agents, llm, orchestration, devops, multi-model-review
This post was co-created with Clawsistant, my OpenClaw AI agent. It helped turn a messy internal evolution—manual mixed-panel runs, async handoff bugs, routing drift, and repeated hardening passes—into a cleaner operator memo that actually matches the live system.
April 8 follow-up: I extended this write-up with the later watchdog-hardening pass: deduplicated progress updates, per-run duplicate-state checks, a full regression suite, and one remaining lifecycle edge case that still deserves future cleanup.
April 29 follow-up: I added the final-delivery bridge-back lesson from long-running Discord work: detaching the work is only half the reliability story; the final answer still needs a contract-derived route back to the right conversation.
June 22 follow-up: I added the context-pressure version of the pattern: panel results need artifact-backed completion and a finalizer ledger because a parent thread can be under context, compaction, or write-lock pressure even when the panelists themselves finished correctly.
July 4 follow-up: a private local-model router can be available before it is eligible for the default panel. Local lanes still need soak, role assignment, timeout and weighting policy, and explicit config/Gateway approval before promotion. I expanded that boundary in A Local LLM Router Is Not a Panel Lane Yet.
Update, August 23, 2026: as documented in August 2026, the public surface is one config-backed Standard review mode. I added blind-first evidence, authority-family quorum, source-snapshot drift handling, and terminal-state accounting—including why operational degradation can coexist with an effective result.
Scope note: this post is about the orchestration pattern, not about proving one model is universally best or disclosing the live roster. The point is how to run one review, finish cleanly, surface dissent honestly, and keep routing policy in the right layer.
Another boundary up front: a full Standard panel is expensive and is not my default for routine queries. I use it for worthwhile ambiguity, higher-cost decisions, explicit panel requests, or cases where independent evidence and dissent are worth the latency.

The current public workflow exposes one config-backed Standard mode. Routine questions skip the panel rather than inventing a second public tier.

The Hard Part Was Never “Ask More Models”

Running a full panel of LLMs in parallel is not the interesting problem. Spawning the children is easy. Keeping the result coherent is the real work.

The failures I kept hitting were never glamorous:

  • one expected panelist quietly did not get launched
  • a distinct executor lane finished, but the answer did not auto-surface to the parent thread
  • a partial result arrived, then the orchestrator went silent
  • a slow non-core model held the whole panel hostage
  • a zero-quorum dissent looked louder than it deserved because the authority rules stayed implicit
  • late completions arrived after the real answer was already delivered

The real unit of work is not “query many models.” It is “finish one user-visible review exactly once, with lineup integrity, evidence provenance, visible weighting, and bounded latency.”

That is the problem the consult-panel workflow now solves inside my OpenClaw setup.

Current public shape: one Standard mode resolves its exact authority families, direct lanes, and nonblocking local corroborators from config at runtime. The article keeps the reusable role classes and quorum rules; it intentionally does not freeze a mutable provider/model roster into public prose.

The Design Decision That Saved the Whole Thing

The best decision was architectural, not prompt-related.

The public invocation surface stays deliberately small. Natural requests like consult the panel, panel review, or have the consultants weigh in map into the same Standard orchestration layer, while the routing truth stays in durable config and ops docs rather than inside the prompt wrapper.

The canonical grounding for current behavior lives in three places: the routing config, the consult-panel skill, and the routing operations guide. That keeps the live policy inspectable without hardcoding model/version logic into the user-facing orchestration layer.

Keep the skill thin. Keep the routing truth in config and ops docs.

The user-facing skill exists to do orchestration:

  • detect that the user wants a panel review
  • resolve the configured lineup
  • shape the review packet
  • spawn the panel
  • track completions and synthesize the result

Every panelist gets the same review packet. That sounds trivial, but it is one of the most important fairness rules in the whole workflow: differences in output should come from the models, not from packet drift.

What it does not do is hardcode model/version policy. That lives in durable config and the ops guide instead:

  • routing config
  • operations guide
  • lineup resolver
  • packet-size gate

That split matters because it keeps model churn from leaking into workflow prose. If a route, authority family, local corroborator, or timeout policy changes, I want to edit and validate config—not rewrite orchestration logic in six places.

Naming lesson: the skill is called consult-panel. The only public config-backed mode is standard; retired or internal labels do not create extra public tiers.

What the Current Panel Exposes Publicly

The exact roster is mutable config, not article content. The stable public contract is a set of role classes with different authority and blocking behavior.

Role class Quorum effect Blocking behavior Public meaning
Authority-family lane At most one credit per configured family Counts toward the minimum family quorum Independent decision evidence with verified route/model identity.
Attested direct lane Only through its configured family Must carry a receipt bound to task, model, and report bytes A non-session executor can contribute without weakening provenance.
Nonblocking local corroborator Zero authority quorum May be cancelled after its opportunity window Can add evidence or dissent but cannot manufacture validity.
Degraded or unusable lane No credit Recorded with an operational reason code Missing evidence, timeout, or shape failure is degradation—not a substantive vote.

The important thing is that the current lineup is config-resolved, not reconstructed from memory. A dormant route definition is not an active lane, and several models from the same provider family do not create several independent quorum credits.

If the resolved lineup and the accepted launch set differ, the run is degraded immediately. Here, the configured minima are the minimum usable evidence families and the minimum independent authority-family quorum. If both minima still pass, the result may remain effective; if either fails, the run cannot promote partial evidence into a valid panel.

resolve_panel_shape(mode="standard")

That distinction matters: degraded describes missing or unusable operational evidence. effective answers whether the configured evidence and authority-family gates still passed. They are related, not opposites.

Local-lane promotion note: the same rule applies to private local model routes. A local router can pass health and quality checks and still remain a zero-quorum corroborator or candidate rather than an authority lane. Promotion needs controls, performance, role, failure policy, rollback, and separately reviewed activation; the standalone follow-up is here.

The Schema That Matters More Than the Prompt

The routing config now carries three layers of truth:

  1. role mapping — what each semantic lane currently points to
  2. Standard shape — authority families, minimum usable family quorum, direct executors, and nonblocking corroborators
  3. panel policy — timeouts, evidence requirements, opportunity windows, completion, and degraded behavior

A simplified shape looks like this:

{
  "publicModes": ["standard"],
  "standard": {
    "authorityFamilies": ["<family-a>", "<family-b>", "<family-c>"],
    "minimumUsableFamilies": "<configured quorum>",
    "directExecutors": ["<attested direct lane>"],
    "localCorroborators": {
      "quorumCredit": 0,
      "blocking": false
    }
  },
  "evidencePolicy": {
    "requestedAndServedIdentityRequired": true,
    "atomicLaneArtifactsRequired": true,
    "effectiveStatusDerivedFromConfiguredGates": true
  }
}
Important boundary: this is a sanitized explanatory sketch, not a byte-for-byte dump of live config. It keeps the reusable family/quorum/evidence semantics while omitting mutable models, providers, route labels, counts, and timeouts.

Why Timeout Policy Had To Change

One of the most useful corrections was embarrassingly simple:

Parallel panel timeout is tail-latency control, not additive latency math.

That sounds obvious once you say it. But it matters operationally.

If authority-family quorum is complete and only nonblocking corroborators remain, I should not keep acting as if the panel is incomplete in the same way it would be when required authority families are missing. Those are different situations.

Class Quorum credit Tail policy Practical rule
authority_family At most one per family Wait through the configured authority deadline. Required evidence until family quorum is satisfied or impossible.
attested_direct Through its family only Use the configured direct-executor deadline. Admit only when task, model, report path, bytes, and receipt bind.
local_nonblocking Zero Cancel after the configured opportunity window. Useful corroboration or dissent, never validity by itself.
operational_failure Zero Terminalize with a reason code. Degradation is recorded separately from substantive dissent.

This was the shift from “wait for everyone because fairness” to “wait intelligently because the panel has structure.”

Weighting Helped, But Only After I Put It in Its Place

I do use capability and evaluation evidence as a rough reference band. I do not use it as a vote-counting formula.

The useful signal is structural rather than brand-specific:

  • authority is counted by independent configured family, not raw model count;
  • a direct lane matters only with an executor receipt and verified identity;
  • local corroborators may improve the review but remain zero-quorum;
  • operational failures never become negative votes.
Important caution: capability-informed weighting is helpful only when it stays advisory. The moment it becomes a mechanical vote tally, the system gets performatively rigorous and operationally dumb.

The Async Rules Are Why the Workflow Finally Feels Trustworthy

The strongest part of the current setup is no longer the model lineup. It is the coordination layer around it.

The workflow now explicitly tracks:

  • expected panelists
  • pending vs completed lanes
  • first substantive result arrival
  • whether interim checkpoint updates have already been sent
  • which panelists are eligible for timeout-drop
  • whether a distinct executor surface needs targeted read-back
  • whether the panel is merely closed or fully superseded

The practical control loop looks more like this now:

resolve lineup from config
spawn all expected panelists
track expected vs completed lanes
send one bounded checkpoint when the first real result arrives
send one second checkpoint only if state changes meaningfully
if one executor surface remains, inspect its own receipt before waiting blindly
after the second checkpoint, timeout-drop non-core stragglers
synthesize immediately once all expected lanes are complete or dropped

That is not glamorous. It is also the part that stops the panel from becoming a reliability anti-feature.

Final Delivery Needs a Bridge Back, Not Just a Background Thread

The long-running-work version of this bug has the same shape as the panel bug: the worker can finish correctly while the user-facing conversation still never receives the final result. Moving a task into the background protects the main turn budget, but it does not automatically solve final delivery.

The reliable pattern is a small delivery contract created before the detached work starts. It records the origin conversation, the work conversation, the single update target, and the delivery mode. Default detached work reports to its bound work thread. Bridge-back to an origin thread is explicit, not something the worker infers from memory or a nearby chat summary.

A background worker should never guess where its final answer belongs.

The practical loop now looks like this:

persist a delivery contract before launch
launch the worker with the contract reference and final-ready marker
wait for an explicit final-ready signal
dry-run the delivery plan against the persisted contract
send the final answer once through an idempotent ledger
split oversized finals deterministically instead of truncating them
record delivered message identifiers when the channel returns them

That is deliberately boring distributed-systems hygiene: stable identity, explicit target selection, idempotent side effects, and observable delivery state. The agent-specific twist is that the final answer is prose, not a database row, so duplicate suppression and oversized-message handling need to preserve the user-visible text rather than silently summarize or drop it.

June 2026 Follow-Up: Artifact-Backed Completion Beats Transcript Luck

The later failure mode was subtler: panelists could finish and write useful results, but the parent thread was not always the healthiest place to notice, validate, synthesize, and deliver them. The failure was not “the panel had no answer.” It was “the answer existed in artifacts, while the user-facing orchestration path was under context and delivery pressure.”

That pushed the design one step past status-line completion. A child saying “ready” is now provisional. The durable proof is an expected result artifact in the run directory, validated against the panel ledger. The finalizer reads the ledger, checks each expected lane, and only then decides whether the run is waiting, ready, blocked, or explicitly partial.

resolve expected panel lanes
write a panel-run ledger
record result paths before launch
accept compact child status lines as hints
validate authoritative result artifacts
finalize from the ledger, not from transcript vibes
deliver once through the recorded target

This matters most when the parent conversation is already large. A huge thread can be slow, compacting, or temporarily write-locked. The panel should not lose functional quality just because the parent transcript is an overloaded coordination surface. The safer pattern is to promote the important state into a small artifact ledger and let the parent thread become one consumer of that ledger, not the only place the truth can live.

If a panel result is important, make it recoverable from artifacts before trusting the chat transcript to remember it.

Important boundary: this is a helper-level bridge-back pattern, not yet a native runtime event dispatcher. It is strong enough for local use because delivery targets come from a validated contract and retries are ledger-backed. A true Gateway/runtime event dispatcher would be a different risk class and deserves its own reviewed design.

The general lesson is simple: if a task is long enough to detach, it is long enough to deserve an explicit final-delivery path. Otherwise “background work” just moves the failure from timeout to silence.

August 2026 Follow-Up: Terminal Outcomes Are Data

Blind-first evidence gathering exposed another lifecycle bug: three very different failures were all surfacing as generic command failures. A malformed lane report, a source snapshot that changed after planning, and an operator-typed invalid command do not have the same scope or meaning.

The durable fix was to record expected operational failures at the narrowest correct scope:

Failure Scope Recorded result Next-phase eligibility
Report path, shape, or size is invalid One lane Terminal, non-usable lane with a reason code Recomputed from the remaining evidence
Allowed source fingerprint changed after planning Whole evidence run Atomically invalidated terminal run with changed-root diagnostics False; no synthesis bundle is created
Configured evidence or authority quorum is not met Whole panel Insufficient evidence False
Some evidence is missing but configured minima pass Whole panel Operationally degraded, potentially effective Determined by the explicit gates

Structured controllers should receive a normal terminal payload with fields such as terminal=true and eligibleForNextPhase=false. Human-oriented CLI mode may still use a nonzero exit to make the stop visible. The point is that orchestration code should not have to scrape a process error to discover state the workflow already recorded durably.

freeze evidence
if source fingerprint drifted:
    record run = invalidated
    record terminal = true
    record eligible_for_next_phase = false
    create no synthesis artifact
    return the same terminal state on repeated freeze

Repeated freeze after invalidation must be read-only and idempotent. Otherwise a controller retry can turn one observed source drift into several competing terminal stories.

Snapshot Mutable Inputs Before Planning

A live managed config tree is a bad evidence root because normal unrelated work can change it while gatherers run. The safer pattern is to materialize a point-in-time snapshot outside the live tree, fingerprint the source before and after copying, fingerprint the copy, and refuse the snapshot if any identity differs.

Runtime bytecode and cache files should not invalidate a source tree when they are outside the source-code claim surface. Ignoring those known runtime artifacts reduces false drift, but it creates an explicit boundary: fingerprint equality does not prove that stale compiled bytecode could not affect execution. A clean build or separate runtime test must own that behavior claim.

Key distinction: degraded describes operational coverage; effective describes whether the configured evidence and authority-family predicates passed. A degraded run can be effective. An invalidated source snapshot cannot enter synthesis.
Falsifier: the lifecycle model has failed if an invalid report is counted usable, source drift still produces a synthesis artifact, repeated freeze changes the terminal record, structured mode omits terminal/non-eligibility state, or effective status is computed as “no degradation occurred” rather than from configured evidence and quorum.

Why Watchdog Coverage Had To Become a Launch Invariant

The ugliest real failure was not “a model said something weird.” It was simpler: the panel could emit a clean waiting on X checkpoint and then never speak again.

That is why I no longer treat “children launched” as a valid waiting state by itself. A multi-child run is only allowed to settle into waiting after two things are true:

  1. the resolved lineup matches the accepted spawn set
  2. real follow-up wakes exist to carry the panel to the next checkpoint or terminal synthesis

In my implementation that means a small launch guard plus a watchdog planner. The planner defaults those wakes to visible delivery and rejects internal-only coverage by default, because a hidden watchdog is not much comfort if the user still experiences silence.

Just as important: generated plans are not proof. I only count coverage as real once the follow-up jobs actually exist. When watchdog creation fails, the run is degraded immediately instead of being presented as a trustworthy “waiting” state.

Important boundary: this is stronger orchestration hardening, not a formal guarantee. Real cron-backed visible-delivery watchdog wakes now carry the panel through to synthesis in my local repros, but I still describe the result as best-effort fail-closed behavior, not mathematical certainty.

A second late bug was older queued checkpoints leaking out after a terminal answer. The local fix there was much smaller than the bug report made it sound: a tiny monotonic per-run delivery ledger that suppresses stale intermediate checkpoints while still allowing a legitimate retry of the final answer if delivery itself needs one more shot.

Watchdog Hardening: The Bug Was Not Just Silence, It Was Repeated Almost-The-Same Progress

The next reliability problem was more embarrassing than dramatic. The panel was no longer always going silent, but it could still emit repeated user-facing checkpoint blocks that looked meaningfully new only because they arrived on different async branches.

The important diagnosis was that this was not a transport-duplication issue. The real bug lived in orchestration: child completions and later watchdog/finalization wakes could each recompute the same visible non-terminal state and both decide it was worth sending.

The hardening rule that actually helped was small and specific:

For non-terminal updates, validate not only run identity and closure state, but also whether the same visible progress state for this panel run has already been delivered.

In plain English, the panel now remembers the shape of the last user-visible checkpoint for the current run. If a later async branch only regenerates the same visible progress state, the watchdog is supposed to do nothing and return quietly instead of spamming the thread with a cosmetically fresh duplicate.

  • duplicate same-state checkpoint → suppress it
  • watchdog recomputes the same visible state → suppress it
  • material state actually changes → allow the next bounded checkpoint through

I trust the fix more because it stopped being just a theory. The deterministic regression suite now passes the full targeted duplicate-state cases, including the same-state duplicate case, the watchdog-recomputation case, and the “state really changed, so the next checkpoint is legitimate” case.

What I would still not overclaim: this hardening closes the duplicate-checkpoint class much more convincingly, but one stale lifecycle edge case still deserves a future cleanup pass. Right now it looks more like unnecessary probing/log noise than a user-facing synthesis corruption bug, but it is still not the kind of lifecycle ambiguity I want to leave permanent.

The Two Delivery Bugs That Taught Me the Most

1. Different executors do not share one completion surface

One of the nastier failure modes was: a direct or external executor finished, useful text existed, but the parent thread still looked silent. The fix was not “wait harder.” The fix was to require an executor-specific receipt and targeted read-back when that surface is the last blocker.

2. Fresh user follow-up is not a late duplicate

Another failure mode was subtle: after a final synthesis was already delivered, a true late completion and a fresh user-authored follow-up could land in the same general window. If the orchestrator treated the whole situation as late-result cleanup, it could accidentally suppress the new user instruction.

That is why the current workflow keeps panel-closed and superseded as separate states.

Durable lesson: multi-agent workflows fail less from “the model said something weird” than from lifecycle ambiguity. Most bugs live in the handoff layer.

What I Learned About User-Facing Synthesis

I used to think the final answer should hide as much orchestration detail as possible. That turned out to be half-right.

The user does not need raw routing trivia. But they do need visible weighting.

So the synthesis now tries to make one thing explicit:

Did the disagreement come from independent authority families, or only from zero-quorum corroborators?

That one distinction dramatically improves the trustworthiness of the result. “There was disagreement” is weak. “The authority families aligned; only nonblocking corroborators dissented” is actionable.

What Other People Can Steal From This Pattern

You do not need my exact stack to steal the shape.

If you run any multi-model or multi-agent review workflow, the parts worth copying are:

  1. semantic roles, not hardcoded versions
  2. config-resolved lineup before spawn
  3. same packet for fair comparison
  4. authority-family and zero-quorum distinctions visible in synthesis
  5. watchdog coverage as a launch invariant, not a hopeful afterthought
  6. explicit final-delivery contracts for detached work
  7. timeout as tail-latency control
  8. executor-specific receipts and completion handling
  9. clear distinction between closed, degraded, and superseded runs

What I would not copy is “always ask all models.” Standard review is expensive. It is worth it when the user explicitly asks, or when the decision is ambiguous or costly enough to justify the latency. Routine work should skip the panel instead of inventing a weaker public mode.

In plain English: the system got easier to trust the moment I stopped treating multi-model review as “fan out and pray” and started treating it like a first-class orchestration problem with schema, lifecycle, and delivery rules.

The Design Rule I Trust Most Now

If I had to compress the whole thing into one line, it would be this:

A good panel workflow does not just collect opinions. It defines which opinions count how much, how long they are allowed to block, and how the final answer reaches the user without ambiguity.

That is what changed the workflow from an interesting prompt trick into a reusable piece of operating infrastructure.

Sanitization note: I kept the architecture, role taxonomy, class policy, and workflow lessons because those are the reusable parts. I intentionally left out local session keys, job IDs, run IDs, exact Discord thread IDs, and other runtime fingerprints that would expose the live environment without helping anyone copy the pattern.

About the Author

Jingxiao Cai works on distributed ML runtime systems and likes orchestration systems that fail loudly, surface dissent honestly, and do not depend on one human remembering where all the asynchronous bodies are buried.

If your panel workflow cannot explain why one model was allowed to block the answer and another one was not, it is still running on vibes.

Found this useful? Send it to the person still calling parallel model calls a “simple panel prompt.”

← Back to Blog