[Blog](https://cohesivity.ai/blog)

Architecture

Published Jul 16, 2026·Updated Aug 30, 2026

![](https://cohesivity.ai/authors/arag.webp)![](https://cohesivity.ai/authors/shouryamaan.webp)[Arag](https://www.linkedin.com/in/aragagrawal/) and [Shouryamaan](https://www.linkedin.com/in/shouryamaanjain/)

# How to Design an Agent Control Plane

[Read as Markdown](https://cohesivity.ai/blog/how-to-design-an-agent-control-plane.md)

Control

Identity

Policy

State

An agent control plane owns the decisions around execution: identity, authorization, credential scope, approval, limits, operation status, resource ownership, and audit records. The data plane performs the permitted database query, browser action, deployment, or API call.

If every tool performs those decisions differently, the system has no real control plane. It has a set of conventions that drift as tools are added.

## Separate decisions from execution

```mermaid
flowchart LR
    Agent[Agent request] --> Identity[Resolve identity and tenant]
    Identity --> Policy{Policy and approval}
    Policy -->|deny| Audit[Audit decision]
    Policy -->|allow| Broker[Issue scoped credential]
    Broker --> Operation[Create or resume operation]
    Operation --> Tool[Execute tool in data plane]
    Tool --> Resource[(Database, API, browser, compute)]
    Tool --> Operation
    Operation --> Audit

```

The control plane should answer who is acting, which resource they own, which action is permitted, whether consent is required, how much work may run, and how the operation can be stopped. The data plane should receive a narrow instruction and enough authority to perform it.

This boundary complements the full [AI agent architecture](https://cohesivity.ai/blog/ai-agent-architecture-memory-tools-state-durable-execution). It does not need to be a separate service on day one, but its contract should be visible in code.

## Put identity ahead of tool selection

Resolve the authenticated human, tenant, agent, and session before executing a tool. Do not accept a tenant identifier from model output when the server can bind it from the credential.

NIST’s [zero trust architecture](https://csrc.nist.gov/publications/detail/sp/800-207/final) treats trust as something evaluated for each request rather than granted because a caller sits inside a network. For agents, that means the downstream service still authorizes the represented identity even when an internal tool made the request.

Keep separate credentials for the control plane, agent session, and application runtime. A management credential that can provision resources should not be available to ordinary application calls.

## Make policy return a concrete decision

A useful policy decision records:

- the subject, tenant, resource, and action;
- the policy version and matched rule;
- whether human approval is required;
- limits on spend, calls, time, or data volume;
- an allow or deny result with a stable reason.

Tool descriptions can tell a model when to ask for approval, but enforcement belongs outside the prompt. OWASP’s [Excessive Agency guidance](https://genai.owasp.org/llmrisk/llm062025-excessive-agency/) recommends minimizing tool functionality, permissions, and autonomy, with authorization enforced in downstream systems.

## Broker credentials at the narrowest useful scope

The data-plane worker should receive a short-lived credential for the approved resource and action where the provider supports it. When it does not, keep the provider credential in the server-side tool and apply the same restriction in the wrapper.

Never pass secrets through model context, tool descriptions, URLs, or model-visible errors. Record a credential reference in traces, not the credential value.

The [agent security guide](https://cohesivity.ai/blog/ai-agent-security-identity-permissions-secrets-audit-logs) describes the full identity and secret path.

## Track operations separately from conversations

A chat turn is not an operation record. Create an operation ID for work that writes, waits, retries, or can outlive the request. Store status, inputs after redaction, idempotency key, approval state, attempts, outputs or references, and terminal result.

This lets an agent ask whether a deployment is still running without replaying the deployment request. It also gives a human a stable object to cancel, resume, or investigate.

## Keep inventory and ownership in the same plane

The control plane should know which tenant owns each database, bucket, deployment, browser session, and agent credential. Inventory makes revocation and deletion tractable. It also prevents a model from selecting a resource by a friendly name that exists in two tenants.

Apply quotas to the authenticated tenant and operation, not to a tenant field supplied by the model. Limits should fail with a stable result that the agent can explain without retrying blindly.

## Audit decisions and outcomes together

An audit record needs both the policy decision and the observed outcome. “Allowed delete” and “delete completed” are different events. Keep operation ID, actor, tenant, resource, action, policy version, approval reference, timestamps, and result class.

Do not place raw prompts, secrets, or full tool results in the audit log by default. Store hashes or references when the exact content must be retained under a separate access policy.

## Start inside the existing application

A small system can implement this as middleware, a policy module, a credential adapter, an operations table, and an append-only audit table. Split it into services when scale or ownership demands it. The initial goal is one consistent decision path.

The prompt below traces an existing workflow and finds controls buried in individual tool handlers. Those duplications are the first candidates to move behind a shared contract.

or send it to[Claude Code](https://claude.ai/new?q=Inspect+this+repository%27s+highest-impact+AI+agent+workflow.+Do+not+edit+code+or+call+external+services.+For+every+tool+call%2C+identify+where+identity+is+established%2C+authorization+is+enforced%2C+credentials+are+issued%2C+approval+is+checked%2C+limits+are+applied%2C+operation+status+is+stored%2C+and+the+audit+record+is+written.+Separate+control-plane+decisions+from+data-plane+execution.+List+duplicated+or+model-enforced+controls%2C+then+propose+the+smallest+central+contract+that+removes+the+three+most+serious+gaps. "Send to Claude")[Cursor](https://cursor.com/link/prompt?text=Inspect+this+repository%27s+highest-impact+AI+agent+workflow.+Do+not+edit+code+or+call+external+services.+For+every+tool+call%2C+identify+where+identity+is+established%2C+authorization+is+enforced%2C+credentials+are+issued%2C+approval+is+checked%2C+limits+are+applied%2C+operation+status+is+stored%2C+and+the+audit+record+is+written.+Separate+control-plane+decisions+from+data-plane+execution.+List+duplicated+or+model-enforced+controls%2C+then+propose+the+smallest+central+contract+that+removes+the+three+most+serious+gaps. "Send to Cursor")[Codex](https://chatgpt.com/codex?prompt=Inspect+this+repository%27s+highest-impact+AI+agent+workflow.+Do+not+edit+code+or+call+external+services.+For+every+tool+call%2C+identify+where+identity+is+established%2C+authorization+is+enforced%2C+credentials+are+issued%2C+approval+is+checked%2C+limits+are+applied%2C+operation+status+is+stored%2C+and+the+audit+record+is+written.+Separate+control-plane+decisions+from+data-plane+execution.+List+duplicated+or+model-enforced+controls%2C+then+propose+the+smallest+central+contract+that+removes+the+three+most+serious+gaps. "Send to Codex")[opencode](https://opencode.ai/?q=Inspect+this+repository%27s+highest-impact+AI+agent+workflow.+Do+not+edit+code+or+call+external+services.+For+every+tool+call%2C+identify+where+identity+is+established%2C+authorization+is+enforced%2C+credentials+are+issued%2C+approval+is+checked%2C+limits+are+applied%2C+operation+status+is+stored%2C+and+the+audit+record+is+written.+Separate+control-plane+decisions+from+data-plane+execution.+List+duplicated+or+model-enforced+controls%2C+then+propose+the+smallest+central+contract+that+removes+the+three+most+serious+gaps. "Send to OpenCode")
