☰
Claude Code 明文存储风险治理:用 CLAUDE_CODE_SKIP_PROMPT_HISTORY 与 cleanupPeriodDays 管住工程风险
2026/9/29 20:46:12 网站建设 项目流程

1. 为什么 Claude Code 的明文存储值得你花十分钟处理

Claude Code 明文存储风险治理这件事,说白了就是一句话:Claude Code 会把你的会话记录、命令输出、工具返回结果,以明文形式写到本地磁盘上。它不会在本机做静态加密,能保护这些文件的,基本只有操作系统的文件权限。你可能会想,本地文件而已,能有多大问题?问题在于,Claude Code 是一个 agentic coding 工具,它要读文件、跑命令、调工具,而这些东西的输出全都会进入会话转录文件。如果某次调试时你让它读了.env,或者某条命令把 token 打印到了终端,这个值就会被写进projects/<project>/<session>.jsonl这类文件里。

这不是模型记忆突然变危险了,而是一个很朴素的工程事实:凡是被读进上下文、被命令输出、被工具返回的内容,都有机会进入会话转录文件。Claude Code 支持/resume、跨会话上下文、调试复盘、历史提示召回,这些体验都依赖持久化。但开发者日常工作里最敏感的东西也常常离代码最近——.env、数据库连接串、云厂商 access key、GitHub token、npm token、OAuth client secret、临时 bearer token,都可能出现在同一台开发机、同一个 repository、同一个终端窗口里。

所以这篇内容聚焦的不是"Claude Code 安不安全"这种大而空的问题,而是从两个具体的配置项切入:CLAUDE_CODE_SKIP_PROMPT_HISTORY和cleanupPeriodDays。我会给出可复制的settings.json骨架,配上验证动作,让你能确认配置真的生效了。适合谁看?适合所有把 Claude Code 用在真实项目里的开发者,尤其是那些项目里带.env、带生产凭据、带客户数据的人。如果你只是拿它写写 demo、跑跑学习项目,那默认配置够用;但只要你开始碰真实系统的凭据,这篇就值得你跟着做一遍。

2. 前置准备:TaoToken 接入与 Claude Code 环境确认

在动手改配置之前,先把接入层理清楚。Claude Code 本身是一个客户端工具,它需要连到模型服务才能工作。我这边用的是 TaoToken 提供的接入方式,官网入口是 https://taotoken.net/?utm_source=taotoken_aicg_blog_end&utm_medium=csdn&utm_campaign=rewrite&utm_content= ,API 地址是 https://taotoken.net/api 。如果你还没配好,先去控制台拿一个 API Key,地址在 https://taotoken.net/console?utm_source=taotoken_aicg_blog_end&utm_content=console&utm_campaign=rewrite ,Key 的管理页面在 https://taotoken.net/api-keys?utm_source=taotoken_aicg_blog_end&utm_content=api-keys&utm_campaign=rewrite 。

拿到 Key 之后,你需要确认 Claude Code 能正常跑起来。最直接的方式是设好环境变量,然后发一条最简单的请求。这里要注意,环境变量的设置方式取决于你的 shell,我用的是 zsh,所以写在~/.zshrc里;如果你用 bash,就写~/.bashrc。

# 设置 TaoToken 接入地址和 Key export ANTHROPIC_BASE_URL="https://taotoken.net/api" export ANTHROPIC_API_KEY="你的_TaoToken_API_Key" # 重新加载 shell 配置 source ~/.zshrc # 验证 Claude Code 能正常响应 claude -p "回复 ok 两个字母即可"

如果这条命令返回了ok,说明接入层没问题。接下来才是重点:确认 Claude Code 的本地数据目录结构。默认情况下,Claude Code 的数据放在~/.claude/下面,核心目录包括:

路径内容是否自动清理
~/.claude/projects/<project>/<session>.jsonl会话转录文件受 cleanupPeriodDays 控制
~/.claude/history.jsonlprompt 历史不自动清理
~/.claude/feedback-bundles/反馈包手动管理
~/.claude/settings.json全局配置不适用

你可以先看一眼当前目录里有什么:

# 查看 Claude Code 数据目录大小 du -sh ~/.claude/ # 列出 projects 下的会话文件 ls -lh ~/.claude/projects/ # 查看 history.jsonl 的行数 wc -l ~/.claude/history.jsonl

这一步的目的是建立基线。你得先知道现在有多少数据、放在哪里,后面配置改完才能对比验证。如果你看到projects/下面已经有一堆.jsonl文件,而且时间跨度很长,那说明默认的 30 天清理周期对你来说可能偏长。

3. 可复制配置:settings.json 骨架与两个关键参数

Claude Code 的配置分几个层级:全局的~/.claude/settings.json、项目级的.claude/settings.json、以及企业级的 managed settings。我们这里主要动全局配置,因为cleanupPeriodDays和权限规则这类东西,放在全局更省事。项目级配置适合放跟具体仓库相关的 deny 规则。

先给一个完整的settings.json骨架,你可以直接复制到~/.claude/settings.json:

