cots
The Cots.ai SDK for Rust. cots::agents is the interceptor client for agents written in Rust —
mirrors @cots/sample (the Node package) field for field: same config shape, same guard() pattern,
same wire format the Rust PEP/PDP expects. Future modules (cots::policy, cots::audit, ...) would
live alongside agents in this same crate as it grows.
Add it
Or add it to your Cargo.toml directly:
[]
= "0.2"
= { = "1", = ["macros", "rt-multi-thread"] }
Configure
use ;
let agent = new;
Or load COTS_TENANT_ID / COTS_AGENT_ID / COTS_DATA_PLANE_URL / COTS_CONTROL_PLANE_URL /
COTS_APPROVAL_TIMEOUT_MS / COTS_APPROVAL_POLL_MS from the environment (same convention as the Node
SDK):
let agent = new;
Use it — guard() is the one method most agents need
use NormalizedAction;
let result = agent
.guard
.await?;
// result.outcome is Executed | Blocked | Timeout
// result.decision is "allowed" | "blocked" | "require_approval"
guard() calls the interceptor first. If allowed, your closure runs immediately. If blocked, it
never runs. If require_approval, it holds and polls the control plane until a human decides (or
approval_timeout_ms elapses), then runs your closure only if approved.
Need lower-level control? agent.intercept(action) and agent.wait_for_approval(action_event_id) are
the two calls guard() composes.
Onboarding (one-time, per organization/agent)
agent.control_plane exposes the same onboarding surface the admin panel's wizard uses:
let reg = agent.control_plane.register_tenant.await?;
let created = agent.control_plane.register_agent.await?;
agent.control_plane
.create_action_surface
.await?;
let pep_config = agent.control_plane.activate_agent.await?;
// pep_config.pep_endpoint is a real-deployment placeholder — locally, keep using data_plane_url above.
Framework-agnostic — works with actix-web, axum, or nothing at all
cots::agents has no dependency on any web framework — just reqwest + tokio. It works inside
whatever server your agent already runs (or no server at all, e.g. a CLI or worker). Two runnable
proofs are in examples/:
Both call cots::agents::AgentClient::guard(...) from inside a request handler and return the real
interceptor decision — same crate, same API, either framework.
What this crate does not do
- No real Slack/SMS/email/payments integrations — your
executeclosure does that however you like. - No retry beyond the approval poll loop —
intercept()is a single request; on failure it returnsErr. - No dependency on any particular agent framework — call
guard()wherever your agent decides to act.
License
Licensed under the MIT License. © 2026 Cots.ai.
Made with ❤️ by Srotas Space