# KOBIL Agent Trust - Complete Documentation > KOBIL Agent Trust gives every AI agent a verifiable identity, checks every tool call against policy before it executes, and writes every decision to a tamper-evident audit trail - without changing your existing APIs or AI models. This file is the entire developer documentation as plain text, generated from https://demo-agenttrust.shift-go.uk on 2026-08-11. It is intended to be read in full by an LLM or coding assistant: everything needed to integrate the SDK is below, in reading order, including both the TypeScript and Python variants of every code sample and both sides of every before/after comparison. Canonical HTML for each section is linked at the section heading. ## Contents - Platform - SDK Packages - Deployment Options - Pricing - Developer Portal - Quickstart - Integration Guide - Deploy - SDK Reference - Samples - Solution white paper: Verifiable Identity for Every AI Agent --- # Platform Source: https://demo-agenttrust.shift-go.uk/platform.html ## 8 Services, One Platform Every AI agent gets a verifiable identity and operates under enforced security controls. PLATFORM SERVICES 1 #### PostgreSQL :5432 One database with three schemas: SHIFT IDP, OpenFGA, and management. Every service owns its own schema, and all management data is stored relationally. 2 #### SHIFT IDP :80 SHIFT Identity Provider for the platform. It issues the tokens and handles login, CIBA, and DPoP on the pre-configured `aitrust` realm. 3 #### Elasticsearch :9200 Primary audit data store with five indices. It unifies the event data received from SDK clients and from SHIFT Kafka events. 4 #### OpenFGA :8080 Fine-grained permission engine. It answers a single question: can user X access document Y through agent Z? 5 #### Management API KOBIL :8100 Control plane for agent identity. Requests flow from the Agent SDK through Istio to the Management API, which writes to PostgreSQL, OpenFGA, and the AST CA. It exposes ten API groups; a token exchange touches all three backends. 6 #### Audit Service KOBIL :8101 Unified audit ingestion service. SDK events arrive through the REST API, SHIFT platform events arrive through Kafka, and every record is stored in Elasticsearch. 7 #### Istio (routing) Service mesh routing based on VirtualService rules. It enforces mTLS between the services, manages traffic, and routes each request by path to the platform services. 8 #### Redis :6379 In-memory cache with two databases. DB 2 serves the Management API config cache and DPoP nonce rotation; DB 3 serves the Audit anomaly detection counters. DEPLOYMENT A complete, deployable platform with no per-customer code changes. #### KOBIL Delivers - Agent Trust Platform (all 8 services). Deploy as-is or KOBIL-hosted - TypeScript & Python SDKs (3 packages each) — install & integration in the Developer Portal - Pre-configured SHIFT IDP realm, AST CA certificates, OpenFGA model, Istio routing - No custom code per customer. Same platform for everyone #### K8s Deployment - Single Helm chart: `helm upgrade --install aitrust server/helm/aitrust/` - ConfigMap: shared env vars (IDP, OpenFGA, AST CA, Redis, Elasticsearch, Kafka) - Secrets: database credentials, store IDs, encryption keys - Per-service Deployments with health probes, Istio sidecar, and config-checksum rolling restarts - Istio VirtualService: path-based routing (`/api/v1/*`, `/v1/*`, `/realms/*`) #### Customer Already Has - Their AI Agent / LLM. KOBIL wraps around it, doesn't modify it - Their Resource Server (APIs, RAG, MCP). No code changes needed - Their existing APIs. KOBIL adds security on top --- # SDK Packages Source: https://demo-agenttrust.shift-go.uk/sdk.html ## TypeScript + Python SDKs 3 packages per language. Drop-in security for any AI agent framework. Platform Agent Trust Agent SDK Agent Audit Managed Service KOBIL Agent Trust Platform ### Platform The K8s control plane behind the SDKs — agent identity, tokens, policies, and the audit trail. Identity serviceManagement APISHIFT IDPOpenFGAAudit service Developer SDKs @kobil/aitrust ### Agent Trust The unified meta-package — one install wraps any tool or LLM agent in the full security pipeline. IdentityFGACIBAAuditOne install Full API in the SDK Reference → Python TypeScript 01 @kobil/kobil-agent-sdk ### Agent SDK The core package — unified authentication and identity for AI agents. OAuth 2.1PKCECIBADPoPIdentityToken Vault Full API in the SDK Reference → Python TypeScript 02 @kobil/kobil-agent-audit ### Agent Audit Observability and compliance — a tamper-evident record of everything the agent did. Tamper-evident logSIEM exportToken trackingCIBA approvalCompliance Full API in the SDK Reference → Python TypeScript 03 BUILD WITH THE SDK Install one package and wrap your agent — every tool call gets identity, scoped tokens, human approval, and an audit trail. The hands-on guide — install, before/after code, and the full step-by-step integration in TypeScript & Python — lives in the Developer Portal. Quickstart Integration Guide SDK Reference FRAMEWORK SUPPORT Works with the OpenAI SDK, the Anthropic SDK, and Google ADK. No model changes required. OpenAI SDK Anthropic SDK Google ADK Install the SDK, point your API gateway to our JWKS endpoint, and every AI agent gets identity, certificates, permissions, audit trails, and human-in-the-loop approval. --- # Deployment Options Source: https://demo-agenttrust.shift-go.uk/deployment.html Packaging & Delivery ## One platform, two ways to run it What you get Layer 1 · Control plane #### The platform Eight services — identity provider, authorization, management API, audit, service mesh and their data stores — as one Helm chart. Realm, certificate authority, authorization model and routing ship pre-configured. 8 services · 1 chart Layer 2 · Developer surface #### The SDKs Three software development kit (SDK) packages per language from KOBIL's package registry: the meta-package that wraps a tool call, the identity and approval core, and the tamper-evident audit client. TypeScript and Python are at parity. 3 packages × 2 languages Layer 3 · Delivery #### How you run it KOBIL-hosted, or self-managed in your own Kubernetes. Same platform either way, with support, a stated version window and a published release cadence. Hosted or self-managed Two ways to run it | KOBIL-hosted | Self-managed Control plane runs | On KOBIL infrastructure | On your Kubernetes cluster You provide | Your AI agent and your resource servers | A Kubernetes cluster, plus your AI agent and resource servers Delivery | Managed service, no artifacts to install | Single Helm chart, container images, SDK packages Upgrades | KOBIL, on the published cadence | You, with `helm upgrade` Agent traffic | Your agents call the platform over mutual TLS (mTLS) | Stays inside your cluster Your APIs and models | Unchanged in both cases. The platform wraps your agent; it does not modify it. Custom development | None in either case. No custom code per customer — the same platform ships to everyone. Priced from | €60,000 per year, by audit capacity | €80,000 per year, by deployment scope What ships What you get | Ships as Control plane | 1 Helm chart, 8 container images Software development kits (SDKs) | 6 packages: 3 per language, TypeScript and Python at parity Documentation | Integration guide, SDK reference, quickstart #### SDK packages Language | Protocol | Packages TypeScript | npm | `@kobil/aitrust`, `@kobil/kobil-agent-sdk`, `@kobil/kobil-agent-audit` Python | PyPI | `kobil-aitrust`, `kobil-agent-sdk`, `kobil-agent-audit` --- # Pricing Source: https://demo-agenttrust.shift-go.uk/pricing.html ## Simple pricing, unlimited agents One platform, two ways to run it. Never priced by agent, decision or approval. Most deployments KOBIL-Hosted We operate the control plane. Nothing to install. from €60,000 per year Implementation from €10,000 - Priced by audit capacity, from 25 million units per month - 90-day searchable retention included - Unlimited agent identities - Shared platform by default, single-tenant available Talk to us Self-Managed Runs in your Kubernetes, under your control. from €80,000 per year Implementation from €40,000 - Priced by deployment scope, not by audit volume - Capacity and retention bounded only by your infrastructure - Unlimited agent identities - Sovereign scope adds your own hardware security module (HSM) Talk to us KOBIL-Hosted capacity Included capacity | Annual price | Implementation 25 million audit units per month | €60,000 | €10,000 50 million audit units per month | €80,000 | €10,000 100 million audit units per month | €120,000 | from €15,000 Single-tenant deployment, dedicated to you | from €240,000 | from €25,000 Beyond your included capacity | €75 per additional million units, billed in arrears — your agents are never blocked Retention beyond 90 days | 12 months searchable, +€12,000 per year at any capacity level Self-Managed scopes | Standard | Sovereign Annual price | €80,000 | from €240,000 Production clusters | 1 | Unlimited Certificate authority | KOBIL certificate authority (CA) | Your own hardware security module (HSM), offline root Support | Business hours | Named technical contact, extended hours Audit capacity and retention | Bounded by your own infrastructure. No unit metering, no overage. Implementation | From €40,000, scoped per estate Who provides what | KOBIL-Hosted | Self-Managed Platform software | KOBIL — one Helm chart, eight container images Software development kits (SDKs) | KOBIL — six packages, TypeScript and Python at parity Realm, certificate authority, authorization model, routing | KOBIL — pre-configured, identical for every customer Kubernetes cluster | KOBIL | You Databases, search, storage, backups | KOBIL | You Upgrades | KOBIL, on the published cadence | You, with `helm upgrade` Your AI agent and resource servers | You, in both models Custom development | None in either model. The platform wraps your agent; your APIs and models are unchanged. --- # Developer Portal Source: https://demo-agenttrust.shift-go.uk/developers.html ## Developer Portal ### Start here Two runnable starter apps — same insurance-claims agent, your choice of language. #### TypeScript starter TypeScriptNode ≥ 18Anthropic `aitrust-agent-starter` — browser chat, Claude Vision damage assessment, settlement PDF, in-browser signing. No KOBIL SDK yet. View the repo → #### Python starter PythonFastAPIAnthropic `aitrust-agent-starter-python` — the same app on FastAPI + reportlab. Identical flow and API, shared web UI. View the repo → ### What the SDK adds to a tool call Register your tools once; every call the model makes runs through one guarded pipeline. - 1token acquire mTLS, no secrets in agent memory - 2FGA check OpenFGA policy decides - 3CIBA approval human says yes on phone - 4execute your tool code runs - 5audit tamper-evident trail Step 1 #### Identity Every agent has a verifiable platform identity; tokens are acquired over mTLS and never live in agent memory. Steps 2–3 #### Authorization & approval OpenFGA decides which tools may run; sensitive actions require a human approval on their phone via CIBA. Step 5 #### Audit Every tool call is written to a tamper-evident audit trail. --- # Quickstart Source: https://demo-agenttrust.shift-go.uk/quickstart.html ## Run your first agent Start from the SDK-free starter — a complete AI insurance-claims agent. It runs entirely on your machine with just an Anthropic API key: no platform account, no external services. What you'll run: a browser chat where a customer describes an accident and uploads a photo; the agent looks up the policy, assesses the damage with Claude Vision, calculates a settlement, generates a PDF agreement, and lets the customer sign it in the browser. ### 1 · Prerequisites Node ≥ 18 and an Anthropic API key . Python ≥ 3.11 and an Anthropic API key . ### 2 · Install & run [TypeScript] ```typescript cd aitrust-agent-starter cp .env.example .env # paste your ANTHROPIC_API_KEY npm install npm run dev # → http://localhost:3005 ``` [Python] ```python cd aitrust-agent-starter-python cp .env.example .env # paste your ANTHROPIC_API_KEY python -m venv .venv && source .venv/bin/activate pip install -e . python -m src.server # → http://localhost:3005 ``` Commands assume a POSIX shell (macOS, Linux, WSL, Git Bash). On Windows `cmd.exe` use `copy .env.example .env`, and `.venv\Scripts\activate` to activate the virtualenv. ### 3 · Drive a claim Open `http://localhost:3005` and: ##### Describe the accident - e.g. “I had a car accident and my front bumper is damaged” — and attach a photo of any car (). ##### Watch the agent work - It calls `check_policy`, runs a Claude Vision `assess_damage`, then `calculate_settlement` — each shown as a tool chip. ##### Accept & generate - Say “I accept option 1, generate the agreement”. A settlement PDF appears with a signature pad. ##### Sign in the browser - Draw a signature and confirm — the signed PDF is produced and downloadable. If the agent pauses after the assessment instead of auto-calculating, just say “calculate my settlement” — that's normal LLM behaviour, not a bug. ### 4 · What's missing (on purpose) The starter deliberately has no agent identity, authorization, human approval, or audit. That's exactly what you add next. #### Add the Agent Trust SDK → Follow the 7-step integration guide to turn this starter into a fully-secured production agent — one capability at a time, with copy-paste diffs for TypeScript and Python. Open the integration guide → --- # Integration Guide Source: https://demo-agenttrust.shift-go.uk/integration.html ## 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 After · with SDK TypeScript — request access Python — request access 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. Variable | Needed from | What it is / where it comes from `ANTHROPIC_API_KEY` | baseline | Your model provider's API key. The sample runs on Anthropic; the variable is the sample's, not the platform's. `AITRUST_MANAGEMENT_URL` | Step 2 | Base URL of your platform tenant. Required — `AITrust()` throws `ConfigurationError` without it. `AITRUST_CLIENT_ID` / `AITRUST_CLIENT_SECRET` | Step 2 | Agent 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_URL` | Step 2 | SHIFT IDP base URL (token acquisition, CIBA). `AITRUST_REALM` | Step 2 | IDP 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_URL` | Step 6 | Audit service base URL. Events are dropped silently if unreachable. `AITRUST_AGENT_ID` | Step 2 | The agent's stable id, written as `agent:` 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_URL` | Step 2 | Management 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_PATH` | Step 2 | The 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) [TypeScript] ```typescript @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} ``` [Python] ```python [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 [TypeScript] ```typescript npm install @kobil/aitrust @kobil/kobil-agent-sdk @kobil/kobil-agent-audit --legacy-peer-deps ``` [Python] ```python 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 [TypeScript] [BEFORE - without the SDK] ```typescript "dependencies": { "@anthropic-ai/sdk": "^0.40.0", "pdf-lib": "^1.17.1" } ``` [TypeScript] [AFTER - with the SDK] ```typescript "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" } ``` [Python] [BEFORE - without the SDK] ```python dependencies = [ "anthropic>=0.40.0", "reportlab>=4.2.0", "pypdf>=5.1.0", ] ``` [Python] [AFTER - with the SDK] ```python 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 [TypeScript] [BEFORE - without the SDK] ```typescript // No SDK — the agent has no platform identity. // The Anthropic client is the only thing constructed. const anthropic = new Anthropic(); ``` [TypeScript] [AFTER - with the SDK] ```typescript import { AITrust } from "@kobil/aitrust"; import type { AITrustInstance } from "@kobil/aitrust"; let _sdk: AITrustInstance | null = null; export async function getAgentSDK(): Promise { 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; } ``` [Python] [BEFORE - without the SDK] ```python # No SDK — the agent has no platform identity. anthropic = AsyncAnthropic() ``` [Python] [AFTER - with the SDK] ```python 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(...))` Parameter | Required | What it is `agentIdagent_id` | yes | Stable agent identifier used for audit, in the form `agent:`. `clientIdclient_id` / `clientSecretclient_secret` | yes | OAuth 2.1 credentials issued when you registered the agent. Used to acquire tokens over mTLS. `managementUrlmanagement_url` | yes* | Base URL of the Management API (FGA checks, approver routing, identity badge). `auditUrlaudit_url` | no | Base URL of the Audit API. Omit to disable platform audit. `idpUrlidp_url` · `realm` | yes* | Identity provider base URL + SHIFT IDP realm (set it; the default is another tenant) for token issuance. `proxyUrlproxy_url` | yes* | 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_path` | yes* | The agent's mTLS pair. `kobilctl deploy` mounts them at `/certs` and sets both for you. `timeoutMstimeout_ms` | no | Per-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_URL` — not `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 [TypeScript] [BEFORE - without the SDK] ```typescript import { defineTool } from "./tools-runtime.js"; import type { ToolDefinition, ToolInput } from "./tools-runtime.js"; ``` [TypeScript] [AFTER - with the SDK] ```typescript import { defineTool } from "@kobil/aitrust"; import type { ToolDefinition, ToolInput } from "@kobil/aitrust"; ``` [Python] [BEFORE - without the SDK] ```python from .tools_runtime import ToolDefinition, ToolInput, define_tool ``` [Python] [AFTER - with the SDK] ```python 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 [TypeScript] [BEFORE - without the SDK] ```typescript 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 ``` [TypeScript] [AFTER - with the SDK] ```typescript 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 ``` [Python] [BEFORE - without the SDK] ```python 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 ``` [Python] [AFTER - with the SDK] ```python 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. Phase 2 / 3 ### Enforcement & trust Decide which tools may run, require a human for sensitive actions, and record everything to a tamper-evident trail. 4 ### Authorization (FGA) @kobil/aitrustkobil_aitrust What: decide which tools may run from a central policy. How: the SDK checks each tool against OpenFGA by its name — `tool:` with permission `can_execute` (or `needs_approval` when the tool sets `needsApproval`) — and throws `NotAuthorized` when denied. Catch it in the loop. What actually grants access. Access is granted by OpenFGA tuples on the tool, seeded per agent: `allowed_agent` to permit, `denied_agent` to block, `require_approval` to force CIBA. The `scopes` list below is not read by this check — it is metadata used to generate those seed tuples, and it is the scope set requested at token acquisition (where the platform runs a separate `can_use` check on `scope:`). Editing `scopes` alone will not change whether a registered tool runs; change the tuples. tool-defs.tstool_defs.py [TypeScript] [BEFORE - without the SDK] ```typescript generate_settlement_document: defineTool({ name: "generate_settlement_document", parameters: { /* ... */ }, execute: async (input) => { /* ... */ }, }), ``` [TypeScript] [AFTER - with the SDK] ```typescript generate_settlement_document: defineTool({ name: "generate_settlement_document", scopes: ["insurance:write"], // metadata: seeds FGA tuples + token scope parameters: { /* ... */ }, execute: async (input) => { /* ... */ }, }), ``` [Python] [BEFORE - without the SDK] ```python "generate_settlement_document": define_tool(ToolDefinition( name="generate_settlement_document", parameters={...}, execute=_generate_settlement_document, )), ``` [Python] [AFTER - with the SDK] ```python "generate_settlement_document": define_tool(ToolDefinition( name="generate_settlement_document", scopes=["insurance:write"], # metadata: seeds FGA tuples + token scope parameters={...}, execute=_generate_settlement_document, )), ``` agent.ts — handle denialagent.py — handle denial [TypeScript] [BEFORE - without the SDK] ```typescript // delete_claim was blocked with a hard-coded throw in code: execute: async () => { throw new Error("Deleting claims is blocked by policy"); } ``` [TypeScript] [AFTER - with the SDK] ```typescript import { NotAuthorized } from "@kobil/aitrust"; try { const resultText = await securedTools[name].execute(input); } catch (e) { if (e instanceof NotAuthorized) { // DENIED centrally by FGA — no scope. Tell the model + audit captured it. } else throw e; } ``` [Python] [BEFORE - without the SDK] ```python # delete_claim was blocked with a hard-coded raise in code: async def _delete_claim(_inp): raise RuntimeError("Deleting claims is blocked by policy") ``` [Python] [AFTER - with the SDK] ```python from kobil_aitrust import NotAuthorized try: result_text = await secured[name].execute(tool_input) except NotAuthorized: ... # DENIED centrally by FGA — no scope ``` This moves the `delete_claim` decision out of code and into a policy you can change without a redeploy — and the denial is now audited. Prerequisite. The denial only takes effect once either: - a `denied_agent` tuple exists for `tool:delete_claim`, or - the agent simply has no `allowed_agent` tuple. Seed it with the platform's OpenFGA setup, or flip it in the Agent Trust Dashboard. Without a reachable OpenFGA and seeded tuples, this catch block never fires. Never cache an authorization decision. Calling the platform directly, send `cache: "no-store"`. Frameworks cache `fetch` by default — Next.js does — and a cached decision means a permission you revoke keeps working until the cache expires. calling the check directly ``` const res = await fetch(`${process.env.AITRUST_MANAGEMENT_URL}/api/authorization/check`, { method: "POST", headers: { "Content-Type": "application/json" }, // bare client id — this endpoint adds the agent: prefix itself. // Sending "agent:" here yields agent:agent:, which denies everything. body: JSON.stringify({ agentId: process.env.AITRUST_CLIENT_ID, toolName: tool }), cache: "no-store", // a revoked permission must stop working now signal: AbortSignal.timeout(8000), }); // Fail closed: an authorization service you cannot reach is not consent. if (!res.ok) return { allowed: false, requiresCIBA: false }; // Three states, not two. A `ciba` rule answers allowed:false + requiresCIBA:true, // so reading `allowed` alone reports an approval-gated tool as a flat denial. const { allowed, requiresCIBA, policy } = await res.json(); // policy: "allow" | "ciba" | "deny" ``` Checkpoint · needs platform (FGA) With OpenFGA tuples seeded, a tool whose scope the agent lacks raises `NotAuthorized`; an allowed tool runs. 5 ### Human approval (CIBA) @kobil/aitrustkobil_aitrust What: require a person to approve sensitive actions. How: mark the tool `needsApprovalneeds_approval` and provide an `approver` + `approvalMessageapproval_message`. The SDK pauses, pushes the request to the approver's phone, and only runs `execute` on approval. What "pushes it to the phone" actually means. Three pieces sit behind that sentence, and you need all three for this step to do anything visible: - SHIFT IDP — initiates the CIBA backchannel request. - CIBA Backend (`:8092`) — tracks the pending approval and delivers the push. - Mobile approver app — where the human actually taps Approve. The approver is per-deployment, so read it from the environment rather than baking an address into the image — there is no platform variable for it, pick your own (`APPROVER_EMAIL`) and set it in `.env.local`. Register the tool as `ciba` and declare `needsApprovalneeds_approval` in code: the registration decides whether approval is demanded, the code decides who is asked, and a tool registered `ciba` with no approver has nobody to ask. The approver must be enrolled on a device with the app installed. Without one the call fails fast with `invalid user` — not a timeout, so do not read a quick failure as a wiring problem. tool-defs.ts — request_signaturetool_defs.py — request_signature [TypeScript] [BEFORE - without the SDK] ```typescript request_signature: defineTool({ name: "request_signature", scopes: ["claims:sign"], execute: async (input) => { /* send for signing */ }, }), ``` [TypeScript] [AFTER - with the SDK] ```typescript request_signature: defineTool({ name: "request_signature", scopes: ["claims:sign"], needsApproval: true, // ← gate on a human approver: resolveApproverForPolicyholder, // string | (input) => string approvalMessage: (input) => buildCibaBindingMessage("request_signature", input), execute: async (input) => { /* send for signing */ }, }), ``` [Python] [BEFORE - without the SDK] ```python "request_signature": define_tool(ToolDefinition( name="request_signature", scopes=["claims:sign"], execute=_request_signature, )), ``` [Python] [AFTER - with the SDK] ```python "request_signature": define_tool(ToolDefinition( name="request_signature", scopes=["claims:sign"], needs_approval=True, # ← gate on a human approver=resolve_approver_for_policyholder, # str | (input) -> str approval_message=lambda inp: _build_ciba_binding_message("request_signature", inp), execute=_request_signature, )), ``` Start with a static approver. `approverapprover` accepts a plain email string — `approver: "approver@example.com"approver="approver@example.com"` is enough to complete this step. The `resolveApproverForPolicyholderresolve_approver_for_policyholder` shown above is not a one-liner: in the reference it is ~50 lines that call the platform's per-policyholder routing endpoint over mTLS, with its own fail-open/fail-closed policy. Treat per-policyholder routing as an advanced pattern to add later, not a prerequisite. On `request_signature`: this tool is not in the public starter — we introduce it here to show the CIBA fields, and its body is completed in Step 9. To apply CIBA to a tool you already have, put the same fields on `generate_settlement_document`. Parameters — CIBA fields on a tool Field | Type | What it does `needsApprovalneeds_approval` | boolean | When true, the SDK opens a CIBA backchannel and waits for a human before executing. `approver` | string | fn(input) | Login hint of who approves — a static email, or a function that resolves it per call (e.g. per-policyholder routing). `approvalMessageapproval_message` | string | fn(input) | The binding message shown on the approver's device. Keep it ≤ 50 chars, no spaces (e.g. `Sign-CLM-ABC123`) — it is a binding token tying the approval to this one call, not a sentence, so identify the action and the object and let the device render the rest. handle decline / timeout [TypeScript] [BEFORE - without the SDK] ```typescript // Nothing — there was no approval step. ``` [TypeScript] [AFTER - with the SDK] ```typescript import { ApprovalDenied, ApprovalTimeout } from "@kobil/aitrust"; // catch ApprovalDenied (approver said no) and ApprovalTimeout (nobody answered) ``` [Python] [BEFORE - without the SDK] ```python # Nothing — there was no approval step. ``` [Python] [AFTER - with the SDK] ```python from kobil_aitrust import ApprovalDenied, ApprovalTimeout # except ApprovalDenied / ApprovalTimeout ``` Checkpoint · needs platform + a device Calling the tool pushes a prompt to the approver's mobile approver app; approving lets `execute` run, denying raises `ApprovalDenied`. 6 ### Audit kobil-agent-audit What: a tamper-evident trail. How: tool calls via the secured registry are audited automatically — for events outside the tool loop (inbound messages, signing/payment callbacks), POST them yourself. `action` and `eventType` are both required top-level fields — moving either one into `details` gets you a `422`. Everything else can go in `details`. server.tsserver.py [TypeScript] [BEFORE - without the SDK] ```typescript // No audit trail — events were only console.log'd locally. console.log("[SIGNED]", instanceId); ``` [TypeScript] [AFTER - with the SDK] ```typescript await ai.audit.logEvent({ action: "document_sign", // required (top-level) eventType: "claims.document_signed", // required (top-level) outcome: "success", resourceId: instanceId, details: {}, }); // agentId is filled from the SDK config. Use the SDK, not a bare fetch: on a // deployed external agent AITRUST_AUDIT_URL is an mTLS gateway, and only the // SDK transport presents the client certificate. ``` [Python] [BEFORE - without the SDK] ```python # No audit trail — events were only printed locally. print("[SIGNED]", instance_id) ``` [Python] [AFTER - with the SDK] ```python await ai.audit.log_event({ "action": "document_sign", # required (top-level) "eventType": "claims.document_signed", # required (top-level) "outcome": "success", "resourceId": instance_id, "details": {}}) # agentId is filled from the SDK config; the SDK transport also handles the # mTLS gateway a deployed external agent talks to — a bare HTTP POST cannot. ``` Checkpoint · needs platform A completed tool call (and your manual events) appear in `GET {AUDIT_URL}/v1/events?agentId=agent:`. 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. --- ### Step 7 - End-user identity & approver routing (optional) Everything so far ran with a hardcoded userId. For a deployed agent that means one static CIBA approver and a public chat page. This optional step adds real end-user login and per-policyholder approver routing. Register a public OIDC client with PKCE in the `agenttrust` realm of SHIFT IDP, redirect URI `https:///auth/callback` (ask your platform admin). This is a different client from AITRUST_CLIENT_ID, and a different IDP from the one kobilctl registers apps in - keep `"oidc": false` in kobil.json and let the SDK own the login. Env: OIDC_CLIENT_ID, OIDC_AUTHORIZE_URL and OIDC_TOKEN_URL (agenttrust realm endpoints), OIDC_REDIRECT_URI, KOBIL_SESSION_SECRET (stable across restarts). TypeScript: ```ts import { createKobilIdentity } from "@kobil/kobil-agent-sdk/web"; const identity = process.env.OIDC_CLIENT_ID ? createKobilIdentity() : null; // null = local dev, unchanged // per request: if (identity && await identity.handle(req, res)) return; // owns /auth/login + /auth/callback const user = identity ? await identity.getUser(req) : null; // { sub, email } | null const userId = user?.email ?? "claims-adjuster"; // the policyholder ``` Python: `from kobil_agent_sdk.web import create_kobil_identity` - same shape (`get_user`, module docstring shows the FastAPI wiring for the two auth routes). Approver routing: `GET {AITRUST_MGMT_URL}/agents/{AITRUST_CLIENT_ID}/route-approver?policyholder_email={userId}` returns `{ "approver_email": ... }` - pass it as the CIBA login hint. Three caveats: (1) the endpoint is behind ROUTING_ENDPOINT_ENABLED=true on the management API, off by default; (2) fall back to a default approver on routing errors but LOG it - a `[ROUTING]` warning means CIBA still works yet every request goes to the static approver; (3) the routed approver must be a real realm user with the approver app (see /approver.html) installed and signed in. Checkpoint: open /auth/login, sign in, request a payout - the CIBA push reaches the approver routed for your email, and the agent log shows no [ROUTING] warning. # Deploy Source: https://demo-agenttrust.shift-go.uk/deploy.html ## Deploy Internal and design-partner use. This guide deploys to a KOBIL-managed cluster with `kobilctl`, using access your KOBIL contact provides. To run an agent on your own Kubernetes, talk to your KOBIL contact. Before you start Integrate the SDK first Phase 1 / 3 ### Prepare Install the CLI, connect to the cluster, and let `kobilctl` tell you the URL your agent will answer on. 0 ### Install What: the CLI, connected to the cluster. How: one credential, plus standard machine setup. The credential — your registry token, from a platform admin. It is the only one you are given: `login` exchanges it for cluster access itself, so you never request or handle a cluster credential. The machine setup — one-time, and nothing to rotate: - Node 20 or newer, with `kubectl`, `helm` and `git` on your PATH - SSH access to the cluster host: your admin authorises your key, and gives you the alias for `~/.ssh/config`. `kobilctl` opens and repairs the tunnel itself. - Docker is not required — the cluster builds your image install ``` cat >> ~/.npmrc <<'EOF' @development:registry=https://gitlab.kobil.com/api/v4/packages/npm/ //gitlab.kobil.com/api/v4/packages/npm/:_authToken=YOUR_DEPLOY_TOKEN EOF chmod 600 ~/.npmrc npm install -g @development/kobilctl ``` This is a different registry — and a different token — from the `@kobil` one in the Integration Guide. The SDK token does not install kobilctl: GitLab reports the mismatch as 404 Project not found, not as an auth error. Ask your platform admin for the kobilctl install token. connect ``` kobilctl login alice ``` `login` writes `~/.kobil/kubeconfig.yaml` at mode `0600`. Access lasts 90 days and renews itself, so there is nothing to request later. Pass `--token` or `--kubeconfig` if you were handed either; a kubeconfig you supply is never touched. Checkpoint · local `kobilctl doctor` reports no failures. 1 ### Describe the app What: a `Dockerfile`, a `kobil.json`, and your URL. How: run `init` in the agent's directory. init ``` cd my-agent && kobilctl init # → https://alice-my-agent.shift-go.uk ``` Run this before you open the Dashboard, so you know the host before anything references it (registration takes no description field — the URL is for your own records). Registration itself does not ask for the URL. Commit `kobil.json`. Its `app` field fixes your namespace and URL, so every redeploy lands on the same host. `"oidc": false` tells `deploy` the Dashboard owns the login. `init` can only add it once agent credentials exist, so set it by hand after Step 3. Leave it out if the app has its own user login. On a Next.js project, `init` also adds `output: "standalone"` to your Next config if it is missing, and tells you it did. The generated image ships `.next/standalone`, which Next only produces when asked; without it the container starts and exits immediately. Checkpoint · local `kobil.json` has your `app` name (plus `"oidc": false` only if the Dashboard owns the login), and `init` printed your URL. Phase 2 / 3 ### Identity The Dashboard issues the agent's identity. Bring it back to disk. 2 ### Register in the Dashboard What: credentials, an mTLS certificate, and the policy that governs the agent. Where: the Agent Trust Dashboard, under Agents → Register agent. Sign in with your KOBIL account. Dashboard Open the Agent Trust Dashboard How: fill in the registration form. - Name — required, and it becomes the Client ID unless you set one. The Client ID is immutable afterwards, and it prefixes the certificate files you download. - Owner Email — required. This is the agent's default approver: when an approver routing rule matches it wins, otherwise the request falls back to this address, and it fails only when there is neither. Set it even if your code picks approvers itself — it is the fallback that keeps approval working. - Deployment: External — see the warning below. The field defaults to In-cluster, so you have to change it. - Scopes and Tool permissions — both come pre-selected for the agent type. The tool list is a fixed catalogue, not free text: you set each one to allow, ciba or deny, and a tool your code calls that is not in the catalogue has no policy and is refused. Registration never asks for the URL your agent runs on. The fields under Advanced are optional and play no part in deployment — leave them empty. Choose Deployment: External. In-cluster writes the mTLS identity straight into the platform's own cluster, where your agent is not running, and hands you nothing to download. External returns the certificate and key once, which is what Step 3 puts in `certs/`. Then: the Dashboard shows the credentials once. Take all four now: - `agent id` and `client id` — the agent id is a UUID that addresses the agent over the API. The client id is what goes in `AITRUST_AGENT_ID` and `AITRUST_CLIENT_ID` in Step 3: audit and authorization are written against `agent:`, never the UUID. - `client secret` — into `.env.local` in Step 3 - `-tls.crt` and `-tls.key`, from the download buttons — into `certs/` in Step 3 Neither is shown again. The secret is displayed once and the private key is never stored by the platform. Lose either and the only way forward is to register the agent again for a fresh pair. Declare what the agent may do, as you register it. Send one entry per tool your code declares — `allow`, `ciba` or `deny` — and your own scopes. The platform turns them into the authorization rules it enforces. register with your own tools and scopes ``` curl -X POST "$AITRUST_MANAGEMENT_URL/api/agents/register" \ -H 'Content-Type: application/json' -d '{ "name": "my-agent", "ownerEmail": "you@example.com", "deploymentTarget": "external", "scopes": ["my-agent-read", "my-agent-write"], "toolPermissions": { "search_listings": "allow", "grant_report_access": "deny" } }' ``` The registration form offers only the built-in insurance agent's tools and scopes, with no field for your own. Until that changes, register through the API above if your agent is anything else. Scope names are free strings, but the ones you send here and the ones your tools declare in code must match exactly — nothing reconciles them for you. The response echoes them under `unboundScopes`, meaning they exist as authorization rules but are not yet SHIFT IDP client scopes; tool rules still apply. Afterwards the Dashboard shows the rules under Authorization → Rules, but its editor only offers tools it already knows, so change your own through the same API: change a rule, no redeploy ``` # allow can_execute · approval needs_approval · deny denied_agent # POST ADDS a rule. It never replaces one, and deny outranks allow — so to change a # rule, DELETE the old one first. Adding allow on top of a deny leaves it denied. curl -X DELETE "$AITRUST_MANAGEMENT_URL/api/authorization/tuples" \ -H 'Content-Type: application/json' \ -d '{"user":"agent:my-agent","relation":"denied_agent","object":"tool:search_listings"}' curl -X POST "$AITRUST_MANAGEMENT_URL/api/authorization/tuples" \ -H 'Content-Type: application/json' \ -d '{"user":"agent:my-agent","relation":"can_execute","object":"tool:search_listings"}' ``` Deleting a rule revokes it, since a tool with no rule is denied. The change is live on the next call — provided the agent does not cache the decision (Integration Step 4). Check the decision, not the response. `POST` answers `{"ok":true}` for a rule it added even when that rule changes nothing, because the deny you left in place still wins. Confirm with `POST /api/authorization/check` before believing a change took effect. A tool with no rule is denied. Register with an empty `toolPermissions` and the agent deploys, reports healthy, and refuses every call — which reads like a broken integration rather than an empty policy. The Dashboard is also where you read the audit trail. The development Dashboard serves a staging certificate, so your browser warns that the connection is not private the first time you open it. That is expected in this environment. Verify the host reads `….gondor.dev.kobil.com` before you continue. Checkpoint · dashboard The agent is listed under Agents, you have both PEM downloads on disk, and Authorization → Rules shows a rule for every tool your agent declares. 3 ### Credentials on disk What: the Dashboard's output, where `deploy` reads it. How: credentials into `.env.local`, and the two PEMs into `certs/` — renamed. The Dashboard downloads them prefixed with the client id; `deploy` looks for `tls.crt` and `tls.key`. rename ``` mkdir -p certs mv ~/Downloads/-tls.crt certs/tls.crt mv ~/Downloads/-tls.key certs/tls.key chmod 600 certs/tls.key ``` Registered through the API instead? There are no downloads — the same two PEMs come back in the response as `mtlsCertificate` and `mtlsPrivateKey`. Write them out yourself, and do not save the response to a file: it holds the private key and the client secret, the generated `.dockerignore` excludes `certs/` but knows nothing about a file you invent, and every Dockerfile here does `COPY . .` — so a saved response is baked into an image layer and pushed to the registry. Pipe it: from the API response ``` mkdir -p certs # pipe the response straight in — do not save it to a file first curl -s -X POST "$AITRUST_MANAGEMENT_URL/api/agents/register" \ -H 'Content-Type: application/json' -d @register.json \ | python3 -c 'import json,sys; d=json.load(sys.stdin) open("certs/tls.crt","w").write(d["mtlsCertificate"]) open("certs/tls.key","w").write(d["mtlsPrivateKey"]) print("client secret:", d["clientSecret"])' chmod 600 certs/tls.key ``` my-agent/ ``` my-agent/ ├── kobil.json "oidc": false (see Step 1) ├── .env.local the settings below └── certs/ ├── tls.crt └── tls.key ``` .env.local ``` # Issued by the Dashboard in Step 2 AITRUST_CLIENT_ID=my-agent AITRUST_CLIENT_SECRET=... AITRUST_AGENT_ID=my-agent # the client id, not the UUID # The environment: ask your KOBIL contact for these AITRUST_PLATFORM_URL=https:///dashboard AITRUST_MANAGEMENT_URL=https:///dashboard AITRUST_AUDIT_URL=https:///dashboard AITRUST_PROXY_URL=https:// # NOT the platform host — ask for it AITRUST_IDP_URL=https:///auth AITRUST_REALM=agenttrust ``` `AITRUST_AGENT_ID` is easy to miss and the failure is opaque: without it the app starts, serves traffic, and refuses the first tool call with `MISSING_CONFIG: GuardConfig.agentId is required`. The platform URLs belong to the environment, not to your agent, so registration does not return them. `AITRUST_PROXY_URL` is the one people miss, twice over. Without it the first tool call fails with `proxyUrl is required for clientCredentials` — and it is a separate host from the platform URLs above, because it is the only endpoint that terminates mutual TLS. Point it at the platform host and every tool call fails with `Client certificate not provided`, because that host never asks for your certificate. Ask your KOBIL contact for the mTLS host explicitly; it is not derivable from the others. Set `OPENFGA_STORE_ID` only if your own code queries OpenFGA directly. The SDK does not read it — it asks the platform, which resolves the store itself. `certs/` is mounted into the pod at `/certs`, and `AITRUST_PROXY_CERT_PATH` and `AITRUST_PROXY_KEY_PATH` are set for you. Keep the PEMs as files: flattening one into `.env` fails at the TLS handshake. How env files merge: `.env.production.local` -> `.env.local` -> `.env.production` -> `.env`, first seen wins — and the merged result ships to the pod. `AITRUST_PROXY_CERT_PATH`/`_KEY_PATH` are derived by kobilctl as defaults, so any value in your env files overrides them; a relative local path there breaks the pod (kobilctl warns when it sees one). `deploy` refuses to run if git is tracking anything in `certs/`. `init` adds it to `.gitignore` and `.dockerignore`, so this only fires if it was committed before. The development platform serves a staging certificate. Node refuses it with `UNABLE_TO_GET_ISSUER_CERT`, so the agent starts but cannot reach its control plane. Ship the chain and point `NODE_EXTRA_CA_CERTS` at it. Do not disable verification. save the chain ``` HOST= { openssl s_client -connect $HOST:443 -servername $HOST -showcerts /dev/null \ | awk '/BEGIN CERT/,/END CERT/' | awk 'BEGIN{n=0} /BEGIN CERT/{n++} n>1' curl -s https://letsencrypt.org/certs/staging/letsencrypt-stg-root-x1.pem } > certs/platform-ca.pem # then in .env.local NODE_EXTRA_CA_CERTS=/certs/platform-ca.pem ``` It goes in `certs/` because everything there is mounted at `/certs` for you — no Dockerfile change. The server sends its leaf and intermediates but not the root, and Node needs a chain ending in one, hence the second command. `/certs` is the container path — this same `.env.local` is what `next dev` reads on your machine, where it does not exist, so to run locally override all three pod paths (`NODE_EXTRA_CA_CERTS`, `AITRUST_PROXY_CERT_PATH`, `AITRUST_PROXY_KEY_PATH`) to your own `certs/` directory. Checkpoint · local Both PEMs are in place, and `certs/` is not tracked. If the project is a git repo, `git ls-files certs/` returns nothing; if it is not one, there is nothing to check — nothing here requires git. Phase 3 / 3 ### Ship Publish, then confirm the agent works rather than merely runs. 4 ### Deploy What: the agent live at your URL. How: one command. It sends your source to the cluster, which builds the image and pushes it, then applies the chart and waits for pods to become ready. deploy Building in the cluster — the default — needs the SDK vendored: build pods cannot reach `gitlab.kobil.com`, so `npm ci` fails on `getaddrinfo`. Install once locally, copy into `vendor/@kobil/`, depend on them by path: vendor the SDK ``` mkdir -p vendor/@kobil cp -R node_modules/@kobil/* vendor/@kobil/ ls vendor/@kobil # must list every package, not just aitrust # in package.json — every @kobil entry, not only the meta-package "@kobil/aitrust": "file:vendor/@kobil/aitrust", "@kobil/kobil-agent-sdk": "file:vendor/@kobil/kobil-agent-sdk", "@kobil/kobil-agent-audit": "file:vendor/@kobil/kobil-agent-audit" rm -f .npmrc rm -rf node_modules package-lock.json && npm install # lockfile must reference no remote @kobil ``` Do run that `ls`. Without `--legacy-peer-deps` npm nests `kobil-agent-sdk` inside `aitrust/node_modules`, the copy misses it, and the app builds fine then dies at runtime on `Cannot find module`. In your source tree the SDK is no longer a dependency to a bundler: it walks the package and fails on the LangChain, OpenAI and Vercel adapters. Mark the ones you do not use as external. next.config.mjs ``` webpack: (config) => { config.externals = [...(Array.isArray(config.externals) ? config.externals : []), "@langchain/core", "@langchain/core/tools", "openai", "ai"]; return config; }, // The SDK reaches the audit package through a dynamic import, which Next's standalone // tracer cannot see — so it is left out of the image and you lose the audit trail with // no build error. Name it explicitly. outputFileTracingIncludes: { "/**": ["./node_modules/@kobil/**"], }, ``` `ls vendor/@kobil` passing is not enough — it checks your source tree, not the image. Verify after deploying by writing an audit event and reading it back (Integration Step 6), not by reading `health()`: that line says "not installed" under Next.js whether or not the package shipped, so it cannot tell you either way. ``` kobilctl deploy ``` Three to five minutes on a first deploy, mostly the build, whose log streams back. If the cluster is too busy to start it, `kobilctl` says so in the cluster's own words. Redeploying is idempotent: same host, no leftovers. To roll back, pass a tag you already built — `kobilctl deploy --tag --skip-build`; every deploy prints its tag. `--local-build` uses your own Docker and its layer cache when iterating. Checkpoint · cluster The run ends with pods ready and prints your URL. 5 ### Verify What: evidence the agent works, not just that the command exited zero. How: check health, then make it do something. verify ``` kobilctl status # health, URL, deployed image tag kobilctl logs -f # stream container logs ``` A green pod is not the finish line. The failures worth catching here only surface on a tool call, so make one. Checkpoint · end to end A tool call completes and appears in the audit trail in the Dashboard. 6 ### When something goes wrong Start here: `kobilctl doctor` checks every prerequisite in the order they depend on each other, so fix the first failure and re-run rather than working through the list. `doctor --fix` repairs what it safely can. diagnose ``` kobilctl doctor --fix ``` What you see | What it means | What to do | The cluster rejected your credential | Your cluster access is not valid and could not be renewed automatically, usually a missing registry token in `~/.npmrc`. | Re-run `kobilctl login `. | Cannot reach the cluster | The SSH tunnel could not be opened. The network is the problem, not your credential. | Check you are on the internal network and that your SSH alias resolves. | waiting for the cluster… | The cluster has no room to start your build yet. The message carries the cluster's own reason. | Retry shortly. If it persists, send that line to your KOBIL contact. | The build failed in the cluster | Your image did not build. The reason is quoted from the build log. | Fix the Dockerfile or sources and deploy again. | Pod runs, URL does not answer | Routing, not the app. | `kobilctl status` for the pod and image, then `kobilctl logs -f`. | Build cannot resolve the registry | A `getaddrinfo` failure on `gitlab.kobil.com`: build pods cannot reach it — for the SDK download, or for the FROM base image. | For the SDK: vendor it (Step 3). For the base image: common bases are mirrored on registry.shift-go.uk; MANIFEST_UNKNOWN means yours is not — ask an admin to mirror it (crane copy), or build with --local-build meanwhile. | Certificate not trusted | `UNABLE_TO_GET_ISSUER_CERT` from the development platform's staging certificate. The agent cannot reach its own control plane. | Ship the chain, point `NODE_EXTRA_CA_CERTS` at it. Never disable verification. | Certificate not provided | The SDK takes tokens only over mutual TLS. Either `AITRUST_PROXY_URL` points at the platform host instead of the mTLS host, or TLS is terminating before your certificate arrives. | Check the host first — it is the common cause and it is yours to fix. If it is already the mTLS host, the rest is platform-side: send the message to your KOBIL contact. | Every tool call is refused | The agent has no rules of its own, so the platform denies each tool by default. | Declare your tools in `toolPermissions` at registration, as Step 2 describes. | Login lands on an unreachable host | The app built its redirect from the inbound request URL, which behind the gateway is the container's own listener. | Redirect against your public base URL. Application code, not the platform. If your agent redirects to a login page instead of serving, that is its own authentication working, not a deployment failure. Follow the redirect before concluding anything is broken. --- # SDK Reference Source: https://demo-agenttrust.shift-go.uk/reference.html ## SDK Reference 1 ### Agent Trust — meta-package @kobil/aitrustkobil-aitrust The front door. Bundles the Agent SDK + Audit behind one `AITrust()` factory and the declarative tool API. Recommended path: define tools with `defineTool` and register them with `registerTools` — that's exactly what the integration guide and the sample agents use. `ai.tool()` and `ai.secureAgent()` are higher-level shortcuts for quick prototypes. Factory + instance [TypeScript] ```typescript import { AITrust } from "@kobil/aitrust"; const ai = AITrust({ agentId, clientId, clientSecret, managementUrl, auditUrl, idpUrl, realm, timeoutMs }); // platformUrl is required — AITrust() throws ConfigurationError without it // instance methods ai.tool(fn, { scopes, name }) // wrap a function in the full pipeline ai.secureAgent(client, { tools }) // auto-detect framework, secure every call await ai.requireApproval({ approver, message }) // inline CIBA await ai.health() // subsystem health ``` [Python] ```python from kobil_aitrust import AITrust, AITrustConfig ai = AITrust(AITrustConfig(agent_id=..., client_id=..., client_secret=..., management_url=..., audit_url=..., idp_url=..., realm=..., timeout_ms=...)) # instance methods (async where they call the platform) ai.tool(fn, {"scopes": [...], "name": "..."}) ai.secure_agent(client, {"tools": {...}}) await ai.require_approval(options) # inline CIBA await ai.health() ``` Declarative tools [TypeScript] ```typescript import { defineTool, registerTools, toAnthropicTools, toOpenAITools } from "@kobil/aitrust"; const def = defineTool({ name, description, parameters, // JSON Schema scopes?, needsApproval?, approver?, approvalMessage?, unguarded?, unaudited?, execute: async (input) => string, }); const secured = registerTools(ai, { [name]: def }); // → secured registry const tools = toAnthropicTools(secured); // or toOpenAITools(secured) await secured[name].execute(input); ``` [Python] ```python from kobil_aitrust import define_tool, register_tools, to_anthropic_tools, to_openai_tools, ToolDefinition d = define_tool(ToolDefinition( name=..., description=..., parameters={...}, # JSON Schema scopes=None, needs_approval=None, approver=None, approval_message=None, unguarded=None, execute=async_fn, # async (input) -> str )) secured = register_tools(ai, {name: d}) tools = to_anthropic_tools(secured) # or to_openai_tools(secured) await secured[name].execute(tool_input) ``` Errors [TypeScript] ```typescript import { NotAuthorized, ApprovalDenied, ApprovalTimeout, NotAuthenticated, UntrustedAgent, ConfigurationError } from "@kobil/aitrust"; ``` [Python] ```python from kobil_aitrust import (NotAuthorized, ApprovalDenied, ApprovalTimeout, NotAuthenticated, UntrustedAgent, ConfigurationError) ``` 2 ### Agent SDK @kobil/kobil-agent-sdkkobil-agent-sdk The low-level engine under the meta-package: identity + token acquisition, the tool registry, and per-framework secure clients. Use it directly for fine-grained control or unusual frameworks. Framework secure clients [TypeScript] ```typescript import { SecureAnthropicClient, SecureOpenAIClient, SecureGoogleAdkClient, SecureLangChainClient, SecureVercelAIClient, SecureGoogleGenAIClient } from "@kobil/kobil-agent-sdk"; // one-line converters too: import { toAnthropicTool, toOpenAITool, toGoogleAdkTool, toLangChainTool, toVercelTool } from "@kobil/kobil-agent-sdk"; // identity / auth primitives: import { KobilAI, OAuthClient, CIBAClient, AgentIdentityManager } from "@kobil/kobil-agent-sdk"; // quick helpers: import { kobilTool, createKobil } from "@kobil/kobil-agent-sdk"; ``` [Python] ```python # Python package: kobil_agent_sdk — identity, token acquisition, tool registry, # and the same per-framework secure clients exposed through the meta-package's # secure_agent(...) / integrations. Most apps use kobil_aitrust and never import # kobil_agent_sdk directly. ``` Framework coverage: Anthropic, OpenAI (incl. Agents SDK), Google ADK, Google GenAI, LangChain, Vercel AI, and Claude Agent / MCP. 3 ### Audit @kobil/kobil-agent-auditkobil-agent-audit A tamper-evident trail of every tool call, token grant, and approval, plus token-usage tracking, CIBA async-authorization, and compliance reporting. Tool calls through `registerToolsregister_tools` are audited automatically; post your own events for work outside the pipeline. [TypeScript] ```typescript import { KobilAgentAudit, AuditLogger, TokenTracker, AsyncAuthorization, ComplianceReporter } from "@kobil/kobil-agent-audit"; ``` [Python] ```python from kobil_agent_audit import (KobilAgentAudit, AuditLogger, TokenTracker, AsyncAuthorization, ComplianceReporter) ``` Manual event (HTTP) ``` POST {AITRUST_AUDIT_URL}/v1/events { "agentId": "agent:", "action": "document_sign", "eventType": "claims.document_signed", "outcome": "success", "resourceId": "", "details": { } } // `action` is required ``` Ready to wire these together? The integration guide shows the exact order — identity → tools → FGA → CIBA → Audit — with copy-paste diffs. --- # Samples Source: https://demo-agenttrust.shift-go.uk/samples.html ## Agent Samples ### Start here — SDK-free starters The “before” state. Run one, then follow the integration guide to add the SDK. #### aitrust-agent-starter TypeScriptAnthropicno SDK Browser chat, Claude Vision damage assessment, settlement PDF, in-browser signing. Node backend with live streaming. Clone / download #### aitrust-agent-starter-python PythonAnthropicno SDK The same app on FastAPI + reportlab/pypdf, sharing the exact web UI and `/api` contract. Clone / download ### Fully-integrated reference agents The “after” state — the full Agent Trust pipeline (FGA · CIBA · Audit). Pick the framework you build with. #### Anthropic (Claude) #### aitrust-insurance-agent TypeScriptAnthropicfull SDK The canonical reference. Claude tool-use loop secured by `@kobil/aitrust`'s `registerTools` pipeline. Available on request #### aitrust-insurance-agent-python PythonAnthropicfull SDK The Python reference: FastAPI backend on the Agent Trust Python SDK (`kobil_aitrust`), same secured pipeline. Available on request #### OpenAI #### aitrust-openai-insurance-agent TypeScriptOpenAIfull SDK OpenAI agent for insurance claims, secured with the Agent Trust SDK — tools converted with `toOpenAITools()` and wrapped through the same pipeline. Available on request #### aitrust-insurance-agent-openai-python PythonOpenAIfull SDK The OpenAI agent on the Python SDK — same claims flow and secured tool pipeline. Available on request #### Google ADK (Gemini) #### aitrust-google-insurance-agent TypeScriptGoogle ADKfull SDK Insurance claims agent built on Google ADK + Gemini, with ADK `FunctionTool`s secured through the Agent Trust Agent SDK. Available on request #### aitrust-insurance-agent-google-python PythonGoogle / Geminifull SDK The Gemini agent on the Python SDK — same secured pipeline. Available on request ### Coverage at a glance Framework | TypeScript | Python Starter (no SDK) | `aitrust-agent-starter` | `aitrust-agent-starter-python` Anthropic | `aitrust-insurance-agent` | `aitrust-insurance-agent-python` OpenAI | `aitrust-openai-insurance-agent` | `aitrust-insurance-agent-openai-python` Google ADK | `aitrust-google-insurance-agent` | `aitrust-insurance-agent-google-python` --- # Solution white paper: Verifiable Identity for Every AI Agent Source: https://demo-agenttrust.shift-go.uk/whitepaper-agent-trust.html Solution & White Paper ## Verifiable identity for every AI agent KOBIL Agent Trust gives each agent its own cryptographic identity, checks every tool call against policy before it executes, and writes every decision to a tamper-evident audit trail — without changing your models or your APIs. 8 platform services, one Helm chart 3 SDK packages, TypeScript and Python 3 agent frameworks: Anthropic, OpenAI, Google ADK The agent never holds the credential, never evaluates the policy, and never writes the record. KOBIL-hosted or self-managed English edition | 06 Aug 2026 | Confidential working paper 01 / Executive Summary ## Executive Summary An AI agent stops being a chatbot the moment it can call a tool. From then on it can move money, change a record or send something on the organisation's behalf — and the credential model most deployments inherited was never designed for that. 1 ##### Identity Every agent proves who it is with its own certificate and credentials, issued and revocable one agent at a time. 2 ##### Authorization Every action is checked against policy before it executes, by a component the agent cannot instruct. 3 ##### Accountability Every decision is logged — what happened, why, and who approved it — where the agent cannot edit it. ### The Challenge Scoping permissions does not close the gap. Scope is a statement about categories; the risk is in the instance — this agent, this argument, this moment. 01 ##### Untrusted input Documents, pages, retrieved passages 02 ##### Agent reasoning Non-deterministic tool choice 03 ##### Privileged action API, payment, record change 04 ##### Business effect Irreversible, and attributable to you The feared event An agent holding standing authority is manipulated through content it did not write, and uses valid credentials to take a real action — with no independent record of who authorised it. 02 / Market Development & Trends ## Market Development & Trends Adoption, autonomy and regulation are advancing together. The combination turns agent identity from an architecture preference into an operational requirement. 62% experiment with or scale AI agents McKinsey, State of AI 2025 23% scale at least one agentic system McKinsey, State of AI 2025 <10% scale agents in any single function McKinsey, State of AI 2025 ##### Obligation, not intention DORA has applied to in-scope financial entities since 17 January 2025. It asks for demonstrable control over automated processes, not documented good intent. ##### Agentic risk is now named OWASP published a Top 10 for Agentic Applications in December 2025, separating identity abuse, inter-agent trust and tool misuse from ordinary application risk. ##### Human oversight becomes testable EU AI Act Articles 12 and 14 require automatic logging and effective human oversight. High-risk obligations now apply from December 2027 after the Digital Omnibus deferral. ##### The building blocks already exist CIBA is an OpenID standard and DPoP became RFC 9449 in 2023. What is new is not the cryptography but applying it per agent, per action. Market signal Adoption is broad; governed production is rare. The constraint is no longer whether an agent can act, but whether an organisation can prove what it did and stop it when it should not. 03 / The Solution ## The Solution Agent Trust sits at the point where an agent's output becomes an action. Five steps run on every tool call, and none of them depend on the agent cooperating. ### Technology & Product Overview Agent layer Anthropic SDK OpenAI SDK Google ADK Your own framework Developer SDKs aitrust agent-sdk agent-audit TypeScript · Python Control plane SHIFT IDP OpenFGA Management API Audit service Your estate REST APIs MCP servers RAG stores Databases Integration scope The platform wraps the tool call. It does not host your model, replace your agent framework or require code changes in the services the agent calls. One package install, and your API gateway pointed at the platform's JWKS endpoint. 04 / Use Cases ## Use Cases The strongest fit is where agent speed meets money, personal data or a regulator. 1 ##### Banking & payments Scenario An agent prepares a transfer and must not complete it alone above a threshold. Controls CIBA approval on a separate device, policy threshold, correlated audit record 2 ##### Insurance claims Scenario An agent assesses damage, drafts a settlement and touches customer records. Controls Per-resource authorization, scoped delegation, tamper-evident trail 3 ##### MCP tool servers Scenario Agents reach shared tool servers that must not trust the caller's word. Controls mTLS between agents, verifiable scoped tokens, per-tool policy 4 ##### Regulated audit Scenario A supervisor asks what one agent did on a named date, and who allowed it. Controls Append-only records, SIEM export, per-agent attribution Pilot principle Start with one agent and a small set of consequential actions. Gating everything produces reflexive approval, which is worse evidence than no approval at all. 05 / Business Impact ## Business Impact The case is not one security feature. It is the ability to put agents into production at all in an environment where someone must answer for what they did. ##### Production becomes possible Agents reach real systems under a control an auditor recognises, instead of stalling in proof-of-concept. ##### Blast radius is bounded Per-agent identity means one compromised agent is revoked alone, and what it did is attributable. ##### Evidence is a by-product The record is produced by the control path itself, rather than assembled from logs after a question is asked. ##### One control, many frameworks The same identity and policy layer covers Anthropic, OpenAI and Google ADK agents without per-framework work. ### Pilot measurement framework ##### Time to governed production Elapsed time from a chosen use case to an agent running under enforced policy. ##### Policy coverage Share of consequential actions with an explicit rule rather than a default allow. ##### Approval quality Proportion of gated actions where the approver saw platform-composed detail, and the approval rate. ##### Evidence completeness Share of actions with a full correlated record: agent, principal, resource, decision, approver, timestamp. Evidence status No verified customer or ROI metrics are published in this paper. The measures above are the objectives a design-partner pilot is intended to establish. 06 / Technical Details ## Technical Details Eight services deployed as a single Helm chart, with the realm, certificate authority, authorization model and mesh routing pre-configured. No per-customer build. ##### SHIFT IDP Identity provider. Tokens, login, CIBA and DPoP on a pre-configured realm. ##### OpenFGA Relationship-based authorization: may agent Z reach document Y for user X? ##### Management API The agent identity control plane; token exchange across all three backends. ##### Audit service Unified ingestion from SDK clients and platform events, stored in Elasticsearch. ##### Istio Service mesh: mTLS, traffic management and path-based routing. ##### PostgreSQL · Redis · Elasticsearch Relational store, config cache with DPoP nonce rotation, and the audit index. ### Trust boundaries Honest scope The platform authorises the tool call; it does not sandbox what the tool then executes, inspect prompts, or vet the packages your agent loads. It addresses three entries of the OWASP Agentic Top 10 — ASI02 tool misuse, ASI03 identity and privilege abuse, and ASI07 insecure inter-agent communication, not all ten. 07 / Product Maturity & Compliance ## Maturity & Compliance Credible adoption needs a clear line between what ships today, what is target state, and what remains the customer's responsibility. Area | Today | Target state Control plane | 8 services, single Helm chart | Same, with air-gapped bundle SDK coverage | 3 packages, TypeScript and Python at parity | Additional runtimes on demand Deployment | KOBIL-hosted or self-managed Kubernetes | Dedicated regional tenancy Approval coverage | CIBA on policy-selected actions | Richer approver routing and delegation Evidence | Correlated records, SIEM export | Packaged regulatory evidence sets ### Regulatory mapping Instrument | Status | What the platform contributes DORA | Applies since Jan 2025 | Enforced control points over automated processes, with supervisory evidence NIS2 | Transposition incomplete | Strong approver authentication and per-agent access control EU AI Act, Art. 12 & 14 | High-risk from Dec 2027 | Automatic per-action logging; oversight the system cannot bypass OWASP Agentic Top 10 | Published Dec 2025 | ASI02, ASI03 and ASI07; the remaining seven named and attributed elsewhere This document is not legal advice and is not a certification. Controls may support compliance; the outcome depends on architecture, configuration, process and evidence. 08 / Key Takeaways ## Key Takeaways 1 ##### The control must sit outside the agent A manipulated agent will not honour an instruction to ask permission. Identity, policy and evidence therefore live where the agent cannot reach them. 2 ##### Approval is a mechanism, not a slogan CIBA is a decoupled standard with a banking pedigree. The approver reads what the platform composed from the resolved call, on a device the agent cannot see. 3 ##### Evidence has to survive the session A correlated, append-only record answers the question a supervisor actually asks: what did this agent do, and who allowed it. 4 ##### Scope honestly, then pilot Three of the OWASP ten, not all ten. One agent, a handful of consequential actions, and a measurable objective. ### Call to Action From one prioritised use case to defensible evidence. 1 Architecture review 2 Policy design 3 One agent integrated 4 Evidence & scale Request a technical demo or design-partner discussion kobil.com/contact-us 09 / Sources ## Sources & Notes Internal product facts combined with public market, security and regulatory references. External sources accessed 06 Aug 2026. [1] McKinsey — The State of AI 2025 mckinsey.com/capabilities/quantumblack/our-insights/the-state-of-ai [2] OWASP — Top 10 for Agentic Applications, Dec 2025 genai.owasp.org/resource/owasp-top-10-for-agentic-applications-for-2026/ [3] Regulation (EU) 2022/2554 — DORA eur-lex.europa.eu/eli/reg/2022/2554/oj [4] Regulation (EU) 2024/1689 — Artificial Intelligence Act, Art. 12 & 14 eur-lex.europa.eu/eli/reg/2024/1689/oj [5] Directive (EU) 2022/2555 — NIS2 eur-lex.europa.eu/eli/dir/2022/2555/oj [6] OpenID Foundation — CIBA Core 1.0 openid.net/specs/openid-client-initiated-backchannel-authentication-core-1_0.html [7] IETF RFC 9449 — OAuth 2.0 DPoP rfc-editor.org/rfc/rfc9449.html [8] KOBIL Agent Trust — platform documentation Internal source, 06 Aug 2026 Document status Solution and technical white paper based on the KOBIL Agent Trust platform as of 06 Aug 2026. No product certification, legal advice or commitment to future functionality.