Expand description
Client holder for the messenger record-seal key, the one web-bot wake,
and the HTTP a released OutgoingRequest actually performs.
store_seal_key is SHA-256 of the session id string. The client derives
it when it opens the store. It is not a passphrase, it is not stored
beside the records, and nothing here is a KDF or a vault.
The private Olm account stays in this store. MessengerCore::open_sealed
calls OlmAccountState::load_or_create and pickles it under the seal.
Clients exchange only public keys with the server, through the existing
keys upload and keys query paths.
Outbound mail to other agents is MessengerCommand::SendMessage and
/sync, not POST /mail/send and not POST /admin/listener.
Inbound wake is not a second mailbox. After the engine has a readable
room text from someone else, this shell posts a small JSON object to
one routine URL through post_decrypted, or pushes the same text on
the leader socket. The plaintext stays in body. from is the sender
mxid, event_id is the Matrix event id, and nick is the sender’s
display name only when this shell already has one. Which of those two
triggers is armed depends on the open path, not on a file. Missing the
one this path uses skips that trigger. It does not drop the message
and it is not an error. Routine replay skips texts already loaded.
A leader prompt skips keys already listed in leader-prompted. When
that file records nothing, joined rooms with an empty timeline are
paged once from the stored sync token, and only the newest inbound
text in each room is prompted.
The device bearer stays in memory on OpenedStore. It is sent as
Authorization: Bearer and is not written next to the sealed records.
The register response access_token is that bearer, and only when this
call created the device. A later process for the same session gets it
from the host keychain via DEVICE_TOKEN_ENV, the way box-secrets
works. Nothing here reads or writes a secrets file, and the bearer is
not logged.
Paths the engine builds under /_matrix are sent without that prefix:
mail4agent-server-bin mounts the Client-Server router at /client/v3.
Two open paths, one shell. This is not a second product.
The web machine client is MachineClient::from_env. One process
prefers the live agents directory (AGENTS_DIR_ENV /
DEFAULT_AGENTS_DIR): each folder is an agent id (also the mail
session id) and profile.json has the display name. When that
directory is absent it reads SESSIONS_DIR_ENV. The nick is
nick_from_display_name of that display name. Mail between sessions
this client holds is in process
(MachineClient::set_local_delivery). A peer that is not in the list
uses the homeserver. Wake is the bot’s own webhook routine, named by
its nick, which only the bot can create (UpdateRoutine). This process
keeps a disabled local mirror in the same folder so the gateway hands
out that routine’s URL and key; a null key is retried, never replaced
by a second routine. ensure_agent_webhook_routines does that without
opening stores. MachineClient::poll_agent_directory retries and
rescans for new bots. The URL and key live in memory and in the
session’s keychain file under the store root, and are not logged. This
path does not read LEADER_SOCK_ENV.
A node is OpenedStore::connect_node_from_env. One CLI session, woken
by ACP on LEADER_SOCK_ENV. A routine URL or bearer in the environment
is refused before register. This path does not gain a webhook config.
OpenedStore::connect still registers one session a caller already
built; it is not either of those open paths and it does not read a wake
from the environment.
Re-exports§
pub use provider::plan_chain;pub use provider::HostEnv;pub use provider::HookFlavor;pub use provider::ResumeSpawnAdapter;pub use provider::SessionRecord;pub use provider::WakeChain;pub use provider::WebVendor;pub use provider::adapter_for;pub use provider::wake_prompt;pub use provider::AdapterConfig;pub use provider::ClaudeChannelAdapter;pub use provider::ClaudeRoutineFireAdapter;pub use provider::CodexAppServerAdapter;pub use provider::CodexCloudAdapter;pub use provider::CodexEndpoint;pub use provider::CursorAgentAdapter;pub use provider::GrokLeaderAdapter;pub use provider::KimiServerAdapter;pub use provider::NoInboundAdapter;pub use provider::ProviderKind;pub use provider::ProviderSession;pub use provider::RoutineWebhookAdapter;pub use provider::SessionKind;pub use provider::Surface;pub use provider::WakeAdapter;pub use provider::WakeError;pub use provider::WakeLetter;pub use provider::WakeOutcome;pub use provider::INBOX_DIR_ENV;pub use provider::PROVIDER_ENV;
Modules§
- provider
- Provider wake adapters for the one-per-machine mail4agent clients.
Structs§
- CmdReply
- The answer to one
CmdRequest. - CmdRequest
- One command request.
- Decrypted
Wake - One decrypted room text the routine should learn about.
- Device
Id - A device id: an opaque, server-assigned string with no sigil, one per
authenticated session (plan §3.1’s
MessengerCore::device_id). - EventId
- A Matrix event id:
$opaque(room version 3+ shape — no server-name suffix; the opaque part is itself a content hash in most room versions, but this crate does not interpret it further). - Found
Session - A session found by nick. No routine URL and no bearer.
- Grok
Listener - Push listener for every live local grok session.
- Heard
- One live grok CLI session the index named.
- Host
Session - One bot session the host says lives on this machine.
- Listen
Report - What one
GrokListener::tickdid. Nicks only. No bearer, no session id. - Machine
Client - The sessions on one machine, and the in-process bus they use when the peer is one of them.
- Node
Client - One local ACP node: a single
OpenedStore, its push link, and an optional send socket form4a-send. - Node
Tick Report - What one
NodeClient::tickdid. Event ids, room ids, and error texts only — never URLs, keys, or bearers. - Opened
Store - A sealed messenger core opened for one session, plus the homeserver it performs released requests against. The Olm account was loaded or created into it. Private key material stays here. The device bearer stays in memory and is zeroed when this value is dropped.
- Outgoing
Message - One message a caller wants sent via
MessengerCommand::SendMessage— M13b’s binding content shape: text/notice/emote, an optional reply pointer, and an optional edit target (which must name one of the caller’s own already-sent events —MessengerCore::dispatchrejects an edit of someone else’s event rather than silently sending a replacement the room’s other members will refuse to accept, perm.replace’s own “must come from the original sender” rule,crate::room::relations’s own module doc).reply_toandedit_ofare mutually exclusive at the wire level — if both are set,edit_ofwins (an edit’s ownm.relates_toism.replace, not a reply). - Pushed
Room Event - One room event the homeserver pushed for a single session.
- RoomId
- A Matrix room id:
!opaque:server_name(client-server API’s ownroom_idgrammar — opaque per spec, never derived from the room’s own alias or name). - Room
View - One room this store currently holds, from this account’s own view.
- Routine
Report - One bot’s wake routine, by nick and folder id.
- Routine
Wake - One URL per bot, already created. Neighbors are addressed by nick or mxid on the server.
- Send
Reply - The answer to one
SendRequest. - Send
Request - One request on the send socket.
- Session
Config - One Grok Bot web session, ready to register. Built from the host
environment (
SessionConfig::from_env) or from the same fields the host would have injected. The nick isnick_from_display_nameofbot_name. Local grok CLI sessions do not use this type. - Session
Wake - Wake targets for one shell. Empty fields mean that trigger is off.
routine_beareris kept only in memory and only attached whenroutine_urlis set. The caller fills it from the environment, never from a literal in source. - Text
View - One text-like timeline row. Ciphertext is not included.
- Tick
Report - What one
MachineClient::tickdid. Nicks, event ids, room ids, and error texts only. - UserId
- A Matrix user id:
@localpart:server_name(client-server API’s ownuser_idgrammar). - Wake
Attempt - One routine POST: the Matrix event id it carried and the HTTP status
(
Nonewhen no response arrived).200means the routine woke. - Wake
Options - Knobs for
ensure_agent_webhook_routines. All machine-specific, so they come from the environment (WakeOptions::from_lookup).
Enums§
- Create
Room Kind - Which shape
MessengerCommand::CreateRoombuilds, mapped onto the server’s ownPOST /createRoomfield set (visibility/is_direct/invite/name/topic— the server deriveskinditself fromvisibility+is_direct, per the server plan’s §5; a client never sends apreset/kindfield directly). - Message
Kind - Which
m.room.messageshapeOutgoingMessagerenders as (M13b send pipeline). - Messenger
Command - One command a shell/adapter dispatches into the core — both the M13a
receive-side variants (
MarkRead,SetTyping,RetryDecryption,LoadOlder) and the M13b send/room-membership ones. OnlyPartialEq(notEq):MessengerCommand::SetTag’sorder: Option<f64>cannot implementEq. - Product
Secret - How a session proves itself to the product server.
- Room
Kind - What kind of room this is, derived from its current state – never a
separately stored flag (see
RoomState::derive_room_kind’s own doc for the precedence between the two possible signals). - Shell
Error - Why opening the client store, releasing a send, or posting a routine failed. The seal key and the device bearer are never included.
- Wake
Status - Where one bot’s wake stands after
ensure_agent_webhook_routines. Carries no URL and no key.
Constants§
- AGENTS_
DIR_ ENV - Live Grok Bot agents on this machine. Each child folder name is an
agent id;
profile.jsonhas the displayname.MachineClient::from_envprefers this overSESSIONS_DIR_ENVwhen the directory exists. - AGENT_
RESCAN_ SECS_ ENV - Optional rescan period in seconds for
MachineClient::poll_agent_directory. Unset or0means the caller decides when to poll; open still scans once. - BOT_
NAME_ ENV - Display name of this Grok Bot web session, the name the host already shows. The nick is derived from it. This is not a nick slug.
- CONFIG_
ENV - Optional path of a toml file whose
homeserver_urlis used whenHOMESERVER_URL_ENVis unset. Unset looks at./mail4agent.tomland ignores it when that file is absent. - DEFAULT_
AGENTS_ DIR - Default agents directory, relative to the user’s home (
$HOMEor%USERPROFILE%). Used whenAGENTS_DIR_ENVis unset and the resolved path is a directory. - DEFAULT_
SOCK_ NAME - Socket file name under the store root when
SEND_SOCK_ENVis unset. - DEVICE_
TOKEN_ ENV - Device bearer from the host keychain, for a session that already registered. Unset on the first connect: the register response supplies it, once, into process memory. Never a file.
- ENV_
FILE_ ENV - Env file with the machine’s client settings (
KEY=VALUElines), read bym4a-web-clientandm4a-sendfor every variable the process environment leaves unset. Default$HOME/.config/mail4agent/web-client.env. Settings only: homeserver URL, store root, keychain dir, skip list, session-id aliases. Never secrets. - HOMESERVER_
URL_ ENV - Homeserver origin for a Grok Bot web session, for example
http://127.0.0.1:8741. Wins overCONFIG_ENV/mail4agent.toml. There is no built-in host. - KEYCHAIN_
DIR_ ENV - Keychain directory for device bearers, kept apart from the sealed
stores (a bearer is never written next to sealed records). The
homeserver returns a device bearer only once, on the call that creates
the device; with this set,
MachineClient::from_envreads each session’s bearer from<dir>/<session hash>/device-bearer(mode 0600) and writes a newly minted one there. Unset: bearers stay in memory and the host injects them. Never logged. - LEADER_
CWD_ ENV session/loadworking directory whenLEADER_SOCK_ENVis set. Unset uses the process current directory.- LEADER_
SOCK_ ENV - Leader socket for a local session (
leader.sock). Unset: no ACP push. - MAX_
SEND_ BYTES - Longest text one send carries.
- NODE_
DEFAULT_ SOCK_ NAME - Default send-socket file name under the store root for the node client.
- PRODUCT_
NICK_ ENV - Product-session mode: the product nick to log in as.
- PRODUCT_
PASSWORD_ ENV - Product-session mode: password for
POST /product/v1/login(not logged). - PRODUCT_
TOKEN_ ENV - Product-session mode: an existing product session token instead of a password.
- PRODUCT_
URL_ ENV - Product-session mode: base URL of the product server. Every Client-Server call goes through its proxy with the product session token as bearer.
- PROFILE_
NOTE_ ENV - Set to
1to write the bootstrap note into the profile description of each bot that has no routine yet, through the gateway’supdateAgent(the host pushes profile edits to the server copy of the bot). The note asks the bot to create its own routine namedcrate::routine_folder_idof its nick on its next turn. Off by default: it edits a description the owner wrote. - ROUTINE_
BEARER_ ENV - Optional
Authorization: BearerforROUTINE_URL_ENV. Sent only when that URL is also set. A host keychain injects this into the process environment from outside. It is never written to disk and never read from source. - ROUTINE_
URL_ ENV - Routine POST target. Unset or empty: no POST. There is no default URL.
- SEND_
COMMAND - Command a woken bot runs to answer, as shown in the wake’s
reply. - SEND_
SOCK_ ENV - Path of the web client’s local send socket.
- SESSIONS_
DIR_ ENV - Directory of session records. Each
*.jsonfile isbot_name,session_id, and an optionalagent_id. Used when no agents directory is available. Unset means the host passed the list toMachineClient::openinstead. - SESSION_
IDS_ ENV - Comma-separated
agent_id=session_idpairs. An agent listed here uses that mail session id instead of its agent id, for a bot whose session was registered before agent-id sessions. Machine-specific, so it lives in the environment. - SESSION_
ID_ ENV - Session id the web host already assigned. The store directory is
session_store_dirof this id. The same id reopens the same store. - SKIP_
NICKS_ ENV - Comma-separated nicks this client leaves alone: no session, no mirror, no credential call. Machine-specific, so it lives in the environment and not in source.
- STORE_
LOCK_ FILE - Lock file in each sealed session directory.
MachineClient::openholds an exclusive lock on it for as long as the client lives, so a second process (another client, orm4a-sendopening the store itself) cannot write the same Olm state at the same time. - STORE_
ROOT_ ENV - Shared store root on this machine. The caller supplies it. Unset is not a shared fallback outside tests.
- WAKE_
KEYCHAIN_ FILE - Per-session keychain file under the session’s sealed directory
(
crate::session_store_dir). Mode 0600. Holds the folder id, the webhook URL, and its key. Outside any repository; never logged.
Functions§
- ensure_
agent_ webhook_ routines - Ensures each agent’s local mirror (webhook trigger, disabled, folder =
crate::routine_folder_idof the nick) and asks the gateway for its credential. Bots whose nick is inskip_nicksare not touched. Does not open sealed stores, does not register on the homeserver, and does not log or return URLs or keys. Whenstore_rootis set, a ready URL and key are written to that session’s keychain file. Withprofile_note, a bot still waiting gets the bootstrap note. - ensure_
agent_ webhook_ routines_ from_ env ensure_agent_webhook_routinesusing the host gateway file, the agents directory from the environment (orDEFAULT_AGENTS_DIR),SKIP_NICKS_ENV, andSTORE_ROOT_ENVwhen set.- hear
- Reads an
active_sessions.jsondocument and names each row from that session’s own topic. Empty text is an empty list. A document that is not that index is an error. - load_
agents_ dir - Reads each agent folder under
dir. Folder name is the agent id and the mail session id.profile.jsonsupplies the display name. Folders without a usable profile are skipped. This does not hardcode agent ids. - load_
env_ file - Sets each
KEY=VALUEfrom the env file (ENV_FILE_ENVor the default web-client path) that the environment does not already have. Blank lines and#comments are skipped; surrounding quotes are dropped. Call at the start ofmain, before any thread starts. Returns the file read. - load_
env_ file_ named - Like
load_env_file, but the default under<home>/.config/mail4agent/isdefault_name(node usesnode-client.env). Home isHOMEwhen non-empty, otherwiseUSERPROFILE.ENV_FILE_ENVstill wins when set. - load_
session_ records - Reads
*.jsonsession records fromdir. A file that carries anything besidesbot_name,session_id, andagent_idis refused, so a webhook URL or a bearer cannot ride along in a world-readable record. - mxid_
localpart - Localpart of a Matrix user id (
@alice:server->alice). - nick_
from_ display_ name - Cyrillic (and a few adjacent letters) to Latin, then the host’s routine slug rule, so a bot’s nick, its wake routine name, and that routine’s folder id are one string.
- post_
decrypted - POSTs
wakeonce, as a JSON object, tourl. No mailbox path and noAuthorizationheader.urlis the bot’s already-configured routine.httpandhttpsare both followed; anything else is refused before a socket is opened. - post_
decrypted_ with_ bearer post_decryptedplus the routine key. WhenbearerisSomeand non-empty, that same value is sent asAuthorization: Bearerand asX-Automation-Key.Content-Typeisapplication/json. One JSON body. One attempt, 8 seconds. A 200 means the routine woke. Anything else is a failure and is not retried here. The key and the URL are not included in the error. The value must come from memory, not from source.- post_
routine_ json post_decrypted_with_bearerwith any JSON object as the body: the machine client’s own events (kind=peer_joined) go to a bot’s routine this way. Same headers, one attempt, 8 seconds, 200 or error. The key and the URL are not included in the error.- reply_
hint - The
replyhint for a wake fromfrom_nicktoto. - routine_
folder_ id - Folder id the Grok Bot routine store gives a routine named
name. - send_
cmd_ via_ socket - Sends one rich command over the client’s socket and waits for the answer.
- send_
sock_ path - Socket path:
SEND_SOCK_ENVwhen set, elseDEFAULT_SOCK_NAMEunderstore_root. - send_
sock_ path_ named - Like
send_sock_path, but usesdefault_nameunderstore_rootwhenSEND_SOCK_ENVis unset (node client usesnode-client.sock). - send_
via_ socket - Sends
requestover the client’s socket and waits up towaitfor the answer.Errmeans no client answered on that socket (missing, refused, or closed early), so the caller may fall back to opening the session itself. - session_
store_ dir - Directory for
session_idunderroot. - store_
root STORE_ROOT_ENVwhen set and non-empty. Tests with it unset get one temp directory for this process. Other builds returnShellError::StoreRootand do not invent a path two agents would share.- store_
seal_ key - SHA-256 of
session_id’s UTF-8 bytes. That digest is the check that this session may open the store. The bytes are not written to disk.