关于 claude-history-ingest
claude-history-ingest 将 Claude Code 对话、记忆文件及桌面 Agent 会话中的信息整理到 Obsidian wiki。它支持增量处理、清单追踪和预提取文本,并按项目筛选及抽样会话。
主要功能
- 01读取记忆文件、对话记录和桌面会话审计日志
- 02依据清单处理新增或修改的来源
- 03优先使用预提取的对话文本
- 04按项目抽样会话并报告覆盖范围
- 05支持忽略指定项目和完整导入
适用场景
- 01将 Claude Code 新会话整理到 wiki
- 02从项目记忆文件提取已整理的信息
- 03通过桌面会话审计日志查找 Agent 操作记录
- 04重建 wiki 时执行完整历史导入
安装
复制下面的命令,在终端中运行。
npx skills add https:/ / github.com/ ar9av/ obsidian-wiki --skill claude-history-ingest安装后在 Claude Code 中输入/claude-history-ingest确认已加载。
附带文件references/claude-data-format.md
详细介绍
Claude History Ingest — 对话挖掘
从用户过去的 Claude Code 对话中提取知识,并将其提炼到 Obsidian 知识库中。对话内容丰富但杂乱,你的工作是找出关键信息并加以整理。
此技能可直接调用,也可通过 wiki-history-ingest 路由调用(/wiki-history-ingest claude)。
开始之前
写作风格配置: 在起草或改写自然语言 Markdown 前,阅读并应用 llm-wiki/SKILL.md 中的 Writing Profile Resolution 部分。框架架构、来源信息、安全性及具体操作要求优先。
WRITING.md 中的偏好仅适用于新起草或改写的自然语言 Markdown;请保留源内容和结构化记录。
- 解析配置 — 遵循
llm-wiki/SKILL.md中的 Config Resolution Protocol(内联@name覆盖 → 沿 CWD 向上查找.env→ 全局配置 → 提示用户设置)。这会提供OBSIDIAN_VAULT_PATH和CLAUDE_HISTORY_PATH(默认为~/.claude) - 读取知识库根目录中的
.manifest.json,检查已经摄取的内容 - 读取知识库根目录中的
index.md,了解知识库已有的内容 - 项目范围限定 — 从配置中读取
WIKI_SKIP_PROJECTS(以逗号分隔的子字符串)。以下每个步骤(扫描、增量检查、抽样、清单写入)都要排除名称包含这些子字符串的项目目录。如果用户要求本次额外跳过其他项目,也一并添加。统一应用排除规则;不要在各条命令中分别手写grep -v过滤条件,以免扫描步骤与清单步骤出现偏差。
摄取模式
追加模式(默认)
针对每个源文件(对话 JSONL、记忆文件)检查 .manifest.json。仅处理:
- 清单中没有的文件(新对话、新记忆文件、新项目)
- 修改时间晚于清单中
ingested_at时间的文件
通常情况下,这就是你想要的模式——用户运行了几次新会话,并希望捕获新增内容。
比较时使用可移植键。 清单键遵循
llm-wiki/SKILL.md→.manifest.json中定义的来源键规范(v2)。$HOME下的会话使用相对于~的键(~/.claude/projects/.../abc.jsonl),而不是展开后的机器路径;另外两种形式是相对于知识库的路径和伪键。在判断文件是否为“新文件”之前,要以工具相同的方式解析存储的键(展开~/环境变量,将相对于知识库的路径解析为相对于知识库根目录)——否则,已跟踪的文件会被误认为新文件并再次摄取。scripts/manifest.py可帮助你完成此操作:# 遵循 WIKI_SKIP_PROJECTS + --skip,查找新增或已修改的来源: python3 "$OBSIDIAN_WIKI_REPO/scripts/manifest.py" delta "$OBSIDIAN_VAULT_PATH" \ --scan "$CLAUDE_HISTORY_PATH/projects/*/memory/*.md" # 如果清单中仍有旧版绝对路径键,可一次性修复: python3 "$OBSIDIAN_WIKI_REPO/scripts/manifest.py" migrate "$OBSIDIAN_VAULT_PATH" --dry-run此辅助脚本为可选项;如果无法使用,请在每次查询和写入清单前以内联方式执行相同的路径解析。
预提取(推荐——摄取前运行)
原始 JSONL 文件中有 80%–90% 是噪声:按字节数计算,tool_use 块、thinking 块、progress 事件和
file-history-snapshot 条目占据了大部分内容。scripts/extract-jsonl.py 助手脚本会剔除所有这些内容,并将仅含有效信息的紧凑 JSON 写入 ~/.claude/extracted/,将
文件大小缩减 50–200 倍(例如,12 MB JSONL → 64 KB 提取文件)。这样一来,在相同的令牌预算内,每次运行都能让技能读取 5–10 倍的对话内容。
调用此技能前,请先运行该脚本:
# First run — extract everything (skip excluded projects)
python3 "$OBSIDIAN_WIKI_REPO/scripts/extract-jsonl.py" --skip tsg,autom8
# Incremental — only sessions modified in the last day
python3 "$OBSIDIAN_WIKI_REPO/scripts/extract-jsonl.py" \
--since "$(date -v-1d +%Y-%m-%d)" --skip tsg,autom8
提取后的文件位于 ~/.claude/extracted/<project-dir>/<session-id>.json,包含:
{
"session_id": "uuid",
"project": "-Users-name-myapp",
"cwd": "/Users/name/myapp",
"start_ts": "...",
"end_ts": "...",
"n_turns": 18,
"n_user_words": 620,
"turns": [
{"role": "user", "text": "..."},
{"role": "assistant", "text": "..."}
]
}
步骤 3 读取对话时,始终优先使用提取后的文件,而非原始 JSONL。(参见步骤 3。)
如果未先运行 extract-jsonl.py,则回退到原始 JSONL——但请注意,由于读取每个原始文件消耗的令牌多得多,覆盖范围会更浅。
对话抽样启发式
一个历史记录路径可能包含数百个对话 JSONL——不要试图全部读取。对每个项目:
- 如果项目已有记忆文件(
memory/*.md),请先摄取这些文件(其中已提炼出有效信息),然后也处理清单中尚未记录的对话——即使是记忆丰富的项目,也应记录新对话。 - 如果项目没有记忆文件,则仅读取最近的 3 个对话(按 mtime 排序),以了解项目概况。优先使用预提取文件(见上文)——它们的读取成本足够低,在读取 1 个原始 JSONL 的令牌预算内可以读取 5–10 个。
- 始终报告已抽样和已跳过的内容(例如,“agenttower:已摄取 7 个记忆文件 + 4 个新对话,跳过 14 个未更改的对话”),让覆盖范围的缺口清晰可见,而不是悄然遗漏。
完整模式
无论清单如何,都处理所有内容。在执行 wiki-rebuild 后,或用户明确要求时使用。
Claude Code 数据布局
Claude Code 将数据存储在两个位置。请扫描两个位置。
来源 1:~/.claude/(CLI 会话)
~/.claude/
├── projects/ # Per-project directories
│ ├── -Users-name-project-a/ # Path-derived name (slashes → dashes)
│ │ ├── <session-uuid>.jsonl # Conversation data (JSONL)
│ │ └── memory/ # Structured memories
│ │ ├── MEMORY.md # Memory index
│ │ ├── user_*.md # User profile memories
│ │ ├── feedback_*.md # Workflow feedback memories
│ │ └── project_*.md # Project context memories
│ ├── -Users-name-project-b/
│ │ └── ...
├── sessions/ # Session metadata (JSON)
│ └── <pid>.json # {pid, sessionId, cwd, startedAt, kind, entrypoint}
├── history.jsonl # Global session history
├── tasks/ # Subagent task data
├── plans/ # Saved plans
└── settings.json
来源 2:~/Library/Application Support/Claude/local-agent-mode-sessions/(桌面应用 Agent 会话)
请先进行预检查。 许多用户只使用 CLI,没有桌面会话。在遍历下方结构前,请先确认该目录非空:
DESKTOP_SESSIONS="$HOME/Library/Application Support/Claude/local-agent-mode-sessions" [ -d "$DESKTOP_SESSIONS" ] && find "$DESKTOP_SESSIONS" -name "audit.jsonl" | head -1如果没有任何输出,则跳过本节(来源 2 + 步骤 3b),也不要提及本节。
Claude 桌面应用会在此处存储本地 Agent 模式会话。目录结构层级很深:
~/Library/Application Support/Claude/local-agent-mode-sessions/
└── <outer-uuid>/
└── <inner-uuid>/
├── local_<session-uuid>.json # Session metadata
└── local_<session-uuid>/
├── audit.jsonl # Audit log — tool calls, file reads, commands run
└── .claude/
└── projects/
└── <path-encoded-name>/ # Same path-encoding as ~/.claude/projects/
└── <uuid>.jsonl # Conversation transcript (same JSONL format as CLI)
如何查找所有本地 Agent 模式会话:
# Find all session metadata files
find ~/Library/Application\ Support/Claude/local-agent-mode-sessions -name "local_*.json" -maxdepth 4
# Find all audit logs
find ~/Library/Application\ Support/Claude/local-agent-mode-sessions -name "audit.jsonl"
# Find all conversation transcripts
find ~/Library/Application\ Support/Claude/local-agent-mode-sessions -name "*.jsonl" -path "*/.claude/projects/*"
会话元数据(local_<uuid>.json)——包含 sessionId、cwd、startedAt、model、title 等字段的 JSON 文件。请先读取此文件,了解会话上下文,再打开会话记录。
审计日志(audit.jsonl)——每行都是一条 JSON 记录,记录一次 Agent 操作:工具调用(Read、Write、Bash、Edit)、文件访问、执行的 shell 命令、MCP 调用。可用于了解 Agent 实际执行了什么——通常比单独查看对话文本包含更丰富的信息。字段:type、toolName、input、output、timestamp、sessionId。
对话记录(.claude/projects/.../<uuid>.jsonl)——格式与 CLI 对话 JSONL 相同。请使用与解析 ~/.claude/projects/*/*.jsonl 相同的方法。
按价值排序的关键数据源(合并两个位置):
- 记忆文件(
~/.claude/projects/*/memory/*.md)——经过预先提炼,已适合用于 Wiki。非常有价值。 - 对话 JSONL(
~/.claude/projects/*/*.jsonl和桌面应用转录记录)——完整的对话转录记录。内容丰富,但噪声较多。 - 审计日志(桌面会话中的
audit.jsonl)——工具调用级别的操作记录。即使对话内容稀少,也有助于提取具体操作、文件模式和命令模式。 - 会话元数据(
sessions/*.json和local_*.json)——用于了解项目、时间和 CWD。
第 1 步:调查并计算差异
扫描两个数据位置,并与 .manifest.json 对比:
# --- Source 1: CLI sessions (~/.claude) ---
# Find all projects
Glob: ~/.claude/projects/*/
# Find memory files (highest value)
Glob: ~/.claude/projects/*/memory/*.md
# Find conversation JSONL files
Glob: ~/.claude/projects/*/*.jsonl
# --- Source 2: Desktop app local-agent-mode sessions ---
DESKTOP_SESSIONS="$HOME/Library/Application Support/Claude/local-agent-mode-sessions"
# Session metadata
find "$DESKTOP_SESSIONS" -name "local_*.json" -maxdepth 4
# Audit logs
find "$DESKTOP_SESSIONS" -name "audit.jsonl"
# Conversation transcripts
find "$DESKTOP_SESSIONS" -name "*.jsonl" -path "*/.claude/projects/*"
建立统一清单并对每个文件分类:
- 新增 — 清单中没有 → 需要导入
- 已修改 — 在清单中,但文件更新日期更晚 → 需要重新导入
- 未更改 — 在清单中且未修改 → 追加模式下跳过
向用户报告:“找到 X 个 CLI 项目、Y 个桌面会话。记忆文件:A。对话:B。审计日志:C。差异:新增 D 个,已修改 E 个。”
第 2 步:先导入记忆文件
记忆文件已经采用 YAML frontmatter 结构化:
---
name: memory-name
description: one-line description
type: user|feedback|project|reference
---
Memory content here.
对于每个记忆文件:
- 读取文件并解析 frontmatter
user类型 → 写入介绍用户的实体页面,或介绍其领域的概念页面feedback类型 → 写入技能页面(工作流模式、有效做法和无效做法)project类型 → 写入介绍该项目的实体页面reference类型 → 写入指向外部资源的参考页面
每个项目中的 MEMORY.md 索引文件是快速摘要——先读取它,以决定哪些单独的记忆文件值得完整阅读。
第 3 步:解析对话 JSONL
始终先检查是否有预提取文件(见上文“预提取”部分)。对于每个对话 ~/.claude/projects/<proj>/<uuid>.jsonl,查找其对应文件 ~/.claude/extracted/<proj>/<uuid>.json。如果找到,则读取该文件——其中已筛选出用户和助手的文本轮次,与原始 JSONL 相比,所需 token 少 50–200 倍。
# Resolution order for each session:
1. ~/.claude/extracted/<project>/<session-id>.json ← prefer (compact, signal-only)
2. ~/.claude/projects/<project>/<session-id>.jsonl ← fallback (raw, noisy)
**读取预提取文件:**其中只包含所需的轮次。直接遍历 turns[].{role, text}。顶层字段(cwd、start_ts、n_user_words 等)可提供项目信息,无需进一步解析。
**读取原始 JSONL(备用方案):**每行都是一个 JSON 对象:
{
"type": "user|assistant|progress|file-history-snapshot",
"message": {
"role": "user|assistant",
"content": "text string"
},
"uuid": "...",
"timestamp": "2026-03-15T10:30:00.000Z",
"sessionId": "...",
"cwd": "/path/to/project",
"version": "2.1.59"
}
对于助手消息,content 可能是内容块数组:
{
"content": [
{"type": "thinking", "text": "..."},
{"type": "text", "text": "The actual response..."},
{"type": "tool_use", "name": "Read", "input": {...}}
]
}
- 仅筛选
type: "user"和type: "assistant"条目 - 对于助手条目,提取
text块(跳过thinking和tool_use——这些都是噪声) cwd字段用于确定此对话所属的项目- 跳过
type: "progress"——内部 Agent 进度更新 - 跳过
type: "file-history-snapshot"——文件状态跟踪 - 跳过子 Agent 对话(位于
subagents/子目录中)——除非用户提出要求
步骤 3b:解析审计日志(仅限桌面会话)
对于在 local-agent-mode-sessions/ 下找到的每个 audit.jsonl,逐行读取。每行都是一条记录 Agent 操作的 JSON 记录:
{
"type": "tool_call",
"toolName": "Bash",
"input": {"command": "npm test"},
"output": "...",
"timestamp": "2026-04-10T14:22:00Z",
"sessionId": "..."
}
从审计日志中提取的内容:
- 文件访问模式 — Agent 反复读取或编辑了哪些文件?这些是项目中的高价值文件。将它们记为项目参考资料。
- Shell 命令 — 反复出现的 Bash 命令可以揭示项目的构建、测试和部署工作流。将这些内容提炼成
skills/页面(例如“如何构建和测试此项目”)。 - 工具调用顺序 — 如果 Agent 总是按特定顺序执行读取 → 编辑 → Bash,这种工作流模式值得记录。
- 错误模式 — 失败的工具调用(非零退出代码、错误输出)可以揭示痛点、已知问题或反复出现的错误。
- MCP 工具调用 — 对 MCP 工具的调用可以揭示项目集成了哪些外部服务和 API。
从审计日志中跳过:
- 没有规律的常规文件读取(例如只读取一次配置文件)
- 纯属噪声的工具输出(冗长的堆栈跟踪、详细日志)——概括错误类别,而非完整输出
- 命令参数或输出中任何看起来像秘密、令牌或凭据的内容
与对话记录交叉参考: 审计日志告诉你发生了什么;对话告诉你为什么。同一会话的两者都可用时,请结合使用——审计日志可以用具体操作为对话内容提供依据。
处理审计日志前,先读取配对的 local_<uuid>.json 会话元数据——其中的 cwd、startedAt 和 title 可为这些操作提供背景信息。
步骤 4:按主题归类
不要为每段对话都创建一个 Wiki 页面。请改为:
- 将不同对话中提取的知识按主题分组
- 一段关于“调试身份验证 + 设置 CI”的对话 → 拆分为两个独立主题
- 不同日期的三段关于“React 性能”的对话 → 合并为一个主题
- 项目目录名称可作为自然的第一级分组
步骤 5:提炼为 Wiki 页面
每个 Claude 项目都对应知识库中的一个项目目录。~/.claude/projects/ 中的项目目录名称编码了原始路径——解码后即可得到简洁的项目名称:
-Users/Documents/projects/my-Project → myproject
-Users/Documents/projects/Another-app → anotherapp
项目专属知识与全局知识
| 你发现的内容 | 应存放的位置 | 示例 |
|---|---|---|
| 项目架构决策 | projects/<name>/concepts/ | projects/my-project/concepts/main-architecture.md |
| 项目专属调试经验 | projects/<name>/skills/ | projects/my-project/skills/api-rate-limiting.md |
| 用户学到的一般概念 | concepts/(全局) | concepts/react-server-components.md |
| 多个项目中反复出现的问题 | skills/(全局) | skills/debugging-hydration-errors.md |
| 使用的工具/服务 | entities/(全局) | entities/vercel-functions.md |
| 多次对话中出现的模式 | synthesis/(全局) | synthesis/common-debugging-patterns.md |
对于包含内容的每个项目,请在 projects/<name>/<name>.md 创建或更新项目概览页面——文件名应当使用项目名称,而不是 _project.md。Obsidian 的图谱视图使用文件名作为节点标签,因此 _project.md 会让所有项目在图谱中都显示为 _project。将文件命名为 <name>.md,可让每个项目都有独特且易读的节点名称。
**重要:**提炼_知识_,而不是对话内容。不要写“在 3 月 15 日的一次对话中,用户询问了 X。”应直接写出知识本身,并将对话列为来源。
为每个新建或更新的页面编写 summary: frontmatter 字段——用 1–2 句话、不超过 200 个字符说明“此页面介绍什么”,让尚未打开页面的读者也能了解内容。wiki-query 的快速检索路径会读取此字段,以避免打开页面正文。
为每个新建页面的 frontmatter 添加置信度和生命周期字段:
base_confidence: 0.42
lifecycle: draft
lifecycle_changed: <obsidian-wiki memory now --date>
更新页面时,保持 lifecycle 和 lifecycle_changed 不变——只有人工编辑者才能转换生命周期状态。
按照 llm-wiki 中的约定标记来源(“Provenance Markers”一节):
- 记忆文件大多是提取而来的——它们由用户手动编写,且已经过提炼。除非你要整合多个记忆文件中的说法,否则应将源自记忆的说法视为提取所得。
- 对话提炼大多是推断所得。你需要综合多轮对话中的内容得出连贯的观点,通常还要补足隐含的推理。对于综合得出的模式、跨会话归纳,以及对“用户真正想表达的意思”的解读,请广泛使用
^[inferred]。 - 如果用户在不同会话中改变了想法,或者助手与用户相互矛盾且无法明确判断如何解决,请使用
^[ambiguous]。 - 为每个新建或更新的页面编写
provenance:frontmatter 块,概述来源的大致构成。
第 6 步:更新 Manifest、日志和特殊文件
更新 .manifest.json
对于处理过的每个源文件,添加或更新其条目,包含:
ingested_at、size_bytes、modified_atsource_type:取值为"claude_conversation"、"claude_memory"、"claude_audit_log"、"claude_desktop_session"之一project:解码后的项目名称pages_created和pages_updated列表
同时更新 manifest 的 projects 部分:
{
"project-name": {
"source_path": "~/.claude/projects/-Users-...",
"vault_path": "projects/project-name",
"last_ingested": "TIMESTAMP",
"conversations_ingested": 5,
"conversations_total": 8,
"memory_files_ingested": 3,
"desktop_sessions_ingested": 2,
"audit_logs_ingested": 2
}
}
创建日志条目并更新特殊文件
使用一次带锁的调用更新 index.md、log.md 和 hot.md:
obsidian-wiki memory sync CLAUDE_HISTORY_INGEST \
projects=<projects> conversations=<conversations> \
desktop_sessions=<desktop_sessions> audit_logs=<audit_logs> \
pages_updated=<pages_updated> pages_created=<pages_created> \
mode=<mode> \
--takeaways "Ingested 5 Claude conversations across 2 projects; surfaced patterns in API design and testing strategy."
绝不要手动编辑 index.md、log.md 或 hot.md——该命令会获取锁,防止并行写入者丢失你的更新。--takeaways 是过去用于“最近活动”的单行概念摘要;省略它即可保留之前的 takeaways 不变。
如果你现在对某个进行中的项目有了更深入的理解,请记录相关事项,以便下一个会话接续处理:obsidian-wiki memory todo add "<thread>" --origin projects/<name>.md。
完整流程请参阅 .skills/llm-wiki/references/MEMORY.md。
隐私
- 提炼并综合内容——不要逐字复制原始对话文本
- 跳过任何看起来像机密、API 密钥、密码或令牌的内容
- 如果遇到个人或敏感内容,请先征求用户同意再纳入
- 用户的对话可能会提及其他人——谨慎决定哪些内容写入知识库
参考
有关数据结构的更多详情,请参阅 references/claude-data-format.md。
写入 Vault 后刷新 QMD
QMD 是搜索索引,不是事实来源。如果 $QMD_WIKI_COLLECTION 为空或未设置,请跳过此步骤。仅在此技能写入或重写 vault Markdown 后运行。如果 QMD 刷新失败,不要回滚 vault 更改;请单独报告 QMD 状态。
如果设置了 $QMD_CLI,请使用它;否则使用 qmd。
${QMD_CLI:-qmd} update
如果输出提示需要向量或嵌入可能已过时,请运行:
${QMD_CLI:-qmd} embed
使用以下任一方式验证集合:
${QMD_CLI:-qmd} ls "$QMD_WIKI_COLLECTION"
或者,如果已知特定页面路径:
${QMD_CLI:-qmd} get "qmd://$QMD_WIKI_COLLECTION/<page>.md" -l 5
记录以下其中一项:
QMD refreshed: update + embed + verifiedQMD refreshed: update only + verifiedQMD skipped: QMD_WIKI_COLLECTION unsetQMD skipped: qmd CLI unavailableQMD failed: <short error summary>