Skip to content
Live demo · Nemotron 3 Ultra on NVIDIA NIM · resets nightly

Let AI agents act — safely.

Aegis sits between AI agents and your company's tools. The model only asks. Deterministic code decides: permission, policy, human approval, exactly-once execution, and an audit row for every action.

One-click demo accounts · no sign-up

aegis://gateway · live decisions
ExecutiveagentEngineeringagentCustomeragentAEGIS GATEWAYthe model asks · code decidesresolveauthorizevalidatepolicyidempotencyexecuterecordauditreturnAtlasGitHubGmailCalendarSlackJiraNotion

Honest status

What runs for real on the public demo, and what is simulated.

  • Nemotron via NVIDIA NIMlivethrough an AI gateway, falls back to Groq, then Cloudflare
  • Atlas over MCPlivea separate RAG product, streamable HTTP
  • Approvals · audit · rate limitslivereal, on Postgres and Redis
  • GitHublive-capablelive REST connector with a stored token; the public demo blocks credentials, so it runs on the mock
  • Gmail · Calendar · Slack · Jira · Notionsimulatedrealistic mock backends with latency, faults and reconcile
  • Google OAuth · long-term memoryplannednot built yet
FIG 00 · the design rule

The model decides what. Code decides whether.

An agent never calls Gmail, GitHub or Notion itself. It asks for a tool, and the request goes through one gateway that every call shares, native or MCP. The LLM is never the security boundary, so a prompt injection can change what the model wants, not what it is allowed to do.

the model decides
code decides
Which tool to use next
Whether the agent is allowed to use it
What arguments to pass
Whether the arguments are valid (JSON Schema)
How to read the results
Whether the action needs a human (policy)
When the task is done
Whether the action already ran (idempotency)
What to write in the answer
Whether the run is within budget
FIG 01 · the gateway

Nine checks between “the model wants to” and “it happened”.

Resolve, authorize, validate, policy, idempotency, execute, record, audit, return. A denied call is still recorded, because it is the proof that the guardrails worked.

  • 01Pick a scenario. The same pipeline handles every tool call, native or MCP.
  • 02Merge a PR is denied by policy before anything reaches GitHub.
  • 03Write pauses for a human. Click Approve or Reject yourself.
aegis://gateway/notion.create_pagein flight
  1. 01Resolve
  2. 02Authorize
  3. 03Validate
  4. 04Policy
  5. 05Idempotency
  6. 06Execute
  7. 07Record
  8. 08Audit
  9. 09Return
tool request
agent Executive Assistant
notion.create_page(
"parent": "Meeting Briefs",
"title": "Acme QBR brief",
)
riskexecute
gateway log
current check
Executive Assistant asks for notion.create_page

The model only asked. Every decision here is plain, deterministic code.

01/12 Executive Assistant asks for notion.create_page

FIG 02 · an agent run

“Prepare me for my meeting with Acme tomorrow.”

A replay of the Executive Assistant on the live demo. On the real thing the model picks its own path, so your run may read different sources. Try it and compare.

  • 01The agent searches Atlas over MCP, a separate knowledge product, alongside Calendar, Gmail and Jira.
  • 02Saving the brief to Notion is execute-level, so the run pauses and checkpoints.
  • 03After approval it resumes exactly where it stopped. The trace streams live.
aegis://runs/9281 · Executive Assistant v3running
Executive AssistantNemotron 3 Ultra · NVIDIA NIM
Prepare me for my meeting with Acme tomorrow. Check our internal docs too.
maya@northwind.dev
Tracelive · SSE0 tool calls
0 tool calls · 5 systems… activeapproval wait excluded

01/13 Maya asks the Executive Assistant

FIG 03 · reliability

Exactly once, even when things break.

Idempotency keys are saved before the external call. Retries back off exponentially and reconcile first. A per-connection circuit breaker stops the agent from hammering a system that is down.

  • 01A timeout after a write is the classic way to create JIRA-1021 and JIRA-1022. Here the retry checks Jira first.
  • 02Three failures in a row open the circuit: calls fail fast and the agent works around the outage.
  • 03Only transient errors are retried. Auth and bad-data errors fail at once.
aegis://gateway/reliabilityexactly once
A · idempotencykey 7c1e…a94f
jira.create_issue(project: "ENG", summary: "Acme: CSV export drops rows over 10k")
  1. idempotency_records ← 7c1e…a94f · in_progress
naive retry
ENG-318
ENG-319duplicate
through aegis
ENG-318
exactly one issue
B · circuit breakerconnection: Gmail
closedcalls flow
openfail fast · 60s
probeone call through
consecutive failures
0/3 · threshold opens the circuit

01/12 jira.create_issue (approved) · key saved as in_progress

FIG 04 · audit + policy

Every action audited. Every rule readable.

The application writes the audit log insert-only. Policies are evaluated in a fixed order (explicit deny, permission, budget, risk, custom rules), so the same call always gets the same answer, and you can explain it to an auditor.

  • 01Who started the run, what the agent touched, who approved it, and what was refused.
  • 02Policies are small JSON rules. Toggle one and the decision changes.
  • 03Send a call through the simulator: it lands in the log like a real one.
aegis://security/auditinsert-only
  1. 14:02:07Maya Okaforrun.startedExecutive Assistant · run 9281
  2. 13:58:44Priya Shahapproval.rejectedslack.post_message · “not to #general”
  3. 13:57:12Engineering Agenttool.executedgithub.search_issues · risk=read · 412 ms
  4. 13:55:30Maya Okaformcp.tools_importedAtlas · 2 tools · risk=read
  5. 13:54:02Dan Reyesagent.updatedExecutive Assistant · v3 published