{ "cleanupPeriodDays": 7, "permissions": { "deny": [ "Read(.env)", "Read(.env.*)", "Read(**/.env)", "Read(**/.env.*)", "Read(**/*.pem)", "Read(**/id_rsa)", "Read(**/id_ed25519)", "Read(**/.aws/credentials)", "Read(**/.config/gcloud/**)", "Read(**/credentials.json)", "Read(**/service-account*.json)", "Bash(cat .env*)", "Bash(printenv*)", "Bash(env)", "Bash(export *)" ], "ask": [ "Bash(curl *)", "Bash(wget *)" ] } }

这个骨架里,cleanupPeriodDays设成了 7。官方默认值是 30,最小值是 1,设成 0 会被校验拒绝。7 天对大多数项目是个折中:既保留了最近一周的调试复盘能力,又不至于让明文副本长期滞留。如果你的项目敏感度更高,可以降到 3 甚至 1。

permissions.deny这块是运行时约束,不是温柔提醒。官方文档明确说了,deny 规则优先于 ask 和 allow,而且 prompt 或 CLAUDE.md 里的自然语言要求并不能改变实际允许的工具访问。所以别指望写一句"请不要读取 .env"就完事,得用 deny 规则把敏感路径挡在工具层外。这里我同时限制了Read和Bash,因为 Claude Code 读文件不一定非要通过 shell,Read、Grep、Glob这些只读工具默认看起来低风险,但读取本身就可能造成二次记录。

然后是CLAUDE_CODE_SKIP_PROMPT_HISTORY。这个不是写在settings.json里的,而是环境变量。它的作用是在任何模式下跳过 transcript 和 prompt history 写入。设置方式:

# 在 shell 配置里加上这一行 export CLAUDE_CODE_SKIP_PROMPT_HISTORY=1 # 重新加载 source ~/.zshrc

如果你只在特定场景下想关闭持久化,可以写一个单独的 shell 函数或者 alias,比如:

# 定义一个"安全模式"启动函数 claude-secure() { CLAUDE_CODE_SKIP_PROMPT_HISTORY=1 claude "$@" }

这样你平时用claude保持默认体验,遇到敏感任务时用claude-secure,环境本身替你做安全分流,不需要每次靠记忆做选择。另外,非交互模式下还可以用--no-session-persistence,或者在 Agent SDK 里把persistSession设为false。CLI reference 里写得很清楚,--no-session-persistence会禁用 session persistence,使 session 不保存到磁盘,也不能 resume,而且只适用于 print mode。

这里有个取舍要提前说清楚:关闭持久化以后,Claude Code 的体验会变得更短期,不能依赖本地 transcript 恢复上下文,也少了历史召回的便利。对安全要求高的项目,这个代价可以接受;对日常开发项目,可以只在敏感任务中启用。

4. 验证请求:确认配置真的生效了

配置写完不代表生效,得验证。验证分两步:先确认cleanupPeriodDays起作用了,再确认CLAUDE_CODE_SKIP_PROMPT_HISTORY真的阻止了写入。

第一步,验证清理周期。先记录当前会话文件的数量和时间戳:

# 记录当前状态 ls -lh ~/.claude/projects/ | tee /tmp/claude_before.txt wc -l ~/.claude/history.jsonl

然后启动一次 Claude Code,随便问一个问题,让它产生一个新的会话文件:

claude -p "用一句话解释什么是 JSONL 格式"

退出后,再检查一次:

# 对比前后变化 ls -lh ~/.claude/projects/ | tee /tmp/claude_after.txt diff /tmp/claude_before.txt /tmp/claude_after.txt

你应该能看到新增了一个.jsonl文件。这个文件就是本次会话的转录。如果你把cleanupPeriodDays设成了 7,那么启动时 Claude Code 会清理超过 7 天的会话文件。你可以手动造一个旧文件来测试:

# 创建一个时间戳为 10 天前的测试文件 touch -d "10 days ago" ~/.claude/projects/test-project/old-session.jsonl # 启动 Claude Code,触发清理 claude -p "test" # 检查旧文件是否被删除 ls ~/.claude/projects/test-project/old-session.jsonl

如果返回"No such file or directory",说明清理逻辑生效了。

第二步,验证CLAUDE_CODE_SKIP_PROMPT_HISTORY。先记录当前history.jsonl的行数,然后用安全模式启动一次:

# 记录当前行数 BEFORE=$(wc -l < ~/.claude/history.jsonl) echo "Before: $BEFORE" # 用安全模式启动 CLAUDE_CODE_SKIP_PROMPT_HISTORY=1 claude -p "这条不应该被记录" # 再次检查行数 AFTER=$(wc -l < ~/.claude/history.jsonl) echo "After: $AFTER" # 如果 BEFORE 和 AFTER 相等,说明写入被跳过了

同时检查projects/目录下有没有新增文件:

# 查看最近 1 分钟内修改的文件 find ~/.claude/projects/ -mmin -1 -type f

如果没有任何输出,说明 transcript 写入也被跳过了。这两个验证动作做完,你就能确认配置真的在起作用,而不是"我以为它生效了"。

5. 本篇常见错排查

