Skip to content

Latest commit

Β 

History

345 Commits

Folders and files

NameName
Last commit message
Last commit date
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 

Repository files navigation

AgentRail

Guardrails and observability for autonomous AI agents. Tool-call auditing, spend caps, and rollback for anything an agent does in production.

PyPI Go License: MIT CI

pip install agentrail-sdk
agentrail init

Table of Contents


Why This Exists

Agent frameworks are good at getting an LLM to call tools. None of them are good at answering "what did it actually do, why, and how do I undo it" after the fact.

Give an agent a database write tool, a payment API, or git push access, and the failure mode isn't "it hallucinated an answer" β€” it's "it did something real, silently."

AgentRail sits between your agent and the tools it calls, and gives you three things most setups don't have:

πŸ›‘ Hard stop Blocks expensive or destructive actions before they execute
πŸ“‹ Audit trail Complete record of every tool call, cost, and decision
↩️ Rollback A way to undo what happened

Why Three Languages

This isn't polyglot for its own sake β€” each piece is written in what it's actually good at, and the split is load-bearing.

πŸ”§ Policy Daemon β†’ Go

Every tool call an agent makes blocks on a policy check. That check needs to happen in single-digit milliseconds regardless of how many agents are hammering it concurrently. Go gives us a static binary with no runtime dependency, cheap goroutines for concurrent session handling, and GC pauses low enough not to show up in the latency budget.

🐍 SDK / Framework Adapters β†’ Python

Every agent framework worth integrating with (LangChain, CrewAI, raw OpenAI/Anthropic function-calling loops) lives in Python. The SDK has to feel native there, so it is. It talks to the Go daemon over a local Unix socket via gRPC β€” the interception logic itself is thin; the daemon does the real work.

πŸ’» Approval Dashboard β†’ TypeScript / React (Next.js)

The one piece humans actually look at. Approval queues and audit trails are a UI problem, and the web ecosystem is where that problem is best solved. Talks to the daemon over gRPC-web.

Net effect: sub-millisecond policy checks even under load, an SDK that doesn't feel bolted-on in whatever Python agent code you're already writing, and a dashboard that doesn't feel like an afterthought.

β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”        Unix socket / gRPC        β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”
β”‚     Python SDK       β”‚ ────────────────────────────────►│   Go Policy Daemon    β”‚
β”‚  (@guard decorator)  β”‚ ◄────────────────────────────────│     (agentraild)      β”‚
β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜                                   β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”¬β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜
                                                                        β”‚
                                                              β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β–Όβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”
                                                              β”‚     Audit Store      β”‚
                                                              β”‚ (Postgres / SQLite)  β”‚
                                                              β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”¬β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜
                                                                        β”‚ gRPC-web
                                                              β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β–Όβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”
                                                              β”‚    TS Dashboard      β”‚
                                                              β”‚ (approvals, trace)   β”‚
                                                              β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜

Install

Three components β€” install what you need.

Python SDK (always required β€” this is what your agent code imports)

pip install agentrail-sdk

Go daemon (runs locally or as a sidecar)

brew install yourorg/tap/agentraild
# or
go install github.com/yourorg/agentrail/daemon/cmd/agentraild@latest

Dashboard (optional β€” only needed for the approval UI)

docker compose -f docker/dashboard-compose.yml up -d

agentrail init scaffolds config and starts the daemon in dev mode (in-process, no separate binary needed) so you can try it without standing up all three pieces.


Wrapping Your Agent's Tools

from agentrail import guard, Policy

policy = Policy(
    max_session_spend_usd=5.00,
    require_approval=["send_email", "execute_sql"],
    block=["DROP TABLE", "rm -rf"],
)

@guard(policy, reversible=True, undo="delete_row")
def insert_row(table: str, data: dict):
    return db.insert(table, data)

Under the hood, @guard makes a ~0.4ms round trip to agentraild over the local socket before letting the call through.

Framework adapters ship for LangChain and native OpenAI/Anthropic function-calling:

from agentrail.adapters.langchain import wrap_tools
tools = wrap_tools(my_langchain_tools, policy=policy)

CLI (talks to the Go daemon)

agentrail watch                              # tail audit log live
agentrail trace abc123                       # what did session abc123 do
agentrail rollback abc123 --confirm          # undo everything reversible
agentrail spend --agent research-bot --window 24h

Example trace:

$ agentrail trace abc123

Session abc123 β€” agent: support-bot β€” started 2026-08-26 09:14:02

[09:14:03] search_knowledge_base("refund policy")           $0.0002   ok
[09:14:05] check_order_status(order_id="ORD-9921")           $0.0001   ok
[09:14:08] BLOCKED  issue_refund(order_id="ORD-9921", amount=450.00)
           reason: exceeds require_approval threshold ($50)
           β†’ escalated to approval dashboard

Total spend: $0.0003   |   1 blocked   |   0 rolled back

Repo Layout

