Developers
Three lines, and the refusal is a value.
No runtime to adopt and no framework to migrate to. The governed unit is the action, so this is a call you make before a consequential one — and the answer is recorded either way.
pip install rotascale
from rotascale import Rotascale rs = Rotascale() # reads ROTASCALE_URL and ROTASCALE_API_KEY # The agent appears here, the first time it speaks. Nobody registers it. agent = rs.agent("refund-assistant") # One episode of work, recorded as it happens. with rs.witness(agent, goal={"ticket": "TICKET-88123"}) as t: # Ask BEFORE acting. The answer is recorded either way. decision = t.authorize(grant_id, {"tools": ["issue_refund"]}, amount_minor=4_500, currency="EUR") if decision.allowed: ... # do the thing t.outcome(decision="refunded", outcome_amount_minor=4_500) else: # A refusal is not an exception. It is the product working. t.outcome(decision="refused", reason=decision.reason)
Two rules the SDK will not let you break
- Capture fails open
- A recording problem must never break a production agent. Evidence is worth a lot; it is not worth an outage. Capture calls do not raise.
- Enforcement fails closed
- If the control plane is unreachable, the honest position is that the
action is ungoverned — and an ungoverned action is worse than a delayed
one. Teams who genuinely cannot accept that set
fail_open_enforcement=Trueand own the consequence explicitly, which is at least a recorded decision rather than an accident.
The refusal types name the remedy: Blocked means change the
grant, Exhausted means raise the budget or issue a new one,
Gated means the context was tainted and needs approval or a
declared sanitiser, ReviewRequired means park it, a person is
deciding. That is why they are distinct types rather than one
Refused.
Where to go
Reference documentation lives in the console at /developers,
because it knows which deployment you are integrating against — whether
taint enforcement is on, which market profile resolves, and whether the
signing key is deployment-held or yours. A static page can only say "it
depends"; that one says which.