Skip to content

feat: default cc-peer front (slot identity, yield, dedup) - #171

Merged
Mearman merged 11 commits into
mainfrom
feat/ccpeer-front
Sep 17, 2026
Merged

Mearman merged 11 commits into
mainfrom
feat/ccpeer-front

Conversation

@Mearman

@Mearman Mearman commented Sep 17, 2026

Copy link
Copy Markdown
Member

Closes #157

Implements the default coordinator-run cc-peer front: the machine's coordinator bridge fronts local Claude Code sessions that don't already have their own live agent-comms bridge, using the same (harness, cwd) identity slot that session's own bridge would use, so addressing carries over unchanged the moment that session's own bridge appears.

Work in progress; pushing early per the stacked-PR convention. Will flip to ready once the full slice lands and CI is green.

Building on top of cc-peer's session-enumeration support (ExaDev/cc-peer#40), already available in the installed version -- no cc-peer version bump needed.

Reply-alias wiring via cc-peer's AliasPool is out of scope here (#158, blocked on this PR); this PR's design is checked not to foreclose it -- the shared front-wide CcPeer instance and per-session mesh identity are exactly what #158's reply routing will sit on top of.

probeSlotOwner reads a slot's lock file without writing to it, and loadIdentityForFront loads or creates the slot's persisted identity without taking the exclusivity lock. Together these let a caller assume a not-yet-live (harness, cwd) slot's future identity while leaving the lock free for that slot's real owner to acquire normally later.
…ests

Wraps probeSlotOwner's own parameter list and a multi-line assertion in the identity-store test suite onto prettier's expected line breaks.
createBridgeMeshSyncFromIdentity and createBridgeMeshFromIdentity build a mesh from an already-loaded identity, letting createBridgeMeshSync/createBridgeMesh keep owning loadOrCreateIdentity's lock while the cc-peer front (agent-comms#157) builds a mesh identity from loadIdentityForFront's lock-free one instead. Also exports the identity-store slot helpers from core/index.ts so bridge code outside core/ can reach them the same way it already reaches everything else in this factory.
…r the default front

