Skip to content

An AI usage policy engineers will follow

An AI usage policy for coding agents is an acceptable-use document covering data classes, approved routes, disclosure, review duties and prohibited actions, in which every clause is tagged with how it is enforced: by managed settings, by a hook or repository rule, by detection after the fact, or by trust alone. Clauses that rest on trust need a named check.

Your legal team circulated a four-page “Generative AI Acceptable Use” PDF in spring. Since then two developers have logged in to Claude Code with personal accounts, someone added an unvetted MCP server that reads the whole Jira instance, and nobody can say which merged pull requests an agent wrote. The PDF was never wrong; it was unenforceable and unverifiable.

This page is for the CTO who signs the policy and the tech lead who makes it true in eight repositories. It reuses the data tiers from data privacy and enterprise policies and leaves distribution and audit to enforcing one policy across every coding agent.

What this AI usage policy template gives you

Section titled “What this AI usage policy template gives you”
  • A policy of 28 numbered clauses for your handbook, each tagged with its enforcement type.
  • An enforcement map naming the Claude Code, Codex, Cursor or repository setting behind each clause.
  • A managed-settings file for Claude Code and a requirements.toml for Codex.
  • A prompt-screening hook and a pull-request disclosure check.
  • A verification routine, plus the failure modes that quietly switch clauses off.

Why do engineers ignore most AI usage policies?

Section titled “Why do engineers ignore most AI usage policies?”

Most AI policies state values (“use AI responsibly”), not behavior a reviewer could check. Engineers follow the letter and lose the tools, or follow judgment and hope. Neither produces the “clear and communicated AI stance” that DORA lists as the first of its seven AI capabilities (Google Cloud blog, Storer and DeBellis, 2025-09-23). DORA’s rationale: “Ambiguity creates risk. A clear policy provides the psychological safety developers need to experiment effectively” (Google Cloud blog, Harvey and Park, 2025-12-10).

A policy engineers follow is short and specific: every clause names an action, a data class or a tool setting, and a clause no concrete act can break belongs in the preamble. It is enforced where the tool allows it and honest about the rest: clauses no setting can enforce (“do not paste customer data into a browser chatbot on your phone”) are labeled trust clauses with a named check.

TagMeaningEvidence that it holds
[MANAGED]Enforced by the tool’s managed configuration, which users and repositories cannot override/status in Claude Code names the managed source; /debug-config in Codex shows the requirement source
[HOOK]Enforced by an organization-deployed hook that blocks the action at run timeHook denial events in telemetry; a drill that triggers the block
[REPO]Enforced by repository rules or a required CI check, independent of which tool wrote the codeRuleset and required-check configuration; a failing test PR
[DETECT]Not prevented, but detected after the fact through telemetry, audit logs or scanningA named dashboard or report and its owner
[TRUST]Rests on the engineer’s judgment; no tool can see the actA named periodic check (sampling, attestation, training record)

Aim for mostly [MANAGED], [HOOK] and [REPO]; a mostly-[TRUST] policy is the legal team’s PDF with better formatting.

Copy this into your handbook and replace the owners and tool list. Keep clause numbers stable, because hooks, CI messages and exception tickets cite them.