Org policiesfirst decisive rule wins
  • DENY
  • DENY
  • APPROVAL
  • APPROVAL
1{
2 "name": "External drafts need review",
3 "effect": "require_approval",
4 "priority": 50,
5 "condition": {
6 "tool": "gmail.create_draft",
7 "args.to": {
8 "not_domain": "northwind.dev"
9 }
10 }
11}
try a tool call
ALLOWPrepare-level action allowed by defaultrule 7 · default

01/12 run.started · Executive Assistant

FIG 05 · architecture

One gateway in the middle of everything.

Agents are configuration (model, instructions, permitted tools, budget) on one shared runtime. Atlas is a separate product, reached only over MCP. MCP is the transport, not the boundary.

It runs on a single VPS with Docker Compose. Caddy serves the console and the API from one domain, so the session cookie is first-party and traces stream unbuffered. The database is restored from a clean snapshot every night.
People
Console
Next.js 16 · runs, traces, approvals
Reviewers
admin · builder · approver · viewer
Edge + API
Caddy
TLS · /api proxy, unbuffered
FastAPI
session cookie · rate limits · SSE traces
Runtime
Redis queue
run jobs · per-run lock
Worker · LangGraph
reason → act → await_approval
AI gateway
NIM Nemotron → Groq → Cloudflare
Tool gateway
1resolve2authorize3validate4policy5idempotency6execute7record8audit9return
the only path from an agent to an external system
Tools
Atlasp1
knowledge · MCP over HTTP
GitHubapi
REST connector · token encrypted
Gmail · Calendar · Slack · Jira · Notion
mock backends with faults
Support AIp2
ticket product · not connected yet
State
Postgres + pgvector
runs · steps · approvals · audit_log · LangGraph checkpoints · knowledge
FIG 06 · capabilities

Everything a company asks before it lets an agent act.

Which systems can it touch? Who approved that email? Why did it make 14 tool calls? Did the new model do better? What did we spend? Aegis has an answer for each one.

Approvals that survive restarts

A risky call interrupts the LangGraph run and checkpoints it to Postgres. A reviewer approves, edits the arguments, or rejects with a reason, and any worker resumes the run, hours later if needed. Approvals expire, and an expired approval counts as a rejection.

  1. interrupt
    graph pauses
  2. checkpoint
    Postgres
  3. approve
    inline or inbox
  4. resume
    any worker

MCP tools, fully governed

MCP servers (streamable HTTP or stdio) are imported as ordinary tools with a risk level. They go through the same nine checks. Bearer tokens are encrypted and never logged.

# imported from Atlas
atlas.search_knowledge read
atlas.get_document read

Live traces

Every LLM and tool call is a step with latency, tokens, cost and an error category, streamed to the trace over SSE as it happens.

Evals before you promote

Suites replay scenarios against mock tools in a sandbox. They score task completion, tool choice, argument correctness, unnecessary calls and policy compliance.

Encrypted credentials

Fernet-encrypted at rest, with a rotatable keyring. The API is write-only: reads return a masked hint like ghp_…a1b2. Secrets never reach the model or the trace.

Budgets and rate limits

Per-agent cost caps are enforced by the policy engine, plus a per-agent, per-tool call cap (30 a minute by default). HTTP limits are counted in Redis per IP and per user.

Any model

Agents are configuration on one runtime. The provider layer supports Anthropic, NVIDIA NIM (directly or through any OpenAI-compatible gateway), the Claude CLI, or a deterministic mock. The UI always shows the model that really answered.

Roles for humans

Admins, builders, approvers and viewers each see what their role allows. The API re-checks every action. The demo has one account per role.

FIG 07 · questions

Fair questions.

Short answers from the architecture notes.

Is Aegis a product I can buy?

No. It is a showcase project by Kanav Chauhan: a complete, working governance layer, built to show how agents can act on real company tools safely. Nothing here is for sale, and there is no waitlist.

Why not let the model call the tools directly?

A model can be talked into anything: a prompt injection in an email can make it want to send that email to everyone. In Aegis the model can only ask. Permission, schema, policy, approval and idempotency are plain, deterministic code that the model can't skip.

What happens when a call is denied?

Nothing reaches the external system. The agent gets a structured error such as POLICY_DENIED or PERMISSION_DENIED with the reason, and it adapts: it uses another source or tells the user. The denial is recorded in the trace and the audit log, because denials prove the guardrails work.

How can a run wait hours for an approval?

The run is a LangGraph graph. A risky call interrupts it, and the state is checkpointed to Postgres after every node. When someone approves, any worker picks the run up from that checkpoint. Approvals expire, and an expired approval is treated as a rejection.

Which model runs the demo?

NVIDIA Nemotron through NVIDIA NIM, via an AI gateway that falls back to Groq and then Cloudflare Workers AI. The agents keep their Claude model names so they run unchanged on the Anthropic API, and the UI shows the model that really served each step.

Can a retry send the same email twice?

Not through the gateway. A write gets an idempotency key, sha256(run | tool | args), which is saved before the call. If the reply is lost, the retry first checks the target system for that key. A repeat of a finished action returns the stored result instead of running again.

What can I do in the live demo?

Log in with one click as Maya (admin), Dan (builder), Priya (approver) or Sam (viewer). Run the Executive Assistant, approve or reject its actions, read traces, try policies and look at the audit log. Risky endpoints answer 403, runs are rate limited, and the data resets every night.

Watch it stop a bad call. Then approve a good one.

One click logs you in. No sign-up, and the demo data resets every night.