Summary
There is no command to leave a centrally-managed fleet. hyp join has three side effects (central seed, daemon install, daemon-driven client attach/backfill), but no first-class inverse. Reversing a join today requires an error-prone manual sequence including raw rm of internal kernel state files.
hyp leave is already named in the design corpus as the host-level inverse of join — it was deliberately deferred ("when that lands"), not forgotten:
- LLP 0041 §Undo on leave: "
reverse(requestKey) runs when desired() no longer names a request key that the marker records as applied - i.e. the central config stopped naming the effect, or the machine left the fleet (hyp leave/detach, when that lands)."
- LLP 0044 references
hyp leave repeatedly (as the trigger that "clears the central layer" and restores client settings on leave).
This issue tracks promoting that deferred command into a real spec + implementation.
Current state: no coherent "leave" path
hyp join (src/core/cli/core_commands.js):
- Writes the central seed
~/.hyp/hypaware/config-control/seed.json (server URL + bootstrap token).
- Installs the daemon (LaunchAgent
com.hyperparam.hypaware).
- The daemon pulls central config, applies it, and the reconciler attaches clients (modifies
~/.claude/settings.json, codex config), backfills, starts sinks.
To reverse this today, an operator must run, in the right order:
hyp daemon stop
hyp daemon uninstall
hyp detach all
rm ~/.hyp/hypaware/config-control/seed.json
rm ~/.hyp/hypaware/config-control/config.a.json ~/.hyp/hypaware/config-control/config.b.json \
~/.hyp/hypaware/config-control/config.b.etag ~/.hyp/hypaware/config-control/active
This is undiscoverable, order-sensitive, and reaches into kernel-internal state files by hand.
Why this is a real gap, not just sugar
The reverse machinery already exists. The reconciler's reversible-handler path (src/core/config/action_reconciler.js:198-237) detaches clients automatically when desired() stops naming them, and crucially deletes the marker (delete markers[requestKey], line 212), keeping disk + markers coherent.
So hyp leave is mostly wiring an existing path:
- Drop the central layer (remove seed + applied central config slots).
desired() no longer names the attached clients.
- The reconciler's
reverse() detaches every client and clears its attach marker.
- Stop + uninstall the daemon (keep recordings/cache/logs, like
daemon uninstall).
Relationship to #217
#217 (manual hyp detach orphans a done attach marker, so a later join never re-attaches) is a symptom of the same root cause: there is no coherent on-the-way-out lifecycle operation, so users reverse piecemeal via detach + rm, outside the path that keeps markers and disk in sync. A hyp leave that routes through the reconciler reverse() would not hit #217 by construction. Consider #217 subsumed by this work (or fixed alongside it).
Proposed behavior (for the spec to refine)
hyp leave:
- Reverses all client attaches (via the reconciler
reverse() path, not ad-hoc disk edits) so client settings are restored and markers cleared.
- Removes the central layer (seed + applied central config) so the host no longer pulls central config or rejoins.
- Stops and uninstalls the daemon.
- Keeps local config (
hypaware-config.json), recordings, cache, and logs — same retention stance as daemon uninstall.
- Flags: likely
--dry-run and --json for parity with attach/detach; possibly --keep-daemon to leave the fleet but keep the daemon for local-only capture.
Open design questions
- Central notification: should leaving notify the central server, or is local leave silent? (Deferrable - the consent model in LLP 0044 treats leave as the user's prerogative.)
- Locked config:
leave acts on central-locked config locally; confirm that is consistent with the LLP 0044 consent footing (attach is consent-based and user-reversible).
- Partial leave vs full: is there a use for "leave the fleet but keep local capture running" (
--keep-daemon), or is leave always a full teardown?
Suggested process (per repo norms)
- Promote the deferred
hyp leave from LLP 0041 §Undo on leave / LLP 0044 into an actual spec or plan LLP; run /llp-grill against 0031 (layered config / central seed), 0041 (reconciler + undo on leave), and 0044 (attach-on-join consent).
- Implement, landing the LLP edit in the same commit as the code (
@ref annotations on the new command).
References
Summary
There is no command to leave a centrally-managed fleet.
hyp joinhas three side effects (central seed, daemon install, daemon-driven client attach/backfill), but no first-class inverse. Reversing a join today requires an error-prone manual sequence including rawrmof internal kernel state files.hyp leaveis already named in the design corpus as the host-level inverse ofjoin— it was deliberately deferred ("when that lands"), not forgotten:reverse(requestKey)runs whendesired()no longer names a request key that the marker records as applied - i.e. the central config stopped naming the effect, or the machine left the fleet (hyp leave/detach, when that lands)."hyp leaverepeatedly (as the trigger that "clears the central layer" and restores client settings on leave).This issue tracks promoting that deferred command into a real spec + implementation.
Current state: no coherent "leave" path
hyp join(src/core/cli/core_commands.js):~/.hyp/hypaware/config-control/seed.json(server URL + bootstrap token).com.hyperparam.hypaware).~/.claude/settings.json, codex config), backfills, starts sinks.To reverse this today, an operator must run, in the right order:
This is undiscoverable, order-sensitive, and reaches into kernel-internal state files by hand.
Why this is a real gap, not just sugar
The reverse machinery already exists. The reconciler's reversible-handler path (
src/core/config/action_reconciler.js:198-237) detaches clients automatically whendesired()stops naming them, and crucially deletes the marker (delete markers[requestKey], line 212), keeping disk + markers coherent.So
hyp leaveis mostly wiring an existing path:desired()no longer names the attached clients.reverse()detaches every client and clears its attach marker.daemon uninstall).Relationship to #217
#217 (manual
hyp detachorphans adoneattach marker, so a laterjoinnever re-attaches) is a symptom of the same root cause: there is no coherent on-the-way-out lifecycle operation, so users reverse piecemeal viadetach+rm, outside the path that keeps markers and disk in sync. Ahyp leavethat routes through the reconcilerreverse()would not hit #217 by construction. Consider #217 subsumed by this work (or fixed alongside it).Proposed behavior (for the spec to refine)
hyp leave:reverse()path, not ad-hoc disk edits) so client settings are restored and markers cleared.hypaware-config.json), recordings, cache, and logs — same retention stance asdaemon uninstall.--dry-runand--jsonfor parity withattach/detach; possibly--keep-daemonto leave the fleet but keep the daemon for local-only capture.Open design questions
leaveacts on central-locked config locally; confirm that is consistent with the LLP 0044 consent footing (attach is consent-based and user-reversible).--keep-daemon), or is leave always a full teardown?Suggested process (per repo norms)
hyp leavefrom LLP 0041 §Undo on leave / LLP 0044 into an actual spec or plan LLP; run/llp-grillagainst 0031 (layered config / central seed), 0041 (reconciler + undo on leave), and 0044 (attach-on-join consent).@refannotations on the new command).References
llp/0041-central-config-client-actions.design.md:247-254llp/0044-client-attach-on-join.decision.md(lines 20, 40, 110, 135-139)resetCentralLayerToSeedinapply.js)src/core/config/action_reconciler.js:198-237