.
β”œβ”€β”€ sdk-python/                 # the pip-installable package agents import
β”‚   β”œβ”€β”€ agentrail/
β”‚   β”‚   β”œβ”€β”€ core/
β”‚   β”‚   β”‚   β”œβ”€β”€ guard.py        # decorator, calls daemon via gRPC
β”‚   β”‚   β”‚   └── client.py       # gRPC client to agentraild
β”‚   β”‚   β”œβ”€β”€ adapters/
β”‚   β”‚   β”‚   β”œβ”€β”€ langchain.py
β”‚   β”‚   β”‚   └── openai_functions.py
β”‚   β”‚   └── cli.py
β”‚   β”œβ”€β”€ tests/
β”‚   └── pyproject.toml
β”‚
β”œβ”€β”€ daemon/                     # agentraild β€” the Go policy engine
β”‚   β”œβ”€β”€ cmd/agentraild/
β”‚   β”‚   └── main.go
β”‚   β”œβ”€β”€ internal/
β”‚   β”‚   β”œβ”€β”€ policy/             # rule evaluation, spend tracking
β”‚   β”‚   β”œβ”€β”€ storage/            # Postgres/SQLite backends
β”‚   β”‚   β”œβ”€β”€ rollback/
β”‚   β”‚   └── anomaly/            # baseline + deviation scoring
β”‚   β”œβ”€β”€ grpc/                   # service definitions, generated code
β”‚   β”œβ”€β”€ go.mod
β”‚   └── Makefile
β”‚
β”œβ”€β”€ dashboard/                  # TS/Next.js approval queue + audit browser
β”‚   β”œβ”€β”€ src/
β”‚   β”‚   β”œβ”€β”€ app/
β”‚   β”‚   β”œβ”€β”€ components/
β”‚   β”‚   └── lib/grpc-web-client.ts
β”‚   β”œβ”€β”€ package.json
β”‚   └── next.config.js
β”‚
β”œβ”€β”€ proto/                      # shared .proto definitions (SDK ↔ daemon ↔ dashboard)
β”‚   └── agentrail/v1/policy.proto
β”‚
β”œβ”€β”€ examples/
β”‚   β”œβ”€β”€ langchain_support_bot/
β”‚   └── raw_function_calling/
β”‚
β”œβ”€β”€ docs/
β”‚   β”œβ”€β”€ writing-a-policy.md
β”‚   β”œβ”€β”€ rollback-guide.md
β”‚   β”œβ”€β”€ daemon-deployment.md
β”‚   └── architecture.md
β”‚
β”œβ”€β”€ docker/
β”‚   β”œβ”€β”€ daemon-compose.yml
β”‚   └── dashboard-compose.yml
β”‚
β”œβ”€β”€ .github/
β”‚   β”œβ”€β”€ workflows/
β”‚   β”‚   β”œβ”€β”€ ci-python.yml
β”‚   β”‚   β”œβ”€β”€ ci-go.yml
β”‚   β”‚   └── ci-dashboard.yml
β”‚   β”œβ”€β”€ ISSUE_TEMPLATE/
β”‚   └── PULL_REQUEST_TEMPLATE.md
β”‚
β”œβ”€β”€ .editorconfig
β”œβ”€β”€ .gitignore
β”œβ”€β”€ CODEOWNERS
β”œβ”€β”€ CONTRIBUTING.md
β”œβ”€β”€ CHANGELOG.md
β”œβ”€β”€ SECURITY.md
β”œβ”€β”€ LICENSE
└── README.md

Configuration

agentrail.yaml β€” read by the Go daemon on startup:

storage:
  backend: postgres
  connection: "${AGENTRAIL_DB_URL}"

policy:
  max_session_spend_usd: 5.00
  max_daily_spend_usd: 100.00
  require_approval: [send_email, execute_sql, issue_refund]
  block_patterns: ["DROP TABLE", "rm -rf"]
  allowlist_mode: false

approval:
  channel: slack
  webhook_url: "${APPROVAL_WEBHOOK}"
  timeout_seconds: 300
  on_timeout: deny

anomaly_detection:
  enabled: true
  baseline_window_days: 14

Performance

Benchmarked with the Go daemon running as a local sidecar, 10,000 tool calls, Unix socket transport:

Configuration Added latency per call
Policy check only ~0.4ms
Policy + audit log write (Postgres) ~1.3ms
Policy + audit + anomaly scoring ~2.1ms

For comparison, an earlier in-process Python-only prototype averaged ~4ms for the same policy+audit path β€” the daemon split was worth doing specifically because agent loops sometimes fire several tool calls per turn, and that adds up under concurrency.


CI

Each component has its own workflow and only runs on changes to its directory:

# .github/workflows/ci-go.yml β€” runs on daemon/** changes
- run: go test ./... -race
- run: golangci-lint run

# .github/workflows/ci-python.yml β€” runs on sdk-python/** changes
- run: pytest --cov=agentrail

# .github/workflows/ci-dashboard.yml β€” runs on dashboard/** changes
- run: npm run lint && npm run build

proto/ changes trigger all three CI workflows, since a schema change touches every component.


Known Limitations

  • The daemon must be running for the SDK to work in production mode β€” agentrail init's dev mode (in-process, no daemon) is for local testing only, not deployment.
  • Anomaly detection needs ~2 weeks of baseline data before it's useful β€” it's silent-only until then.
  • Rollback is only as good as the undo function you write β€” AgentRail verifies that it ran, not that it's correct.

Contributing

Each directory is closer to its own project than a monorepo convenience β€” sdk-python/, daemon/, and dashboard/ each have their own CONTRIBUTING notes linked from the root CONTRIBUTING.md.

Proto changes need sign-off from a CODEOWNERS reviewer on all three sides, since they're a breaking-change surface by nature.


License

MIT. See LICENSE.


AgentRail limits blast radius, it doesn't guarantee correctness. This is the seatbelt, not the driver.

Troubleshooting

  • agentrail: connection refused - the daemon is not running. Start it with airecalld --config agentrail.yaml and retry.
  • Everything is blocked - check max_daily_spend_usd; a crossed daily cap blocks all calls until midnight UTC.

About

Guardrails and observability for autonomous AI agents - tool-call auditing, spend caps, and rollback for anything an agent does in production.

Resources

Contributing

Security policy

Stars

28 stars

Watchers

6 watching

Forks

Releases

Packages

Contributors

Languages