Skip to content

The suite

Six plugins, six refusals.

They install together and are enabled together. Each one owns a single decision and says no in one specific way.

pip install hermes-mordred
hermes-mordred setup
Plugin Decides Refuses with Platform
keyvault Whether a signature or decryption may happen at all MRD-01xx macOS / Linux
network Whether a socket may open, and through which route MRD-02xx macOS / Linux
e2e Whether a message body may leave in readable form MRD-03xx macOS / Linux
llm_guard Whether a prompt may reach a remote model MRD-014x macOS / Linux
privacy_check Nothing — it only reports what the others decided n/a · exit code macOS / Linux
wizard Whether the configuration is complete enough to run MRD-09xx macOS / Linux

[TBD]Reason-code ranges and per-platform differences to be confirmed by engineering.

mordred_keyvault

Holds the identity.

Signing and decryption are requested, never performed in your process — the private key stays behind the platform helper for its whole life.

MACOS
Secure Enclave · P-256
LINUX
TPM 2.0 · persistent handle
Docs — keyvault →

It refuses

  • Any request to export, print, or back up key material. MRD-0101
  • Signing when the hardware attestation does not match the policy. MRD-0107
mordred keyvault init
mordred keyvault attest
mordred keyvault pubkey

mordred_network

Egress is denied by default.

A run inherits exactly one declared route — Tor, a VPN, or clearnet — and cannot widen it while running.

ROUTES
tor / vpn / clearnet
DEFAULT
deny
Docs — network →

It refuses

  • Connections to hosts outside the declared allow-list. MRD-0204
  • Falling back to a weaker route when the declared one is down. MRD-0201
mordred network show
mordred network declare --route tor
mordred network allow slack.com

mordred_e2e

Seals message bodies to the recipient before the transport client sees them.

Slack, Discord, and mail relays carry ciphertext and metadata, nothing more.

GATEWAYS
slack / discord / smtp
SEAL
age · recipient key
Docs — e2e →

It refuses

  • Sending to a recipient with no known public key. MRD-0302
  • Plaintext delivery, even when the gateway asks for it. MRD-0305
mordred e2e recipients
mordred e2e inspect --last

mordred_llm_guard

The last check before a prompt leaves for a remote model.

A match halts the call rather than redacting quietly, because a silent edit hides the real problem.

SCANS
keys, tokens, private paths
LOGS
match name, never value
Docs — llm_guard →

It refuses

  • Prompts carrying credentials or key material. MRD-0142
  • Providers with no guard profile configured. MRD-0148
mordred guard test ./prompt.txt

mordred_privacy_check

Reads the live configuration rather than the file you meant to write.

It decides nothing; it just makes the current state legible, and exits non-zero when a guarantee is unmet.

OUTPUT
one line per guarantee
EXIT
0 met · 1 unmet
Docs — privacy_check →
mordred privacy-check

mordred_wizard

Guided setup for the other five.

It either leaves you in a state the policy can enforce, or stops and tells you which answer is missing.

WRITES
~/.mordred/policy.toml
IDEMPOTENT
re-run any time
Docs — wizard →

It refuses

  • Finishing with an undeclared route or a missing key. MRD-0902
  • Writing a policy weaker than the one already on disk without --downgrade. MRD-0911
hermes-mordred setup
hermes-mordred setup --review

How they compose.

One outbound message passes each decision in order. A refusal anywhere in the chain stops the whole run — there is no partial send.

  1. Agent writes a message
  2. llm_guard scans for secrets
  3. e2e seals the body
  4. network opens the declared route
  5. Slack receives ciphertext

keyvault signs and decrypts underneath all four; the key never appears in the chain.

privacy_check reads the chain afterwards and reports which links held.