feat(onboarding): guided setup ladder β enable walks login/mirror/import, status shows the checklist, re-enable resumes#1618
feat(onboarding): guided setup ladder β enable walks login/mirror/import, status shows the checklist, re-enable resumes#1618peyton-alt wants to merge 9 commits into
Conversation
Model onboarding as a ladder of rungs (hooks, auth, mirror, import), each recomputing done/missing/blocked from ground truth on every check β installed hooks on disk, the stored auth context (offline), the control-plane mirror list (5s timeout, degrades to unknown), and local agent-transcript discovery. One source of truth so enable's prompts, its closing summary, and status's checklist can never disagree. The offer runner drives the connect rungs at the end of enable: a single consent prompt (set up everything / step by step / skip), best-effort offers reusing the existing browser-login flow and createAndAwaitMirror (--no-wait), and a closing checklist with deduped run-later hints. Rung state is recomputed before each offer, so a login completed mid-pass unblocks the mirror rung in the same pass, and rungs finished out-of-band are never re-offered. Blocked rungs (mirror without login) render as blocked instead of offering commands that would 401. The import rung is status-row only for now: its enable-time offer lands with PR #1595 and will wrap into the rung as a follow-up. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com> Entire-Checkpoint: 8323d0af36d1
β¦ status Wire the onboarding ladder into every enable path and into status, making `entire enable` both the onboarding wizard and the resume command: - Interactive enable (and `--agent`) runs the connect rungs after hook setup: one consent prompt covering whatever is missing, then the checklist. - Bare enable on an already-enabled repo β previously a hard short-circuit at "Entire is already enabled." β now re-offers only the missing rungs, so an interrupted setup is resumed by just running enable again. Re-enabling a disabled repo converges the same way. - Non-interactive (--yes / no TTY) never prompts and never creates a mirror; the checklist hints carry the follow-up commands. - `entire status` renders the same checklist (Setup N/M complete, with a pointer back at enable) and collapses to a single Connected line once done; `status --json` exposes the rung states as a `setup` object. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com> Entire-Checkpoint: 7027c08f348a
There was a problem hiding this comment.
Cursor Bugbot has reviewed your changes and found 2 potential issues.
β Bugbot Autofix is OFF. To automatically fix reported issues with cloud agents, enable autofix in the Cursor dashboard.
Want fixes drafted automatically? Bugbot Autofix can create code changes for findings. A team admin can enable Autofix in the Cursor dashboard.
Comment @cursor review or bugbot run to trigger another review on this PR
Reviewed by Cursor Bugbot for commit 3fbeea0. Configure here.
There was a problem hiding this comment.
Pull request overview
This PR introduces a shared βsetup ladderβ onboarding model so entire enable and entire status can consistently compute and present setup progress (hooks, auth, mirroring, import) from ground truth, and so re-running entire enable resumes any incomplete onboarding steps.
Changes:
- Add a new
onboardingmodel package (rungs, states, results) plus ladder helpers (Summary,Complete,Missing) with unit tests. - Wire
entire status(human +--json) to render the onboarding checklist/collapsed βConnectedβ line when enabled. - Update
entire enableto run the onboarding ladder after setup and when re-run on already-enabled / re-enabled repos, with offer-runner logic and tests.
Reviewed changes
Copilot reviewed 13 out of 13 changed files in this pull request and generated 3 comments.
Show a summary per file
| File | Description |
|---|---|
| cmd/entire/cli/status.go | Renders onboarding checklist in human output and exposes rung states via setup in --json. |
| cmd/entire/cli/status_test.go | Adds coverage for checklist rendering and JSON setup wiring via stubs. |
| cmd/entire/cli/setup.go | Runs onboarding ladder at the end of enable flows and on re-enable resume paths. |
| cmd/entire/cli/setup_test.go | Verifies already-enabled and re-enable paths invoke the onboarding ladder. |
| cmd/entire/cli/onboarding/onboarding.go | New canonical onboarding ladder model: rungs, states, checks, and summary helpers. |
| cmd/entire/cli/onboarding/onboarding_test.go | Unit tests for ladder ordering and summary/missing/complete semantics. |
| cmd/entire/cli/onboarding_rungs.go | Implements ground-truth probes for hooks/auth/mirror/import rungs (incl. bounded mirror probe). |
| cmd/entire/cli/onboarding_rungs_test.go | Unit tests for rung probe logic and state transitions. |
| cmd/entire/cli/onboarding_render.go | Shared renderer for checklist vs collapsed connected line (status + enable summary). |
| cmd/entire/cli/onboarding_render_test.go | Output-shape tests for mid-setup, complete collapse, and special states. |
| cmd/entire/cli/onboarding_offer.go | Offer-runner: single consent prompt, best-effort offers, deduped βrun laterβ hints. |
| cmd/entire/cli/onboarding_offer_test.go | Tests for runner modes (all/skip/step-by-step), non-interactive behavior, and hint dedupe. |
| cmd/entire/cli/onboarding_offer_actions.go | Implements the concrete login and mirror-create offers used by the runner. |
The mirror offer returns after placement (--no-wait), so the closing checklist's re-probe can still read "not mirrored" while the server-side clone finishes β right after a successful create, the user saw "β Repo mirrored" plus a retry hint. Track which offers succeeded this pass and render a succeeded-but-lagging rung as "created β sync in progress" instead of missing. Found by live smoke test (real mirror create through the consent prompt; status showed Connected a minute later). Co-Authored-By: Claude Fable 5 <noreply@anthropic.com> Entire-Checkpoint: cd777aacefa7
"Skip β local tracking only" overstated a consequence that doesn't exist: skipping just declines the offers this once. Tracking continues either way, checkpoints still push with plain git credentials, and on an already-mirrored repo a skipper's sessions appear in the web UI on their next push β no login required. New label points at the actual affordance: "Skip for now β finish anytime with `entire enable`". Co-Authored-By: Claude Fable 5 <noreply@anthropic.com> Entire-Checkpoint: 1b82d68bb8bb
"Set up everything" used to dead-end at 3/4 with a run-later hint, because the import rung deliberately had no offer (deferred to the richer enable-time offer in PR #1595). Live testing showed that dead-end undercuts the flow: enable walks you through login and then stops one step short of done. Wire a minimal import offer β same flow as `entire import <agent>` (checkpoint policy honored, redaction config loaded, agentimport.Run per discoverable agent) β so the ladder carries through to Connected in one pass. When #1595 lands, its offer (per-agent selection, first-run gating) replaces these internals. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com> Entire-Checkpoint: 11dc95701f15
- huh prompts use RunWithContext so command cancellation stops the consent
and per-rung confirm forms promptly (Cursor).
- Unknown rungs surface their hint in the row ("couldn't check β retry with
`entire repo mirror list`") β previously an offline probe left a bare "?"
with no footer and no run-later line (Cursor).
- The login offer writes to enable's output writer instead of os.Stdout
(Copilot).
- onboardingSetupSummary rebuilt with a plain builder and strings.ToUpper
instead of ASCII byte arithmetic (Copilot).
- Partial imports no longer overstate remaining work: when some turns are
already imported the detail switches to "<agent> history partially
imported (N turns pending)" instead of claiming every discovered session
is unimported (Copilot + trail finding).
- `entire status` hot-path cost (trail finding): ladder checks now run
concurrently (latency = slowest probe, not the sum), and the mirror probe
gets a 15-minute per-user cache with write-through on mirror create β the
steady state pays no network round-trip, and a mirror created via the
offer renders β immediately.
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Entire-Checkpoint: 1cd70ffad940
β¦ failures Two stale trail findings the earlier findings pass missed: - probeRepoMirrored asked only the active context's core, while the mirror offer creates on the default cluster's core (NewForCluster). When those front different federations, a successfully created mirror was invisible to the probe and the rung re-offered creation forever. The probe now asks both cores (deduped by CoreOrigin, so the common same-core case costs one call) and counts a mirror found on either. - Probe failures are now cached for 5 minutes (successes keep the 15-minute TTL), so an authed-but-offline terminal hangs on the probe once per window instead of on every `entire status`. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com> Entire-Checkpoint: 388476fe51e5
`entire status` paid full transcript I/O and parsing (checkpoint store open, ReadFile + SplitTurns per discovered file) on every invocation via the import rung's dry-run. Cache the scan result per repo behind an exact fingerprint β discovered files' (path, mtime, size) plus the local metadata-branch tip β so an unchanged repo pays only the cheap discovery glob. Invalidation is precise rather than TTL-based: appending to a transcript moves its mtime, and any new checkpoint or `entire import` moves the metadata ref, both recomputing immediately. Partial results (a failed per-agent run or a file vanishing mid-scan) are never memoized. Resolves trail finding 019f280f-fe4. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com> Entire-Checkpoint: ddfab02082dd
Correctness (the overclaiming-degradation cluster):
- A suspended mirror placement returns nil error from createAndAwaitMirror;
the offer now reports it like `repo mirror create` does, returns an error
so the rung keeps its retry hint, and skips the cache write-through that
claimed "mirrored" for the TTL (finalizeMirrorOffer, unit-tested).
- Import-scan failures no longer collapse into "no prior history found" or
a false Done: discovery errors poison the memo and count; all-agents-
failed returns an error so the rung renders Unknown with a retry hint.
- authRung distinguishes a keyring/token-store failure (Unknown + `entire
auth status`) from a genuinely empty token (Missing) β no more browser
logins offered against a broken keyring.
- mirrorRung maps origin-resolution failures to Unknown; only a non-GitHub
forge is NotApplicable ("no GitHub origin" was masquerading as fact).
- Explicit `entire enable` clears cached probe failures first β a transient
blip no longer suppresses the mirror offer for the failure TTL.
- offerable() gates Blocked rungs on an offerable blocker preceding them:
the consent prompt can no longer promise work that cannot run.
- `enable --agent` honors its documented non-interactive contract: the
ladder always runs with prompting suppressed there.
- patchSucceededOffers deleted: dead for mirror in production (the cache
write-through covers it) and it mislabeled auth/import failures as
"created β sync in progress".
Hardening and hygiene:
- setupModeSkip is now the mode enum's zero value (a forgotten mode must
never run login or mirror creation).
- Operational logging (logging.Warn/Debug) at every degrade-and-continue
point β discovery/dry-run/keyring/origin/prompt/offer failures now leave
a trace for doctor logs; no user content logged.
- Shared jsonFileCache shell with atomic tmp+rename writes replaces both
caches' hand-rolled non-atomic persistence.
- githubSlug() is the single encoding of the lowercase-slug invariant
(replaces the parseGitHubURL round-trip and inline ToLower calls).
- Dead Rung.Offer field removed; five rotted comments fixed (import-offer
enumeration, summary example, ground-truth qualifier, seam docs, #1595
prediction softened to a constraint).
- onboardingSetupSummary reuses formatTokenClassList.
- New tests: consent-cancel behaves like skip, step-by-step accept runs the
offer, blocked-gating, first-run and --agent call sites, suspended/empty
mirror outcomes, clearUnreachable.
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Entire-Checkpoint: 732b4eb2ebf3

What
entire enablecurrently ends at "hooks installed" and calls it success, leaving users with local checkpoints, an empty web UI, and no signal that login + mirroring even exist as steps. This PR turns onboarding into a converging setup ladder:entire enablefinishes with a single consent prompt β "Finish setup?" (set up everything / choose step by step / skip for now) β that walks login β mirror β history import for whatever is missing, then prints a checklist:entire statusrenders the same checklist from the same source (plus asetupobject in--json), collapsing to one quietConnected: <handle> Β· mirrored to <slug>line once done.Re-running
entire enableis the resume path: rung state is recomputed from ground truth (hooks on disk, stored login, control-plane mirror list, local transcript discovery), so an interrupted setup β or a rung completed out-of-band β is picked up exactly where it left off, with no progress state to corrupt. The previous hard short-circuit at "Entire is already enabled." now re-offers only the missing rungs.Design decisions
entire enable". Tracking continues either way; on an already-mirrored repo a skipper's sessions still reach the UI on their next push.--yes/ no TTY): never prompts, never creates a mirror implicitly; the checklist hints carry the follow-up commands.Relationship to #1595
The import rung ships with a minimal inline offer (same flow as
entire import <agent>: checkpoint policy honored, redaction config loaded,agentimport.Runper discoverable agent) β live testing showed that a ladder which dead-ends at 3/4 with a run-later hint undercuts the whole flow. When #1595 lands, its richer enable-time offer (per-agent selection, first-run gating) replaces the internals of this rung β the rung interface doesn't change, and the remaining overlap is a smallsetup.goconflict for whichever merges second.Tests & verification
mise run lintclean;mise run test:cifully green (unit + integration + e2e canary).entirehq/tmp-onboarding-smokeon aws-us-east-2), interrupted-setup resume, out-of-bandentire importreflected automatically, step-by-step declines honored, and the full one-pass ladder ending atConnected. The walkthrough caught and this PR fixes: the dead resume path on already-enabled repos, the falseβ Repo mirroredright after a successful create, and the misleading skip-option copy.π€ Generated with Claude Code