Skip to main content

Module registry

Module registry 

Source
Expand description

File-based cross-instance agent registry.

Each AgentMux instance writes agent registrations to {data_dir}/agents/{agent_id}.json. When a local inject fails with “agent not found”, the inject handler looks up this registry and HTTP-forwards the request to the owning instance.

Lifecycle:

  • Register: write file (on HTTP register endpoint + shell auto-register)
  • Unregister: delete file (on HTTP unregister endpoint + process exit)
  • Cleanup: TTL-based removal of stale files at startup

Structs§

AgentEntry
One entry per registered agent in the shared data dir.

Constants§

FORWARD_FAILURE_GRACE_MS 🔒
Grace period during which a forward failure against a live-process entry is presumed transient rather than proof the specific agent is gone — see should_evict_on_forward_failure. pub(crate) so muxspect_handlers’s verify-sender route can reuse the same real, already-tested staleness judgment for shared-registry entries instead of inventing its own threshold (see that module’s own doc comment for why).

Statics§

JEKT_PUBLIC_KEY_RESOLVER 🔒
LOCAL_AUTH_KEY 🔒
Process-wide auth key for the local AgentMux instance.
REGISTRY_OP_LOCK 🔒
Serializes this process’s own read-compare-remove sequences (remove_if_nonce / remove_shared_if_nonce) against its own writes. Both the racing writer (a fallback respawn’s re-registration) and the racing remover (the dying spawn’s exit-handler) live in this same agentmux-srv process — each per-agent registry file has exactly one writing instance — so a process-local mutex is sufficient to make the compare-and-remove atomic; no file locking needed. Plain removes/writes for other controller types don’t need the guard but take it anyway for uniformity (it’s uncontended).
UID_KEY_RESOLVER 🔒

Functions§

