* feat(review): procedural correctness finders, effort levels, and posting/verify guardrails
Rework the /review skill's finder layer and add precision and cost controls,
informed by dogfooding the skill against real PRs.
Recall:
- Split Agent 1 (Correctness) into three procedural finders defined by how they
walk the diff — 1a line-by-line (incl. language-pitfall and wrapper-routing
checks), 1b removed-behavior audit, 1c cross-file tracer — so coverage is
complementary instead of overlapping. Bump the 3A dimension fan-out to 12
agents and shift the 3A/3B gate to 3200 diff lines.
- Add Agent 8: up to two diff-specialized finders written per-review when the
diff concentrates in a domain with a known failure grammar.
- Fold altitude into Code Quality and a quote-the-rule discipline into the
conventions pass.
Precision:
- Every finding must state a concrete failure scenario (trigger to wrong
outcome, or concrete cost); findings that can't are dropped at the source,
and verification re-traces the scenario rather than judging prose.
- Verification checks a finding against the diff's own documented intent: a
"regression" the diff deliberately changes and documents is a design
decision, not a defect.
Cost and safety:
- Add --effort low|medium|high: cheap inline passes with no subagents (default
high for PRs, medium for local changes).
- Hard-gate PR posting: never submit a review unless --comment was passed or the
user explicitly asked, regardless of verdict.
- Add a substantive-return check for whole-diff agents (invariant, cross-file,
test-coverage matrix) so a silently whiffing agent is caught like a missing
chunk receipt.
DESIGN.md records the rationale and dogfooding cases behind each change; user
docs updated with the effort levels and the new agent roster.
* docs(review): fix stale topology numbers flagged in review
- Define H in the 3B pipeline diagram cost annotation (3 invariant agents
per heavy file).
- Annotate the 40-PR re-gating cost figures with the roster they were
measured under (22 agents / ~5% at 10 agents; ~34 / ~7% at 12).
- Correct the fork-subagent savings estimate to ~88-92% (~750-950K →
~80-88K); the previous range predated the updated totals.
- "None or nine" receipts under 3A is eleven under the 12-agent roster
(every agent except Build & Test walks the diff).
* fix(review): address review feedback on effort/verify/lightweight edge cases
Criticals from review:
- Apply the --comment→high-effort override only after target disambiguation;
an ignored --comment (non-PR target) no longer silently forces high.
- The documented-intent gate caps confidence only when the rationale makes the
harm uncertain; a traced harm that survives the rationale keeps high
confidence, and rejection is reserved for pure re-descriptions.
- Lightweight cross-repo mode degrades Agents 1a/1b to diff-only and routes
unverifiable re-establishment claims to low confidence instead of asserting
them, matching the verifier's limits.
Suggestions:
- Agent 0's empty-scope exit now carries its evidence and the whiff check
recognizes it, so a legitimate no-linked-issue return is not relaunched.
- Reframe the 3200-line clause as an attention bound (3B is not guaranteed
cheaper with heavy files or specialized finders).
- Fix call-budget notation: F for findings vs N for chunks; correct the 3B
budget to rounds × chunks for the reverse audit (~70 calls on the 19-chunk
example, not ~28-30); state the runtime concurrency cap (10) instead of
claiming ~1x wall time.
- Preserve the failure scenario through pattern aggregation and posted inline
comments; extend quality-finding verification to check the named helper
does what the finding claims.
- Document medium effort's roster (no dedicated security/test-coverage pass);
qualify the cross-effort scope note (incremental cache is high-only); define
"lenses" on first use; fix tense and the stale 9-agent line in commands.md;
clarify the 1b skip condition (no removed/replaced lines).
* fix(review): close 422-relocation verdict hole and lightweight-mode context gap
From review feedback (one human, two model reviews):
- 422 recovery: Criticals relocated into the review body now keep the event at
REQUEST_CHANGES — the event/body table counted comments only, so a review
whose blockers were all relocated could submit as APPROVE/no-blockers
COMMENT with blocker text in the body.
- Lightweight cross-repo mode now runs pr-context (pure GitHub API): Agent 0
and the open-Critical re-check need the PR body and open threads, which the
bare gh-pr-diff setup never captured.
- Define --effort value parsing so a non-enum next token (e.g. a PR number) is
never consumed as the value.
- Add the missing test-coverage-matrix definition section; mark agent counts
as maxima (1b skipped on no-deletion diffs).
- Sync DESIGN's documented-intent paragraph with the corrected confidence
policy; align 3A/3B budget headings with the dual-trigger gate and state the
38-95 reverse-audit range explicitly.
- Docs: dual-trigger diagram labels, attention-bound wording, diff-reading
lenses phrasing, per-stage-bounded (not fixed-total) cost claim, effort
table qualifications, failure-scenario in the Step 7 JSON samples.
* docs(review): reconcile verifier rejection rule and close remaining edge notes
- State the Critical-rejection bar once, without the self-contradicting
"never reject / to reject" phrasing: rejection requires quoting the
contradicting code, and the floor verdict is confirmed (low confidence)
when it cannot be quoted.
- Note the one sanctioned exception to the empty REQUEST_CHANGES body:
unmappable or 422-relocated Criticals.
- Give the callee-direction check a concrete procedure (walk the other
changed symbols this territory calls, re-read their post-change
contracts).
- Define lightweight-mode pr-context failure handling: continue diff-only,
skip Agent 0, open-Critical re-checks become "cannot tell" (no Approve).
- Clarify Agent 8 applies in every mode (it needs only the diff) and that
Step 6 follow-up tips are high-effort only.
* fix(review): close flag-parse, context-unavailable, and downgrade edge cases
Address the latest review round on the skill text:
- An invalid spaced --effort value is discarded (with the warning) whenever
another token is the target, so `/review 6711 --effort typo` reviews PR
6711 instead of leaking `typo` into target disambiguation; the token is
kept only when it is itself the sole target candidate.
- The lightweight-mode pr-context failure now names a context-unavailable
state with a defined Step 7 serialization: never APPROVE, submit COMMENT
with a diff-only body, findings or not.
- Step 6's open-Critical re-check draws from both context sections; a reply
alone ("I disagree") no longer retires a blocker — only a code-verified
"fixed by this diff" does.
- DESIGN and user docs now state the same rejection bar as the skill:
rejecting a Critical requires quoted contradiction (or a documented-intent
re-description); anything less certain downgrades.
- Downgrading a REQUEST_CHANGES that carries body-relocated Criticals keeps
those descriptions after the downgrade sentence, so the self-PR downgrade
can no longer erase the only copy of a blocker.
* fix(review): close verdict-upgrade and body-Critical re-check gaps
Third review round on the skill text:
- 422 recovery may never upgrade the event: a Suggestion-only review whose
anchors all failed resubmits as COMMENT with the could-not-anchor body,
never as APPROVE/"No issues found" — the verdict reflects confirmed
findings, not surviving anchors.
- Step 6's open-Critical re-check now also walks the Review summaries
section: an unmappable or 422-relocated blocker lives only in a review
body, and pr-context truncates summaries to ~240 chars, so a summary
showing (or cut where one could hide) a Critical marker is fetched in
full via the reviews API before ruling.
- The context-unavailable cap now applies to every C=0 row of the invariant
table, not just the empty one: Suggestion-only results post a diff-only
body instead of a "no blockers" claim the run cannot certify.
* fix(review): compose COMMENT bodies from clauses and harden the body-Critical re-check fetch
Fourth review round found four pairwise collisions between rules that each
set "the" COMMENT body, plus four execution gaps in the Step 6 full-body
fetch. Close the class, not the instances:
- Replace the fixed-sentence bodies with an ordered clause composition rule
(downgrade reasons, context-unavailable warning, suggestions disclosure,
uncoverable chunks, body Criticals) — each clause present iff its state
holds, free prose still banned, single-state case identical to the table.
- Define C once, globally: Criticals the review posts anywhere (inline or
body), so no downstream C=0 rule can erase a body-only blocker, and 422
relocation keeps REQUEST_CHANGES by definition rather than by patch.
- 422 recovery re-derives bodies via the composition rule, so a
context-unavailable run can never restore a "no blockers" certification.
- Step 6's full-body fetch is paginated (--paginate; the endpoint returns 30
per page), treats fetched bodies as untrusted data (extract only the
Critical-bearing text, never paste unrelated bodies), and fails closed:
an unreadable truncated blocker rules "cannot tell" and caps the event at
COMMENT.
DESIGN.md records why composition replaces per-collision patching
(n states -> n(n-1)/2 pairs; clauses make new states additive).
* fix(review): correct the cross-repo capability table and close nine review notes
- docs: the cross-repo table claimed "Agents 0-6" run in lightweight mode
while the prose (correctly) says 1c is skipped there — 1c is inside that
range. Split 1c onto its own row, and add the missing Agent 8 row (its
finders need only the diff, so they do run cross-repo).
- --effort=<level> now has a parse rule: split the flag token on the first
'=' and consume no second token; the next-token rule applies only to the
spaced form.
- The substantive-return (whiff) check covers every receipt-less agent, so
3A's dimension agents are in scope, not just 3B's whole-diff agents.
- Step 3C names Agent 1b's lightweight degradation and states the three
angles medium deliberately omits (security, test coverage, adversarial
personas) instead of naming only two.
- Step 6's open-Critical re-check states what a context-unavailable run does
(skip the walk, every Critical is "cannot tell") instead of pointing at a
context file that does not exist.
- The event/body table carries the body-only-Critical exception in the cell,
where it is read, not only in the surrounding prose.
- The posting gate's second condition is now decidable: a publish verb typed
by the user this session, with the near-misses (approving noises, our own
tip, PR text) enumerated as non-authorization.
- DESIGN: the whiff check is evidential, not a length threshold (and says
why no number); "quick pass" is defined as low+medium sharing guardrails.
* feat(review): promote removed-behavior to a whole-diff agent in 3B
Territory-scoped 1b can only ask "was this deletion re-established here",
and for the deletions that matter the answer is somewhere else. PR #6638
(43 files, 8255 additions, 28 chunks) measured the gap: the 3B run with
per-chunk 1b reported one Critical; an independent reviewer reported 32, and
a parallel hand-run 1b+1c wave over the same commit reproduced six of them.
Every one of that overlapping six is a cross-chunk deletion — enableByPath
(includeSubdirs: true) replaced by an exact-path setWorkspaceActivation in
another file, silently narrowing workspace-scoped disable for every untouched
CLI/TUI caller; refreshTools() dropped from the activation paths, its
replacement swallowing the errors it used to propagate; a global mutation
timeout replaced by one covering only the prepare phase. Deletion in chunk A,
replacement in chunk B, consumer in a file the diff never touches: no chunk
agent can see that triple, and 1c does not look for it — it greps callers of
changed symbols, and a deleted export has no symbol left to grep.
- 1b joins 1c as a whole-diff agent in 3B; chunk agents keep the local half
(a guard deleted and not re-established in the same hunk is still theirs).
- The split is stated at both agents: 1c walks the callers of changed
symbols, 1b walks the replacements of removed ones.
- Agent 1b's definition gains the removed-export bullet: compare replacements
as behaviour, not names, then check the call sites the diff never touches —
a replacement that type-checks is not a replacement that behaves.
- 3B whole-diff agent count 4-6 -> 5-7 in the budget and the docs diagram.
* fix(review): serialize cannot-tell blockers, gate the no-blockers opener, and read reviews from a file
Fifth review round, all four notes real:
- The clause inventory had no way to serialize Step 6's `cannot tell`
verdict, so a Critical the review could neither confirm nor clear had
nowhere to go and dropped out of the public review. Added clause 5
(unresolved existing-Critical), which survives downgrades and 422 recovery
like the body-Critical carve-out, and Step 6 now points at it.
- `Reviewed — no blockers.` was injected as the opener whenever context was
available, regardless of C or scope — so a self-PR downgraded to COMMENT
with an inline Critical, or a review with an uncoverable chunk, opened by
certifying the absence of the blockers it was carrying. The opener is now
gated on C === 0 AND no unresolved existing Critical AND no uncoverable
chunk AND context available; otherwise it is a plain `Reviewed.`
- The paginated `/reviews` fetch ran through the shell, whose successful
output is capped at 30 000 chars and split head/tail: a body-only blocker
in the elided middle passes with exit 0 and the fail-closed branch never
fires. It is now redirected to a file and paged with read_file, and a body
read only in part is `cannot tell`, not "no Critical in it" — the same
lesson as "the diff is a file, not a command".
- The substantive-return gate rejected a bare "No issues found" while the
agent contract demanded exactly that string. The contract now asks for
`No issues found — <one line naming what you examined>`, and the relaunch
is capped at one attempt per agent, with the dimension reported under "Not
reviewed" if the second return is still bare.
* fix(review): wire whole-diff 1b into the gates, cap the event on unread scope, page reviews as NDJSON
Sixth round. Four Criticals all trace to the two previous commits:
- Whole-diff Agent 1b was declared but never wired in: it was missing from
the receipt-less roster (so a whiffing 1b passed undetected) and the launch
contract handed every 3B agent "its own chunk range", which is exactly what
a cross-chunk pairing agent cannot work from. The payload contract now
splits by role — chunk agents get one range, every whole-diff agent gets
the entire chunks[] plan.
- The whiff check ended at "note it as Not reviewed", which left an
unreviewed Security or removed-behavior lens able to ship an LGTM. It now
carries an unreviewedDimensions state that forbids Approve, caps the event
at COMMENT, and is serialized in the body next to uncoverable chunks.
- Clause 5 put an undecidable existing Critical in the body while event
selection still chose APPROVE from the C/S table — a review approving the
very blocker it asks the author to confirm. The table now has explicit
overrides: cannot-tell existing Critical, uncoverable chunk, and unreviewed
dimension each cap the event at COMMENT (a confirmed Critical still earns
REQUEST_CHANGES).
- Redirecting `gh api --paginate` to a file does not make it pageable: it
emits compact JSON, so the file is one 150 KB+ line that read_file
truncates and offset skips past to EOF. The fetch now filters with --jq to
marker-bearing bodies and emits line-delimited records that page normally.
Also: the 1b/1c split is by task, not by symbol (1c greps the removed
export's old name and owns caller compatibility; 1b owns the pairing and the
semantic comparison) — the earlier "no symbol left to grep" claim understated
1c and risked dropping its removed-symbol pass. Plus stale arithmetic from the
larger roster (+4 -> +5, worked example 26-28 -> 27-29), the receipt count's
missing Agent 8, "0 LLM calls" -> "0 subagent calls", the fixed "12 parallel
tasks" -> its real range, and 1c's callee procedure no longer speaking of a
"territory" it does not have.
* fix(review): select body Criticals offline, propagate unreviewed dimensions, close the no-findings bypass
Seventh (final self-review) round. The three Criticals all attack the newest
machinery:
- The NDJSON fetch filtered on a literal [Critical] marker, but a body-only
blocker is not guaranteed to carry it (a real emitted review on this repo
does not) — the filter discarded exactly what the re-check exists to
recover. The --jq now keeps every nonempty body and selection happens
offline after reading records whole; clauses 5 and 7 additionally mandate
the marker on everything we serialize, so our own output stays
self-identifying.
- unreviewedDimensions stopped at the event cap: Step 6's Not-reviewed
section only listed uncoverable chunks (a non-posting run hid the missing
lens entirely), and the body invariant made the required disclosure
illegal on a REQUEST_CHANGES. The section now lists both, and the
not-reviewed clause is the second sanctioned REQUEST_CHANGES body
exception — a confirmed Critical must not squeeze out the disclosure of
what was never read.
- The no-confirmed-findings branch still said "APPROVE by default",
special-casing only presubmit and context-unavailable — bypassing the
cannot-tell/uncoverable/unreviewed caps added one commit earlier. The
branch now runs the same machinery as every submission: table with
overrides, then downgrades, then composition; the hard-coded LGTM example
applies only with no cap state present.
Plus the round's consistency notes: cross-file trace marked same-repo-only
in the docs' medium row; +5 -> +4 in the crossover arithmetic (Build & Test
reads no diff) so "crosses twelve about there" is true at 3200; DESIGN's
whole-diff enumeration gains 1b; budget total widened to the honest 15-21
row-sum; fork-subagent math redone at 52K/agent; the payload paragraph
names the invariant agents' third payload class; consumer-direction grep
patterns get Python/Go forms; 3C medium states 1a's lightweight degradation
and scopes the grep permission; the aggregated-format shorthand carries
Failure scenario and Severity; the exactly-one-sentence rule forward-
references the composition rule; and the Step 7 comment template embeds the
failure-scenario shape it was already demanding in prose.
* feat(review): sink argument parsing into a tested parse-args subcommand
The --comment/--effort grammar and target disambiguation were ~400 words of
prose in SKILL.md that the model re-simulated on every run; three separate
parsing bugs shipped that way (the spaced form consuming a flag as its
value, the --effort=<level> form left undefined, and an invalid value token
surviving into target disambiguation). Each is now a table-driven test case.
qwen review parse-args '<raw args>' emits a JSON verdict: classified target
(pr-number / pr-url with owner+repo+number extracted / file / local),
resolved effort with its source (explicit / default / forced-by-comment),
comment.requested vs comment.effective, verbatim warnings, and leftover
tokens the parser refuses to guess about. The skill's Step 1 shrinks to
"run the parser, use the verdict verbatim", and the target branches key off
target.type instead of hand-classifying tokens.
* feat(review): sink event selection and body composition into compose-review
The Step 7 machine — the C/S table, three event-capping overrides, the
seven-clause body composition, and the presubmit downgrade carve-outs — was
restated across four places in SKILL.md, and keeping the restatements in
sync by hand produced five shipped bugs (four Critical), all one shape: a
downstream branch not updated when an upstream rule gained a new state.
qwen review compose-review reads a state JSON (inline/body Critical and
Suggestion counts, discarded anchors, cannot-tell existing Criticals,
uncoverable chunks, unreviewed dimensions, context-unavailable, presubmit
flags, model id) and returns {event, body, baseEvent, cappedBy, downgraded}
for verbatim submission. The truth-table tests pin every previously shipped
bug as a named case: caps forbid APPROVE but never soften a REQUEST_CHANGES;
discarded Suggestions still count toward S so a 422 resubmit can never
upgrade to LGTM; a self-PR downgrade keeps body Criticals after the
downgrade sentence; the no-blockers opener appears only when certifiable;
every disclosure survives every stacking. Writing the tests immediately
caught one more instance of the class (all-discarded -> S=0 -> APPROVE).
SKILL.md's Step 7 shrinks to gathering the state and using the output
verbatim; the 422 recovery becomes "re-run compose-review with updated
counts"; the no-findings branch is the same call with zero counts; the
posting gate (judgment, not bookkeeping) stays prose.
* feat(review): render review bodies in full, quarantine replied Criticals, raise the gh buffer
The Step 6 body-fetch instruction was rewritten five times in four review
rounds (missing pagination -> shell truncation -> unpageable single-line
JSON -> a marker filter that discarded markerless blockers -> offline
selection) — the signature of a download program written in English. This
ends the chain at its root, in pr-context itself:
- Review bodies render in full under "Review summaries" instead of
240-char snippets: an unmappable or 422-relocated blocker lives only
there, and a snippet once hid one from the re-check. A body past the 8000
cap ends by naming its review id, so the tail stays fetchable as a single
object; a body read in part is `cannot tell`, not "no Critical in it".
- Replied Critical threads are quarantined into their own "Replied
Criticals" section, rendered before the settled threads, instead of
sinking into "Already discussed" — a reply alone ("I disagree") never
retires a blocker, and marker-matching in this direction is fail-safe: a
forged marker can only add a thread to the re-check list, never hide one.
- The gh wrapper's maxBuffer rises from Node's 1 MiB default to 64 MiB,
closing the ENOBUFS that killed pr-context and presubmit mid-review on a
comment-heavy 43-file PR.
SKILL.md's NDJSON fetch block is deleted: the re-check reads the context
file's three finding-bearing sections under its untrusted-data preamble,
with one residual single-object fetch for capped bodies. Verified against
this PR's own 100+-comment history: the markerless body-Critical review
that motivated the last rewrite now renders whole, and the fetch survives
without ENOBUFS.
DESIGN.md records the sinking rationale for all three subcommand changes;
the user docs note that parsing and the event/body decision are now pinned
by unit tests rather than prompt text.
* test(review): register parse-args and compose-review in the exact-list assertion
The parent-command test pins the exact subcommand roster; the two new
subcommands landed without updating it, which is precisely the drift the
assertion exists to catch — it caught it in CI, one directory above where
the new tests were run locally.
* fix(review): carry every disclosure on REQUEST_CHANGES and select blockers semantically
Review round on the new subcommands, plus the prompt notes it surfaced:
- compose-review's REQUEST_CHANGES branch dropped the context-unavailable
clause entirely and gated the not-reviewed disclosure on other parts being
present — an RC with only an uncoverable chunk disclosed nothing. Every
clause whose state holds now appears on every event (a confirmed blocker
must not squeeze out the trust warning or the unread-scope disclosure);
four new tests pin it.
- Step 6 selects blockers semantically, not by the literal [Critical]
marker: legacy body-only blockers were emitted markerless, and a marker
filter once discarded exactly such a review.
- The same-repo pr-context failure now sets context-unavailable like the
lightweight path (the guard's "lightweight" narrowing is removed) — a
same-repo run that lost the context file must not behave as if it had
read it.
- Step 5's dry-round return aligns with the agent contract (receipt-bearing
"No issues found — <what it re-examined>"), ending the contradiction where
a compliant reverse auditor would be flagged as whiffing.
- Consumer-direction grep forms for Python/Go are call sites now, with the
declaration forms explicitly labeled as callee lookup.
- The 15-19 totals left downstream (docs table, DESIGN heading and cost
row) move to the honest 15-21 / 13-20.
* fix(review): stdin transport for parse-args, validated compose input, full-body re-check context
Round 9 of review-the-review on this PR: 19 unique findings across three
reviews, each verified against source before fixing.
parse-args:
- The documented positional invocation broke on any flag-first raw string
(`qwen review parse-args '--effort low'` -> "Unknown argument") and the
`--` form silently returned a wrong local/default verdict. The raw
string now travels on stdin (`--stdin`; SKILL.md pipes a quoted
heredoc, immune to leading dashes, quotes, and $(...)); positional +
--stdin and post-`--` smuggling are refused loudly. Wiring-level tests
drive the real yargs command, pinning the strict-mode rejection that
pure-function tests could not see.
- PR URL identity hardened: the number must end its path segment
(/pull/42oops is refused, never PR 42), owner/repo restricted to
GitHub's name charset (keeps shell metacharacters out of derived
values), scheme matched case-insensitively, url canonicalized
(lowercase scheme/host, query/fragment dropped) with a new host field;
near-miss URLs are warned about and reported in extraTokens, never
guessed into a file path or PR number. Step 1 remote matching now
requires host AND owner/repo.
- Repeated --effort warnings state what is actually in effect (last valid
occurrence / --comment forcing / the default), composed after
resolution; previously a later typo claimed the default while an
earlier valid effort stayed active.
compose-review:
- Input validated at the boundary: absent counts default to 0; malformed
values throw typed errors naming the field. Previously
{bodyCriticals:["x"], modelId} made undefined+1=NaN, failed both event
comparisons, and returned APPROVE over the only blocker.
- "Suggestions are inline." keys off suggestionsInline, not s: an
all-discarded 422 recovery no longer claims inline suggestions while
the discarded sentence says the opposite (s still decides the event).
- canCertify requires !downgraded: a downgraded Approve opens with the
neutral "Reviewed." instead of certifying "no blockers" two clauses
after naming failing CI.
- unreviewedDimensions entries may carry their own reason after an
em-dash and render verbatim (used by Agent 0's fetch failure below).
pr-context:
- Replied-Critical root bodies render in full (shared capBody; a cut
names the comment id and the exact fetch); reply snippets name their
comment id when cut. The Step 6 re-check no longer rules on
silently-truncated claims, and the fail-closed "read in part = cannot
tell" rule can actually fire for this section.
- The LGTM filter matches the exact canonical template, anchored to the
whole body: a legacy body opening with the LGTM line but carrying a
relocated blocker below it is shown instead of dropped.
- classifyInlineThreads() extracted: buildMarkdown and the stdout count
use the same walk, so the count cannot diverge from the file.
SKILL.md:
- Step 6 re-check scope: every comment-bearing section, including
"Already discussed" (inline threads and issue-level comments) — the
quarantine keys on the literal marker, a floor not a ceiling, so
unmarked blockers settle there; the false "holds only non-Critical
threads" parenthetical is gone. The residual long-body fetch redirects
to a file (shell output truncates at 30k) and is read paged.
- Step 5 reverse audit: dry = zero new findings WITH the evidence-bearing
receipt; the substantive-return check runs after every round (one
relaunch); a twice-whiffed agent's round is never dry.
- Step 3: Agent 7 added to both whiff-check rosters (evidence = commands
run + outcomes; build-and-test recorded in unreviewedDimensions on the
second whiff). Agent 0's linked-issue fetch failure is fail-closed
after one retry via a self-explained unreviewedDimensions entry.
- Step 8: a fail-closed run (unreviewed dimensions, uncoverable chunks,
context-unavailable) must not advance the incremental cache — caching
it would exempt the disclosed-unreviewed scope from every future run.
- Counting truthfulness: "Twelve agents all reading the same diff" is
eleven (every 3A agent except Build & Test walks the chunk plan); fixed
in the 3B rationale, the diff-capture section, and the user docs.
review.ts: demandCommand message names plan-diff, with a test that the
message stays in sync with the registered roster.
* fix(review): nested-safe stdin guard, validated presubmit, refetchable snippets everywhere
Round 10: 12 findings, all verified before fixing. The headline is
self-inflicted: the round-9 post-`--` guard read argv._ as
['parse-args', ...extras], but the real CLI nests the command, so argv._
is ['review', 'parse-args'] and the guard rejected every real
invocation — while the wiring tests, which register the command
top-level, stayed green. Reproduced against the built CLI before
fixing.
parse-args:
- The smuggle guard skips the command-path prefix in argv._; new wiring
tests go through the real parent `review` command (nested stdin
invocation + nested post-`--` refusal).
- --effort values match case-insensitively (`--effort High` is not a
file target named High); the verdict keeps the lowercase form.
- Single-dash tokens are unknown flags, never target candidates
(`/review -c 6711` reviewed a nonexistent file `-c` and demoted the
PR number to extraTokens).
compose-review:
- presubmit and contextUnavailable get the same boundary validation as
the counts: boolean flags reject stringified "false" (truthy — it
flipped an inline-Critical RC to COMMENT and published the diff-only
warning on runs that fetched context fine), downgradeReasons rejects
scalars with the field name (was a raw .join TypeError), presubmit
rejects non-objects.
- Certification is gated on what presubmit PERMITS, not on whether it
changed the event: a Suggestion-only review is already COMMENT, so
failing CI flipped nothing and the body still certified "no
blockers". Either downgrade flag now suppresses the certifying
opener.
pr-context:
- Every truncating render carries an exact refetch ref: open-root
snippets, settled replied threads (roots and replies), and
issue-level comments (their own issues/comments endpoint). The
Step 6 semantic re-check reads these sections, and a markerless
blocker past the 240-char cut was invisible with no way back.
- Refs are copy-runnable: buildMarkdown threads owner/repo and PR
number into every ref, so emitted commands carry real values.
`gh api` substitutes only {owner}/{repo} — from the CURRENT repo,
wrong in cross-repo mode — and passes {n} through literally.
SKILL.md:
- Step 1: the raw argument string travels via write_file to
.qwen/tmp/qwen-review-args-input.txt and stdin redirection. A quoted
heredoc disables expansion but not delimiter recognition, so a raw
string containing the delimiter line would end the heredoc early and
execute the rest as shell. Step 9 removes the file.
- Step 1: remote matching is structural segment equality (host AND
owner/repo, .git stripped, case-insensitive) — substring "contains"
let shao/qwen-code match a wenshao/qwen-code remote. Non-github.com
hosts must carry GH_HOST on every gh call for the PR.
- Step 5: a twice-whiffed reverse-audit scope is tracked, cleared only
by a later substantive audit, and fed into unreviewedDimensions as a
self-explained entry when the loop ends — terminal prose alone let a
capped run approve with an audit that never ran.
- Step 6: snippet cuts carry their own filled-in fetch note; ruling on
a cut prefix is the fail-closed violation.
- Step 7: the stale hand-derivation bullets (event table, empty-RC-body
rule, one-line COMMENT inventory) are replaced with descriptions of
what compose-review guarantees; the sanity check is byte equality
with the subcommand's output; the last-resort 422 branch re-runs
compose-review instead of hand-building "the one-line body".
- Step 8: the fail-closed cache rule includes cannotTellCriticals — a
cached SHA plus the same-SHA shortcut would skip the very re-check
that must re-rule on an undecided blocker.
MSG2
git log --oneline -1; git push origin feat/review-procedural-finders-effort 2>&1 | tail -2
* feat(review): deterministic overlap disposal, --host routing, machine-readable completion line
Three changes measured out of the first six-PR dogfood batch, not
predicted from review comments.
Overlap disposal (SKILL.md Step 7): presubmit's overlap report used to
end in "list the overlaps to the user, ask whether to proceed" — 2 of 6
batch runs stalled on an improvised interactive question (fatal for a
headless run) while the other 4 proceeded. An overlap is a duplicate by
the Exclusion Criteria; the rule is now drop the overlapping finding,
adjust the counts handed to compose-review (a dropped finding never
flips the verdict), note "already reported at <path>:<line>" in the
terminal, and continue without asking. Zero findings left after
dropping is still not a question — compose-review handles the shape.
--host routing (lib/gh.ts + fetch-pr/pr-context/presubmit): the
round-10 GH_HOST-by-prose rule required the model to remember a prefix
on every call; a forgotten one silently reads from and posts to
github.com's same-named owner/repo. The three gh-calling subcommands
now accept --host and thread it through setGhHost()/ghEnv(), so every
wrapped gh call carries GH_HOST in code; hostname input is
charset-validated. SKILL.md keeps the prose prefix only for the gh
commands the orchestrating model runs directly (Agent 0's fetches,
Step 6's residual body fetch, Step 7's submission).
Completion line (SKILL.md Step 9): three different ad-hoc completion
phrasings across one batch each needed their own driver regex. Every
run now ends with exactly one line, `Review complete: <target> —
<disposition>`, with a closed disposition grammar covering posted
events, unposted verdicts, and quick passes — detectable with a single
^Review complete: match.
Tests: gh host-state unit tests (inherit-by-default, GH_HOST extension,
host:port, charset rejection), presubmit handler --host threading (set
and reset), builder registration checks for fetch-pr and pr-context.
48 KiB
Commands
This document details all commands supported by Qwen Code, helping you efficiently manage sessions, customize the interface, and control its behavior.
Qwen Code commands are triggered through specific prefixes and fall into three categories:
| Prefix Type | Function Description | Typical Use Case |
|---|---|---|
Slash Commands (/) |
Meta-level control of Qwen Code itself | Managing sessions, modifying settings, getting help |
At Commands (@) |
Quickly inject local file content into conversation | Allowing AI to analyze specified files or code under directories |
Exclamation Commands (!) |
Direct interaction with system Shell | Executing system commands like git status, ls, etc. |
1. Slash Commands (/)
Slash commands are used to manage Qwen Code sessions, interface, and basic behavior.
1.1 Session and Project Management
These commands help you save, restore, and summarize work progress.
| Command | Description | Usage Examples |
|---|---|---|
/init |
Analyze current directory and create initial context file | /init |
/summary |
Generate project summary based on conversation history | /summary |
/compress |
Replace chat history with summary to save Tokens | /compress or /summarize |
/compress-fast |
Fast compression without AI — strips old tool outputs and thinking parts | /compress-fast |
/resume |
Resume a previous conversation session | /resume or /continue |
/recap |
Generate a one-line session recap now | /recap |
/restore |
Revert project files to the checkpoint before a tool call ran | /restore (list) or /restore <ID> |
/delete |
Delete a previous session | /delete |
/branch |
Fork the current conversation into a new session | /branch |
/fork |
Spawn a background agent that inherits the full conversation | /fork <directive> |
/rewind |
Rewind conversation to a previous turn | /rewind or /rollback |
/export |
Export session history to file | /export html, /export md, /export json, /export jsonl |
/rename |
Rename or tag the current session | /rename My Feature or /tag |
Note
/summarizeis an alias for/compress(it compresses chat history — a destructive operation). To generate a non-destructive project summary instead, use/summary.
1.2 Interface and Workspace Control
Commands for adjusting interface appearance and work environment.
| Command | Description | Usage Examples |
|---|---|---|
/clear |
Clear conversation history and free up context | /clear, /reset, /new |
/context |
Show context window usage breakdown | /context |
→ detail |
Show per-item context usage breakdown | /context detail |
/history |
Control history display preferences and visibility | /history collapse-on-resume, /history expand-on-resume, /history expand-now |
/diff |
Open an interactive diff viewer showing uncommitted changes and per-turn diffs. Use ←/→ to switch between current git diff and individual conversation turns, ↑/↓ to browse files | /diff |
/theme |
Change Qwen Code visual theme | /theme |
/vim |
Turn input area Vim editing mode on/off | /vim |
/voice |
Toggle voice dictation input | /voice, /voice hold, /voice tap, /voice off, /voice status |
/directory |
Manage multi-directory support workspace | /dir add ./src,./tests, /dir show |
/cd |
Move this session to a new working directory | /cd ../other-project |
/editor |
Open dialog to select supported editor | /editor |
/statusline |
Open interactive status line preset dialog | /statusline |
/statusline <text> |
Generate a command-mode status line via agent | /statusline show model and git branch |
/terminal-setup |
Configure terminal keybindings for multiline input | /terminal-setup |
1.3 Language Settings
Commands specifically for controlling interface and output language.
| Command | Description | Usage Examples |
|---|---|---|
/language |
View or change language settings | /language |
→ ui [language] |
Set UI interface language | /language ui zh-CN |
→ output [language] |
Set LLM output language | /language output Chinese |
- Available built-in UI languages:
zh-CN(Simplified Chinese),en-US(English),ru-RU(Russian),de-DE(German),ja-JP(Japanese),pt-BR(Portuguese - Brazil),fr-FR(French),ca-ES(Catalan) - Output language examples:
Chinese,English,Japanese, etc.
1.4 Tool and Model Management
Commands for managing AI tools and models.
| Command | Description | Usage Examples |
|---|---|---|
/mcp |
List configured MCP servers and tools | /mcp, /mcp desc, /mcp nodesc, /mcp schema |
/import-config |
Import MCP servers from Claude configs | /import-config all, /import-config claude-code, /import-config claude-desktop --scope user|project |
/tools |
Display currently available tool list | /tools, /tools desc |
/skills |
Open the Skills panel to browse, search, toggle, and launch skills | /skills, /<skill-name> |
/plan |
Switch to plan mode or exit plan mode | /plan, /plan <task>, /plan exit |
/approval-mode |
Change the tool-approval mode (current session only) | /approval-mode, /approval-mode auto-edit |
→ plan |
Analysis only, no execution (secure review) | /approval-mode plan |
→ default |
Require approval for edits (daily use) | /approval-mode default |
→ auto-edit |
Auto-approve edits (trusted environment) | /approval-mode auto-edit |
→ auto |
Classifier-evaluated approval (autonomous) | /approval-mode auto |
→ yolo |
Auto-approve everything (quick prototyping) | /approval-mode yolo |
/model |
Switch model used in current session | /model, /model <model-id> (switch immediately) |
/model --fast |
Set a lighter model for prompt suggestions | /model --fast qwen3-coder-flash |
/model --voice |
Set the model used for voice transcription | /model --voice <model-id> |
/model --vision |
Set the vision-bridge model used to transcribe images for a text-only main model | /model --vision <model-id> |
/effort |
Set reasoning effort for thinking-capable models | /effort (opens picker), /effort high (low/medium/high/xhigh/max; mapped & clamped per provider) |
/extensions |
Manage extensions | /extensions list, /extensions manage |
→ list |
List installed extensions | /extensions list |
→ manage |
Manage installed extensions (interactive) | /extensions manage |
→ explore |
Open extensions page in browser | /extensions explore <Gemini|ClaudeCode> |
→ install |
Install an extension from a git repo or path | /extensions install <repo-or-path> |
/memory |
Open the Memory Manager dialog | /memory |
/remember |
Save a durable memory | /remember Prefer terse responses |
/forget |
Remove matching entries from auto-memory | /forget <query> |
/dream |
Manually run auto-memory consolidation | /dream |
/hooks |
Manage Qwen Code hooks | /hooks, /hooks list |
/reload-plugins |
Reload extension changes (commands, skills, agents, hooks, MCP/LSP servers) from disk | /reload-plugins |
/permissions |
Manage permission rules | /permissions |
/agents |
Manage subagents | /agents manage, /agents create |
/arena |
Manage Arena sessions | /arena start, /arena stop, /arena status, /arena select (alias choose) |
/goal |
Set a goal — keep working until condition met | /goal <condition>, /goal clear |
/tasks |
List background tasks | /tasks |
/workflows |
Inspect workflow runs | /workflows, /workflows <runId> |
/lsp |
Show LSP server status | /lsp |
/trust |
Manage folder trust settings | /trust |
Warning
Only install extensions (
/extensions install) from sources you trust. Extensions can bundle MCP servers, skills, and commands that run with the same permissions as Qwen Code itself — they can access your files, API keys, and conversation data./extensions installdoes not prompt for confirmation.
Warning
The
auto-edit,auto, andyoloapproval modes bypass approval prompts for tool executions. Inyolomode, all actions — including shell commands, file writes, and network requests — run without confirmation. Only use these modes in trusted, sandboxed, or disposable environments.
Note
/workflows,/lsp, and/trustare registered only when their feature is enabled — via theQWEN_CODE_ENABLE_WORKFLOWS=1env var, the--experimental-lspCLI flag, and thesecurity.folderTrust.enabledsetting respectively. When disabled they won't appear and will report an unknown command. Similarly,/dreamand/forgetare registered only when managed auto-memory is available; without it they won't appear.
1.5 Built-in Skills
These commands invoke bundled skills that provide specialized workflows.
| Command | Description | Usage Examples |
|---|---|---|
/review |
Multi-agent code review (12 parallel agents at high effort) | /review, /review 123, /review 123 --comment, /review --effort low |
/loop |
Run a prompt on a recurring schedule | /loop 5m check the build |
/simplify |
Review recent changes and apply safe cleanup edits directly | /simplify, /simplify focus on duplication |
/qc-helper |
Answer questions about Qwen Code usage and configuration | /qc-helper how do I configure MCP? |
See Code Review for full /review documentation.
1.6 Side Question (/btw)
The /btw command allows you to ask quick side questions without interrupting or affecting the main conversation flow.
| Command | Description |
|---|---|
/btw <your question> |
Ask a quick side question |
?btw <your question> |
Alternative syntax for side questions |
How It Works:
- The side question is sent as a separate API call with recent conversation context (up to the last 20 messages)
- The response is displayed above the Composer — you can continue typing while waiting
- The main conversation is not blocked — it continues independently
- The side question response does not become part of the main conversation history
- Answers are rendered with full Markdown support (code blocks, lists, tables, etc.)
Keyboard Shortcuts (Interactive Mode):
| Shortcut | Action |
|---|---|
Escape |
Cancel (while loading) or dismiss (after completed) |
Space or Enter |
Dismiss the answer (when input is empty) |
Ctrl+C or Ctrl+D |
Cancel an in-flight side question |
Example:
(While the main conversation is about refactoring code)
> /btw What's the difference between let and var in JavaScript?
╭──────────────────────────────────────────╮
│ /btw What's the difference between let │
│ and var in JavaScript? │
│ │
│ + Answering... │
│ Press Escape, Ctrl+C, or Ctrl+D to cancel│
╰──────────────────────────────────────────╯
> (Composer remains active — keep typing)
(After the answer arrives)
╭──────────────────────────────────────────╮
│ /btw What's the difference between let │
│ and var in JavaScript? │
│ │
│ `let` is block-scoped, while `var` is │
│ function-scoped. `let` was introduced │
│ in ES6 and doesn't hoist the same way. │
│ │
│ Press Space, Enter, or Escape to dismiss │
╰──────────────────────────────────────────╯
> (Composer still active)
Supported Execution Modes:
| Mode | Behavior |
|---|---|
| Interactive | Shows above Composer with Markdown rendering |
| Non-interactive | Returns text result: btw> question\nanswer |
| ACP (Agent Protocol) | Returns stream_messages async generator |
Tip
Use
/btwwhen you need a quick answer without derailing your main task. It's especially useful for clarifying concepts, checking facts, or getting quick explanations while staying focused on your primary workflow.
1.7 Session Recap (/recap)
The /recap command generates a short "where you left off" summary of the
current session, so you can resume an old conversation without scrolling
back through pages of history.
| Command | Description |
|---|---|
/recap |
Generate and show a one-line session recap |
How it works:
- Uses the configured fast model (
fastModelsetting) when available, falling back to the main session model. A small, cheap model is enough for a recap. - The recent conversation (up to 30 messages, text only — tool calls and tool responses are filtered out) is sent to the model with a tight system prompt.
- The recap is rendered in dim color with a
❯prefix so it stands apart from real assistant replies. - Refuses with an inline error if a model turn is in flight or another command
is processing. If there is no usable conversation, or the underlying
generation fails,
/recapshows a short info message instead of a recap — the manual command always responds with something.
Auto-trigger when returning from being away:
If the terminal is blurred for 5+ minutes and gets focused again, a recap
is generated and shown automatically (only when no model response is in
progress; otherwise it waits for the current turn to finish and then fires).
Unlike the manual command, the auto-trigger is fully silent on failure: if
generation errors or there is nothing to summarize, no message is added to
the history. Controlled by the general.showSessionRecap setting
(default: false); the manual /recap command always works regardless of
this setting.
Example:
> /recap
❯ Refactoring loopDetectionService.ts to address long-session OOM caused by
unbounded streamContentHistory and contentStats. The next step is to
implement option B (LRU sliding window with FNV-1a) pending confirmation.
Tip
Configure a fast model via
/model --fast <model>(e.g.qwen3-coder-flash) to make/recapfast and cheap. Setgeneral.showSessionRecaptotrueto enable the auto-trigger; the manual/recapcommand always works regardless of this setting.
1.8 Diff Viewer (/diff)
The /diff command opens an interactive diff viewer showing uncommitted changes and per-turn diffs. Use ←/→ to switch between the current git diff and individual conversation turns, ↑/↓ to browse files, and Enter to view inline diffs.
How it works:
In interactive mode, /diff opens a dialog with a source picker along the top:
- Current — working tree vs HEAD (
git diff HEAD). Shows all uncommitted changes including staged, unstaged, and untracked files. - T1, T2, T3, … — per-turn diffs, one tab per model turn that modified files. Most recent turns appear first. Each tab shows a preview of the original prompt for context.
The file list displays per-file stats (lines added/removed) with tags for special states (new, deleted, untracked, binary, truncated, oversized). Press Enter on a file to view its inline diff with syntax-highlighted hunks.
Per-turn diffs require file checkpointing to be enabled (on by default in interactive mode). When file checkpointing is off, only the "Current" source is available.
Keyboard shortcuts:
| Key | Action |
|---|---|
← / → |
Switch between sources (Current / T1 / T2…) |
↑ / ↓ |
Navigate file list |
j / k |
Navigate file list (vim-style) |
| Enter | View inline diff for selected file |
← / Esc |
Return to file list from inline diff view |
| Esc | Close the dialog |
Example:
┌ /diff · Turn 3 "refactor the auth middleware" ──── 3 files +45 -12 ┐
│ │
│ ◀ Current · T3 · T2 · T1 ▶ │
│ │
│ › src/utils/parser.ts +30 -8 │
│ src/utils/parser.test.ts +12 -2 │
│ README.md +3 -2 │
│ │
│ ←/→ source · ↑/↓ file · Enter view · Esc close │
└─────────────────────────────────────────────────────────────────────┘
Non-interactive mode:
In headless (--prompt) or non-interactive contexts, /diff prints a plain-text summary of the working tree vs HEAD. Per-turn navigation is not available.
3 files changed, +45 / -12
+30 -8 src/utils/parser.ts
+12 -2 src/utils/parser.test.ts
+3 -2 README.md
1.9 Information, Settings, and Help
Commands for obtaining information and performing system settings.
| Command | Description | Usage Examples |
|---|---|---|
/help |
Display help information for available commands | /help or /? |
/status |
Display version information | /status or /about |
/status paths |
Display current session file and log paths | /status paths |
/stats |
Open the interactive usage statistics dashboard (Session, Activity, and Efficiency tabs) | /stats or /usage |
/stats model |
Show per-model token breakdown and estimated cost | /stats model |
/stats tools |
Show per-tool call counts | /stats tools |
/stats skills |
Show per-skill call counts for the current live session (live only; excludes cross-session daily/monthly activity) | /stats skills |
/stats daily |
Show daily token usage statistics | /stats daily (alias day), /stats day [YYYY-MM-DD] |
/stats monthly |
Show monthly token usage statistics | /stats monthly (alias month), /stats month [YYYY-MM] |
/stats export |
Export usage statistics to CSV or JSON | /stats export <daily|monthly> [date|month] [--format csv|json] [--output path] |
/settings |
Open settings editor | /settings |
/config |
Get or set any setting by dot-path key (writes to user settings) | /config (list all), /config <key>, /config <key>=<value> |
/auth |
Change authentication method | /auth, /connect, /login |
/doctor |
Run installation and environment diagnostics | /doctor, /doctor memory |
→ memory |
Show current process memory diagnostics | /doctor memory [--json] [--sample] [--snapshot] |
→ cpu-profile |
Record a CPU profile for Chrome DevTools analysis | /doctor cpu-profile [--duration <seconds>] |
→ rollback |
Roll back the standalone CLI binary to the previous version (standalone installs only; for conversation history use /rewind) |
/doctor rollback |
/docs |
Open full Qwen Code documentation in browser | /docs |
/ide |
Manage IDE integration | /ide status, /ide install, /ide enable, /ide disable |
/insight |
Generate programming insights from chat history | /insight |
/setup-github |
Set up GitHub Actions | /setup-github |
/bug |
Submit issue about Qwen Code | /bug Button click unresponsive |
/copy |
Copy to clipboard: reply (Nth-last), code (by lang), LaTeX, or Mermaid | /copy, /copy 2, /copy python, /copy latex, /copy mermaid |
/quit |
Exit Qwen Code immediately | /quit or /exit |
Warning
/doctor memory --snapshotwrites a V8 heap snapshot that may contain prompts, file contents, API keys, and tool results from the current session. Review the file before sharing it.
Note
/configreads and writes individual settings by dot-path key (e.g.general.vimMode), complementing the interactive/settingseditor. Running/configwith no argument (or--help) lists every settable key with its type and current value./config <key>prints the current value — except for boolean keys, where it toggles the value./config <key>=<value>sets the value. Changes are written to user settings (~/.qwen/settings.json). Onlyboolean,string,number, andenumsettings can be changed this way —arrayandobjectsettings must be edited insettings.jsondirectly. Sensitive values (API keys, tokens, base URLs) are masked in output, and settingtools.approvalModetoyolois blocked.
1.10 Common Shortcuts
| Shortcut | Function | Note |
|---|---|---|
Ctrl/cmd+L |
Clear screen | Clears the visible screen only (does not reset the session like /clear) |
Ctrl/cmd+T |
Toggle tool description | MCP tool management |
Ctrl/cmd+C×2 |
Exit confirmation | Secure exit mechanism |
Ctrl/cmd+Z |
Undo input | Text editing |
Ctrl/cmd+Shift+Z |
Redo input | Text editing |
1.11 Authentication Commands
Use /auth inside a Qwen Code session to configure authentication. Use /doctor to inspect the current authentication and environment status.
| Command | Description |
|---|---|
/auth |
Configure authentication interactively (aliases: /connect, /login) |
/doctor |
Show authentication and environment checks |
Note
The standalone
qwen authCLI command has been removed. Legacy invocations such asqwen auth statusprint a removal notice with migration guidance. See the Authentication page for full details.
2. @ Commands (Introducing Files)
@ commands are used to quickly add local file or directory content to the conversation.
| Command Format | Description | Examples |
|---|---|---|
@<file path> |
Inject content of specified file | @src/main.py Please explain this code |
@<directory path> |
Recursively read all text files in directory | @docs/ Summarize content of this document |
Standalone @ |
Used when discussing @ symbol itself |
@ What is this symbol used for in programming? |
Note: Spaces in paths need to be escaped with backslash (e.g., @My\ Documents/file.txt)
3. Exclamation Commands (!) - Shell Command Execution
Exclamation commands allow you to execute system commands directly within Qwen Code.
| Command Format | Description | Examples |
|---|---|---|
!<shell command> |
Execute command in sub-Shell | !ls -la, !git status |
Standalone ! |
Switch Shell mode, any input is executed directly as Shell command | !(enter) → Input command → !(exit) |
Environment Variables: Commands executed via ! will set the QWEN_CODE=1 environment variable.
4. Custom Commands
Save frequently used prompts as shortcut commands to improve work efficiency and ensure consistency.
Note
Custom commands now use Markdown format with optional YAML frontmatter. TOML format is deprecated but still supported for backwards compatibility. When TOML files are detected, an automatic migration prompt will be displayed.
Quick Overview
| Function | Description | Advantages | Priority | Applicable Scenarios |
|---|---|---|---|---|
| Namespace | Subdirectory creates colon-named commands | Better command organization | ||
| Global Commands | ~/.qwen/commands/ |
Available in all projects | Low | Personal frequently used commands, cross-project use |
| Project Commands | <project root directory>/.qwen/commands/ |
Project-specific, version-controllable | High | Team sharing, project-specific commands |
Priority Rules: Project commands > User commands (project command used when names are same)
Command Naming Rules
File Path to Command Name Mapping Table
| File Location | Generated Command | Example Call |
|---|---|---|
~/.qwen/commands/test.md |
/test |
/test Parameter |
<project>/.qwen/commands/git/commit.md |
/git:commit |
/git:commit Message |
Naming Rules: Path separator (/ or \) converted to colon (:)
Markdown File Format Specification (Recommended)
Custom commands use Markdown files with optional YAML frontmatter:
---
description: Optional description (displayed in /help)
---
Your prompt content here.
Use {{args}} for parameter injection.
| Field | Required | Description | Example |
|---|---|---|---|
description |
Optional | Command description (displayed in /help) | description: Code analysis tool |
| Prompt body | Required | Prompt content sent to model | Any Markdown content after the frontmatter |
TOML File Format (Deprecated)
Warning
Deprecated: TOML format is still supported but will be removed in a future version. Please migrate to Markdown format.
| Field | Required | Description | Example |
|---|---|---|---|
prompt |
Required | Prompt content sent to model | prompt = "Please analyze code: {{args}}" |
description |
Optional | Command description (displayed in /help) | description = "Code analysis tool" |
Parameter Processing Mechanism
| Processing Method | Syntax | Applicable Scenarios | Security Features |
|---|---|---|---|
| Context-aware Injection | {{args}} |
Need precise parameter control | Automatic Shell escaping |
| Default Parameter Processing | No special marking | Simple commands, parameter appending | Append as-is |
| Shell Command Injection | !{command} |
Need dynamic content | Execution confirmation required before |
1. Context-aware Injection ({{args}})
| Scenario | TOML Configuration | Call Method | Actual Effect |
|---|---|---|---|
| Raw Injection | prompt = "Fix: {{args}}" |
/fix "Button issue" |
Fix: "Button issue" |
| In Shell Command | prompt = "Search: !{grep {{args}} .}" |
/search "hello" |
Execute grep "hello" . |
2. Default Parameter Processing
| Input Situation | Processing Method | Example |
|---|---|---|
| Has parameters | Append to end of prompt (separated by two line breaks) | /cmd parameter → Original prompt + parameter |
| No parameters | Send prompt as is | /cmd → Original prompt |
🚀 Dynamic Content Injection
| Injection Type | Syntax | Processing Order | Purpose |
|---|---|---|---|
| File Content | @{file path} |
Processed first | Inject static reference files |
| Shell Commands | !{command} |
Processed in middle | Inject dynamic execution results |
| Parameter Replacement | {{args}} |
Processed last | Inject user parameters |
3. Shell Command Execution (!{...})
| Operation | User Interaction |
|---|---|
| 1. Parse command and parameters | - |
| 2. Automatic Shell escaping | - |
| 3. Show confirmation dialog | ✅ User confirmation |
| 4. Execute command | - |
| 5. Inject output to prompt | - |
Example: Git Commit Message Generation
---
description: Generate Commit message based on staged changes
---
Please generate a Commit message based on the following diff:
```diff
!{git diff --staged}
```
4. File Content Injection (@{...})
| File Type | Support Status | Processing Method |
|---|---|---|
| Text Files | ✅ Full Support | Directly inject content |
| Images/PDF | ✅ Multi-modal Support | Encode and inject |
| Binary Files | ⚠️ Limited Support | May be skipped or truncated |
| Directory | ✅ Recursive Injection | Follow .gitignore rules |
Example: Code Review Command
---
description: Code review based on best practices
---
Review {{args}}, reference standards:
@{docs/code-standards.md}
Practical Creation Example
"Pure Function Refactoring" Command Creation Steps Table
| Operation | Command/Code |
|---|---|
| 1. Create directory structure | mkdir -p ~/.qwen/commands/refactor |
| 2. Create command file | touch ~/.qwen/commands/refactor/pure.md |
| 3. Edit command content | Refer to the complete code below. |
| 4. Test command | @file.js → /refactor:pure |
---
description: Refactor code to pure function
---
Please analyze code in current context, refactor to pure function.
Requirements:
1. Provide refactored code
2. Explain key changes and pure function characteristic implementation
3. Maintain function unchanged
Custom Command Best Practices Summary
Command Design Recommendations Table
| Practice Points | Recommended Approach | Avoid |
|---|---|---|
| Command Naming | Use namespaces for organization | Avoid overly generic names |
| Parameter Processing | Clearly use {{args}} |
Rely on default appending (easy to confuse) |
| Error Handling | Utilize Shell error output | Ignore execution failure |
| File Organization | Organize by function in directories | All commands in root directory |
| Description Field | Always provide clear description | Rely on auto-generated description |
Security Features Reminder Table
| Security Mechanism | Protection Effect | User Operation |
|---|---|---|
| Shell Escaping | Prevent command injection | Automatic processing |
| Execution Confirmation | Avoid accidental execution | Dialog confirmation |
| Error Reporting | Help diagnose issues | View error information |
5. CLI Subcommands
These commands are run from the shell as qwen <subcommand> before starting an interactive session.
Session Management
| Command | Description | Usage Examples |
|---|---|---|
qwen sessions list |
List recent conversation sessions | qwen sessions list, qwen sessions list --json --limit 50 |
qwen sessions list
Lists your recent Qwen Code sessions with metadata.
Flags:
| Flag | Type | Default | Description |
|---|---|---|---|
--json |
boolean | false |
Output as JSON Lines (one JSON object per line) |
--limit |
number | 20 |
Maximum number of sessions to show |
Human-readable output (default):
A table with columns: SESSION ID, STARTED (UTC timestamp), TITLE, BRANCH, PROMPT.
JSON output (--json):
Outputs JSON Lines on stdout. Each line is a JSON object with fields:
sessionId, startTime, mtime, prompt, gitBranch, customTitle, titleSource, filePath, cwd
The "has more sessions" hint is emitted via stderr so piping to jq remains safe.
Examples:
# Show last 20 sessions (default)
qwen sessions list
# Show last 50 sessions
qwen sessions list --limit 50
# Output as JSON for scripting
qwen sessions list --json | jq .