Imported from Consiliency/agent-harness (
phase-loop-runtime/src/phase_loop_runtime/skills_bundle/gemini-advisor-panel/SKILL.md). Install upstream withnpx skills add Consiliency/agent-harness --skill gemini-advisor-panel. Copyright stays with the author.
Advisor Board
Use this skill when a plan, implementation diff, release closeout, or other high-stakes artifact needs an independent cross-vendor review board. This skill was formerly named advisor-panel; that name still resolves as an alias, so existing instructions that say "advisor-panel" keep working.
Source Of Truth
The advisor-board (formerly advisor-panel) implementation is owned by agent-harness:
- Runtime primitive:
phase_loop_runtime.panel_invoker - Board model:
phase_loop_runtime.advisor_board(seats, boards, resolver, validation) - Entry points (runnable default):
advisor_board.composition.compose_review_board+panel_invoker.invoke_board, exposed as thephase-loop advisor-board <artifact>CLI. The legacyavailable_panel_legs/invoke_panel/invoke_panel_requeststay in place for the governed review/pre-merge gates (unchanged, byte-identical golden). - Governed workflow integration: phase-loop governed review/pre-merge paths
Do not call dotfiles advisor-panel scripts, copy provider-specific shell scripts, or introduce a separate implementation in the skill body. The skill is a thin operator guide over the runtime primitive.
Boards & Availability-Aware Composition
Named boards live in phase_loop_runtime.advisor_board.presets; the default review board is code-review, a 4-vendor cross-vendor panel: Claude Fable 5 (claude-fable-5-1), Grok 4.6 (grok-4.6), GPT-6 Astra (gpt-6-astra), and Gemini 3.8 Flash (gemini-3.8-flash). Each seat uses its maximum supported thinking level and a distinct review lens (correctness / adversarial / red-team / alternative-approach).
Composition is AVAILABILITY-AWARE (composition.compose_review_board): it targets 4 independent reviewers (hard floor 3) and NEVER collapses to 1–2 when vendors are down. Each vendor that is both present on PATH AND authenticated gets one lens-distinct seat first; the remaining seats are BACKFILLED onto the available (up + authed) vendors with DIFFERENT lenses. So 2 vendors up still yields a full 4-seat board, and 1 vendor up yields 4 distinct-lens seats on that vendor. The default/premerge board uses the same four model defaults; only the explicit legacy invoke_panel API retains its three-leg shape.
When a president is required, the availability ladder is Fable, then Sol (the GPT seat alias — gpt-6-astra by default; gpt-5.6-sol stays accepted as an explicit legacy id), then Grok 4.6, then Gemini 3.8 Flash. Advance only on a typed president_unavailable result; disagreement or a blocking ruling never triggers fallback.
Three Ways To Feed Material
There are THREE DISTINCT ways to give the panel material. The #114 fix names them accurately: artifact_ref and brief_ref are Read-file-and-stage conveniences, while context_refs is the true by-reference mode.
- Inline (
artifact="...") — small material passed as a string, written verbatim intoreview-bundle.md. A large inline artifact logs a steering warning. - Read-file-and-stage (
artifact_ref="path/to/bundle.md", or a list) — the runtime READS the local file(s) off disk and stages their bytes intoreview-bundle.md(a single path verbatim; multiple paths under per-file headers). This keeps YOUR context lean, but the file CONTENTS still land in the staged bundle every leg reads. Use it when you WANT the legs to read the material verbatim.artifact_refwins overartifactif both are given. brief_ref="path/to/brief.md"— a Read-file-and-stage path for a large review brief; staged asreview-instructions.md. Omit it to use the built-in review/advisory brief.- TRUE by-reference (
context_refs=["path/to/large.pdf", ...], #114) — the runtime stages ONLY a path + metadata manifest (path, size, sha256, MIME/extension, and PDF page count when cheap) plus an instruction telling each leg to OPEN the files with its own local tools. Raw file contents are not read into the bundle or prompt by this runtime path. Use it for LARGE or PRIVATE local material when the selected provider/backing can access the same local file path. A missing/unreadable path fails CLOSED naming the path, unless you passcontext_refs_soft_warn=True(logs a warning and emits anUNREADABLEmanifest entry). Pathnames and hashes can disclose sensitive metadata, and a leg may disclose file contents after it intentionally inspects a referenced file unless an output policy forbids disclosure.
Bounding A Slow Leg
Legs fan out concurrently, so panel wall-clock ≈ max(leg), not sum. Each leg's default timeout is INPUT-SCALED (~600s floor + ~12s/KB) and then raised to a ~1800s backstop.
Liveness is heartbeat-based, not clock-based. A leg is reclaimed when its heartbeat goes EXTINCT — no new stdout/stderr byte AND no process-group CPU advance for 180s — not when a timer expires. Print-mode legs (codex/gemini/grok) heartbeat on any new stdout OR stderr byte (different CLIs stream on different channels — some to stderr, some to stdout — so both are watched); advancing process-group CPU is a secondary signal that can only EXTEND a leg's life, never kill it. The TUI route heartbeats on genuine reviewer progress — novel transcript/output growth — and reports a TUI stall marker carrying the age of the last progress, so cosmetic animation and idle CPU do not keep a wedged leg alive.
The wall-clock deadline is a rarely-hit BACKSTOP. Reliable stall detection is exactly what makes that generous backstop safe.
timeouts_by_leg is a HARD DEADLINE, not a stall threshold. Passing an explicit value
REPLACES the backstop with your number for that leg, and it fires even while the leg is making
healthy progress: {"gemini": 300} kills an attempt at 300s whether or not it is still streaming.
On the print routes it is a deadline per ATTEMPT on the print routes, not a leg-wide ceiling;
the routes differ, and the numbers below are derived from the runtime's retry guards:
codexseat (print route): a soft-empty first attempt that failed fast (elapsed under 0.5 × T) is retried once with a fresh deadline and a fresh liveness clock — worst case just under 1.5 × T.geminiandgrokseats (print route): the same retry, but "fast" is elapsed under 0.5 × (T + 60 s), so the worst case is 1.5 × T + 30 s (1.6 × at T = 300; approaching 2 × as T falls toward 60).claudeseat (TUI route): ONE backstop for the whole leg — a retry gets only the remainder of T, so there T is the leg-wide ceiling.geminiseat, a THIRD clock: the runtime also passes the leg'stimeout_stoagy --print-timeout— agy's own internal wait budget. By default that is the input-scaled default, NOT the raised ~1800 s backstop, so a healthy attempt on that seat can end at ~600 s (+12 s/KB) with a "timeout waiting for response" marker before either heartbeat extinction or the process deadline; the runtime reads that marker as a transient stall. An explicittimeouts_by_legvalue sets both agy's budget and the process deadline to T. When diagnosing that seat, this is the third cause to rule out.
These figures are retry algebra, not absolute wall-clock ceilings. When a deadline fires the leg's process group is sent SIGTERM and given 5 s to exit, then SIGKILL after another 5 s — add ~10 s of teardown to every figure above — and a process that ignores signals can hold its slot past any stated maximum. If policy needs a leg-wide ceiling on a print-route leg, the runtime does not provide one today — size the value for the worst case above, plus teardown, and record that in the policy.
- Default: omit it. Heartbeat extinction already reclaims dead legs, normally long before any deadline is reached.
- Use it only when policy requires an absolute ceiling on an actively-progressing leg.
- Do not reach for it because you saw a leg stall. Stalls are already handled, and a value shorter than the real work converts a recoverable stall into a guaranteed kill: the leg's process group is terminated and it is reported as a timeout result, verdict unwritten.
When a leg does end early, distinguish the two causes before diagnosing: heartbeat extinction
(a [leg-liveness] stall marker, or a TUI stall marker with last_progress_age_s) means the
leg went silent; a hard-deadline expiry means a wall-clock ceiling fired — your override if you
set one, otherwise the ~1800s backstop — so an expiry alone does not prove an override was
passed. They are not the same failure and are not retried on the same basis.
A transient CLI stall (an empty turn or a "timeout waiting for response" marker) is retried once, but only when it fails FAST, so a retry can never double a slow leg's wall-clock.
Use
Optional governed research
For current external evidence, opt in with ResearchPolicy(enabled=True) on the
board. The runtime requires the exact published pmcp==1.20.0
scoped_advisor_audit.v1 capability, creates unique per-seat locks/audits, and
exposes only PMCP health/catalog/describe/invoke backed by Firecrawl and Bright
Data research tools. It disables Codex native web search/apps, derives success
from the completed correlated audit rather than model prose, and emits only
privacy-safe tool IDs, statuses, source hashes, and digests. Claude still runs
only through the subscription TUI adapter—never an API, SDK, direct HTTP call,
gateway backing, or native Task Agent. Harness/agy, Grok, Omnigent, native-host,
and custom-spawn research seats fail closed as
research_profile_unenforceable.
- Prefer the repo's governed phase-loop path when reviewing phase execution or pre-merge work.
- For a standalone smoke or diagnostic, run
phase-loop advisor-board <artifact>(or, in-process, compose withcompose_review_boardand pass the material's path viaartifact_reftophase_loop_runtime.panel_invoker.invoke_board). - Require every leg to end with
AGREE,PARTIALLY AGREE, orDISAGREE. - Treat
EMPTY,TIMEOUT,ERROR,DEGRADED, andUNAVAILABLEas structured evidence, not successful reviews. - Keep provider API keys and custom authorization headers out of the environment; the runtime strips known API-key variables and request-header overrides and uses local subscription CLIs.
- Bound a review→fix→re-review loop before round one (
docs/agent-phase-convergence.md, "Bound the review loop"):- Delta review. After a fix, re-run the seats that dissented (
DISAGREE,PARTIALLY AGREE, or any blocking finding) against the delta since the round they dissented on, and record that delta's base and head. A seat's standing verdict is the usable verdict from its most recent run; a run that endsEMPTY,TIMEOUT,ERROR,DEGRADED, orUNAVAILABLEleaves no standing verdict, and that seat is re-run until it has one — never carried. A seat is carried forward, marked(carried), only when its standing verdict isAGREE; the loop has converged when every seat's standing verdict isAGREE, fresh or carried. Where a gate requires an exact-head unanimous board (the runtime's mandatory LEGIBLE implementation board), that board runs once on the final head after the loop converges; delta review governs the fix rounds before it. - No cancel-on-first-blocker. Let every seat finish the round (a leg that reaches its bound has finished, with that status); collect all findings, then fix once.
- Blocking findings cite what they break. A finding blocks only when it names the
EC-<ALIAS>-<N>it claims is violated; for a change with no roadmap goal, the acceptance criteria or contract the change itself declares; or an existing invariant, published guarantee, or test the change regresses. A finding that names none of these is a suggestion and cannot become the round's new goal — and a defect is never dismissed because the goal it breaks was not written as a roadmap ID. - Round cap → descope. Write the cap into the PR body before round one (three is usual). When it trips: fix input-binding defects, carry findings that pin the change's own outputs to a follow-up, and descope the class the loop kept re-litigating — remove the scope that carries it from the change, leave its goal unclaimed and carried, and record the removal as an exception. Descope never means merging with a blocking finding waived; a blocker that survives the cap and cannot be removed with its scope halts the change for the operator. When each fix adds a new falsifiable number, cut the number and keep the rule.
- Delta review. After a fix, re-run the seats that dissented (
- Every Fable or Opus seat requires the homebrew Claude Code self-PTY adapter after a metadata-only probe proves first-party
claude.aisubscription auth. Never substitute a gateway, API, SDK, direct HTTP call, or native Task/subagent;tui_backing_required,subscription_auth_unproven, andtui_adapter_requiredfail closed.
Standalone Smoke Shape
from phase_loop_runtime.advisor_board.composition import compose_review_board
from phase_loop_runtime.panel_invoker import invoke_board
# Availability-aware by default: compose_review_board seats only vendors that are
# BOTH on PATH and authenticated (unauthed vendors are dropped and backfilled).
board = compose_review_board()
result = invoke_board(board, "", artifact_ref="path/to/bundle.md")
for leg in result.legs:
print(leg.seat_key, leg.status)