agent_path 🔒
agents_dir 🔒
cleanup_stale
Remove stale entries at startup.
cleanup_stale_shared
Startup sweep over the host-global registry: remove any entry whose updated_at is past max_age_ms OR whose pid is no longer alive on this host (§4.4) — the dead-Agent3 case from the spec’s problem statement, where per-channel TTL cleanup never reached an entry belonging to a channel that hadn’t restarted.
init_jekt_public_key_resolver
Install the process’s agent-public-key resolver. Idempotent — first call wins, same contract as init_local_auth_key.
init_local_auth_key
Initialise the process’s local auth key. Idempotent — first call wins.
init_uid_key_resolver
Install the process’s block → (UID, UID public key) resolver. First call wins. Until it is called, entries are written without a UID.
jekt_public_key_for 🔒
The agent’s published public key, or empty if unavailable.
list_all_shared
List every entry currently in the host-global shared registry, across every agent name and channel. Used by the /agentmux/discovery endpoint to populate host.cross_channel[] (§4.5 of the cross-channel delivery spec) — unlike lookup_all_shared, which targets one known agent name, this enumerates the whole directory.
local_auth_key 🔒
local_channel_id
This process’s own channel id — AGENTMUX_CHANNEL, default "stable".
local_host_label
This machine’s host label — the hostname half of an agent’s WAN instance identity, paired with local_channel_id to identify which AgentMux instance under an account owns a given agent’s WAN keypair.
lookup
Look up an agent entry. Returns None if not found or file is malformed.
lookup_all_shared
Return every live candidate for agent_id across all channels, freshest-first (§4.3: Tier 2b prefers the freshest candidate). Does NOT filter by staleness/pid-liveness — callers needing that should use cleanup_stale_shared (startup sweep) plus the existing evict-on-forward-failure pattern already used by Tier 2a/3 in server/reactive.rs, matching how this codebase already handles registry staleness elsewhere rather than re-validating on every read.
lookup_shared_by_uid
Every channel’s shared entry that published a key for uid (identity M4d-6). Scans the whole registry: entries are filed by name, and one UID live in several channels has an entry, and a key, in each.
pid_alive 🔒
True if a process with this PID is currently running on this host. Meaningful here specifically because the shared registry is always same-host by construction (a local file only readable by local processes) — unlike a LAN/cloud registry, PID-liveness is an authoritative staleness signal, not just a heuristic.
read_entry_file 🔒
Best-effort read of one (agent, channel) entry file. Missing, unreadable, or malformed files are treated as absent — same graceful-degradation posture as the per-channel lookup.
read_entry_files_in_dir 🔒
Read every valid .json entry file directly inside dir (one level, not recursive) — used for both lookup_all_shared (one agent’s per-channel dir) and list_all_shared (one agent-name dir at a time).
remove
Remove an agent entry from the shared registry.
remove_if_nonce
Remove an agent entry only if it was written by the spawn with expected_nonce — compare-and-remove for persistent-controller exit-handlers (issue #2363; nonce is process-wide unique, so the guard holds across controller replacement too — codex P1 on PR #2500). An entry with no recorded nonce (0) is never removed by this variant: leaving a stale file to the TTL sweep (cleanup_stale) is strictly safer than deleting a live registration. Atomic w.r.t. this process’s own writes via REGISTRY_OP_LOCK.
remove_shared
Remove this channel’s entry for agent_id from the shared registry. Best-effort removes the now-possibly-empty agent directory too (a concurrent writer recreating it a moment later is harmless — the next write just re-creates the directory via create_dir_all).
remove_shared_from_env
Convenience wrapper over remove_shared — see write_shared_from_env.
remove_shared_from_env_if_nonce
Convenience wrapper over remove_shared_if_nonce — see write_shared_from_env.
remove_shared_if_nonce
remove_shared only if this channel’s entry was written by the spawn with expected_nonce — see remove_if_nonce (issue #2363). Cross-channel note: only this channel’s own file is read and removed, matching write_shared’s single-writer contract, so the process-local REGISTRY_OP_LOCK still suffices.
sanitize_path_component 🔒
Lowercase + sanitize a single path component (agent name or channel id) to alphanumeric/dash/underscore only, preventing path traversal and matching ReactiveHandler’s lowercase key convention.
shared_agent_dir 🔒
Directory holding one file per channel currently registering agent_id in the host-global shared registry.
shared_channel_path 🔒
Path to one (agent, channel) pair’s entry file.
should_evict_on_forward_failure
Should server/reactive.rs’s evict-on-forward-failure sites remove this entry after a failed forward (success:false or a connection error)?
uid_key_for_block 🔒
write
Write (create or update) an agent entry in the shared registry.
write_entry_file 🔒
Write one (agent, channel) entry file, atomically (temp file + rename) so a concurrent reader never observes a partially-written file. Mode 0600 on Unix at open time — same auth_key exposure boundary as the per-channel registry (§5 of the cross-channel spec: same-user trust boundary, not cross-user).
write_shared
Write (create or update) this channel’s entry for agent_id in the host-global shared registry. Writes only this channel’s own file (shared_channel_path) — never touches another channel’s file, so concurrent writers for different channels of the same agent name cannot race or clobber each other.
write_shared_from_env
Convenience wrapper over write_shared: resolves the shared dir and this process’s channel itself, no-op if the shared root can’t be resolved. Exists so call sites outside server/reactive.rs’s explicit register/unregister handlers (PTY shell auto-register, persistent stream-json controller auto-register — both call the per-channel write/remove directly, not through the HTTP handler) don’t each repeat the same resolve-dir-then-read-env dance.
write_shared_from_env_with_nonce
Convenience wrapper over write_shared_with_nonce — see write_shared_from_env.
write_shared_with_nonce
write_shared, recording the registering persistent-controller spawn’s registration nonce — see AgentEntry::registration_nonce / issue #2363.
write_with_nonce
[write], recording the registering persistent-controller spawn’s registration nonce — see AgentEntry::registration_nonce / issue #2363.

Type Aliases§

PubkeyResolver 🔒
Resolves an agent’s published Ed25519 public key for AgentEntry::jekt_public_key.
UidKeyResolver 🔒
Resolves a registered block’s agent UID and that UID’s public key, for AgentEntry::uid / AgentEntry::uid_public_key (identity M4d-5). By block, because the block is what every registration path has. A load, never a mint, like jekt_public_key_for: M4d-2 mints the key at spawn.