Control in Motion SDK -- runtime governance for AI agents
Project description
Control in Motion SDK
Runtime governance enforcement for AI agents. Every tool call your agent makes is checked against your governance policies and delegation contracts before it executes.
Installation
pip install sunbeam-cim
With LangChain support:
pip install sunbeam-cim[langchain]
Quick Start
from sunbeam_cim import CIMAgent
agent = CIMAgent(
gateway_url="http://localhost:8001",
agent_id="my-agent-001",
tenant_id="00000000-0000-0000-0000-000000000001",
)
# Check before acting
decision = agent.check("http_request", domain="api.example.com", method="GET")
if decision.allowed:
response = requests.get("https://api.example.com/data")
elif decision.denied:
print(f"Blocked: {decision.explanation}")
elif decision.requires_approval:
print(f"Waiting for approval: {decision.approval_id}")
Environment Variables
Set these instead of passing constructor args:
export CIM_GATEWAY_URL="http://localhost:8001"
export CIM_AGENT_ID="my-agent-001"
export CIM_TENANT_ID="00000000-0000-0000-0000-000000000001"
export CIM_ENVIRONMENT="prod"
Then just:
from sunbeam_cim import CIMAgent
agent = CIMAgent() # reads from env
Action Types
HTTP Request
decision = agent.check(
action_type="http_request",
domain="api.stripe.com",
method="POST",
body={"amount": 1000},
)
Send Message
decision = agent.check(
action_type="send_message",
recipient="customer@example.com",
data_class="internal",
)
Database Query
decision = agent.check(
action_type="query_db",
db="production",
table="users",
)
Decision Object
decision.allowed # bool — True if ALLOW
decision.denied # bool — True if DENY
decision.requires_approval # bool — True if REQUIRE_APPROVAL
decision.redacted # bool — True if REDACT
decision.explanation # str — human-readable reason
decision.policy_id # str — which policy matched
decision.approval_id # str — approval request ID (if pending)
decision.redacted_fields # list — fields that were masked
# Raise exception instead of checking manually
decision.raise_if_denied() # raises CIMError on DENY
decision.raise_if_not_allowed() # raises CIMError on anything except ALLOW
Error Handling
from sunbeam_cim import CIMAgent, CIMError
agent = CIMAgent(...)
try:
decision = agent.check("http_request", domain="api.example.com")
decision.raise_if_denied()
# safe to proceed
except CIMError as e:
print(f"Governance blocked: {e}")
print(f"Decision was: {e.decision.decision}")
Gateway Unreachable
If the gateway is down, the SDK returns DENY by default (fail-closed):
decision = agent.check("http_request", domain="api.example.com")
# If gateway is unreachable:
# decision.denied == True
# decision.explanation == "Gateway unreachable — action blocked by default"
LangChain Integration
Wrap a tool
from langchain.tools import tool
from sunbeam_cim import CIMAgent
agent = CIMAgent(...)
@tool
def search_web(query: str) -> str:
"""Search the web for information."""
return requests.get(f"https://api.search.com?q={query}").text
# Wrap with governance
governed_search = agent.as_langchain_tool(
search_web,
action_type="http_request",
domain="api.search.com",
)
# Use in your agent as normal — governance runs automatically
Callback handler (intercepts all tools)
from langchain.agents import AgentExecutor
executor = AgentExecutor(
agent=llm_agent,
tools=tools,
callbacks=[agent.as_langchain_callback()],
)
# Every tool call now goes through governance before executing
Full ActionEvent (advanced)
from sunbeam_cim import CIMAgent, ActionEvent
agent = CIMAgent(...)
event = ActionEvent(
tenant_id = "00000000-...",
agent_id = "my-agent-001",
action_type = "http_request",
tool_name = "stripe_charge",
target = {"domain": "api.stripe.com", "method": "POST"},
request = {"body": {"amount": 5000, "currency": "usd"}},
context = {
"data_class": "confidential",
"tags": ["verified", "production-ready"],
"user_id": "user-123",
},
environment = "prod",
)
decision = agent.invoke(event)
Demo (works with local dev stack)
from sunbeam_cim import CIMAgent
agent = CIMAgent(
gateway_url = "http://localhost:8001",
agent_id = "demo-agent-001",
tenant_id = "00000000-0000-0000-0000-000000000001",
environment = "dev",
)
# Should ALLOW (if policy permits)
d = agent.check("http_request", domain="api.example.com")
print(d) # Decision(ALLOW: Permitted by policy)
# Should DENY (if blocklist policy active)
d = agent.check("http_request", domain="evil.com")
print(d) # Decision(DENY: Domain blocked by policy)
Project details
Release history Release notifications | RSS feed
Download files
Download the file for your platform. If you're not sure which to choose, learn more about installing packages.
Source Distribution
Built Distribution
Filter files by name, interpreter, ABI, and platform.
If you're not sure about the file name format, learn more about wheel file names.
Copy a direct link to the current filters
File details
Details for the file sunbeam_cim-1.0.0.tar.gz.
File metadata
- Download URL: sunbeam_cim-1.0.0.tar.gz
- Upload date:
- Size: 9.9 kB
- Tags: Source
- Uploaded using Trusted Publishing? No
- Uploaded via: twine/6.2.0 CPython/3.11.15
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
ea11386e084f3d32d47c07c08b0c8605af2baad396036b07bbe00c65d1ac72e0
|
|
| MD5 |
dbbbca5dbc1bc8ca7e6f37e7afa2bd57
|
|
| BLAKE2b-256 |
b152e203dfe01cb5cea2778828f801fda2dd0bb6a885c9f0c9d17fabb65a49a5
|
File details
Details for the file sunbeam_cim-1.0.0-py3-none-any.whl.
File metadata
- Download URL: sunbeam_cim-1.0.0-py3-none-any.whl
- Upload date:
- Size: 7.6 kB
- Tags: Python 3
- Uploaded using Trusted Publishing? No
- Uploaded via: twine/6.2.0 CPython/3.11.15
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
176f512c595821458370d2fcc4024027b8d9771c94f7f8cc370a1af0819489b8
|
|
| MD5 |
c06d4e5e91cbd03d7d66be635108665e
|
|
| BLAKE2b-256 |
64b337c28dbfe4070738759eaa21fe7c8eb52d848d98e9ccda8aac375c18fda9
|