配置过程中最容易踩的坑,我整理了几个高频问题。

问题一:cleanupPeriodDays设成 0 被拒绝。官方校验规则是最小值为 1,设成 0 不会报错但会被忽略,实际行为可能回退到默认值。如果你想要"启动即清理",设成 1 就行,别设 0。

问题二:deny 规则写了但没生效。最常见的原因是路径匹配模式不对。Claude Code 的 permission 规则用的是 glob 风格,Read(.env)只匹配当前目录下的.env,不匹配子目录里的。要匹配所有层级的.env,得用Read(**/.env)。另外,deny 规则要放在permissions.deny数组里,不是permissions.allow。放错位置的话,规则会被当成允许项处理。

问题三:CLAUDE_CODE_SKIP_PROMPT_HISTORY设了但 history.jsonl 还在增长。先确认环境变量真的被加载了:

echo $CLAUDE_CODE_SKIP_PROMPT_HISTORY

如果输出为空,说明 shell 配置没生效,检查你是不是写在了正确的配置文件里,以及有没有source。另外要注意,这个变量只影响新的会话,已经写入的历史不会被删除。如果你想让已有的history.jsonl也清掉,得手动处理:

# 备份后清空 cp ~/.claude/history.jsonl ~/.claude/history.jsonl.bak > ~/.claude/history.jsonl

问题四:项目级配置覆盖了全局配置。Claude Code 的配置是分层合并的,项目级的.claude/settings.json会覆盖全局的同名配置项。如果你在全局设了cleanupPeriodDays: 7,但项目里设了cleanupPeriodDays: 30,那在这个项目里就是 30。排查的时候记得检查项目目录下有没有.claude/settings.json。

问题五:managed settings 的 deny 不能被本地覆盖。企业环境下,管理员可能通过 managed settings 下发了 deny 规则。这种情况下,你本地的allow规则是覆盖不了的。如果你发现某个路径明明没在本地 deny 里,但就是读不了,大概率是 managed settings 在起作用。这个不是 bug,是设计如此。

问题六:--no-session-persistence在交互模式下不生效。这个参数只适用于 print mode,也就是claude -p这种非交互调用。如果你在交互式会话里加这个参数,它会被忽略。交互模式下要用CLAUDE_CODE_SKIP_PROMPT_HISTORY。

6. 把明文存储纳入日常工程习惯

配置改完、验证通过之后,剩下的就是把它变成习惯。我的做法是把不同风险等级拆成不同的 shell 入口:普通开发终端用默认的claude,生产排障终端、客户环境终端固定用claude-secure。这样不需要每次靠记忆做选择,环境本身替我做安全分流。

另外,claude project purge这个命令值得记住。它可以删除某个 project 的 transcripts、auto memory、per-session tasks、debug、file history 条目,并过滤history.jsonl里的匹配 prompt lines。官方文档说它会展示 deletion plan,并支持 dry run。适合在项目交付、客户环境排障结束、临时敏感任务完成后使用。手动删目录当然也能做,但命令式清理更容易被写进团队 runbook,也更容易在离职交接、设备回收、项目归档时执行。

如果你想把安全配置和 repository 模板绑在一起,可以在项目模板里放基础 permissions,禁止读取.env、.pem、私钥和 credential 目录。企业项目模板里额外降低cleanupPeriodDays,为 shell 命令加审计前缀或 hooks。官方 permissions 文档提到,permission rules 可以 check into version control 并分发给组织开发者,managed settings 里的 deny 也不能被本地 allow 覆盖。这对企业很重要,因为安全不应该完全依赖个人习惯。

最后说一个心智模型上的转变。Claude Code 不是一个只会回答问题的聊天框,它更像一个坐在开发机旁边的自动化同事,会读文件、会运行命令、会保存工作记录、会在下次接着干。这样的系统必须有记忆,但记忆不能不设边界。cleanupPeriodDays管保留多久,CLAUDE_CODE_SKIP_PROMPT_HISTORY和--no-session-persistence管要不要落盘,permission deny rules 管哪些东西根本不许读,sandbox 管 shell 能走到哪里,secret rotation 管事故后的止血。这几件事合在一起,才是 Claude Code 明文存储的正确打开方式。

如果你还没配好接入层,先去 https://taotoken.net/api-keys?utm_source=taotoken_aicg_blog_end&utm_content=api-keys&utm_campaign=rewrite 拿个 Key,接入文档在 https://taotoken.net/doc?utm_source=taotoken_aicg_blog_end&utm_content=doc&utm_campaign=rewrite 。想先试试模型对话效果的,可以直接用 https://taotoken.net/chat?utm_source=taotoken_aicg_blog_end&utm_content=model-chat&utm_campaign=rewrite 。长期跑编码任务或者 Agent 的,Coding Plan 在 https://taotoken.net/coding-plan?utm_source=taotoken_aicg_blog_end&utm_content=coding-plan&utm_campaign=rewrite 。把配置做扎实,比事后补救省心得多。

需要专业的网站建设服务?

联系我们获取免费的网站建设咨询和方案报价,让我们帮助您实现业务目标

立即咨询