# AI usage policy for software engineering (v1.0, owner: CTO, reviewed quarterly)
Purpose: let every engineer use coding agents daily, on real work, inside guardrails
the tools enforce. Where a guardrail cannot be enforced, this policy says so.
## 1. Scope
1.1 Applies to every employee and contractor who uses an AI coding tool (IDE agent,
CLI agent, cloud agent, chat assistant) on company code, data or systems. [TRUST]
1.2 Applies to unattended agents (CI jobs, scheduled loops, review bots) through their
owners, recorded in the agent identity register. [DETECT]
## 2. Data classes (tiers from the data privacy policy)
2.1 Public and Internal code may be used with any approved route (section 3). [MANAGED]
2.2 Confidential material (unreleased features, pricing logic, security design) may be
used only through approved routes whose terms exclude training on company data. [MANAGED]
2.3 Credentials never appear in a prompt. [HOOK]
2.4 Customer PII, payment and health data never enter an agent's context: not in prompts,
files the agent can read, logs or test fixtures. [TRUST]
2.5 Agents may not read secret files (.env*, cloud credential files, SSH keys). [MANAGED]
2.6 Production data reaches an agent only as an anonymized or synthetic copy. [TRUST]
## 3. Approved routes
3.1 Use only the approved tools listed in the tool register, signed in to the company
tenant. Personal accounts on company work are not allowed. [MANAGED]
3.2 Use only the models on the approved list; new models are added through the model
change process. [MANAGED]
3.3 MCP servers, plugins and plugin marketplaces must be on the allowlist. [MANAGED]
3.4 Browser chat assistants outside the tool register may be used for Public material
only. [TRUST]
3.5 A tool not on the register can be trialed through an exception (section 7), never
by installing it and asking later. [DETECT]
## 4. Disclosure
4.1 Commits an agent authored or co-authored carry the tool's attribution trailer; do not
strip it. [MANAGED] [DETECT]
4.2 Every pull request states its AI assistance level: none, assisted or agent-authored. [REPO]
4.3 Customer-facing deliverables produced with agents follow the client contract's
disclosure clause. [TRUST]
## 5. Review duties
5.1 A human with merge rights approves every change before it reaches the default
branch; an agent approval never counts as the required review. [REPO]
5.2 The approver is accountable for the change as if they wrote it, and approves on
evidence (tests, checks, acceptance criteria), not on the agent's summary. [TRUST]
5.3 Changes to paths owned by security, payments or infrastructure require a review
from the owning team. [REPO]
5.4 CI gates (type check, lint, tests, secret scanning, dependency checks) must pass;
no agent may disable or skip them. [REPO]
## 6. Prohibited actions
6.1 Pasting credentials into a prompt, a file or an agent configuration. [HOOK]
6.2 Running an agent with approvals and sandbox fully bypassed, outside a disposable,
network-restricted sandbox. [MANAGED]
6.3 Letting an agent force-push, rewrite shared history or push to protected
branches. [MANAGED] [REPO]
6.4 Letting an agent deploy to production, run migrations against production or
change production secrets without the human gate in the governance policy. [REPO]
6.5 Adding hooks, MCP servers or plugins to a repository to widen what an agent may do
without platform-team review. [MANAGED]
6.6 Using agent output to make decisions about people (hiring, performance). [TRUST]
## 7. Exceptions and review
7.1 Exceptions are requested by ticket, name the clause, the scope and an end date, and
are approved by the platform owner and security. [DETECT]
7.2 This policy is reviewed quarterly and after every AI-related incident; each change
names the clause, the reason and the enforcement change. [TRUST]

The template counts 28 clauses: 17 are enforced by managed settings, hooks or repository rules (6.3 by both; 4.1 is also detected in CI), 3 are detected only, and 8 rest on trust.

Which clauses can Claude Code, Codex and Cursor enforce?

Section titled “Which clauses can Claude Code, Codex and Cursor enforce?”

The enforcement map is the platform team’s working document; each row names the setting or rule that makes the clause true. Cursor cells are thinner because its admin controls could not be re-verified on 2026-09-26; treat a Cursor clause as [REPO] plus [TRUST] until your Cursor admin confirms the control.

ClauseClaude Code (managed settings)Codex (requirements.toml)CursorRepository
2.2 Confidential only on no-training routesCompany tenant login (3.1) plus the retention terms of that planCompany workspace login (3.1) plus its data termsPrivacy settings: confirm in admin dashboard—
2.3 Credentials out of promptsUserPromptSubmit hook that exits 2[hooks] UserPromptSubmit in requirements.tomlHooks (JSON over stdio)Secret scanning with push protection
2.5 No secret-file readspermissions.deny plus sandbox.filesystem.denyRead[permissions.filesystem] deny_read (absolute paths or globs)Confirm in agent security settings—
3.1 Company tenant onlyforceLoginMethod, forceLoginOrgUUIDallowed_login_methods, allowed_chatgpt_workspacesSSO on the team plan: confirm—
3.2 Approved modelsavailableModels, enforceAvailableModels; deniedModels needs v2.1.283 (latest channel on 2026-09-26)No model allowlist key in requirements.toml (checked 0.157.1); model_provider pins the provider and [models.new_thread] sets defaults onlyModel controls: confirm—
3.3 MCP, plugin, marketplace allowlistallowedMcpServers + allowManagedMcpServersOnly, strictKnownMarketplaces[mcp_servers.<name>.identity], plugins, marketplacesConfirm in admin dashboard—
4.1 Attribution trailerattribution in managed settingsA built-in instruction to add Co-authored-by: Codex <noreply@openai.com>, switched by the user’s account setting—Trailer detection in CI
4.2, 5.1, 5.3, 5.4, 6.4———Rulesets, CODEOWNERS, required checks, environment approvals
6.2 No full bypasspermissions.disableBypassPermissionsMode: "disable"allowed_sandbox_modes without danger-full-access; allowed_approval_policiesConfirm run-mode controls—
6.3 No force-pushpermissions.deny on Bash(git push --force *)[rules] prefix_rules with decision = "forbidden"HooksBranch rulesets block force-push
6.5 No repository-added hooksallowManagedHooksOnly, allowManagedPermissionRulesOnlyallow_managed_hooks_only = true—CODEOWNERS on .claude/, .codex/, .cursor/

