Self-review is the cheapest review layer and the one most often skipped, because assembling the diff and framing the question is friction at exactly the moment you want to be finished.
Copilot CLI removes that friction. /review and /diff operate on your working tree directly — no
copying, no attaching, no leaving the terminal.
This lesson is what that buys and where it stops.
The commands
Section titled “The commands”/review/review src/payments/client.pyWhat it doesReviews code changes, or the contents of a specific file if one is named.
Why we run itIt reads your working tree directly, which removes the assembly step that makes self-review get skipped.
Expected resultReview findings for the changes or file in question.
{/* Review changes in the current directory */}/diffThe distinction: /diff is oriented at what has changed; /review can also take a path and review a
file’s contents whether or not it changed.
Both operate locally, on uncommitted work, before anything is pushed. That is the defining property of this layer.
What this layer is for
Section titled “What this layer is for”Before the commit. Debug output, commented-out code, a hardcoded path, a TODO from twenty minutes
ago, a test left with .only on it. The category that costs a review round trip and is embarrassing to
have pointed out.
Before the push. The whole branch, read as a reviewer will read it. This is where you find the unrelated file and the change larger than you remembered.
On unfamiliar code you are about to change. /review path/to/file.py on something you did not
write, asking what it does and what would break if you changed it.
Not for: proving anything. It has run nothing. Tests and CI are separate and unchanged.
Asking well
Section titled “Asking well”“Review this” produces a list of observations of uneven value. The questions that produce findings:
“What did I leave in?” Highest yield, and instantly checkable.
“What does this change that the diff does not make obvious?” A changed default, a removed guard, a narrowed condition. Second-order effects are what human reviewers skim past.
“For each new code path, is there a test?” Absence is what a systematic reader catches and a human does not.
“What would a reviewer ask?” Pre-empts a round trip, and the answers belong in your pull request description.
“Is anything here security-relevant?” Broad, worth asking on anything touching input, auth, or command construction. Treat the output as prompts to check.
The agent can also run commands to answer these — checking whether a function is called elsewhere, whether a test file exists, whether the linter passes. That is the difference from pasting a diff into a chat window, and it is worth exploiting:
Review my staged changes. For anything you flag, check whether it is actually reachable by looking at the callers.
Suggested fixes and applying them
Section titled “Suggested fixes and applying them”A review that can also edit is convenient and needs a boundary.
Reviewing is read-only. Nothing changes while it reads.
Applying a fix is an edit, and requires approval like any other. Read it.
The failure mode specific to this combination: accepting a suggested fix without evaluating whether the finding was real. The suggestion arrives with the finding, both sound plausible, and applying it is one approval away. If the finding was a false positive — the model lacking a file, usually — the “fix” is an unnecessary change to working code.
The habit that avoids it: decide the finding is real before looking at the fix. They are two judgements and the interface presents them as one.
Confidence and triage
Section titled “Confidence and triage”The most useful thing to ask for, and the one nobody asks for: a confidence statement per finding.
For each finding, say how confident you are and what would change your assessment.
That turns an undifferentiated list into a triage order. High-confidence findings — a leftover debug line, a missing test file — are checkable in seconds. Low-confidence ones usually depend on code the model has not read, which tells you exactly what to supply.
It also surfaces the honest uncertainty that is otherwise absent. A finding presented flatly reads as a
defect; the same finding presented as “possible, depending on whether process_order validates upstream
— I have not read it” reads as what it is, which is a question.
The related instruction worth including in any review agent:
If a finding depends on code you have not read, say so explicitly rather than assuming.
Between them, those two lines address most of what makes AI review findings tiring to work through. The volume is not usually the problem; the problem is that every item arrives with the same apparent weight, so triage requires reading all of them carefully.
False positives
Section titled “False positives”The same pattern as everywhere: findings that are wrong because the model saw the diff and not the system.
Missing error handling that is handled by a decorator or middleware it did not see.
Unused variables used in a file it was not given.
Style objections contradicting your linter, which is authoritative.
Security concerns about test fixtures, where the credential is deliberately fake — worth a second of thought each time, because occasionally the fixture is real.
Suggestions to add checks made unreachable by your type system.
The fix is nearly always to supply the missing context rather than to argue. In the CLI this is easy: tell it to read the file.
That is handled by the
@handle_errorsdecorator inapp/decorators.py. Read it and re-check.
Calibrate by treating findings as questions. A question costs seconds to answer and does not require you to be right about whether the model was.
How this differs from pull request review
Section titled “How this differs from pull request review”Both are AI review. They are not redundant.
Terminal /review | Copilot code review | |
|---|---|---|
| Runs | Your machine, before push | On the pull request |
| Sees | Working tree, uncommitted work | The pull request diff |
| Output | Terminal, ephemeral | Review comments, persistent |
| Audience | You | The team |
| Configuration | Repository instructions, skills, agents | Instructions, path-specific rules, skills |
| Can run commands | Yes | No |
| Record | None | In the pull request |
Two consequences worth acting on.
Terminal review catches things before they cost anybody attention. A leftover debug line found here never becomes a review comment.
It leaves no record. For anything the team should see — a concern about the approach, a known limitation — that belongs in the pull request description or a comment, not in a terminal session nobody else sees.
The productive sequence: terminal review to clean up, pull request review to catch what you missed, human review for judgement. Each is cheaper than the next.
Reviewing directories and unfamiliar code
Section titled “Reviewing directories and unfamiliar code”/review on a path is useful beyond your own changes.
Before modifying unfamiliar code: “Review src/scheduler/ and tell me what it is responsible for,
what calls it, and what would break if I changed the retry interval.”
Before a refactor: what the current structure does, and what depends on it.
When picking up somebody else’s branch: a read of what changed, before you start adding to it.
This is closer to chat’s explain use than to review, and it works well here because the agent can read whatever it needs rather than being handed files.
The caution is scope: reviewing a large directory produces a large amount of output, most of which is description. Narrow the question — “what would break if I changed X” beats “review this directory”.
Reviewing a range rather than the working tree
Section titled “Reviewing a range rather than the working tree”Sometimes the thing to review is not what is uncommitted but a set of commits — a colleague’s branch, a range you are about to merge, or your own work after committing.
The agent can produce and read those diffs itself:
Review the changes on this branch against main. Use
git diff main...HEAD. What would a reviewer ask?
Two details from AI-assisted Git code reviews that matter here:
Three dots, not two. main...HEAD compares against the merge base and is what a reviewer sees.
main..HEAD compares tips and, on a branch that is behind, reports files as deleted that you never
touched.
Commit-by-commit is a different question. Reviewing each commit separately answers “does each one stand on its own” — which is about bisectability rather than about the final state, and it is much easier to fix before pushing.
Show me each commit on this branch as a separate diff. Does each one leave the tests passing? Is any of them doing two unrelated things?
Reviewing somebody else’s branch this way is legitimate and has one caveat worth stating: findings from a terminal session are not review comments. If you have something to say about a colleague’s work, it belongs in the pull request where they will see it and where the conversation is recorded.
Configuration
Section titled “Configuration”Terminal review reads the same repository configuration as everything else in the CLI, which means review criteria can be codified rather than retyped.
Repository instructions shape what it considers important.
Path-specific instructions apply where relevant, so a review of a migration checks migration things.
A review skill is the durable form for anything long — a full checklist with examples, loaded when relevant. See agent skills.
A review agent restricts tools so review is genuinely read-only:
---name: reviewerdescription: Reviews changes against this repository's standards. Read-only.tools: ["read", "search"]---
Review the changes you are given against these criteria, in order:
1. Leftovers: debug output, commented code, hardcoded values, `.only` on tests.2. Missing tests for new code paths.3. Changes to defaults, guards or validation that the diff does not make obvious.4. Input reaching a query, command or path without the helpers in `security/`.5. New dependencies — name them and say what they are for.
For each finding: the file, the line, why it matters here, and how confident youare. If a finding depends on code you have not read, say so.
Do not propose edits. Report only.The last two instructions are the useful ones. Asking for a confidence statement makes triage faster. Asking it to flag when a finding depends on unread code surfaces the exact condition that produces false positives.
Reviewing what an agent produced
Section titled “Reviewing what an agent produced”A specific case that is becoming common: reviewing work an agent just did, in the same session.
The obvious problem is that you are asking the thing that wrote the code whether the code is good, and it will find something positive to say. That framing produces confirmation rather than review.
Two ways to get useful output anyway.
Start a fresh session. A new session reviewing the diff has no memory of having written it and no investment in the approach. This is the closest thing to an independent read available, and it costs one command.
Use a review agent with explicit criteria. The agent above does not know or care who wrote the code; it checks the list. That consistency is the point — the same criteria applied regardless of provenance.
What neither fixes: an agent cannot tell you whether the approach was right. If it misunderstood the task, a review of the resulting code will find the code to be a good implementation of the misunderstanding. That judgement is yours, and it is why reading the plan matters more than reviewing the output.
The practical sequence for agent-produced work: read the plan before it acts, review the diff yourself, then run a fresh review session for the mechanical checks, then CI. Four layers, of which two are you.
Reviewing before a commit, in practice
Section titled “Reviewing before a commit, in practice”The loop, compressed to what it actually looks like.
-
git status— what is in the working tree at all. The agent can run this. -
/diffwith a specific question — “what did I leave in?” -
Fix what it found, yourself where it is quick.
-
Stage deliberately.
git add -pif there is more than one logical change. -
/reviewon the staged diff — “what does this change that is not obvious?” -
Commit, with a message from the staged diff.
-
Before pushing:
/reviewthe whole branch — “what would a reviewer ask?”
Steps 2 and 7 are the two that matter and take about a minute together. Step 7’s output is also the material for the pull request description, so it is not extra work.
The reason to put it in a numbered list rather than describing it as a habit: the friction that kills self-review is deciding to do it. A sequence attached to commands you already run does not require a decision.
Making it a team practice
Section titled “Making it a team practice”Terminal review is individual by default, which limits it. Three things make it shared.
Commit the review agent. A .github/agents/reviewer.md with agreed criteria means everybody’s
self-review checks the same things. That consistency is worth more than any individual’s thoroughness,
and it is a reviewable artefact — adding a criterion is a pull request and a conversation.
Derive the criteria from real review comments. The best source is the last three months of pull request comments. What reviewers keep pointing out is exactly what self-review should catch, and moving it earlier is a direct saving in round trips.
Measure the round trips, not the findings. The signal that this is working is fewer review comments of the “you left a debug statement in” variety — the category that costs a cycle and teaches reviewers this branch needs careful reading. Finding count measures usage.
The failure to avoid: making it mandatory. A pre-push hook that runs a review and prints findings gets scrolled past, because output nobody asked for is output nobody reads. The habit you want is somebody choosing to look, which is a cultural thing rather than a technical one — and the way to get it is for the layer to be genuinely useful, which is what the criteria are for.
Common mistakes
Section titled “Common mistakes”“Review this” with no specific question. A list of observations rather than findings.
Applying a suggested fix before evaluating the finding. Two judgements presented as one.
Arguing with a false positive instead of supplying the file. It could not see the caller.
Treating it as a substitute for tests. It has run nothing.
Reviewing only staged changes. The unstaged diff is where the accidental changes are.
Leaving concerns in the terminal. Anything the team should know belongs in the pull request.
Reviewing a whole directory. Narrow the question or drown in description.
What terminal review does not catch
Section titled “What terminal review does not catch”Worth listing, because a layer that catches things starts to feel like a layer that catches everything.
Anything requiring execution. It has not run your code, your tests, or your linter — unless you ask it to, which is worth doing and is a different activity from reading.
Architectural fit. Whether this belongs in this module, whether the abstraction is right, whether this duplicates something elsewhere in the codebase it did not read.
Product correctness. Whether the behaviour is what was wanted. That is in the issue, the ticket, or somebody’s head.
Cross-cutting consequences. The effect of your change on a caller three modules away, on a downstream service, on a client that depends on the current response shape.
Anything about your organisation. That this table is replicated, that this endpoint has a partner contract, that this module is owned by another team.
Its own blind spots. It will not tell you it lacked context; it will produce a confident finding based on what it had.
That list is the specification for the layers after it. Tests catch execution. Code scanning catches data-flow problems this cannot see. Human review catches architecture, product and organisational knowledge — which is why it stays the accountable layer regardless of how good the earlier ones get.
Mental model
Section titled “Mental model”Terminal review is a careful reader looking at your work before anybody else has to. It costs seconds, catches the things that would have cost a round trip, and proves nothing — which is what the tests are for.
What you learned
Section titled “What you learned”/reviewand/diffoperate on your working tree without you assembling anything- Removing the assembly friction is what makes self-review actually happen
- Specific questions produce findings; “review this” produces observations
- The agent can run commands to check its own findings, which chat cannot
- Deciding a finding is real and evaluating its fix are two judgements
- False positives almost always mean missing context, which is cheap to supply here
- Terminal review leaves no record; anything the team needs belongs in the pull request
- A read-only review agent with explicit criteria makes the layer consistent
Exercise
Section titled “Exercise”Use a branch with real uncommitted changes.
-
Run
/diffwith no further instruction. Count how many findings are actionable. -
Ask three specific questions instead. Compare the actionable proportion.
-
Ask “for each new code path, is there a test?” Predict: does it find a gap you knew about?
-
Find a false positive. Tell the agent which file it was missing and ask it to re-check. Predict: does the finding survive?
-
Accept a suggested fix without evaluating the finding first. Predict: was the change necessary?
-
Write a review agent with explicit criteria and run it. Compare consistency with the ad-hoc review.
-
Push the branch and let Copilot code review run. Predict: does it find anything the terminal review did not?