React Native

AI Coding Agent Permissions: One Policy for Every Agent (6 Steps, 2026)

Enforce one permissions policy across Claude Code, Cursor, and Copilot: a shared AGENTS.md, deny-by-default tool rules, hooks, and audit-to-enforce rollout in 6 steps.

October 30, 2026 • 7 min • Mikołaj Gramowski

To enforce one permissions policy across every AI coding agent, write the rules once in a shared AGENTS.md, deny risky actions by default in each tool's native permission config, and back them with deterministic hooks and CI checks. Roll rules out in audit mode first, then warn, then enforce. Prompts are advice; permissions, hooks, and CI are enforcement.

Most teams now run more than one agent: Claude Code in the terminal, Cursor in the editor, Copilot in pull requests. Each has its own config format, its own defaults, and its own idea of what "allowed" means. The result is policy drift: a command blocked in one tool runs freely in another. This guide gives you a single model that works across all of them. It builds on the AI coding agent security checklist, the hooks security controls, and the sandbox escape analysis.

Why per-tool settings drift apart

Every agent ships with its own permission surface. Claude Code uses allow and deny lists in settings files plus hooks. Cursor uses rules files and an allowlist for terminal commands. Copilot relies on repository instructions and the permissions of the identity it runs under. None of these formats is portable, so a rule copied by hand into three places will be out of sync within a month.

LayerWhat it doesEnforced?Portable across agents?
AGENTS.md / instructionsStates intent and conventionsNo, advisory onlyYes, widest support
Native permission configAllow, ask, deny per tool or commandYes, by the agentNo, one format per tool
Hooks / policy engineBlocks or rewrites actions before they runYes, deterministicPartly, via adapters
CI and branch protectionRejects bad changes regardless of agentYes, agent-independentYes
Credentials and sandboxLimits what the agent can reach at allYes, at OS or cloud levelYes

The portable layers are the first and the last two. Your strategy is to put the real guarantees in the portable, agent-independent layers and treat native configs as a second line of defense.

1. Write one source of truth in AGENTS.md

Start with a single AGENTS.md at the repo root. It has the widest cross-tool support, and Claude Code can read it by pointing CLAUDE.md at it with one line. Keep tool-specific files thin and make them reference the shared file instead of copying it.

## Agent policy (applies to every tool)
- Never read or print .env, *.pem, or ~/.ssh/*
- Never run destructive commands: rm -rf, git push --force, DROP, TRUNCATE
- Do not add dependencies without an issue link
- Run `pnpm test` and `pnpm lint` before declaring work done
- Production deploys, migrations, and secrets changes need a human

Write it by hand. Auto-generated files tend to be generic and bloated, and every line should exist because of a real incident or a real risk. Remember this file only states intent. Steps 2 to 5 make it true.

2. Deny by default in each tool's native config

Translate the policy into each agent's permission system. The principle is the same everywhere: start from read-only and ask-first, then allowlist narrow, known-safe commands. Do not start from "allow everything" and try to subtract.

// .claude/settings.json
{
  "permissions": {
    "allow": ["Bash(pnpm test:*)", "Bash(pnpm lint:*)", "Read(src/**)"],
    "deny": ["Read(.env*)", "Read(**/*.pem)", "Bash(rm -rf:*)", "Bash(git push --force:*)", "Bash(curl:*)"]
  }
}

Do the equivalent in Cursor's command allowlist and rules, and in Copilot's repository instructions. Keep a short table in your docs that maps each policy line to the setting that implements it in each tool, so a reviewer can spot a gap quickly.

3. Enforce with hooks, not hopes

Native allow and deny lists match command strings, and strings are easy to sidestep with shell tricks, wrappers, or a script the agent writes itself. A hook runs code before the action and can block it based on the real arguments. Put your non-negotiables there: secret file access, network egress, writes outside the workspace, and edits to the policy files themselves.

  • Protect the policy. Block agent writes to AGENTS.md, settings files, hooks, and CI workflows. An agent that can edit its own guardrails does not have guardrails.
  • Normalize before matching. Resolve paths and expand variables so ./a/../.env is caught.
  • Fail closed. If the hook errors or times out, the action is denied, not allowed.

If you want one rule set across several agents, use a shared policy engine with an adapter per tool, so a rule written once maps each agent's native event format onto a common model. See the hooks security guide for concrete hook patterns.

4. Scope credentials and tool access

Permissions inside the agent only matter if the environment is also limited. Agents leave credentials in config files, logs, and shell history, so assume anything the agent can read may be copied. Give it short-lived, least-privilege tokens, a separate dev identity, and no access to production secrets at all.

  • Use a dedicated bot account with read-only repo access by default.
  • Run agents in a container or sandbox with no home-directory mounts.
  • Review every MCP server as a privileged integration. See MCP server security controls.
  • Lock down CI agents separately, since they run unattended. See GitHub Actions prompt injection fixes.

5. Put the final check in CI

Whatever the agent does locally, the pull request is the same for everyone. Make branch protection and CI the agent-independent backstop: required reviews, required status checks, no direct pushes to main, secret scanning, and a dependency check. A policy that only exists on developer laptops is a suggestion.

6. Roll out in audit, warn, enforce stages

Do not turn on strict rules for the whole team in one day. Deploy each new rule in audit mode and review the logs to confirm it matches the right events. A false positive in audit mode is a log line; in enforce mode it is a blocked developer.

StageBehaviorExit criterion
AuditLog matches, block nothingOne week with no unexplained matches
WarnShow a message, allow overrideOverrides are rare and justified
EnforceBlock and logReviewed monthly, rules pruned

Common mistakes

  • Copying the same rules into three files by hand, then never diffing them.
  • Relying on instructions alone and calling it a policy.
  • Allowing broad wildcards such as a general shell or network tool "just for convenience".
  • Letting the agent modify its own settings, hooks, or CI files.
  • Skipping the audit stage and breaking the team's flow on day one.

Frequently asked questions

Should I use AGENTS.md or CLAUDE.md?

Use AGENTS.md as the shared source of truth because most agents read it. Add a CLAUDE.md only for Claude-specific instructions, and have it reference AGENTS.md instead of duplicating rules.

Are allow and deny lists enough on their own?

No. They match command patterns, which can be bypassed through wrappers or generated scripts. Pair them with hooks that inspect real arguments, a sandbox, and CI checks.

How do I keep policies in sync across tools?

Keep intent in one AGENTS.md, keep a mapping table from each policy line to its per-tool setting, and rely on agent-independent layers (CI, credentials, sandbox) for the guarantees that must never drift.

Do I need this for a solo project?

A lightweight version, yes. A deny list for secrets and destructive commands plus branch protection takes under an hour and prevents the worst outcomes.

Need a second pair of eyes on an AI-assisted codebase or a production hardening plan? Get in touch for a freelance full-stack review.