wiki-import

Compare original and translation side by side

🇺🇸

Original

English
🇨🇳

Translation

Chinese

Wiki Import — Reconstruct Pages from graph.json

Wiki 导入 — 从graph.json重建页面

You are importing a vault's knowledge graph from a
graph.json
export (produced by
wiki-export
) into the current vault. This reconstructs page stubs with correct frontmatter, wikilinks, and typed relationships, then updates all vault metadata.
你正在将某个vault的知识图谱从
graph.json
导出文件(由
wiki-export
生成)导入当前vault。此操作会重建带有正确前置元数据(frontmatter)、维基链接(wikilinks)和类型化关系的页面 stub,然后更新所有vault元数据。

Before You Start

开始之前

  1. Resolve config — follow the Config Resolution Protocol in
    llm-wiki/SKILL.md
    (walk up CWD for
    .env
    ~/.obsidian-wiki/config
    → prompt setup). This gives
    OBSIDIAN_VAULT_PATH
    .
  2. Read
    $OBSIDIAN_VAULT_PATH/AGENTS.md
    if it exists — apply any owner-specific conventions.
  1. 解析配置 — 遵循
    llm-wiki/SKILL.md
    中的配置解析协议(从当前工作目录向上查找
    .env
    ~/.obsidian-wiki/config
    → 提示设置)。这将获取
    OBSIDIAN_VAULT_PATH
  2. 如果存在
    $OBSIDIAN_VAULT_PATH/AGENTS.md
    ,请阅读该文件 — 应用任何所有者特定的约定。

Step 1: Locate and Validate Source

步骤1:定位并验证源文件

Find the import source:
  • If the user provided a path argument, use it directly.
  • Otherwise auto-detect
    ./wiki-export/graph.json
    in the current directory.
  • If neither exists, ask the user for the path.
Validate the file:
  • Must be valid JSON
  • Must have top-level keys:
    nodes
    (array),
    links
    (array),
    graph
    (object)
  • Must have at least 1 node
If validation fails, report what's wrong and stop.
Show a preview before importing:
Import preview
  Source: <path>  (exported at <graph.exported_at>)
  Nodes:  N total  (concepts: A, entities: B, skills: C, references: D, ...)
  Links:  M edges  (X typed, Y untyped)
  Target: $OBSIDIAN_VAULT_PATH
查找导入源:
  • 如果用户提供了路径参数,直接使用该路径。
  • 否则自动检测当前目录下的
    ./wiki-export/graph.json
  • 如果两者都不存在,请求用户提供路径。
验证文件:
  • 必须是有效的JSON文件
  • 必须包含顶级键:
    nodes
    (数组)、
    links
    (数组)、
    graph
    (对象)
  • 至少包含1个节点
如果验证失败,报告问题并停止操作。
导入前显示预览:
Import preview
  Source: <path>  (exported at <graph.exported_at>)
  Nodes:  N total  (concepts: A, entities: B, skills: C, references: D, ...)
  Links:  M edges  (X typed, Y untyped)
  Target: $OBSIDIAN_VAULT_PATH

Step 2: Determine Conflict Resolution Mode

步骤2:确定冲突解决模式

Read the user's phrasing to determine mode. Default is
merge
.
ModeTrigger phrasesBehaviour
merge
(default, no special phrasing)Existing pages: update frontmatter tags/summary/relationships and add missing wikilinks; new pages: create stub.
skip
"skip existing", "don't overwrite", "only new pages"Leave existing pages completely untouched; only create pages that don't exist yet.
overwrite
"overwrite", "replace existing", "force import"Replace all matched pages with freshly reconstructed stubs regardless of existing content.
根据用户的表述确定模式。默认模式为
merge
模式触发短语行为
merge
(默认,无特殊表述)现有页面:更新前置元数据的标签/摘要/关系,并添加缺失的维基链接;新页面:创建stub。
skip
"skip existing"、"don't overwrite"、"only new pages"完全保留现有页面;仅创建尚不存在的页面。
overwrite
"overwrite"、"replace existing"、"force import"无论现有内容如何,用新重建的stub替换所有匹配的页面。