The repository column judges the change rather than the tool, so it covers every agent, including shadow tools; that is why clauses 5.1 to 5.4 and 6.4 live there. Both tools add attribution by instructing the model, not by rewriting the commit. Codex reads the switch from the user’s account setting (commit_attribution_enabled in openai/codex at rust-v0.157.1, checked 2026-09-26) and requirements.toml has no key for it, so for Codex clause 4.1 is detection only. A human can amend any commit, so the CI trailer check is the evidence for both tools.

How do you enforce the data and route clauses?

Section titled “How do you enforce the data and route clauses?”

Deliver these files through device management, not the repository (see the first failure mode below).

Claude Code reads managed settings from /Library/Application Support/ClaudeCode/managed-settings.json on macOS, /etc/claude-code/managed-settings.json on Linux and WSL, and C:\Program Files\ClaudeCode\managed-settings.json on Windows, or from server-managed settings in the claude.ai admin console on Team and Enterprise plans. Managed settings take precedence over command-line arguments, project and user settings.

{
"forceLoginMethod": "claudeai",
"forceLoginOrgUUID": "ORG_UUID",
"availableModels": ["opus", "sonnet"],
"enforceAvailableModels": true,
"permissions": {
"deny": [
"Read(./.env)",
"Read(./.env.*)",
"Read(~/.aws/**)",
"Read(~/.ssh/**)",
"Bash(git push --force *)",
"Bash(git push -f *)"
],
"disableBypassPermissionsMode": "disable"
},
"allowManagedPermissionRulesOnly": true,
"sandbox": {
"enabled": true,
"filesystem": { "denyRead": ["~/.aws/credentials", "~/.ssh"] }
},
"allowedMcpServers": [
{ "serverUrl": "https://api.githubcopilot.com/mcp/*" },
{ "serverUrl": "https://mcp.internal.example.com/*" }
],
"allowManagedMcpServersOnly": true,
"strictKnownMarketplaces": [
{ "source": "github", "repo": "anthropics/claude-plugins-official" },
{ "source": "github", "repo": "acme-corp/approved-plugins" }
],
"allowManagedHooksOnly": true,
"attribution": {
"commit": "Co-Authored-By: Claude <noreply@anthropic.com>\nAI-Policy: v1.0"
},
"companyAnnouncements": [
"AI usage policy v1.0 applies: handbook/ai-usage-policy. Restricted data never goes in a prompt."
]
}

ORG_UUID is your Anthropic organization ID. The Read deny rules cover Claude’s file tools and the Bash file commands Claude Code recognizes, such as cat and sed. With the sandbox on, Claude Code also copies every Read(...) deny path into the sandbox’s denyRead list, which the operating system enforces for every sandboxed command; the explicit denyRead entries add home-directory credential files the default sandbox read policy would expose. List the marketplaces you actually approve: an empty strictKnownMarketplaces array blocks every source, including Anthropic’s official one.

How do you enforce prohibited actions with a hook?

Section titled “How do you enforce prohibited actions with a hook?”

Clauses 2.3 and 6.1 need a check that runs before the model sees the prompt. The script below rejects a prompt that contains a private key or a common credential format; it cannot recognize customer PII, which is why clause 2.4 stays [TRUST]. Save it where developers cannot edit it and register it in managed settings.

#!/usr/bin/env bash
# /etc/claude-code/hooks/block-credentials.sh (AI usage policy 2.3, 6.1)
command -v jq >/dev/null || { echo 'AI usage policy: jq missing, prompt blocked' >&2; exit 2; }
prompt=$(jq -r '.prompt // empty') || { echo 'AI usage policy: unreadable hook input, prompt blocked' >&2; exit 2; }
if printf '%s' "$prompt" | grep -Eq -- '-----BEGIN [A-Z ]*PRIVATE KEY-----|AKIA[0-9A-Z]{16}|gh[pousr]_[A-Za-z0-9]{36}|sk-ant-[A-Za-z0-9_-]{20,}'; then
echo "Blocked by AI usage policy 2.3/6.1: the prompt contains a credential. Remove it and reference the secret by name." >&2
exit 2
fi
exit 0
{
"hooks": {
"UserPromptSubmit": [
{ "hooks": [{ "type": "command", "command": "/etc/claude-code/hooks/block-credentials.sh" }] }
]
}
}

