From d99b8cb44de7da19bf15de28617db2e03b6a29a7 Mon Sep 17 00:00:00 2001 From: minsoo-web Date: Mon, 9 Mar 2026 07:30:43 +0900 Subject: [PATCH] feat: add obsidian-brain plugin for learning archival automation Add new plugin that archives learnings from Claude Code sessions to Obsidian vault as Zettelkasten notes and loads vault knowledge as conversational context. Components: - SKILL.md: auto-invoked skill for vault context loading (94 lines) - /obsidian-archive: session learning extraction command - /brain: explicit vault knowledge loading command - 3 reference files: vault-setup, templates, archive-workflow Also updates obsidian skill with mutual exclusion boundary to prevent trigger collision between the two plugins. Benchmarked: 100% pass rate (17/17 assertions) vs 72.4% without skill. Co-Authored-By: Claude Opus 4.6 --- .claude-plugin/marketplace.json | 7 +- .../2026-03-09-obsidian-brain-brainstorm.md | 126 +++++ ...6-03-09-feat-obsidian-brain-plugin-plan.md | 522 ++++++++++++++++++ .../obsidian-brain/.claude-plugin/plugin.json | 12 + plugins/obsidian-brain/README.md | 75 +++ plugins/obsidian-brain/commands/brain.md | 52 ++ .../commands/obsidian-archive.md | 32 ++ .../skills/obsidian-brain/SKILL.md | 94 ++++ .../references/archive-workflow.md | 158 ++++++ .../obsidian-brain/references/templates.md | 109 ++++ .../obsidian-brain/references/vault-setup.md | 81 +++ plugins/obsidian/.claude-plugin/plugin.json | 2 +- plugins/obsidian/skills/obsidian/SKILL.md | 16 +- 13 files changed, 1278 insertions(+), 8 deletions(-) create mode 100644 docs/brainstorms/2026-03-09-obsidian-brain-brainstorm.md create mode 100644 docs/plans/2026-03-09-feat-obsidian-brain-plugin-plan.md create mode 100644 plugins/obsidian-brain/.claude-plugin/plugin.json create mode 100644 plugins/obsidian-brain/README.md create mode 100644 plugins/obsidian-brain/commands/brain.md create mode 100644 plugins/obsidian-brain/commands/obsidian-archive.md create mode 100644 plugins/obsidian-brain/skills/obsidian-brain/SKILL.md create mode 100644 plugins/obsidian-brain/skills/obsidian-brain/references/archive-workflow.md create mode 100644 plugins/obsidian-brain/skills/obsidian-brain/references/templates.md create mode 100644 plugins/obsidian-brain/skills/obsidian-brain/references/vault-setup.md diff --git a/.claude-plugin/marketplace.json b/.claude-plugin/marketplace.json index c5288e8..f4241c5 100644 --- a/.claude-plugin/marketplace.json +++ b/.claude-plugin/marketplace.json @@ -1,7 +1,7 @@ { "name": "kit", "description": "Community plugin & skills marketplace for Claude Code", - "version": "1.6.1", + "version": "1.7.0", "owner": { "name": "hamsurang", "email": "zlemzlem5656@naver.com" @@ -36,6 +36,11 @@ "name": "obsidian", "source": "./plugins/obsidian", "description": "Work with Obsidian vaults — search, create, edit, organize notes and manage frontmatter via obsidian-cli and Obsidian Headless" + }, + { + "name": "obsidian-brain", + "source": "./plugins/obsidian-brain", + "description": "Archive learnings from Claude Code sessions to Obsidian vault as Zettelkasten notes and use vault knowledge as conversational context" } ] } diff --git a/docs/brainstorms/2026-03-09-obsidian-brain-brainstorm.md b/docs/brainstorms/2026-03-09-obsidian-brain-brainstorm.md new file mode 100644 index 0000000..a448fcc --- /dev/null +++ b/docs/brainstorms/2026-03-09-obsidian-brain-brainstorm.md @@ -0,0 +1,126 @@ +--- +date: 2026-03-09 +topic: obsidian-brain +status: brainstorm +--- + +# Obsidian Brain - 학습 아카이빙 자동화 스킬 + +## What We're Building + +Claude Code 대화에서 배운 것을 Obsidian vault에 Zettelkasten 방식으로 자동 아카이빙하는 플러그인. + +두 가지 핵심 기능: +1. **`/obsidian-archive` command** - 현재 세션에서 학습한 내용을 추출 → 기존 vault 노트와 관계 판단 → 드래프트 제시 → 수정 반영 → Zettelkasten 노트로 저장 +2. **`obsidian-brain` auto-invoked skill** - vault에 축적된 지식을 Claude 컨텍스트에 자동 반영하여 더 맥락있는 답변 제공 + +### 사용 흐름 + +**아카이빙 흐름 (`/obsidian-archive`)**: +1. 사용자가 작업 중 또는 학습 후 `/obsidian-archive` 호출 +2. Claude가 현재 대화를 분석하여 핵심 학습 포인트 추출 +3. vault의 기존 노트를 스캔하여 관련 노트 탐색 +4. 새 노트 드래프트 제시: 제목, 내용, `[[wikilink]]` 연결, 태그 +5. 사용자가 수정 제안 가능 (내용 수정, 연결 추가/제거, 태그 변경) +6. 승인 후 vault에 저장 + +**컨텍스트 활용 흐름 (auto-invoked skill)**: +- Claude가 대화 주제와 관련된 vault 노트를 자동으로 참조 +- 사용자의 기존 지식 수준과 용어 사용 패턴을 반영한 답변 + +### 사용 시나리오 + +**시나리오 A: 작업 중 부산물 캡처** +> React 프로젝트 작업 중 useTransition에 대해 새로 배움 +> → `/obsidian-archive` +> → "useTransition은 concurrent rendering에서 낮은 우선순위 업데이트를 위한 hook" +> → 기존 "React Hooks" 노트, "Concurrent Mode" 노트와 자동 연결 +> → 수정 없이 승인 → 저장 + +**시나리오 B: 의도적 학습 세션** +> "Rust의 lifetime에 대해 알려줘" → 학습 대화 진행 +> → `/obsidian-archive` +> → 여러 개의 원자적 노트 생성 제안 (lifetime 기본, borrow checker, 'static lifetime 등) +> → 각 노트 간 연결 + 기존 "Ownership" 노트와 연결 +> → 일부 내용 수정 후 승인 → 저장 + +## Why This Approach + +### 별도 플러그인 (`obsidian-brain`)으로 분리하는 이유 + +- **관심사 분리**: 아카이빙(command)과 컨텍스트 활용(skill)은 다른 트리거와 동작 패턴 +- **기존 `obsidian` 플러그인과의 역할 구분**: obsidian 플러그인은 범용 vault 관리, obsidian-brain은 지식 관리에 특화 +- **확장성**: 나중에 학습 통계, 복습 리마인더 등 추가 가능 +- **브랜치 이름(`obsidian-brain`)과 일치** + +### Zettelkasten 방식을 채택하는 이유 + +- 원자적 노트 = Claude가 특정 개념을 정확히 참조하기 좋음 +- `[[wikilink]]` 연결 = 지식 그래프 형성 → "관련 지식" 탐색 가능 +- 태그 + 링크 이중 분류 = 다양한 경로로 접근 가능 + +### Claude 판단 기반 연결의 이유 + +- 단순 키워드 매칭보다 의미적 관계 파악이 정확 +- "확장", "반대 의견", "사례", "전제 조건" 등 관계 유형 판단 가능 +- vault 규모가 커져도 관련성 높은 연결만 제안 가능 + +## Key Decisions + +1. **플러그인 구조**: `plugins/obsidian-brain/` 독립 플러그인으로 생성 +2. **트리거 방식**: `/obsidian-archive` command (명시적 호출) +3. **노트 형태**: Zettelkasten — 하나의 개념 = 하나의 노트, wikilink 연결 +4. **연결 방식**: Claude가 기존 노트를 읽고 의미적 관계를 판단하여 연결 +5. **사용자 개입**: 드래프트 제시 → 수정 제안 가능 → 승인 후 저장 +6. **vault 구조**: 새로 시작 — 스킬과 함께 설계 +7. **활용 목적**: 개인 레퍼런스 + Claude 컨텍스트 (양방향 지식 순환) +8. **기존 obsidian 플러그인 의존**: vault 탐색, 파일 생성 등 기본 동작은 기존 스킬 활용 +9. **vault 경로**: 첫 실행 시 사용자에게 질문하여 저장 +10. **파일명**: 타임스탬프 기반 (`YYYYMMDDHHmmss-title.md`) +11. **노트 스캔**: MOC 기반 탐색 (MOC → 관련 노트 순으로 탐색) +12. **컨텍스트 활용**: 사용자 명시적 요청 시만 vault 참조 +13. **언어**: 제목/태그는 영어, 내용은 한국어 + +## Vault Structure (초안) + +``` +vault/ +├── 0-inbox/ # 새 노트가 처음 생기는 곳 +├── 1-zettelkasten/ # 정리된 원자적 노트 +├── 2-maps/ # MOC (Map of Contents) — 주제별 인덱스 노트 +├── templates/ # 노트 템플릿 +│ ├── zettel.md +│ └── moc.md +└── .obsidian/ # Obsidian 설정 +``` + +## Note Template (초안) + +```markdown +--- +id: {{YYYYMMDD}}{{HHmmss}} +title: {{title}} +tags: [{{tags}}] +created: {{date}} +source: claude-session +related: [] +--- + +# {{title}} + +{{content}} + +## Links +- {{wikilinks with relationship type}} + +## Source +- Claude Code 세션 ({{date}}) +``` + +## Resolved Questions + +1. **vault 경로 설정** → command 첫 실행 시 사용자에게 물어보고 저장 +2. **노트 ID 체계** → 타임스탬프 기반 (`202603091430-react-use-transition.md`) +3. **기존 노트 스캔 범위** → MOC 기반 탐색 (MOC를 먼저 읽고, 관련 MOC에 연결된 노트만 깊이 탐색) +4. **auto-invoked skill 트리거** → 사용자 명시적 요청 시만 ("내 노트에서 찾아봐", "이전에 정리한 거 있어?" 등) +5. **다국어 처리** → 혼용 (제목/태그는 영어, 내용은 한국어) diff --git a/docs/plans/2026-03-09-feat-obsidian-brain-plugin-plan.md b/docs/plans/2026-03-09-feat-obsidian-brain-plugin-plan.md new file mode 100644 index 0000000..a854278 --- /dev/null +++ b/docs/plans/2026-03-09-feat-obsidian-brain-plugin-plan.md @@ -0,0 +1,522 @@ +--- +title: "feat: Add obsidian-brain plugin for learning archival automation" +type: feat +status: active +date: 2026-03-09 +origin: docs/brainstorms/2026-03-09-obsidian-brain-brainstorm.md +--- + +# feat: Add obsidian-brain plugin for learning archival automation + +## Enhancement Summary + +**Deepened on:** 2026-03-09 +**Research agents used:** Zettelkasten best practices, Claude Code skill patterns, Knowledge extraction patterns, Architecture review, Quality compliance review + +### Key Improvements +1. **트리거 충돌 해소**: 기존 obsidian 스킬과의 상호 배제 경계를 명확히 정의, 양쪽 스킬 모두 수정 +2. **MOC 스캔 알고리즘 교정**: 예산 불일치 수정 (char 기반), Grep 기반 확장성 확보 +3. **vault 경로 전략 변경**: 별도 config 대신 obsidian-cli 해석 재사용, config는 override만 +4. **SKILL.md 콘텐츠 예산 수립**: ~93줄 타겟, references 3개 파일로 분리 +5. **Cold start 개선**: 첫 MOC 자동 생성 (제안 → 승인) +6. **노트 품질 기준 추가**: Zettelkasten 원자성 테스트, 선언형 제목 패턴 + +### New Considerations Discovered +- 기존 obsidian 스킬의 "Zettelkasten", "PKM" 트리거를 범위 조정해야 함 +- Progressive Summarization 패턴을 학습 추출에 적용 가능 +- Orphan note 감지를 `/brain` command에 추가 가능 (향후) + +--- + +## Overview + +Claude Code 대화에서 배운 것을 Obsidian vault에 Zettelkasten 방식으로 자동 아카이빙하는 `obsidian-brain` 플러그인. 두 가지 핵심 기능: (1) `/obsidian-archive` command로 세션 학습 내용 추출 및 저장, (2) `obsidian-brain` auto-invoked skill로 vault 지식을 Claude 컨텍스트에 반영. + +## Problem Statement / Motivation + +- Claude Code로 작업하며 배우는 것들이 대화가 끝나면 사라짐 +- 수동으로 노트를 정리하는 건 번거롭고 일관성 없음 +- 축적된 지식을 다시 Claude에게 참조시키면 더 맥락 있는 답변을 받을 수 있음 +- **양방향 지식 순환**: 학습 → 저장 → 참조 → 더 나은 학습 + +## Proposed Solution + +### Plugin Structure + +``` +plugins/obsidian-brain/ +├── .claude-plugin/ +│ └── plugin.json +├── commands/ +│ ├── obsidian-archive.md # 학습 아카이빙 command +│ └── brain.md # vault 컨텍스트 명시적 로딩 command +├── skills/ +│ └── obsidian-brain/ +│ ├── SKILL.md # auto-invoked skill (컨텍스트 활용) +│ └── references/ +│ ├── vault-setup.md # vault 구조, 경로 해석, 초기화 가이드 +│ ├── templates.md # 노트/MOC 템플릿 정의 +│ └── archive-workflow.md # 학습 추출, 드래프트 형식, 중복 검사 로직 +├── README.md +└── README.ko.md +``` + +### Research Insights: Plugin Architecture + +**References 3-파일 분리 근거** (from skill quality review): +- `vault-setup.md`: 첫 실행 시에만 로딩 — vault 경로 해석, 디렉토리 부트스트랩 +- `templates.md`: 노트 생성 시에만 로딩 — zettel/MOC 템플릿, 파일명 규칙 +- `archive-workflow.md`: `/obsidian-archive` 실행 시에만 로딩 — 추출 기준, 드래프트 형식, 중복 검사 + +이 분리로 SKILL.md body를 ~93줄로 유지 가능 (150줄 한도 내). + +--- + +### Component 1: `/obsidian-archive` Command + +**흐름:** + +``` +/obsidian-archive + │ + ▼ +[vault 경로 확인] ──없음──▶ [사용자에게 질문 → config에 저장] + │ │ + ▼ ▼ +[vault 구조 확인] ──없음──▶ [디렉토리 생성 + 첫 MOC 자동 생성 제안] + │ + ▼ +[현재 세션 분석 → 학습 포인트 추출] + │ + ▼ +[추출 결과 없음?] ──예──▶ ["이 세션에서 아카이빙할 내용을 찾지 못했습니다"] + │ 아니오 + ▼ +[Grep으로 2-maps/ 내 주제 키워드 검색 → 관련 MOC 식별] + │ + ▼ +[상위 3 MOC Read → wikilink 추출 → 관련 노트 최대 5개 Read] + │ + ▼ +[Grep으로 중복 체크 (제목 + 핵심 문구)] + │ + ▼ +[드래프트 생성: 선언형 제목, 내용, wikilink + 관계유형, 태그] + │ + ▼ +[사용자에게 제시 → 수정/승인/거절] + │ + ├─승인──▶ [0-inbox/에 저장 → 관련 MOC 업데이트 → 완료] + ├─수정──▶ [수정 반영 → 다시 제시] + └─거절──▶ [저장 없이 종료] +``` + +**command 파일 (`commands/obsidian-archive.md`) 설계:** + +```yaml +--- +description: Archive learnings from current session to Obsidian vault as Zettelkasten notes +allowed-tools: [Read, Write, Edit, Glob, Grep, Bash] +--- +``` + +command body는 thin wrapper — "Follow the **obsidian-brain** skill's archive workflow. Read `references/archive-workflow.md` for extraction criteria and draft format." 패턴 사용 (see `library-analyzer/commands/analyze.md`). + +### Research Insights: Command Design + +- **`allowed-tools` 명시** (from quality review): 필요한 도구를 선언하여 의도하지 않은 도구 접근 방지 +- **Thin wrapper 패턴** (from skill patterns research): command는 6줄 이내의 진입점, 실제 로직은 skill + references에 위임 +- **`!`command`` 구문 활용 가능**: vault 경로를 동적으로 주입할 수 있으나, config 읽기는 런타임에서 처리 + +--- + +### Component 2: `/brain` Command (명시적 컨텍스트 로딩) + +```yaml +--- +description: Load relevant knowledge from Obsidian vault into current conversation context +argument-hint: [topic] +allowed-tools: [Read, Glob, Grep] +--- +``` + +사용자가 명시적으로 vault 지식을 불러오고 싶을 때 사용. `$ARGUMENTS`로 topic을 받아 MOC 기반 탐색 실행. + +--- + +### Component 3: `obsidian-brain` Auto-Invoked Skill + +**SKILL.md description 설계 — 기존 obsidian 스킬과의 경계:** + +```yaml +--- +name: obsidian-brain +description: > + Use when the user explicitly requests their personal vault notes as + conversational context. Activates on "이전에 정리한 거 있어?", + "내 노트 참고해서 답해줘", "check my notes about", "I wrote something + about this before", "what do my notes say about". Do NOT trigger for + vault management (creating, moving, editing, searching notes) — those + belong to the obsidian skill. Do NOT trigger for generic Obsidian or + Zettelkasten questions. +--- +``` + +### Research Insights: Trigger Delineation (CRITICAL) + +**문제**: 기존 `obsidian` 스킬이 "Zettelkasten", "PKM", "내 노트에서 찾아줘"를 트리거로 사용 중 — `obsidian-brain`과 충돌. + +**해결 — 양쪽 스킬 모두 수정 필요:** + +| 조치 | 대상 | +|------|------| +| "search my vault for context" 제거 (검색 동작과 혼동) | `obsidian-brain` description | +| "내 노트에서 찾아줘" → obsidian 스킬에서 유지, brain에서는 다른 문구 사용 | 양쪽 | +| obsidian 스킬에 "Do NOT activate when user wants vault notes as conversational context" 추가 | `obsidian` SKILL.md | +| "Zettelkasten" 트리거를 obsidian에서 "Zettelkasten vault setup/structure"로 스코프 축소 | `obsidian` SKILL.md | + +**핵심 구분**: **obsidian = vault 관리 (CRUD)**, **obsidian-brain = 지식 활용 (read for context)** + +| 요청 | 담당 스킬 | +|------|-----------| +| "노트 만들어줘", "frontmatter 수정해줘" | `obsidian` | +| "vault에서 X 검색해줘" | `obsidian` | +| "내가 이전에 정리한 거 있어?" | `obsidian-brain` | +| "이 주제에 대해 내 노트 참고해서 답해줘" | `obsidian-brain` | +| `/obsidian-archive` | `obsidian-brain` (command) | + +--- + +## Technical Considerations + +### Vault 경로 해석 (수정됨) + +**전략 변경** (from architecture review): 별도 config 대신 기존 obsidian 스킬의 해석 메커니즘을 **재사용**하고, config는 override로만 사용. + +**해석 우선순위:** +1. `~/.claude/obsidian-brain/config.json`의 `vaultPath` (사용자 override, 있으면 최우선) +2. `obsidian-cli print-default --path-only` (obsidian-cli 설치 시) +3. Obsidian 앱 config에서 default vault 읽기: + - macOS: `~/Library/Application Support/obsidian/obsidian.json` + - Linux: `~/.config/obsidian/obsidian.json` +4. 모두 실패 시: 사용자에게 경로 질문 → config.json에 저장 + +```json +{ + "vaultPath": "/Users/username/obsidian-vault", + "language": "ko" +} +``` + +### Research Insights: Config Storage +- 기존 obsidian 스킬과 **동일한 vault**를 가리키므로 해석 메커니즘 통일이 중요 +- config.json은 override + 추가 설정(언어 등)만 저장 +- 에러 핸들링 추가: config 디렉토리 쓰기 불가 시 인메모리 fallback + +--- + +### Vault 구조 부트스트랩 + +첫 실행 시 vault 경로에 필요한 디렉토리가 없으면 생성을 제안: + +``` +다음 디렉토리를 생성하겠습니다: +- 0-inbox/ +- 1-zettelkasten/ +- 2-maps/ +- templates/ + +진행할까요? +``` + +**Cold Start 개선** (from architecture review): 첫 번째 노트 저장 시 관련 MOC가 없으면, **자동으로 첫 MOC 생성을 제안하고 승인 시 생성**. 단순 제안에 그치지 않고, 첫 노트가 즉시 MOC에 연결되어 시스템의 가치를 첫 사용에서 보여줌. + +--- + +### MOC 스캔 알고리즘 (수정됨) + +**예산 기반 설계** (from architecture review — 기존 10노트×200줄 ≠ 15K chars 불일치 수정): + +``` +총 컨텍스트 예산: 15,000자 (hard limit) + +1. Grep으로 2-maps/*.md 내에서 주제 키워드 검색 → 관련 MOC 파일 식별 + (파일명 매칭이 아닌 내용 기반 — 확장성 확보) +2. 상위 3개 MOC의 전체 내용 Read (~1,000자 × 3 = ~3,000자) +3. MOC에서 [[wikilink]] 추출 +4. 관련 노트 최대 5개 Read (노트당 최대 2,000자 — ~10,000자) +5. 잔여 예산 ~2,000자: 관계 판단용 여유 공간 +``` + +**확장성** (from architecture review): +- MOC 매칭: Grep 기반이므로 수천 개 MOC에서도 동작 +- 중복 검사: Grep으로 `0-inbox/` + `1-zettelkasten/` 내 제목 + 핵심 문구 검색 (전체 노트 Read 대신) +- MOC 25개 항목 초과 시 자동으로 sub-MOC 분리 제안 + +--- + +### 노트 포맷 + +**파일명**: `YYYYMMDDHHmmss-kebab-title.md` +- 배치 저장 시 타임스탬프 충돌 방지: sequential suffix 추가 (`-01`, `-02`, zero-padded 2자리) +- 특수문자(`/`, `\`, `:`, `?`, `*`) 제거, 공백은 하이픈으로, 최대 60자 + +### Research Insights: Zettelkasten Note Quality + +**원자성 테스트** (from Zettelkasten research): +- "하나의 선언형 제목으로 표현할 수 있는가?" → 가능하면 원자적 +- 제목은 **완전한 문장/구** 형태 (e.g., "useTransition defers low-priority state updates" not "useTransition") +- 노트가 하나의 개념/인수/모델/관찰만 포함해야 함 + +**관계 유형 taxonomy** (from Zettelkasten research — 검증 및 보강): + +| 관계 | 의미 | 예시 | +|------|------|------| +| `extends` | 이 개념을 확장/심화 | "Lifetime elision" extends "Rust lifetimes" | +| `prerequisite` | 이 개념을 이해하려면 필요 | "Ownership" is prerequisite for "Borrowing" | +| `example` | 구체적 사례 | "React useMemo" exemplifies "Memoization" | +| `contrast` | 대조되는 개념 | "Composition" contrasts with "Inheritance" | +| `related` | 일반적 관련 | "TS generics" related to "Rust generics" | + +향후 확장 고려: `source`, `supersedes`, `refines`, `contradicts` + +**모든 wikilink에 관계 유형 주석 필수** — 나중에 다시 읽을 때 *왜* 연결했는지 알 수 있어야 함: +```markdown +## Related +- [[rust-ownership]] — prerequisite (ownership 없이 lifetime 이해 불가) +- [[cpp-raii-pattern]] — contrast (C++의 같은 문제 접근법) +``` + +**노트/MOC 템플릿**: `references/templates.md`에 정의 (SKILL.md body에서 분리). + +--- + +### 학습 추출 기준 + +### Research Insights: Knowledge Extraction + +**Progressive Summarization 적용** (from knowledge extraction research): +Claude가 세션을 분석할 때 계층적 추출 적용: +1. **1차**: 세션 전체에서 학습 관련 대화 구간 식별 +2. **2차**: 각 구간에서 핵심 개념/인사이트 추출 +3. **3차**: 각 인사이트를 원자적 노트로 변환 가능한지 판단 + +**추출 대상** (Zettelkasten knowledge atoms 기반): +- **개념 정의** — 새로운 용어나 개념의 경계를 정한 것 +- **패턴 발견** — 디버깅 과정에서 찾은 원인-해결 패턴 +- **모델/관계** — 엔티티 간 관계에 대한 이해 ("A는 B의 특수한 경우") +- **실증적 관찰** — 라이브러리/프레임워크의 실제 동작 확인 + +**제외**: 단순 파일 조작, 설정 변경, 반복 작업, 이미 잘 알고 있는 내용 + +**중복 검사** (from knowledge extraction research): +- Claude의 판단 기반 semantic comparison (embeddings 불필요) +- Grep으로 기존 노트에서 제목 + 핵심 용어 검색 → 유사 노트 발견 시 사용자에게 "병합/별도 생성/건너뛰기" 선택 제시 + +--- + +### MOC 자동 업데이트 + +노트 저장 시 관련 MOC에 wikilink를 자동 추가. +- 매칭되는 MOC가 없으면 새 MOC 생성을 제안 (승인 후 생성) +- MOC 내 항목이 25개 초과 시 sub-MOC 분리 제안 (from Zettelkasten research) +- MOC format: navigation 역할만 — 간단한 wikilink + 한 줄 설명 + +--- + +### 의존성 전략 + +Claude Code 플러그인은 의존성 선언이 불가하므로, `obsidian-brain`은 **자체적으로 vault 조작이 가능**하도록 설계: +- vault 경로 탐색: 다단계 fallback (obsidian-cli → 앱 config → 사용자 질문) +- 파일 생성/수정: Claude의 Read/Write/Edit 도구 직접 사용 +- 검색: Glob/Grep 직접 사용 + +obsidian-cli는 optional enhancement (설치되어 있으면 wikilink-aware move 등에 활용). + +--- + +### 에러 핸들링 + +| 상황 | 대응 | +|------|------| +| vault 경로 무효 | "vault 경로가 변경된 것 같습니다. 새 경로를 알려주세요" | +| config 디렉토리 쓰기 불가 | 인메모리 fallback, 세션 내에서만 유지 | +| obsidian-cli 미설치 | Read/Write/Glob으로 fallback (wikilink-aware move 불가 안내) | +| 세션에 학습 내용 없음 | "이 세션에서 아카이빙할 학습 내용을 찾지 못했습니다" | +| 중복 노트 감지 | "유사한 노트가 이미 있습니다: [[기존노트]]. 병합/별도 생성/건너뛰기?" | +| 파일 쓰기 실패 | 에러 메시지 표시, 드래프트 내용을 텍스트로 제시하여 수동 저장 가능 | +| MOC 25개 항목 초과 | sub-MOC 분리 제안 | + +--- + +## SKILL.md Content Budget + +**~93줄 타겟** (from quality review — 150줄 한도 내 comfortable headroom): + +| 섹션 | 예상 줄수 | +|------|-----------| +| Frontmatter (name + description) | 8 | +| When This Skill Activates | 12 | +| Skill Boundary (obsidian vs obsidian-brain) | 10 | +| Vault Path Resolution (요약) | 8 | +| Context Loading Workflow (요약, 5단계) | 15 | +| Archive Workflow (요약, "Read references/archive-workflow.md") | 10 | +| Iron Rules | 12 | +| References Loading Guide | 10 | +| 여유 | 8 | +| **합계** | **~93** | + +**References Loading Guide 테이블:** + +| Situation | Load | +|-----------|------| +| Setting up vault for the first time | `references/vault-setup.md` | +| Creating new zettel notes or MOC entries | `references/templates.md` | +| Running /obsidian-archive (extraction, draft, dedup) | `references/archive-workflow.md` | + +--- + +## Acceptance Criteria + +### Functional Requirements + +- [ ] `plugins/obsidian-brain/` 디렉토리가 plugin-spec.md 규격을 준수 +- [ ] `/obsidian-archive` command가 현재 세션에서 학습 내용을 추출 +- [ ] 추출된 내용을 Zettelkasten 노트 드래프트로 변환하여 사용자에게 제시 +- [ ] 노트 제목은 선언형 구(declarative phrase) 형태 +- [ ] 사용자가 드래프트를 수정, 승인, 거절할 수 있음 +- [ ] 승인된 노트가 `0-inbox/`에 타임스탬프 기반 파일명으로 저장 +- [ ] MOC 기반으로 기존 노트를 스캔하여 `[[wikilink]]` + 관계유형 연결을 제안 +- [ ] 관련 MOC에 새 노트 링크가 자동 추가됨 +- [ ] Cold start 시 첫 MOC 자동 생성 제안 +- [ ] `/brain [topic]` command가 vault에서 관련 노트를 로딩하여 컨텍스트로 활용 +- [ ] `obsidian-brain` skill이 명시적 요청 시에만 활성화됨 +- [ ] **기존 `obsidian` skill description에 상호 배제 "Do NOT" 절 추가** +- [ ] vault 경로 해석: obsidian-cli → 앱 config → 사용자 질문 순서 +- [ ] vault 구조 없으면 생성 제안 +- [ ] 노트 제목/태그는 영어, 내용은 한국어로 작성 +- [ ] marketplace.json에 플러그인 등록 (keywords ≤ 5개) +- [ ] `1-zettelkasten/` 승격은 v1 범위 밖 — 수동 Obsidian 작업으로 처리 + +### Quality Gates + +- [ ] SKILL.md body ≤ 150 lines (~93줄 타겟, references 3개로 분리) +- [ ] SKILL.md frontmatter은 `name` + `description`만 +- [ ] Description은 "Use when..." 형식 + "Do NOT..." 경계 조건 (≤ 500자) +- [ ] Command frontmatter에 `allowed-tools` 명시 +- [ ] skill-review 통과 (zero errors) +- [ ] README.md에 설치 방법, 사용 예시, vault 구조 설명 포함 + +--- + +## Implementation Phases + +### Phase 0: 기존 obsidian 스킬 수정 (선행 조건) + +**목표**: 트리거 충돌 방지를 위한 기존 스킬 업데이트 + +**파일 수정:** +- `plugins/obsidian/skills/obsidian/SKILL.md` — description에 "Do NOT activate when the user wants to use vault notes as conversational context (e.g., '내 노트 참고해서 답해줘', 'check my notes about X') — that belongs to obsidian-brain" 추가. "Zettelkasten" 트리거를 "Zettelkasten vault setup" 등으로 스코프 축소. + +**Success**: obsidian 스킬이 컨텍스트 활용 요청에 활성화되지 않음 + +### Phase 1: Plugin Skeleton + Vault Setup + +**목표**: 플러그인 구조 생성 및 vault 초기화 로직 + +**파일 생성:** +- `plugins/obsidian-brain/.claude-plugin/plugin.json` +- `plugins/obsidian-brain/skills/obsidian-brain/SKILL.md` (~93줄) +- `plugins/obsidian-brain/skills/obsidian-brain/references/vault-setup.md` +- `plugins/obsidian-brain/skills/obsidian-brain/references/templates.md` +- `plugins/obsidian-brain/skills/obsidian-brain/references/archive-workflow.md` +- `plugins/obsidian-brain/README.md` + +**SKILL.md 콘텐츠 (요약):** +- 트리거 조건 (한국어 + 영어) — 기존 obsidian과 상호 배제 +- vault 경로 해석 (4단계 fallback, 요약) +- 컨텍스트 로딩 워크플로우 (5단계 요약) +- 아카이빙 워크플로우 (references 위임) +- Iron Rules +- References Loading Guide 테이블 + +**Success**: plugin.json이 validate-plugin CI를 통과, SKILL.md ≤ 150줄 + +### Phase 2: `/obsidian-archive` Command + +**목표**: 아카이빙 command 구현 + +**파일 생성:** +- `plugins/obsidian-brain/commands/obsidian-archive.md` + +**command 내용 (thin wrapper):** +1. "Follow the obsidian-brain skill's archive workflow" +2. vault 경로 확인 → `references/vault-setup.md` 참조 +3. 세션 분석 + 추출 → `references/archive-workflow.md` 참조 +4. 노트 생성 → `references/templates.md` 참조 +5. 수정/승인/거절 흐름 +6. 저장 + MOC 업데이트 + +**Success**: `/obsidian-archive` 실행 시 드래프트가 제시되고, 승인 후 vault에 저장됨 + +### Phase 3: `/brain` Command + Context Loading + +**목표**: 명시적 vault 컨텍스트 로딩 + +**파일 생성:** +- `plugins/obsidian-brain/commands/brain.md` + +**Success**: `/brain React hooks` 실행 시 관련 노트가 로딩되어 답변에 반영됨 + +### Phase 4: Marketplace 등록 + README + +**목표**: 배포 준비 + +**파일 수정:** +- `.claude-plugin/marketplace.json`에 obsidian-brain 추가 + +**파일 생성/수정:** +- `plugins/obsidian-brain/README.md` (한국어 버전 포함) + +**Success**: marketplace 등록 완료, skill-review zero errors + +--- + +## Dependencies & Risks + +| 리스크 | 영향 | 완화 | +|--------|------|------| +| 기존 obsidian 스킬과 트리거 충돌 | 잘못된 스킬 활성화 | **Phase 0에서 양쪽 description 수정** + 상호 "Do NOT" 절 | +| MOC 스캔 시 컨텍스트 초과 | 느린 응답, 토큰 낭비 | char 기반 예산 (15K), Grep 기반 매칭 | +| 빈 vault에서 사용성 저하 | 첫 경험이 빈약 | 첫 MOC 자동 생성 제안, 즉시 연결 | +| Claude의 학습 추출 품질 불안정 | 저품질/무관한 노트 생성 | Progressive Summarization 계층 추출 + 원자성 테스트 + 사용자 리뷰 | +| vault 경로 divergence | obsidian과 다른 vault 참조 | obsidian-cli 해석 재사용, config는 override만 | +| SKILL.md 150줄 초과 | 스킬 품질 기준 위반 | 콘텐츠 예산 수립 (~93줄), references 3개 분리 | +| "Hoarder" 안티패턴 | vault에 저품질 노트 축적 | 원자성 테스트 (선언형 제목 가능?), 사용자 승인 필수 | + +--- + +## Sources & References + +### Origin + +- **Brainstorm document:** [docs/brainstorms/2026-03-09-obsidian-brain-brainstorm.md](docs/brainstorms/2026-03-09-obsidian-brain-brainstorm.md) — Key decisions: 별도 플러그인 분리, Zettelkasten 방식, MOC 기반 탐색, 명시적 트리거, 혼용 언어 정책 + +### Internal References + +- Plugin spec: `docs/contributors/plugin-spec.md` +- Skill quality standards: `docs/solutions/quality-maintenance/skill-plugin-quality-review-fixes.md` +- Existing obsidian plugin: `plugins/obsidian/skills/obsidian/SKILL.md` +- Command+skill pattern: `plugins/library-analyzer/commands/analyze.md` +- Persistent state pattern: `plugins/personal-tutor/skills/personal-tutor/SKILL.md` +- Skill review checklist: `plugins/skill-review/skills/skill-review/references/checklist.md` +- Marketplace: `.claude-plugin/marketplace.json` + +### External References (from research) + +- [zettelkasten.de Atomicity Guide](https://zettelkasten.de/atomicity/guide/) — 원자적 노트 구조 +- [Andy Matuschak's Taxonomy of Note Types](https://notes.andymatuschak.org/Taxonomy_of_note_types) — 선언형 제목 +- [Obsidian Rocks MOC Guide](https://obsidian.rocks/maps-of-content-effortless-organization-for-notes/) — MOC 패턴 +- [Progressive Summarization - Forte Labs](https://fortelabs.com/blog/progressive-summarization-a-practical-technique-for-designing-discoverable-notes/) — 계층적 추출 +- [Claude Code Skills Documentation](https://code.claude.com/docs/en/skills) — 스킬 설계 +- [12 Common PKM Mistakes](https://www.dsebastien.net/12-common-personal-knowledge-management-mistakes-and-how-to-avoid-them/) — 안티패턴 diff --git a/plugins/obsidian-brain/.claude-plugin/plugin.json b/plugins/obsidian-brain/.claude-plugin/plugin.json new file mode 100644 index 0000000..5ef0062 --- /dev/null +++ b/plugins/obsidian-brain/.claude-plugin/plugin.json @@ -0,0 +1,12 @@ +{ + "name": "obsidian-brain", + "version": "1.0.0", + "description": "Archive learnings from Claude Code sessions to Obsidian vault as Zettelkasten notes and use vault knowledge as conversational context", + "author": { + "name": "minsoo.web", + "github": "minsoo-web" + }, + "license": "MIT", + "keywords": ["obsidian", "zettelkasten", "knowledge", "archival", "learning"], + "skills": "./skills/" +} diff --git a/plugins/obsidian-brain/README.md b/plugins/obsidian-brain/README.md new file mode 100644 index 0000000..5d0fdc9 --- /dev/null +++ b/plugins/obsidian-brain/README.md @@ -0,0 +1,75 @@ +# obsidian-brain + +Archive learnings from Claude Code sessions to Obsidian vault as Zettelkasten notes and use vault knowledge as conversational context. + +## Install + +```bash +claude install-plugin hamsurang/kit --plugin obsidian-brain +``` + +## Features + +### `/obsidian-archive` — Session Learning Archival + +Extract learnings from the current conversation and save them as atomic Zettelkasten notes. + +``` +/obsidian-archive +``` + +- Scans conversation for concepts, patterns, models, and observations +- Checks for duplicate notes before creating +- Presents drafts for approval — never auto-saves +- Saves to `0-inbox/` and updates MOC in `2-maps/` + +### `/brain` — Load Vault Knowledge + +Load notes from your vault into the current conversation context. + +``` +/brain rust ownership +/brain react hooks +``` + +- Searches MOCs by topic keywords +- Reads up to 5 linked notes within a 15,000 char budget +- Answers questions using your personal knowledge base + +### Auto-invoked Skill + +The `obsidian-brain` skill auto-activates when you reference your notes: + +- "내 노트 참고해서 답해줘" +- "이전에 정리한 거 있어?" +- "check my notes about X" + +## Vault Structure + +``` +vault/ +├── 0-inbox/ # New notes land here +├── 1-zettelkasten/ # Reviewed atomic notes +├── 2-maps/ # MOC (Map of Contents) index notes +└── templates/ # Note templates +``` + +On first run, the plugin offers to create missing directories. + +## Note Format + +Notes use Zettelkasten conventions: + +- **Title**: Declarative English phrase (e.g., "useTransition defers low-priority state updates") +- **Tags**: English, lowercase +- **Content**: Korean +- **Filename**: `YYYYMMDDHHmmss-kebab-title.md` + +## Requirements + +- [obsidian-cli](https://github.com/minsoo-web/obsidian-cli) (recommended for vault path resolution) +- An Obsidian vault + +## Companion Plugin + +Use with the [obsidian](../obsidian) plugin for vault CRUD operations (create, edit, move, search notes). diff --git a/plugins/obsidian-brain/commands/brain.md b/plugins/obsidian-brain/commands/brain.md new file mode 100644 index 0000000..c82a5e5 --- /dev/null +++ b/plugins/obsidian-brain/commands/brain.md @@ -0,0 +1,52 @@ +--- +name: brain +description: > + Explicitly load Obsidian vault knowledge into the current conversation + context. Use when the user wants to reference their personal notes + about a specific topic. +args: "[topic]" +--- + +# /brain — Load Vault Knowledge + +Load notes from Obsidian vault as conversational context. + +## Usage + +``` +/brain rust ownership +/brain react hooks +/brain 이전에 정리한 캐싱 전략 +``` + +## Prerequisites + +1. Load `references/vault-setup.md` and resolve vault path +2. Verify vault structure exists + +## Execution + +1. **Parse topic** — extract keywords from the argument (or ask if empty) +2. **MOC scan** — Grep `2-maps/*.md` for topic keywords +3. **Read top 3 MOCs** — extract `[[wikilinks]]` from matching MOCs +4. **Read up to 5 linked notes** — prioritize most relevant by keyword match +5. **Fallback search** — if no MOCs matched, Grep `1-zettelkasten/` and `0-inbox/` directly for keywords to find orphan notes not yet linked to any MOC +6. **Context budget** — stay within 15,000 characters total +7. **Present findings** — summarize loaded notes and answer in context + +## Output Format + +``` +vault에서 [N]개 노트를 찾았습니다: + - [[note-1-title]] (from MOC: topic-name) + - [[note-2-title]] (from MOC: topic-name) + +[Answer the user's question using the loaded note content] +``` + +## No Results + +``` +"[topic]"에 대한 노트를 찾지 못했습니다. +검색한 키워드: [terms] +``` diff --git a/plugins/obsidian-brain/commands/obsidian-archive.md b/plugins/obsidian-brain/commands/obsidian-archive.md new file mode 100644 index 0000000..5fec30e --- /dev/null +++ b/plugins/obsidian-brain/commands/obsidian-archive.md @@ -0,0 +1,32 @@ +--- +name: obsidian-archive +description: > + Extract learnings from the current Claude Code session and archive them + as Zettelkasten notes in Obsidian vault. Use when the user wants to save + what they learned during a coding session. +--- + +# /obsidian-archive — Session Learning Archival + +Archive learnings from the current conversation to Obsidian vault. + +## Prerequisites + +1. Load `references/vault-setup.md` and resolve vault path +2. Verify vault structure exists (create if needed with user approval) + +## Execution + +Load `references/archive-workflow.md` and follow steps 1–5: + +1. **Session Analysis** — scan conversation for learnings using Progressive Summarization +2. **MOC Scan** — Grep `2-maps/*.md` for related topics (15,000 char budget) +3. **Duplicate Detection** — check `0-inbox/` and `1-zettelkasten/` for existing notes +4. **Draft Generation** — present drafts for user approval (load `references/templates.md`) +5. **Save & Update MOC** — write to `0-inbox/`, update or create MOC in `2-maps/` + +## Important + +- Never auto-save — always get user approval first +- If no learnings found, say: "이 세션에서 아카이빙할 학습 내용을 찾지 못했습니다." +- Support modification loop: user can edit title, tags, connections, content before saving diff --git a/plugins/obsidian-brain/skills/obsidian-brain/SKILL.md b/plugins/obsidian-brain/skills/obsidian-brain/SKILL.md new file mode 100644 index 0000000..8c14e00 --- /dev/null +++ b/plugins/obsidian-brain/skills/obsidian-brain/SKILL.md @@ -0,0 +1,94 @@ +--- +name: obsidian-brain +description: > + Use when the user explicitly requests their personal vault notes as + conversational context. Activates on "이전에 정리한 거 있어?", + "내 노트 참고해서 답해줘", "check my notes about", "I wrote something + about this before", "what do my notes say about". Do NOT trigger for + vault management (creating, moving, editing, searching notes) — those + belong to the obsidian skill. Do NOT trigger for generic Obsidian or + Zettelkasten questions. +--- + +# Obsidian Brain — Vault Knowledge as Context + +Use vault notes as conversational context and archive session learnings as Zettelkasten notes. + +## Skill Boundary + +| Intent | Skill | +|--------|-------| +| Create, edit, move, search notes | `obsidian` | +| Use vault knowledge as context | `obsidian-brain` ✅ | +| Archive session learnings | `/obsidian-archive` command | +| Explicitly load vault context | `/brain` command | + +## Vault Path Resolution + +Resolve once per session, cache for reuse: + +1. **User override**: `~/.claude/obsidian-brain/config.json` → `vaultPath` +2. **obsidian-cli**: `obsidian-cli print-default --path-only` +3. **Obsidian app config**: `~/Library/Application Support/obsidian/obsidian.json` +4. **Ask user**: "Obsidian vault 경로를 알려주세요" + +If vault path is invalid, clear config and re-resolve. See `references/vault-setup.md` for details. + +## Context Loading Workflow + +When the user asks to reference their notes: + +1. **Parse query** — extract topic keywords from the user's request +2. **MOC scan** — Grep `2-maps/*.md` for keywords, read top 3 matching MOCs +3. **Note retrieval** — extract `[[wikilinks]]` from MOCs, read up to 5 linked notes +4. **Fallback search** — if MOC scan finds nothing, Grep `1-zettelkasten/` and `0-inbox/` directly for keywords (catches orphan notes not linked to any MOC) +5. **Context budget** — stay within 15,000 characters total: + - 3 MOCs × ~1,000 chars = ~3,000 + - 5 notes × ~2,000 chars = ~10,000 + - Remaining ~2,000 for relationship context +6. **Present** — summarize what was found, answer the user's question using note content + +### If No Notes Found + +``` +이 주제에 대한 노트를 찾지 못했습니다. +관련 키워드: [searched terms] +``` + +### Cold Start (Empty Vault) + +If `2-maps/` is empty or missing, inform the user: +``` +vault에 아직 노트가 없습니다. /obsidian-archive 로 학습 내용을 저장해보세요. +``` + +## Archive Workflow + +The `/obsidian-archive` command handles learning extraction. It follows: + +1. **Session analysis** — Progressive Summarization으로 학습 추출 +2. **MOC scan** — 기존 노트와 관련성 검색 +3. **Duplicate detection** — 중복 노트 확인 +4. **Draft generation** — 사용자 승인/수정 루프 +5. **Save** — `0-inbox/`에 저장, MOC 업데이트 + +Full workflow details in `references/archive-workflow.md`. +Note and MOC templates in `references/templates.md`. + +## Iron Rules + +1. **Never auto-save** — always present drafts for user approval +2. **Respect context budget** — never exceed 15,000 chars in MOC scan +3. **Atomic notes only** — one idea per note, declarative English title +4. **Korean content** — note body is always in Korean +5. **No forced archival** — if no learnings found, say so honestly +6. **Vault path first** — resolve vault path before any file operation +7. **Grep over glob** — use Grep to search inside MOCs, not read-all + +## References Loading Guide + +| Situation | Load | +|-----------|------| +| First run, vault setup needed | `references/vault-setup.md` | +| Creating notes or MOCs | `references/templates.md` | +| Running /obsidian-archive | `references/archive-workflow.md` | diff --git a/plugins/obsidian-brain/skills/obsidian-brain/references/archive-workflow.md b/plugins/obsidian-brain/skills/obsidian-brain/references/archive-workflow.md new file mode 100644 index 0000000..7daab59 --- /dev/null +++ b/plugins/obsidian-brain/skills/obsidian-brain/references/archive-workflow.md @@ -0,0 +1,158 @@ +# Archive Workflow Reference + +Load this reference when running `/obsidian-archive` to extract and save learnings. + +## Step 1: Session Analysis — Learning Extraction + +Apply Progressive Summarization to extract learnings from the current conversation: + +1. **Scan**: Identify conversation segments where learning occurred (not operational segments like "rename this file") +2. **Extract**: From each segment, identify the core insight or concept +3. **Atomize**: Can each insight be expressed as a single declarative title? If not, split further + +### What Qualifies as a Learning + +Extract these knowledge atom types: + +| Type | Description | Example | +|------|-------------|---------| +| **Concept** | New term or idea with defined boundaries | "useTransition is a hook for concurrent rendering" | +| **Pattern** | Reusable cause-solution discovered during debugging | "N+1 queries solved by eager loading with includes" | +| **Model** | Relationship between entities | "Ownership is prerequisite for understanding Borrowing" | +| **Observation** | Confirmed behavior of a library/framework | "Next.js App Router caches fetch by default" | + +### What to Exclude + +- Simple file operations (rename, move, delete) +- Configuration changes (env vars, settings) +- Repetitive tasks the user already knows +- Operational commands (git, npm, docker) unless a new pattern was discovered + +### No Learnings Found + +If the session contains no extractable learnings, respond: +"이 세션에서 아카이빙할 학습 내용을 찾지 못했습니다." + +Do not force creation of low-quality notes. + +## Step 2: MOC Scan — Find Related Notes + +**Context budget: 15,000 characters total** + +``` +1. Use Grep to search inside 2-maps/*.md for the topic keywords + - Grep pattern: key terms from the extracted learnings + - This scales to thousands of MOCs (no need to read all) + +2. Read the top 3 most relevant MOCs fully (~1,000 chars × 3 = ~3,000 chars) + +3. Extract [[wikilink]] references from those MOCs + +4. Read up to 5 linked notes (max 2,000 chars per note = ~10,000 chars) + +5. Remaining budget ~2,000 chars for relationship judgment +``` + +If no MOCs exist (empty vault / cold start): skip this step entirely. + +## Step 3: Duplicate Detection + +Before generating drafts, check for existing notes that cover the same concept: + +1. Use Grep to search `0-inbox/` and `1-zettelkasten/` for: + - The proposed note title (or key phrases from it) + - Core technical terms from the extracted learning +2. If a similar note is found, present options: + +``` +유사한 노트가 이미 있습니다: + [[20260308-rust-ownership-ensures-memory-safety]] + +어떻게 할까요? +1. 병합 — 기존 노트에 새 내용 추가 +2. 별도 생성 — 새 노트를 만들고 기존 노트와 연결 +3. 건너뛰기 — 이 학습은 아카이빙하지 않음 +``` + +## Step 4: Draft Generation + +For each extracted learning, generate a draft using the zettel template (see `references/templates.md`). + +### Draft Presentation Format + +**Single note:** +``` +아카이빙 드래프트 + +제목: useTransition defers low-priority state updates +태그: #react, #hooks, #concurrent-rendering +연결: + - [[20260309-react-hooks-overview]] — extends + - [[20260308-concurrent-mode]] — related (concurrent rendering의 핵심 hook) + +--- +useTransition은 React의 concurrent rendering에서 낮은 우선순위의 상태 +업데이트를 처리하기 위한 hook이다... +--- + +승인 / 수정 / 거절 +``` + +**Multiple notes (batch):** +Present each note with a number, then offer "모두 승인" option: +``` +3개의 노트를 생성하겠습니다: + +[1/3] Rust lifetimes ensure references never outlive their data + 태그: #rust, #lifetimes, #memory-safety + 연결: [[20260308-rust-ownership]] — prerequisite + +[2/3] Lifetime elision rules reduce annotation burden + 태그: #rust, #lifetimes, #compiler + 연결: [1/3] — extends + +[3/3] Static lifetime means the reference lives for the entire program + 태그: #rust, #lifetimes, #static + 연결: [1/3] — extends + +모두 승인 / 개별 검토 / 모두 거절 +``` + +### Modification Loop + +When user requests changes: +- "제목 바꿔줘" → regenerate title +- "태그 추가해줘" → add tags +- "연결 제거해줘" → remove wikilink +- "내용 수정해줘" → edit content +- For batch: "2번 수정" → modify only note #2 + +Re-present the modified draft for approval. + +## Step 5: Save and Update MOC + +After user approves: + +1. **Save note** to `0-inbox/` — always `0-inbox/`, never directly to `1-zettelkasten/` + - `1-zettelkasten/` is for reviewed notes that the user has manually promoted + - Use Write tool to create the file + - Verify the file was created successfully + +2. **Update related MOC** — if a relevant MOC was found in Step 2: + - Use Edit tool to append the new note's wikilink to the MOC's `## Notes` section + - Format: `- [[filename]] — brief one-line description` + +3. **Create new MOC** — if no relevant MOC exists: + - Propose: "이 주제에 대한 MOC를 만들까요?" + - If approved, create MOC in `2-maps/` using the MOC template + - Add the new note's wikilink to the MOC + +4. **MOC size check** — if the updated MOC has more than 25 items: + - Suggest splitting: "이 MOC에 항목이 25개를 넘었습니다. 하위 MOC로 분리할까요?" + +5. **Confirmation**: +``` +저장 완료! + 파일: 0-inbox/20260309143022-usetransition-defers-low-priority-updates.md + MOC 업데이트: 2-maps/react-hooks.md +``` diff --git a/plugins/obsidian-brain/skills/obsidian-brain/references/templates.md b/plugins/obsidian-brain/skills/obsidian-brain/references/templates.md new file mode 100644 index 0000000..9107b9a --- /dev/null +++ b/plugins/obsidian-brain/skills/obsidian-brain/references/templates.md @@ -0,0 +1,109 @@ +# Note & MOC Templates + +Load this reference when creating new zettel notes or MOC entries. + +## Zettel Note Template + +```markdown +--- +id: "{{YYYYMMDDHHmmss}}" +title: "{{declarative-title-in-english}}" +tags: + - {{tag1}} + - {{tag2}} +created: "{{YYYY-MM-DD}}" +source: claude-session +--- + +# {{declarative-title-in-english}} + +{{content in Korean — explain the concept in your own words}} + +## Related +- [[{{related-note-filename}}]] — {{relationship-type}} ({{brief reason in Korean}}) +``` + +## MOC (Map of Contents) Template + +```markdown +--- +title: "{{Topic Name}}" +type: moc +updated: "{{YYYY-MM-DD}}" +--- + +# {{Topic Name}} + +## Notes +- [[{{note-filename}}]] — {{brief one-line description}} +``` + +MOC rules: +- Keep under 25 items per MOC — split into sub-MOCs if larger +- MOCs are navigation, not content — annotations should be one-line descriptions +- One note can appear in multiple MOCs + +## Filename Conventions + +**Zettel notes**: `YYYYMMDDHHmmss-kebab-title.md` +- Example: `20260309143022-usetransition-defers-low-priority-updates.md` +- Batch collision: append sequential suffix `-01`, `-02` (zero-padded 2 digits) +- Sanitize: remove `/\:?*"<>|`, replace spaces with hyphens, lowercase, max 60 chars after timestamp + +**MOC files**: `kebab-topic-name.md` in `2-maps/` +- Example: `2-maps/react-hooks.md` + +## Title Guidelines + +Titles must be **declarative phrases** that state the idea, not topic labels: + +| Bad (topic label) | Good (declarative) | +|---|---| +| "useTransition" | "useTransition defers low-priority state updates" | +| "Rust lifetimes" | "Rust lifetimes ensure references never outlive their data" | +| "Docker volumes" | "Docker volumes persist data beyond container lifecycle" | + +The atomicity test: if you cannot express the note's content as a single declarative title, it contains multiple ideas and should be split. + +## Frontmatter Fields + +### Required +| Field | Type | Description | +|-------|------|-------------| +| `id` | string | Timestamp ID `"YYYYMMDDHHmmss"` | +| `title` | string | Declarative English title | +| `tags` | list | English tags, lowercase | +| `created` | string | `"YYYY-MM-DD"` | +| `source` | string | `claude-session` for archived notes | + +### Optional (future) +| Field | Type | Description | +|-------|------|-------------| +| `updated` | string | Last modification date | +| `aliases` | list | Alternative titles for search | + +## Relationship Types + +Every `[[wikilink]]` in the Related section must include a relationship annotation: + +| Type | Meaning | Example | +|------|---------|---------| +| `extends` | Deepens or elaborates | "Lifetime elision" extends "Rust lifetimes" | +| `prerequisite` | Must understand first | "Ownership" is prerequisite for "Borrowing" | +| `example` | Concrete instance | "useMemo caching" exemplifies "Memoization" | +| `contrast` | Opposing approach | "Composition" contrasts with "Inheritance" | +| `related` | General connection | "TS generics" related to "Rust generics" | + +Format in notes: +```markdown +## Related +- [[rust-ownership]] — prerequisite (ownership 없이 lifetime 이해 불가) +- [[cpp-raii-pattern]] — contrast (C++의 같은 문제 접근법) +``` + +## Language Policy + +- **Title**: English (declarative phrase) +- **Tags**: English, lowercase +- **Content**: Korean (자기 말로 이해한 것을 적음) +- **Related annotations**: relationship type in English, reason in Korean diff --git a/plugins/obsidian-brain/skills/obsidian-brain/references/vault-setup.md b/plugins/obsidian-brain/skills/obsidian-brain/references/vault-setup.md new file mode 100644 index 0000000..0dd5ee8 --- /dev/null +++ b/plugins/obsidian-brain/skills/obsidian-brain/references/vault-setup.md @@ -0,0 +1,81 @@ +# Vault Setup Reference + +Load this reference when setting up the vault for the first time or when vault path resolution is needed. + +## Vault Path Resolution + +Resolve the vault path in this order. Stop at the first success: + +1. **User override**: Read `~/.claude/obsidian-brain/config.json` — if `vaultPath` exists and the directory is valid, use it +2. **obsidian-cli**: Run `obsidian-cli print-default --path-only` — if installed and a default vault is set +3. **Obsidian app config**: Read the Obsidian config file for the default vault path: + - macOS: `~/Library/Application Support/obsidian/obsidian.json` + - Linux: `~/.config/obsidian/obsidian.json` + - Windows: `%APPDATA%/obsidian/obsidian.json` +4. **Ask user**: If all above fail, ask: "Obsidian vault 경로를 알려주세요" + - Validate the path exists as a directory + - Save to `~/.claude/obsidian-brain/config.json` + +### Config File Structure + +```json +{ + "vaultPath": "/Users/username/my-vault", + "language": "ko" +} +``` + +Create `~/.claude/obsidian-brain/` directory if it doesn't exist. +If the directory is not writable, use the resolved path in-memory for the current session only. + +### Path Validation + +After resolving the path: +1. Verify the directory exists: `ls ` +2. If the directory does not exist, inform the user: "vault 경로가 변경된 것 같습니다. 새 경로를 알려주세요" +3. Clear the stored config and re-run resolution from step 4 + +## Vault Structure Bootstrap + +Check if the required directories exist inside the vault: + +``` +/ +├── 0-inbox/ +├── 1-zettelkasten/ +├── 2-maps/ +└── templates/ +``` + +If any are missing, propose creation: + +``` +다음 디렉토리를 생성하겠습니다: +- 0-inbox/ (새 노트가 처음 저장되는 곳) +- 1-zettelkasten/ (정리된 원자적 노트) +- 2-maps/ (주제별 MOC 인덱스 노트) +- templates/ (노트 템플릿) + +진행할까요? +``` + +Wait for user confirmation before creating directories. + +## Cold Start (Empty Vault) + +When the vault is empty (no MOCs in `2-maps/`): + +1. Skip MOC scanning — there is nothing to scan +2. After the first note is saved to `0-inbox/`, **propose creating the first MOC**: + +``` +첫 번째 노트가 저장되었습니다. 이 주제에 대한 MOC(Map of Contents)를 +만들어서 노트를 연결할까요? + +MOC는 주제별 인덱스 역할을 하며, 나중에 관련 노트를 쉽게 찾을 수 있게 합니다. +``` + +3. If approved, create the MOC in `2-maps/` using the MOC template (see `references/templates.md`) +4. Add the first note's wikilink to the new MOC + +This ensures the first use demonstrates the full value of the Zettelkasten system. diff --git a/plugins/obsidian/.claude-plugin/plugin.json b/plugins/obsidian/.claude-plugin/plugin.json index 098f5bb..524b8c9 100644 --- a/plugins/obsidian/.claude-plugin/plugin.json +++ b/plugins/obsidian/.claude-plugin/plugin.json @@ -1,6 +1,6 @@ { "name": "obsidian", - "version": "1.0.1", + "version": "1.0.2", "description": "Work with Obsidian vaults — search, create, edit, organize notes and manage frontmatter via obsidian-cli and direct file access", "author": { "name": "minsoo.web", diff --git a/plugins/obsidian/skills/obsidian/SKILL.md b/plugins/obsidian/skills/obsidian/SKILL.md index e5fec68..02e6a6c 100644 --- a/plugins/obsidian/skills/obsidian/SKILL.md +++ b/plugins/obsidian/skills/obsidian/SKILL.md @@ -2,12 +2,16 @@ name: obsidian description: > Use when the user mentions Obsidian, vault, daily notes, wikilinks, - frontmatter, backlinks, graph view, PKM, Zettelkasten, or obsidian-cli. - Activates for searching, creating, editing, moving notes in an Obsidian - vault, managing YAML frontmatter, or syncing vaults via Obsidian Headless - (ob CLI). Also trigger on Korean phrases like "내 노트에서 찾아줘" or - "vault 동기화". Do NOT trigger for generic Markdown editing (README, docs) - or other note apps (Notion, Bear). + frontmatter, backlinks, graph view, or obsidian-cli. Activates for + searching, creating, editing, moving notes in an Obsidian vault, + managing YAML frontmatter, setting up Zettelkasten vault structure, + or syncing vaults via Obsidian Headless (ob CLI). Also trigger on + Korean phrases like "노트 만들어줘", "vault 동기화", or "frontmatter + 수정해줘". Do NOT trigger for generic Markdown editing (README, docs) + or other note apps (Notion, Bear). Do NOT activate when the user wants + to use vault notes as conversational context (e.g., "내 노트 참고해서 + 답해줘", "check my notes about X", "이전에 정리한 거 있어?") — that + belongs to the obsidian-brain skill. --- # Obsidian Vault Skill