Imported from marmot-protocol/mdk (
crates/agent-connector/AGENTS.md). Install upstream withnpx skills add marmot-protocol/mdk --skill agent-connector. Copyright stays with the author.
AGENTS.md - agent-connector
Local Marmot agent connector daemon; ships the wn-agent binary.
Scope
- Own
serve_socket/AgentConnectorand thewn-agentUnix-socket daemon that bridges theagent-controlprotocol andagent-stream-composepreviews toMarmotApp/MarmotAppRuntime. - Own
wn-agent bootstrap, which creates or reuses a local agent account through the running control socket and prints phone invite details (npub,nprofile, optional terminal QR). - Own connector socket binding and permission hardening (
bind_connector_socket,default_socket_path). - Keep agent-facing wire types in
agent-controland stream composition inagent-stream-compose; this crate is the process glue, not the protocol or composition owner. - Publisher routing and TLS trust use
marmot-apphost-safety validation.allow_insecure_local_brokerremains an explicit dev-only opt-in.
Key files
The AgentConnector inherent impl is split across thematic sibling modules (Rust allows one inherent impl to span
several files in the same crate); methods shared across those files are pub(crate).
src/lib.rs—serve_socket,AgentConnectorConfig, theAgentConnectorstruct, and its core lifecycleimpl(open,serve_once,start, agent-account readiness,configured_relay_endpoints). Crate-internal constants live here aspub(crate).src/connection.rs—AgentConnector::handle_connection, peer authorization, theerror_responseprojection, and theAgentControlRequest→ handler dispatch.src/account.rs— account list/create, profile publishing,local_account_for_account_id, and welcomer-allowlist list/add/remove handlers.src/messaging.rs— final-message sends, agent activity/operation/group-system event handlers, and debug send recording/inject helpers.src/stream.rs— QUIC text-stream preview session lifecycle (begin/append/status/progress/finalize/cancel) and the idle-session sweeper.src/inbound.rs—SubscribeInbounddrain loop and storage-backedreplay_missed_inboundrecovery after broadcast lag.src/invite_policy.rs— background reconciliation of pending group invites against the welcomer allowlist (worker spawn, reconcile, candidate enumeration, apply). Event- and retry-driven:GroupJoinedevents apply immediately, per-candidate retries wake on their own backoff, and full enumeration is an adaptive safety net (baseINVITE_POLICY_RECONCILE_INTERVAL, doubling toINVITE_POLICY_RECONCILE_MAX_INTERVALwhile passes find nothing) over the targetedMarmotApp::pending_group_invitesread — never a fullapp.groups()projection load (mdk#1380). Enumeration failures back off on a separate failure floor so a failing store cannot spin the worker even with a matured retry pending.src/reconcile_telemetry.rs— privacy-safe aggregate counters for the background reconciliation loops (ReconcileTelemetryon the connector: passes, outcomes, accounts/candidate rows considered) plus theReconcileSourcelabel used on per-pass tracing events (mdk#1380). Current catch-up/replay state is exposed throughdiagnostic_replay().src/diagnostics.rs— identifier-freediagnostic_statushandler (account selection, KeyPackage aggregates, relay/replay/home observations) using no-start runtime reads.src/error.rs—ConnectorErrorand itscode/client_message/retryable/privacy_safe_codeprojections.src/socket.rs— socket path/bind/hardening (default_socket_path,bind_connector_socket*, stale-socket recovery).src/allowlist.rs—AllowlistStore/AllowlistRecordper-account invite-policy and welcomer-allowlist persistence.src/stream_session.rs—StreamSessionStore/ActiveStreamSession, the shared runtime publisher handles, and persistedSendIdempotencyStore($MARMOT_HOME/dev/send-idempotency.json, 1024-entry FIFO, versioned SHA-256 request fingerprints,stream_finalize_v2:/stream_finish_v1:keys for durable finalized sends, crash-safe atomic writes, plus bounded same-key/same-fingerprint in-flight gates whose followers reuse a leader's successful result or receivesend_in_progresswhen the gate wait expires), and theDebugFinalSendStorerecorder.src/media_temp.rs— TTL sweep of decrypted inbound media temp dirs under$TMPDIR/marmot-media/.src/event_projection.rs— runtime/debug event → control event projection, theDeliveredInboundCursor, and theInboundCatchUpDriver. The driver's scheduled passes are an adaptive safety net (baseINBOUND_CATCH_UP_BASE_INTERVAL, doubling toINBOUND_CATCH_UP_MAX_INTERVALwhile the runtime is quiet): steady-state delivery is push-driven by each account worker, so qualifying runtime activity (anything butAccountError, which a failing pass could self-emit) resets the net and wakes a backed-off pass, never faster than the base cadence (mdk#1380). Subscription initial catch-ups stay prompt out-of-band requests.src/validation.rs— control-plane/profile/hex validation helpers and the invite-policy retry-state holders.src/bootstrap.rs—wn-agent bootstrapflow.src/bin/wn-agent.rs— thewn-agentbinary entrypoint and clap CLI surface (ServeArgs, thebootstrapsubcommand andBootstrapArgs, octal socket-mode parsing, and terminal-QR rendering).src/tests.rs— white-box test suite exercising the abovepub(crate)internals.
Verification
Before pushing connector changes, run the repo-wide pre-push gate plus this crate's tests:
just fast-ci
cargo test -p agent-connector
GitHub CI runs the full just ci workspace suite.