{"slug": "the-manifest-that-keeps-your-ai-agent-honest", "title": "The Manifest That Keeps Your AI Agent Honest", "summary": "Cognous has released the Open Control Stack, a set of four open-source projects designed to keep AI agents in check by enforcing pre-defined permissions. The first component, Declare, introduces the Agent Action Manifest, a versioned file that outlines an agent's allowed actions, tools, and data classifications. This manifest aims to prevent scenarios like an AI customer-service agent sending mass emails without approval.", "body_md": "In our first post, [Cognous Keeps Your AI in Check](https://dev.to/cognous/cognous-keeps-your-ai-in-check-69l), we introduced the scenario: a customer-service agent that pulls CRM records, drafts replies, and — if nobody's watching — occasionally sends 1,000 tone-deaf emails to your best clients. We said the fix isn't reading what the agent wrote after the fact. It's deciding, in advance, what the agent is even allowed to attempt.\n\nThat decision has to live somewhere. It can't live in a Slack thread, a comment in the agent's system prompt, or \"Dave from platform remembers we blocked that.\" It needs to be a file — versioned, reviewable, and boring enough that a security team can actually sign off on it.\n\nThat's what Cognous's Open Control Stack is for. It's four small, open-source projects — Declare, Control, Replay, Evidence — that sit beside your agents and cover authorize, enforce, and prove. Declare comes first, and its artifact is the **Agent Action Manifest**. This post describes the Action Manifest tooling in the Open Control Stack, available on [GitHub](https://github.com/cogno-us/cognous-open-control-stack).\n\nIf you remember in post one, our AI agent was pulling customer data, drafted a cringey email, and sent it to our top 1,000 customers. The Action Manifest is used to outline the agent's permissions as declarations, to prevent this from ever happening again:\n\n```\n{\n  \"manifest_version\": \"0.1\",\n  \"manifest_id\": \"customer-service-agent-manifest\",\n  \"agent_name\": \"customer-service-agent\",\n  \"owner\": \"support-platform-team\",\n  \"environment\": \"production\",\n  \"default_action\": \"block\",\n  \"tools\": [\n    {\n      \"tool_name\": \"crm\",\n      \"description\": \"Customer relationship management system\",\n      \"allowed\": true,\n      \"external_system\": \"crm.internal\",\n      \"data_classification\": \"customer_pii\"\n    },\n    {\n      \"tool_name\": \"email\",\n      \"description\": \"Outbound customer email system\",\n      \"allowed\": true,\n      \"external_system\": \"smtp.internal\",\n      \"data_classification\": \"customer_pii\"\n    }\n  ],\n  \"actions\": [\n    {\n      \"action_name\": \"pull_top_customers\",\n      \"tool_name\": \"crm\",\n      \"action_type\": \"read\",\n      \"description\": \"Retrieve top customer records from the CRM.\",\n      \"default_action\": \"allow\",\n      \"reliance_requirement\": {\n        \"required\": true,\n        \"allowed_source_types\": [\"tool\", \"database\"]\n      }\n    },\n    {\n      \"action_name\": \"draft_reply\",\n      \"tool_name\": \"email\",\n      \"action_type\": \"write\",\n      \"description\": \"Draft a reply email for a customer inquiry.\",\n      \"default_action\": \"allow\",\n      \"authority_required\": [\n        {\n          \"scope\": \"email.draft.customer\",\n          \"description\": \"Permission to draft outbound customer emails\",\n          \"required\": true,\n          \"source\": \"support-platform-team\"\n        }\n      ],\n      \"review_requirement\": {\n        \"mode\": \"draft_first\"\n      }\n    },\n    {\n      \"action_name\": \"pull_contract_details\",\n      \"tool_name\": \"crm\",\n      \"action_type\": \"read\",\n      \"description\": \"Retrieve contract terms from the CRM.\",\n      \"default_action\": \"block\",\n      \"tags\": [\"contract\", \"restricted\"]\n    },\n    {\n      \"action_name\": \"send_email\",\n      \"tool_name\": \"email\",\n      \"action_type\": \"external_send\",\n      \"description\": \"Send an approved email to the customer.\",\n      \"default_action\": \"escalate\",\n      \"authority_required\": [\n        {\n          \"scope\": \"email.send.customer\",\n          \"description\": \"Outbound customer send scope\",\n          \"required\": true,\n          \"source\": \"email.send.customer\"\n        }\n      ],\n      \"review_requirement\": {\n        \"mode\": \"approval_required\",\n        \"reviewer_role\": \"support-lead\"\n      },\n      \"reliance_requirement\": {\n        \"required\": true,\n        \"allowed_source_types\": [\"tool\", \"user_input\"]\n      },\n      \"payload_policy\": {\n        \"sensitive_fields\": [\"customer_email\", \"customer_name\"],\n        \"forbidden_fields\": [\"contract_terms\"]\n      },\n      \"redaction_hints\": [\n        {\n          \"field_path\": \"customer_email\",\n          \"reason\": \"PII in exported records\"\n        }\n      ]\n    }\n  ]\n}\n```\n\n(Field names here follow the public schema — check the [repo](https://github.com/cogno-us/cognous-open-control-stack) for the exact current shape if you're implementing against it.)\n\nRules are only as good as what is defined. At the very top of the manifest, we explicitly cover anything not mentioned: `\"default_action\": \"block\"`\n\n. So when a new tool is onboarded (for example `send_tweet`\n\n), you don't need to go back and update every manifest — it's blocked until you expressly give the agent permission to use it.\n\nFor those actions that are defined:\n\n`pull_top_customers`\n\nand `draft_reply`\n\nare both `allow`\n\n, but not the same kind of allow: pulling the top customers is allowed, full stop, but the draft reply has `review_requirement.mode: draft_first`\n\n— the agent can write it, but it stops there.`send_email`\n\nisn't just \"escalate\" as a vague gesture — it names the exact authority scope required (`email.send.customer`\n\n), the exact reviewer role (`support-lead`\n\n), and which payload fields have to be redacted before this record goes anywhere near an audit export.`pull_contract_details`\n\nis the odd one out — it doesn't strictly need to be there. `default_action: block`\n\nalready covers anything undeclared, so an unlisted \"read contract details\" action would be blocked anyway. It's included for visibility: a blocked action that shows up in the manifest, tagged `restricted`\n\n, is a documented decision someone can point to. A blocked action that's simply never mentioned looks identical to an oversight.It's important to note that the manifest is not enforcement. It doesn't stop the agent from doing anything — a runtime layer has to actually read it and act on it (that'll be described in the next post). What the manifest gives you is a single artifact that says, in one place, what *should* happen — before the agent has run even once.\n\nIn our simple manifest above, we show three possible action types. The manifest supports nine. These classifications are what give a governance review the ability to distinguish a harmless read from something that should never happen without a human:\n\n| Action | Meaning |\n|---|---|\n`read` |\nretrieves or inspects information |\n`write` |\ncreates or modifies information, not necessarily sent externally |\n`external_send` |\nsends information outside the system boundary |\n`delete` |\nremoves information or records |\n`export` |\npackages or transfers information downstream |\n`purchase` |\ninitiates or prepares a purchase |\n`approve` |\napproves or authorizes a workflow step |\n`escalate` |\nroutes to a human or supervisory process |\n`other` |\nanything not otherwise classified |\n\nA tool list alone can't tell you this. Knowing the agent \"has access to email\" tells you nothing about whether it can draft, send, or both, and what's supposed to happen before each.\n\nAction type says *what kind* of thing an action is. Review mode says *who has to look at it, and when* — and it's doing just as much governance work in our example as action type is. There are four:\n\n| Mode | Meaning |\n|---|---|\n`none` |\nno specific review posture declared |\n`human_review` |\na human is expected to look at it before execution or completion — no specific person named |\n`approval_required` |\napproval is required from a named reviewer role\n|\n`draft_first` |\nthe agent produces a draft; it does not finish the action itself |\n\nThe difference between `human_review`\n\nand `approval_required`\n\nis easy to miss but it matters: `human_review`\n\nsays \"someone should look at this\" without saying who. `approval_required`\n\nis stricter — it names a reviewer role, and the validator enforces that: an `approval_required`\n\naction with no `reviewer_role`\n\nfails validation outright.\n\nThat's why `send_email`\n\nin our manifest uses `approval_required`\n\nwith `reviewer_role: \"support-lead\"`\n\n, not `human_review`\n\n. Sending customer email isn't \"someone should probably glance at this\" — it's \"this specific role signs off, or it doesn't go out.\"\n\nWorth being precise about what `\"support-lead\"`\n\nactually is here: a role string, nothing more. The manifest doesn't know who holds that role, doesn't know they're on Slack, and doesn't page anyone. Your enterprise-side plumbing converts \"support lead\" to Janice, and builds an alerting system in Slack to let her know that her approval is required. The public stack's job ends at \"this role must approve, and there's a record of whether it did.\"\n\nAuthority asks whether an action was *allowed*. Review asks whether a *person* signed off. Reliance asks something different: what did this action actually *depend on* to produce its result?\n\nA `reliance_requirement`\n\ndeclares that an action should leave a record of its source — a tool, a database, a file, an API, or user input. `pull_top_customers`\n\ndeclares reliance on `tool`\n\nand `database`\n\n, because a governance review should be able to see it actually came from the CRM and not somewhere the agent invented. `send_email`\n\ndeclares reliance on `tool`\n\nand `user_input`\n\n, tying the send back to the approved draft it was built from.\n\n`draft_reply`\n\nand `pull_contract_details`\n\ndon't declare a reliance requirement — which is why the summarize output above shows `Actions requiring reliance: 2`\n\n, not 4.\n\nA manifest can be valid JSON, but be semantic nonsense. A `delete`\n\naction on the production database marked `allow`\n\nisn't caught by JSON Schema. It's caught by the validator, which checks things like:\n\n`external_send`\n\n, `write`\n\n, `delete`\n\n, `purchase`\n\n, `approve`\n\n) missing an authority requirement it should have?`approval_required`\n\nbut missing a reviewer role?Run it from the CLI — `aam`\n\n, short for Agent Action Manifest, is the command-line tool that ships with the manifest repo. First we run the validate command to ensure that the JSON is valid:\n\n``` bash\n$ aam validate customer-service-agent-manifest.json\nValidation result: VALID\nManifest ID:       customer-service-agent-manifest\n\nWarnings (3):\n  [W004] [actions[1](draft_reply)] Action 'draft_reply' has effective default_action 'allow' for action_type 'write'.\n  [W006] [actions[1](draft_reply).payload_policy] Action 'draft_reply' has action_type 'write' but no payload_policy is declared.\n  [W005] [actions[2](pull_contract_details).reliance_requirement] Action 'pull_contract_details' has action_type 'read' but no reliance_requirement is declared.\n```\n\nVALID, but not silent — the validator still flags things worth a second look, even in a manifest that passes. Fair warnings, too: we didn't bother declaring a payload policy for a draft-only action, and a blocked action doesn't need reliance evidence it'll never produce.\n\nNext we can summarize the manifest with the summarize command:\n\n``` bash\n$ aam summarize customer-service-agent-manifest.json\nManifest ID:          customer-service-agent-manifest\nAgent name:           customer-service-agent\nEnvironment:          production\nTools:                2\nActions:              4\n\nActions by type:\n  external_send: 1\n  read: 2\n  write: 1\n\nActions by default posture:\n  allow: 2\n  block: 1\n  escalate: 1\n\nActions requiring authority: 2\nActions requiring review:    2\nActions requiring reliance:  2\n```\n\nThat \"2\" next to authority is easy to misread as just the send — it's actually `draft_reply`\n\nand `send_email`\n\nboth. Drafting on a customer's behalf declares its own authority requirement (`email.draft.customer`\n\n), separate from the one on the final send (`email.send.customer`\n\n). Declaring it isn't the same as enforcing it — nothing here checks whether that authority actually exists. That check is the Control Plane's job, next post.\n\n`aam`\n\nverifies that your manifest is ready, and gives the team a concise summary of what's allowed.\n\nThe manifest is the **Declare** layer, and it stays in its lane:\n\n`email.send.customer`\n\nbeing Declaring that sending email should require approval is not the same thing as stopping an unapproved send. That gap — between what's declared and what actually happens when the agent tries to act — is exactly what the next layer closes.\n\nThe manifest says what the agent *may* propose. It says nothing about what the agent actually *does* on a Tuesday afternoon when it's mid-run and reaching for the send button. That's the **Agent Control Plane** — it reads this exact manifest, sits beside the agent at runtime, and turns every proposed action into a recorded decision: allow, block, or escalate, deterministically, every time. That's next.\n\nThe manifest repo, examples, schemas, and test suite are live now: [github.com/cogno-us/cognous-open-control-stack](https://github.com/cogno-us/cognous-open-control-stack). Clone it, validate the customer-service example, break it on purpose and watch the validator catch you.", "url": "https://wpnews.pro/news/the-manifest-that-keeps-your-ai-agent-honest", "canonical_source": "https://dev.to/cognous/the-manifest-that-keeps-your-ai-agent-honest-3e97", "published_at": "2026-08-12 14:50:04+00:00", "updated_at": "2026-08-12 15:19:11.787774+00:00", "lang": "en", "topics": ["ai-agents", "ai-safety", "ai-policy", "developer-tools"], "entities": ["Cognous", "Open Control Stack", "Agent Action Manifest", "GitHub"], "alternates": {"html": "https://wpnews.pro/news/the-manifest-that-keeps-your-ai-agent-honest", "markdown": "https://wpnews.pro/news/the-manifest-that-keeps-your-ai-agent-honest.md", "text": "https://wpnews.pro/news/the-manifest-that-keeps-your-ai-agent-honest.txt", "jsonld": "https://wpnews.pro/news/the-manifest-that-keeps-your-ai-agent-honest.jsonld"}}