Identity M4d-6 (SPEC_AGENT_IDENTITY_CARRIED_NOT_DERIVED_2026_09_23.md
§6.5.10): the LAN v2 signature, checked once the v1 LAN signature verified.
LAN peers are unauthenticated, so a UID it proves is recorded only as
claimed by that LAN path: never verified, never matched to a local row.
Summary of the most recent identity-mismatch audit entry for this
agent_id, if any (see #2695’s Handler::inject_message_inner check) —
narrowed from AuditLogEntry to what the Stash badge needs.
One cross-instance/channel entry from the host-global shared registry
(backend::reactive::registry::AgentEntry), narrowed to what the
frontend actually needs to render a “registered elsewhere too” badge —
deliberately excludes local_url/auth_key, which are internal
forwarding plumbing, not UI-relevant.
What one forward attempt concluded. The distinction that matters is
Stale vs
Inconclusive: only the former is evidence
about the candidate, and only the former may drive an eviction.
Anti-replay window for cross-channel channel_sig —
SPEC_JEKT_CROSS_CHANNEL_TRUST_2026_09_02.md §D6: host-tier’s tighter
JEKT_SIG_MAX_AGE_SECS, NOT LAN/WAN’s wider one. A cross-channel forward
is a same-machine HTTP call to 127.0.0.1; it has no real-network
latency budget to accommodate, for the same reason host-tier doesn’t.
Max age (seconds) a signed jekt’s ts_secs may be from “now” and still
verify (SPEC_JEKT_TRUST_LAYER_COMPLETION_2026_08_13.md §2.2, anti-replay
— reagentx P1 on PR #2565: ts_secs was bound into the signed material
specifically for this purpose per jekt_sign.rs’s own doc comments, but
nothing actually checked it, so a captured valid signature verified
forever). Generous enough for normal host-tier delivery latency and
modest clock skew between the signing agent process and this srv
instance (same machine, but not guaranteed same clock read down to the
second); tight enough to bound replay to a narrow window instead of
indefinite reuse.
Anti-replay window for LAN lan_sig — reuses the WAN reasoning
(REAGENT_SIG_MAX_AGE_SECS) rather than host-tier’s tighter
JEKT_SIG_MAX_AGE_SECS: LAN crosses an actual network hop (mDNS
discovery + an HTTP round trip through a peer instance), not a
same-process call, so it needs the wider real-network-delivery-latency
margin WAN already established rather than host-tier’s same-machine one.
Max cross-instance HTTP forwards a single inject request may go through
(Tier 2a/2b/3 each increment before forwarding). A legitimate delivery
is always exactly one hop (caller’s instance → the owning instance);
this only exists to bound a pathological cycle — two channels each
holding a stale-but-PID-alive shared-registry entry pointing at the
other for the same agent name would otherwise forward back and forth
indefinitely, hanging the original request (reagent P1 on PR #2350).
Anti-replay window for req.reagent_ts_secs, same purpose as
JEKT_SIG_MAX_AGE_SECS above but WAN-scoped: wider than host-tier’s
300s because this covers real network delivery latency, not a
same-machine call — matches cloud_subscriber::REAGENT_SIG_MAX_AGE_SECS
(the WS delivery path’s own constant of the same value) and the review
notifications’ own delivery window.
Server-side ceiling on max_lines — protects a Supervisor’s transcript
pull (and this route in general) from an unbounded read of a huge
session file. Callers wanting more must paginate some other way; this
route is a “recent tail” primitive, not a full-history export.
The relay’s lease answer as a route: hold here unless it says another
install runs the agent or cannot say; an unreachable relay holds here
(there is no relay to send through anyway).
The UID and slug of the agent defined in this channel that target
names, as the hold resolves it (hold_for_absent_target). The slug is
the agent’s AGENTMUX_AGENT_ID, which its relay lease is keyed by.
Deliver an inject — verify, try this instance, then forward
cross-instance, cross-channel, LAN and cloud relay — exactly as
POST /agentmux/reactive/inject does. Shared with the cron scheduler’s
in-process fire (identity M4c-3, spec §6.5.9), which passes its tier
explicitly (auth_via) in place of the route’s ReactiveAuthVia
extension. caller_uid is the sender’s attributed UID, audited on this
instance only (InjectionRequest::audit_source_uid never rides a hop);
"" when Unattributed.
The trust an echoed marker should carry after a forward, given the
peer’s response body. The RECEIVING instance is the one that computes
channel_verified (the forwarder holds the sender’s HMAC key, so §D2
step 2 of SPEC_JEKT_CROSS_CHANNEL_TRUST_2026_09_02.md makes it skip
cross-channel verification) and threads it back via
InjectionResponse::channel_verified, exactly as it already does for
effective_tier/requires_stop. Taking it from the body keeps the
sender’s echoed TRUST= consistent with the ESCALATE= the same body
supplies — otherwise a sensitive cross-channel message could echo as
TRUST=self-declared … ESCALATE=none, which contradicts itself (codex
P2 on #3064). A body without the field (an older peer) leaves the
caller’s value alone.
Agent NAMES only, for LAN peers: not handle_reactive_agents, whose
full AgentRegistration records (block_id, tab_id, registration_nonce,
…) are routing details that stay behind full auth.
Mint-or-reuse agent_id’s host-tier jekt signing key and return it,
base64-encoded — the same value agent_config::inject_jekt_signing_keys_into_mcp_json
writes into a real agent’s .mcp.json at spawn time, exposed directly
here instead of only reachable through agent.open’s WebSocket
(WshRpcEngine) path. That path also spawns a real provider session,
which makes it unusable for anything that just wants to exercise
host-tier jekt signing/verification (tests, external harnesses) without
the cost and side effects of a live LLM session.
POST /agentmux/reactive/supervisor-decision — a Warden Supervisor
watcher agent’s decision about a target agent it just polled (see
GetAgentTranscript). action: "nudge" delivers a fixed continuation
message (not caller-supplied text — see SupervisorAction::Nudge’s
doc) to target_agent through the same path SendMessage/Loop use
and audits it as a Supervisor-originated entry; action: "decline"
sends nothing and just audits the decision. A nudge that would exceed
the consecutive-nudge ceiling is refused with HTTP 429 — the calling
agent should treat that as a signal to stop and escalate to a human
instead of retrying.
GET /agentmux/reactive/transcript?agent=<name>&max_lines=<n> — read the
tail of a registered agent’s session output, for a Warden Supervisor
watcher agent to inspect on its own poll interval (v1 is pull/poll, not
push — see
docs/analysis/ANALYSIS_WARDEN_AUTO_CONTROLLER_CONTINUATION_WATCHER_2026_08_12.md).
Fallback path for handle_reactive_transcript when the target agent
isn’t on this instance’s own host-tier registry — checks the host-global
cross-channel shared registry and, on a hit, forwards to the owning
channel’s own instance. A miss here (not found on this channel OR any
other channel on this host) 404s exactly as the host-only lookup always
did — this does not reach LAN or WAN (Phase A scope; see spec Phase B/C).
The conditions under which this instance may hold a jekt at all (durable
jekt spec §2.1): a full-key, host-tier request (a LAN caller never fills
the hold); not a periodic cron fire; and an id to key the row by.
Hold a jekt no tier could take, when every condition of
SPEC_DURABLE_JEKT_DELIVERY_2026_09_24.md §2.1 holds: a full-key,
host-tier request (a LAN caller never fills the hold); not a periodic
cron fire; and a target that is a known agent of this channel —
resolved to its row’s UID, so a typo or a name registered later by
another block never receives the backlog. None keeps today’s error.
Whether a host-global shared-registry entry is THIS instance’s own
registration (as opposed to a genuinely different instance/channel on
the same host) — every agent unconditionally writes itself into that
same registry, so a “remote”/“elsewhere” listing must exclude its own
entry or it fires on every healthy agent (reagentx P1 on #2698). Same
comparison this file already uses for Tier 2a/2b forwarding.
Registers reactive.registrations, called by the Stash “Registration”
tab (AgentIdentityLinksPanel’s sibling — see frontend/app/store/ rpc-api/reactive.ts) to answer “is this agent’s jekt identity healthy
right now”: where it’s registered locally, whether any OTHER
instance/channel on this host also claims the same agent_id (the
collision shape #2694 fixed one specific cause of), and whether a
recent delivery hit the #2695 identity-mismatch guard.
Server-derived delivery_tier for the LAN-key case only —
docs/specs/SPEC_JEKT_LAN_TIER_SIGNING_2026_08_15.md §3, revised after
reagentx P0 on the implementing PR: an earlier version of this override
also force-downgraded a “lan” claim to “host” whenever auth was via the
full auth_key, reasoning that “nothing authenticated via the full key
could have genuinely crossed the LAN boundary.” That’s false once
same-host forwarding (Tier 2a/2b below in handle_reactive_inject) is
considered: a jekt legitimately authenticated via lan_key at its FIRST
hop, then relayed to a sibling channel/instance on this same machine,
authenticates that SECOND hop with the sibling’s own full auth_key
(not lan_key — that credential is peer-to-peer between distinct
machines, never shared across same-host channels). Downgrading there
silently discarded an already-detected LAN signature failure’s
forced-sensitive escalation (lan_verified/reagent_verified are
#[serde(skip_deserializing)], so they reset to None on every hop and
must be free to re-derive from whatever delivery_tier the forward
legitimately carries).
Server-side resolution of InjectionRequest::is_transcript_request /
transcript_request_escalate_forced — see both fields’ own doc comments
(backend/reactive/types.rs) and
SPEC_JEKT_TRANSCRIPT_REQUEST_TIER_RULES_2026_08_22.md. Lives here (not
Handler::inject_message_inner) because it needs Store access —
Handler has no Store access “by design,” same reason
sig_verified/lan_verified are resolved by this same caller before
the request reaches the handler.
Decide AbsentRoute for a target no tier found live. Holding here is
the default for an agent defined in this channel, so messaging works
without the relay; the relay overrides it only when it says another
install of the account holds the agent’s lease. Anything the relay
cannot answer plainly keeps the old order (relay first), so an older
relay changes nothing.
The delivery_tier a same-host Tier 2a/2b forward carries to the peer
instance — SPEC_JEKT_CROSS_CHANNEL_TRUST_2026_09_02.md §D4. See the call
site in handle_reactive_inject for the full reasoning; in short: a
host-tier (or unlabelled) request becomes channel on the hop, and
anything already carrying a network tier keeps it so the peer re-derives
that tier’s own verification.
Tier 4. Some(body) when the cloud accepted the injection (and the sender
echo has been emitted); None when tier 4 doesn’t apply or didn’t take,
leaving the caller to return its original error.
verify_cross_channel_signature with the shared registry dir and clock
injected — the testable core; the wrapper above only resolves the real
dir. Keeps tests off the process-global AGENTMUX_SHARED_DIR env var.
Host-tier jekt sender verification (SPEC_JEKT_TRUST_LAYER_COMPLETION_2026_08_13.md
§2.2). Mutates req.sig_verified in place based on whether the claimed
source_agent’s stored signing key (if any) verifies req.jekt_sig,
within the anti-replay freshness window.
LAN-tier per-agent Ed25519 signature verification —
docs/specs/SPEC_JEKT_LAN_TIER_SIGNING_2026_08_15.md §2.4. Async, unlike
verify_jekt_signature’s synchronous local-only key lookup: the claimed
sender’s public key lives on WHICHEVER peer instance actually hosts that
agent, so finding it costs a LAN round trip
(LanDiscoveryController::find_agent_lan_pubkey).
WAN-tier reagent-signature verification for the HTTP
/agentmux/reactive/inject path — mirrors
cloud_subscriber::sync_agent_reactive’s in-process verification of the
same four fields for the desktop app’s WS delivery path, but for callers
that deliver over HTTP instead (@agentmuxai/muxbus-client’s
pollAndDeliverInjections, and any future standalone poller). Before
this, InjectionRequest declared reagent_sig/reagent_key_id as
deserializable input fields but nothing on the HTTP path ever read them
— a reagent-signed notification delivered through this path arrived
unsigned in effect, reagent_verified always None, and could never
render SIG=verified (reagentx P1 on PR #41).