CONCEPTS · STANDING REVIEW POOLS

Standing review pools

A standing review pool is a team of reviewer agents that stays running between reviews. Start one with start-review-team/synthex:start-review-team, and every review-code/synthex:review-code or performance-audit/synthex:performance-audit that matches its roster hands the work to reviewers that are already warm — no per-review spawn.

Why it exists

By default, every review-code/synthex:review-code spawns its reviewers fresh, runs them, and throws them away. That's the right trade for occasional reviews. When you review many times an hour — a fast-moving branch, a pre-commit flow where you're waiting on the result — the spawn cost on every run adds up.

A pool pays that cost once. The reviewers sit idle until a review arrives, an idle reviewer claims the task, and you get the same consolidated report the normal path produces.

For a few reviews a day, skip pools. The default path is simpler and the idle pool isn't worth it.

Requirements

Pools are built on Claude Code's Agent Teams feature, so they only work on Claude Code:

  • The Agent Teams flag. Set CLAUDE_CODE_EXPERIMENTAL_AGENT_TEAMS=1 and restart Claude Code. start-review-team/synthex:start-review-team checks for it before doing anything else.
  • The Agent Teams tools. The pool commands check that SendMessage and ListAgents are in the session's tool list. On a host without them, start-review-team/synthex:start-review-team, stop-review-team/synthex:stop-review-team, and list-teams/synthex:list-teams print a one-line notice and stop. review-code/synthex:review-code and performance-audit/synthex:performance-audit keep working there with their normal reviewers.
  • Routing turned on. Commands only look for a pool when standing_pools.enabled: true. It's off by default.

configure-teams/synthex:configure-teams is the exception: it only writes config, so it runs on any host. That lets a team on mixed tools set up the shared config from wherever they are.

Quick start

# 1. Turn on routing (writes standing_pools to .synthex/config.yaml)
/synthex:configure-teams

# 2. Start a pool with the default roster (code-reviewer, security-reviewer)
/synthex:start-review-team

# 3. Review as usual — the command finds the pool on its own
/synthex:review-code

# 4. Stop the pool when you're done
/synthex:stop-review-team --name review-pool

When a review routes to a pool, the command says so:

Routing to standing pool 'review-pool' (multi-model: no).

and the report header starts with Review path: standing pool 'review-pool' (multi-model: no).

Lifecycle

A pool moves through four states, which list-teams/synthex:list-teams shows:

StateMeaning
idleNothing pending or in progress. Available for routing.
activeOne or more reviews pending or in progress. Still available for routing.
drainingFinishing in-flight reviews before shutdown. Not accepting new work.
stoppingShutdown signal sent, waiting for confirmation. Disappears from the list soon.

Start. start-review-team/synthex:start-review-team validates the name and roster, spawns a Pool Lead plus one teammate per reviewer, and records the pool in a shared index at ~/.claude/teams/standing/index.json. Pools live under your home directory, so a pool is visible to every session on the machine — but only routes reviews whose roster it matches.

Route. A matching command submits its review as tasks to the pool, waits up to lifecycle.submission_timeout_seconds (default 300) for the result, and presents the pool's consolidated report as its own. A pool can only serve reviews while the Claude Code session that started it is still open.

Idle and TTL. A pool that sits idle past ttl_minutes (default 60) becomes eligible for shutdown. TTL is enforced lazily: nothing watches the clock. The next time something looks for pools — a list-teams/synthex:list-teams call or a routed review — it notices the expired pool and treats it as gone. Set ttl_minutes: 0 to turn off TTL reaping entirely.

Stale pools. Pools don't outlive the Claude Code session that started them. When a pool's metadata directory is missing, or it's been inactive longer than the TTL or 24 hours (whichever is longer), the next routed review cleans it up, prints a one-time warning, and carries on without it.

Stop. stop-review-team/synthex:stop-review-team asks the Pool Lead to shut down, lets in-flight reviews finish, and removes the pool from the index.

How routing works

review-code/synthex:review-code and performance-audit/synthex:performance-audit check for a pool first, before resolving the diff or spawning anyone. A pool matches when it is a standing pool, isn't draining or stopping, hasn't passed its TTL, and its roster fits the reviewers the command needs:

  • review-code/synthex:review-code needs the reviewers from its --reviewers flag, or code_review.reviewers in config, or code-reviewer + security-reviewer if neither is set. Prompt-file reviewers are dropped from that set — a pool can only hold agents — and they don't run when a pool handles the review. If every configured reviewer is a prompt file, the command skips pool routing.
  • performance-audit/synthex:performance-audit always needs performance-engineer, so only a pool that includes it will match.

