Let AI agents act. Without letting them loose.

TrustRail is the authorization and execution boundary between your agents and the real world: deterministic policy decisions, digest-bound human approvals, and a credential gateway your agents can never bypass.

// Wrap a tool you already have. It runs only if policy allows.
import { agentFromEnvironment } from "@trustrail/sdk-js";

const sendEmail = agentFromEnvironment().guard(
  {
    actionType: "communications.email.send",
    resource: { type: "mailbox", id: "support@example.com" },
    purpose: (args) => `Email ${args.to.join(", ")}`,
  },
  myExistingSender,
);
deny-by-default · RFC 8785 canonical digests · Ed25519 one-use execution tokens · at-most-once provider execution · forced row-level security · hash-chained audit evidence

The action lifecycle, governed end to end

An agent never holds provider credentials and never calls a provider directly. Every consequential action flows through five governed stages, each producing verifiable evidence.

Canonical actionThe agent submits a typed, normalized action. TrustRail computes a canonical SHA-256 digest that every later stage binds to.
Deterministic decisionA bounded, non-Turing-complete policy engine plus integer-only risk scoring decide allow, deny, or require-approval — bit-identically reproducible.
Human approvalApprovers confirm the exact subject digest with phishing-resistant MFA. Quorums, separation of duties, and race-safe single finalization built in.
Signed authorizationA five-minute Ed25519 token with a closed claim set and a one-use identifier is the only thing that unlocks execution.
Enforced executionA separate gateway process holds the provider credential, revalidates every fact, and treats ambiguous outcomes as first-class state to reconcile — never to retry blindly.

Built for the failure cases

Most agent frameworks optimize the happy path. TrustRail is engineered around what goes wrong: prompt injection, replayed requests, stale authority, crashed processes, and ambiguous provider timeouts.

Invariant

A denied action cannot execute

The gateway consumes a signed, digest-bound, one-use token before any provider call. No token, no execution — enforced in a separate process with its own least-privilege database role.

Invariant

Mutation invalidates authorization

Approvals bind to the canonical digest of the exact request. Change one byte of the payload and every downstream authorization fails closed.

Invariant

Delegation only narrows

Agent-to-subagent handoffs are signed grants checked on ten axes — capabilities, resources, spend, depth, time — in both the application and the database. Revoking an ancestor kills the whole subtree.

Invariant

Ambiguity is never a retry

A provider timeout is recorded as UNKNOWN and reconciled by a stable idempotency key. The guarantee is at most one logical operation — stated honestly, engineered thoroughly.

Invariant

Tenants are isolated in the database

Forced PostgreSQL row-level security with composite tenant keys means isolation holds even if application code has a bug. Cross-tenant probes return 404, never a hint.

Invariant

Evidence is tamper-evident

Every privileged transition appends to a per-tenant SHA-256 hash chain in the same transaction. The whole chain is re-verifiable through the API on demand.

Honest enforcement modes

TrustRail tells you exactly what each mode guarantees — and what it does not. Only Enforce mode prevents external action; the others are for visibility and rollout.

ModeBehaviorSecurity claim
ObserveReceives telemetry alongside or after actionsVisibility only — no prevention claim
ShadowEvaluates before the action; the client still executes independentlyPolicy impact measurement — no enforcement claim
DecisionReturns allow/deny/approval, but a client could bypass itAdvisory authorization
EnforceThe gateway holds the provider credential and the execution pathProtected against ordinary client bypass within the deployment boundary

Two integration modes, two different promises

Start by gating the tools you already have. Move the ones that matter inside the boundary. The difference is not convenience — it is what survives a compromised agent process, and TrustRail will not let you confuse the two.

Decision mode

guard() — one wrapper, no migration

Your tool keeps its signature and its implementation. TrustRail decides whether it runs, and a denial reaches the model as a tool result that tells it not to route around the refusal. Works with every action type in the registry.

Gates your code; does not hold your credentials. A compromised agent process could bypass it. Not enforcement.

Enforce mode

act() — the agent never holds the credential

Drop the local implementation. A separate gateway process holds the provider credential, revalidates every fact, and spends a one-use Ed25519 authorization. The agent cannot perform the action on its own.

Requires a reviewed provider adapter, so it covers the action types the registry marks EXECUTABLE.

// Enforce mode: evaluate, wait for a human if required, execute
const result = await agent.act({
  purpose: "Reorder the stock the planner flagged",
  actionType: "payments.purchase.create",
  resource: { type: "payment", id: "order-4821" },
  parameters: restockOrder,
  financial: { amountMinor: "4999", currency: "USD" },
  waitForApprovalSeconds: 120,
});

// -> result.status: "EXECUTED" | "DENIED" | "AWAITING_APPROVAL"

A denial is a returned result, never a thrown error. Refusing an action is a normal answer, and code that treats it as a crash ends up working around it.

Drops into the frameworks you already use

The adapters are matched structurally and import nothing, so there are no peer dependencies and no version coupling. Governance refusals become tool results rather than exceptions that abort a run.

FrameworkIntegration
Vercel AI SDKgovernedAiTool(agent, spec, tool)
LangChain / LangGraphgovernedLangChainTool(...) · Python @agent.guard(...)
OpenAI / Anthropic tool loopsgovernedHandler(agent, spec, handler)
MCP-capable agentsOne config entry — Claude Code, Claude Desktop, and others
Anything elsegovernedExecute · governedTextExecute