agent-history-hygiene

Compare original and translation side by side

🇺🇸

Original

English
🇨🇳

Translation

Chinese

agent-history-hygiene

Agent历史记录规范

Keep agent chat transcripts and plan files committed together with the code they produced, without leaking secrets. Pairs with the
redact-agent-secrets
+
gitleaks
pre-commit hooks the skill installs.
Surfaces, separated by purpose:
SurfaceQuestion it answers
find-session.sh
"Which transcript / plan file is my current session?"
stage-agent-artifacts.sh
"Which agent files belong in the next commit?"
agent-commit-metadata.sh
"Which harness/model + artifact trailers belong in it?"
bootstrap-project.sh
"How do I get pre-commit + gitleaks + redactor into a repo?"
scan-staged.sh
"Is there a leaked secret in what I'm about to commit?"
probe-specstory-redaction.py
"What does SpecStory already redact, so we don't redo it?"
references/remediation.md
"I already pushed a secret — now what?"
将Agent聊天记录和计划文件与它们生成的代码一同提交,且不会泄露秘密。与该技能安装的
redact-agent-secrets
+
gitleaks
pre-commit钩子配合使用。
按用途划分的工具:
工具解决的问题
find-session.sh
“哪份对话记录/计划文件属于我当前的会话?”
stage-agent-artifacts.sh
“哪些Agent文件应纳入下一次提交?”
agent-commit-metadata.sh
“提交中应包含哪些工具链/模型 + 记录尾注?”
bootstrap-project.sh
“如何在仓库中配置pre-commit + gitleaks + 脱敏工具?”
scan-staged.sh
“我即将提交的内容中是否存在泄露的秘密?”
probe-specstory-redaction.py
“SpecStory已自动脱敏哪些内容,避免重复处理?”
references/remediation.md
“我已经推送了秘密——现在该怎么办?”

Core invariants

