feat(cli): first-run install UX — post-install smoke test + connect panel - #272
Merged
Conversation
…anel install-service now polls until the daemon is actually responsive (a real smoke test, not a guess), then prints a connect panel: dashboard URL (from the pid file's actual bound port — a default install is :3000, make prod forces :3100), the auth token (from $configDir/token), and a click-to-auth link. A --open flag opens the dashboard in a browser, no-opping on headless boxes and in CI; install.sh passes it on an interactive terminal (opt out AUTONOMOS_NO_OPEN=1). On a verify timeout install-service returns exit 3 (activated-but-unresponsive) so a piped curl install reports the failure instead of printing a success banner over a down daemon. ADR-052. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01S7yopZT2FmLCSboCAMAXxb
aterrylu
enabled auto-merge (squash)
June 29, 2026 08:15
nox-0x
reviewed
Jun 29, 2026
nox-0x
approved these changes
Jun 29, 2026
nox-0x
left a comment
Collaborator
There was a problem hiding this comment.
Approving — the post-install smoke-test + connect panel is a clean win, the pid-file-as-source-of-truth choice keeps the URL correct across :3000/:3100/OS-assigned ports, and the --open headless/CI guards are right.
Verified:
migrate-from-pm2forwards itsargvintorunInstallServiceCommand, so the--openflag frominstall.shsurvives the pm2 migration path (packages/cli/src/commands/migrate-from-pm2.ts:38).install.sh'sRC=$?plumbing surfaces the new exit-code 3 ("activated but daemon not responsive") honestly instead of papering it over.openBrowseris properly detached/unref'd with anerrorhandler, so a missingxdg-opencan't fail the install.readToken()'s fallback ordering matchesresolveAuthToken()(per-config-dir → legacy~/.autonomos/token), so the panel agrees with what the daemon will actually accept.
One non-blocking 🟡 inline: the new test only isolates AUTONOMOS_CONFIG_DIR, not HOME, so the legacy ~/.autonomos/token fallback can read the developer's real prod token in the "no token file" case — passes on CI, can fail locally for anyone who has autonomOS installed. Fixable in a follow-up by also pinning process.env.HOME = TEST_DIR.
…lback Addresses review (nox-0x): the test only overrode AUTONOMOS_CONFIG_DIR, not HOME, so readToken()'s legacy $HOME/.autonomos/token fallback would read (and leak) the maintainer's real token on a machine with autonomOS installed — green on CI, broken locally. Pin HOME=TEST_DIR and add a hermetic test that exercises the fallback branch. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01S7yopZT2FmLCSboCAMAXxb
This was referenced Jun 29, 2026
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.
Problem
PR1 (#271, ADR-050) moved supervision to launchd/systemd-user, but
install-servicestill ended with an un-verified line — "daemon should be running shortly" — and never told the user where to reach the dashboard. A first-timecurl install.sh | shuser got a binary and a service file, but no confirmation it worked and no URL/token. That's the exact onboarding friction this initiative set out to remove (the deferred "Tier-1 install UX").Solution (ADR-052)
A shared post-install verifier that turns a silent install into a confirmed one.
graph TD subgraph OLD["❌ before"] A1["install-service loads the unit"] --> A2["print: 'should be running shortly'"] A2 --> A3["exit 0 — no verification, no URL, no token"] A3 --> A4["user: is it up? what's the URL? 🤷"] end subgraph NEW["✅ after"] B1["install-service loads the unit"] --> B2["poll pid-file until daemon responds<br/>(real smoke test, ~12s budget)"] B2 -->|"responsive"| B3["connect panel:<br/>URL (actual bound port) · token · auth link"] B3 --> B4["--open → browser (no-op on headless / CI)"] B4 --> B5["exit 0"] B2 -->|"timeout"| B6["⚠️ warn: check autonomos logs"] B6 --> B7["exit 3 — curl install reports failure,<br/>no false success banner"] end OLD ==> NEWWhat changed
packages/cli/src/lib/post-install.ts(new) —verifyAndReportInstall()polls until the daemon is actually responsive (pid file present + pid alive + port answers/api/system/version), then prints the connect panel. Reads the actual bound port from the pid file (a default install binds:3000; onlymake prodforces:3100) and the token from$configDir/token(with the same~/.autonomos/tokenlegacy fallback the server uses). Never throws.install-service.ts— calls the verifier after activation (both platforms) behind a new--openflag. Returns exit 3 (activated-but-unresponsive) on timeout so the failure is honest.install.sh— passes--openon an interactive terminal ([ -t 1 ], opt outAUTONOMOS_NO_OPEN=1), and branches its closing message on the exit code — "installed and running" (URL/token shown above) vs. "installed but not responding — checkautonomos logs" (and exits non-zero). Previously a piped install printed a success banner even over a down daemon.Why the exit-code matters (review catch)
The silent-failure review found that with the verifier returning⚠️ not responsive" immediately followed by "✓ installed / URL shown above" — a contradictory success banner over a dead daemon.
void, acurl install.sh(which hasset -eand no smoke gate of its own) would print "make prodwas safe (itsinstall-prod-service.shhas a hard smoke gate), but the curl path wasn't. Fixed by the boolean return → exit 3 → install.sh branch.Testing
false+ warns, doesn't throw). Fullmake checkgreen — server/cli + 227 dashboard tests.:3100): realinstall-servicepolled the daemon up and printed the correct URL + real on-disk token + click-to-auth link; clean launchd teardown.Notes
install-service.ts— a different region than the concurrent ElectronCleanup PR's Desktop-detection removal (low conflict; later merger rebases).export PATH=…to the user's shell rc — editing an rc from a pipedcurl | shis an invasive footgun; the existing PATH hint stays.docs/DECISIONS.md(051 reserved for ElectronCleanup per the later-merger convention).🤖 Generated with Claude Code