# Siyuan Second Memory

> Use SiYuan Note as a personal second memory and Knowledge Graph. Triggered when the user wants to remember, recall, link, organize, or reason over personal knowledge — including saving insights, creating concept maps, building topic clusters, logging decisions, and retrieving past context. This skill enforces three hard connection rules: every new document must link to at least one existing document (Mandatory Link Prompt), every outgoing link must create a matching backlink on the target (Backlink Enforcement), and orphan documents are tracked in a weekly review queue. Use it when the user says: 'remember this', 'save this idea', 'what do I know about X', 'link this to Y', 'build a concept map', 'add to my second brain', 'log this decision', 'what have I noted about Z', 'review my notes'.

- Skill: `thanabordeen/siyuan-second-memory` (Agent Skill, multi-file: 91 files)
- Install (CLI): `npx skillmds@latest add thanabordeen/siyuan-second-memory`
- Raw SKILL.md: https://api.skillmd.com/api/skills/thanabordeen/siyuan-second-memory/raw
- Safety review: pending
- Works with: Claude Code, Claude.ai, OpenAI Codex
- Category: AI & ML
- Author: ThanabordeeN (https://skillmd.com/u/thanabordeen)
- Updated: 2026-09-22
- Page: https://skillmd.com/skills/thanabordeen/siyuan-second-memory

---


# SiYuan Second Memory — Knowledge Graph Protocol v2

> This skill turns SiYuan Note into a **structured personal Knowledge Graph (KG)**:
> every node is a document, every link is a bidirectional SiYuan block reference,
> and every document lives in a well-defined taxonomy path.
>
> **Three hard rules enforce connectivity — no exceptions:**
> 1. **Mandatory Link Prompt** — every new document must have ≥1 outgoing link before it is considered saved
> 2. **Backlink Enforcement** — every outgoing link A→B must immediately create a matching backlink B→A
> 3. **Orphan Queue** — any document that cannot be linked at creation time is flagged in `_Index/orphans` for weekly review

---

## 1. Taxonomy (Notebook Structure)

All knowledge lives under a **single notebook** named `KG`.

```
KG/
├── Concepts/          # Atomic ideas, definitions, mental models
├── Projects/          # Ongoing work, goals, deliverables
├── People/            # Individuals, relationships, contact context
├── Decisions/         # Choices made, rationale, outcomes
├── Insights/          # Observations, patterns, "aha" moments
├── References/        # Articles, papers, books, external sources
├── Logs/              # Time-stamped event logs, meeting notes, journal
└── _Index/            # Auto-maintained index docs (never edit manually)
    ├── orphans        # Docs with zero confirmed backlinks — review weekly
    ├── all-tags       # Master tag registry
    ├── recent-decisions
    └── cluster-{topic}
```

**Rules:**
- One document = one atomic concept, person, project, decision, etc.
- Document titles: `lowercase-with-dashes` (e.g., `gradient-descent`, `project-apex`)
- Every document must declare **Type**, **Tags**, and **Link-Status** in its opening block
- All cross-references use SiYuan block references `((block-id "Title"))` — never plain text

---

## 2. The Three Connection Rules

### Rule 1 — Mandatory Link Prompt

**Trigger:** immediately after writing a new document's content, before marking it done.

**Protocol:**
```
search "<title keywords>" --mode keyword     # attempt 1
search "<main concept>"   --mode keyword     # attempt 2 (broader)

→ Choose ≥1 link target from results

IF zero candidates found after both attempts:
  → Add doc to _Index/orphans  (see Rule 3)
  → Set Link-Status: orphan in the doc metadata
  → Do NOT leave it silently unlinked — silence is not acceptable
```

**Candidate evaluation — link if ANY of these are true:**

| Condition | Link type |
|-----------|-----------|
| Same domain / topic | `— related concept` |
| One is sub-topic of the other | `— parent concept` / `— sub-topic of` |
| One was the context for the other | `— observed in` / `— motivated by` |
| One contradicts the other | `— contradicts` |
| One is evidence for the other | `— supporting evidence from` |
| Same project or person | `— part of project` / `— involves` |

**Minimum outgoing links per doc type:**

| Doc type | Min links | Suggested targets |
|----------|-----------|-------------------|
| Concept | 1 | Parent or related concept |
| Insight | 2 | Source context (Project/Log) + parent concept |
| Decision | 2 | Project it affects + concept it relates to |
| Project | 1 | Key concepts it uses |
| Person | 1 | Project or context where known |
| Reference | 1 | Concept it supports or introduces |
| Log | 1 | Project or topic it belongs to |

---

### Rule 2 — Backlink Enforcement

**Every outgoing link A→B must be immediately followed by a backlink on B pointing back to A.**

A one-way link is a broken edge. This rule is never skipped.

**Protocol for each link created:**
```
Step 1 → info <docB-id> --raw          # get block IDs of target doc
Step 2 → identify the ## Links block ID in docB
Step 3 → block-update <links-block-id> # append ← backlink entry
```

**Backlink entry format** (use `←` to distinguish from `→` outgoing):
```markdown
- ← ((docA-block-id "Doc A Title")) — {inverted reason}
```

**Direction inversion examples:**

| Outgoing link (A→B) | Backlink on B (←A) |
|---------------------|--------------------|
| `— builds on this concept` | `← extended by` |
| `— motivated this decision` | `← decision motivated by this` |
| `— observed in this project` | `← contains insight` |
| `— contradicts this` | `← contradicted by` |
| `— supporting evidence from` | `← supported by` |
| `— sub-topic of` | `← has sub-topic` |

**If docB has no `## Links` section yet**, append the full section:
```bash
node scripts/content.js <docB-id>              # verify current content
node scripts/block-update.js <last-block-id> \
  --content "## Links\n\n- ← ((docA-id \"Doc A\")) — {inverted reason}"
```

---

### Rule 3 — Orphan Queue & Weekly Review

An **orphan** is any document with `Link-Status: orphan` — it was saved but no link candidates were found at creation time.

**Orphan entry format in `_Index/orphans`:**
```markdown
- ((doc-block-id "Title")) — added {YYYY-MM-DD} — {reason no link found}
```

**Weekly Review Protocol** (say "review my orphan notes" to trigger):
```
Step 1 → content <_Index/orphans>              # list all orphans
Step 2 → for each orphan:
           search "<title>"         --mode semantic   # semantic attempt
           search "<summary concept>" --mode keyword  # keyword attempt
Step 3 → if candidates found:
           apply Rule 1 + Rule 2
           update doc: Link-Status: linked
           remove from _Index/orphans, add to Resolution Log
Step 4 → if still no match:
           leave in queue, update the date note
           consider: should this doc be split? retitled?
```

---

## 3. Core Workflows

### 3a. Save New Knowledge ← most common

```
Step 1  → exists --title              check for duplicates
Step 2  → create                      create under correct taxonomy path
Step 3  → update                      write content (Section 4 template)
Step 4  → search ×2        [RULE 1]   find ≥1 link candidate
          ↓ candidates found                    ↓ no candidates
Step 5a → block-update (new doc)      Step 5b → block-update (_Index/orphans)
          add → outgoing links                    add orphan entry
          info --raw (each target)               update metadata:
          block-update (each target)  [RULE 2]     Link-Status: orphan
          add ← backlinks
          update metadata:
            Link-Status: linked
Step 6  → tags                        add domain + type + link-status tags
Step 7  → protect                     if Decision or _Index doc
```

### 3b. Recall / Retrieve

```
Step 1 → search <query> --mode keyword
Step 2 → content <top result doc-ids>
Step 3 → follow ← backlinks to surface connected context
Step 4 → synthesize: doc titles + key extracts + connected nodes
```

### 3c. Link Two Existing Nodes

```
Step 1 → info <docA-id> --raw
Step 2 → info <docB-id> --raw
Step 3 → block-update <docA links-block>   add → link to B
Step 4 → block-update <docB links-block>   add ← backlink to A  [RULE 2]
Step 5 → if either doc was in _Index/orphans:
           remove from queue, update Link-Status: linked
```

### 3d. Update Existing Knowledge

```
Step 1 → search → content             find and read the doc
Step 2 → block-update                 update only the changed block
Step 3 → append Changelog entry       {date}: {what changed}
Step 4 → if new content implies new links → apply Rule 1+2
```

### 3e. Build a Topic Cluster

```
Step 1 → search <topic> --mode hybrid       find all member docs
Step 2 → create _Index/cluster-{topic}
Step 3 → update cluster index               write member list with block refs
Step 4 → block-update each member           add ← backlink to cluster index
Step 5 → protect cluster index doc
```

### 3f. Weekly Review (orphan resolution)

```
Step 1 → content <_Index/orphans>
Step 2 → for each orphan: search ×2 (keyword + semantic)
Step 3 → link resolved orphans (Rule 1+2), remove from queue
Step 4 → report: N resolved, M still pending
```

---

## 4. Document Format (Markdown Template)

```markdown
# {Title}

**Type:** {Concept | Project | Person | Decision | Insight | Reference | Log}
**Tags:** #{tag1} #{tag2} #{tag3}
**Created:** {YYYY-MM-DD}
**Updated:** {YYYY-MM-DD}
**Link-Status:** {linked | orphan}

---

## Summary

{One to three sentences. What is this? Why does it matter?}

## Body

{Main content — explanations, arguments, evidence, data, quotes.}

## Key Points

- {Concise bullet. One idea per bullet.}

## Links

- → ((block-id "Related Doc")) — {reason for link}
- ← ((block-id "Doc That Links Here")) — {inverted reason}

## Open Questions

- {Unresolved question or uncertainty}

## Changelog

- {YYYY-MM-DD}: Created · Link-Status: {linked|orphan}
- {YYYY-MM-DD}: {What changed}
```

**New fields vs v1:**
- `Link-Status` in metadata (linked / orphan)
- `←` prefix on backlink entries in `## Links`
- Changelog tracks link-status changes

---

## 5. Tagging Conventions

| Rule | Example |
|------|---------|
| Lowercase, hyphens, no spaces | `#machine-learning`, `#project-apex` |
| Max 5 tags per document | — |
| At least 1 domain tag | `#iot`, `#finance`, `#ai`, `#health` |
| At least 1 type tag | `#concept`, `#decision`, `#insight`, `#log` |
| 1 status tag | `#active`, `#archived`, `#draft` |
| 1 link-status tag | `#linked` or `#orphan` |

Update `_Index/all-tags` whenever a **new** tag appears for the first time.

---

## 6. Decision Log Format

```markdown
# Decision: {Short Title}

**Type:** Decision
**Tags:** #decision #{domain} #{project}
**Status:** #decided | #reconsidering | #reversed
**Date:** {YYYY-MM-DD}
**Link-Status:** linked

---

## Context

{What situation prompted this decision?}

## Options Considered

| Option | Pros | Cons |
|--------|------|------|
| {A} | | |
| {B} | | |

## Choice

**Selected:** {Option name}
**Rationale:** {Why this option won.}

## Links

- → ((block-id "Project")) — decision affects this project
- → ((block-id "Concept")) — relates to this concept
- ← ((block-id "Insight")) — insight that informed this decision

## Outcome

{Fill in later: what actually happened?}
```

Decisions require **minimum 2 outgoing links** and must be `protect`ed immediately after creation.

---

## 7. `_Index/orphans` Document Format

```markdown
# Index: Orphans

**Type:** Index
**Updated:** {YYYY-MM-DD}

---

## Pending Review

- ((block-id "Doc Title")) — added {YYYY-MM-DD} — {why no link found}

## Resolution Log

- {YYYY-MM-DD}: ((block-id "Doc Title")) → linked to ((block-id "Target")) — {reason}
```

---

## 8. Search Strategy

| Goal | Command | When |
|------|---------|------|
| Known title | `search <title> --mode legacy` | Exact lookup |
| Concept recall | `search <topic> --mode keyword` | Default for Rule 1 attempt 1+2 |
| No keyword match | `search <topic> --mode semantic` | Orphan review |
| Broad sweep | `search <topic> --mode hybrid` | Cluster building |
| Check existence | `exists --title <title>` | Always before `create` |

Rule 1 requires **two keyword searches** before declaring orphan. Semantic search is reserved for orphan review (slower, requires QDRANT + OLLAMA).

---

## 9. Quality Checks

Run after any batch write session:

| Check | How | Pass condition |
|-------|-----|---------------|
| No silent orphans | `content <_Index/orphans>` | Every unlinked doc explicitly listed |
| Backlinks complete | Spot-check 3 random docs | Every `→` has a `←` on target |
| Tags consistent | `content <_Index/all-tags>` | No variant spellings |
| Decisions protected | `info <decision-docId>` | Protect attribute present |
| Link-Status accurate | Search `#orphan` | Count matches `_Index/orphans` list |

---

## 10. Script Reference

```bash
# ── Bootstrap ──────────────────────────────────────────────
node scripts/notebooks.js                       # confirm KG notebook exists

# ── Save new doc (full Rule 1+2 flow) ──────────────────────
node scripts/exists.js --title "doc-title"
node scripts/create.js "doc-title" --path "/KG/{Folder}/doc-title"
node scripts/update.js <docId> --content "$(cat doc.md)"

# Rule 1: find candidates
node scripts/search.js "title keywords" --mode keyword
node scripts/search.js "main concept"   --mode keyword

# Rule 2: backlink on each target
node scripts/info.js <targetDocId> --raw
node scripts/block-update.js <target-links-blockId> \
  --content "- ← ((newDoc-blockId \"New Doc Title\")) — {inverted reason}"

# Rule 3: orphan queue (only if no candidates)
node scripts/info.js <_Index/orphans-docId> --raw
node scripts/block-update.js <orphans-list-blockId> \
  --content "- ((newDoc-blockId \"Title\")) — added {date} — {reason}"

# ── Tag ────────────────────────────────────────────────────
node scripts/tags.js <blockId> --add "concept,ai,active,linked"

# ── Protect ────────────────────────────────────────────────
node scripts/protect.js <docId>           # Decisions + _Index docs only

# ── Weekly review ──────────────────────────────────────────
node scripts/content.js <_Index/orphans-docId>
node scripts/search.js "<orphan title>" --mode semantic
# → link resolved orphans, remove from queue
```

---

## 11. Full Example — Save Flow with All Three Rules

**User says:** "Remember that normalizing inputs speeds up gradient descent — saw this in Project Apex."

```
# 1. Check duplicates
exists --title "insight-gradient-normalization"   → not found

# 2. Create
create "insight-gradient-normalization" --path "/KG/Insights/insight-gradient-normalization"

# 3. Write content (Link-Status: orphan temporarily)

# 4. RULE 1: find candidates
search "gradient descent" --mode keyword   → found: gradient-descent (Concepts/)
search "project apex"     --mode keyword   → found: project-apex (Projects/)
# candidates found → NOT an orphan

# 5a. Add outgoing links to new doc
block-update <insight-links-blockId>:
  "- → ((gradient-descent-id)) Gradient Descent — parent concept
   - → ((project-apex-id)) Project Apex — observed in this project"

# 5b. RULE 2: backlink on gradient-descent
info <gradient-descent-docId> --raw
block-update <gradient-descent-links-blockId>:
  "- ← ((insight-id \"Insight: Gradient Normalization\")) — contains supporting insight"

# 5c. RULE 2: backlink on project-apex
info <project-apex-docId> --raw
block-update <project-apex-links-blockId>:
  "- ← ((insight-id \"Insight: Gradient Normalization\")) — insight generated in this project"

# 6. Update Link-Status
block-update <insight-metadata-blockId>: "**Link-Status:** linked"

# 7. Tag
tags <insight-blockId> --add "insight,machine-learning,project-apex,active,linked"

# Result: 3 documents updated · 2 bidirectional edges created · 0 orphans added
```

---

## Notes

- **SiYuan ≥ 3.6.0** and **Node.js ≥ 14.0.0** required
- Set `SIYUAN_BASE_URL` and `SIYUAN_TOKEN` before running any script
- `SIYUAN_DELETE_SAFE_MODE` must remain at default — this skill never modifies it
- This is a protocol layer on top of `siyuan-skill` base commands
- **v2 changes from v1:** added `Link-Status` field · `←` backlink syntax · `_Index/orphans` · Rule 1/2/3 enforcement in all workflows · minimum link counts per doc type
