Integration Guide

Get the code and follow along. Download the starter (no SDK), work through the steps, and compare against the integrated version. On each code box use the Before / After button; pick your language with the TypeScript / Python toggle.
Before · no SDK TypeScript Python
Phase 1 / 3

Foundation

Install the SDK, give the agent a verifiable identity, and route every tool through the secured pipeline.

0

Prerequisites

What: what you need before Step 1.

How: register an agent to get its credentials, then put them in .env.

Runtime — enough on its own to run the baseline app:

  • Node ≥ 18 (TypeScript) or Python ≥ 3.11
  • An API key for your model provider

Register the agent — required before Step 2. From the Agent Trust Dashboard you get:

  • a client id and client secret
  • an mTLS certificate the SDK authenticates with

The Dashboard is also where you later change FGA policy and read the audit trail.

Environment variables — every variable used in this guide, in one place. Steps 1, 3 and 6 need none of them.

VariableNeeded fromWhat it is / where it comes from
ANTHROPIC_API_KEYbaselineYour model provider's API key. The sample runs on Anthropic; the variable is the sample's, not the platform's.
AITRUST_MANAGEMENT_URLStep 2Base URL of your platform tenant. RequiredAITrust() throws ConfigurationError without it.
AITRUST_CLIENT_ID / AITRUST_CLIENT_SECRETStep 2Agent credentials issued at registration — registering is the Deploy guide, Step 2; do that first, this guide assumes you already have these. AITRUST_CLIENT_ID is also the agent id the platform knows you by: it is what audit events and authorization rules are written against, so a wrong value fails silently rather than loudly.
AITRUST_IDP_URLStep 2SHIFT IDP base URL (token acquisition, CIBA).
AITRUST_REALMStep 2IDP realm. Set it to the realm your contact gives you. The SDK default is superapp, which is a different tenant — leaving it unset issues tokens nobody accepts.
AITRUST_AUDIT_URLStep 6Audit service base URL. Events are dropped silently if unreachable.
AITRUST_AGENT_IDStep 2The agent's stable id, written as agent:<client-id> on every audit event and authorization rule. Set it to your client id — not the UUID the Dashboard also shows. Without it the first tool call fails with MISSING_CONFIG: GuardConfig.agentId is required.
AITRUST_PROXY_URLStep 2Management proxy the SDK acquires tokens through, over mutual TLS. A separate host from AITRUST_MANAGEMENT_URL — ask for it by name. Required for any real tool call — without it the first one fails with proxyUrl is required for clientCredentials.
AITRUST_PROXY_CERT_PATH / ..._KEY_PATHStep 2The agent's mTLS pair. kobilctl deploy sets both for you; running against the platform from your laptop means pointing them at the PEMs yourself.
Checkpoint · local

The baseline app runs with just the model provider's key. The rest are only needed from the step named above.

1

Install the SDK

What: add the three SDK packages to your manifest.

How: the packages are served from KOBIL's own registry, so you point your package manager at it once, then install normally — no vendoring, no build step.

You need an access token first.
  • The SDK ships from KOBIL's own registry, not public npm/PyPI — a plain npm install @kobil/aitrust fails with a 404.
  • Ask your KOBIL contact for a package registry token (a read-only deploy token).
  • No KOBIL account is needed; the token grants nothing but package downloads.

Configure the registry once, in your project root:

.npmrcpip.conf (or ~/.config/pip/pip.conf)
@kobil:registry=https://gitlab.kobil.com/api/v4/groups/3778/-/packages/npm/
//gitlab.kobil.com/api/v4/groups/3778/-/packages/npm/:_authToken=${KOBIL_REGISTRY_TOKEN}
[global]
extra-index-url = https://${KOBIL_REGISTRY_USER}:${KOBIL_REGISTRY_TOKEN}@gitlab.kobil.com/api/v4/groups/3778/-/packages/pypi/simple

Keep the token in an environment variable — don't commit it. Then install:

install
npm install @kobil/aitrust @kobil/kobil-agent-sdk @kobil/kobil-agent-audit --legacy-peer-deps
pip install kobil-aitrust kobil-agent-sdk kobil-agent-audit

--legacy-peer-deps is required. npm installs the SDK's optional peers anyway, pulling @anthropic-ai/claude-agent-sdk, which needs @anthropic-ai/sdk ≥ 0.93.0; an app on an older version fails with ERESOLVE. The flag also keeps the packages flat in node_modules/@kobil, which the vendoring step depends on.

Or declare them in your manifest and install as usual:

package.jsonpyproject.toml
"dependencies": {
  "@anthropic-ai/sdk": "^0.40.0",
  "pdf-lib": "^1.17.1"
}
"dependencies": {
  "@anthropic-ai/sdk": "^0.40.0",
  "pdf-lib": "^1.17.1",
  "@kobil/aitrust":           "0.2.20-rc.4",
  "@kobil/kobil-agent-sdk":   "0.2.20-rc.4",
  "@kobil/kobil-agent-audit": "0.2.20-rc.4"
}
dependencies = [
  "anthropic>=0.40.0",
  "reportlab>=4.2.0", "pypdf>=5.1.0",
]
dependencies = [
  "anthropic>=0.40.0",
  "reportlab>=4.2.0", "pypdf>=5.1.0",
  "kobil-aitrust", "kobil-agent-sdk", "kobil-agent-audit",
]
Checkpoint · local

