Skip to content

guides

Intended Documentation

Enforcement SDK

The @intended-inc/sdk reference — createIntendedSdk, submitIntent, verifyAuthorityToken, simulateIntent, evidence and audit helpers, plus the separate physical-AI SDK.

Enforcement SDK#

@intended-inc/sdk is the TypeScript client for the Intended runtime. It attaches your credentials to every request, validates request bodies against the published contracts before they leave your process, and exposes the runtime surface — submitting intents, verifying Authority Tokens, simulating, and pulling audit and evidence records.

There is no separate "enforcement" package. Enforcement in your own code is two things the SDK already gives you: submit an intent to get a decision, and verify the Authority Token locally before you act on an APPROVED decision.

Create the client#

createIntendedSdk takes baseUrl, tenantId, and apiKey. The client sends Authorization: Bearer <apiKey> and x-tenant-id: <tenantId> on every request, so you never assemble headers by hand.

ts
import { createIntendedSdk } from "@intended-inc/sdk";

const sdk = createIntendedSdk({
  baseUrl: "https://api.intended.so",
  tenantId: "tenant_acme_prod",
  apiKey: process.env.INTENDED_API_KEY!, // intended_live_…
});

Note

A Go client also ships under the package name intended (github.com/intended-so/intended-go). The TypeScript signatures on this page are the reference; the Go and Python clients mirror the same runtime routes.

Submit an intent#

submitIntent validates the body against IntentRequestSchema, then POSTs to /intent. It returns the raw decision response. See the API Quickstart for the full field reference and decision outcomes.

ts
const result = await sdk.submitIntent({
  tenantId: "tenant_acme_prod",
  actor: { id: "svc-ci-bot", type: "service" },
  targetSystem: "acme/platform-api",
  proposedAction: "dispatch release workflow",
  riskContext: {
    baseRiskScore: 42,
    policyCompliant: true,
    requiresPrivilegedAccess: false,
    touchesProduction: false,
    containsSensitiveData: false,
    github: { owner: "acme", repo: "platform-api", ref: "refs/heads/main" },
  },
});

// result.authorityDecision.decision is "APPROVED" | "ESCALATED" | "DENIED"

Verify the Authority Token#

On APPROVED, verify the token before acting. verifyAuthorityToken delegates to @intended/verify's verifyToken (Ed25519, kid-pinned). The return is { valid, reason, claims, header }.

ts
const verification = await sdk.verifyAuthorityToken({
  token: result.authorityDecisionToken as string,
  publicKeyPem,                 // tenant public key for the token's kid
  expectedKid: kid,
  expectedTenantId: "tenant_acme_prod",
  expectedAdapterId: "github-actions-adapter",
  maxTokenTtlSeconds: 300,
  clockSkewSeconds: 60,
});

if (!verification.valid) {
  // verification.reason: KID_MISMATCH | TOKEN_EXPIRED | TOKEN_TENANT_MISMATCH | …
  throw new Error(verification.reason ?? "TOKEN_INVALID");
}

The failure-reason table lives in Verify Decision Tokens. Remember that verifyToken does signature + claim checks only — single-use nonce consumption happens inside the connector SDK.

Method reference#

The SDK surface relevant to enforcement and audit:

MethodRoutePurpose
submitIntent(intent)POST /intentSubmit an intent; get a decision (+ token on approval).
simulateIntent(intent)POST /intent/simulateEvaluate without executing or minting a token.
verifyAuthorityToken(input)localVerify an Ed25519 Authority Token via @intended/verify.
getEvidenceBundle({ intentId })GET /tenants/:t/intents/:i/evidenceSelf-contained evidence bundle for an intent.
getAuditEvents({ … })GET /tenants/:t/auditQuery audit events by correlation id / event type.
listEscalations()GET /escalations/pendingPending escalations for the tenant.
approveEscalation({ … }) / rejectEscalation({ … })POST /escalations/:id/{approve,reject}Resolve an escalation.
compileIntent(input)POST /intent/compileCompile a natural-language request into a structured intent.

Info

The evidence bundle returned by getEvidenceBundle is signed with HMAC-SHA256 keyed off the tenant's own secret, not an asymmetric signature. Verifying it requires possession of that tenant secret; it is tamper-evident, but not independently verifiable by a third party without the key. State this precisely in any compliance claim.

Simulate before you submit#

simulateIntent runs the same evaluation as submitIntent but performs no execution and mints no token — useful for previewing how a policy change would decide an action.

ts
const preview = await sdk.simulateIntent({ /* same IntentRequest shape */ });
// preview carries the decision and rationale without side effects.

Physical-AI SDK#

Embodied / robotics integrations use a separate client, createIntendedPhysicalSdk, so digital callers don't pull the physical types into their bundle.

ts
import { createIntendedPhysicalSdk } from "@intended-inc/sdk";

const physical = createIntendedPhysicalSdk({
  apiBaseUrl: "https://api.intended.so",
  apiKey: process.env.INTENDED_API_KEY!, // intended_live_…
});

// Classify a structured goal into an OI v2 code (cloud classifier).
const classification = await physical.classifyStructuredGoal(structuredGoal, {
  allowOfflineFallback: true,
});

// Ask the cloud to mint a short-lived physical Authority Token.
const { token, expiresAtMs, oiCode } = await physical.issueAuthorityToken({
  intent: { oiCode: classification.oiCode, structuredGoal },
  dagNode,
  claims,
});

Note

Roadmap. The physical SDK does not verify tokens locally — it is a cloud round-trip client. Local verification and the sub-50ms hot path are the job of the edge verifier (the Rust SDK), which is not yet in the repo. See Verify Decision Tokens for the on-robot verifier shape.

Error handling#

SDK requests throw an IntendedSdkError carrying statusCode, code (the runtime error code), and body. Map the HTTP status to the runtime's documented behavior — 400 VALIDATION_ERROR, 401/403 auth failures, 429 RATE_LIMITED, 500 AUTHORITY_LOOP_FAILED. The full table is in Error Patterns.

ts
try {
  await sdk.submitIntent(intent);
} catch (err) {
  const e = err as { statusCode?: number; code?: string; body?: unknown };
  if (e.statusCode === 429) {
    // back off and retry
  } else if (e.statusCode === 403) {
    // denied or insufficient permission — do not retry
  }
}

Next steps#

Enforcement SDK | Intended