| name | km-workflow |
| description | 6-phase workflow for content extraction, analysis, and export to Obsidian/Notion |
Knowledge Manager Workflow
Complete 6-phase workflow guide for content processing
Workflow Overview
Phase 0: Load Configuration
โ
Phase 1: Detect Input Source
โ
Phase 1.5: Collect User Preferences
โ
Phase 2: Extract Content
โ
Phase 3: Analyze Content
โ
Phase 4: Select Output Format
โ
Phase 5: Execute Export
โ
Phase 6: Verify and Report
๐ MANDATORY WORKFLOW - ์ ๋ ๊ฑด๋๋ฐ์ง ๋ง์ธ์!
Antigravity/Gemini CLI์์ ๋ฐ๋์ ์คํ:
STEP 1: ์ฌ์ฉ์ ์ ํธ๋ ํ์ธ (Phase 1.5) - ํ์!
์ฝํ
์ธ ์ฒ๋ฆฌ ์ ๋ฐ๋์ ์๋ ์ง๋ฌธ์ ์ฌ์ฉ์์๊ฒ ๋ฌผ์ด์ผ ํฉ๋๋ค:
๐ ์์ธ ์์ค: 1.์์ฝ / 2.๋ณดํต / 3.์์ธ
๐ฏ ์ค์ ์์ญ: A.๊ฐ๋
/ B.์ค์ฉ / C.๊ธฐ์ / D.์ธ์ฌ์ดํธ / E.์ ์ฒด
๐ ๋
ธํธ ๋ถํ : โ ๋จ์ผ / โก์ฃผ์ ๋ณ / โข์์์ / โฃ3-tier
๐ ์ฐ๊ฒฐ ์์ค: ์ต์ / ๋ณดํต / ์ต๋
๊ธฐ๋ณธ๊ฐ(3.์์ธ, E.์ ์ฒด, โฃ3-tier, ์ต๋)์ ์ฌ์ฉํ์๊ฒ ์ต๋๊น?
๐ก 3-tier๋? ๊ฐ์ ๋
ธํธ + ์ฃผ์ ๋ณ ๋
ธํธ + ์์์ ๋
ธํธ๋ก ๊ณ์ธต ๊ตฌ์กฐํ
์์
๋ฏธ๋์ด(Threads/Instagram) URL์ธ ๊ฒฝ์ฐ ์ถ๊ฐ ์ง๋ฌธ:
๐ ๋ต๊ธ ์์ง ๋ฒ์:
1) depth=1: ์ง์ ๋ต๊ธ๋ง (๋น ๋ฆ)
2) depth=2: ๋ต๊ธ์ ๋ต๊ธ๊น์ง (๋ ์์ ํ ๋งฅ๋ฝ)
โ ๏ธ ์ด ๋จ๊ณ๋ฅผ ๊ฑด๋๋ฐ๋ฉด ์ ๋ฉ๋๋ค!
- ์ฌ์ฉ์๊ฐ "๋น ๋ฅด๊ฒ", "๊ธฐ๋ณธ์ผ๋ก" ๋ฑ ํต ํ๋ฆฌ์
ํค์๋๋ฅผ ์ฌ์ฉํ ๊ฒฝ์ฐ๋ง ์๋ต ๊ฐ๋ฅ
- ๊ทธ ์ธ ๋ชจ๋ ๊ฒฝ์ฐ: ๋ฐ๋์ ์ง๋ฌธ ํ ์งํ
STEP 2-0: ์ ์ฅ ๋ฃจํธยท์์น ๊ฒฐ์ (Phase 3.4) - ํ์! ๐ด
์ ์ฅ ๋ฃจํธ๋ backend ์ค์ ์ด ์๋๋ผ ์ฌ์ฉ์๊ฐ ์ฐ ํ๋ก์ ํธ๊ฐ ์ ํ๋ค. ChatGPT Work ๋ก์ปฌ ํ๋ก์ ํธ์์๋ host๊ฐ ์ ๊ณตํ๋ primary ์ฐ๊ฒฐ ํด๋, Codex CLI์์๋ ๋ํ๋ฅผ ์์ํ ์์
๋๋ ํฐ๋ฆฌ, IDE์์๋ ์ ํํ workspace root๋ฅผ target_root๋ก ๊ธฐ๋กํ๋ค. ChatGPT ํ๋ก์ ํธ(๋ก์ปฌ ํ๋ก์ ํธ ์๋)๋ ์ปดํจํฐ ํด๋์ ์ง์ ์ ๊ทผํ์ง ๋ชปํ๋ฏ๋ก target_root๋ฅผ ์ถ์ธกํ์ง ์๋๋ค.
์ฐ์ ์์: ์ฌ์ฉ์๊ฐ ์ด๋ฒ ์์ฒญ์์ ๋ช
์ํ ๋์ ํด๋ > host๊ฐ ์ ๊ณตํ primary project/workspace root > project-scoped ์์ฒญ์ด ์๋ ๋๋ง km-config.json backend. ์ฌ์ฉ์๊ฐ ๋ช
์์ ์ผ๋ก ๋ค๋ฅธ ์ฐ๊ฒฐ ํด๋๋ Notion์ ์ ํํ ๊ฒฝ์ฐ๋ ๊ทธ ์ง์๋ฅผ ๋ฐ๋ฅธ๋ค.
- ๋ฃจํธ ํ์ :
target_root = realpath(host_project_root)๋ก canonicalizeํ๋ค. host๊ฐ primary root์ shell cwd๋ฅผ ๊ตฌ๋ถํ๋ฉด cwd๋ฅผ ํ๋ก์ ํธ ๋ฃจํธ๋ก ์ถ์ ํ์ง ์๋๋ค. project-scoped ์์ฒญ์ธ๋ฐ root๋ฅผ ํ์ธํ ์ ์์ผ๋ฉด ์ ์ฅ์ ์ค๋จํ๊ณ ๋์ ํด๋๋ฅผ ์์ฒญํ๋ค.
- ๊ตฌ์กฐ ์ ๋
(MUST-read):
${target_root}/VAULT-STRUCTURE.md๊ฐ ์์ผ๋ฉด ๊ฒฝ๋ก๋ฅผ ์ ํ๊ธฐ ์ ์ ๋ฐ๋์ readํ๊ณ ๊ทธ ๊ตฌ์กฐ(์: ์ง๊ตฐ/์ฌ์
/์ฐ๋/๋ฌธ์์ข
๋ฅ)์ ๋ง๋ ํด๋๋ฅผ ๊ฒฐ์ ํ๋ค. ์์ผ๋ฉด ${target_root}/MOC-Map.md๋ readํ์ฌ ๊ธฐ์กด ํ๋ธยท๊ด๋ จ ๋ฌธ์ ์ฐ๊ฒฐ์ ์ฌ์ฉํ๋ค. ์ฌ์ฉ์๊ฐ ๊ฒฝ๋ก๋ฅผ ์ง์ ํ์ผ๋ฉด ๊ทธ ์ง์๊ฐ ์ฐ์ ์ด๋ค. read ์คํจยท๋ถ์ฌ ์ ์ ์ต์์ ํด๋๋ฅผ ์ถ์ ์์ฑํ์ง ๋ง๊ณ , ๋ช
์ ๊ฒฝ๋ก๊ฐ ์์ผ๋ฉด target root์ ์ ์ฅํ๊ณ ๊ทธ fallback์ ๋ณด๊ณ ํ๋ค.
- ๊ฒฝ๋ก ๋ด์:
relativePath๋ฅผ ์ ๊ทํํ ๋ค candidate_path = realpath(parent) + filename์ ๊ณ์ฐํ๋ค. candidate_path๊ฐ target_root ๋ฐ์ด๋ฉด ์ ์ฅํ์ง ์๋๋ค(.., ์ ๋๊ฒฝ๋ก, symlink escape ํฌํจ).
- ๋๊ตฌ๋ ๋ฃจํธ ๋ค์ ์ ํ: Obsidian CLI/MCP์ ์ค์ ์ฐ๊ฒฐ ๋ณผํธ๋ฅผ canonicalizeํ์ฌ
target_root์ ๋์ผํ๋ค๊ณ ํ์ธํ ๋๋ง ์ฌ์ฉํ๋ค. ๋ถ์ผ์นยทํ์ธ ๋ถ๊ฐ๋ฉด ํ์ผ ์ฐ๊ธฐ ๋๊ตฌ๋ก target root ์์ ์ ์ฅํ๋ค.
- Provenance: ์ต์ข
๋ณด๊ณ ์ ๊ตฌ์กฐ ๋ฌธ์ read ๊ฒฐ๊ณผ,
target_root, ์ ํํ ์๋ ๊ฒฝ๋ก, ์ ์ฅ ํ ๊ด์ธกํ actual_saved_path๋ฅผ ๋จ๊ธด๋ค.
โ ๏ธ VAULT-STRUCTURE.md ๊ฐ ์๋๋ฐ ์ ์ฝ๊ณ ์ ์ฅ = ์๋ชป๋ ๋์!
โ ๏ธ target_root ๋ฐ(๋ค๋ฅธ ๋ณผํธ)์ ์ ์ฅ = ์๋ชป๋ ๋์!
STEP 2: Vault ๊ฒ์ ๋ฐ ๋
ธํธ ์ฐ๊ฒฐ (Phase 3.5) - ํ์!
๋
ธํธ ์ ์ฅ ์ ๋ฐ๋์ ๊ด๋ จ ๋
ธํธ๋ฅผ ๊ฒ์ํ๊ณ ์ฐ๊ฒฐํฉ๋๋ค.
MOC-Map.md๊ฐ ์์ผ๋ฉด ๊ฒ์ ์ ์ ๋จผ์ ์ฝ๊ณ , ๊ทธ ์์ ๊ธฐ์กด MOCยทํ๋ธ๋ฅผ ๊ฒ์์ด์ wikilink ํ๋ณด์ ๋ฐ์ํฉ๋๋ค. MOC-Map.md๋ ์ฐ๊ฒฐ ์ง๋์ด๋ฉฐ ํด๋ ๊ตฌ์กฐ ์ ๋ณธ์ VAULT-STRUCTURE.md์
๋๋ค.
Step 2-1: ๊ด๋ จ ํค์๋ ์ถ์ถ
์ฝํ
์ธ ์์ ํต์ฌ ํค์๋ ์ถ์ถ:
- ์ฃผ์ ํค์๋ (์: "AI", "ํ๋กฌํํธ", "Claude")
- ์ธ๋ฌผ/๊ณ์ ๋ช
(์: "@openai", "Anthropic")
- ๊ธฐ์ ์ฉ์ด (์: "LLM", "RAG", "embedding")
Step 2-2: Vault ๊ฒ์ ์คํ
keywords = ["AI", "ํ๋กฌํํธ", "Claude"]
if (obsidian_connected_root && same_path(obsidian_connected_root, target_root)) {
keywords.forEach(keyword => mcp_obsidian_search_vault({ query: keyword }))
} else {
keywords.forEach(keyword => search_files({ root: target_root, query: keyword }))
}
Step 2-3: ๊ด๋ จ ๋
ธํธ ์ฝ๊ธฐ ๋ฐ ๋ถ์
๊ฒ์ ๊ฒฐ๊ณผ์์ ์์ ๋
ธํธ๋ค์ ์ฝ์ด ๊ด๋ จ์ฑ ํ์ธ:
search_results.slice(0, 10).forEach(result => {
assert(is_within(realpath(result.path), realpath(target_root)))
read_file(result.path)
})
๊ฒ์ยท์ฝ๊ธฐ๋ ์ ์ฅ๊ณผ ๊ฐ์ root gate๋ฅผ ์ ์ฉํฉ๋๋ค. Obsidian integration/config root๊ฐ target_root์ ๋ค๋ฅด๊ฑฐ๋ ํ์ธ ๋ถ๊ฐ๋ฉด ๊ทธ integration์ผ๋ก ๊ฒ์ํ์ง ์์ต๋๋ค.
Step 2-4: ์ฐ๊ฒฐ ์์ค์ ๋ฐ๋ฅธ ๋งํฌ ์ถ๊ฐ
Phase 1.5์์ ์ ํํ "๐ ์ฐ๊ฒฐ ์์ค"์ ๋ฐ๋ผ ๋งํฌ ๊ฐ์ ๊ฒฐ์ :
| ์ฐ๊ฒฐ ์์ค | ๋งํฌ ๊ฐ์ | ์ค๋ช
|
|---|
| ์ต์ | 1-2๊ฐ | ๊ฐ์ฅ ๊ด๋ จ์ฑ ๋์ ๋
ธํธ๋ง ์ฐ๊ฒฐ |
| ๋ณดํต (๊ธฐ๋ณธ๊ฐ) | 3-5๊ฐ | ์ฃผ์ ๊ด๋ จ ๋
ธํธ ์ฐ๊ฒฐ |
| ์ต๋ | 5-10๊ฐ | ๊ด๋ จ ๊ฐ๋ฅ์ฑ ์๋ ๋ชจ๋ ๋
ธํธ ์ฐ๊ฒฐ |
Step 2-5: Wikilink ํ์์ผ๋ก ๋
ธํธ์ ์ถ๊ฐ
## ๊ด๋ จ ๋
ธํธ
- [[AI-ํ๋กฌํํธ-๊ธฐ์ด]]
- [[Claude-์ฌ์ฉ-๊ฐ์ด๋]]
- [[LLM-ํ์ฉ๋ฒ]]
โ ๏ธ Vault ๊ฒ์ ์์ด ์ ์ฅ = ์๋ชป๋ ๋์!
โ ๏ธ ๊ด๋ จ ๋
ธํธ ๋ฐ๊ฒฌํ๋๋ฐ wikilink ์ ํจ = ์๋ชป๋ ๋์!
STEP 3: ์ ์ฅ ๋๊ตฌ ์ ํ (Phase 5) - ํ์!
๋์์น: ํ์ผ์ STEP 2-0์์ ํ์ ํ target_root ์ ๊ฒฝ๋ก์ ๋จ์ด์ ธ์ผ ํ๋ค. ๋๊ตฌ๋ ๊ทธ ๋ค์ ๋ฌธ์ ๋ค.
| ํ๊ฒฝ | 1์์ | ์กฐ๊ฑด๋ถ | ์ ๋ ๊ธ์ง |
|---|
| ChatGPT Work / Codex | ํ์ผ ์ฐ๊ธฐ ๋๊ตฌ(target_root ์๋ ๊ฒฝ๋ก) | mcp_obsidian_create_note โ Obsidian ๋ณผํธ = target_root์ผ ๋๋ง | target_root ๋ฐ ์ ์ฅ |
| Antigravity | mcp_obsidian_create_note โ ๋ณผํธ = ์์
๋์ ๋ณผํธ ํ์ธ ํ | write_to_file (MCP ๋ถ๊ฐ ์) | ์์
๋์ ๋ฐ ์ ์ฅ |
| Gemini CLI | mcp_obsidian_create_note โ ๋ณผํธ = ์์
๋์ ๋ณผํธ ํ์ธ ํ | write_to_file (MCP ๋ถ๊ฐ ์) | ์์
๋์ ๋ฐ ์ ์ฅ |
โ ๏ธ Obsidian MCP๊ฐ ์ฐ๊ฒฐํ ๋ณผํธ โ target_root์ธ๋ฐ MCP๋ก ์ ์ฅ = ์๋ชป๋ ๋์!
Phase 0: Load Configuration (CRITICAL)
Must execute before all operations
target_root = resolve_host_project_root()
config = Read("km-config.json") || {}
if (is_project_scoped_request() && !target_root) {
return "Project root could not be verified. Ask the user to select a target folder."
}
storage_config = config.storage || {}
storage = {
primary: storage_config.primary,
obsidian: storage_config.obsidian,
notion: storage_config.notion,
local: storage_config.local
}
browser_config = config.browser || {}
browser = {
provider: browser_config.provider,
hyperbrowser: browser_config.hyperbrowser
}
Phase 1: Detect Input Source
Input Type Detection
| Input Pattern | Type | Processing |
|---|
https://threads.net/* | Social Media | โ km-browser-abstraction (stealth recommended) |
https://instagram.com/* | Social Media | โ km-browser-abstraction (stealth recommended) |
https://* | Web URL | โ km-browser-abstraction |
*.hwp *.hwp3 *.hwpx *.hwpml | ํ๊ธ File | โ km-content-extraction (npx kordoc ์๋ ๋ณํ) |
*.pdf | PDF File | โ km-content-extraction (Read 1์์) |
*.docx *.xlsx | Office File | โ km-content-extraction (anydoc 1์์) |
๊ธฐํ ๋ก์ปฌ ํ์ผ (*.md *.txt *.csv ๋ฑ) | Local File | โ km-content-extraction |
notion.so/* | Notion Page | โ Notion MCP |
Phase 2: Extract Content
์
๋ ฅ ์ ํ์ ๋จผ์ ํ์ ํ๊ณ ๋ผ์ฐํ
ํ๋ค โ ๋๊ตฌ ํธ์ถ ์์ด ์ฝํ
์ธ ์ถ์ธก ๊ธ์ง.
A. Local file input โ Content Extraction Router
โ See km-content-extraction skill (๋ก์ปฌ ๋ฌธ์ ํ์๋ณ ํ์ ๋๊ตฌ ํ)
ํต์ฌ ๊ท์น ์์ฝ:
| ํ์ผ ํ์ | ํ์ ๋๊ตฌ |
|---|
| ํ๊ธ (HWP/HWPX) | npx kordoc <files> -d <outdir> โ ๋ณํ md ๋ฅผ Read (์๋ โ ์ฌ์ฉ์์๊ฒ ์๋ ๋ณํ์ ์๊ตฌํ์ง ์๋๋ค) |
| PDF | Read โ ์คํจ ์ km-content-extraction ์ ๋ค๋จ ๊ฒฝ๋ก |
| DOCX/XLSX | npx -y @firecrawl/anydoc "[ํ์ผ]" โ ๊นจ์ง๋ฉด kordoc |
| TXT/MD/CSV/์ด๋ฏธ์ง | Read |
B. URL input โ Browser Abstraction Layer
โ See km-browser-abstraction skill
content = scrape_url(url, {
stealth: inputType.requiresStealth
})
Phase 3: Analyze Content
Apply Zettelkasten Principles
- Atomicity: One idea = One note
- Self-contained: Note is understandable on its own
- Connectivity: Links between related concepts
Phase 4-6: Export and Verify
Use Storage Abstraction Layer
โ See km-storage-abstraction skill
result = save_note(relativePath, content, {
target_root: target_root,
project_scoped: true
})
actual_saved_path = realpath(result.path || `${target_root}/${relativePath}`)
assert(file_exists(actual_saved_path))
assert(is_within(actual_saved_path, realpath(target_root)))
๋
ธํธ ํ์ผ ํ์ ๊ท์น (frontmatter โ ํ์!)
frontmatter ๊ฐ "์๋๋ฐ ์ ์ฉ์ด ์ ๋๋" ๊ฒฐํจ์ ์์ธ์ ๋๋ถ๋ถ ํ์ผ ๋งจ ์์ด --- ๊ฐ ์๋์ด์๋ค. ์ ์ฅํ๋ ๋ชจ๋ ๋
ธํธ์ ๊ฐ์ :
- ํ์ผ์ ์ฒซ ์ค =
--- โ ๊ทธ ์์ ๋น ์คยท์ ๋ชฉยท์๋ด ๋ฌธ์ฅยทBOM ๋ฑ ์ด๋ค ๊ฒ๋ ๋์ง ์๋๋ค. (ํ ๊ธ์๋ผ๋ ์์ ์์ผ๋ฉด Obsidian ์ด frontmatter ๋ก ์ธ์ํ์ง ์๋๋ค)
- frontmatter ๋
--- โฆ --- ๋ก ๋ซ๊ณ , ๋ด๋ถ๋ ์ ํจํ YAML(ํญ โ ์คํ์ด์ค ๋ค์ฌ์ฐ๊ธฐ, ์ฝ๋ก ๋ค ๊ณต๋ฐฑ). ๊ฐ์ ์ฝ๋ก (:)ยท#ยท๋ฐ์ดํ๊ฐ ๋ค์ด๊ฐ๋ฉด ๊ฐ ์ ์ฒด๋ฅผ "โฆ" ๋ก ๊ฐ์ผ๋ค โ ์: title: "๋ณด๊ณ ์: 8์๋ถ" (๋ฌด์ธ์ฉ์ด๋ฉด ํ์ฑ์ด ๊นจ์ ธ ์์ฑ ์ ์ฒด๊ฐ ๋ฏธ์ ์ฉ๋๋ค โ ์ค์ธก ์ต๋ค ์์ธ).
- ๋
ธํธ ์ ์ฒด๋ฅผ ``` ์ฝ๋ํ์ค๋ก ๊ฐ์ธ์ ์ ์ฅ โ โ ์ฝ๋ํ์ค ์์
--- ๋ frontmatter ๊ฐ ์๋๋ค.
- ์ ์ฅ ํ ๊ฒ์ฆ: ํ์ผ ์ฒซ 3๋ฐ์ดํธ๊ฐ
--- ์ธ์ง ํ์ธ(์: head -c 3 <ํ์ผ>). ์๋๋ฉด ์ฌ์ ์ฅ.
Final Report Template
## โ
Processing Complete!
### Input
- Source: {url or filename}
- Type: {web / file / social media}
### Saved Notes
| Title | Path | Status |
|-------|------|--------|
| {note1} | {path1} | โ
|
### ๐ ์ ์ฅ ์์น (Provenance โ ํ์!)
- ๋ณผํธ(์ ์ฅ ๋ฃจํธ): {์ ์ฅ ๋ฃจํธ ์ ๋ ๊ฒฝ๋ก ๋๋ ํ๋ก์ ํธ ํด๋๋ช
}
- ์ ์ฅ ๊ฒฝ๋ก: {๋ณผํธ ๊ธฐ์ค ์๋ ๊ฒฝ๋ก โ ์: 03_ํต๊ณ์ง/2026/๋ณด๋์๋ฃ/๋
ธํธ.md}
- ์ค์ ์ ์ฅ ๊ฒฝ๋ก: {์กด์ฌ ๊ฒ์ฆํ actual_saved_path}
- ์ ์ฉ ๊ท์น: {VAULT-STRUCTURE.md ๊ตฌ์กฐ / ์ฌ์ฉ์ ์ง์ ๊ฒฝ๋ก / ๊ธฐ๋ณธ ๋ฃจํธ(๊ตฌ์กฐ ๋ฌธ์ ์์)}
โ ๏ธ ใ์ ์ฅ ์์นใ ์น์
์ด ์๋ ์๋ฃ ๋ณด๊ณ = ๋ฏธ์์ฑ ๋ณด๊ณ ! ์ฌ์ฉ์๋ ์ด ์ค๋ก ํ์ผ์ด ยซ์ด๋ค ๋ณผํธ์ ์ด๋์ยป ์๊ฒผ๋์ง ์ฆ์ ์๋ค.