Policy enforcement and audit trails for AI agents. Works for any action. Open standard.
AI proposes → MAP checks policy → Allowed: execute + receipt | Blocked: deny | Risky: require approval
MAP is a firewall for AI actions. Whatever your AI agent wants to do — send emails, write to databases, call APIs, deploy infrastructure, process payments, update records — MAP enforces your rules and generates a signed receipt for every decision.
MAP is in developer preview.
- The reference TypeScript implementation is the most complete surface today.
@sidianlabs/mapis the best-supported package in the repo.- The Python and Go SDKs are preview source packages and still need more contract alignment and polish.
- The conformance harness is useful for compatibility testing, but it should still be treated as preview infrastructure.
The right expectation is: preview, but real. You can evaluate it, build against it, and learn from it today, but parts of the packaging, multi-SDK experience, and release workflow are still being tightened.
# TypeScript / Node.js (best-supported surface today)
npm install @sidianlabs/map
# Python (preview: source install today)
pip install -e packages/python
# Go (preview: source package)
go get github.com/SidianLabs/micro-agent-protocol/packages/go/mapprotoimport { map } from '@sidianlabs/map';
// Works for ANY action your AI agent takes
const agent = map({
policy: [
// Payments: require approval above $1000
{ when: 'payment.*', amount_gt: 1000, require: 'approval' },
// Database: block all writes to production
{ when: 'db.write', env: 'production', require: 'deny' },
// Infrastructure: always require approval
{ when: 'aws.*', env: 'production', require: 'approval' },
// Email: require approval for bulk sends
{ when: 'email.send', amount_gt: 100, require: 'approval' },
// Everything else: allow
{ when: '*', require: 'allow' },
],
onApprovalRequired: async ({ capability, approve }) => {
const ok = await askHuman(`Approve ${capability}?`);
if (ok) await approve();
},
});
// Register handlers for whatever your agent does
agent.can('payment.execute', async (input) => {
return await stripe.charges.create({ amount: input.amount });
});
agent.can('db.write', async (input) => {
return await db.query(input.sql, input.params);
});
agent.can('email.send', async (input) => {
return await sendgrid.send({ to: input.to, subject: input.subject });
});
agent.can('aws.ec2_start', async (input) => {
return await ec2.startInstances({ InstanceIds: [input.instance_id] });
});
// Run any capability — MAP enforces your policy automatically
const result = await agent.run('payment.execute', {
amount: 5000,
currency: 'USD',
vendor_id: 'vendor_abc',
});
// result.status → 'executed' | 'denied' | 'approval_required'
// result.output → whatever your handler returned
// result.receipt → cryptographically signed proof of what happenedThat's it. No TaskEnvelope. No AgentDescriptor. No DelegationToken. Just policy, handlers, and receipts.
AI agents are being deployed into production systems — payments, databases, HR, healthcare, infrastructure, customer data — with almost no control layer between the AI and the action.
When you give an AI assistant access to tools, the AI becomes the effective superuser over everything it can reach. If it's manipulated via prompt injection, confused by context, or just wrong, it executes the action anyway. There is no enforced checkpoint.
Three failures happen repeatedly:
- No policy gate — high-risk actions execute automatically with no checkpoint
- No audit trail — when something goes wrong, there's no verifiable record of what happened and why
- No approval workflow — humans can't review and approve actions before they execute
MAP solves all three, for any action your AI agent takes.
flowchart TD
AI["AI System
ChatGPT, Claude, Copilot, your agent
'Transfer $5,000 to vendor_abc'"]
AI -->|Intent| Policy["MAP Policy Engine
Rule: payment.* + amount > 1000 → require_approval
Rule: db.write + env=production → deny"]
Policy -->|ALLOW| Execute["Execute Adapter"]
Policy -->|REQUIRE_APPROVAL| Notify["Notify approver
(webhook/Slack)
Human reviews and approves
MAP re-evaluates → Execute"]
Execute --> Receipt["Signed Receipt
{ receipt_id, action, policy_checks, timestamp, sig }
Cryptographically verifiable. Tamper-evident."]
Notify -->|Approved| Execute
Policy is a JSON document. It lives outside your code. Change it at runtime without restarting.
const agent = map({
policy: [
// Payments: require approval above $1000
{ when: 'payment.*', amount_gt: 1000, require: 'approval' },
// Database: block all writes to production
{ when: 'db.write', env: 'production', require: 'deny' },
// Infrastructure: always require approval in production
{ when: 'aws.*', env: 'production', require: 'approval' },
{ when: 'k8s.*', env: 'production', require: 'approval' },
// Critical risk: always require approval regardless of capability
{ when: '*', risk: 'critical', require: 'approval' },
// Services: block non-service requesters from internal APIs
{ when: 'internal.*', requester_type: 'user', require: 'deny' },
// Everything else: allow
{ when: '*', require: 'allow' },
],
});{
"version": "1.0",
"rules": [
{
"id": "high-value-payment",
"capability": "payment.*",
"condition": { "gt": ["input.amount", 1000] },
"action": "require_approval"
},
{
"id": "production-db-write",
"capability": "db.write",
"condition": { "eq": ["constraints.environment", "production"] },
"action": "deny"
}
]
}const agent = map({ policy: './policy.json' });// No restart needed
agent.setPolicy([
{ when: '*', require: 'deny' } // lockdown
]);const check = agent.check('payment.execute', { amount: 5000 });
// { action: 'require_approval', reason: 'Rule: high-value-payment' }When policy returns require_approval, MAP stops execution and notifies your approver.
const agent = map({
policy: [
{ when: 'payment.*', amount_gt: 1000, require: 'approval' },
],
onApprovalRequired: async ({ capability, input_summary, approval_reference, approve }) => {
// Send to Slack, email, your ticketing system — whatever you use
await slack.send(`Approve ${capability}? Amount: ${input_summary.amount}`);
// When the human approves, call approve()
// (or store approval_reference and call agent.approve(ref) later)
const approved = await waitForHumanDecision();
if (approved) await approve();
},
});Or handle it manually:
const result = await agent.run('payment.execute', { amount: 5000 });
if (result.status === 'approval_required') {
// Store result.approval_reference, notify approver
// Later, when approved:
const approved = await agent.approve(result.approval_reference);
}MAP ships with adapters for common capabilities:
import { map, HttpAdapter, PaymentExecuteAdapter, DbReadAdapter } from '@sidianlabs/map';
const agent = map({ policy: [...] });
// HTTP requests (SSRF protection built in)
agent.can('http.request', new HttpAdapter());
// Stripe-compatible payments (simulation mode without API key)
agent.can('payment.execute', new PaymentExecuteAdapter());
// PostgreSQL reads (SELECT-only, output minimization)
agent.can('db.read', new DbReadAdapter());Or build your own:
agent.can('crm.update', async (input, context) => {
await salesforce.update(input.record_id, input.fields);
return { updated: true, record_id: input.record_id };
});Every decision generates a cryptographically signed receipt. Tamper-evident. Independently verifiable.
{
"receipt_id": "receipt:intent_abc123:1747123456789",
"intent_id": "intent_abc123",
"capability": "payment.execute",
"action": "executed",
"timestamp": "2026-05-15T10:00:00Z",
"status": "ok",
"signature": "eyJhbGciOiJIUzI1NiIsImtpZCI6Im1hcC1kZXYta2V5LTEiLCJ0eXAiOiJNQVBTSUcifQ..."
}For production deployments, run MAP as an HTTP server:
MAP_POLICY_PATH=./policy.json \
MAP_APPROVAL_WEBHOOK_URL=https://your-app.com/approvals \
MAP_SIGNING_SECRET=your-secret \
npm run dev:server# Dispatch an intent
curl -X POST http://localhost:8787/dispatch \
-H "Content-Type: application/json" \
-d '{ "capability": "payment.execute", "envelope": { ... } }'
# Get current policy
curl http://localhost:8787/policy
# Hot-swap policy
curl -X POST http://localhost:8787/policy -d @policy.json
# Query audit trail
curl http://localhost:8787/audit-eventsThe EU AI Act requires audit trails for high-risk AI systems (August 2, 2026 deadline).
MAP provides:
- [Yes] Tamper-evident audit event log (
GET /audit-events) - [Yes] Cryptographically signed execution receipts
- [Yes] Hash-chained audit checkpoints (verifiable integrity)
- [Yes] Policy decision records (what rule triggered, why)
- [Yes] Human oversight via approval workflow
- [Yes] Export-ready audit data
Policy evaluation is sub-millisecond. MAP adds essentially zero overhead.
| Scenario | Latency | Throughput |
|---|---|---|
| Policy eval (5 rules) | ~1µs | 1.2M/sec |
| Policy eval (100 rules) | ~20µs | 50K/sec |
| Full execution (no I/O) | ~4µs | 256K/sec |
| Policy hot-swap | ~6µs | instant |
Compare: AI-in-loop approaches average 10,000–15,000ms. MAP is 3,000–10,000x faster.
| Profile | Use Case | Signed Requests | Tenant Required | Key Algorithm |
|---|---|---|---|---|
open |
Development | Optional | Optional | HS256 or RS256 |
verified |
Staging/Production | Required | Optional | RS256 only |
regulated |
Finance/Healthcare | Required | Required | RS256 only |
MAP_DEPLOYMENT_PROFILE=regulated| Language | Package | Status |
|---|---|---|
| TypeScript | @sidianlabs/map |
Stable |
| Go | github.com/SidianLabs/micro-agent-protocol/packages/go/mapproto |
Stable |
| Python | mapprotocol |
Preview |
The protocol specification is at spec/MAP-SPEC-v1.md.
MAP is an open protocol. Anyone can implement it in any language. The TypeScript reference server is one implementation.
| Variable | Default | Description |
|---|---|---|
PORT |
8787 |
Server port |
MAP_DEPLOYMENT_PROFILE |
open |
open, verified, or regulated |
MAP_POLICY_PATH |
— | Path to JSON policy file |
MAP_SIGNING_SECRET |
demo key | HMAC signing secret |
MAP_APPROVAL_WEBHOOK_URL |
— | Default webhook for approval notifications |
MAP_SERVER_BASE_URL |
— | Server base URL (used in approval payloads) |
MAP_ADMIN_TOKEN |
— | Token for admin endpoints |
MAP_REQUIRE_TENANT |
false |
Require tenant_id on all requests |
MAP_PAYMENT_API_KEY |
— | Payment provider API key |
MAP_DB_CONNECTION_STRING |
— | PostgreSQL connection string |
Apache 2.0 — LICENSE
See CONTRIBUTING.md. Major changes require a MAP Enhancement Proposal (MEP) in rfcs/.
Report vulnerabilities via GitHub Security Advisory. See SECURITY.md.
MAP is built by Sidian Labs. Maintained by @BHAWESHBHASKAR.