feat(cli): aileron daemon start/stop/status + auto-spawn on every command#472
Merged
ALRubinger merged 2 commits intomainfrom May 6, 2026
Merged
feat(cli): aileron daemon start/stop/status + auto-spawn on every command#472ALRubinger merged 2 commits intomainfrom
ALRubinger merged 2 commits intomainfrom
Conversation
…mand
First user-visible piece of ADR-0012. CLI commands no longer require
a manually-started 'aileron serve' — bindingAPIBaseURL now resolves
the daemon URL via internal/daemon/spawn.Resolve, which auto-spawns
the daemon binary (sibling 'server') if none is running.
New subcommands:
- aileron daemon start fork-execs the daemon (idempotent)
- aileron daemon stop SIGTERMs by PID from daemon.json, waits for
discovery cleanup; cleans up stale daemon.json
if PID is gone
- aileron daemon status prints URL/PID/version/started_at + locked
or unlocked vault state if reachable
- aileron stop alias for daemon stop, per the ADR
Wiring:
- AILERON_API_URL still bypasses spawn (test/dev escape hatch); read
on every call so tests can flip behavior.
- spawn.Resolve result cached for the CLI process lifetime; repeat
calls don't reprobe.
- Daemon binary resolves via os.Executable + sibling lookup, falling
back to PATH ('server').
- Spawn failure logs to stderr and falls back to localhost:8721 so
the user sees the familiar 'connection refused' rather than a
malformed URL.
Refs #454.
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
|
🚅 Deployed to the aileron-pr-472 environment in aileron 1 service not affected by this PR
|
Codecov Report❌ Patch coverage is ❌ Your patch check has failed because the patch coverage (73.28%) is below the target coverage (80.00%). You can increase the patch coverage or adjust the target coverage. Additional details and impacted files@@ Coverage Diff @@
## main #472 +/- ##
==========================================
+ Coverage 8.45% 82.22% +73.77%
==========================================
Files 212 234 +22
Lines 20357 24079 +3722
==========================================
+ Hits 1721 19799 +18078
+ Misses 18456 3144 -15312
- Partials 180 1136 +956
Flags with carried forward coverage won't be shown. Click here to find out more. 🚀 New features to boost your workflow:
|
…okup Lifts patch coverage on the Step 7 changes from ~52% to ~86%: - spawnResolveFn package var becomes the test seam — runDaemonStart and spawnResolveCached both route through it so tests can substitute spawn.Resolve without fork-execing a real daemon binary. - spawnResolveCached factored into spawnResolveOnce (the body, fully testable) and a thin sync.Once wrapper. - New tests: runDaemonStart happy path, spawn-error propagation, binary-not-found; spawnResolveOnce happy path, trailing-slash trim, binary-missing error, spawn-error propagation; daemonBinaryPath sibling and PATH branches; defaultStateDir under HOME. - runDaemonStop happy path (SIGTERM a real daemon and poll for cleanup) is intentionally not faked here — shell traps are flaky across platforms and a Go subprocess helper added go-build-in-test brittleness. Acceptance Test 8 in #454 is the canonical proof. Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
14 tasks
This was referenced May 6, 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.
Summary
Step 7 of #454. First user-visible piece of ADR-0012. CLI commands no longer require a manually-started
aileron serve—bindingAPIBaseURLnow resolves the daemon URL viaspawn.Resolve(#469), which auto-spawns the daemon binary (siblingserver) if none is running.This collapses the historical
(forgot to start serve) → (connection refused) → (oh right, run serve in another terminal)loop into a single command: `aileron ` Just Works.New subcommands
aileron daemon start— fork-execs the daemon. Idempotent: if one is already running, prints its URL and exits 0.aileron daemon stop— readsdaemon.pid, sends SIGTERM, waits fordaemon.jsonto be removed (signalling clean shutdown). Cleans up staledaemon.jsonif PID is gone.aileron daemon status— prints URL / PID / version / started_at and alocked/unlockedvault summary (probes/v1/vault/local/status).aileron stop— alias foraileron daemon stop, per the ADR.Wiring
AILERON_API_URLstill bypasses spawn (test/dev escape hatch). Read on every call so tests can flip behavior mid-process without resetting cache.spawn.Resolveresult is cached for the CLI process lifetime; repeat callers (e.g.runStatuscallsbindingAPIBaseURLtwice) don't reprobe.os.Executable()+ sibling lookup (server), falling back to PATH lookup.localhost:8721so the user sees the familiar "connection refused" rather than a malformed URL.Test plan
go test ./cmd/aileron/... -raceis green.go vet ./cmd/aileron/...is clean.runDaemon90%,runDaemonStatus83.3%,probeLocalVaultLocked90.9%,bindingAPIBaseURL85.7%,spawnResolveCached47.4%,daemonBinaryPath71.4%.t.Setenv("AILERON_API_URL", ...)to point at httptest servers, and the env-override path is hit on every call so the cache doesn't interfere.runDaemonStart, the SIGTERM happy-path ofrunDaemonStop) are 0% / 46% covered locally — the umbrella issue's Test 1, 2, 4, 8 are the canonical proof.Notes
server(build artifact atbuild/server). Renaming toaileron-daemonis deferred per the plan's mechanical-PR followup.AILERON_VAULT_PASSPHRASE/--passphrase-filefor non-TTY unlock — not in this PR. The vault unlock surface is still the daemon's/v1/vault/local/unlockendpoint (webapp modal). The env / flag for headless contexts is a follow-up if real usage shows it's needed.aileron daemon startandaileron stopare intentionally not routed throughbindingAPIBaseURL— they manage the daemon's lifecycle and shouldn't auto-spawn at the wrong moment.🤖 Generated with Claude Code