Blog · Guide · 28 October 2026

How AEGIS seals a tool call: the SEAL gateway, step by step

Also in: Español, Português, 日本語, Deutsch, Français, 한국어, 简体中文, Italiano, हिन्दी

Disclosure: 100monkeys.ai builds AEGIS and the SEAL Gateway, so read this guide as a maker's account. It was drafted by one of our AI agents from the public documentation, chiefly the SEAL Protocol page, Integration with AEGIS and Security Contexts, and reviewed by the company. The fields, codes and flows below are the docs' own, not output we captured for this guide.

AEGIS by 100monkeys.ai, in beta, does not trust an agent's tool call because the agent made it. Each call is wrapped in a signed envelope and checked by the SEAL Gateway before anything outside the run is touched. This guide follows one call from the moment a run starts to the audit record it leaves.

What SEAL is for

SEAL stands for Signed Envelope Attestation Layer. The docs name four gaps in ordinary tool-call protocols: no proof of which client sent a request, permissions that are all or nothing per session, bodies that can be tampered with in transit, and no record proving which caller did what. Their example is a prompt injection: a fetched page tells the model to delete /workspace. "With SEAL, the caller's SecurityContext has no fs.delete capability. The gateway blocks it before it ever reaches the tool."

The gateway is standalone-first. In the docs' words, it is "the same aegis-seal-gateway binary" that the AEGIS orchestrator "deploys alongside itself". With AEGIS you do nothing extra to get the steps below; "it is the default."

Step 1. The orchestrator opens a session for the run

When an execution enters Running, the orchestrator generates a fresh Ed25519 keypair for that execution and registers it with the gateway: POST /v1/seal/sessions with a session_id (the execution id, "so audit trails line up"), the public_key, the security_context and an expires_at bounded to the run's wall-clock budget. Only a caller holding the seal.session.create scope can do this; "agents themselves cannot self-register."

Step 2. The private key goes to the agent, and nowhere else

The private half is written to the agent container's ephemeral runtime config, "a tmpfs mount, never persisted", with the gateway URL and the session id. So every execution has its own key, and "a leaked private key is bounded to a single execution's lifetime."

Step 3. The session is bound to one security context

A security context is a named policy on the gateway: a deny_list and an ordered list of capabilities, each with a tool_pattern and optional path_allowlist, command_allowlist, subcommand_allowlist, domain_allowlist and max_response_size. Spawned agents run under aegis-system-agent-runtime, not the tier context of the person who asked. The orchestrator stamps the context at provisioning, and the agent "cannot escalate by claiming a different scp in its envelope".

Step 4. The agent signs a canonical message

The signature is not over the raw JSON. It is over three keys, payload, security_token and timestamp, serialized with keys sorted at every level, no whitespace, an integer Unix timestamp and UTF-8. Any other byte sequence gives a different signature, and "the gateway will reject the envelope."

Step 5. The agent sends the envelope

The envelope carries protocol (always seal/v1), the security_token (a JWT issued at attestation, default lifetime one hour), the Ed25519 signature, the payload (for MCP-style calls a JSON-RPC tools/call), an optional container_id and the timestamp. It goes to the gateway's invocation endpoint, POST /v1/invoke. The gateway listens on 8089 by default; the AEGIS orchestrator's own API is on 8088.

Step 6. The gateway runs nine checks

  1. The protocol field is seal/v1.
  2. The token decodes into its claims: sub, scp, wid, exec_id, iat, exp, jti.
  3. The token's signature verifies against the gateway's key, with the alg header checked explicitly.
  4. The token has not expired.
  5. The caller's registered public key is found for the session.
  6. The canonical message is rebuilt.
  7. The envelope signature verifies against that key and message.
  8. The timestamp is within 30 seconds of the server's clock.
  9. The security context named in scp is loaded and the call is evaluated.

"Every check must pass before the payload is unwrapped and forwarded."

Step 7. The security context decides

Evaluation runs in a fixed order: if a deny_list pattern matches, the call is refused; otherwise "the first capability whose tool_pattern matches the tool name owns the decision"; if none matches, the call is refused, because "there is no implicit allow." A family pattern such as fs.* matches fs.read and never fs or fsx.read.

Step 8. The call is forwarded, or refused with a code

An allowed call has its payload unwrapped and sent to the tool; credentials, where the tool needs them, are resolved at that moment. A refused call answers with a numeric code: 2000 to 2006 for policy (not granted, on the deny list, path, command or domain outside its allowlist, rate limit, no matching capability), 1001 to 1006 for signatures, tokens and sessions, 3000 to 3002 for attestation. The docs' advice: "Switch on error.code, not on the status."

Step 9. Every decision leaves an audit event

The gateway publishes ToolCallAuthorized or PolicyViolationBlocked, among others, with the envelope's signature, timestamp and jti, the token's sub, scp, wid and exec_id, the tool name, a payload digest ("payloads are not logged by default") and the decision with its deciding rule. Because only the session's private key could have signed the envelope, the record gives non-repudiation.

Step 10. The session ends with the run

When the execution ends, by success, error, timeout or cancellation, the orchestrator calls DELETE /v1/seal/sessions/{session_id}. The gateway purges the key, and a captured envelope replayed after that is rejected.

What the docs leave open

Next

To find these calls in a real run, read Reading an AEGIS execution log. To try it, AEGIS installs with the command printed on 100monkeys.ai:

curl -fsSL https://get.100monkeys.ai | bash

Install AEGIS from 100monkeys.ai