Step 3: Build Internal Maps

步骤3:构建内部映射

Before writing anything, build two maps from the
links
array:
Adjacency map — for each node id, collect all neighbour ids (edges in either direction):
adjacency["concepts/transformers"] = ["entities/vaswani", "concepts/lstm", ...]
Typed edge map — for each node id, collect outgoing typed edges only (
typed: true
):
typed_edges["concepts/transformers"] = [
  {target: "concepts/lstm", relation: "contradicts"},
  ...
]
在写入任何内容之前,从
links
数组构建两个映射:
邻接映射 — 为每个节点ID收集所有相邻节点ID(双向边):
adjacency["concepts/transformers"] = ["entities/vaswani", "concepts/lstm", ...]
类型化边映射 — 为每个节点ID仅收集 outgoing 类型化边(
typed: true
):
typed_edges["concepts/transformers"] = [
  {target: "concepts/lstm", relation: "contradicts"},
  ...
]

Step 4: Reconstruct Pages

步骤4:重建页面

Record counts:
created = 0
,
skipped = 0
,
merged = 0
.
For each node in
nodes
:
  1. Compute
    page_path = $VAULT/<node.id>.md
  2. Ensure the parent directory exists (e.g.
    $VAULT/concepts/
    )
  3. Check if the file already exists:
    • merge mode (default) + exists → read existing file, apply merge logic (see below), increment
      merged
    • merge mode (default) + doesn't exist → proceed to create stub, increment
      created
    • skip mode + exists → increment
      skipped
      , continue to next node
    • skip mode + doesn't exist → proceed to create stub, increment
      created
    • overwrite mode + exists → proceed to write fresh stub (overwrite), increment
      merged
    • overwrite mode + doesn't exist → proceed to create stub, increment
      created
