Technical architecture

How AgentTrust works under the hood

AgentTrust is a stateless HTTP service with three stages — identity, policy, and audit — sitting in front of a swappable data store. Any agent connects with one request; nothing about your agent's runtime or framework matters.

System overview

Requests flow top-to-bottom: agents authenticate at the edge, pass through the policy engine, and every decision is written to the audit store before the verdict is returned.

Your AI AgentsLangChain, AI SDK, CrewAI, or custom loops
HTTPS + Bearer key

AgentTrust API · agenttrustcore.com

IdentityVerify API key, resolve & attribute the agent
then
Policy EngineMatch action, resource & conditions → verdict
then
Audit LoggerRecord request + decision, return allow/deny/flag
reads / writes
TrustStoreIn-memory today · swappable to Supabase behind one interface

Request lifecycle

What happens between an agent's intention and a real-world action, step by step.

  1. 1

    Agent

    Intercept the action

    Right before a side effect (charge a card, write a row, send an email), the agent builds an evaluation request instead of acting directly.

  2. 2

    Agent → API

    POST /api/evaluate

    The agent sends its Bearer key plus { action, resource, params } over HTTPS. This single call is the entire integration surface.

  3. 3

    API

    Authenticate identity

    The key is hashed and looked up. Unknown or suspended keys are rejected with 401/403 before any policy runs — fail closed by default.

  4. 4

    API

    Evaluate policies

    The engine collects every policy whose action glob and resource match, evaluates conditions (e.g. amount > 1000), and resolves the strongest verdict: deny wins over flag wins over allow.

  5. 5

    API → Store

    Write the audit record

    The request, matched policies, verdict, and reason are appended to the log for accountability — regardless of the outcome.

  6. 6

    API → Agent

    Return the verdict

    A JSON decision comes back in milliseconds: allow (200), flag (200, proceed with caution), or deny (403). The agent only performs the action on allow/flag.

How another agent connects

Connecting is deliberately minimal — three things, then a single HTTP call before each guarded action.

1. An API key

Register the agent in the dashboard and copy its atk_… key. Store it as AGENT_TRUST_KEYin the agent's environment.

2. The base URL

Point the agent at your deployment — https://agenttrustcore.com. No SDK, VPN, or sidecar is required.

3. One call before acting

Send POST /api/evaluate and act only if the decision is not deny. Works from any language.

Minimal client — no dependencies:

typescript
// The entire client contract — no SDK required
async function isAllowed(action, params) {
  const res = await fetch("https://agenttrustcore.com/api/evaluate", {
    method: "POST",
    headers: {
      Authorization: `Bearer ${process.env.AGENT_TRUST_KEY}`,
      "Content-Type": "application/json",
    },
    body: JSON.stringify({ action, params }),
  })
  const data = await res.json()
  return data.decision !== "deny" // allow + flag proceed, deny blocks
}

The API contract

One endpoint, one request shape, four possible outcomes. This is the complete surface an agent needs to understand.

Request

bash
POST https://agenttrustcore.com/api/evaluate
Authorization: Bearer atk_your_agent_key
Content-Type: application/json

{
  "action":   "payment.send",   // required · dotted verb, e.g. email.send
  "resource": "stripe",          // optional · the system being acted on
  "params":   {                  // optional · used by policy conditions
    "amount": 5000,
    "currency": "usd"
  }
}

Responses

json
// 200 OK  (allow)                 // 200 OK  (flag)
{ "decision": "allow",           { "decision": "flag",
  "reason": "No deny policy",      "reason": "Matched review rule",
  "matchedPolicies": [],           "matchedPolicies": ["pol_..."],
  "requestId": "req_...",          "requestId": "req_...",
  "agentId": "agt_..." }           "agentId": "agt_..." }

// 403 Forbidden  (deny)          // 401 Unauthorized (bad/missing key)
{ "decision": "deny",            { "error": "invalid_api_key" }
  "reason": "Blocked by policy: Block large payments",
  "matchedPolicies": ["pol_..."],
  "requestId": "req_..." }

Design principles

  • Fail closed

    Missing keys, unknown agents, or malformed requests are rejected before any policy runs.

  • Provider-agnostic

    It is plain HTTP + JSON. No framework, language, or runtime assumptions about the calling agent.

  • Stateless edge

    The API holds no per-request state; all durable data lives behind the TrustStore interface.

  • Storage is swappable

    In-memory today for evaluation; implement the same interface against Supabase to make it durable — zero API changes.

  • Deny beats flag beats allow

    When multiple policies match, the strictest verdict always wins, so a single deny rule is enough to block.

  • Everything is audited

    Every evaluation — allowed, flagged, or denied — is recorded with its matched policies and reason.

Where each piece lives

LayerFileResponsibility
HTTP APIapp/api/evaluate/route.tsAuth, orchestration, verdict + status codes
Policy enginelib/trust/engine.tsMatch rules, evaluate conditions, resolve verdict
Data storelib/trust/store.tsAgents, policies, logs behind one interface
Typeslib/trust/types.tsShared contracts for agents, policies, decisions
Client SDKsdk/agent-trust.tscheck() + guard() wrapper, zero dependencies