Enforce with the AI Agent Guardrails SDK

AI Agent Guardrails provide a deterministic authorization layer for autonomous agents. Your policies — and only your policies — decide whether an action is allowed, challenged, or denied. No AI model ever participates in the decision; the models your agents use propose actions, and AI Agent Guardrails dispose of them. The AI Agent Guardrails SDK is a single dependency-free file (akrum-guard.ts) you drop into any project.

Quickstart

import { createGuardClient } from "./akrum-guard";

const guard = createGuardClient({ apiKey: process.env.AKRUM_KEY ?? "" });

const result = await guard.authorize({
  agent: "payments-agent",          class="tk-c">// a registered Guard agent identity
  action: "create_payout",
  resource: "acct:class="tk-n">1234",
  context: { amount_usd: class="tk-n">2500 },
});

class="tk-c">// result = { decision, reason, obligations, matched_policy_id, evaluated_at }

Your API key needs the guard scope. Create one under API keys.

authorize vs enforce

authorize() always returns the decision object so you can branch yourself. enforce() returns the decision only on allow; on deny it throws GuardDeniedError and on challenge it throws GuardChallengeError — both carry reason and obligations.

import { GuardDeniedError, GuardChallengeError } from "./akrum-guard";

try {
  await guard.enforce({ agent: "payments-agent", action: "create_payout", resource: "acct:class="tk-n">1234" });
  await createPayout();
} catch (e) {
  if (e instanceof GuardDeniedError) {
    class="tk-c">// hard stop — log and do not retry
  } else if (e instanceof GuardChallengeError) {
    class="tk-c">// step-up — surface e.obligations (e.g. require_human_approval) and pause
  }
}

Handling challenge and obligations

A challenge means the action may proceed only after the listed obligations are satisfied — for example a human approval step or step-up authentication. Obligations are structured: { type, description, details? }, so your agent can act on them programmatically.

Fail-closed behavior

If Guard cannot be reached — a timeout, network error, or 5xx — the SDK never invents an allow. It returns a synthetic decision with reason Guard unreachable (fail-closed). and the decision you configure via onUnreachable (deny by default, or challenge). Client errors like a bad key (401/403) throw GuardRequestError instead — a misconfiguration should never look like a policy outcome.

const guard = createGuardClient({
  apiKey: process.env.AKRUM_KEY!,
  timeoutMs: class="tk-n">5000,
  onUnreachable: "deny", class="tk-c">// or "challenge"
});

Wrapping agent tools

wrapTool turns any function into a Guard-gated tool: the call arguments are sent as decision context, and the function runs only on allow.

const sendEmail = guard.wrapTool(
  { agent: "comms-agent", action: "send_email", resource: "mailbox:support" },
  async (to: string, subject: string, body: string) => mailer.send({ to, subject, body }),
);

await sendEmail("user@example.com", "Hello", "…"); class="tk-c">// throws on deny / challenge

Equivalent curl

curl https://akrum.io/api/public/v1/authorize \
  -H "Authorization: Bearer $AKRUM_KEY" \
  -H "Content-Type: application/json" \
  -d '{
    "agent": "payments-agent",
    "action": "create_payout",
    "resource": "acct:-n">1234",
    "context": { "amount_usd": -n">2500 }
  }'

Unknown or revoked agent identities are denied before any policy is evaluated, and with no matching policy AI Agent Guardrails default to deny — nothing is allowed unless one of your policies grants it.