incipient.ai
← Intelligence Hub

Architecture · 2026-03-03 · 10 min

The Anatomy of an Enterprise Agent Harness

Five layers wrap the model between a user request and your systems of record — interface, orchestration, context, tools, and guardrails — with identity, secrets, and audit cutting across all of them.

A harness is not one thing — it is a stack of layers that wrap the model between a user request and your enterprise systems of record. Each layer has a single job, and cross-cutting concerns like identity and audit run through all of them. This is the anatomy.

The five layers

#LayerJobContains
1InterfaceAccept and authenticate requestsRequests, channels, auth
2OrchestrationDrive the agent loopPlanning, step control, routing
3Model + ContextGive the model what it needs to reasonPrompting, memory, RAG
4Tools & ActionsAct on systems of record safelyGoverned API / code calls
5Guardrails & Obs.Enforce policy and record everythingPolicy, tracing, eval

Requests flow down through the layers to the systems of record and back up. No layer reaches around another — the model never touches a raw API, and no tool runs without passing the guardrail layer.

Layer 1 — Interface

The entry point normalizes every channel (chat, API, batch) into one request shape and authenticates the caller before the model sees anything. Identity established here travels with the request for the rest of its life.

type AgentRequest = {
  id: string;
  identity: Principal;      // resolved + verified at the edge
  channel: "chat" | "api" | "batch";
  input: string;
  scopes: string[];         // what this caller may do
};

Layer 2 — Orchestration

The orchestration layer owns the agent loop: it asks the model to plan, decides whether to act or stop, routes tool calls, and enforces the step ceiling. This is where "plan → act → observe → repeat" lives, and where you keep control flow deterministic rather than trusting the model to decide when it is done.

const plan = await model.plan(request, ctx);
switch (plan.type) {
  case "final":  return respond(plan.answer);
  case "tool":   return dispatch(plan.toolCall);   // → Layer 4
  case "clarify": return askUser(plan.question);
  case "escalate": return handoffToHuman(plan);    // HITL
}

Layer 3 — Model + Context

Raw reasoning is only as good as the context it is given. This layer assembles the prompt, injects retrieved knowledge (RAG), and manages memory across steps and sessions — while keeping the context window (and token spend) within budget.

const ctx = await context.assemble({
  system: policyPrompt(request.identity),
  memory: await memory.recall(request.id, k = 8),   // cross-step state
  retrieved: await rag.search(request.input, {      // grounded knowledge
    scope: request.scopes,                           // scoped to entitlements
  }),
  budget: { maxTokens: 12_000 },                     // cost control
});

Grounding retrieval in governed data is what keeps answers citable — the same semantic layer that powers federated agents feeds this layer.

Layer 4 — Tools & Actions

This is where the agent touches reality: CRMs, EHRs, core banking. Every action is a typed, governed tool with an explicit schema, a permission contract, and a blast-radius limit — never a raw endpoint the model can call however it likes.

registry.define({
  name: "issue_refund",
  input: z.object({ account: z.string(), amountUsd: z.number().max(10_000) }),
  scopes: ["payments:write"],
  limits: { perDay: 50, requiresApprovalOver: 100 },
  handler: async (args, ctx) => paymentRails.refund(args, ctx.identity),
});

Layer 5 — Guardrails & Observability

The outer layer wraps every tool call in policy enforcement and records everything. Permission checks, output validation, and limits run before the action; a trace span and audit log are written after — so every run is reproducible for compliance, model-risk, and incident review.

async function guardedInvoke(tool, args, ctx) {
  guard.checkScopes(ctx.identity, tool.scopes);      // permission
  guard.checkLimits(tool.limits, ctx.usage);         // blast radius
  if (guard.needsApproval(tool, args)) await approvals.request(ctx, tool, args);
  const out = await tool.handler(args, ctx);
  validate(tool.output, out);                        // no malformed side effects
  audit.write({ tool: tool.name, args, out, identity: ctx.identity, ts });
  return out;
}

Cross-cutting concerns

Five concerns are not layers — they apply across every layer:

  • Identity & permissions — established at the interface, enforced at every tool call.
  • Secrets management — credentials never enter the prompt or the model's context.
  • Sandboxing — code and tool execution isolated with least privilege.
  • Human-in-the-loop approvals — high-risk actions pause for a person (see HITL governance).
  • Logging & audit trail — a reproducible record from request to response.

The path to implement

  1. Normalize channels and authenticate at the interface; carry identity through the whole request.
  2. Make orchestration deterministic — a bounded loop with explicit plan/act/clarify/escalate branches.
  3. Assemble scoped, budgeted context with governed RAG and cross-session memory.
  4. Register every side effect as a typed tool with scopes, limits, and an approval threshold.
  5. Wrap tool calls in a guard + trace so policy is enforced and every run is auditable.

Build these as first-class engineering, not glue code. Incipient's AI Harness supplies the layered runtime and test harnesses, and our forward-deployed engineers stand it up alongside your teams.

See the AI Harness in the Lab →