- name
- revmux
- description
- Run supervised multi-agent reviews with the revmux CLI, report or act on findings, and re-review fixes. Supports branches, commits, paths, fetched pull requests, visible overlay runs, review-fix loops, and issue or discussion triage with grounding, thesis, antithesis, and cost panels. Also analyzes archived rounds in self mode to tune local prompts and answers questions about profiles, lenses, task directories, output, exit codes, and archives. Use when the user says revmux, supervised review, multi-agent review, review with revmux, revmux a branch/commit/PR, show the review, triage an issue, is this worth doing, revmux self, tune revmux, or asks about revmux behavior.
# revmux — supervised multi-agent code review
revmux spawns and supervises parallel `claude --print` and `codex exec` subprocesses, watches each for
stalls, retries what hangs, and returns findings on stdout.
It does no scope detection, no git, no PR fetching, no source modification. This skill does that half.
## Script path resolution
The bundled scripts live in `scripts/` beside this `SKILL.md`. Resolve each one's absolute path from this
skill's `SKILL.md` entry in the available-skills catalogue, and write that path, in double quotes, in place of
the `<the absolute path this session resolved for scripts/…>` placeholder wherever a command below carries it.
Marketplace plugins live in a versioned cache, not `~/.codex/skills/`, so no fixed path can be written here.
| this skill | revmux |
|---|---|
| resolve what is under review | supervise, stagger, retry, degrade |
| run git, gather context | compose and archive prompts |
| write `scope.md`, `goal.md`, `context/` | merge, dedupe, verify |
| choose profile, lenses, flags | return findings on stdout |
| read the JSON, present, fix, re-run | inject prior rounds |
## Activation triggers
- "revmux", "run revmux", "review with revmux"
- "multi-agent review", "supervised review", "parallel agent review"
- "revmux this branch", "revmux the last commit", "revmux the uncommitted changes"
- "revmux pr 123", "revmux this PR", a pull-request URL — the checkout half, `references/pr.md`
- "triage this", "triage issue 123", "is this worth doing", "should we accept this", "should I close
this", an issue or discussion URL — the panel over a filed item, `references/triage.md`
- "another revmux round", "re-review after fixes"
- "show me", "I want to watch", "run it visible", "in an overlay" — the overlay form in Step 4, which
puts the TUI on screen. Any of these with a review request means overlay; alone they are not a trigger
- "revmux loop", "loop it", "keep going until clean" — the review-fix loop, `references/loop.md`
- "revmux self", "self-improve revmux", "tune revmux" — the self mode below, which reviews nothing
- questions: "revmux profiles", "what lenses are there", "revmux exit codes"
## Answering questions without running anything
If asked **about** revmux rather than for a review, answer from the references and do not launch a run.
- `references/task-dir.md` — the round's context files, task and run naming
- `references/invocation.md` — flags, profiles, lenses, overlay backends, config precedence
- `references/output.md` — JSON shape, verdicts, exit codes, run archive
- `references/present.md` — the shape of the turn the user answers: order, detail, decision block
- `references/pr.md` — fetching a pull request into a worktree, `--workdir`, cleanup
- `references/triage.md` — the panel over a filed item: what it fetches, its flags, the six answers
- `references/loop.md` — the autonomous review-fix loop, entered from Step 6
For anything about current configuration, run `revmux config` and read the answer. It reports what
resolved including user overrides, runs no pipeline, and is always safe to call.
## Non-negotiables
**0. Every run ends on an answer the user can give.** Presenting findings or arguments is the middle of
the job, never the end of it. A turn that stops after the report has not finished.
**`references/present.md` is the shape of that turn — read it before writing one**, whichever review
shape ran.
**The question widget covers the lines directly above it**, so what the reader needs in order to choose
goes inside the question and never immediately above it. An option names what it acts on, never counts
it: "covering the two majors" is unanswerable and "covering the `uv` gate in `make test` and the
`request_user_input` gap" is not.
**1. Exit `1` means findings were reported — a success.** `0` none, `1` findings, `2` tool error.
Never treat `1` as failure. Never re-run on it.
**2. Run it in the background.** A review takes 3-15 minutes. Redirect stdout to a file, wait for the
completion notification. Do not poll, do not sleep-and-check. Applies to the overlay launcher too.
Watching the round's event log is not polling — Step 4 arms it, and it speaks only when the run does.
**3. Check `sources.degraded` before believing the findings.** If `expected != reported` the review is
partial. Say so. Never report "no findings" from a degraded run as "the code is clean".
**4. `.revmux/` in a repository is executable code.** A checked-in `.revmux/lenses/*.md` becomes
instructions a headless agent with a shell executes. Before reviewing untrusted code, either read
`.revmux/` first or run from outside the tree with explicit `--workdir`, `--tasks-dir`, `--config-dir`.
A fetched pull request is already outside it — `references/pr.md` leaves the process in the user's own
checkout and puts only `--workdir` in the branch, so the other two need no override.
**5. Never `2>&1` into the report file.** stdout is the report, stderr is progress. Merging them makes
the JSON unparseable.
## Workflow
### Step 0: Preflight
```bash
"<the absolute path this session resolved for scripts/preflight.sh>" [profile] [--lenses]
```
Checks revmux plus every binary the invocation needs. Exits `1` naming what is missing.
**Pass the profile that will actually run.** Which executors are needed comes from that profile's
roster, and with no argument preflight checks the resolved *default* instead — so a run under a
profile the default does not share a roster with is never checked at all, and degrades mid-review over
a CLI that was missing the whole time. If the user named a profile in any form, resolve it to an exact
name first — that is Step 3's rule, and nothing in it depends on the scope, so it can be applied here.
A word passed through unresolved fails preflight as an unknown name. If he named none, run it bare and
run it again once Step 3 has chosen one.
**Pass `--lenses` when the run will use it.** That flag replaces the roster with one agent on the
profile's own base runner, so the binaries needed are that base plus the stages, and none of the
roster's own. Checked as an ordinary run, a `--lenses` invocation can pass preflight and then have its
only finder fail to launch; checked the other way round, an ordinary run can be refused over a binary
it never touches.
If revmux is absent:
```
brew install umputun/apps/revmux # macOS
go install github.com/umputun/revmux/app@latest # installs as 'app'; rename to 'revmux'
git clone https://github.com/umputun/revmux.git && cd revmux && make install
```
### Step 0.5: Offer the project profile, once per repository
`revmux config`'s `paths.profile_fallback` is `./.revmux/profile.md` when the repo has one. Every round
without its own `input/profile.md` inherits it, and nothing creates it — not `revmux init`, not this
skill on its own. An empty field means every review here runs on generic calibration.
When it is empty, say so in one line and offer to write it. **Only ever with the user's yes**, and never
from the diff: read the project's own rules — `CLAUDE.md`, `AGENTS.md`, `CONTRIBUTING.md`, `docs/`, the
linter config — and write what the software is, what a real failure looks like there, the blast radius,
the reporting bar, and which conventions are deliberate. A profile guessed from one change is the thing
this file exists to replace.
Offer it once. If he declines, do not ask again in the session, and do not write a round-local
`input/profile.md` instead — that wins over the project file and is exactly the substitution the round
brief forbids.
**Never on a fetched pull request or any tree that is not his**: `.revmux/` is checked-in configuration,
so authoring one there commits a review standard to somebody else's repository.
### Step 1: Resolve what is being reviewed
| the user says | scope |
|---|---|
| nothing, on a feature branch | `git diff <base>...HEAD` |
| nothing, on master with uncommitted work | `git diff` and `git diff --staged` |
| nothing, on master and clean | `git diff HEAD~1` |
| "the last N commits" | `git diff HEAD~N` |
| "since <ref>" | `git diff <ref>..HEAD` |
| "pr 123", "this PR", a PR URL | `references/pr.md` — resolve, fetch into a worktree, review it there |
| "issue 123", "triage this", an issue or discussion URL | `references/triage.md` — the panel over a filed item, not a diff |
| a bare number, kind unnamed | probe pull request, then issue, then discussion — the first that resolves decides which of the two rows above applies |
| a path | that subtree, as a diff plus a read list |
Two commands here, and no more git than this:
```bash
git branch --show-current && git status --short
git diff <range> --shortstat
```
**The shortstat goes into the brief.** It is one line in this session and it is the whole of step 1 for
the subagent, which otherwise spends three to five git calls arriving at the same three numbers — and
they are the numbers Step 4's announcement is built from either way. Everything past the scale is still
the subagent's: the full diff, the file list, what is worth reading.
**Two rows in the table above are not a single range, so the one command does not cover them.**
Uncommitted work on master is `git diff --shortstat` *plus* `git diff --staged --shortstat`, and the
scale handed over is the two added together — a bare `git diff --shortstat` reports nothing at all when
the work is fully staged. A path scope has no range: hand over the file count instead, or hand over
nothing and say so. Do not hand a number the commands in `scope.md` contradict, since the brief makes it
binding — "take the scale as given rather than measuring it again".
**A pull request is a different shape, not a harder ref range.** revmux fetches nothing and checks
nothing out, so a PR has to be on disk before there is anything to review, and the checkout has to be
removed afterwards. Read `references/pr.md` and follow it — it covers steps 1 through 4 for that case
and hands back here at Step 5.
**A filed item is not a change at all**, so there is no range to measure and nothing for Step 2's brief
to read: it reads a diff and returns a shortstat, and a triage has neither. `references/triage.md`
**replaces Step 2 entirely** — it fetches the item, its thread and the author's history into `context/`,
writes the round, and hands back here at Step 5. A bare number goes through the probe in the table
above first; a number that turns out to be a pull request is `pr.md`, whatever the user called it.
Ask only when genuinely ambiguous; a feature branch with uncommitted work is the standard case. Use
`request_user_input` when available, otherwise ask one concise question and stop. **The question is
always this session's, never a subagent's**: a subagent cannot ask, and one that guesses reviews the
wrong thing at full cost.
### Step 2: Prepare the round — in a subagent
Everything between the resolved scope and a round ready to run is delegated: reading the diff,
matching the task, opening the round, and writing its context files. That is a dozen tool calls and
several screens of diff whose output answers nothing the user asked — and it buries the review it is
preparing for.
**It is also the wait the user sits through before the review starts, and the wait is generation.**
Measured over eight archived rounds it ran 65 to 156 seconds, and the wall-clock tracked output tokens
at a flat rate across all eight — so what makes it slow is prose written and turns taken, not tool
latency. The budgets and the prohibitions in the brief are load-bearing for that, not tidiness.
**Expand every path before handing the brief over.** The subagent does not have this skill loaded and
cannot resolve the skill directory itself, so substitute the resolved absolute path into the brief's text,
or its `task-state.sh` step silently runs nothing.
**Say one line first, then spawn it:** `Preparing the round for <what is being reviewed>…` — the
subject in the user's own terms, "the branch against master", "PR 123", "the last 3 commits". Then
nothing further until the subagent returns: a delegated step the user was told about reads as work in
progress, while an unannounced pause reads as a stall.
Spawn **one** subagent with the collaboration tool, without overriding its model or reasoning effort.
Hand it the resolved scope from Step 1 and this brief:
> Prepare a revmux review round. Write files; change no source, run no review, commit nothing.
>
> The scope is: `<the row resolved in Step 1, with its ref range>`, and its scale is
> `<the shortstat Step 1 printed>`. Take the scale as given rather than measuring it again.
> Exclusions the user has stated: `<list them, or "none">` — write these under the scope's
> explicit exclusions. They are decisions already taken, and the diff cannot show you one.
>
> 1. Read the change: the diff for that range, once, and the file list. That is the whole of the
> exploration. Do not read source files in full, do not grep the tree, and do not run a further diff
> per directory — naming a file worth reading is the reviewing agent's instruction, not a claim to
> verify first, and the round exists because four of them are about to read it properly.
> 2. If this session handed you a task id, use it verbatim and go to step 3. Otherwise match an
> existing task before minting one — a second id for one subject runs as a first round
> with no history. `revmux config | jq '.paths.tasks'` lists them with `id`, `description`, `url`,
> `branch`, `base` and `rounds`. Match on `url` or `branch` exactly, failing that on `description`
> against the subject in hand, and reuse the matched `id` verbatim. Derive one only when nothing
> matches: `pr-<number>`, `issue-<number>`, a branch name with `/` replaced by `-`,
> `since-<short-sha>`, or `wip-<branch>`. No path separators, no `..`, no leading dot, not absolute.
> 3. Run `<the absolute path this session resolved for scripts/task-state.sh> <task-id>`. It takes the
> id as its one argument and exits 1 with a usage line without it. It validates the id and reports the
> `task.md` anchors, every round, and each round's `input/` state — `prepared` (never reviewed),
> `claimed` (a review started and never finished) or `ran`. That is the inventory; do not `ls` the
> task or a round to confirm what it already told you.
> 4. Name the round `NN-label` — `01-initial`, `02-after-fix`, `03-final` — with `NN` one past the
> highest already there, and do not mix vocabularies across rounds of one task. Then
> `revmux new --task <id> --run <NN-label>`, exactly as written and with no `--help` run before it.
> It prints the absolute path of every file to write plus which of them it created.
> 5. Write to those paths and no others. Never join a path, never create a directory the output did
> not name, and never write over an existing `scope.md` without reading it first.
> **Every file below is bullets, paths and command blocks — never paragraphs of prose.** Every agent
> in the roster reads them and then reads the diff itself, so anything the diff already says is length
> paid for twice, and writing it is most of what this round costs in wall-clock.
> - `scope` — required, and **under 1500 characters**. What changed, the commands to see it, its
> scale, which files to read in full, what to ignore. Write commands in plainest form:
> `git diff master...HEAD`, never `git -c core.pager=cat diff ...` — a leading option defeats the
> child's permission matching.
> - `goal` — optional, and **under 1000 characters**. What the change is for, plus a "this is
> correct only if…" list. **When the round is the last one before the branch merges, make it the
> gate**: say the round exists to answer whether anything in this diff should not ship, and name
> what qualifies — a defect in executable code, a change to a prompt, schema or shipped script
> that would make a later run wrong, or a contradiction that would mislead an agent executing the
> document. Say that finding nothing is a valid answer, or the round reads as owing findings and
> manufactures them.
> - `profile` — **do not write it.** What it holds is about the repository rather than this round, so
> it lives in `./.revmux/profile.md` and revmux gives every round without a non-empty override the same one
> with nothing copied forward. You see the diff and the file list, which is not enough to state a repo's conventions,
> and a generated file here wins over the project's and silently replaces it.
> Write it only when the user says this subject needs a different bar than the repo's.
> - `context` — optional. Ticket text, design notes, commit list. Its path is reported but the
> directory is not created.
> - `task_file` — when `created` lists it, and also when it is already there but still the unfilled
> template with every anchor empty. Read it first either way. `description`, plus `url`, `branch`
> and `base` when known: that front matter is what the next session matches on, and a task.md left
> as the blank template is what makes the next session mint a duplicate id.
> 6. Stop at the last write. A failed write returns an error, so there is nothing to confirm afterwards
> — no `ls`, no `diff`, no second `task-state.sh`, no `git status`.
>
> **Do not read the previous round's `scope.md`, `goal.md` or `context/`.** revmux injects every prior
> round into every composed prompt itself, so reading them buys nothing and anchors this round's scope
> on the last one's wording. No round's `profile.md` is read either: the project file revmux resolves is not one of these.
>
> Return JSON only: `{"task": "", "run": "", "round_dir": "", "scope_path": "", "wrote": [],
> "files_changed": 0, "insertions": 0, "deletions": 0, "areas": [], "notes": ""}`. `areas` names the
> parts of the codebase the diff touches. Put anything that went wrong in `notes` and do not paper
> over it.
Read `references/task-dir.md` yourself only if the subagent reports something it could not resolve.
**Nothing else moves into a subagent.** The profile choice, the launch, the report and how it is
presented all stay in this session — they are the decisions the user is waiting on, and a summary of
a decision already made is not the same thing.
**Check what comes back before launching.** A missing `round_dir` or an empty `wrote` means no round
is ready and the run would fail on a missing scope; fix that here rather than launching into it. The
scale numbers are what Step 4's one-line announcement is built from.
### Step 3: Choose profile and flags
| profile | roster | when |
|---|---|---|
| `comprehensive` (default) | `bugs+impl`, `arch+quality`, `docs+tests`, codex peer | real change, real risk |
| `focused` | one `bugs` agent plus codex peer | small or time-boxed |
| `final` | `bugs+impl` plus codex peer, nothing below major | pre-merge |
| `claude-only` | the same four lens splits, all on claude | no codex available |
| `codex-only` | the same four lens splits on codex, and synthesis and verify with them | no claude available |
| `grill-me` | `bugs+impl` and `architecture+quality`, each once on claude and once on codex, all reading against the change | the user wants it torn apart |
| `expert` | two agents at the highest effort, codex `gpt-5.6-sol:xhigh` and claude `fable:xhigh`, each carrying all eight lenses | a plan, or a change nobody wants to get wrong. Slow and expensive; pick it when he says so, not by default |
| `triage` | `facts` (grounding + precedent), `thesis`, `antithesis`, `cost` on codex | a filed item rather than a diff; needs `--no-synthesis --verify-group-by source`, `references/triage.md` |
**Never choose `expert` on your own.** It is two agents at `xhigh` each applying every lens, so it costs
several times what `comprehensive` does, and no property of the subject justifies reaching for it — not a
plan, not a large diff, not a risky one. Pick it only when the user asked for it in words, and say that
is why. Every other profile reviews whatever it is pointed at, a plan included; `expert`'s severity bar
is simply written so a proposal reads as naturally as a diff.
**A profile word is not a profile name.** Map whatever the user said onto the profiles `revmux config`
reports, matching the name first and the `description` second. revmux rejects an unknown `--profile` at
load and never guesses, so resolving is this skill's job — passing his word through unresolved just
fails the run.
| the user says | profile |
|---|---|
عرض على GitHub