Tips & Tricks (更新: 2026/6/3)

Claude Code Permission Budget Loop:5分钟检查权限、成本和日志

用一个实用循环检查 Claude Code 的 allow/deny 规则、成本上限、执行日志和团队交接。

Claude Code Permission Budget Loop:5分钟检查权限、成本和日志

为什么每天早上要检查5分钟

使用 Claude Code 时,真正的运营问题不只是“它会不会写代码”。更重要的是:“哪些事情可以让它不经确认就做?”每个 Bash 命令都手动批准,第一天看起来很谨慎,但很快就会出现审批疲劳。全部放开更危险:读取 .env、安装依赖、git push、生产 deploy、数据库 migration、billing 变更,都可能进入同一条通道。

Permission budget 是一张很短的运行表。它写清楚 Claude Code 哪些动作可以无需批准,哪些动作必须先问人,哪些动作在这个仓库里禁止。Loop 指的是每天早上把这张表和前一天的执行日志、使用量对照一遍。换句话说,就是每天数一遍交给 agent 的钥匙和预算。

截至 2026年6月3日,官方文档说明 Claude Code 权限使用 allowaskdenydeny 优先于 askallow/permissions 会显示当前规则以及规则来自哪个 settings 文件。成本方面,/usage 适合看本地或当前 session 的情况,Claude Console 才是 billing 和 workspace limit 的权威来源。建议收藏 Configure permissionsClaude Code settingsManage costs effectivelyCLI reference

内部延伸阅读可以连接到 Claude Code permissions guidepermission audit checklistpermission receipt pattern

不用安全术语也能理解的基础

