fix(pilotctl): default beacon to the production address, honor PILOT_BEACON#419
Merged
Merged
Conversation
…BEACON
Symptom: the documented bootstrap flow
pilotctl init --hostname my-agent
pilotctl daemon start
writes a dead beacon (127.0.0.1:9001) into ~/.pilot/config.json while
writing the production registry (34.71.57.205:9000) into the same file.
A node bootstrapped this way registers fine but cannot traverse NAT —
its beacon points at localhost where nothing is listening.
Three code locations conspired:
1. cmdInit: beaconAddr := flagString(flags, "beacon", "127.0.0.1:9001")
— localhost fallback, inconsistent with the registry default in the
same function ("34.71.57.205:9000").
2. buildDaemonArgs: when config lacked a beacon it injected
"127.0.0.1:9001", and it never consulted PILOT_BEACON — while the
registry path in the same function resolves flag > config > env >
hardcoded default (via getRegistry).
3. cmd/daemon's own default IS the production beacon
("34.71.57.205:9001", with $PILOT_BEACON support), but pilotctl
always passes an explicit --beacon, so the daemon's correct default
was unreachable through the documented start path. pilotctl's own
`daemon start --help` already documents "--beacon <addr> beacon
address (default: $PILOT_BEACON or 34.71.57.205:9001)" — this change
makes the code match its shipped help.
Fix: both pilotctl fallbacks now use 34.71.57.205:9001, and beacon
resolution gains a getBeacon() helper mirroring getRegistry() exactly,
closing the env-precedence gap (flag > config > PILOT_BEACON > default).
Blast radius:
- Every 127.0.0.1:9001 in tests is a local test *registry* listen
address (registry.New / NewWithStore) or an explicit SetBeaconAddr —
none depends on the removed pilotctl fallback.
- Installer users are unaffected: both install.sh in this repo and the
one in pilot-protocol/release write an explicit "beacon" key into
config.json and pass -beacon in the service units.
- Local-dev beacons still work via --beacon, the config key, or (new)
PILOT_BEACON — the same three escape hatches the registry has.
Verified: gofmt clean; go build ./cmd/... ok; go test ./cmd/pilotctl ok.
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_0142ryqVGEmJN66VZtCC7wFD
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.
Symptom
The documented bootstrap flow:
writes a dead beacon (
127.0.0.1:9001) into~/.pilot/config.jsonwhile writing the production registry (34.71.57.205:9000) into the same file. A node bootstrapped this way registers fine but cannot traverse NAT — its beacon points at localhost where nothing is listening.The three code locations (all verified on current
main)cmdInit(cmd/pilotctl/main.go:2014):Registry defaults to production; beacon defaults to localhost — and gets persisted to config.json, poisoning every later
daemon start.buildDaemonArgs(cmd/pilotctl/main.go:2645-2652): when config lacks a beacon it injected"127.0.0.1:9001", and it never consultedPILOT_BEACON— while the registry path a few lines above resolves flag > config > env > hardcoded default (the else branch callsgetRegistry(), which checks$PILOT_REGISTRY). The beacon had no env leg at all.The daemon binary's own default IS the production beacon (
cmd/daemon/main.go:53-58:beaconDefault := "34.71.57.205:9001", with$PILOT_BEACONsupport) — butbuildDaemonArgsalways passes an explicit--beacon, so the daemon's correct default is unreachable through the documented start path.Notably, pilotctl's own shipped help already documents the intended behavior —
daemon start --helpsays--beacon <addr> beacon address (default: $PILOT_BEACON or 34.71.57.205:9001)andconfig --helpsaysbeacon beacon address (overrides $PILOT_BEACON). This change makes the code match its own help.Fix (minimal, 19 lines)
cmdInitbeacon fallback:127.0.0.1:9001→34.71.57.205:9001(mirroring the registry default one line above).getBeacon()helper mirroringgetRegistry()line for line (env → config → production default), andbuildDaemonArgs's else branch now calls it — giving beacon the exact same precedence the registry has: flag > config >PILOT_BEACON> hardcoded production default.The new default matches both the daemon binary's own compiled default (
cmd/daemon/main.go:53) and the address the pilot-protocol/release installer uses (PILOT_BEACON:-34.71.57.205:9001).Blast-radius analysis
127.0.0.1:9001/9001(including tests): every127.0.0.1:9001hit outside the two changed lines is a local test registry listen address (registry.New("127.0.0.1:9001")/NewWithStore(...)intests/zz_*_test.go) or an explicitSetBeaconAddr/beacon-selection fixture inpkg/daemontests — none reachescmdInit/buildDaemonArgsfallbacks. Thecmd/pilotctllifecycle tests (zz_lifecycle_test.go,zz_commands_test.go) exercise beacon via explicit--beaconflags or config values (b.x:9001,cfg.example:9001) and never assert the old fallback.TestBuildDaemonArgsDefaultsonly asserts that a--beaconflag is present, not its value.install.shin this repo (writes"beacon": "${BEACON}"with defaultregistry.pilotprotocol.network:9001into config.json and passes-beaconin the launchd/systemd units) andinstall.shin pilot-protocol/release (default34.71.57.205:9001, same explicit-write pattern) always persist an explicit beacon, so the fallback never fires for them.--beacon 127.0.0.1:9001,pilotctl config --set beacon=..., or (new, previously missing)PILOT_BEACON.Verification
Built locally with Go 1.26.3:
gofmt -lclean,go build ./cmd/...succeeds,go test ./cmd/pilotctlpasses (13.1s, ok).🤖 Generated with Claude Code
https://claude.ai/code/session_0142ryqVGEmJN66VZtCC7wFD