In Claude Code, exit code 2 from a UserPromptSubmit hook rejects the prompt and shows the message; exit code 1 is a non-blocking error that lets the prompt through. With allowManagedHooksOnly set, only managed hooks and hooks from force-enabled plugins run. The two jq guards make the hook fail closed when jq is missing or the input cannot be parsed.

Codex has the same UserPromptSubmit event among its 12 hook events. Register the script in the [hooks] table of requirements.toml (shape from hook_config.rs and config_requirements.rs in openai/codex at rust-v0.157.1, checked 2026-09-26):

[hooks]
managed_dir = "/etc/codex/hooks"
windows_managed_dir = 'C:\ProgramData\OpenAI\Codex\hooks'
[[hooks.UserPromptSubmit]]
[[hooks.UserPromptSubmit.hooks]]
type = "command"
command = "/etc/codex/hooks/block-credentials.sh"
timeout = 10

A user or project layer cannot replace these managed hooks. The source does not settle whether Codex reads exit code 2 as Claude Code does, so confirm the block with /hooks and a test prompt. The pattern list is a floor: pair it with your secret scanner’s rules.

How do you enforce disclosure and review in the repository?

Section titled “How do you enforce disclosure and review in the repository?”

Three controls carry clauses 4.2 and 5.1 to 5.4:

  1. A branch ruleset on the default branch requiring a pull request, one approving review, passing required checks and no force-pushes. Only approvals from accounts with write access count, so keep agent identities without it.
  2. CODEOWNERS for security-owned paths and the agent configuration directories (.claude/, .codex/, .cursor/, .mcp.json), so widening an agent’s permissions needs the platform team.
  3. A required disclosure check, below, on every pull request.
name: ai-disclosure
on:
pull_request:
types: [opened, edited, synchronize]
permissions:
contents: read
jobs:
disclosure:
runs-on: ubuntu-latest
steps:
- name: Require an AI assistance declaration (policy 4.2)
env:
PR_BODY: ${{ github.event.pull_request.body }}
run: |
if ! printf '%s' "$PR_BODY" | grep -Eq '^AI assistance: (none|assisted|agent-authored)[[:space:]]*$'; then
echo "::error::Add 'AI assistance: none|assisted|agent-authored' to the PR description (AI usage policy 4.2)."
exit 1
fi

The workflow passes the untrusted PR body through env:, not interpolation. It proves a declaration exists, not that it is true: add a second step that flags a PR whose commits carry a Co-Authored-By: Claude or Co-authored-by: Codex trailer while the body says none. The change provenance answer key shows how to route the declared level into review depth.

Eight clauses stay [TRUST]. For each, name a check and an owner, so “trust” means “trusted and sampled”, not “unexamined”:

ClauseCheckOwnerCadence
1.1, 3.4 Scope and browser chatAnnual attestation plus the AI-literacy training recordEngineering managersYearly, at onboarding
2.4 No PII, payment or health dataSample 10 agent-session transcripts and the fixtures and logs they touched; check for real customer dataData protection leadQuarterly
2.6 Anonymized production dataSample 10 test fixtures added in agent-authored PRs; check for real identifiersData protection leadQuarterly
4.3 Client disclosureContract checklist at kickoff for each client engagementDelivery leadPer engagement
5.2 Approve on evidenceSample 20 merged agent-authored PRs; can the approver name the evidence?Tech leadsMonthly
6.6 No decisions about peopleHR process reviewHR and CTOYearly
7.2 Policy reviewChange log with clause, reason and enforcement changeCTOQuarterly

The AI-literacy record can also serve as evidence of the staff AI-literacy measures that Article 4 of the EU AI Act still requires (softened, not removed, by the Digital Omnibus according to Gibson Dunn’s summary, checked 2026-09-26); see the EU AI Act for companies building software with agents.

The three [DETECT] clauses each need a source and owner:

ClauseDetection sourceOwnerCadence
1.2 Unattended agents registeredAgent identity register reconciled against CI service accounts and bot tokensPlatform teamMonthly
3.5 No unregistered toolsDevice-management software inventory, plus claude_code.managed_settings_resolved coverageIT and securityMonthly
7.1 Exceptions expireException tickets past their end dateSecurityWeekly

How do you verify the policy is actually in force?

Section titled “How do you verify the policy is actually in force?”