selectSessionsToFront filters a cc-peer roster down to the real Claude Code sessions the front should attach to: excludes other cc-peer-library peers (identified by cc-peer's own literal "cc-peer" version marker) and any session whose own identity slot is already held by a live bridge. matchInboundMessageSession attributes an inbound cc-peer message to the fronted session it came from, by matching the envelope's uds:<socketPath> convention against each fronted session's own messagingSocketPath.

Kept free of any real cc-peer/MeshStore construction so the decision logic is testable purely over data; front-runtime.ts (agent-comms#157, still to come) builds the real stateful controller on top of these functions.
Fires true right after this store becomes coordinator (a fresh bind in init(), or a takeover via PeerLifecycle.handleBecomeCoordinator) and false right before shutdown() drops the role, mirroring the existing onDelivery/onPatch/onError callback fields. Gives bridge-mesh.ts a place to start and stop a coordinator-only, Node/filesystem-specific capability -- the cc-peer front (agent-comms#157) -- without pulling that concern into this transport-agnostic core.
CcPeerFront polls the injected roster on a fixed interval, attaching newly-selected sessions and detaching ones that exited or yielded (their own slot got claimed by a live bridge), diffing against what's already fronted so nothing is re-attached or double-torn-down across ticks. stop() detaches every still-fronted session, since a side that just lost the coordinator role has no business relaying on any session's behalf anymore. Mirrors StaleAgentChecker's own coordinator-only periodic-probe shape and stays free of any real cc-peer/MeshStore construction, matching front.ts's own testability discipline.
buildFrontedSessionRecord wires both relay directions for a single fronted session against its already-constructed mesh store/tool and the front's shared cc-peer peer: mesh-to-session sends a formatted delivery to the session's own pid, session-to-mesh posts an inbound cc-peer message into the session's own project room. detachFrontedSession marks the agent offline before shutting its store down.

Mirrors bridges/cc-peer/bridge.ts's own wireCcPeerBridge split -- kept free of any real CcPeer.create()/createBridgeMeshFromIdentity construction so it's testable against fakes, with front-runtime.ts (still to come) supplying the real ones.
…uction

createDefaultCcPeerFront builds the real CcPeerFront: a shared, lazily-created CcPeer instance (created on the first poll tick that actually needs it, not at start()), and an attach function that loads a not-yet-fronted session's identity via loadIdentityForFront, builds its mesh via createBridgeMeshFromIdentity, registers and rooms it, then wires the relay via buildFrontedSessionRecord. A construction or attach failure reports through onError rather than throwing, so a machine with no local Claude Code sessions -- or one where cc-peer itself can't bind -- degrades to a clean no-op front instead of crashing the coordinator that owns it.

Widens CcPeerRosterEntryLike.name and CcPeerFrontDeps.pollIntervalMs/onError to explicit `| undefined` so they type-check against cc-peer's own RegistryEntry and an options object's optional fields under this repo's exactOptionalPropertyTypes.

Untested directly, matching run.ts's own established precedent for real CcPeer.create() construction -- front.ts, front-controller.ts, and front-relay.ts already carry the front's entire decision/diffing/relay logic under direct DI-based unit tests.
…fault front

wireDefaultCcPeerFront builds the callback a real bridge assigns to its own store.onCoordinatorRoleChanged: starts the front the moment that store becomes this machine's mesh coordinator, stops it the moment it loses that role. This is the piece that actually makes "a machine's coordinator bridge fronts local Claude Code sessions by default" true, rather than a capability every bridge builds but nothing switches on -- the real bridge entry points wire it next.

Kept the only file outside bridges/cc-peer/ that needs to know cc-peer exists, matching this repo's own portable-runtime-boundary convention: core/mesh-store.ts's hook is a bare boolean callback, and core/bridge-mesh.ts's factories stay cc-peer-agnostic.
…entry point

Every bridge entry point (pi, claude-code, mcp, codex, opencode, user, cc-peer's own one-shot command) now assigns store.onCoordinatorRoleChanged = wireDefaultCcPeerFront(store) right after constructing its own mesh, before init() ever runs. This is what actually makes "a machine's coordinator bridge fronts local Claude Code sessions by default" true for a real deployment, rather than leaving the front's own machinery built but never switched on -- whichever bridge type happens to win this machine's coordinator election starts fronting, and stops the moment it loses that role.

user/controller.ts's fromExisting() path (wrapping an already-built store shared with a UI, e.g. pi's own web server) deliberately does not re-wire this -- the store's owning bridge already did, and wiring it twice would silently orphan the first front instance without ever starting it.
Adds a subsection alongside the existing cc-peer (cross-machine Claude Code relay) docs explaining the coordinator-run default front: identity belongs to the (harness, cwd) slot rather than whichever process currently serves it, no configuration is needed, and an empty local roster degrades to a clean no-op.
@Mearman
Mearman marked this pull request as ready for review September 17, 2026 16:57
@chatgpt-codex-connector

chatgpt-codex-connector Bot commented Sep 17, 2026

Copy link
Copy Markdown

Codex Review Summary

This comment shows the latest Codex review activity on this pull request.

Review Status Commit Review trigger
🔒 Security Review Completed 2026-09-17T17:08:02.736381Z 7b44592 Draft marked ready
ℹ️ About Codex in GitHub

Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you

  • Open a pull request for review
  • Mark a draft as ready
  • Comment "@codex review" or "@codex security review".

Codex reacts with 👀 while any review is running, comments if it has suggestions, and reacts with 👍 once all reviews finish with no findings.

@Mearman
Mearman merged commit 71c1d5c into main Sep 17, 2026
6 checks passed
@Mearman
Mearman deleted the feat/ccpeer-front branch September 17, 2026 16:57
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

Default cc-peer front: slot identity, yield, dedup

1 participant