Skip to content

feat(onboarding): guided setup ladder β€” enable walks login/mirror/import, status shows the checklist, re-enable resumes#1618

Open
peyton-alt wants to merge 9 commits into
mainfrom
cli-onboard
Open

feat(onboarding): guided setup ladder β€” enable walks login/mirror/import, status shows the checklist, re-enable resumes#1618
peyton-alt wants to merge 9 commits into
mainfrom
cli-onboard

Conversation

@peyton-alt

@peyton-alt peyton-alt commented Jul 2, 2026

Copy link
Copy Markdown
Contributor

What

entire enable currently 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 enable finishes 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:

    Setup 1/3 complete
      βœ“ Agent hooks    Claude Code
      βœ— Logged in
      βœ— Repo mirrored  needs login
    β†’ Run `entire enable` to finish setup (2 steps left)
      run later: entire auth login
    
  • entire status renders the same checklist from the same source (plus a setup object in --json), collapsing to one quiet Connected: <handle> Β· mirrored to <slug> line once done.

  • Re-running entire enable is 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

  • One consent prompt, not a wizard: the happy path is one keypress + one browser tab. Step-by-step is opt-in for cautious users.
  • Best-effort offers: a failed login or mirror create prints a notice and a retry hint; enable never fails because of a connect rung.
  • Blocked β‰  missing: mirror without login renders as "needs login" instead of offering a command that would 401; run-later hints are deduped so the fix-command appears once.
  • Skipping isn't a mode: the skip option reads "Skip for now β€” finish anytime with entire enable". Tracking continues either way; on an already-mirrored repo a skipper's sessions still reach the UI on their next push.
  • Non-interactive contract (--yes / no TTY): never prompts, never creates a mirror implicitly; the checklist hints carry the follow-up commands.
  • Mirror probe is bounded (5s) and degrades to "unknown" offline; the auth check is deliberately offline (stored context, not token refresh). A mirror created this pass renders as "created β€” sync in progress" while the server-side clone finishes, instead of a false βœ—.

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.Run per 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 small setup.go conflict for whichever merges second.

Tests & verification

  • TDD throughout: unit tests for the ladder model, each rung, the renderer, the offer runner (mode/decline/best-effort/dedupe/sync-lag/import), status wiring, and the re-enable resume paths.
  • mise run lint clean; mise run test:ci fully green (unit + integration + e2e canary).
  • Live smoke-tested end-to-end, including: real browser OAuth through the consent prompt, a real mirror created via the flow (entirehq/tmp-onboarding-smoke on aws-us-east-2), interrupted-setup resume, out-of-band entire import reflected automatically, step-by-step declines honored, and the full one-pass ladder ending at Connected. The walkthrough caught and this PR fixes: the dead resume path on already-enabled repos, the false βœ— Repo mirrored right after a successful create, and the misleading skip-option copy.

πŸ€– Generated with Claude Code

peyton-alt and others added 2 commits July 3, 2026 00:05
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
Copilot AI review requested due to automatic review settings July 2, 2026 22:06
@peyton-alt peyton-alt requested a review from a team as a code owner July 2, 2026 22:06

@cursor cursor Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Cursor Bugbot has reviewed your changes and found 2 potential issues.

Fix All in Cursor

❌ 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.

Comment thread cmd/entire/cli/onboarding_offer.go
Comment thread cmd/entire/cli/onboarding_render.go

Copilot AI left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

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 onboarding model 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 enable to 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.

Comment thread cmd/entire/cli/onboarding_offer_actions.go
Comment thread cmd/entire/cli/onboarding_offer.go Outdated
Comment thread cmd/entire/cli/onboarding_rungs.go
peyton-alt and others added 7 commits July 3, 2026 11:30
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
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Development

Successfully merging this pull request may close these issues.

2 participants