Documentation Index Fetch the complete documentation index at: https://docs.swarmd.ai/llms.txt
Use this file to discover all available pages before exploring further.
Policy Configuration
Policy groups control what flows through the relay. Each policy group is a Rego file (Open Policy Agent’s policy language) that defines which middleware rules to apply. Rego gives you conditional logic, time-based gating, and the ability to combine multiple rules in a single group.
Policy groups are applied through a two-step process:
Create a policy group with Rego source that defines the middleware rules
Create a policy binding that attaches the group to a tenant, agent, or subscription
How the Middleware Pipeline Works
Source Agent -> [REQUEST_FROM_SOURCE] -> Relay -> [REQUEST_TO_SINK] -> Sink Agent
|
Source Agent <- [RESPONSE_TO_SOURCE] <- Relay <- [RESPONSE_FROM_SINK] <- Sink Agent
Every middleware rule specifies which legs of this flow it applies to via enabledLegs:
Leg Direction Example use requestFromSourceSource -> Relay Scan outgoing requests for PII before they leave requestToSinkRelay -> Sink Restrict which skills can be invoked on the target agent responseFromSinkSink -> Relay Detect sensitive data in agent responses responseToSourceRelay -> Source Mask data before returning to the caller
At least one leg must be enabled. The API will reject a policy where all four legs are false.
How Evaluation Works
When a message flows through the relay:
The system finds all active bindings that match the current tenant, agent, and subscription
For each binding, the associated policy group’s Rego file is evaluated with the request context as input
The Rego file returns a list of middleware configs to execute
Each middleware config is instantiated and executed in the specified order
If any middleware returns BLOCK, the message is rejected
Bindings are evaluated in priority order (lower number = higher priority). Within a group, middlewares are ordered by their order field.
Rego File Structure
Every policy group’s Rego file must follow this structure:
package swarmd.policy
import rego.v1
middlewares contains {
"name": "Human-readable name for this rule",
"type": "MIDDLEWARE_TYPE",
"order": 0,
"config": {
"type": "MIDDLEWARE_TYPE",
...type-specific fields...
}
}
Field Required Description nameYes A human-readable name for this rule (shown in audit logs) typeYes One of: SKILL_RESTRICTION, REGEX_DETECTION, PRESIDIO_DETECTION, COMPREHEND_DETECTION, RATE_LIMIT, HITL orderYes Evaluation order within the group (lower = first) configYes Type-specific configuration (see sections below) config.typeYes Must match the outer type field config.enabledLegsYes Which relay legs this rule applies to
Middleware Types
Skill Restriction
Control which skills an agent is allowed to use. You can allowlist or blocklist skills by ID, name, or tag.
package swarmd.policy
import rego.v1
middlewares contains {
"name": "Block filesystem access",
"type": "SKILL_RESTRICTION",
"order": 0,
"config": {
"type": "SKILL_RESTRICTION",
"mode": "BLOCKLIST",
"skillNames": ["read_file", "write_file", "delete_file"],
"skillIds": [],
"skillTags": ["filesystem"],
"action": "BLOCK",
"enabledLegs": {
"requestFromSource": true,
"requestToSink": true,
"responseFromSink": false,
"responseToSource": false
}
}
}
Field Required Description modeYes ALLOWLIST (only these skills permitted) or BLOCKLIST (these skills denied)actionYes LOG, WARN, or BLOCKskillIdsNo Set of skill IDs to match skillNamesNo Set of skill names to match skillTagsNo Set of skill tags to match
At least one of skillIds, skillNames, or skillTags must be non-empty. Use ALLOWLIST mode for high-security environments where agents should only use explicitly approved skills.
Regex Detection
Match message content against a regular expression.
package swarmd.policy
import rego.v1
middlewares contains {
"name": "Block AWS access keys",
"type": "REGEX_DETECTION",
"order": 0,
"config": {
"type": "REGEX_DETECTION",
"pattern": {
"regex": "AKIA[0-9A-Z]{16}",
"action": "BLOCK"
},
"enabledLegs": {
"requestFromSource": true,
"requestToSink": true,
"responseFromSink": true,
"responseToSource": true
}
}
}
Field Required Description pattern.regexYes Java-compatible regular expression (validated at creation time) pattern.actionYes LOG, MASK, BLOCK, WARN, or HUMAN_REVIEW_REQUIRED
PII Detection (Presidio)
Detect personally identifiable information using Microsoft Presidio.
package swarmd.policy
import rego.v1
middlewares contains {
"name": "Mask credit card numbers",
"type": "PRESIDIO_DETECTION",
"order": 0,
"config": {
"type": "PRESIDIO_DETECTION",
"entity": {
"type": "CREDIT_CARD",
"scoreThreshold": 0.8,
"action": "MASK"
},
"enabledLegs": {
"requestFromSource": true,
"requestToSink": true,
"responseFromSink": true,
"responseToSource": true
}
}
}
Field Required Description entity.typeYes Presidio entity type (e.g. CREDIT_CARD, US_SSN, EMAIL_ADDRESS, PERSON, PHONE_NUMBER) entity.scoreThresholdYes Confidence threshold between 0.0 and 1.0 entity.actionYes LOG, MASK, BLOCK, WARN, or HUMAN_REVIEW_REQUIRED
Supported Presidio Entity Types
Entity Type Description CREDIT_CARDCredit card numbers CRYPTOCryptocurrency wallet addresses EMAIL_ADDRESSEmail addresses IBAN_CODEInternational bank account numbers IP_ADDRESSIP addresses LOCATIONPhysical locations PERSONPerson names PHONE_NUMBERPhone numbers MEDICAL_LICENSEMedical licence numbers US_BANK_NUMBERUS bank account numbers US_DRIVER_LICENSEUS driver licence numbers US_ITINUS Individual Taxpayer Identification Numbers US_PASSPORTUS passport numbers US_SSNUS Social Security Numbers UK_NHSUK National Health Service numbers ES_NIFSpanish tax identification numbers IT_FISCAL_CODEItalian fiscal codes IT_DRIVER_LICENSEItalian driver licence numbers IT_VAT_CODEItalian VAT codes IT_PASSPORTItalian passport numbers IT_IDENTITY_CARDItalian identity card numbers SG_NRIC_FINSingapore NRIC/FIN numbers AU_ABNAustralian Business Numbers AU_ACNAustralian Company Numbers AU_TFNAustralian Tax File Numbers AU_MEDICAREAustralian Medicare numbers IN_PANIndian PAN card numbers IN_AADHAARIndian Aadhaar numbers IN_VEHICLE_REGISTRATIONIndian vehicle registration numbers
PII Detection (AWS Comprehend)
Detect PII using AWS Comprehend .
package swarmd.policy
import rego.v1
middlewares contains {
"name": "Block SSN exposure",
"type": "COMPREHEND_DETECTION",
"order": 0,
"config": {
"type": "COMPREHEND_DETECTION",
"entity": {
"type": "SSN",
"scoreThreshold": 0.9,
"action": "BLOCK"
},
"enabledLegs": {
"requestFromSource": false,
"requestToSink": false,
"responseFromSink": true,
"responseToSource": true
}
}
}
Field Required Description entity.typeYes Comprehend entity type (e.g. CREDIT_DEBIT_NUMBER, NAME, SSN, EMAIL, ADDRESS) entity.scoreThresholdYes Confidence threshold between 0.0 and 1.0 entity.actionYes LOG, MASK, BLOCK, WARN, or HUMAN_REVIEW_REQUIRED
Rate Limiting
Throttle request volume. Three strategies are available:
Sliding Window:
middlewares contains {
"name": "100 requests per minute",
"type": "RATE_LIMIT",
"order": 0,
"config": {
"type": "RATE_LIMIT",
"strategy": {
"strategyType": "SLIDING_WINDOW",
"maxRequests": 100,
"windowSizeSeconds": 60
},
"enabledLegs": {
"requestFromSource": true,
"requestToSink": false,
"responseFromSink": false,
"responseToSource": false
}
}
}
Token Bucket:
"strategy" : {
"strategyType" : "TOKEN_BUCKET" ,
"bucketCapacity" : 100 ,
"refillRatePerSecond" : 10.0
}
Leaky Bucket:
"strategy" : {
"strategyType" : "LEAKY_BUCKET" ,
"bucketCapacity" : 50 ,
"leakRatePerSecond" : 5.0
}
Human-in-the-Loop (HITL)
Pause messages for manual human approval before they reach the target agent.
middlewares contains {
"name": "Require human approval",
"type": "HITL",
"order": 0,
"config": {
"type": "HITL",
"enabledLegs": {
"requestFromSource": false,
"requestToSink": true,
"responseFromSink": false,
"responseToSource": false
}
}
}
See the Human-in-the-Loop tutorial for the complete approval workflow.
Conditional Logic with Rego
This is where OPA’s power comes in. Instead of static rules, you can use Rego’s if statements to activate rules conditionally based on the request context, time of day, day of week, and more.
Available Input Context
Every Rego evaluation receives this input:
{
"tenantId" : "uuid" ,
"sourceAgentId" : "uuid" ,
"sourceUserId" : "uuid" ,
"sinkAgentId" : "uuid" ,
"timestamp" : "2026-04-03T14:30:00Z" ,
"timestampNanos" : 1775225400000000000
}
Field Type Description tenantIdUUID string The tenant executing the policy sourceAgentIdUUID string The agent sending the message (null for user sources) sourceUserIdUUID string The user sending the message (null for agent sources) sinkAgentIdUUID string The agent receiving the message timestampRFC 3339 string Evaluation time (usable with time.parse_rfc3339_ns()) timestampNanosinteger Evaluation time as epoch nanoseconds (usable with time.clock(), time.weekday(), etc.)
Time-Based Activation
Activate rules only during specific time windows using OPA’s built-in time.* functions with input.timestampNanos:
package swarmd.policy
import rego.v1
# HITL review only during business hours (Mon-Fri 09:00-17:00 UTC)
middlewares contains {
"name": "Business hours HITL",
"type": "HITL",
"order": 0,
"config": {
"type": "HITL",
"enabledLegs": {
"requestFromSource": false,
"requestToSink": true,
"responseFromSink": false,
"responseToSource": false
}
}
} if {
hour := time.clock(input.timestampNanos)[0]
hour >= 9
hour < 17
day := time.weekday(input.timestampNanos)
day != "Saturday"
day != "Sunday"
}
Combining Always-On and Conditional Rules
package swarmd.policy
import rego.v1
# Always block dangerous tools (no condition)
middlewares contains {
"name": "Block shell commands",
"type": "SKILL_RESTRICTION",
"order": 0,
"config": {
"type": "SKILL_RESTRICTION",
"mode": "BLOCKLIST",
"skillNames": ["shell_command", "execute_code"],
"skillIds": [],
"skillTags": [],
"action": "BLOCK",
"enabledLegs": {
"requestFromSource": true,
"requestToSink": true,
"responseFromSink": false,
"responseToSource": false
}
}
}
# Stricter rate limiting outside business hours
middlewares contains {
"name": "After-hours rate limit",
"type": "RATE_LIMIT",
"order": 1,
"config": {
"type": "RATE_LIMIT",
"strategy": {
"strategyType": "SLIDING_WINDOW",
"maxRequests": 10,
"windowSizeSeconds": 60
},
"enabledLegs": {
"requestFromSource": true,
"requestToSink": false,
"responseFromSink": false,
"responseToSource": false
}
}
} if {
hour := time.clock(input.timestampNanos)[0]
hour < 9
}
middlewares contains {
"name": "After-hours rate limit",
"type": "RATE_LIMIT",
"order": 1,
"config": {
"type": "RATE_LIMIT",
"strategy": {
"strategyType": "SLIDING_WINDOW",
"maxRequests": 10,
"windowSizeSeconds": 60
},
"enabledLegs": {
"requestFromSource": true,
"requestToSink": false,
"responseFromSink": false,
"responseToSource": false
}
}
} if {
hour := time.clock(input.timestampNanos)[0]
hour >= 17
}
# HITL for all weekend requests
middlewares contains {
"name": "Weekend HITL",
"type": "HITL",
"order": 2,
"config": {
"type": "HITL",
"enabledLegs": {
"requestFromSource": false,
"requestToSink": true,
"responseFromSink": false,
"responseToSource": false
}
}
} if {
day := time.weekday(input.timestampNanos)
day == "Saturday"
}
middlewares contains {
"name": "Weekend HITL",
"type": "HITL",
"order": 2,
"config": {
"type": "HITL",
"enabledLegs": {
"requestFromSource": false,
"requestToSink": true,
"responseFromSink": false,
"responseToSource": false
}
}
} if {
day := time.weekday(input.timestampNanos)
day == "Sunday"
}
Rego uses AND logic within a single if block (all conditions must be true). For OR logic, define multiple middlewares contains blocks with the same middleware config but different conditions - if any block matches, the middleware is included.
Negation
Apply rules when a condition is NOT met:
# Strict PII scanning outside business hours
middlewares contains {
"name": "After-hours PII scan",
"type": "PRESIDIO_DETECTION",
"order": 0,
"config": { ... }
} if {
hour := time.clock(input.timestampNanos)[0]
not hour >= 9
}
Common Time-Gating Patterns
Business hours only (Mon-Fri 09:00-17:00 UTC):
} if {
hour := time.clock(input.timestampNanos)[0]
hour >= 9
hour < 17
day := time.weekday(input.timestampNanos)
day != "Saturday"
day != "Sunday"
}
Weekdays only:
} if {
day := time.weekday(input.timestampNanos)
day != "Saturday"
day != "Sunday"
}
Date-range / maintenance window:
} if {
# Active from 1 May 2026 onwards
input.timestampNanos >= time.parse_rfc3339_ns("2026-05-01T00:00:00Z")
}
} if {
# Active until end of Q2 2026
input.timestampNanos < time.parse_rfc3339_ns("2026-07-01T00:00:00Z")
}
Agent-specific conditions:
} if {
input.sinkAgentId == "550e8400-e29b-41d4-a716-446655440000"
}
Future Possibilities
Rego supports many more patterns that can be used as we enrich the input context:
Tenant-specific overrides - different rules per tenant ID
Agent metadata matching - rules based on agent properties like name and group
Dynamic config values - threshold values computed from input data
Policy Actions
Every detection rule requires an action that determines what happens when a match is found:
Action Behaviour LOGRecord the detection in the audit log. Message continues normally. WARNLog an advisory warning. Message continues normally. MASKRedact the matched content before forwarding the message. BLOCKReject the message entirely. The sender receives an error. HUMAN_REVIEW_REQUIREDPause the message and create a HITL approval request.
Creating a Policy Group
curl -X POST https://api.swarmd.ai/relay/v1/policy-groups \
-H "Content-Type: application/json" \
-H "Authorization: Bearer $SWARMD_TOKEN " \
-d '{
"name": "PII Protection Suite",
"description": "Detect and mask common PII types",
"regoSource": "package swarmd.policy\n\nimport rego.v1\n\nmiddlewares contains {\n \"name\": \"Mask credit cards\",\n \"type\": \"PRESIDIO_DETECTION\",\n \"order\": 0,\n \"config\": {\n \"type\": \"PRESIDIO_DETECTION\",\n \"entity\": {\n \"type\": \"CREDIT_CARD\",\n \"scoreThreshold\": 0.8,\n \"action\": \"MASK\"\n },\n \"enabledLegs\": {\n \"requestFromSource\": true,\n \"requestToSink\": true,\n \"responseFromSink\": true,\n \"responseToSource\": true\n }\n }\n}\n\nmiddlewares contains {\n \"name\": \"Mask SSNs\",\n \"type\": \"PRESIDIO_DETECTION\",\n \"order\": 1,\n \"config\": {\n \"type\": \"PRESIDIO_DETECTION\",\n \"entity\": {\n \"type\": \"US_SSN\",\n \"scoreThreshold\": 0.7,\n \"action\": \"MASK\"\n },\n \"enabledLegs\": {\n \"requestFromSource\": true,\n \"requestToSink\": true,\n \"responseFromSink\": true,\n \"responseToSource\": true\n }\n }\n}",
"primaryUserId": "YOUR_USER_ID",
"secondaryUserId": "BACKUP_USER_ID"
}'
The Rego source is validated before saving:
Rego syntax is checked
Each middleware config is validated against its type-specific schema
Invalid configs are rejected with detailed error messages
Testing Before Saving
Use the evaluate endpoint to dry-run your Rego without creating a group:
curl -X POST https://api.swarmd.ai/relay/v1/policy-groups/evaluate \
-H "Content-Type: application/json" \
-H "Authorization: Bearer $SWARMD_TOKEN " \
-d '{
"regoSource": "YOUR_REGO_SOURCE_HERE"
}'
For time-gated policies, pass a timestamp to test at a specific point in time. When omitted, the current server time is used:
curl -X POST https://api.swarmd.ai/relay/v1/policy-groups/evaluate \
-H "Content-Type: application/json" \
-H "Authorization: Bearer $SWARMD_TOKEN " \
-d '{
"regoSource": "YOUR_REGO_SOURCE_HERE",
"timestamp": "2026-04-07T10:30:00Z"
}'
Policy Bindings
Bindings attach a policy group to a scope. Three levels are available:
Level Scope Use case TENANTAll agents in your tenant Organisation-wide compliance rules AGENTA specific agent Rules for a particular agent regardless of who calls it SUBSCRIPTIONA specific source -> sink pair Fine-grained control over a single communication path
When multiple bindings apply to a message, they are evaluated in priority order (lower number = higher priority). Within each binding’s policy group, middlewares execute in order field sequence. All matching middlewares from all applicable bindings are applied.
Evaluation Order
Binding Priority 0 (TENANT) -> Group A Rego -> [middleware order 0, 1, 2]
Binding Priority 1 (AGENT) -> Group B Rego -> [middleware order 0, 1]
Binding Priority 2 (SUBSCRIPTION) -> Group C Rego -> [middleware order 0]
All middlewares from all matching bindings execute in this sequence. If any middleware returns BLOCK, the chain short-circuits and the message is rejected.
Create Bindings
Tenant-level (applies to all agents):
curl -X POST https://api.swarmd.ai/relay/v1/policy-bindings \
-H "Content-Type: application/json" \
-H "Authorization: Bearer $SWARMD_TOKEN " \
-d '{
"groupId": "GROUP_ID",
"groupVersion": "1.0.0",
"bindingLevel": "TENANT",
"priority": 0
}'
Agent-level (applies to a specific agent):
curl -X POST https://api.swarmd.ai/relay/v1/policy-bindings \
-H "Content-Type: application/json" \
-H "Authorization: Bearer $SWARMD_TOKEN " \
-d '{
"groupId": "GROUP_ID",
"groupVersion": "1.0.0",
"bindingLevel": "AGENT",
"agentId": "AGENT_ID",
"priority": 10
}'
Subscription-level (applies to a specific source -> sink path):
curl -X POST https://api.swarmd.ai/relay/v1/policy-bindings \
-H "Content-Type: application/json" \
-H "Authorization: Bearer $SWARMD_TOKEN " \
-d '{
"groupId": "GROUP_ID",
"groupVersion": "1.0.0",
"bindingLevel": "SUBSCRIPTION",
"sourceAgentId": "SOURCE_AGENT_ID",
"sinkAgentId": "SINK_AGENT_ID",
"priority": 20
}'
Versioning
Both policy groups and bindings are versioned using semantic versioning (e.g. 1.0.0, 2.0.0).
Updating a group creates a new version. The old version is disabled automatically.
Upgrading a binding points it to the latest group version via POST /v1/policy-bindings/{id}/upgrade.
Version history is available via GET /v1/policy-groups/{id}/history.
Ownership
Every policy group has a primary owner and an optional secondary owner (escalation contact). Ownership can be transferred via POST /v1/policy-groups/{id}/transfer-ownership.
Example: Full Setup
# 1. Create a policy group with Rego
GROUP_ID = $( curl -s -X POST https://api.swarmd.ai/relay/v1/policy-groups \
-H "Content-Type: application/json" \
-H "Authorization: Bearer $SWARMD_TOKEN " \
-d '{
"name": "Security Baseline",
"description": "Block dangerous tools and mask PII",
"regoSource": "package swarmd.policy\n\nimport rego.v1\n\nmiddlewares contains {\n \"name\": \"Block shell commands\",\n \"type\": \"SKILL_RESTRICTION\",\n \"order\": 0,\n \"config\": {\n \"type\": \"SKILL_RESTRICTION\",\n \"mode\": \"BLOCKLIST\",\n \"skillNames\": [\"shell_command\", \"execute_code\"],\n \"skillIds\": [],\n \"skillTags\": [],\n \"action\": \"BLOCK\",\n \"enabledLegs\": {\"requestFromSource\": true, \"requestToSink\": true, \"responseFromSink\": false, \"responseToSource\": false}\n }\n}\n\nmiddlewares contains {\n \"name\": \"Mask email addresses\",\n \"type\": \"PRESIDIO_DETECTION\",\n \"order\": 1,\n \"config\": {\n \"type\": \"PRESIDIO_DETECTION\",\n \"entity\": {\"type\": \"EMAIL_ADDRESS\", \"scoreThreshold\": 0.7, \"action\": \"MASK\"},\n \"enabledLegs\": {\"requestFromSource\": true, \"requestToSink\": true, \"responseFromSink\": true, \"responseToSource\": true}\n }\n}",
"primaryUserId": "YOUR_USER_ID"
}' | jq -r '.groupId' )
echo "Created group: $GROUP_ID "
# 2. Bind to your tenant
curl -X POST https://api.swarmd.ai/relay/v1/policy-bindings \
-H "Content-Type: application/json" \
-H "Authorization: Bearer $SWARMD_TOKEN " \
-d "{
\" groupId \" : \" $GROUP_ID \" ,
\" groupVersion \" : \" 1.0.0 \" ,
\" bindingLevel \" : \" TENANT \" ,
\" priority \" : 0
}"
That’s it - two API calls instead of four. The Rego file contains all your rules.
Next Steps
Human-in-the-Loop Set up manual approval workflows for sensitive operations.
Monitoring & Audit View policy enforcement events and audit trails.