Review and Simplify CLI Integration

Critically review this integration. https://github.com/entireio/cli/pull/1266 what are options to simplify?
I fetched PR #1266 locally. High-level: it’s a big, useful integration, but it front-loads too much product/API complexity into the CLI: a 1.2k-line command file handles target resolution, API paths, pagination, hydration, dashboard aggregation, status mutation, review submission, SSE delegation, patch safety, and git apply.
Main concerns
-
Scope is too wide for one CLI integration
- Dashboard/list/show
- Start/watch
- Resolve/dismiss/reopen
- Approve/request-changes
- Apply server-provided patches safely
These are multiple feature slices, not one integration.
-
CLI is compensating for missing API shape
- Dashboard counts require fetching all comments separately.
show/apply/resolvemust scan paginated comments to find a comment ID, then fetch review state to hydrate suggestions.- Pagination ignores
NextOffsetand assumesoffset += limit. - A direct comment detail/update endpoint would remove a lot of client code.
-
Patch apply is the highest-risk part
- It adds git HEAD checks, custom patch path validation, atomic apply logic, and temp repo tests.
- Even with current hardening, path validation is subtle across quoted paths, case-insensitive filesystems, symlinks, etc.
- This is probably not needed for the first CLI version.
-
Some UX combinations are awkward
trail review start --json --watchprints JSON then enters human watch mode.--status,--stale, and--include-dismissedcreate confusing combinations.trail watchandtrail review watchduplicate the same behavior.
Best simplification options
Option 1: MVP cut
Ship only:
Defer:
This likely removes the riskiest 30–40% of the PR, especially patch application.
Option 2: Move orchestration server-side
Add API endpoints shaped for the CLI:
Then the CLI avoids:
- scanning all comments for prefix matches
- fetching review state just to hydrate one comment
- computing counts locally
- managing list pagination for dashboard totals
This preserves functionality while simplifying the client.
Option 3: Keep features, but refactor structure
Split trail_review_cmd.go into smaller files:
Also add a shared JSON helper in api.Client to reduce repeated Get/Post/Patch -> check -> decode boilerplate.
Option 4: Simplify UX flags
Replace the filter matrix with presets:
instead of exposing --status, --stale, and --include-dismissed independently.
My recommendation
For fastest safe merge: ship the read/watch/start slice first, drop apply and verdict submission from this PR, and add a server-side dashboard/comment-detail endpoint before reintroducing mutations. That would make this feel like a clean CLI integration instead of a full review client implemented in one command file.
But would also love to be able to create a review comment via API? I always see "entire trail review [number]" NUMBER but wtf. I want lists, no one knows a fucking number before not having a list to pick from?
Yeah, agreed. The [number] UX is backwards.
Right now PR #1266 says:
but the discoverability path is weak because entire trail list currently prints branch/author/time, not the trail number/title. So users are asked for a number they probably have no way to know.
I’d change the integration around this:
1. Add a real review/trail list first
Example:
Then:
makes sense.
Also update entire trail list to include at least:
If trail number is central to the CLI, every list must show it.
2. No args should list or pick
entire trail review should do:
- If current branch has a trail: open that review dashboard.
- Else if TTY: show an interactive picker.
- Else: print the review list and say “pass a number”.
So the happy path is:
not “go find a magic number first.”
3. Consider accepting more than numbers
Instead of only [number], support a selector:
Or explicit flags:
4. Yes: add create-comment API
This is missing from the integration. The CLI can read/review/apply, but agents need to produce review comments too.
I’d want an API like:
Body:
Also probably batch:
with idempotency via client_id / Idempotency-Key, because agents retry.
My suggested simplification
For this PR, I’d prioritize:
Defer risky stuff like apply, approve, request-changes, maybe even status mutation. First make the loop discoverable and let agents create comments. Then layer mutations/apply on top.
Ok, but the user might already be on a branch within a repo that has a certain trail ID and so it would be good to just get them the comments for that or allow to post for that?
Yes — that should be the default path.
The CLI should treat “current branch’s trail” as the primary target, and trail number as an override.
Good UX:
All should resolve:
- current git repo
- current branch
- trail for that branch
- trail ID
- latest/active review for that trail
Only if that fails should it ask for/list trails.
So I’d avoid advertising:
and instead frame it as:
Examples:
For posting comments, I’d add a trail-scoped API that does not force callers to know review_id:
Body:
Server can attach it to the active/latest review, or create/reuse one idempotently.
CLI:
For agents, also add batch:
with client_id per finding for idempotency.
PR #1266 already partially does current-branch resolution when number is omitted, but the command shape/docs make the number feel central. I’d change the mental model to:
“Current branch trail by default. List/pick only when ambiguous. Number/id/branch only as explicit override.”
Implemented the UX/API changes.
Changed:
entire trail reviewnow uses[<trail>]where trail can be number, id, or branch.- Added persistent selector:
--trail <number|id|branch>
- Current branch remains the default target for:
entire trail reviewentire trail review commentsentire trail review comment add- status/show/apply/watch/start/submit flows
- If
entire trail reviewcan’t find a current-branch trail, it now falls back to showing a repo trail list. - Added:
entire trail review listentire trail review comment addentire trail review comments addalias
- Added trail-scoped create-comment API client path:
POST /api/v1/trails/{trail_id}/reviews/comments
- Added create request API types for review comments, locations, and suggested changes.
- Updated
entire trail listrows to includeNUM,BRANCH,TITLE, etc., so numbers are discoverable. - Refactored watch slightly so review watch can stream by resolved trail ID, not just number.
- Added tests for selector parsing, review list output, create comment request building, and create-comment POST path.
Validation:
env -u PI_CODING_AGENT mise exec -- go test ./...passedmise exec -- golangci-lint runpassedgit diff --checkpassed
Note: git-remote-entire is still untracked in the worktree; I left it untouched.
Update the PR description and document the command usage properly. Also make e2e examples for the golden path.
Done.
Updated:
- PR #1266 description with new targeting model, golden path, command docs, API shape, and test status.
- Added
docs/trail-review.mdwith full command usage. - Added manual e2e examples:
e2e/examples/README.mde2e/examples/trail-review-golden-path.sh
- Updated
e2e/README.mdto document manual examples.
Validation:
env -u PI_CODING_AGENT mise exec -- go test ./cmd/entire/cli ./cmd/entire/cli/apienv -u PI_CODING_AGENT mise exec -- go test ./...mise exec -- golangci-lint rungit diff --check
All passed. E2E example script is manual/service-backed, so I did not run it.
"entire trail review list --status any" doesn't entire trail list already list all the trails? This feels reundant. Also support for the # hash prefix.
I want to see the output for each of the commands.
Done.
Changes made:
- Removed redundant
entire trail review list. - Discovery now uses existing:
entire trail list --status any
entire trail reviewfallback now prints regular trail list when no current-branch trail is found.- Documented and tested
#425selector support.- Noted shell caveat: use
'#425',--trail '#425', or--trail=#425.
- Noted shell caveat: use
- Updated PR description again.
- Rewrote
docs/trail-review.mdwith output examples for each command:entire trail list --status anyentire trail review- fallback output
startcommentscomment addshowapplyresolve/dismiss/reopenapprove/request-changeswatch
- Updated golden path e2e example to use
entire trail list --status any.
Validation:
env -u PI_CODING_AGENT mise exec -- go test ./cmd/entire/cli ./cmd/entire/cli/apienv -u PI_CODING_AGENT mise exec -- go test ./...mise exec -- golangci-lint rungit diff --check
All passed.
Why even supporting "#" at all? Remove that doc, put it in the PR description instead. Make it concise. Where does approve/request-changes come from? that's not part of the code review API?
Agreed. I cleaned that up.
Changes:
- Removed
#selector support. Selectors are now only:- number:
425 - trail id:
trl_abc123 - branch:
feat/foo
- number:
- Removed the standalone
docs/trail-review.md; command docs/output now live concisely in the PR description. - Removed
approve/request-changescommands and API types. You’re right — those were trail verdict actions, not part of the agent-native code review API. - Updated PR description to be shorter and focused.
- Kept
entire trail list --status anyas the discovery path instead of adding redundant review-specific list. - Updated tests accordingly.
Validation passed:
env -u PI_CODING_AGENT mise exec -- go test ./cmd/entire/cli ./cmd/entire/cli/apienv -u PI_CODING_AGENT mise exec -- go test ./...mise exec -- golangci-lint rungit diff --check
- "entire trail list --status any" already exists?
- How to make a code suggestion? I do see apply.
- Is "entire trail review start" really needed, like what does it even do?
Addressed.
Changes:
- Removed
#425support entirely. - Removed
approve/request-changescode and API types. - Removed standalone
docs/trail-review.md; kept docs concise in PR description. - Updated PR description to clarify:
entire trail list --status anyalready exists; PR only improves list output withNUM/TITLE.- Code suggestions are created via
comment add --patch-file suggestion.diffor--patch-file -. review startis optional/advanced: only for explicitly requesting/rerunning automated review, not needed for list/post/respond.
- Added
--patch-filesupport for code suggestions. - Removed
review startfrom golden-path e2e example. - Updated manual e2e docs accordingly.
Validation passed:
env -u PI_CODING_AGENT mise exec -- go test ./cmd/entire/cli ./cmd/entire/cli/apienv -u PI_CODING_AGENT mise exec -- go test ./...mise exec -- golangci-lint rungit diff --check
Still untouched: untracked git-remote-entire.
You’re right — if we can’t explain review start clearly, it shouldn’t be in this UX.
I removed it.
Now the flow is just:
Also updated:
- Removed
review startcode, API types, tests, and PR docs. - Removed
PostWithHeadersthat only existed forstart. - Clarified PR description:
entire trail list --status anyalready exists.- Code suggestions are via
comment add --patch-file suggestion.diffor--patch-file -.
- Golden-path e2e example no longer includes
review start.
Validation passed:
go test ./cmd/entire/cli ./cmd/entire/cli/apigo test ./...golangci-lint rungit diff --check
Is it best practice in this CLI but also others to do a list command e.g. comments and then a single comment?
Usually no. Better practice is one consistent resource namespace.
Current mixed shape is a bit awkward:
Better canonical shape:
Then aliases can exist for ergonomics:
This matches common CLI patterns better: resource + verb, e.g. gh issue list/view/create, kubectl get/describe, etc.
One caveat: “comment” may be API language while the UI says “finding.” If the user-facing concept is finding, then even better:
But if API/product calls them review comments, use comment. My recommendation: make comment list/show/add/... canonical and keep shorter old forms as aliases if desired.
Yes — agreed. I changed it to:
Also removed:
entire trail reviewentire trail review startapprove/request-changes#425support/docs
Updated:
- PR description
- golden-path e2e example renamed to
e2e/examples/trail-finding-golden-path.sh - e2e docs
- output text to say “finding” instead of “comment” where user-facing
Validation passed:
go test ./cmd/entire/cli ./cmd/entire/cli/apigo test ./...golangci-lint rungit diff --check
Review the branch for regressions, redudant or dead code. Is everything functional an in a good shape?
Review complete. Overall the current working tree is in good shape functionally.
Fixed during review:
- Replaced remaining user-facing “comment” output with “finding”, including status/apply output and watch event rendering.
- Updated
trail watchwording from code-review/comment language to finding language. - Fixed removed
entire trail reviewsilently falling through toentire trailby addingcobra.NoArgsontrail. - Added tests verifying
findingcommand surface and removedreview/start/comments/approve/request-changes. - Switched
--patch-file -to read fromcmd.InOrStdin(). - Updated PR #1266 description examples via
gh pr edit.
Validation passed:
env -u PI_CODING_AGENT mise exec -- go test ./cmd/entire/cli ./cmd/entire/cli/apienv -u PI_CODING_AGENT mise exec -- go test ./...mise exec -- golangci-lint rungit diff --check
Remaining cautions:
- Code changes are still uncommitted/unpushed, so PR code does not yet reflect them.
e2e/examples/is untracked and should be added if committing.git-remote-entireis still untracked and appears unrelated; leave it out.- Two unrelated lint-cleanup edits remain in checkpoint/strategy files because lint currently flags those stale
nolintdirectives.
Committed and pushed.
- Commit:
43067b86d feat: simplify trail finding CLI - Pushed to:
origin/feat/trail-review-cli - PR head now points to
43067b86d - Removed untracked
git-remote-entire - Working tree is clean
Note: commit/push hooks printed a missing ./scripts/entire-dev warning, but both operations completed successfully.
Done.
- Fetched latest
origin/main - Merged into current branch
pr-1266 - Resolved conflicts in:
cmd/entire/cli/checkpoint/committed_reader_resolve.gocmd/entire/cli/strategy/manual_commit.go
- Committed merge:
caa7203a5 - Pushed to PR branch:
origin/feat/trail-review-cli - Removed the untracked root
git-remote-entirefile - Working tree is clean
Validation passed:
env -u PI_CODING_AGENT mise exec -- go test ./cmd/entire/cli ./cmd/entire/cli/apienv -u PI_CODING_AGENT mise exec -- go test ./...mise exec -- golangci-lint rungit diff --check
PR is mergeable; checks are currently running.
Checked out/fetched latest branch state.
Current HEAD:
edaadf399 refactor: address trail finding CLI review feedback- Matches
origin/feat/trail-review-cli - Working tree is clean
- PR is mergeable
Validation passed locally:
env -u PI_CODING_AGENT mise exec -- go test ./cmd/entire/cli ./cmd/entire/cli/apienv -u PI_CODING_AGENT mise exec -- go test ./...mise exec -- golangci-lint rungit diff --check origin/main...HEAD- No conflict markers found
Latest changes look valid. CI on GitHub still has some test jobs in progress, but completed jobs are passing so far.
wtf does that comment mean? Medium — finding commands bypass the resolveTrailRemote forge guard
resolveTrailReviewTarget (trail_review_cmd.go:436) calls gitremote.ResolveRemoteRepo directly:
host, owner, repo, err := gitremote.ResolveRemoteRepo(ctx, "origin")
But the watch path (and the rest of trail_cmd.go) goes through resolveTrailRemote, which exists specifically to catch an empty forge — its doc comment says:
▎ Without this guard, an unmapped host (e.g. gitlab.com…) produces a malformed /api/v1/trails//owner/repo path that the server rejects with an opaque error instead of a clear ▎ "unsupported forge" one.
So every entire trail finding * command on a non-GitHub origin reintroduces exactly the opaque-error behavior that guard was added to prevent — and it's inconsistent with entire trail watch in the same PR. Recommend calling resolveTrailRemote(ctx) here instead.
It means the review was valid: entire trail finding ... was resolving the git remote with the lower-level helper, which can return an empty forge for unsupported remotes like GitLab. That would build a bad API path like:
Instead of failing locally with a clear unsupported-forge error.
I fixed it by changing resolveTrailReviewTarget to call resolveTrailRemote(ctx), the guarded helper already used by trail/watch paths, and added a regression test for unsupported forge handling.
Pushed fix:
Validation passed locally:
go test ./cmd/entire/cli ./cmd/entire/cli/apigo test ./...golangci-lint rungit diff --check
Working tree is clean; PR checks are queued.