关于 find-past-conversation
这项 Claude Code 技能帮助用户从本地会话记录中找回过去的对话,适用于记得主题但需要定位具体会话的人。它指导按项目和关键词筛选 JSONL 记录,并提取会话标识、时间及讨论摘要。
主要功能
- 01按项目目录定位会话
- 02使用 ripgrep 搜索关键词
- 03跳过子 Agent 记录以减少重复
- 04从 JSONL 中提取有限上下文
- 05汇报会话标识、时间和摘要
适用场景
- 01找回关于特定主题的 Claude Code 对话
- 02确认过去会话讨论过的决定
- 03定位可能完成某项工作的会话
- 04从记录中核查分支、提交或 PR
安装
复制下面的命令,在终端中运行。
npx skills add https:/ / github.com/ donnfelker/ donnfelker-plugin-marketplace --skill find-past-conversation安装后在 Claude Code 中输入/find-past-conversation确认已加载。
详细介绍
查找以前的 Claude Code 对话
你正在帮助用户回忆以前的 Claude Code 会话。他们大致记得讨论过什么,希望你找到实际的对话记录——会话 ID、发生时间、简短摘要,以及(如有相关内容)最终交付了什么。
Claude Code 会将每个会话保存为 ~/.claude/projects/ 下的 JSON-lines 文件。本技能将介绍如何高效搜索这些对话记录,避免因读取数兆字节的日志文件而耗尽上下文。
何时使用此技能
遇到以下类似说法时触发:
- “搜索你的历史记录,查找关于 [主题] 的内容”
- “找出我们之前关于 [主题] 的对话”
- “翻翻你过去的会话,看看有没有关于 [主题] 的内容”
- “我有没有完成过关于 [主题] 的工作?”
- “我们上周对 [主题] 作了什么决定?”
- “提醒我一下,[主题] 那次会话最后得出了什么结果”
不要用此技能搜索当前代码库、当前 PR 的评论或 Slack/Jira 等外部系统——这些各有自己的技能和工具。
对话记录的组织方式
~/.claude/projects/
├── -Users-alice-source-acme-api/
│ ├── 06c5c59e-0735-...jsonl # one session = one file
│ ├── a7e955d8-cf10-...jsonl
│ └── a7e955d8-cf10-.../
│ └── subagents/
│ └── agent-ab42fde6...jsonl # subagent transcripts
├── -Users-alice-source-acme-worker/
└── ...
重要事项:
- **项目文件夹名称是工作目录将
/替换为-后的结果。**例如,在/Users/alice/source/acme/api中运行的会话,其文件位于~/.claude/projects/-Users-alice-source-acme-api/下。 - 会话 ID 是不含
.jsonl的文件名,例如a7e955d8-cf10-42ec-a36b-0fe2bcb42d45。 .jsonl中的每一行都是一条独立的 JSON 消息,包含type字段(user、assistant、system等)、timestamp和内容。每行都没有格式化,长度可能达到数十 KB。- **子 Agent 的对话记录位于
<session-id>/subagents/agent-*.jsonl。**其中噪声较多,还会增加命中数,却没有太大帮助。默认跳过。
搜索流程
第 1 步 — 选择正确的项目文件夹
如果用户当前在某个仓库中工作,而且他们记得的会话就在该仓库中,就从这里开始。根据当前工作目录计算项目文件夹:
ENCODED=$(pwd | sed 's|/|-|g')
ls ~/.claude/projects/$ENCODED/*.jsonl 2>/dev/null | wc -l
如果用户想在所有工作中查找(例如“我们以前在什么地方讨论过 X 吗?”),就搜索所有项目:
ls -d ~/.claude/projects/*/
拿不准时就问:“那次对话是在这个仓库里,还是涉及你所有的工作?”——事先缩小范围可以节省时间并减少误报。
第 2 步 — 使用 ripgrep 定向搜索
在项目文件夹中使用 rg。绝不要 cat 整个 .jsonl 文件——这些文件通常有数兆字节,而且包含带有加密签名的大段模型思考内容,会耗尽上下文。
rg -l -i "<distinctive phrase>" ~/.claude/projects/<project>/*.jsonl
-l(仅列出文件)是正确的第一步——你只需要找到候选文件。缩小范围后,再进行第二轮检查内容。
**注意搜索词的选择。**常见词会产生很多噪声:
auto-approve→ 会匹配每个使用了terraform apply -auto-approve的 CI 工作流commit→ 会匹配每个会话中的所有 git 提交消息error→ 会匹配每条重试过的 bash 命令
如果用户只提供了一个通用词,搜索前先请他们提供一个有辨识度的短语:错误字符串、函数名称、标志、文件路径、UI 标签或人名。一个具体短语胜过五个通用词。
子 Agent 的对话记录位于更深一层(<project>/<session-id>/subagents/agent-*.jsonl),因此顶层 shell glob(如 ~/.claude/projects/<project>/*.jsonl)会自动跳过它们——针对这种情况无需额外标志:
rg -l -i "your phrase" ~/.claude/projects/<project>/*.jsonl
如果改用 ripgrep 递归搜索所有内容(例如不知道项目在哪),请明确排除子 Agent 目录树,否则会得到重复命中:
rg -l -i "your phrase" ~/.claude/projects \
--glob '*.jsonl' --glob '!**/subagents/**'
第 3 步 — 筛选候选列表
- 0 个命中 → 告知用户,并请他们提供更有辨识度的短语。不要继续猜测同义词。
- 1–3 个命中 → 很好,逐一检查。
- 4 个或更多命中 → 请用户提供第二个缩小范围的词,或按最近时间排序,优先查看最新记录(
ls -lt)。
步骤 4 — 提取上下文,识别 JSON
对于每个候选文件,使用有界窗口提取周边上下文。以下两种模式都很实用:
模式 A — grep 并显示行上下文(快速、粗略):
rg -i -B 2 -A 5 "your phrase" ~/.claude/projects/<project>/<session>.jsonl | head -100
这会捕获每个匹配项周围数百行原始 JSON。适合快速目视检查。
模式 B — 识别 JSON 结构后提取(更整洁):
rg -i "your phrase" ~/.claude/projects/<project>/<session>.jsonl | \
jq -r 'select(.type=="user" or .type=="assistant") |
"\(.timestamp) [\(.type)] \(.message.content // .content | tostring | .[0:300])"'
这会筛选出仅包含用户/助手的轮次,并打印时间戳和前 300 个字符。除非 tool_use 和 tool_result 条目与用户搜索的内容直接相关,否则跳过它们——这些条目内容很多,而且很少能提供答案。
步骤 5 — 报告发现
对于每个有力的候选项,列出:
- 会话 ID(不含
.jsonl的文件名) - 项目文件夹(
~/.claude/projects/<encoded>) - 日期/时间(使用匹配消息上的时间戳;若没有,则使用文件的修改时间)
- 2-4 句摘要,说明讨论和决定的内容
如果有多个候选项,逐一简要列出,让用户选择要深入查看哪一个。不要把 20 KB 的原始 JSON 一股脑贴进聊天中——用户要的是回顾摘要,而不是重读一遍。
报告结果(可选后续操作)
用户真正想问的往往是“我们最终发布了吗?”找到会话后,可以扫描转录内容,了解实际完成了什么:
# Branches created, commits made, PRs opened
rg -o '"command":"git (commit|push|checkout -b)[^"]*' <session>.jsonl
rg -o 'gh pr create[^"]*' <session>.jsonl
rg -o 'https://github.com/[^"]*pull/[0-9]+' <session>.jsonl | sort -u
如果找到 PR URL,请检查其当前状态:
gh pr view <N> --repo <owner>/<repo> --json number,title,state,mergedAt,reviewDecision,url
回复时报告:开放 / 已合并 / 已关闭、当前评审决定,以及 CI 最近一次是否通过。这通常才是用户真正想知道的答案。
应避免的反模式
- 不要用
cat读取整个.jsonl文件。 这些文件非常大,还包含signature块、base64 思维轨迹和工具结果负载。先用rg找到匹配行,再用jq或grep -B/-A提取窗口。 - 不要在没有限定条件时搜索常见词。
approve、error、fix、commit、pr会匹配到每个会话。围绕用户记得的独特内容进行搜索。 - 不要轻信第一个匹配项。 会话可能持续数小时;关键决定往往出现在后续轮次。检查时间戳,优先选择会话末尾附近的匹配项,而不是开头附近的匹配项。
- 不要自动包含子 Agent 的转录。 它们会从不同角度重复父会话的内容,并增加匹配项数量。递归时,使用
--glob '!**/subagents/**'排除;使用顶层 Shell 通配符时,它们已经被跳过。 - 不要凭记忆转述。 如果要报告讨论内容,每个说法都必须以从文件中提取的实际行作为依据——模型对过往会话的记忆并不可靠。
- 如果用户已明确指出仓库,不要搜索整个
~/.claude/projects/*。 先缩小搜索范围。
故障模式与恢复
- 搜索没有结果。 请用户提供更具体的短语(错误消息、函数名、文件路径、人名)。如果用户只记得一个主题,尝试 2-3 个同义词变体——之后就停止并询问,不要没完没了地尝试模式匹配。
- 匹配文件位于一个你从未见过的项目中。 这没问题——转录文件仍位于
~/.claude/projects/<encoded-cwd>/。编码后的目录名会告诉你原始 cwd;如果需要检查仓库,可以切换到该目录。 - 找到会话后,无法判断做出了什么决定。 阅读最后几轮用户消息,以及工具调用链结束前的最后一轮助手消息。决定通常在这些内容里,而不是漫长的调试对话中间。
示例
用户说:“找到我们讨论机器人发现有人批准 PR 后自动批准 PR 的那段对话。”
# Step 1: across all projects since user didn't name a repo.
# The shell glob `*/[0-9a-f]*.jsonl` only matches top-level session files,
# so subagent transcripts (one dir deeper) are naturally excluded.
rg -l -i "auto.approv" ~/.claude/projects/*/[0-9a-f]*.jsonl
# → too many hits; mostly `terraform apply -auto-approve`. Ask for a distinctive phrase.
# User: "look for 'request changes'"
rg -l -i "request changes" ~/.claude/projects/*/[0-9a-f]*.jsonl
# → narrows to ~10 files. Sort by recency.
ls -lt $(rg -l -i "request changes" ~/.claude/projects/*/[0-9a-f]*.jsonl) | head -5
# Step 4: read context from the most recent candidate
rg -i -B 2 -A 5 "request changes" \
~/.claude/projects/-Users-alice-source-acme-api/a7e955d8-*.jsonl | head -60
# Step 5: report — Session a7e955d8-... in acme-api, 2026-05-14, about the review bot
# posting a plain comment after a REQUEST_CHANGES review (which doesn't clear the
# block) instead of submitting a new opinionated review.
# Outcome check
rg -o 'https://github.com/[^"]*pull/[0-9]+' \
~/.claude/projects/-Users-alice-source-acme-api/a7e955d8-*.jsonl | sort -u
# → https://github.com/acme/api/pull/23
gh pr view 23 --repo acme/api --json state,mergedAt,reviewDecision
# → OPEN, APPROVED, not yet merged
用户会得到一条简洁的答复:会话 ID、日期、摘要,以及“PR #23 — 已批准,但尚未合并。”