Investigate CLI Repo and Branch Flags

make a new branch off origin/main for this. i have a feeling that entire trail ... commands all require the cli to be running inside a checked-out git repo, and it derives the trail's repo and branch from that. i'd like to be able to use the cli as a backend for my own Trails GUI, so it could be good to add --repo and --branch flags, too, where appropriate. don't write code yet, investigate feasibility.
I'd like to be able to call, e.g.,
entire trail show --repo gh/entireio/cli --branch my/feature
entire trail finding list --repo gh/entireio/cli --branch my/feature
entire trail finding list --repo gh/entireio/cli --trail-id 123
Let me check runAuthenticatedTrailAPI and the context cache to confirm auth itself doesn't need a git repo.
i can tell you about auth - by default we'll be hitting up entire.io as our API base url. that resource provider is exposing a .well-known/....json blob with informatino about who can authenticate it. that mechanism is already in the CLI and used in the entire activity feature. we should do the exact same thing, and if the user wants to override the API base URL (e.g., to use staging's https://partial.to) then we should use the appropriate auth context for that.
I have everything I need. Here's the feasibility assessment.
Bottom line
Feasible, and the change is small and localized. Every entire trail command derives the repo from origin and the branch from the current checkout through exactly two chokepoints. Add --repo/--branch overrides at those two points and the read/metadata commands work with no git clone at all. Auth is already git-independent (it keys off the API base URL's .well-known/entire-api.json, exactly as entire activity does — nothing to change there).
The only two git dependencies
resolveTrailRemote(ctx)(trail_cmd.go:1633) →gitremote.ResolveRemoteRepo(ctx, "origin")— produces the(forge, owner, repo)triple used to build every API path (/api/v1/trails/<forge>/<owner>/<repo>/...). Requires a clone with anoriginremote.GetCurrentBranch(ctx)(git_operations.go:188) — used only when no trail selector is given, to find the trail by branch.
That's it. The triple and branch are passed as plain strings into findTrailByBranch / findTrailBySelector / trailsBasePath — nothing validates them against a local clone. So overriding them is purely additive.
What --repo gh/entireio/cli maps to
gh/entireio/cli is the forge/owner/repo triple verbatim — the server path format. A --repo flag just needs to split on / into 3 segments (and optionally accept a full clone URL via the existing gitremote.ParseURL). No new server contract.
Per-command breakdown
Clean wins (read/metadata only — these should get --repo/--branch):
trail show,trail list,trail update,trail delete,trail watchtrail finding+list,add,show,update,resolve,dismiss,reopen
Note on findings + branch: entire trail finding already has a --trail selector that accepts number, id, or branch (trail_review_cmd.go:92). So once --repo exists, --trail my/feature and --trail-id 123 both already work — your --trail-id 123 example maps to the existing --trail 123. You may still want --branch as an explicit, clearer alias.
Inherently local — should NOT get --repo (they mutate the local worktree):
trail create— creates/fetches/pushes local branchestrail checkout— checks out a branch in the worktreetrail finding apply— applies a patch to the worktree and verifies localHEAD(trail_review_cmd.go:1037,:1022)
Recommended seams (when we write code)
- Add
--repoas a persistent flag on thetrailroot (newTrailCmd,trail_cmd.go:41) — same pattern as the existing persistent--insecure-http-auth. Conflict-free; no command defines--repotoday. - Wrap the two chokepoints: a
resolveTrailRepo(cmd, ctx)that returns the parsed--repotriple or falls back toresolveTrailRemote(ctx); similarly for branch. --branchis trickier:create/update/deletealready define a--branchflag with command-specific meaning, so it can't be a single persistent flag. Add--branchper-command onshow/finding/watch(which today only use the current branch), and leave the existing three as-is.- The best-effort enablement cache (
currentTrailEnablementScope,trail_context_cache.go:91) readsorigintoo, but it's debug-log-only on failure — it degrades gracefully outside a clone. Optionally feed it the--repotriple so the cache works in GUI mode, but not required for correctness.
Want me to turn this into an implementation plan (or just build it)?
this sounds reasonable. let's make this feature and see what my colleagues say. as for the --branch flag, yes, let's only add it on the commands where that makes sense.
Done. Committed on trail-repo-branch-flags (not pushed).
What shipped
--repo (persistent on trail root) — accepts gh/entireio/cli or a clone URL; defaults to origin. Honored by show, list, update, delete, watch, finding (+ subcommands). Rejected on the local-clone commands (create, checkout, finding apply) with a clear error.
--branch (new on show, watch, finding) — selects the trail by branch instead of the current checkout. update/delete already had it. Mutually exclusive with an explicit trail selector.
Your examples now work without being in the repo:
Design notes for your reviewers
- Two chokepoints, not scattered: every command resolved repo via
resolveTrailRemoteand branch viaGetCurrentBranch. AddedresolveTrailRepoOrRemote/resolveTrailBranchwrappers; the override threads through existing options structs/params with no behavior change when flags are absent. - Auth untouched — already git-independent (
.well-known/entire-api.jsonoff the API base URL, same asentire activity), soENTIRE_API_BASE_URL=https://partial.topicks the right context automatically. --trail-id 123from your example maps to the existing--trail 123.
Verification
mise run fmt && mise run lint→ 0 issues- Full
cmd/entire/clipackage tests pass; addedtrail_repo_flag_test.go(parser table, override-skips-git, mutual-exclusion, local-command guards).
Want me to push, or open a draft PR?
push and open a PR. Reason in the description is to make it easier to use trails as a scripting tool.
Pushed and PR opened: https://github.com/entireio/cli/pull/1532
- Branch
trail-repo-branch-flags→main - Description leads with the rationale: using trails as a scripting tool against any repo/branch without needing a local clone.
retrieve the PR comments from https://github.com/entireio/cli/pull/1532 and the trail finding from https://entire.io/gh/entireio/cli/trails/671/feat-trail-repo-and-branch-overrides - they boil down to the same thing. make the slug parsing stricter and fail clearly.
Done — fix pushed to the PR.
What I changed
The slug parser now validates the forge segment of the bare forge/owner/repo form against gitremote.IsSupportedForge (new helper checking the known short-forge set). Host-like or unknown forges fail clearly instead of reaching the server:
gh/acme/app still works; clone URLs (https://…, git@…, entire://…) still route through the URL parser. Added bare host-like / unknown-forge cases to the table test. Lint clean.
One thing to flag
The two PR bots actually raised two distinct issues. I fixed the slug one you pointed at. The other (Cursor Bugbot, medium) is separate: when --repo targets a different repo but --branch is omitted, the commands still default to the local checkout's branch name, which could resolve the wrong trail. That's the "scripting against a repo you're not checked out in" footgun — arguably a caller responsibility, but if you want it hard-stopped I'd make --repo require --branch (or an explicit selector) on the branch-defaulting commands. Say the word and I'll add it.
Pushed. Done.
What changed
--repo now requires an explicit target on every branch-defaulting command, so it can never silently fall back to the local checkout's branch:
| Command | Requires with --repo |
|---|---|
show, finding | a trail selector or --branch |
watch, delete | a trail number or --branch |
update | --branch |
list is unaffected (it doesn't resolve a single branch). The local-only commands (create/checkout/finding apply) still reject --repo outright. Added TestTrailRepoRequiresExplicitTarget covering all five commands.
Heads-up on the lint footgun
My earlier mise run lint (runs with --fix) silently stripped a //nolint:ireturn directive from agentimport.go — a file I never touched — and it rode into a commit. CI lints without --fix, so it would have failed there. I restored the line to match origin/main and verified with the CI-equivalent invocation (golangci-lint run --new-from-rev=origin/main, no --fix) → 0 issues. This is the exact behavior my local-lint-autofixes memory warns about; I avoided re-running the --fix task so it wouldn't strip it again.
Both review findings (the slug strictness and the branch-default footgun) are now addressed on PR #1532.
wait a sec is this valid https://github.com/entireio/cli/pull/1532#discussion_r3479926314
Yes — it was a valid (low-severity) issue, and it's now fixed.
Verdict on that comment
Real bug: the trails-enablement cache writes all derived the repo from the local origin, ignoring --repo. Running entire trail … --repo gh/other/repo from inside a clone of repo A would record "A is trails-enabled" off a query that never touched A, and the error path would even make a spurious enablement network call about A. (In a non-clone dir it was a harmless no-op.)
Fix (pushed in e30a96559)
Threaded the --repo override into runAuthenticatedTrailAPI and skip the cache writes when it's set — both noteTrailCommandEnablement and watch's explicit saveTrailsEnabledForRepoBestEffort. Checkout passes "" (it rejects --repo, so it always tracks local origin). Replied to the cursor comment with the SHA.
Verified: build clean, trail tests pass, gofmt clean, and CI-equivalent lint (--new-from-rev=origin/main, no --fix) reports 0 issues. I avoided mise run lint this round so it couldn't re-strip the agentimport.go //nolint directive — confirmed still present.
Rebased onto latest origin/main and force-pushed.
What happened during the rebase
origin/main moved 25 commits ahead and touched overlapping code, so three things had to be reconciled:
trail watchwas refactored upstream to take a[<trail>]selector and delegate to the sharedrunTrailReviewWatch→authenticatedTrailReviewTarget. That resolver already carries my--repo/--branch/mutual-exclusion/require-target/enablement-skip logic, so watch now gets all of it for free. I dropped my obsolete watch-specific resolver code and kept only the--branchflag registration.agentimport.gono longer needs the//nolint:ireturn— main removed it (ireturn handled via config now). My earlier strip-and-restore churn is gone; the file is byte-identical to main.- A new caller (
review_bridge.go'spostReviewToTrail, added on main) used the oldresolveTrailReviewTargetsignature — updated to pass empty overrides (keeps targeting the current branch's trail).
Verification
go build ./...+go vetcleanTrail/ParseTrailRepo/Reviewtests pass- gofmt clean; CI-equivalent lint (
--new-from-rev=origin/main, no--fix) → 0 issues
Branch is now 5 commits on top of origin/main. PR #1532 is updated.