You already know your AI coding agents can write code. The hard part is stopping them from merging unsafe or non-compliant changes while you’re juggling ten.
You already know your AI coding agents can write code. The hard part is stopping them from merging unsafe or non-compliant changes while you’re juggling ten sessions at once.
This walkthrough shows how to turn coding standards, security rules, and compliance constraints into policy checks that every agent must pass before anything lands.
It’s a companion to the broader pillar: AI coding agent orchestration: the complete guide for multi-agent development.
You’ll set up an orchestration layer that enforces:
Concretely, you’ll:
All examples assume:
Agents are good at “how to implement X”. Policies are for “whether X is allowed.”
Start by writing down specific guardrails:
Then assign each guardrail to one of three buckets:
Write this down as a simple table before touching code. This is your policy spec.
Now turn the spec into something the orchestrator and CI can execute.
The practical pattern is: OPA (Open Policy Agent) + Rego as a decision engine, fed by CI and the orchestrator.
Decisions need structured input. For an AI agent change, you typically have:
{
"repo": "payments-service",
"branch": "feature/agent-update-123",
"author": "ai-agent-claude",
"files": [
{ "path": "src/payments/handler.py", "changed_lines": 42 },
{ "path": "src/payments/sql_queries.sql", "changed_lines": 10 }
],
"tests": {
"passed": true,
"coverage_delta": -2.5
},
"security_scan": {
"status": "fail",
"critical_vulns": 1,
"xss_findings": 2
},
"license_scan": {
"status": "pass"
},
"agent": {
"id": "claude-code-1",
"role": "worker",
"orchestrator_session": "orchestrator-42"
}
}
Your job: make sure your CI pipeline can produce this JSON and hand it to OPA.
Create policy/agent-change.rego:
package ai.agent.change
# Entry point: should this change be allowed to merge?
default allow := false
# Hard blocks
deny[reason] {
input.security_scan.status == "fail"
reason := "security_scan_failed"
}
deny[reason] {
input.security_scan.xss_findings > 0
reason := "xss_vulnerabilities_present"
}
deny[reason] {
input.tests.passed == false
reason := "tests_failed"
}
deny[reason] {
input.tests.coverage_delta < -5
reason := "code_coverage_regression_too_high"
}
# Soft warnings
warn[reason] {
input.agent.author == "ai-agent-claude"
reason := "change_authored_by_ai_agent"
}
warn[reason] {
some f
f := input.files[_]
endswith(f.path, "sql")
reason := "sql_file_modified_require_manual_review"
}
allow {
not deny[_]
}
This one file:
You can extend this with coding standards, PII rules, or license checks.
You now need the policy decision to be merge-blocking, not just advisory.
A minimal workflow to enforce AI agent policies:
# .github/workflows/ai-agent-policy.yml
name: AI Agent Policy Check
on:
pull_request:
types: [opened, synchronize, reopened]
jobs:
policy-check:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
- name: Run tests
run: |
pytest --maxfail=1 --disable-warnings -q
- name: Run security scan
run: |
./scripts/run_security_scan.sh --format json > security.json
- name: Build policy input
run: |
python scripts/build_policy_input.py \
--security security.json \
--output policy-input.json
- name: Evaluate OPA policy
run: |
opa eval \
--format=json \
--data policy \
--input policy-input.json \
"data.ai.agent.change" > decision.json
- name: Fail if policy denies
run: |
python scripts/enforce_policy.py decision.json
enforce_policy.py can be straightforward:
import json
import sys
with open(sys.argv[1]) as f:
decision = json.load(f)
result = decision["result"][0]["expressions"][0]["value"]
allow = result.get("allow", False)
if not allow:
reasons = result.get("deny", [])
print("Policy denied change. Reasons:")
for r in reasons:
print("-", r)
sys.exit(1)
warnings = result.get("warn", [])
if warnings:
print("Policy warnings:")
for w in warnings:
print("-", w)
On GitHub:
main and release/*author: ai-agent-* labelOn GitLab:
This implements OWASP’s pattern: least privilege + required checks + protected merge paths.
Most orgs deploy AI agents before governance: 69% are in production, yet only 21% track agents and MCP connections, and 79% lack monitoring policies.
CI stops bad merges. Your orchestration layer should stop pointless work and give you signal earlier.
You want three behaviors:
If you use Maxxwell, the orchestrator seat is just another coding-agent session started from a brief.
Create a short policy brief:
You are the orchestrator for multiple coding agents.
Before asking any worker to implement a change, enforce these rules:
- No change should proceed without a test plan.
- If a change touches auth, payments, or PII, require explicit human review.
- If CI policy denies a change, stop that worker and report back.
Summarise for me:
- What landed (merged to main)
- What is blocked by policy
- What needs my decision
Do not run git or CI commands yourself. Only draft instructions for workers.
In Maxxwell, that brief is what the orchestrator seat is started from.
Your orchestrator should treat policy status as part of session state visibility.
Example states:
working - agent running tests, implementing changeswaiting_on_ci - policy checks runningblocked(policy_denied) - OPA returned allow=falseneeds_human_review(policy_warn) - warnings presentIn Maxxwell, session tiles already show a readable state per session. Tracking policy status alongside that state gives you:
One subtle but important guardrail: controls draft rather than act.
In Maxxwell, any fleet control that would:
…writes a fully formed, unsent sentence into the composer. It never runs the command.
This matters for policy:
The human stays the one who commits and merges. Policy helps you decide; it doesn’t secretly override you.
NIST and OWASP both care about traceability: you need to explain why the agent was allowed or blocked.
Make sure your stack writes:
policy-input.json)decision.json)allowed, denied, warn) at each decision pointOPA already supports decision logs. Turn them on:
opa run \
--server \
--log-level debug \
--set=decision_logs.console=true
And pipe them somewhere with retention.
This gives you a story you can tell:
The data says the raw AI output needs guardrails: Veracode saw 45% of generated samples fail security tests; XSS showed up in 86% of relevant samples.
Use policy to push checks earlier:
security_scan in policy-input.jsonlicense_scan inputsYour orchestrator doesn’t need to understand each tool. It needs to:
blocked(policy_denied)Maxxwell’s role here is simple: it keeps all sessions visible, with a readable state for each one, and never pretends a missing signal is fine.
You don’t have to build the full NIST AI RMF stack on day one.
Practical rollout:
Each step gives you more control without breaking developer flow.
If you’re coordinating many agents by hand today, Maxxwell is a reasonable orchestration layer to start with: it runs locally, keeps your agents in real terminals you control, and adds visibility and drafting without trying to be another copilot.
Scope policies to author identity and branch patterns.
Example:
feature/agent-* branches when tests/security fail.Use labels (ai-generated, agent:claude) and Rego conditions (input.agent.author) to apply stricter rules to AI changes.
A reasonable baseline:
Encode that in OPA and make the CI job a required check on protected branches.
This alone filters out a large chunk of the 45% of AI-generated samples that would fail basic security tests.
You can start with scripts, but OPA helps when:
Scripted checks are fine early; migrate to OPA when you find yourself copying the same logic into five different workflows.
Maxxwell doesn’t replace your AI coding agents or your CI.
It:
With policy hooked into CI, Maxxwell becomes the place you see which agent sessions are blocked by guardrails and draft what happens next - without giving it permission to act on its own.
You won’t get automatic drift correction out-of-the-box.
Use policy and orchestration together:
Policy keeps bad code out of main; the orchestrator keeps agents pointed roughly at the right goal. The human still decides when to re-aim or kill a session.