Claude Code permission 不是模型的承诺,而是 CLI 真正执行的边界。在 CLAUDE.md 写“不要读取 secret”是有用的指导,但它不是技术边界。Read(./.env)Read(./secrets/**) 这样的 deny rule,才是 Claude Code 可以执行的边界。

Permission mode 也要分清。default 是标准审批流程。plan 更适合阅读和调查。acceptEdits 让文件修改更顺。dontAsk 会拒绝没有预先批准、也没有放进 ask 的工具。bypassPermissions,也就是 --dangerously-skip-permissions,会跳过权限提示,应该只在隔离 container 或 VM 里使用。

成本也一样。/usage 可以发现某个本地 session 是否异常昂贵,但 API billing 要在 Claude Console 确认。对于 claude -p 这样的脚本运行,--max-budget-usd--max-turns 是有用的保护线,但不能代替团队预算。

每天的 permission budget loop

流程必须足够短,才会持续执行。目标不是完美审计,而是不要在危险权限仍然打开时开始一天的工作。

步骤检查项通过条件
1/permissions没有 Bash(*),也没有过宽的 Bash(npm *)
2.claude/settings.jsonsecrets、deploy、database、billing 都在 askdeny
3/usage 和 Console昨天的成本增长可以解释
4git diff 和执行日志已批准工作和 diff 一致
5交接记录open allowances、blocked actions、next reviewer 都写清楚

可以用这个简短 prompt 开始:

Before starting today's Claude Code work, classify the task into:
1. safe to run without approval
2. requires human approval
3. should not run in this session

Then list up to five checks for /permissions, /usage, and git diff.

共享 settings.json 起点

下面是一个 .claude/settings.json 起点。defaultMode: "dontAsk" 很严格:不在 allowask 里的工具不会运行。先在本地试,再考虑作为团队共享设置。

{
  "$schema": "https://json.schemastore.org/claude-code-settings.json",
  "permissions": {
    "defaultMode": "dontAsk",
    "allow": [
      "Bash(npm run lint)",
      "Bash(npm run test)",
      "Bash(npm run test *)",
      "Bash(npm run build)",
      "Bash(git status)",
      "Bash(git diff)",
      "Bash(git diff *)",
      "WebFetch(domain:code.claude.com)"
    ],
    "ask": [
      "Bash(npm install *)",
      "Bash(pnpm add *)",
      "Bash(git push *)",
      "Bash(wrangler deploy *)",
      "Bash(vercel deploy *)",
      "Bash(terraform apply *)",
      "Bash(kubectl apply *)"
    ],
    "deny": [
      "Read(./.env)",
      "Read(./.env.*)",
      "Read(./secrets/**)",
      "Bash(curl *)",
      "Bash(wget *)",
      "Bash(rm -rf *)"
    ]
  }
}

关键不是这份命令列表本身,而是把安全通道保持得足够窄。Bash(npm *) 可能从 test 滑到 install 或 publish。Bash(git *) 可能从 diff 滑到 push。读取、lint、test、build 可以窄范围 allow;install、push、deploy、apply 应该放在人类确认之后。

用 JSON 保留预算和执行日志

权限只是循环的一半,另一半是成本。长时间调查、反复失败的 test、后台 session、大段日志,都可能悄悄增加成本。把预算和每日日志写成 JSON,可以在 pull request 里看到。

{
  "date": "2026-06-03",
  "dailyLimitUsd": 6,
  "warnAtUsd": 4,
  "usageSource": "/usage plus Claude Console",
  "safeAllow": [
    "Bash(npm run lint)",
    "Bash(npm run test)",
    "Bash(git diff *)"
  ],
  "askFirst": [
    "Bash(npm install *)",
    "Bash(git push *)",
    "Bash(wrangler deploy *)"
  ],
  "mustDeny": [
    "Read(./.env)",
    "Read(./.env.*)",
    "Read(./secrets/**)"
  ],
  "handoffRequired": true
}
{
  "date": "2026-06-03",
  "spentUsd": 1.85,
  "usageChecked": true,
  "settingsChecked": true,
  "permissionsReviewed": [
    "/permissions",
    ".claude/settings.json"
  ],
  "openAllowances": [
    "Bash(npm run lint)",
    "Bash(npm run test *)"
  ],
  "handoff": [
    "No deploy allowance left open",
    "Claude stopped before production data work"
  ]
}

分别保存为 .claude/permission-budget.json.claude/daily-claude-log.json。Spreadsheet 可以用于管理报表,但 JSON 更适合 code review 和自动化。

可直接运行的 Node 审计脚本

把下面内容保存为 scripts/audit-claude-loop.mjs,运行 node scripts/audit-claude-loop.mjs。不需要外部依赖。它会检查过宽 Bash 权限、deploy 命令是否误放进 allow.env deny 是否缺失、预算是否超限、交接记录是否为空。

#!/usr/bin/env node
import fs from "node:fs";

const readJson = (file) => JSON.parse(fs.readFileSync(file, "utf8"));

const budget = readJson(".claude/permission-budget.json");
const log = readJson(".claude/daily-claude-log.json");
const settings = readJson(".claude/settings.json");

const problems = [];
const permissions = settings.permissions ?? {};
const allow = new Set(permissions.allow ?? []);
const ask = new Set(permissions.ask ?? []);
const deny = new Set(permissions.deny ?? []);
const hasPattern = (items, pattern) => [...items].some((item) => pattern.test(item));

if (typeof budget.dailyLimitUsd !== "number" || budget.dailyLimitUsd <= 0) {
  problems.push("dailyLimitUsd must be a positive number");
}

if (typeof budget.warnAtUsd !== "number" || budget.warnAtUsd >= budget.dailyLimitUsd) {
  problems.push("warnAtUsd must be lower than dailyLimitUsd");
}

if (log.spentUsd > budget.dailyLimitUsd) {
  problems.push(`spentUsd ${log.spentUsd} exceeds daily limit ${budget.dailyLimitUsd}`);
}

if (log.spentUsd >= budget.warnAtUsd) {
  console.warn(`WARN: spentUsd ${log.spentUsd} has reached warnAtUsd ${budget.warnAtUsd}`);
}

if (!log.usageChecked) problems.push("Run /usage and mark usageChecked true");
if (!log.settingsChecked) problems.push("Review /permissions and mark settingsChecked true");

if (allow.has("Bash") || allow.has("Bash(*)") || hasPattern(allow, /^Bash\(\*.*\)$/)) {
  problems.push("Do not allow every Bash command");
}

if (hasPattern(allow, /(deploy|terraform apply|kubectl apply|git push)/)) {
  problems.push("Deploy, infrastructure, and push commands must be ask-first, not allow");
}

for (const rule of budget.askFirst ?? []) {
  if (!ask.has(rule)) problems.push(`Missing ask rule: ${rule}`);
}

for (const rule of budget.mustDeny ?? []) {
  if (!deny.has(rule)) problems.push(`Missing deny rule: ${rule}`);
}

if (!hasPattern(deny, /Read\(.*\.env/)) {
  problems.push("Deny rules should block .env reads");
}

if (!Array.isArray(log.handoff) || log.handoff.length === 0) {
  problems.push("Add at least one handoff note");
}

if (problems.length) {
  console.error(problems.map((problem) => `- ${problem}`).join("\n"));
  process.exit(1);
}

console.log("Claude Code daily permission budget check passed.");

放进 CI 时,建议先用 warning 或手动执行。第一天就设成强制 gate,往往只会让团队寻找绕过方式。

四个具体用例

第一个用例是文章和文档更新。Markdown、MDX、内部链接、CTA、错字、图片路径通常不会碰到 secret 或生产环境。把 file read、git diff、lint、test、本地 build 窄范围 allow,Claude Code 就能少停顿地生成小 diff。

第二个用例是依赖变更。npm installpnpm add 会影响 lockfile、postinstall、license、vulnerability 和 bundle size。把它们放进 ask。批准前,让 Claude Code 写清为什么需要新依赖、是否有替代方案、如果不接受如何移除。

第三个用例是 deploy 和 migration。wrangler deployvercel deployterraform applykubectl apply、数据库 migration 都会改变外部状态。Claude Code 可以准备命令、影响范围、rollback、验证 URL、监控清单,但执行必须等人批准。

第四个用例是团队交接。如果别人稍后继续,需要写下 open allowances、proof commands、blocked actions 和 remaining budget。没有这条记录,下一位成员会重复调查、消耗更多 token,并重新打开同样的风险权限。

避免这些失败

最常见的失败是 Bash 权限太宽。Bash(npm *)Bash(git *) 看起来方便,但会把只读习惯和改变状态的命令混在一起。日常通道尽量使用精确命令。

第二个失败是忘记关闭 deploy allowance。事故处理中,wrangler deploy * 可能临时从 ask 变成 allow。如果第二天还留着,普通 feature 工作也有了生产权限。

第三个失败是忽视 token 和成本增长。长时间调查看起来很有产出,但可能烧掉预算。检查 /usage,billing 重要时对照 Console,没有明确价值的 session 要停掉。

最后,不要把 prompt 当成 enforcement。“不要读取 secret”是指导。Read(./.env) 放在 deny 才是执行边界。Harness,也就是 agent 的工作框架,需要 prompt、settings、log 和 review 一起存在。

产品、培训和团队落地

个人练习时,先把 JSON 和脚本复制到一个小仓库。可复用 checklist、CLAUDE.md template 和 review prompt 可以看 /products/。如果团队需要权限、成本控制、CI policy、reviewer training 和按仓库定制的规则,可以看 /training/

实践记录:最大的改善并不是把所有危险命令都封死,而是每天早上花5分钟看 /permissions/usagegit diff 和交接记录。窄范围的 allow 仍然有用,而 deploy、billing、secrets 会稳定回到 askdeny

#claude-code #permissions #security #approval #workflow #team
免费

免费 PDF: Claude Code 速查表

输入邮箱即可获取一页 PDF,整理常用命令、审查习惯和安全工作流。

我们会妥善保护你的信息,不发送垃圾邮件。

把 Claude Code 变成真正能带来结果的工作流

先领取中文说明的免费 PDF,再进入英文商品页选择合适的教材。如果你需要团队落地、流程设计或内容变现支持,也可以直接咨询。

Masa

关于作者

Masa

专注 Claude Code 实务流程、团队导入和内容转化的工程师。