A clause marked [MANAGED] that is not deployed is worse than a [TRUST] clause, because everyone believes it holds. Run this routine at rollout and every quarter.

  1. Confirm the managed source on a sample of machines. In Claude Code, /status shows Enterprise managed settings in the Setting sources line, and claude doctor lists entries dropped as invalid. In Codex, /debug-config shows config layers and requirement sources.
  2. Drill each enforced clause in a disposable scratch repository with no real secrets: first confirm claude --dangerously-skip-permissions, codex -s danger-full-access and codex --dangerously-bypass-approvals-and-sandbox are rejected (6.2), then, in a normal session, paste a dummy key that matches the hook pattern, add an unlisted MCP server and force-push from the agent. Each attempt must fail with a message that cites the clause.
  3. Check the repository controls with a test PR. Open a PR with no disclosure line and one that edits .claude/settings.json. The first must fail the required check; the second must request the platform team’s review.
  4. Watch the detection signals. With Claude Code’s OpenTelemetry export (CLAUDE_CODE_ENABLE_TELEMETRY=1 and an OTLP endpoint set in managed settings), the claude_code.managed_settings_resolved event shows which managed source each session loaded, and claude_code.hook_execution_complete counts blocking decisions (num_blocking) per hook. Coverage below 100% means machines outside the rollout, and rising denials on one clause mean it is blocking real work (see below). The agent observability guide covers the pipeline.
  5. Record the results. Keep the drill log with the policy version: it is the auditor’s evidence and the input to the quarterly review (clause 7.2).

Sign-off: the platform owner signs the drill log, security countersigns the map, and the CTO approves each version. The operating model places these roles in its RACI.

Run both prompts in Claude Code or Codex from the root of your handbook repository.

Drill 6.1 separately, because the hook would reject the combined prompt at submission: submit a one-line prompt containing AKIAABCDEFGHIJKLMNOP and expect the 2.3/6.1 message. Drill 6.2 from the shell, as in step 2 of the verification routine.

A “no” in the blocked column is a finding, not an agent failure.

Why do AI usage policies fail in practice?

Section titled “Why do AI usage policies fail in practice?”

A policy lives in project settings. A repository’s .claude/settings.json or .codex/config.toml can be changed on any branch. Recovery: move every enforcement key to managed settings or requirements.toml, keep project files for defaults, and put CODEOWNERS on the agent directories.

Login pinning with the wrong key. In Claude Code, forceLoginMethod pre-selects but does not enforce the method on the interactive /login screen; forceLoginOrgUUID from a managed source is what restricts claude.ai logins to your organization. Recovery: set both, and test by logging in with a personal account.

Deny rules that look complete. Read deny rules miss commands that read files without naming them, such as grep -r, and arbitrary subprocesses. Recovery: turn on the sandbox with sandbox.filesystem.denyRead, and keep secrets out of the workspace, per agent identity, credentials and secrets.

A managed file that breaks startup or disables a feature. Claude Code refuses to start when a managed settings file is not valid JSON, allowManagedHooksOnly stops /goal from running because it depends on hooks, allowManagedPermissionRulesOnly ignores every user and project allow rule, and sandbox.enabled needs bubblewrap on Linux and WSL2 and is not supported on native Windows. Recovery: validate the file in CI, put shared allow rules in managed settings, special-case native Windows and pilot first.

A hook that fails open. Without guards, a missing dependency or unparsable input yields an empty prompt and exit 0, so everything goes through while the clause is still tagged [HOOK]. Recovery: fail closed, as the jq guards above do, and include the hook in the drill.

Codex keys in the wrong file or the wrong system. allow_managed_hooks_only in config.toml does nothing, and a [rules] entry with decision = "allow" fails to parse. On permission profiles (beta), allowed_sandbox_modes is the wrong constraint: use allowed_permission_profiles, because OpenAI states the profile and legacy sandbox systems do not compose. Recovery: keep a linted requirements.toml in the platform repository and check /debug-config on a sample machine after every change.

CI runners caught by the developer file. Leaving never out of allowed_approval_policies also blocks codex -a never on any machine that carries the file, including a CI runner. Recovery: exclude runners from the device rollout and give them their own requirements.toml.

The policy blocks the work. Engineers route around an approved route that is slower than the forbidden one. Watch the exception queue (clause 7.1) and hook-denial counts; a clause that generates weekly exceptions needs a better approved route, not a sterner memo.

Shadow tools the map never covered. A new IDE agent or browser extension carries none of your managed settings. Add the tool to the register or block it at the device layer, per the tooling policy answer key.

Treat any policy breach that reaches production as an incident: revoke the identity, then fix the control that failed; see when an agent causes an incident.

Where to go next with your AI usage policy

Section titled “Where to go next with your AI usage policy”