matching_mode decides what "fits" means:

  • covers (default) — the pool's roster includes every required reviewer. A pool with code-reviewer, security-reviewer, and performance-engineer serves both commands.
  • exact — the pool's roster is exactly the required set, nothing more.

If several pools match, the first by name wins.

routing_mode decides what happens when nothing matches, or a routed review times out:

  • prefer-with-fallback (default) — fall back silently to fresh reviewers. You always get a review.
  • explicit-pool-required — abort with an error naming the missing reviewers and the start-review-team/synthex:start-review-team command that would fix it. Use this when you want to catch a misconfigured or stopped pool rather than quietly paying for fresh reviewers.

When a reviewer fails mid-review. If one pool reviewer crashes, the command re-runs just that reviewer fresh, merges its findings with the rest of the pool's report, and adds a note at the top saying which reviewer was recovered. If the pool itself fails (the Pool Lead crashes, or draining times out), the command falls back to a full fresh review.

Configuration

Pool settings live under standing_pools: in .synthex/config.yaml. These are the shipped defaults:

standing_pools:
  enabled: false # turn on routing from review-code / performance-audit
  ttl_minutes: 60 # idle minutes before a pool can be reaped; 0 = never
  default_name: review-pool # pool name when start-review-team gets none
  default_reviewers: # roster when start-review-team gets none
    - code-reviewer
    - security-reviewer
  default_multi_model: false # start new pools with multi-model review on
  routing_mode: prefer-with-fallback # or explicit-pool-required
  matching_mode: covers # or exact

lifecycle:
  submission_timeout_seconds: 300 # how long a command waits on a pool before falling back

lifecycle is a top-level key, not nested under standing_pools, because it governs the session submitting the review rather than the pool.

The pool storage paths (~/.claude/teams/standing and ~/.claude/tasks/standing) appear in the defaults file but aren't configurable — every session relies on them to find pools.

Pool names must be 1–48 lowercase letters, digits, and hyphens, starting with a letter or digit. index, standing, and names starting with . are reserved.

Legacy config file. If .synthex/config.yaml has no standing_pools block, Synthex still reads it from the old .synthex-plus/config.yaml, printing a deprecation warning. That fallback lasts for one major version. Move the block over (same key, same shape), or run

configure-teams/synthex:configure-teams, which always writes the new location.

Agent Teams hooks

Turning on standing_pools.enabled also activates two Synthex hooks on Agent Teams events:

  • TaskCompleted blocks a teammate from completing a non-documentation task until the completion note records Review verdict: PASS or Review verdict: WARN. The block message names the reviewers the work type needs. Turn it off with hooks.task_completed.review_gate.enabled: false.
  • TeammateIdle hands an idle teammate the next unblocked task that matches its role. Standing-pool teammates are exempt — the Pool Lead manages them. Turn it off with hooks.teammate_idle.work_assignment.enabled: false.

Both fail open, and each nags only once per task, so neither can deadlock a team.

Multi-model pools

Start a pool with --multi_model (or set default_multi_model: true) and each review also runs Synthex's multi-model orchestrator, which fans the review out to the external CLIs you've configured and merges their findings into the same report. Startup runs the multi-model preflight first and stops on a hard error. If any external CLI is configured in sandbox-yolo mode, it also asks you to confirm, defaulting to no.

Only code-reviewer, security-reviewer, design-system-agent, and performance-engineer support multi-model pools. Expect a multi-model review to cost roughly two to three times a native-only one, depending on how many external CLIs are configured. See Multi-model review.

Cost

An idle pool still holds its reviewers open. start-review-team/synthex:start-review-team warns and asks before spawning a pool with four or more reviewers, or with two or more reviewers and a TTL over 240 minutes. Stop pools you aren't using, or keep the TTL short.

Coming from synthex-plus?

Standing pools used to live in the separate synthex-plus plugin. They're now part of Synthex, and synthex-plus has been removed from the marketplace. The four pool commands keep their names under the synthex: namespace. The team-* commands are retired with no direct replacement: their behavior now lives inside review-code/synthex:review-code,

next-priority/synthex:next-priority, write-implementation-plan/synthex:write-implementation-plan, and refine-requirements/synthex:refine-requirements.

The migration guide covers stopping old pools, moving your config, and the full command mapping.

See also