npm install resolves and node -e "require('@kobil/aitrust')" imports without error.

pip install -e . resolves and python -c "import kobil_aitrust" succeeds.

2

Agent identity

@kobil/aitrustkobil_aitrust

What: give the agent a verifiable platform identity.

How: create one cached AITrust instance — it holds the client credentials + platform URLs and is the handle every later step uses. Before there was no SDK at all.

src/agent.tssrc/agent.py
// No SDK — the agent has no platform identity.
// The Anthropic client is the only thing constructed.
const anthropic = new Anthropic();
import { AITrust } from "@kobil/aitrust";
import type { AITrustInstance } from "@kobil/aitrust";

let _sdk: AITrustInstance | null = null;
export async function getAgentSDK(): Promise<AITrustInstance> {
  if (_sdk) return _sdk;
  _sdk = AITrust({
    agentId: `agent:${process.env.AITRUST_CLIENT_ID}`,   // your client id — no fallback
    timeoutMs: 120_000,
    platformUrl:   process.env.AITRUST_MANAGEMENT_URL,
    managementUrl: process.env.AITRUST_MANAGEMENT_URL,
    auditUrl:      process.env.AITRUST_AUDIT_URL,
    idpUrl:        process.env.AITRUST_IDP_URL,
    clientId:      process.env.AITRUST_CLIENT_ID,
    clientSecret:  process.env.AITRUST_CLIENT_SECRET,
    realm:         process.env.AITRUST_REALM,
    // mutual TLS: a separate host, and the cert pair kobilctl mounts at /certs
    proxyUrl:      process.env.AITRUST_PROXY_URL,
    proxyCertPath: process.env.AITRUST_PROXY_CERT_PATH,
    proxyKeyPath:  process.env.AITRUST_PROXY_KEY_PATH,
  });
  return _sdk;
}
# No SDK — the agent has no platform identity.
anthropic = AsyncAnthropic()
from kobil_aitrust import AITrust, AITrustConfig, AITrustInstance

_sdk: AITrustInstance | None = None
async def get_agent_sdk() -> AITrustInstance:
    global _sdk
    if _sdk is not None:
        return _sdk
    client_id = os.environ["AITRUST_CLIENT_ID"]   # your client id — no fallback
    _sdk = AITrust(AITrustConfig(
        agent_id=f"agent:{client_id}",
        guard_policy="standard",
        timeout_ms=120_000,
        platform_url=os.environ.get("AITRUST_MANAGEMENT_URL"),
        management_url=os.environ.get("AITRUST_MANAGEMENT_URL"),
        audit_url=os.environ.get("AITRUST_AUDIT_URL"),
        idp_url=os.environ.get("AITRUST_IDP_URL"),
        client_id=client_id,
        client_secret=os.environ.get("AITRUST_CLIENT_SECRET"),
        realm=os.environ["AITRUST_REALM"],
    ))
    return _sdk
Parameters — AITrust(config)AITrust(AITrustConfig(...))
ParameterRequiredWhat it is
agentIdagent_idyesStable agent identifier used for audit, in the form agent:<client_id>.
clientIdclient_id / clientSecretclient_secretyesOAuth 2.1 credentials issued when you registered the agent. Used to acquire tokens over mTLS.
managementUrlmanagement_urlyes*Base URL of the Management API (FGA checks, approver routing, identity badge).
auditUrlaudit_urlnoBase URL of the Audit API. Omit to disable platform audit.
idpUrlidp_url · realmyes*Identity provider base URL + SHIFT IDP realm (set it; the default is another tenant) for token issuance.
proxyUrlproxy_urlyes*Management proxy that issues tokens over mutual TLS — a different host from managementUrlmanagement_url. Without it the first tool call fails with proxyUrl is required for clientCredentials.
proxyCertPath / proxyKeyPathproxy_cert_path / proxy_key_pathyes*The agent's mTLS pair. kobilctl deploy mounts them at /certs and sets both for you.
timeoutMstimeout_msnoPer-call timeout in milliseconds (default 120000).

* Every field also resolves from AITRUST_* env vars (falling back to KOBIL_*), so you can pass an empty config and configure entirely by environment.

One naming trap.
  • The env var behind platformUrl is AITRUST_PLATFORM_URLnot AITRUST_MANAGEMENT_URL.
  • The snippet above passes AITRUST_MANAGEMENT_URL to both platformUrl and managementUrl explicitly, which is why it works.
  • If you drop those explicit fields and rely on the environment alone, set AITRUST_PLATFORM_URL too — otherwise platformUrl resolves to empty and AITrust() throws.
Checkpoint · needs platform

With valid creds + reachable URLs, getAgentSDK() resolves and await ai.health() returns sdk: healthy. Compiles offline, but identity is only real against the platform.

