feat: add command for local code review#226
Merged
Merged
Conversation
ghost
reviewed
Apr 21, 2026
Contributor
There was a problem hiding this comment.
8 issues found across 14 files
Prompt for AI agents (unresolved issues)
Check if these issues are valid — if so, understand the root cause of each and fix them. If appropriate, use sub-agents to investigate and fix each issue separately.
<file name="cmd/review.go">
<violation number="1" location="cmd/review.go:43">
P2: `reviewCmd` sets `SilenceUsage: true` but not `SilenceErrors: true`. When `errSilentFail` is returned (whose `Error()` returns `""`), Cobra will still print `"Error: \n"` to stderr because `SilenceErrors` defaults to `false`. Add `SilenceErrors: true` to prevent the stray output line after the backend's failure text has already been written.</violation>
<violation number="2" location="cmd/review.go:123">
P2: Build the local patch before cloud setup; current ordering can fail `tusk review` on auth/network even when there is nothing to review.</violation>
</file>
<file name="internal/review/preflight.go">
<violation number="1" location="internal/review/preflight.go:100">
P2: Detached-HEAD check swallows all git errors as a warning instead of only handling the detached-head exit case.</violation>
</file>
<file name="internal/review/patch.go">
<violation number="1" location="internal/review/patch.go:106">
P2: BuildPatch ignores its context, so git commands cannot be canceled or timed out by callers.</violation>
<violation number="2" location="internal/review/patch.go:305">
P2: Use tab-delimited parsing for `git diff --numstat`; `strings.Fields` can corrupt file paths (spaces/renames).</violation>
</file>
<file name="go.mod">
<violation number="1" location="go.mod:5">
P1: Don't commit the local replace directive; it breaks builds outside the sibling-repo development layout.</violation>
</file>
<file name="internal/review/poll.go">
<violation number="1" location="internal/review/poll.go:46">
P2: TTY detection checks `os.Stderr` instead of the configured `opts.Stderr`, so polling output mode can be wrong when stderr is redirected.</violation>
</file>
<file name="cmd/review_status.go">
<violation number="1" location="cmd/review_status.go:52">
P2: `status --watch` should not cancel the backend run on Ctrl+C; it should detach local polling only.</violation>
</file>
Reply with feedback, questions, or to request a fix. Tag @cubic-dev-ai to re-run a review, or fix all with cubic.
sohankshirsagar
commented
Apr 22, 2026
sohankshirsagar
commented
Apr 22, 2026
ghost
reviewed
Apr 23, 2026
There was a problem hiding this comment.
Cursor Bugbot has reviewed your changes and found 1 potential issue.
❌ Bugbot Autofix is OFF. To automatically fix reported issues with cloud agents, enable autofix in the Cursor dashboard.
Reviewed by Cursor Bugbot for commit 89b76b5. Configure here.
jy-tan
approved these changes
Apr 23, 2026
Contributor
|
Add review docs |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.


Summary
Introduces
tusk review, a new top-level CLI parent command for the Tusk AI code review against theuser's local working tree — before they push or open a PR. Ships two subcommands:
tusk review run(submit a review of the current working tree) and
tusk review status <run-id>(check an existingrun, with
--watchto block).tusk review rungenerates a binary git patch, uploads it via three RPCs on the newCodeReviewService(CreateLocalCodeReviewRun,GetCodeReviewRunStatus,CancelCodeReviewRun),polls for completion, and writes the backend-rendered result to stdout.
The CLI is a dumb pipe for presentation: the backend renders both the human-readable text and
the JSON. The only structured field the CLI interprets is the run-status enum (so it knows when to
stop polling).
Command structure
Changes
CLI commands
cmd/review.go— parentreviewCmd(group only, noRunE), shared flag binding,runReviewfunction, result writers.
cmd/review_run.go—reviewRunCmd(Use: "run",RunE: runReview) registered underreviewCmd.cmd/review_status.go—tusk review status <run-id>(single snapshot by default;--watchto block, reusing the same poll loop).
cmd/short_docs/review/overview.md— parent-group help (intro + subcommand list + authpointer).
cmd/short_docs/review/run.md— full docs for the run subcommand.cmd/errors.go—ExitCodeErrorwrapper so specific user-actionable failures surface as exitcode 2.
main.go— unwrapsExitCodeErrorto pick the rightos.Exitvalue (non-wrapped errors stillexit 1).
RPC client
internal/api/code_review.go— three RPC methods plus five sentinel error types the commandlayer switches on for exit-code mapping and verbatim message rendering:
RateLimitError(withRetryAfterIso8601),RepoNotFoundError,PatchInvalidError,NoSeatError,NotAuthorizedError.internal/api/client.go— addedCodeReviewServiceAPIPathand amakeCodeReviewServiceRequesthelper, mirroring the existing pattern for
TestRunService/ClientService.Patch builder + preflight (all in
internal/review/)patch.go—BuildPatchgenerates a binary-clean patch:git add -Nfor untracked paths (signal-safe cleanup viaRegisterCleanup).@{u}upstream tracking ref →git merge-base origin/HEAD HEADfallback.git diff --binary <pivot>+git diff --numstat -z <pivot>against the working tree.branch_name(git branch --show-current) andlocal_head_sha(git rev-parse HEAD)for the request.
poll.go— decoupled spinner (100ms redraw, TTY only) from backend polling (5s default). Spinnerticks locally off cached
display_message; backend is hit only every 5s for heartbeat andterminal-status checks.
filter_test.go— pins list sizes (84 / 9 / 37) as a drift-detector against the backend list.Summary of git commands
tusk review runexecutesrev-parse --show-toplevel,rev-parse --git-dir)..git/).remote get-url origin, unless--repois passed).@{u}→merge-base origin/HEAD HEAD).git add -Nuntracked files so they show up in the diff.git diff --binary <pivot>+git diff --numstat -z <pivot>.git restore --staged <paths>to undo the intent-to-add (registered viaRegisterCleanupso Ctrl+C mid-build still cleans up).Request shape
CreateLocalCodeReviewRunRequestcarries:owner_name,repo_namelast_pushed_sha— the clone pivot (what the sandbox fetches); guaranteed reachable on origin.patch— the delta betweenlast_pushed_shaand the working tree.branch_name— for backend PR lookup + seat resolution.local_head_sha— informational / audit.min_severity(optional),cli_version.Client-side limits (enforced before upload)
The CLI aborts before sending the request when the patch exceeds any of these caps. The user gets
an explicit error with a top-contributors list and remediation text (exit code 2), not a silent
server-side reject:
shouldSkipFile, plus.tuskignoreand--exclude/--includeflags.git applyfailure in the sandbox.Exit codes
0— review completed (issues may or may not be found), or nothing to review after filtering.1— run failed (sandbox error, patch-apply failure, timeout, auth, network).2— user-actionable pre-flight or request failure:@{u}, noorigin/HEAD, shallow clone)retry_after)