核心原则

  1. Agent transcripts and plan files are committed alongside the diff that produced them. Never add them to
    .gitignore
    . An agent that drops these from a commit has broken the user's review trail.
  2. SpecStory state is not review history. Precisely ignore
    .specstory/.project.json
    (machine/path-derived identity) and
    .specstory/statistics.json
    (regenerable statistics), but never ignore
    .specstory/
    or
    .specstory/history/
    as a whole.
  3. 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.
  4. git push --force
    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.
  5. Provenance is derived from the staged snapshot. Never point a commit trailer at an unstaged transcript/plan, and never guess an unknown model.
  6. Nothing this skill ships may trip a downstream scanner.
    npx skills add
    installs this whole directory —
    tests/
    and
    fixtures/
    included — into the consumer's repo under
    .agents/skills/
    , inside their own scan scope.
    detect-private-key
    honours no allowlist marker, so a literal
    BEGIN … PRIVATE KEY
    here fails their commit with nothing they can edit to stop it. Build key headers at runtime (
    pem_header()
    in
    tests/conftest.py
    ) or use a
    __SYNTHETIC_PEM_*__
    placeholder; never answer this with a wider
    exclude:
    . Enforced by
    tests/test_shipped_file_hygiene.py
    .
  1. Agent对话记录和计划文件需与生成的代码差异一同提交。切勿将它们加入
    .gitignore
    。若Agent在提交中遗漏这些文件,会破坏用户的审查追踪链。
  2. SpecStory状态不属于审查历史。明确忽略
    .specstory/.project.json
    (基于机器/路径的标识)和
    .specstory/statistics.json
    (可重新生成的统计数据),但绝不能整体忽略
    .specstory/
    .specstory/history/
    目录。
  3. 在执行任何Git重写前,先在服务商处轮换凭证。唯一能撤销泄露凭证的操作是轮换。历史重写仅能清除单个克隆中的数据,而其他所有克隆仍会保留这些数据。
  4. 针对共享分支执行
    git push --force
    绝非泄露问题的解决方案
    。最好的情况是毫无用处;最坏的情况是破坏队友的工作,且当有人合并旧历史时会重新引入秘密。
  5. 来源信息需从暂存快照中提取。绝不能将提交尾注指向未暂存的对话记录/计划,也绝不能猜测未知模型。
  6. 该技能交付的任何内容都不能触发下游扫描器告警
    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
    ,
    .cursor/plans/*.md
    , or any other configured agent artifact during
    git status
    and you're about to commit a feature.
  • You see recurring
    .specstory/.project.json
    or
    .specstory/statistics.json
    churn, especially across machines.
  • "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
    .env
    " / "a secret went to main" / "do I need to force push?" — the agent must steer to
    references/remediation.md
    and stop the user from force-pushing reflexively.
当用户(或你)遇到以下情况时使用:
  • “提交我的聊天记录” / “保存SpecStory会话” / “将plan与specstory一同提交” / “把 plan 跟 specstory 一起 commit 進去”。
  • git status
    中看到未提交的
    .specstory/history/*.md
    .claude/plans/*.md
    .cursor/plans/*.md
    或任何其他已配置的Agent文件,且你即将提交一项功能。
  • 看到
    .specstory/.project.json
    .specstory/statistics.json
    频繁变更,尤其是跨机器使用时。
  • “清理这份对话记录” / “脱敏我的密钥” / “gitleaks标记了我的聊天记录”。
  • “为该仓库配置pre-commit” / “我正在启动新项目——如何搭建钩子栈?” / “在此处初始化秘密扫描”。
  • “我推送了
    .env
    文件” / “秘密被推送到main分支” / “我需要强制推送吗?”——Agent必须引导用户查看
    references/remediation.md
    ,阻止用户本能地执行强制推送。

When NOT to use

不适用场景

  • The user explicitly wants agent transcripts excluded from the repo. Respect that; suggest a one-liner
    .gitignore
    addition and skip this skill entirely.
  • The leak is already on a shared
    main
    /release branch. Do not offer to rewrite history — jump to
    references/remediation.md
    §5.
  • The project genuinely has no agent session (no
    .specstory/
    , no
    .claude/plans/
    , etc.). Nothing to stage.
  • Single-file, single-commit hygiene that the agent handles without any script (e.g., adding a missing trailing newline).
  • 用户明确要求将Agent对话记录排除在仓库之外。需尊重此需求;建议添加一行
    .gitignore
    规则并完全跳过该技能。
  • 秘密已泄露到共享的
    main
    /发布分支。切勿提议重写历史——直接跳转至
    references/remediation.md
    第5节。
  • 项目确实没有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
    (
    ~/.config/git/hooks/pre-commit
    ) — that wrapper runs the repo's
    .pre-commit-config.yaml
    and then optionally
    gitleaks git --staged
    . The skill bootstraps the repo-level config the wrapper expects to find.
  • chezmoi's
    .gitleaks.toml
    — 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
    assets/gitleaks.toml.template
    ships the same rule IDs so
    .gitleaksignore
    / allowlist tweaks stay portable.
  • the pinned
    redact-agent-secrets
    hook
    — the redactor ships as a pinned pre-commit hook from this repo (
    .pre-commit-hooks.yaml
    ), so every consuming repo gets fixes via
    pre-commit autoupdate
    instead of a vendored copy that drifts. Details in
    references/pre-commit-redaction-stack.md
    .
What this skill adds:
  • Agent-facing discipline (this
    SKILL.md
    +
    references/remediation.md
    ).
  • A single-command project bootstrap (
    bootstrap-project.sh
    ) for repos without chezmoi or where the user wants the stack in one go.
  • Exact checkout/session discovery (
    find-session.sh
    ) with an explicit
    --newest
    compatibility escape hatch for the "find my transcript among many" problem.
  • An exit-code wrapper (
    scan-staged.sh
    ) agents can branch on before committing.
该技能基于用户已有的任何chezmoi管理栈构建,不会重复实现以下内容:
  • chezmoi的全局
    core.hooksPath
    ~/.config/git/hooks/pre-commit
    )——该包装器会执行仓库的
    .pre-commit-config.yaml
    ,然后可选地运行
    gitleaks git --staged
    。该技能会初始化包装器期望找到的仓库级配置。
  • chezmoi的
    .gitleaks.toml
    ——用户的配置已包含针对常见API密钥(OpenAI、Anthropic、Supabase、Linear、WakaTime、Cursor、HuggingFace、Notion、Tailscale、Clash / V2Ray令牌)的精选规则。该技能的
    assets/gitleaks.toml.template
    使用相同的规则ID,因此
    .gitleaksignore
    /白名单调整可在不同仓库间移植。
  • 固定版本的
    redact-agent-secrets
    钩子
    ——脱敏工具作为固定版本的pre-commit钩子从本仓库(
    .pre-commit-hooks.yaml
    )发布,因此所有使用该技能的仓库可通过
    pre-commit autoupdate
    获取修复,而非使用会逐渐过时的本地副本。详情见
    references/pre-commit-redaction-stack.md
该技能新增的功能:
  • Agent端规范(本
    SKILL.md
    +
    references/remediation.md
    )。
  • 单命令项目初始化(
    bootstrap-project.sh
    ),适用于无chezmoi的仓库或希望一次性搭建完整栈的用户。
  • 精确的检出/会话发现(
    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
undefined
Agent即将提交功能变更及聊天/计划文件时的默认流程。
bash
undefined

1. 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=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"

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"
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"

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

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

无选择器调用为**宽泛的分支兼容模式**。它会将一个NUL格式的快照(包括删除/重命名对)归类到`assets/artifact-dirs.txt`下;仅当有意使用该宽泛集合时才使用此模式。

Workflow B: bootstrap a new project

工作流B:新项目初始化

For repos that don't yet have
.pre-commit-config.yaml
/
.gitleaks.toml
installed. Runs once per repo.
bash
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.toml
的仓库。每个仓库仅需运行一次。
bash
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.json
This keeps machine-local identity and generated statistics out of Git without hiding
.specstory/history/
. If either state file is already tracked, bootstrap warns because ignore rules do not affect tracked files; re-run with
--untrack-specstory-state
to apply
git rm --cached
while keeping the local files on disk. Use
--dry-run
to preview it. 3. Runs
pre-commit install
(or
uvx pre-commit@4 install
if pre-commit isn't on
PATH
). 4. Audits
.gitignore
/
.git/info/exclude
for patterns that would silently hide an agent artifact dir — warns without editing. 5. Checks
~/.claude/settings.json
for
plansDirectory
; prints the one-line patch if missing. 6. With
--install-hook
: writes a validation-only
prepare-commit-msg
gate. Explicit
AGENT_HISTORY_*
selectors call
--check-staged
against the exact commit
GIT_INDEX_FILE
; missing feature/artifact diffs abort with the exact staging command, while missing identity visibly no-ops. It never mutates an index, so
commit -a
/
--only
exclusions fail without loops. Automatic install requires
core.hooksPath
genuinely unset—even empty or relative
.git/hooks
is refused because linked worktrees break it.
Migrating a repo off the old vendored layout (a committed
scripts/redact_secrets.py
+ a
- repo: local
redact hook):
bash
bash skills/local/agent-history-hygiene/scripts/bootstrap-project.sh --migrate
removes the vendored script and rewrites the local hook into the pinned remote hook, leaving your other hooks and
.gitleaks.toml
untouched (idempotent; safe to re-run).
pre-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之外,但不会隐藏
.specstory/history/
。若任一状态文件已被跟踪,初始化过程会发出警告,因为忽略规则不会影响已跟踪文件;可添加
--untrack-specstory-state
参数重新运行,执行
git rm --cached
以保留本地文件但从Git中移除。使用
--dry-run
可预览该操作。 3. 运行
pre-commit install
(若pre-commit不在
PATH
中,则运行
uvx pre-commit@4 install
)。 4. 检查
.gitignore
/
.git/info/exclude
中是否存在会隐藏Agent文件目录的规则——仅发出警告而不编辑。 5. 检查
~/.claude/settings.json
中是否存在
plansDirectory
;若缺失则打印单行补丁。 6. 使用
--install-hook
:写入仅验证的精确提交网关。明确的
AGENT_HISTORY_*
选择器会针对精确提交的
GIT_INDEX_FILE
调用
--check-staged
;若缺失功能/文件差异则会中止并给出精确的暂存命令,若缺失标识则会明显无操作。它绝不会修改索引,因此
commit -a
/
--only
排除操作会失败且不会进入循环。自动安装要求
core.hooksPath
确实未设置——即使是空值或相对路径
.git/hooks
也会被拒绝,因为链接工作树会导致其失效。
将仓库从旧的本地布局(已提交的
scripts/redact_secrets.py
+
- repo: local
脱敏钩子)迁移:
bash
bash skills/local/agent-history-hygiene/scripts/bootstrap-project.sh --migrate
该命令会移除本地脚本并将本地钩子重写为固定版本的远程钩子,保留其他钩子和
.gitleaks.toml
不变(幂等操作;可安全重复运行)。

Workflow C: post-leak remediation

工作流C:泄露后补救

When
scan-staged.sh
reports exit
10
/
20
, or the user says "I committed / pushed a secret":
  1. STOP the user from running
    git push --force
    reflexively.
  2. Read
    references/remediation.md
    end-to-end.
  3. Walk the user through step 1 (rotate) regardless of blast radius. Only after rotation does the question of scrubbing history become worth discussing.
  4. Use the decision tree in the runbook to pick the right git action.
scan-staged.sh
返回退出码
10
/
20
,或用户表示“我提交/推送了秘密”时:
  1. 阻止用户本能地运行
    git push --force
  2. 完整阅读
    references/remediation.md
  3. 无论影响范围大小,引导用户完成步骤1(轮换凭证)。只有在轮换后,才值得讨论清理历史的问题。
  4. 使用手册中的决策树选择合适的Git操作。

Gotchas

注意事项

  • .gitignore
    does not retroactively untrack files.
    SpecStory's own nested ignore historically covered
    .project.json
    but not the later-added
    statistics.json
    , and either file may already be committed. Adding the two precise rules stops new files only. Run bootstrap with
    --untrack-specstory-state
    to stage their removal from Git while preserving both local files. Never compensate with
    .specstory/
    or
    .specstory/history/
    in an ignore file; that discards the review trail.
  • 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
    [REDACTED:<rule-id>]
    . 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
    KEY=value
    form via its entropy-based
    generic-api-key
    rule). So: keep this layer, but never rewrite what SpecStory already cleaned.
    redact_secrets.py
    writes the same
    [REDACTED:<rule-id>]
    sentinel and
    .gitleaks.toml
    allowlists it, so a cleaned transcript is left untouched and pre-commit stops demanding a re-
    git add
    . Full matrix + knobs in
    references/specstory-native-redaction.md
    . Only
    [redaction] enabled
    is configurable upstream — the PR's
    extra_patterns
    did not survive the Betterleaks rewrite, so repo-specific rules stay our job. For SpecStory older than 2.4.0 (or with redaction disabled), run
    redact_secrets.py --fix --legacy
    .
  • Scope formatters and linters past the artifact dirs, not just scanners. Since ruff 0.16,
    ruff format
    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
    .agents/skills/
    are vendored code and equally out of scope. Exclude
    .agents
    ,
    .claude
    ,
    .codex
    ,
    .cursor
    ,
    .opencode
    ,
    .specify
    ,
    .specstory
    ;
    .claude
    matters separately from
    .agents
    because
    .claude/skills/<name>
    symlinks into it, so an
    .agents
    -only exclude still reaches the same files. The template already excludes
    ^\.specstory/
    from
    end-of-file-fixer
    +
    trailing-whitespace
    for the same reason — this is that rule applied to tools the template does not install.
  • plansDirectory
    project-level sometimes ignored.
    Claude Code issue #19537 reports project-level
    plansDirectory
    being ignored in some versions. After running a
    /plan
    , verify the file actually landed where you expected before relying on
    stage-agent-artifacts.sh
    picking it up. User-level config (
    ~/.claude/settings.json
    with
    "plansDirectory": "./.claude/plans"
    ) is the recommended default.
  • gitleaks protect
    is deprecated.
    Since v8.19.0 use
    gitleaks git --staged --redact
    (pre-commit) and
    gitleaks dir <path>
    (working directory). The older commands still work but emit a deprecation notice. This skill uses the modern syntax everywhere.
  • pre-commit install
    is per-clone.
    Each teammate must run
    pre-commit install
    in their own clone for hooks to fire. CI cannot be trusted as the single gate — it's second-chance, not last-chance.
  • Transcript files can be huge. A long SpecStory session can exceed 2 MB. The template bumps
    check-added-large-files
    to
    --maxkb=2048
    to avoid false positives, but a very long session can still overflow. If you hit the limit, rotate sessions (
    specstory run claude
    creates a fresh file) instead of raising the cap further.
  • 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
    specstory sync claude -s UUID
    for an explicit raw session. One UUID can produce multiple rendered aliases, so
    find-session.sh --session-id UUID
    fails ambiguous until
    --specstory-path
    selects one.
    EnterWorktree
    does not rebind a SpecStory watcher that was already running; restart the wrapper in the target worktree.
  • Global
    core.hooksPath
    means bare repos aren't protected.
    The chezmoi setup's global hook runs
    .pre-commit-config.yaml
    IF it exists — so a repo without
    .pre-commit-config.yaml
    has no protection. Run
    bootstrap-project.sh
    before the first commit with agent artifacts, not after.
  • --install-hook
    requires an unset
    core.hooksPath
    .
    Empty, relative
    .git/hooks
    , and external/global values all exit 6 before writes. Relative
    .git/hooks
    appears to work in a primary checkout but fails in linked worktrees where
    .git
    is a file. Integrate the validation-only gate manually into a configured hook directory or unset the key; bootstrap never edits it.
  • Active SpecStory writer can defeat the redact loop. The standard
    git add → git commit → pre-commit auto-fixes → re-stage → re-commit
    flow assumes the file is quiescent during the commit. SpecStory's
    specstory_*_watch
    daemon tails the agent transcript continuously, so if the chat captured
    ps -axo args
    -style output that contained an unrelated daemon's secret in argv (e.g. SpecStory's own
    --cloud-token …
    flag), every diagnostic command (
    grep
    ,
    sed -n '<line>p'
    ,
    cat | head | tail
    ) 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)" but
    gitleaks-system
    immediately fails on the same line, re-running
    git add && git commit
    doesn't help, and
    grep -c '<secret-prefix>' file
    shows the count increasing over commit attempts. Workaround: a single atomic
    python3 -c "<in-place re.sub>" && git add <file> && git commit -m "..."
    pipeline 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 with
    lsof <file>
    (looking for
    specstory_*
    writers) instead. See
    pitfalls/redact-secrets-loop-with-active-specstory-writer.md
    in upstream chezmoi for the full debugging trail. Fixed sub-case: the bare-phrase variant of this loop — where the redactor's own
    PRIVATE KEY
    substring 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.
    redact_secrets.py
    now scopes to key headers (the
    detect-private-key
    BLACKLIST), 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 (
    redact-agent-secrets
    ) trips while
    gitleaks
    +
    detect-private-key
    pass, it's the false positive — verify with
    gitleaks git --staged
    and, if clean, commit with
    SKIP=redact-agent-secrets
    (keeps the real gates active).
  • .gitignore
    不会追溯取消跟踪文件
    。SpecStory自身的嵌套忽略规则历史上覆盖了
    .project.json
    但未覆盖后来添加的
    statistics.json
    ,且任一文件可能已被提交。添加这两条精确规则仅能阻止新文件被跟踪。可使用
    --untrack-specstory-state
    参数运行初始化脚本,将这些文件从Git中移除但保留本地文件。绝不能通过在忽略文件中添加
    .specstory/
    .specstory/history/
    来补偿;这会丢弃审查追踪链。
  • SpecStory >= 2.4.0已在写入时自动脱敏——需适配而非抵触。自2026年7月20日v2.4.0版本发布的PR #235以来,CLI默认通过Betterleaks规则集脱敏秘密,覆盖本地Markdown和云同步,写入
    [REDACTED:<rule-id>]
    。实测覆盖54个类别/上下文对中的36个;其中15个为我们独有(所有Webhook规则,以及散文上下文中的所有自定义密钥——Betterleaks仅能通过基于熵的
    generic-api-key
    规则在
    KEY=value
    格式中捕获许多类别)。因此:保留该层,但绝不要重写SpecStory已清理的内容
    redact_secrets.py
    会写入与SpecStory原生相同的
    [REDACTED:<rule-id>]
    标记,且
    .gitleaks.toml
    会将其加入白名单,因此已清理的对话记录不会被修改,pre-commit也不会要求重新执行
    git add
    。完整矩阵和配置项见
    references/specstory-native-redaction.md
    。仅
    [redaction] enabled
    可在上游配置——PR中的
    extra_patterns
    未在Betterleaks重写后保留,因此仓库特定规则由我们负责。对于SpecStory 2.4.0之前的版本(或已禁用脱敏),运行
    redact_secrets.py --fix --legacy
  • 格式化工具和代码检查工具的范围需排除Agent文件目录,而非仅扫描器。自ruff 0.16版本起,
    ruff format
    会格式化Markdown代码块中的Python代码,因此会修改已提交的对话记录——篡改记录,并因SpecStory重写同一文件而导致频繁变更。
    .agents/skills/
    下的已安装技能是本地代码,同样不在范围内。需排除
    .agents
    .claude
    .codex
    .cursor
    .opencode
    .specify
    .specstory
    .claude
    需单独排除,因为
    .claude/skills/<name>
    会链接到该目录,因此仅排除
    .agents
    仍会覆盖相同文件。模板已将
    ^\.specstory/
    end-of-file-fixer
    +
    trailing-whitespace
    中排除,原因相同——此规则适用于模板未安装的工具。
  • plansDirectory
    项目级配置有时会被忽略
    。Claude Code的#19537问题报告称,部分版本中项目级
    plansDirectory
    会被忽略。运行
    /plan
    后,需先验证文件是否确实保存在预期位置,再依赖
    stage-agent-artifacts.sh
    找到它。推荐使用用户级配置(
    ~/.claude/settings.json
    中设置
    "plansDirectory": "./.claude/plans"
    )作为默认值。
  • gitleaks protect
    已被弃用
    。自v8.19.0版本起,使用
    gitleaks git --staged --redact
    (pre-commit)和
    gitleaks dir <path>
    (工作目录)。旧命令仍可运行但会发出弃用通知。该技能在所有地方均使用现代语法。
  • pre-commit install
    是每个克隆独立的
    。每个队友必须在自己的克隆中运行
    pre-commit install
    才能触发钩子。不能仅依赖CI作为唯一网关——它是第二道防线,而非最后一道。
  • 对话记录文件可能非常大。长SpecStory会话可能超过2 MB。模板已将
    check-added-large-files
    的阈值调整为
    --maxkb=2048
    以避免误报,但极长会话仍可能超出限制。若遇到此限制,应轮换会话(
    specstory run claude
    会创建新文件)而非进一步提高阈值。
  • SpecStory 2.10基于检出路径而非分支。渲染输出发现和原始Claude会话发现均遵循检出路径;在一个检出中切换分支不会分离历史。应先创建工作树,然后为每个变更流启动一个SpecStory包装器/会话。使用
    specstory sync claude -s UUID
    获取明确的原始会话。一个UUID可能生成多个渲染别名,因此
    find-session.sh --session-id UUID
    在使用
    --specstory-path
    选择一个别名前会因歧义而失败。
    EnterWorktree
    不会重新绑定已运行的SpecStory监视器;需在目标工作树中重启包装器。
  • 全局
    core.hooksPath
    意味着裸仓库不受保护
    。chezmoi设置的全局钩子会在存在
    .pre-commit-config.yaml
    时运行它——因此无
    .pre-commit-config.yaml
    的仓库不受保护。应在首次提交Agent文件前运行
    bootstrap-project.sh
    ,而非之后。
  • --install-hook
    要求
    core.hooksPath
    未设置
    。空值、相对路径
    .git/hooks
    和外部/全局值均会在写入前返回退出码6。相对路径
    .git/hooks
    在主检出中似乎可行,但在
    .git
    为文件的链接工作树中会失败。需手动将仅验证的网关集成到已配置的钩子目录中,或取消设置该键;初始化脚本绝不会修改它。
  • 活跃的SpecStory写入器可能打破脱敏循环。标准的
    git add → git commit → pre-commit自动修复 → 重新暂存 → 重新提交
    流程假设文件在提交期间处于静止状态。SpecStory的
    specstory_*_watch
    守护进程会持续跟踪Agent对话记录,因此若聊天捕获到
    ps -axo args
    风格的输出,其中包含无关守护进程的秘密(例如SpecStory自身的
    --cloud-token …
    标志),则每个诊断命令(
    grep
    sed -n '<line>p'
    cat | head | tail
    )都会再次打印该秘密,SpecStory会将其追加到对话记录中,脱敏后重新暂存的循环永远不会收敛。症状:pre-commit显示“Successfully redacted N file(s)”但
    gitleaks-system
    立即在同一行失败,重新运行
    git add && git commit
    无济于事,且
    grep -c '<secret-prefix>' file
    显示计数随提交尝试增加。解决方法:使用单个原子的
    python3 -c "<in-place re.sub>" && git add <file> && git commit -m "..."
    管道,以便在任何新的SpecStory写入完成前冻结索引。切勿在恢复期间打印、搜索或对比秘密行——每次打印都会回写到对话记录中。应使用
    lsof <file>
    (查找
    specstory_*
    写入器)进行诊断。上游chezmoi的
    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

可用脚本

  • scripts/find-session.sh (--session-id UUID | --specstory-path PATH | --newest) [--format specstory|claude|both] [--json]
    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
    iconv
    ;
    python3
    is conditional on Claude JSONL validation. Missing dependencies return status/exit 6;
    --newest
    is the only heuristic path.
  • 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]
    --check-staged
    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.
  • scripts/agent-commit-metadata.sh [--harness NAME --model NAME] [--format trailers|json]
    Read staged SpecStory/plan artifacts and emit deduplicated
    AI-Assisted-By
    ,
    Agent-Transcript
    , and
    Agent-Plan
    values. Parses the staged blob rather than a concurrently-changing working-tree transcript; requires explicit harness+model overrides when it cannot prove them.
  • scripts/scan-staged.sh [--redact] [--verbose]
    Run
    gitleaks git --staged
    with agent-friendly exit codes (0 clean / 10 redacted / 20 leaks / 30 gitleaks missing). JSON lines on stdout, prose diagnostics on stderr.
  • scripts/probe-specstory-redaction.py [--json] [--keep] [--dry-run]
    Measure which secret classes SpecStory's native redaction covers, by synthesizing a Claude Code session and rendering it twice (with and without
    --no-redact-secrets
    ). Prints a coverage matrix and the residual set our layer must still handle. Exit 30 when specstory isn't installed.
  • scripts/bootstrap-project.sh [--from-chezmoi] [--migrate] [--install-hook] [--untrack-specstory-state] [--force] [--dry-run]
    Install
    .pre-commit-config.yaml
    +
    .gitleaks.toml
    into the current repo, merge precise SpecStory state ignores, wire the hook to the installed skill's redactor, then run
    pre-commit install
    . Audits
    .gitignore
    and
    ~/.claude/settings.json
    for misconfigurations without hiding transcript directories. Already-tracked state is only untracked with the explicit flag;
    --dry-run
    previews that index change.
    --install-hook
    generates the validation-only exact gate with a visible identity-absent no-op. It exits 6 whenever
    core.hooksPath
    is configured; manual integration is required for global/custom hook directories.
  • scripts/find-session.sh (--session-id UUID | --specstory-path PATH | --newest) [--format specstory|claude|both] [--json]
    验证字节边界的真实SpecStory序言和精确小写UUID;搜索Claude存储并通过严格JSONL验证规范工作树根。绝不会使用不安全/无效的显式选择器。TSV/JSON格式需要
    iconv
    python3
    仅在Claude JSONL验证时需要。缺失依赖会返回状态/退出码6;
    --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]
    --check-staged
    会验证当前提交索引而不修改。暂存模式要求暂存非Agent代码,并拒绝被忽略/无法添加/未合并的文件,且在对备用索引执行添加操作时锁定真实工作树索引,成功后原子发布。失败时真实索引保持不变。宽泛模式使用一对记录的快照;已配置的Agent文件目录(标准化为尾部斜杠)是精确计划的数据源。
  • scripts/agent-commit-metadata.sh [--harness NAME --model NAME] [--format trailers|json]
    读取暂存的SpecStory/计划文件并输出去重的
    AI-Assisted-By
    Agent-Transcript
    Agent-Plan
    值。解析暂存的 blob 而非并发变化的工作树对话记录;当无法验证工具链+模型时,需要显式覆盖。
  • scripts/scan-staged.sh [--redact] [--verbose]
    使用Agent友好的退出码运行
    gitleaks git --staged
    (0=无问题 / 10=已脱敏 / 20=存在泄露 / 30=gitleaks缺失)。标准输出为JSON行,标准错误输出为散文诊断信息。
  • scripts/probe-specstory-redaction.py [--json] [--keep] [--dry-run]
    通过合成Claude Code会话并渲染两次(启用和禁用
    --no-redact-secrets
    ),测量SpecStory原生脱敏覆盖的秘密类别。打印覆盖矩阵和我们的层仍需处理的剩余集合。当未安装specstory时返回退出码30。
  • scripts/bootstrap-project.sh [--from-chezmoi] [--migrate] [--install-hook] [--untrack-specstory-state] [--force] [--dry-run]
    .pre-commit-config.yaml
    +
    .gitleaks.toml
    安装到当前仓库,合并精确的SpecStory状态忽略规则,将钩子连接到已安装技能的脱敏工具,然后运行
    pre-commit install
    。检查
    .gitignore
    ~/.claude/settings.json
    中的配置错误,但不会隐藏对话记录目录。仅当使用显式标志时,才会取消跟踪已跟踪的状态;
    --dry-run
    可预览该索引变更。
    --install-hook
    会生成仅验证的精确网关,当缺失标识时会明显无操作。当
    core.hooksPath
    已配置时返回退出码6;对于全局/自定义钩子目录,需手动集成。

Bundled assets

捆绑资源

  • assets/artifact-dirs.txt
    — the canonical list of agent artifact directories (SpecStory, Claude plans, Cursor plans + rules, OpenCode plans, Spec-kit, Codex). Consumed by
    stage-agent-artifacts.sh
    and by
    bootstrap-project.sh
    when rendering the pre-commit
    files:
    regex.
  • assets/pre-commit-config.yaml.template
    — minimal
    .pre-commit-config.yaml
    with
    redact-agent-secrets
    + gitleaks + standard hygiene hooks.
  • assets/gitleaks.toml.template
    — portable subset of the chezmoi
    .gitleaks.toml
    with custom rule IDs + a path-scoped allowlist for agent artifact dirs.
  • assets/redact_secrets.py
    — the redactor, published to consuming repos as the pinned
    redact-agent-secrets
    pre-commit hook (root
    .pre-commit-hooks.yaml
    ). Writes
    [REDACTED:<rule-id>]
    , the sentinel SpecStory also writes natively;
    --legacy
    writes the pre-2.4.0 placeholders instead. Release procedure in
    references/pre-commit-redaction-stack.md
    .
  • assets/artifact-dirs.txt
    — Agent文件目录的规范列表(SpecStory、Claude计划、Cursor计划+规则、OpenCode计划、Spec-kit、Codex)。被
    stage-agent-artifacts.sh
    bootstrap-project.sh
    在渲染pre-commit的
    files:
    正则表达式时使用。
  • assets/pre-commit-config.yaml.template
    — 包含
    redact-agent-secrets
    + gitleaks + 标准规范钩子的最小
    .pre-commit-config.yaml
  • assets/gitleaks.toml.template
    — chezmoi的
    .gitleaks.toml
    的可移植子集,包含自定义规则ID + Agent文件目录的路径范围白名单。
  • assets/redact_secrets.py
    — 脱敏工具,作为固定版本的
    redact-agent-secrets
    pre-commit钩子(根目录的
    .pre-commit-hooks.yaml
    )发布到使用该技能的仓库。写入
    [REDACTED:<rule-id>]
    ,与SpecStory原生写入的标记相同;
    --legacy
    会写入2.4.0之前的占位符。发布流程见
    references/pre-commit-redaction-stack.md

Reference files

参考文件

  • references/transcript-session-discovery.md
    — SpecStory / Claude session layouts and the
    $PWD → slug
    algorithm. Read when
    find-session.sh
    returns empty or ambiguous results.
  • references/pre-commit-redaction-stack.md
    — three-layer defense (redact → gitleaks →
    scan-staged.sh
    ), allowlist design, sync procedure for the bundled redactor. Read when tuning rules or debugging unexpected pre-commit failures.
  • references/specstory-native-redaction.md
    — 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/remediation.md
    — rotate-first runbook for "I committed / pushed a secret". Read before any
    git filter-repo
    /
    git push --force
    action.
  • references/transcript-session-discovery.md
    — SpecStory / Claude会话布局和
    $PWD → slug
    算法。当
    find-session.sh
    返回空或歧义结果时阅读。
  • references/pre-commit-redaction-stack.md
    — 三层防御(脱敏 → gitleaks →
    scan-staged.sh
    )、白名单设计、捆绑脱敏工具的同步流程。当调整规则或调试意外pre-commit失败时阅读。
  • references/specstory-native-redaction.md
    — SpecStory >= 2.4.0自行脱敏的内容,按秘密类别和上下文测量,包括上游PR、配置项,以及为何我们的层仍必不可少。在修改脱敏占位符前阅读。
  • references/remediation.md
    — “我提交/推送了秘密”的先轮换手册。在执行任何
    git filter-repo
    /
    git push --force
    操作前务必阅读。

Tests

测试

The skill ships with a test suite under
tests/
. Run from repo root:
bash
make test-skill
  • test_redact_secrets.py
    — pytest for pure redactor functions.
  • test_gitleaks_corpus.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_scan_staged.sh
    — exit-code contract for
    scripts/scan-staged.sh
    (0 / 20 / 30 / 2).
  • test_find_session.sh
    — real prologue/JSONL/path safety, dependency output, large-tail bounds, same-checkout leakage, aliases, and worktree roots.
  • test_stage_agent_artifacts.sh
    — exact/broad status parsing, conflicts, ignored/custom paths, index-lock races, trailers, and temporary-index commits.
  • test_bootstrap_project.py
    — exact SpecStory state ignores, idempotency, dry-run, history visibility, and opt-in untracking behavior.
  • test_specstory_coverage.py
    — locks in that SpecStory still redacts by default and still writes
    [REDACTED:<label>]
    ; skips without the CLI.
  • test_agent_commit_metadata.sh
    — staged transcript/model parsing, model deduplication, path handling, JSON output, and explicit-override failures.
  • test_shipped_file_hygiene.py
    — no shipped file carries a
    detect-private-key
    BLACKLIST substring, and the redactor scrubs all ten of them convergently. Runs everywhere; needs no external binary.
The corpus + shell tests skip gracefully when
gitleaks
isn't on
PATH
. See
tests/README.md
for what each regression the suite locks in.
该技能附带
tests/
下的测试套件。从仓库根目录运行:
bash
make test-skill
  • test_redact_secrets.py
    — 纯脱敏函数的pytest测试。
  • test_gitleaks_corpus.py
    — 在临时Git仓库中暂存黄金语料库测试用例,验证真实密钥格式会触发告警,示例格式仅在已配置的Agent文件目录中被白名单放行。
  • test_scan_staged.sh
    scripts/scan-staged.sh
    的退出码契约测试(0 / 20 / 30 / 2)。
  • test_find_session.sh
    — 真实序言/JSONL/路径安全性、依赖输出、大尾部边界、同一检出泄露、别名和工作树根测试。
  • test_stage_agent_artifacts.sh
    — 精确/宽泛状态解析、冲突、忽略/自定义路径、索引锁竞争、尾注和临时索引提交测试。
  • test_bootstrap_project.py
    — 精确SpecStory状态忽略、幂等性、试运行、历史可见性和可选取消跟踪行为测试。
  • test_specstory_coverage.py
    — 锁定SpecStory仍默认脱敏且仍写入
    [REDACTED:<label>]
    的行为;未安装CLI时跳过。
  • test_agent_commit_metadata.sh
    — 暂存对话记录/模型解析、模型去重、路径处理、JSON输出和显式覆盖失败测试。
  • test_shipped_file_hygiene.py
    — 交付的文件均不包含
    detect-private-key
    黑名单子字符串,且脱敏工具会收敛清理所有十个此类字符串。可在任何环境运行;无需外部二进制文件。
gitleaks
不在
PATH
中时,语料库+ shell测试会优雅跳过。详见
tests/README.md
中每个测试锁定的回归问题。

Related skills

相关技能

  • git-workflow
    — defines and validates the English Conventional Commit + canonical provenance contract emitted here.
  • project-knowledge-harness
    — complementary memory harness (TODO.md + backlog/ + pitfalls/) that references
    .claude/plans/
    as "ephemeral agent scratchpads". This skill fills the gap: those scratchpads belong in git, not ignored.
  • git-workflow
    — 定义并验证此处生成的英文约定式提交 + 规范来源契约。
  • project-knowledge-harness
    — 互补的内存管理工具(TODO.md + backlog/ + pitfalls/),将
    .claude/plans/
    称为“临时Agent草稿本”。该技能填补了空白:这些草稿本应纳入Git,而非被忽略。