health() also lists vault, guard and audit. vault is gone and guard is a package this guide does not use, so both read "not installed" on a correct install — expected, and enforcement does not depend on them; the platform decides (Step 4). audit reads "not installed" too, even when the package is installed and importable: the SDK loads it through a dynamic import that bundlers do not resolve, so under Next.js that line is uninformative both locally and in the pod. Do not use health() to judge audit. Test it directly instead — write an event and read it back (Step 6). Allow a few seconds: the trail is not read-your-writes, so an immediate query can return an empty list for an event that was accepted.

3

Secured tool pipeline

@kobil/aitrustkobil_aitrust

What: run every tool through the SDK's guarded pipeline instead of calling it directly.

How: swap the local tool runtime for the SDK's defineTool / registerTools / toAnthropicToolsto_anthropic_tools, then dispatch the secured tools. Your tool definitions don't change.

These samples run on Anthropic, hence the Anthropic converter. The SDK also ships toOpenAITools and wrappers for OpenAI, LangChain and Vercel AI. The identity, policy and audit steps are the same either way.

src/tool-defs.ts — importsrc/tool_defs.py — import
import { defineTool } from "./tools-runtime.js";
import type { ToolDefinition, ToolInput } from "./tools-runtime.js";
import { defineTool } from "@kobil/aitrust";
import type { ToolDefinition, ToolInput } from "@kobil/aitrust";
from .tools_runtime import ToolDefinition, ToolInput, define_tool
from typing import Any
from kobil_aitrust import ToolDefinition, define_tool

ToolInput = dict[str, Any]   # convenience alias; the Python package exports the TS
                             # equivalent of ToolInput as a plain dict
src/agent.ts — build & dispatchsrc/agent.py — build & dispatch
import { toAnthropicTools } from "./tools-runtime.js";

const tools = createInsuranceTools({ /* ctx */ });
const anthropicTools = toAnthropicTools(tools);
// ...
const resultText = await tools[name].execute(input);   // runs directly — no checks
import { registerTools, toAnthropicTools } from "@kobil/aitrust";

const ai = await getAgentSDK();
const defs = createInsuranceTools({ /* ctx */ });   // the same 5-field ctx the starter
                                                   // already builds at agent.ts:270 —
                                                   // claimsCtx, getAnthropic, visionModel,
                                                   // getFile, saveFile. Don't paste the
                                                   // comment literally; reuse that object.
const securedTools = registerTools(ai, defs);          // wraps each tool
const anthropicTools = toAnthropicTools(securedTools) as unknown as Anthropic.Tool[];
// The double cast bridges the SDK's loose return type to Anthropic's stricter Tool[].
// It is safe here (shapes match) but it does switch off type-checking on tool schemas —
// so a typo in a parameter name will surface at runtime, not at compile time.
// ...
const resultText = await securedTools[name].execute(input);  // full pipeline
from .tools_runtime import to_anthropic_tools

defs = create_insurance_tools(ctx)
anthropic_tools = to_anthropic_tools(defs)
# ...
result_text = await defs[name].execute(tool_input)     # runs directly — no checks
from kobil_aitrust import register_tools, to_anthropic_tools

ai = await get_agent_sdk()
defs = create_insurance_tools(ctx)
secured = register_tools(ai, defs)                     # wraps each tool
anthropic_tools = to_anthropic_tools(secured)
# ...
result_text = await secured[name].execute(tool_input) # full pipeline

Order matters, and it will bite you. Each secured tool runs token acquire → FGA → CIBA → execute → audit — FGA comes after the token. So if token acquisition is failing, NotAuthorized is never raised and a denied tool fails exactly like an allowed one: a network error. Your policy looks unenforced when it is merely unreachable. Put the direct check of Step 4 in front of dispatch and you get the decision either way — that is what makes a deny observable in a running app, and it is why the check below is not an optional extra.

Each secured tool now runs: token acquire → FGA → CIBA → execute → audit. The starter's local tools-runtimetools_runtime was built with the same call shape, so this swap is mechanical.

Checkpoint · needs platform

The app compiles and behaves as before (no scopes added yet), and calls now flow through registerToolsregister_tools.

The first build will fail with Module not found: Can't resolve '@langchain/core/tools'. The SDK ships adapters for LangChain, OpenAI and Vercel; your bundler walks them all whether you use them or not. Mark the ones you do not use as external in next.config.mjs — this is not optional and it is not deploy-specific:

next.config.mjs
webpack: (config) => {
  config.externals = [...(Array.isArray(config.externals) ? config.externals : []),
    "@langchain/core", "@langchain/core/tools", "openai", "ai"];
  return config;
},

Note: this step calls getAgentSDK() from Step 2, so AITrust() throws ConfigurationError: platformUrl is required when AITRUST_MANAGEMENT_URL is unset. Set that and AITRUST_CLIENT_ID before running, or the first request that builds the SDK will fail.

Done. Your agent now has identity, FGA, CIBA, and audit — and your tool definitions barely changed. Grab the matched repos from Samples and diff Before vs After end-to-end.