记录计数:
created = 0
skipped = 0
merged = 0
nodes
中的每个节点执行以下操作:
  1. 计算
    page_path = $VAULT/<node.id>.md
  2. 确保父目录存在(例如
    $VAULT/concepts/
  3. 检查文件是否已存在:
    • merge模式(默认)+ 已存在 → 读取现有文件,应用合并逻辑(见下文),
      merged
      计数加1
    • merge模式(默认)+ 不存在 → 继续创建stub,
      created
      计数加1
    • skip模式 + 已存在
      skipped
      计数加1,继续处理下一个节点
    • skip模式 + 不存在 → 继续创建stub,
      created
      计数加1
    • overwrite模式 + 已存在 → 继续写入新的stub(覆盖),
      merged
      计数加1
    • overwrite模式 + 不存在 → 继续创建stub,
      created
      计数加1

Page template (new or overwrite)

页面模板(新建或覆盖)

markdown
---
title: <node.label>
category: <node.category>
tags: <node.tags as YAML list>
sources:
  - "imported from <graph.json path>"
<if node.summary exists>
summary: "<node.summary>"
</if>
<if typed_edges[node.id] is non-empty>
relationships:
<for each {target, relation} in typed_edges[node.id]>
  - target: "[[<target>]]"
    type: <relation>
</for>
</if>
lifecycle: draft
lifecycle_changed: <today YYYY-MM-DD>
base_confidence: 0.5
tier: supporting
created: <ISO timestamp>
updated: <ISO timestamp>
---
markdown
---
title: <node.label>
category: <node.category>
tags: <node.tags as YAML list>
sources:
  - "imported from <graph.json path>"
<if node.summary exists>
summary: "<node.summary>"
</if>
<if typed_edges[node.id] is non-empty>
relationships:
<for each {target, relation} in typed_edges[node.id]>
  - target: "[[<target>]]"
    type: <relation>
</for>
</if>
lifecycle: draft
lifecycle_changed: <today YYYY-MM-DD>
base_confidence: 0.5
tier: supporting
created: <ISO timestamp>
updated: <ISO timestamp>
---

<node.label>

<node.label>

<node.summary paragraph if available, else omit>
<node.summary paragraph if available, else omit>

Related

Related

<for each neighbour in adjacency[node.id], sorted alphabetically> <if edge is typed>
  • [[<neighbour>]] — <relation> <else>
  • [[<neighbour>]] </if>
</for> ```
If
adjacency[node.id]
is empty, omit the
## Related
section entirely.
<for each neighbour in adjacency[node.id], sorted alphabetically> <if edge is typed>
  • [[<neighbour>]] — <relation> <else>
  • [[<neighbour>]] </if>
</for> ```
如果
adjacency[node.id]
为空,则完全省略
## Related
部分。

Merge logic (merge mode, existing page)

合并逻辑(merge模式,现有页面)

  1. Read the existing page's frontmatter.
  2. Tags: union of existing tags and
    node.tags
    (deduplicated, keep existing order, append new ones).
  3. Summary: if the existing page has no
    summary
    field and
    node.summary
    exists, add it.
  4. Relationships: union of existing
    relationships:
    entries and
    typed_edges[node.id]
    — skip entries where the same
    (target, type)
    pair already exists.
  5. Updated: set
    updated
    to the current ISO timestamp.
  6. Body: scan for a
    ## Related
    section. If it exists, append any missing wikilinks from
    adjacency[node.id]
    that aren't already linked anywhere in the body. If no
    ## Related
    section exists, append one with the missing links.
  7. Leave the rest of the body untouched.
  1. 读取现有页面的前置元数据。
  2. 标签:现有标签与
    node.tags
    的并集(去重,保留现有顺序,追加新标签)。
  3. 摘要:如果现有页面没有
    summary
    字段且
    node.summary
    存在,则添加该摘要。
  4. 关系:现有
    relationships:
    条目与
    typed_edges[node.id]
    的并集 — 跳过已存在相同
    (target, type)
    对的条目。
  5. 更新时间:将
    updated
    设置为当前ISO时间戳。
  6. 正文:扫描是否存在
    ## Related
    部分。如果存在,追加
    adjacency[node.id]
    中未在正文中任何位置链接的缺失维基链接。如果不存在
    ## Related
    部分,则追加包含缺失链接的该部分。
  7. 保留正文的其余部分不变。

Step 5: Update Vault Metadata

步骤5:更新Vault元数据

.manifest.json

.manifest.json

Add a new entry keyed by the canonical path of the graph.json file:
json
"<absolute path to graph.json>": {
  "ingested_at": "<ISO timestamp>",
  "source_type": "wiki-export",
  "pages_created": ["list/of/created/pages.md"],
  "pages_updated": ["list/of/merged/pages.md"]
}
Also increment:
  • stats.total_sources_ingested
    by 1
  • stats.total_pages
    by the count of pages actually created (not skipped/merged)
If
.manifest.json
doesn't exist, create it with the standard structure:
json
{
  "stats": {
    "total_sources_ingested": 1,
    "total_pages": <created count>
  },
  "<graph.json path>": { ... }
}
添加一个以graph.json文件的规范路径为键的新条目:
json
"<absolute path to graph.json>": {
  "ingested_at": "<ISO timestamp>",
  "source_type": "wiki-export",
  "pages_created": ["list/of/created/pages.md"],
  "pages_updated": ["list/of/merged/pages.md"]
}
同时增加:
  • stats.total_sources_ingested
    加1
  • stats.total_pages
    加实际创建的页面数(不包括跳过/合并的页面)
如果
.manifest.json
不存在,则使用标准结构创建:
json
{
  "stats": {
    "total_sources_ingested": 1,
    "total_pages": <created count>
  },
  "<graph.json path>": { ... }
}

index.md

index.md

For each created or merged page:
  • Add or update the entry under its category section using the format:
    - [[<id>]] — <summary or title> ( #tag1 #tag2)
    (Note: space before
    (
    description ( #tag)
    not
    description(#tag)
    )
Keep categories sorted alphabetically. Create the category section if it doesn't exist.
对于每个新建合并的页面:
  • 在其分类下添加或更新条目,格式如下:
    - [[<id>]] — <summary or title> ( #tag1 #tag2)
    (注意:
    (
    前有空格 — 应为
    description ( #tag)
    而非
    description(#tag)
保持分类按字母顺序排序。如果分类部分不存在,则创建该部分。

log.md

log.md

Append one line:
- [<ISO timestamp>] IMPORT source="<graph.json path>" pages_created=<N> pages_skipped=<K> pages_merged=<M>
追加一行:
- [<ISO timestamp>] IMPORT source="<graph.json path>" pages_created=<N> pages_skipped=<K> pages_merged=<M>

hot.md

hot.md

Rewrite the Recent Activity section to include this import as the latest entry:
- [<timestamp>] IMPORT from <graph.json path> — created X, merged Z pages
Update the
updated:
frontmatter timestamp. Leave other hot.md sections (Active Threads, Key Takeaways) intact unless they reference pages that were just created — in which case add brief mentions.
重写Recent Activity部分,将此次导入作为最新条目包含:
- [<timestamp>] IMPORT from <graph.json path> — created X, merged Z pages
更新
updated:
前置元数据的时间戳。保留
hot.md
的其他部分(Active Threads、Key Takeaways)不变,除非它们引用了刚创建的页面 — 在这种情况下添加简短提及。

Step 6: Print Summary

步骤6:打印摘要

Wiki import complete → $OBSIDIAN_VAULT_PATH
  Source:  <graph.json path>
           exported at <graph.exported_at>, <N> nodes, <M> links
  Created: <X> pages
  Merged:  <Z> pages  (existing pages updated)
  Skipped: <Y> pages  (only when --skip mode was used)
Only show the
Skipped
line if
skip
mode was explicitly requested. If
overwrite
mode was used, label merged pages as
Replaced
instead.
Wiki import complete → $OBSIDIAN_VAULT_PATH
  Source:  <graph.json path>
           exported at <graph.exported_at>, <N> nodes, <M> links
  Created: <X> pages
  Merged:  <Z> pages  (existing pages updated)
  Skipped: <Y> pages  (only when --skip mode was used)
仅当明确请求
skip
模式时,才显示
Skipped
行。如果使用了
overwrite
模式,则将合并的页面标记为
Replaced
而非
Merged

Notes

注意事项

  • Stub quality: Imported pages are stubs — they have structure and wikilinks but no full body content. They're starting points for future ingestion, not finished pages.
  • Re-running is safe: The default
    merge
    mode is idempotent — re-running on an unchanged export will update timestamps but won't destroy content. Use
    overwrite
    only when you want to fully reset pages to stubs.
  • Directory creation: Always create missing category directories before writing pages.
  • Broken wikilinks: Since pages are being created together from the same export, most links will resolve. Any node referenced in
    links
    but absent from
    nodes
    (broken in the original export) will still appear as a wikilink — it just won't have a corresponding page file, which is valid.
  • Filtered exports: If the source
    graph.json
    was produced with visibility filtering (noted in
    graph.metadata
    ), imported pages will only reflect the filtered set. Note this in the summary if
    graph.graph
    contains a
    filtered
    key.
  • Stub质量:导入的页面是stub — 它们具有结构和维基链接,但没有完整的正文内容。它们是未来摄入内容的起点,而非成品页面。
  • 重复运行安全:默认的
    merge
    模式是幂等的 — 在未修改的导出文件上重复运行只会更新时间戳,不会破坏内容。仅当你想要将页面完全重置为stub时,才使用
    overwrite
    模式。
  • 目录创建:在写入页面之前,始终创建缺失的分类目录。
  • 损坏的维基链接:由于页面是从同一导出文件中一起创建的,大多数链接将可以解析。任何在
    links
    中引用但在
    nodes
    中不存在的节点(原始导出中的损坏节点)仍会显示为维基链接 — 只是没有对应的页面文件,这是允许的。
  • 过滤后的导出:如果源
    graph.json
    是通过可见性过滤生成的(在
    graph.metadata
    中注明),则导入的页面将仅反映过滤后的集合。如果
    graph.graph
    包含
    filtered
    键,请在摘要中注明这一点。