agent-history-hygiene
Compare original and translation side by side
🇺🇸
Original
English🇨🇳
Translation
Chineseagent-history-hygiene
Agent历史记录规范
Keep agent chat transcripts and plan files committed together with the
code they produced, without leaking secrets. Pairs with the
+ pre-commit hooks the skill installs.
redact-agent-secretsgitleaksSurfaces, separated by purpose:
| Surface | Question it answers |
|---|---|
| "Which transcript / plan file is my current session?" |
| "Which agent files belong in the next commit?" |
| "Which harness/model + artifact trailers belong in it?" |
| "How do I get pre-commit + gitleaks + redactor into a repo?" |
| "Is there a leaked secret in what I'm about to commit?" |
| "What does SpecStory already redact, so we don't redo it?" |
| "I already pushed a secret — now what?" |
将Agent聊天记录和计划文件与它们生成的代码一同提交,且不会泄露秘密。与该技能安装的 + pre-commit钩子配合使用。
redact-agent-secretsgitleaks按用途划分的工具:
| 工具 | 解决的问题 |
|---|---|
| “哪份对话记录/计划文件属于我当前的会话?” |
| “哪些Agent文件应纳入下一次提交?” |
| “提交中应包含哪些工具链/模型 + 记录尾注?” |
| “如何在仓库中配置pre-commit + gitleaks + 脱敏工具?” |
| “我即将提交的内容中是否存在泄露的秘密?” |
| “SpecStory已自动脱敏哪些内容,避免重复处理?” |
| “我已经推送了秘密——现在该怎么办?” |
Core invariants
核心原则
- Agent transcripts and plan files are committed alongside the diff
that produced them. Never add them to . An agent that drops these from a commit has broken the user's review trail.
.gitignore - SpecStory state is not review history. Precisely ignore
(machine/path-derived identity) and
.specstory/.project.json(regenerable statistics), but never ignore.specstory/statistics.jsonor.specstory/as a whole..specstory/history/ - Rotate at the provider before any git rewrite. The only act that revokes a leaked credential is rotation. History rewriting scrubs bytes on one clone and leaves them on every other.
- against a shared branch is never the fix for a leak. At best it's useless; at worst it destroys teammate work and silently re-introduces the secret when someone merges their old history back.
git push --force - Provenance is derived from the staged snapshot. Never point a commit trailer at an unstaged transcript/plan, and never guess an unknown model.
- Nothing this skill ships may trip a downstream scanner. installs this whole directory —
npx skills addandtests/included — into the consumer's repo underfixtures/, inside their own scan scope..agents/skills/honours no allowlist marker, so a literaldetect-private-keyhere fails their commit with nothing they can edit to stop it. Build key headers at runtime (BEGIN … PRIVATE KEYinpem_header()) or use atests/conftest.pyplaceholder; never answer this with a wider__SYNTHETIC_PEM_*__. Enforced byexclude:.tests/test_shipped_file_hygiene.py
- Agent对话记录和计划文件需与生成的代码差异一同提交。切勿将它们加入。若Agent在提交中遗漏这些文件,会破坏用户的审查追踪链。
.gitignore - SpecStory状态不属于审查历史。明确忽略(基于机器/路径的标识)和
.specstory/.project.json(可重新生成的统计数据),但绝不能整体忽略.specstory/statistics.json或.specstory/目录。.specstory/history/ - 在执行任何Git重写前,先在服务商处轮换凭证。唯一能撤销泄露凭证的操作是轮换。历史重写仅能清除单个克隆中的数据,而其他所有克隆仍会保留这些数据。
- 针对共享分支执行绝非泄露问题的解决方案。最好的情况是毫无用处;最坏的情况是破坏队友的工作,且当有人合并旧历史时会重新引入秘密。
git push --force - 来源信息需从暂存快照中提取。绝不能将提交尾注指向未暂存的对话记录/计划,也绝不能猜测未知模型。
- 该技能交付的任何内容都不能触发下游扫描器告警。会将整个目录(包括
npx skills add和tests/)安装到消费者仓库的fixtures/下,处于扫描范围内。.agents/skills/不认可任何白名单标记,因此此处若存在字面意义上的detect-private-key,会导致用户提交失败且无法通过编辑解决。需在运行时构建密钥头(如BEGIN … PRIVATE KEY中的tests/conftest.py)或使用pem_header()占位符;绝不能通过扩大__SYNTHETIC_PEM_*__范围解决该问题。此规则由exclude:强制执行。tests/test_shipped_file_hygiene.py
When to use this skill
适用场景
Use it when the user (or you) surface any of:
- "Commit my chat" / "save the specstory session" / "include the plan file in this commit" / "把 plan 跟 specstory 一起 commit 進去".
- You see dirty ,
.specstory/history/*.md,.claude/plans/*.md, or any other configured agent artifact during.cursor/plans/*.mdand you're about to commit a feature.git status - You see recurring or
.specstory/.project.jsonchurn, especially across machines..specstory/statistics.json - "Scrub this transcript" / "redact my key" / "gitleaks flagged my chat history".
- "Set up pre-commit for this repo" / "I'm starting a new project — how do I get the hook stack?" / "bootstrap secret scanning here".
- "I pushed a " / "a secret went to main" / "do I need to force push?" — the agent must steer to
.envand stop the user from force-pushing reflexively.references/remediation.md
当用户(或你)遇到以下情况时使用:
- “提交我的聊天记录” / “保存SpecStory会话” / “将plan与specstory一同提交” / “把 plan 跟 specstory 一起 commit 進去”。
- 在中看到未提交的
git status、.specstory/history/*.md、.claude/plans/*.md或任何其他已配置的Agent文件,且你即将提交一项功能。.cursor/plans/*.md - 看到或
.specstory/.project.json频繁变更,尤其是跨机器使用时。.specstory/statistics.json - “清理这份对话记录” / “脱敏我的密钥” / “gitleaks标记了我的聊天记录”。
- “为该仓库配置pre-commit” / “我正在启动新项目——如何搭建钩子栈?” / “在此处初始化秘密扫描”。
- “我推送了文件” / “秘密被推送到main分支” / “我需要强制推送吗?”——Agent必须引导用户查看
.env,阻止用户本能地执行强制推送。references/remediation.md
When NOT to use
不适用场景
- The user explicitly wants agent transcripts excluded from the
repo. Respect that; suggest a one-liner addition and skip this skill entirely.
.gitignore - The leak is already on a shared /release branch. Do not offer to rewrite history — jump to
main§5.references/remediation.md - The project genuinely has no agent session (no , no
.specstory/, etc.). Nothing to stage..claude/plans/ - Single-file, single-commit hygiene that the agent handles without any script (e.g., adding a missing trailing newline).
- 用户明确要求将Agent对话记录排除在仓库之外。需尊重此需求;建议添加一行规则并完全跳过该技能。
.gitignore - 秘密已泄露到共享的/发布分支。切勿提议重写历史——直接跳转至
main第5节。references/remediation.md - 项目确实没有Agent会话(无、
.specstory/等目录)。无需暂存任何内容。.claude/plans/ - Agent无需脚本即可处理的单文件、单提交规范(例如添加缺失的换行符)。
Integration with existing infrastructure
与现有基础设施的集成
This skill sits on top of any chezmoi-managed stack the user
already has. It does not duplicate:
- chezmoi's global (
core.hooksPath) — that wrapper runs the repo's~/.config/git/hooks/pre-commitand then optionally.pre-commit-config.yaml. The skill bootstraps the repo-level config the wrapper expects to find.gitleaks git --staged - chezmoi's — the user's config already carries curated rules for common API keys (OpenAI, Anthropic, Supabase, Linear, WakaTime, Cursor, HuggingFace, Notion, Tailscale, Clash / V2Ray tokens). The skill's
.gitleaks.tomlships the same rule IDs soassets/gitleaks.toml.template/ allowlist tweaks stay portable..gitleaksignore - the pinned hook — the redactor ships as a pinned pre-commit hook from this repo (
redact-agent-secrets), so every consuming repo gets fixes via.pre-commit-hooks.yamlinstead of a vendored copy that drifts. Details inpre-commit autoupdate.references/pre-commit-redaction-stack.md
What this skill adds:
- Agent-facing discipline (this +
SKILL.md).references/remediation.md - A single-command project bootstrap () for repos without chezmoi or where the user wants the stack in one go.
bootstrap-project.sh - Exact checkout/session discovery () with an explicit
find-session.shcompatibility escape hatch for the "find my transcript among many" problem.--newest - An exit-code wrapper () agents can branch on before committing.
scan-staged.sh
该技能基于用户已有的任何chezmoi管理栈构建,不会重复实现以下内容:
- chezmoi的全局(
core.hooksPath)——该包装器会执行仓库的~/.config/git/hooks/pre-commit,然后可选地运行.pre-commit-config.yaml。该技能会初始化包装器期望找到的仓库级配置。gitleaks git --staged - chezmoi的——用户的配置已包含针对常见API密钥(OpenAI、Anthropic、Supabase、Linear、WakaTime、Cursor、HuggingFace、Notion、Tailscale、Clash / V2Ray令牌)的精选规则。该技能的
.gitleaks.toml使用相同的规则ID,因此assets/gitleaks.toml.template/白名单调整可在不同仓库间移植。.gitleaksignore - 固定版本的钩子——脱敏工具作为固定版本的pre-commit钩子从本仓库(
redact-agent-secrets)发布,因此所有使用该技能的仓库可通过.pre-commit-hooks.yaml获取修复,而非使用会逐渐过时的本地副本。详情见pre-commit autoupdate。references/pre-commit-redaction-stack.md
该技能新增的功能:
- Agent端规范(本+
SKILL.md)。references/remediation.md - 单命令项目初始化(),适用于无chezmoi的仓库或希望一次性搭建完整栈的用户。
bootstrap-project.sh - 精确的检出/会话发现(),带有明确的
find-session.sh兼容选项,解决“在众多记录中找到我的对话记录”的问题。--newest - Agent可在提交前根据退出码分支处理的包装器()。
scan-staged.sh
Workflow A: commit-time hygiene
工作流A:提交时规范管理
Default flow when the agent is about to commit feature changes plus
chat/plan artifacts.
bash
undefinedAgent即将提交功能变更及聊天/计划文件时的默认流程。
bash
undefined1. Take the UUID from Claude Code /status. If SpecStory produced more than
1. 从Claude Code /status获取UUID。若SpecStory为其生成多个别名,同时指定渲染路径。
one alias for it, name the rendered path too.
—
SESSION_ID=01234567-89ab-4cde-8fab-0123456789ab
TRANSCRIPT='.specstory/history/2026-08-28_08-00-00Z.md'
PLAN='.claude/plans/exact-agent-history-selectors.md'
bash skills/local/agent-history-hygiene/scripts/find-session.sh
--session-id "$SESSION_ID" --specstory-path "$TRANSCRIPT"
--session-id "$SESSION_ID" --specstory-path "$TRANSCRIPT"
SESSION_ID=01234567-89ab-4cde-8fab-0123456789ab
TRANSCRIPT='.specstory/history/2026-08-28_08-00-00Z.md'
PLAN='.claude/plans/exact-agent-history-selectors.md'
bash skills/local/agent-history-hygiene/scripts/find-session.sh
--session-id "$SESSION_ID" --specstory-path "$TRANSCRIPT"
--session-id "$SESSION_ID" --specstory-path "$TRANSCRIPT"
2. Stage code, then exactly one validated transcript/plan set.
2. 暂存代码,然后精确暂存一组已验证的对话记录/计划文件。
git add path/to/feature/file.ts
bash skills/local/agent-history-hygiene/scripts/stage-agent-artifacts.sh
--session-only --session-id "$SESSION_ID"
--specstory-path "$TRANSCRIPT" --plan "$PLAN"
--session-only --session-id "$SESSION_ID"
--specstory-path "$TRANSCRIPT" --plan "$PLAN"
git add path/to/feature/file.ts
bash skills/local/agent-history-hygiene/scripts/stage-agent-artifacts.sh
--session-only --session-id "$SESSION_ID"
--specstory-path "$TRANSCRIPT" --plan "$PLAN"
--session-only --session-id "$SESSION_ID"
--specstory-path "$TRANSCRIPT" --plan "$PLAN"
Use --no-plan when no plan exists. Use --no-specstory with --session-id when
当无计划文件时使用--no-plan。当有意不生成渲染历史时,使用--no-specstory搭配--session-id。脚本绝不会自动选择计划文件。
rendered history is intentionally absent. The script never chooses a plan.
3. 从暂存文件生成标准的最终提交尾注块。
3. Generate the canonical FINAL trailer block from staged artifacts.
—
bash skills/local/agent-history-hygiene/scripts/agent-commit-metadata.sh
bash skills/local/agent-history-hygiene/scripts/agent-commit-metadata.sh
4. Belt-and-suspenders secret scan before commit. Exit 0 = clean.
4. 提交前再次执行秘密扫描。退出码0表示无问题。
bash skills/local/agent-history-hygiene/scripts/scan-staged.sh || {
Exit 10/20: leaks found. Jump to references/remediation.md.
echo "Leaks detected — see references/remediation.md before committing." >&2
exit 1
}
bash skills/local/agent-history-hygiene/scripts/scan-staged.sh || {
退出码10/20:发现泄露。跳转至references/remediation.md。
echo "Leaks detected — see references/remediation.md before committing." >&2
exit 1
}
5. Append that block after any native attribution, validate with the
5. 将该块追加到任何原生归属信息之后,使用git-workflow配套工具验证,然后提交。pre-commit会重新执行脱敏/gitleaks扫描。
git-workflow companion, then commit. pre-commit re-runs redaction/gitleaks.
—
bash skills/local/git-workflow/scripts/check-commit-msg.sh
--agentic --staged --file /path/to/commit-message.txt git commit -F /path/to/commit-message.txt
--agentic --staged --file /path/to/commit-message.txt git commit -F /path/to/commit-message.txt
The no-selector invocation remains **broad branch-wide compatibility mode**.
It classifies one NUL porcelain snapshot (including deletion/rename pairs) under
`assets/artifact-dirs.txt`; use it only when that broad set is intentional.bash skills/local/git-workflow/scripts/check-commit-msg.sh
--agentic --staged --file /path/to/commit-message.txt git commit -F /path/to/commit-message.txt
--agentic --staged --file /path/to/commit-message.txt git commit -F /path/to/commit-message.txt
无选择器调用为**宽泛的分支兼容模式**。它会将一个NUL格式的快照(包括删除/重命名对)归类到`assets/artifact-dirs.txt`下;仅当有意使用该宽泛集合时才使用此模式。Workflow B: bootstrap a new project
工作流B:新项目初始化
For repos that don't yet have /
installed. Runs once per repo.
.pre-commit-config.yaml.gitleaks.tomlbash
cd /path/to/new/project
bash skills/local/agent-history-hygiene/scripts/bootstrap-project.sh \
--install-hook # optional: validation-only exact commit gate适用于尚未安装 / 的仓库。每个仓库仅需运行一次。
.pre-commit-config.yaml.gitleaks.tomlbash
cd /path/to/new/project
bash skills/local/agent-history-hygiene/scripts/bootstrap-project.sh \
--install-hook # 可选:仅验证的精确提交网关Verify: shake out any existing issues in the working tree.
验证:检查工作树中是否存在现有问题。
pre-commit run --all-files
What `bootstrap-project.sh` does:
1. Drops `.pre-commit-config.yaml` + `.gitleaks.toml` into the repo
(skips if already present unless `--force`). The redactor is a pinned
remote hook (`repo: …/agent-skills`, `rev: ahh-v1.1.0`), **not** a
vendored `scripts/redact_secrets.py` — so `pre-commit autoupdate`
keeps it current everywhere.
2. Creates or merges `.specstory/.gitignore` with only these anchored rules:
```gitignore
/.project.json
/statistics.jsonThis keeps machine-local identity and generated statistics out of Git
without hiding . If either state file is already
tracked, bootstrap warns because ignore rules do not affect tracked files;
re-run with to apply while
keeping the local files on disk. Use to preview it.
3. Runs (or if
pre-commit isn't on ).
4. Audits / for patterns that would
silently hide an agent artifact dir — warns without editing.
5. Checks for ; prints the
one-line patch if missing.
6. With : writes a validation-only gate.
Explicit selectors call against the exact
commit ; missing feature/artifact diffs abort with the exact
staging command, while missing identity visibly no-ops. It never mutates an
index, so / exclusions fail without loops. Automatic
install requires genuinely unset—even empty or relative
is refused because linked worktrees break it.
.specstory/history/--untrack-specstory-stategit rm --cached--dry-runpre-commit installuvx pre-commit@4 installPATH.gitignore.git/info/exclude~/.claude/settings.jsonplansDirectory--install-hookprepare-commit-msgAGENT_HISTORY_*--check-stagedGIT_INDEX_FILEcommit -a--onlycore.hooksPath.git/hooksMigrating a repo off the old vendored layout (a committed
+ a redact hook):
scripts/redact_secrets.py- repo: localbash
bash skills/local/agent-history-hygiene/scripts/bootstrap-project.sh --migrateremoves the vendored script and rewrites the local hook into the pinned
remote hook, leaving your other hooks and untouched
(idempotent; safe to re-run).
.gitleaks.tomlpre-commit run --all-files
`bootstrap-project.sh`的执行步骤:
1. 将`.pre-commit-config.yaml` + `.gitleaks.toml`放入仓库(若已存在则跳过,除非使用`--force`)。脱敏工具是固定版本的远程钩子(`repo: …/agent-skills`, `rev: ahh-v1.1.0`),**而非**本地副本`scripts/redact_secrets.py`——因此`pre-commit autoupdate`可在所有仓库中保持其最新状态。
2. 创建或合并`.specstory/.gitignore`,仅包含以下锚定规则:
```gitignore
/.project.json
/statistics.json这会将机器本地标识和生成的统计数据排除在Git之外,但不会隐藏。若任一状态文件已被跟踪,初始化过程会发出警告,因为忽略规则不会影响已跟踪文件;可添加参数重新运行,执行以保留本地文件但从Git中移除。使用可预览该操作。
3. 运行(若pre-commit不在中,则运行)。
4. 检查 / 中是否存在会隐藏Agent文件目录的规则——仅发出警告而不编辑。
5. 检查中是否存在;若缺失则打印单行补丁。
6. 使用:写入仅验证的精确提交网关。明确的选择器会针对精确提交的调用;若缺失功能/文件差异则会中止并给出精确的暂存命令,若缺失标识则会明显无操作。它绝不会修改索引,因此/排除操作会失败且不会进入循环。自动安装要求确实未设置——即使是空值或相对路径也会被拒绝,因为链接工作树会导致其失效。
.specstory/history/--untrack-specstory-stategit rm --cached--dry-runpre-commit installPATHuvx pre-commit@4 install.gitignore.git/info/exclude~/.claude/settings.jsonplansDirectory--install-hookAGENT_HISTORY_*GIT_INDEX_FILE--check-stagedcommit -a--onlycore.hooksPath.git/hooks将仓库从旧的本地布局(已提交的 + 脱敏钩子)迁移:
scripts/redact_secrets.py- repo: localbash
bash skills/local/agent-history-hygiene/scripts/bootstrap-project.sh --migrate该命令会移除本地脚本并将本地钩子重写为固定版本的远程钩子,保留其他钩子和不变(幂等操作;可安全重复运行)。
.gitleaks.tomlWorkflow C: post-leak remediation
工作流C:泄露后补救
When reports exit /, or the user says "I
committed / pushed a secret":
scan-staged.sh1020- STOP the user from running reflexively.
git push --force - Read end-to-end.
references/remediation.md - Walk the user through step 1 (rotate) regardless of blast radius. Only after rotation does the question of scrubbing history become worth discussing.
- Use the decision tree in the runbook to pick the right git action.
当返回退出码/,或用户表示“我提交/推送了秘密”时:
scan-staged.sh1020- 阻止用户本能地运行。
git push --force - 完整阅读。
references/remediation.md - 无论影响范围大小,引导用户完成步骤1(轮换凭证)。只有在轮换后,才值得讨论清理历史的问题。
- 使用手册中的决策树选择合适的Git操作。
Gotchas
注意事项
- does not retroactively untrack files. SpecStory's own nested ignore historically covered
.gitignorebut not the later-added.project.json, and either file may already be committed. Adding the two precise rules stops new files only. Run bootstrap withstatistics.jsonto stage their removal from Git while preserving both local files. Never compensate with--untrack-specstory-stateor.specstory/in an ignore file; that discards the review trail..specstory/history/ - SpecStory >= 2.4.0 already redacts on write — plan around it, not
against it. Since
PR #235 shipped in
v2.4.0 (2026-07-20), the CLI redacts secrets via the
Betterleaks ruleset by
default, covering both local markdown and cloud sync, writing
. Measured coverage is 36 of 54 class/context pairs; 15 are ours alone (every webhook rule, plus every custom key in prose context — betterleaks catches many classes only in
[REDACTED:<rule-id>]form via its entropy-basedKEY=valuerule). So: keep this layer, but never rewrite what SpecStory already cleaned.generic-api-keywrites the sameredact_secrets.pysentinel and[REDACTED:<rule-id>]allowlists it, so a cleaned transcript is left untouched and pre-commit stops demanding a re-.gitleaks.toml. Full matrix + knobs ingit add. Onlyreferences/specstory-native-redaction.mdis configurable upstream — the PR's[redaction] enableddid not survive the Betterleaks rewrite, so repo-specific rules stay our job. For SpecStory older than 2.4.0 (or with redaction disabled), runextra_patterns.redact_secrets.py --fix --legacy - Scope formatters and linters past the artifact dirs, not just
scanners. Since ruff 0.16, formats Python inside Markdown code blocks, so it rewrites committed transcripts — falsifying the record, and churning forever against SpecStory rewriting the same file. Installed skills under
ruff formatare vendored code and equally out of scope. Exclude.agents/skills/,.agents,.claude,.codex,.cursor,.opencode,.specify;.specstorymatters separately from.claudebecause.agentssymlinks into it, so an.claude/skills/<name>-only exclude still reaches the same files. The template already excludes.agentsfrom^\.specstory/+end-of-file-fixerfor the same reason — this is that rule applied to tools the template does not install.trailing-whitespace - project-level sometimes ignored. Claude Code issue #19537 reports project-level
plansDirectorybeing ignored in some versions. After running aplansDirectory, verify the file actually landed where you expected before relying on/planpicking it up. User-level config (stage-agent-artifacts.shwith~/.claude/settings.json) is the recommended default."plansDirectory": "./.claude/plans" - is deprecated. Since v8.19.0 use
gitleaks protect(pre-commit) andgitleaks git --staged --redact(working directory). The older commands still work but emit a deprecation notice. This skill uses the modern syntax everywhere.gitleaks dir <path> - is per-clone. Each teammate must run
pre-commit installin their own clone for hooks to fire. CI cannot be trusted as the single gate — it's second-chance, not last-chance.pre-commit install - Transcript files can be huge. A long SpecStory session can exceed
2 MB. The template bumps to
check-added-large-filesto avoid false positives, but a very long session can still overflow. If you hit the limit, rotate sessions (--maxkb=2048creates a fresh file) instead of raising the cap further.specstory run claude - SpecStory 2.10 is checkout-path scoped, not branch scoped. Both rendered
output discovery and raw Claude session discovery follow the checkout path;
switching branches in one checkout does not separate histories. Create the
worktree first, then start one SpecStory wrapper/session per change stream.
Use for an explicit raw session. One UUID can produce multiple rendered aliases, so
specstory sync claude -s UUIDfails ambiguous untilfind-session.sh --session-id UUIDselects one.--specstory-pathdoes not rebind a SpecStory watcher that was already running; restart the wrapper in the target worktree.EnterWorktree - Global means bare repos aren't protected. The chezmoi setup's global hook runs
core.hooksPathIF it exists — so a repo without.pre-commit-config.yamlhas no protection. Run.pre-commit-config.yamlbefore the first commit with agent artifacts, not after.bootstrap-project.sh - requires an unset
--install-hook. Empty, relativecore.hooksPath, and external/global values all exit 6 before writes. Relative.git/hooksappears to work in a primary checkout but fails in linked worktrees where.git/hooksis a file. Integrate the validation-only gate manually into a configured hook directory or unset the key; bootstrap never edits it..git - Active SpecStory writer can defeat the redact loop. The standard
flow assumes the file is quiescent during the commit. SpecStory's
git add → git commit → pre-commit auto-fixes → re-stage → re-commitdaemon tails the agent transcript continuously, so if the chat capturedspecstory_*_watch-style output that contained an unrelated daemon's secret in argv (e.g. SpecStory's ownps -axo argsflag), every diagnostic command (--cloud-token …,grep,sed -n '<line>p') prints the secret again, SpecStory appends it to the transcript, and the redact-then-restage cycle never converges. Symptom: pre-commit says "Successfully redacted N file(s)" butcat | head | tailimmediately fails on the same line, re-runninggitleaks-systemdoesn't help, andgit add && git commitshows the count increasing over commit attempts. Workaround: a single atomicgrep -c '<secret-prefix>' filepipeline so the index is frozen before any new specstory write lands. Don't print, grep, or diff the secret line during the recovery — every print echoes back into the transcript. Diagnose withpython3 -c "<in-place re.sub>" && git add <file> && git commit -m "..."(looking forlsof <file>writers) instead. Seespecstory_*in upstream chezmoi for the full debugging trail. Fixed sub-case: the bare-phrase variant of this loop — where the redactor's ownpitfalls/redact-secrets-loop-with-active-specstory-writer.mdsubstring match kept flagging prose that merely discusses private keys (this skill's docs, or a chat about redaction) with no real secret present — no longer happens.PRIVATE KEYnow scopes to key headers (theredact_secrets.pyBLACKLIST), so prose mentions are ignored and converge immediately. The atomic-commit workaround above is still needed for the harder case: a real secret an active writer keeps re-appending. When only the substring redactor (detect-private-key) trips whileredact-agent-secrets+gitleakspass, it's the false positive — verify withdetect-private-keyand, if clean, commit withgitleaks git --staged(keeps the real gates active).SKIP=redact-agent-secrets
- 不会追溯取消跟踪文件。SpecStory自身的嵌套忽略规则历史上覆盖了
.gitignore但未覆盖后来添加的.project.json,且任一文件可能已被提交。添加这两条精确规则仅能阻止新文件被跟踪。可使用statistics.json参数运行初始化脚本,将这些文件从Git中移除但保留本地文件。绝不能通过在忽略文件中添加--untrack-specstory-state或.specstory/来补偿;这会丢弃审查追踪链。.specstory/history/ - SpecStory >= 2.4.0已在写入时自动脱敏——需适配而非抵触。自2026年7月20日v2.4.0版本发布的PR #235以来,CLI默认通过Betterleaks规则集脱敏秘密,覆盖本地Markdown和云同步,写入。实测覆盖54个类别/上下文对中的36个;其中15个为我们独有(所有Webhook规则,以及散文上下文中的所有自定义密钥——Betterleaks仅能通过基于熵的
[REDACTED:<rule-id>]规则在generic-api-key格式中捕获许多类别)。因此:保留该层,但绝不要重写SpecStory已清理的内容。KEY=value会写入与SpecStory原生相同的redact_secrets.py标记,且[REDACTED:<rule-id>]会将其加入白名单,因此已清理的对话记录不会被修改,pre-commit也不会要求重新执行.gitleaks.toml。完整矩阵和配置项见git add。仅references/specstory-native-redaction.md可在上游配置——PR中的[redaction] enabled未在Betterleaks重写后保留,因此仓库特定规则由我们负责。对于SpecStory 2.4.0之前的版本(或已禁用脱敏),运行extra_patterns。redact_secrets.py --fix --legacy - 格式化工具和代码检查工具的范围需排除Agent文件目录,而非仅扫描器。自ruff 0.16版本起,会格式化Markdown代码块中的Python代码,因此会修改已提交的对话记录——篡改记录,并因SpecStory重写同一文件而导致频繁变更。
ruff format下的已安装技能是本地代码,同样不在范围内。需排除.agents/skills/、.agents、.claude、.codex、.cursor、.opencode、.specify;.specstory需单独排除,因为.claude会链接到该目录,因此仅排除.claude/skills/<name>仍会覆盖相同文件。模板已将.agents从^\.specstory/+end-of-file-fixer中排除,原因相同——此规则适用于模板未安装的工具。trailing-whitespace - 项目级配置有时会被忽略。Claude Code的#19537问题报告称,部分版本中项目级
plansDirectory会被忽略。运行plansDirectory后,需先验证文件是否确实保存在预期位置,再依赖/plan找到它。推荐使用用户级配置(stage-agent-artifacts.sh中设置~/.claude/settings.json)作为默认值。"plansDirectory": "./.claude/plans" - 已被弃用。自v8.19.0版本起,使用
gitleaks protect(pre-commit)和gitleaks git --staged --redact(工作目录)。旧命令仍可运行但会发出弃用通知。该技能在所有地方均使用现代语法。gitleaks dir <path> - 是每个克隆独立的。每个队友必须在自己的克隆中运行
pre-commit install才能触发钩子。不能仅依赖CI作为唯一网关——它是第二道防线,而非最后一道。pre-commit install - 对话记录文件可能非常大。长SpecStory会话可能超过2 MB。模板已将的阈值调整为
check-added-large-files以避免误报,但极长会话仍可能超出限制。若遇到此限制,应轮换会话(--maxkb=2048会创建新文件)而非进一步提高阈值。specstory run claude - SpecStory 2.10基于检出路径而非分支。渲染输出发现和原始Claude会话发现均遵循检出路径;在一个检出中切换分支不会分离历史。应先创建工作树,然后为每个变更流启动一个SpecStory包装器/会话。使用获取明确的原始会话。一个UUID可能生成多个渲染别名,因此
specstory sync claude -s UUID在使用find-session.sh --session-id UUID选择一个别名前会因歧义而失败。--specstory-path不会重新绑定已运行的SpecStory监视器;需在目标工作树中重启包装器。EnterWorktree - 全局意味着裸仓库不受保护。chezmoi设置的全局钩子会在存在
core.hooksPath时运行它——因此无.pre-commit-config.yaml的仓库不受保护。应在首次提交Agent文件前运行.pre-commit-config.yaml,而非之后。bootstrap-project.sh - 要求
--install-hook未设置。空值、相对路径core.hooksPath和外部/全局值均会在写入前返回退出码6。相对路径.git/hooks在主检出中似乎可行,但在.git/hooks为文件的链接工作树中会失败。需手动将仅验证的网关集成到已配置的钩子目录中,或取消设置该键;初始化脚本绝不会修改它。.git - 活跃的SpecStory写入器可能打破脱敏循环。标准的流程假设文件在提交期间处于静止状态。SpecStory的
git add → git commit → pre-commit自动修复 → 重新暂存 → 重新提交守护进程会持续跟踪Agent对话记录,因此若聊天捕获到specstory_*_watch风格的输出,其中包含无关守护进程的秘密(例如SpecStory自身的ps -axo args标志),则每个诊断命令(--cloud-token …、grep、sed -n '<line>p')都会再次打印该秘密,SpecStory会将其追加到对话记录中,脱敏后重新暂存的循环永远不会收敛。症状:pre-commit显示“Successfully redacted N file(s)”但cat | head | tail立即在同一行失败,重新运行gitleaks-system无济于事,且git add && git commit显示计数随提交尝试增加。解决方法:使用单个原子的grep -c '<secret-prefix>' file管道,以便在任何新的SpecStory写入完成前冻结索引。切勿在恢复期间打印、搜索或对比秘密行——每次打印都会回写到对话记录中。应使用python3 -c "<in-place re.sub>" && git add <file> && git commit -m "..."(查找lsof <file>写入器)进行诊断。上游chezmoi的specstory_*中有完整的调试流程。 已修复的子情况:该循环的纯短语变体——脱敏工具自身的pitfalls/redact-secrets-loop-with-active-specstory-writer.md子字符串匹配会标记仅讨论私钥的散文(本技能文档或关于脱敏的聊天),而无真实秘密存在——现已不再发生。PRIVATE KEY现在仅针对密钥头(redact_secrets.py黑名单),因此散文提及会被忽略并立即收敛。上述原子提交解决方法仍适用于更复杂的情况:活跃写入器持续重新追加真实秘密。当仅detect-private-key触发告警而redact-agent-secrets+gitleaks通过时,即为误报——使用detect-private-key验证,若无误则使用gitleaks git --staged提交(保持真实网关活跃)。SKIP=redact-agent-secrets
Available scripts
可用脚本
-
Validate the byte-bounded real SpecStory prologue and exact lowercase UUID; search Claude stores and prove canonical worktree roots from strict JSONL. Unsafe/invalid explicit selectors are never reflected. TSV/JSON require
scripts/find-session.sh (--session-id UUID | --specstory-path PATH | --newest) [--format specstory|claude|both] [--json];iconvis conditional on Claude JSONL validation. Missing dependencies return status/exit 6;python3is the only heuristic path.--newest -
scripts/stage-agent-artifacts.sh [--session-only --check-staged --session-id UUID|--specstory-path PATH (--plan PATH|--no-plan)] [--no-specstory] [--dry-run] [--allow-empty]validates the current commit index without mutation. Staging mode requires staged non-artifact code and rejects ignored/unaddable/unmerged artifacts, and hold the real worktree index lock while one add runs against an alternate index that is atomically published on success. Failures leave the real index unchanged. Broad mode uses one paired-record porcelain snapshot; configured artifact dirs (trailing slash normalized) are the exact-plan source of truth.--check-staged -
Read staged SpecStory/plan artifacts and emit deduplicated
scripts/agent-commit-metadata.sh [--harness NAME --model NAME] [--format trailers|json],AI-Assisted-By, andAgent-Transcriptvalues. Parses the staged blob rather than a concurrently-changing working-tree transcript; requires explicit harness+model overrides when it cannot prove them.Agent-Plan -
Run
scripts/scan-staged.sh [--redact] [--verbose]with agent-friendly exit codes (0 clean / 10 redacted / 20 leaks / 30 gitleaks missing). JSON lines on stdout, prose diagnostics on stderr.gitleaks git --staged -
Measure which secret classes SpecStory's native redaction covers, by synthesizing a Claude Code session and rendering it twice (with and without
scripts/probe-specstory-redaction.py [--json] [--keep] [--dry-run]). Prints a coverage matrix and the residual set our layer must still handle. Exit 30 when specstory isn't installed.--no-redact-secrets -
Install
scripts/bootstrap-project.sh [--from-chezmoi] [--migrate] [--install-hook] [--untrack-specstory-state] [--force] [--dry-run]+.pre-commit-config.yamlinto the current repo, merge precise SpecStory state ignores, wire the hook to the installed skill's redactor, then run.gitleaks.toml. Auditspre-commit installand.gitignorefor misconfigurations without hiding transcript directories. Already-tracked state is only untracked with the explicit flag;~/.claude/settings.jsonpreviews that index change.--dry-rungenerates the validation-only exact gate with a visible identity-absent no-op. It exits 6 whenever--install-hookis configured; manual integration is required for global/custom hook directories.core.hooksPath
-
验证字节边界的真实SpecStory序言和精确小写UUID;搜索Claude存储并通过严格JSONL验证规范工作树根。绝不会使用不安全/无效的显式选择器。TSV/JSON格式需要
scripts/find-session.sh (--session-id UUID | --specstory-path PATH | --newest) [--format specstory|claude|both] [--json];iconv仅在Claude JSONL验证时需要。缺失依赖会返回状态/退出码6;python3是唯一的启发式路径。--newest -
scripts/stage-agent-artifacts.sh [--session-only --check-staged --session-id UUID|--specstory-path PATH (--plan PATH|--no-plan)] [--no-specstory] [--dry-run] [--allow-empty]会验证当前提交索引而不修改。暂存模式要求暂存非Agent代码,并拒绝被忽略/无法添加/未合并的文件,且在对备用索引执行添加操作时锁定真实工作树索引,成功后原子发布。失败时真实索引保持不变。宽泛模式使用一对记录的快照;已配置的Agent文件目录(标准化为尾部斜杠)是精确计划的数据源。--check-staged -
读取暂存的SpecStory/计划文件并输出去重的
scripts/agent-commit-metadata.sh [--harness NAME --model NAME] [--format trailers|json]、AI-Assisted-By和Agent-Transcript值。解析暂存的 blob 而非并发变化的工作树对话记录;当无法验证工具链+模型时,需要显式覆盖。Agent-Plan -
使用Agent友好的退出码运行
scripts/scan-staged.sh [--redact] [--verbose](0=无问题 / 10=已脱敏 / 20=存在泄露 / 30=gitleaks缺失)。标准输出为JSON行,标准错误输出为散文诊断信息。gitleaks git --staged -
通过合成Claude Code会话并渲染两次(启用和禁用
scripts/probe-specstory-redaction.py [--json] [--keep] [--dry-run]),测量SpecStory原生脱敏覆盖的秘密类别。打印覆盖矩阵和我们的层仍需处理的剩余集合。当未安装specstory时返回退出码30。--no-redact-secrets -
将
scripts/bootstrap-project.sh [--from-chezmoi] [--migrate] [--install-hook] [--untrack-specstory-state] [--force] [--dry-run]+.pre-commit-config.yaml安装到当前仓库,合并精确的SpecStory状态忽略规则,将钩子连接到已安装技能的脱敏工具,然后运行.gitleaks.toml。检查pre-commit install和.gitignore中的配置错误,但不会隐藏对话记录目录。仅当使用显式标志时,才会取消跟踪已跟踪的状态;~/.claude/settings.json可预览该索引变更。--dry-run会生成仅验证的精确网关,当缺失标识时会明显无操作。当--install-hook已配置时返回退出码6;对于全局/自定义钩子目录,需手动集成。core.hooksPath
Bundled assets
捆绑资源
- — the canonical list of agent artifact directories (SpecStory, Claude plans, Cursor plans + rules, OpenCode plans, Spec-kit, Codex). Consumed by
assets/artifact-dirs.txtand bystage-agent-artifacts.shwhen rendering the pre-commitbootstrap-project.shregex.files: - — minimal
assets/pre-commit-config.yaml.templatewith.pre-commit-config.yaml+ gitleaks + standard hygiene hooks.redact-agent-secrets - — portable subset of the chezmoi
assets/gitleaks.toml.templatewith custom rule IDs + a path-scoped allowlist for agent artifact dirs..gitleaks.toml - — the redactor, published to consuming repos as the pinned
assets/redact_secrets.pypre-commit hook (rootredact-agent-secrets). Writes.pre-commit-hooks.yaml, the sentinel SpecStory also writes natively;[REDACTED:<rule-id>]writes the pre-2.4.0 placeholders instead. Release procedure in--legacy.references/pre-commit-redaction-stack.md
- — Agent文件目录的规范列表(SpecStory、Claude计划、Cursor计划+规则、OpenCode计划、Spec-kit、Codex)。被
assets/artifact-dirs.txt和stage-agent-artifacts.sh在渲染pre-commit的bootstrap-project.sh正则表达式时使用。files: - — 包含
assets/pre-commit-config.yaml.template+ gitleaks + 标准规范钩子的最小redact-agent-secrets。.pre-commit-config.yaml - — chezmoi的
assets/gitleaks.toml.template的可移植子集,包含自定义规则ID + Agent文件目录的路径范围白名单。.gitleaks.toml - — 脱敏工具,作为固定版本的
assets/redact_secrets.pypre-commit钩子(根目录的redact-agent-secrets)发布到使用该技能的仓库。写入.pre-commit-hooks.yaml,与SpecStory原生写入的标记相同;[REDACTED:<rule-id>]会写入2.4.0之前的占位符。发布流程见--legacy。references/pre-commit-redaction-stack.md
Reference files
参考文件
- — SpecStory / Claude session layouts and the
references/transcript-session-discovery.mdalgorithm. Read when$PWD → slugreturns empty or ambiguous results.find-session.sh - — three-layer defense (redact → gitleaks →
references/pre-commit-redaction-stack.md), allowlist design, sync procedure for the bundled redactor. Read when tuning rules or debugging unexpected pre-commit failures.scan-staged.sh - — what SpecStory >= 2.4.0 redacts on its own, measured per secret class and per context, plus the upstream PRs, config knobs, and why our layer is still load-bearing. Read before changing anything about redaction placeholders.
references/specstory-native-redaction.md - — rotate-first runbook for "I committed / pushed a secret". Read before any
references/remediation.md/git filter-repoaction.git push --force
- — SpecStory / Claude会话布局和
references/transcript-session-discovery.md算法。当$PWD → slug返回空或歧义结果时阅读。find-session.sh - — 三层防御(脱敏 → gitleaks →
references/pre-commit-redaction-stack.md)、白名单设计、捆绑脱敏工具的同步流程。当调整规则或调试意外pre-commit失败时阅读。scan-staged.sh - — SpecStory >= 2.4.0自行脱敏的内容,按秘密类别和上下文测量,包括上游PR、配置项,以及为何我们的层仍必不可少。在修改脱敏占位符前阅读。
references/specstory-native-redaction.md - — “我提交/推送了秘密”的先轮换手册。在执行任何
references/remediation.md/git filter-repo操作前务必阅读。git push --force
Tests
测试
The skill ships with a test suite under
. Run from repo root:
tests/bash
make test-skill- — pytest for pure redactor functions.
test_redact_secrets.py - — golden-corpus fixtures staged in tmp git repos, asserting real-key shapes fire and example shapes are allowlisted only inside configured artifact dirs.
test_gitleaks_corpus.py - — exit-code contract for
test_scan_staged.sh(0 / 20 / 30 / 2).scripts/scan-staged.sh - — real prologue/JSONL/path safety, dependency output, large-tail bounds, same-checkout leakage, aliases, and worktree roots.
test_find_session.sh - — exact/broad status parsing, conflicts, ignored/custom paths, index-lock races, trailers, and temporary-index commits.
test_stage_agent_artifacts.sh - — exact SpecStory state ignores, idempotency, dry-run, history visibility, and opt-in untracking behavior.
test_bootstrap_project.py - — locks in that SpecStory still redacts by default and still writes
test_specstory_coverage.py; skips without the CLI.[REDACTED:<label>] - — staged transcript/model parsing, model deduplication, path handling, JSON output, and explicit-override failures.
test_agent_commit_metadata.sh - — no shipped file carries a
test_shipped_file_hygiene.pyBLACKLIST substring, and the redactor scrubs all ten of them convergently. Runs everywhere; needs no external binary.detect-private-key
The corpus + shell tests skip gracefully when isn't on
. See for what each
regression the suite locks in.
gitleaksPATHtests/README.md该技能附带下的测试套件。从仓库根目录运行:
tests/bash
make test-skill- — 纯脱敏函数的pytest测试。
test_redact_secrets.py - — 在临时Git仓库中暂存黄金语料库测试用例,验证真实密钥格式会触发告警,示例格式仅在已配置的Agent文件目录中被白名单放行。
test_gitleaks_corpus.py - —
test_scan_staged.sh的退出码契约测试(0 / 20 / 30 / 2)。scripts/scan-staged.sh - — 真实序言/JSONL/路径安全性、依赖输出、大尾部边界、同一检出泄露、别名和工作树根测试。
test_find_session.sh - — 精确/宽泛状态解析、冲突、忽略/自定义路径、索引锁竞争、尾注和临时索引提交测试。
test_stage_agent_artifacts.sh - — 精确SpecStory状态忽略、幂等性、试运行、历史可见性和可选取消跟踪行为测试。
test_bootstrap_project.py - — 锁定SpecStory仍默认脱敏且仍写入
test_specstory_coverage.py的行为;未安装CLI时跳过。[REDACTED:<label>] - — 暂存对话记录/模型解析、模型去重、路径处理、JSON输出和显式覆盖失败测试。
test_agent_commit_metadata.sh - — 交付的文件均不包含
test_shipped_file_hygiene.py黑名单子字符串,且脱敏工具会收敛清理所有十个此类字符串。可在任何环境运行;无需外部二进制文件。detect-private-key
当不在中时,语料库+ shell测试会优雅跳过。详见中每个测试锁定的回归问题。
gitleaksPATHtests/README.mdRelated skills
相关技能
-
— defines and validates the English Conventional Commit + canonical provenance contract emitted here.
git-workflow -
— complementary memory harness (TODO.md + backlog/ + pitfalls/) that references
project-knowledge-harnessas "ephemeral agent scratchpads". This skill fills the gap: those scratchpads belong in git, not ignored..claude/plans/
-
— 定义并验证此处生成的英文约定式提交 + 规范来源契约。
git-workflow -
— 互补的内存管理工具(TODO.md + backlog/ + pitfalls/),将
project-knowledge-harness称为“临时Agent草稿本”。该技能填补了空白:这些草稿本应纳入Git,而非被忽略。.claude/plans/