Your AI assistants stop talking to HR, finance and Drive directly. They talk to Aggrete, and Aggrete talks to those systems. Because it is the only way in, nothing gets around the rules, and because assistants already know how to talk to it, nobody installs anything on their laptop.
Every request is checked against two things: your rules, and what that person has already looked up recently. A rule makes the decision, not another AI, so the same request always gets the same answer and you can always see why.
Your systems only accept requests that come from Aggrete, and Aggrete holds the logins to them, never the person or their assistant. A console, if you want one, only reads the two files Aggrete writes.
The full diagram, the Drive connector and the sign-in flow are in the README.
Eight kinds of rule, each for a different way a request can go wrong. Before means it is decided before anything is fetched, so the data never moves. After means it can only be judged once the answer exists, so the answer is withheld. Any rule can be limited to certain people or dates.
| rule | when | what it does |
|---|---|---|
| domain_join | before | Stops harmless answers from adding up to a harmful one.The budget is fine, the staff list is fine, the rota is fine. Together, about the same people, they name who is leaving. The last piece is refused.Refuses the call that would complete a forbidden set of domains for one person (e.g. personnel + budget + rotation), with entity overlap required by default. |
| domain_block | before | A place assistants never go.Documents under legal hold stay closed to every assistant, whoever is asking.A domain that assistants may never reach (legal hold, privileged material). |
| wall | before | Only these people, and only until this date.The restructuring plan is for the planning team until the announcement. For everyone else the tool does not even appear.Who may reach a domain, and until when: embargoes, investigation walls, privilege, restricted health/absence data. |
| min_group | after | A figure about a handful of people is really about one person.Average pay for 200 engineers is a statistic. Average pay for two executives is their salaries.Aggregate-only answers: a result naming fewer than k people is treated as one person's data. |
| self_comparison | after | Your record or your team's, but not yours next to theirs.Approving your team's timesheets is your job. Lining yours up against a colleague's is not.The requester's own record placed next to colleagues' in the same domain, the precondition for benchmarking teammates. |
| entity_budget | after | Nobody needs four thousand customer records in an afternoon.Looking up accounts is selling. Looking up all of them is an export, even though no single lookup was wrong.Caps the number of distinct people one user may accumulate in a domain over the window. |
| flow | before | After reading a stranger's text, nothing leaves.An assistant that has just read a web page or an outside email cannot send, post or share until that task is over, so hidden instructions have nothing to steal.Prompt-injection shield: once a session has read untrusted content, it may not reach an egress domain. Any write counts as egress. |
| arg_match | before | The same button, allowed or not, depending on what is asked of it.Export my team's accounts: fine. Export the whole company's: refused. Same tool, different request.Decides a call from its arguments, not just its kind: allow an export scoped to your own team, refuse the same export scoped to the whole company. Operators: equals, in, regex, gt, lt, exists, missing. |
Anything that changes or sends something (create, update, upload, post, send) counts as a way out of the building, and a rule can apply to those alone. Rules come grouped into protection packs you switch on and off. Every rule can do one of three things when it fires: warn (let it through and note it, the safe way to start), refuse, or ask a person: the request waits, the rule's owner signs off, and it goes through for a few hours with their name on the record. In the policy file these are alert, deny and approve; a rule targets writes only with applies: write; every rule must ship with a test that passes and a test that is refused or held.
The rules decide what a request may add up to. These are the safeguards that run around every request. Each is a fixed check, not a judgment call, each is switched on in the config, and each writes to the same record.
| safeguard | what it does |
|---|---|
| check | Ask before you act."Could I pull these three things?" gets a yes or no, the rule, and how to proceed, without touching any data.Ask whether a sequence of calls would be allowed before running any of them: the decision, the rule, the clause and the fix, with nothing fetched. A built-in aggrete__check tool. |
| tool_integrity | Notices when a tool quietly changes, or lies about itself.A connector that was approved last month and behaves differently today is flagged. One with hidden instructions in its description is blocked.Fingerprint every upstream tool on first sight; flag a later change to its description or schema (a rug pull), and scan descriptions for hidden instructions (poisoning). Alert or block. |
| rate_limit | A speed limit per person.Stops a runaway assistant from making thousands of calls, and the bill that comes with them.A per-user ceiling on calls per window, shared across replicas via Redis. A denial-of-wallet and abuse control. |
| scan_inbound | Passwords and keys never travel onward.If someone pastes a secret into a request, it is stopped or masked before any system sees it.Scan tool arguments for credential-shaped strings and block or mask them before they reach an upstream. |
| audit_forward | Your security team sees it where they already look.Every decision is copied to their monitoring tools as it happens. The sealed local record stays the official one.Stream each audit row to Splunk, Elastic, Datadog or syslog as it is written, off the hot path. The hash-chained local log stays the system of record. |
| approvals | A person can sign off.Instead of a flat no, the request waits, the rule's owner gets a message, and a yes lasts a few hours with their name on it.Human in the loop. A rule with action: approve holds the call, notifies by Slack-compatible webhook or command, and waits. Decide with aggrete approve <id>, POST /approvals/<id>/approve using the approver's own token, or the console. Configured approvers and the rule's owner may decide. |
| metrics | Dashboards and health checks.How much was allowed, refused and held, and whether every connected system is reachable, in the formats monitoring tools read.Prometheus /metrics derived from the same rows as the audit log, so the graphs and the record agree; /healthz and /readyz for the platform; OTLP export to any OpenTelemetry collector; OCSF API Activity events for the SIEM. |
| conformance | A test anyone can rerun.One command proves it does what this page says, and maps the results onto the security checklists buyers ask about.aggrete conformance runs sixteen checks against the real components and maps them onto the OWASP MCP Top 10, the OWASP Agentic Top 10, CoSAI and AIUC-1. --url runs the same scenarios black-box against any gateway. See the report. |
| aggrete-lint | Catches rule mistakes before they go live.A rule that would never fire, an embargo that has already expired, a serious rule that only warns.Static checks on the policy for fail-open and dead rules: a critical rule that only alerts, an expired embargo, an unreachable domain. Exits non-zero for CI. |
Some companies already route their assistants through a central gateway. You do not have to put Aggrete in front of it as one more stop. The gateway can simply ask Aggrete, before and after each request, "is this allowed?", and gets the same answer, the same masking and the same record as if Aggrete were in the path.
| if you run | how it connects |
|---|---|
| agentgateway | Plugs into agentgateway's own policy hook, so it sees every request and every answer.aggrete extmcp --port 9001 serves agentgateway's native ExtMCP hook over gRPC: both phases, tools/list filtering, rewritten arguments and redacted results. One mcpGuardrails processor in the gateway config, with metadata: {user: jwt.email, tool: mcp.tool.name}. pip install "aggrete[agentgateway]". |
| anything | A simple web address any system can ask: here is who, which tool, and what for. Allowed?POST /v1/decide with a subject, a tool and its arguments (request phase), then the result (response phase). Answers allow, deny, hold or rewrite. |
| an AuthZEN PEP | The industry-standard way to ask an authorization question, so tools that already speak it need nothing custom.POST /access/v1/evaluation, OpenID AuthZEN 1.0 with the MCP mapping: subject.id, resource.id = tool, arguments in resource.properties. |
| Docker MCP Gateway | Two hooks Docker's gateway already offers: one before a request, one after.Two http interceptors, before and after, at /adapters/docker/*. A refusal comes back as the tool result; a redaction replaces it. |
| IBM ContextForge | Loads as a ContextForge plugin.python -m aggrete.adapters as an external plugin for tool_pre_invoke and tool_post_invoke. |
One condition: the gateway has to ask about every request, before and after, and say who it is for. What it does not ask about cannot be governed. Details: docs/ADAPTERS.md.