Skip to content
Research
Command

/search

vault 통합 검색 — GraphRAG(있으면) → Obsidian CLI → Obsidian MCP → 텍스트 검색 4단계 자동 폴백. quick(즉답)/deep(분석) 자동 라우팅

BOOST
From plugin
km
24810 skills2 agents10 commands
Install
> /plugin marketplace add treylom/knowledge-manager
> /plugin install km@knowledge-manager

How it fires

How this command gets triggered: by you, by Claude, or both.

  • Fires itselfClaude auto-loads it when your prompt matches the work.
  • You can call itInvoke it directly when you want it.
  • Slash command/search

Context preview

What this command does when you run it.

vault 통합 검색 — GraphRAG(있으면) → Obsidian CLI → Obsidian MCP → 텍스트 검색 4단계 자동 폴백. quick(즉답)/deep(분석) 자동 라우팅

Command definition

search.md
description: vault 통합 검색 — GraphRAG(있으면) → Obsidian CLI → Obsidian MCP → 텍스트 검색 4단계 자동 폴백. quick(즉답)/deep(분석) 자동 라우팅
allowedTools: Bash, Read, Glob, Grep, mcp__obsidian__*

/km:search — vault 통합 검색

$ARGUMENTS

> **핵심 설계**: 검색 창구는 이 명령 하나. **① GraphRAG → ② Obsidian CLI → ③ Obsidian MCP → ④ 텍스트 검색** 자동 폴백. GraphRAG 미설치도 ②~④로 동작.

> **찾는 범위**: vault 문서·개념·관계. 과거 대화·결정 경위는 메모리뱅크(Tier 0). 충돌은 `현재 기준`과 `과거 경위`로 나눠 표시. 한쪽 부재 ≠ 다른쪽 부재.

> 🚨 **실행 순서 계약 (고정)**: ① Phase -1 로 `VAULT_PATH`·`SEARCH_ENDPOINT` 읽기 → ② **곧바로 Tier 1 curl**. ①② 전에 vault rg/grep/find/ls/Read ❌. 로컬 파일은 Tier 1 `VAULT_MODE=same` 또는 Tier 1 실패 후만.

> 📎 **참조 로드**: `search-references/` (명령 파일 기준 같은 디렉터리; Codex 스킬 기준 `../../../commands/search-references/`). **정상 Tier 1 성공·QUICK 경로 참조 Read = 0.** 아래 성공 계약을 이 엔트리에서 실행한다. 참조는 Tier 2~4 폴백·DEEP·0건/빈약/lookup exact 0건/부재 단정 때만 조건부 1회 Read — 전부 선로드 ❌. 참조 Read = 규칙 로드(primary read 예산 **미포함**). **증거 노트 Read 기본 = 3** (QUICK 명시·얕은 질의 1-2 · DEEP·요구항목 미충족 ≤5 · 링크 추적 예산은 `phase-2.5-graph.txt`).

Phase -1: 설정 읽기

1. `km-config.json`: 현재 폴더 → setup이 만든 위치 순. `storage.obsidian.vaultPath` → `VAULT_PATH`; 있으면 확정값이며 Obsidian 재대조·경로 추측 금지. 2. vaultPath가 없을 때만 Obsidian `open:true` 경로를 확인한다. 넓은 find·후보 순회 금지:

OBSIDIAN_JSON=$(ls -1 \
  "$HOME/Library/Application Support/obsidian/obsidian.json" \
  /mnt/c/Users/*/AppData/Roaming/obsidian/obsidian.json \
  "$APPDATA/obsidian/obsidian.json" 2>/dev/null | head -1)
python3 -c 'import json,sys;d=json.load(open(sys.argv[1]))["vaults"];print("\n".join(v["path"] for v in d.values() if v.get("open")))' "$OBSIDIAN_JSON"

WSL 경로는 `wslpath -u`. 파일/열린 항목을 못 찾을 때만 사용자에게 1회 묻는다. 사용자 경로는 `.obsidian`·최근 수정 md 유무를 확인하고 둘 다 아니면 사용 전 재확인한다. 3. `obsidianCli.path` → `OBSIDIAN_CLI`(없으면 Tier 2 자동 감지), `obsidianCli.vault` → `OBSIDIAN_VAULT`(없으면 vaultPath basename). 4. endpoint 우선순위 = 설정 → 환경 → 기본값. 미설정도 기본값 탐침. 아래 할당·echo 뒤 Tier 1 실행:

# CONFIG_ENDPOINT = linking.semantic_adapter.endpoint (없으면 빈 값)
SEARCH_ENDPOINT="${CONFIG_ENDPOINT:-${GRAPHRAG_API_URL:-http://127.0.0.1:8400}}"
echo "SEARCH_ENDPOINT=${SEARCH_ENDPOINT}"

Phase 0 — 모드·구조·대상

**Tier 1 curl 이전에는 모드·대상만 결정하고 vault 접근은 금지. Phase 0.4 로컬 구조 문서는 Tier 1 `VAULT_MODE=same` 확인 또는 Tier 1 실패 후 실행한다. `other`에서는 STRUCT_DOCS=0·ROUTE_HUB_COUNT=0, 다른 vault임을 명시하고 구조 접근을 생략한다.**

Phase 0: 모드 결정

query = "$ARGUMENTS"

IF query가 비어있으면: → "사용법: `/km:search <질문>` or `/km:search --deep <질문>`" → "예시: `/km:search MCP란?` | `/km:search --deep 프롬프트 엔지니어링 기법 비교`" → 종료

플래그 파싱

  • `--quick` 또는 `-q` → **QUICK** (플래그 제거 후 나머지가 query)
  • `--deep` 또는 `-d` → **DEEP** (플래그 제거 후 나머지가 query)
  • `--no-moc` → MOC 제외, 원자 노트 전용
  • 플래그 없음 → **AUTO**

AUTO 라우팅

  • DEEP: 문장형 5단어+, "~하려면/방법/비교/차이/관계/영향", 분석 요청("설명해줘/정리해줘"), 복수 개념("A vs B"), 방법론("어떻게/왜")
  • QUICK: 그 외 (키워드 1-3개, 정의형 "~란?", 노트 찾기)

판정 직후 KM_MODE를 QUICK 또는 DEEP로 할당하고 실행(AUTO는 최종값 아님):

echo "KM_MODE=${KM_MODE}"

검색 시작마다 이전 KM_MODE·VAULT_MODE·KM_HITS를 버린다. 아래 마커는 실제 판정값만 출력한다. Bash 호출이 나뉘면 직전 stdout에서 관측한 값을 다음 호출에 명시적으로 재할당한다(셸 변수 지속 가정 금지). 영수증에는 이 검색에서 출력한 동일값을 넘긴다; 미관측 값은 인자를 생략한다.

Phase 0.4: 구조 문서 축 (000-START-HERE)

셋업이 만든 3문서(`START-HERE`·`VAULT-STRUCTURE`·`MOC-Map`)는 **Tier 1 정합 확인 또는 실패 후 본문 근거 확보 전에 먼저 참조**한다 — 있으면 `MOC-Map` 을 Read(≤130줄)해서 질문을 허브에 매핑한 뒤 검색에 들어간다. 입력 변수는 `VAULT_PATH` 와 `QUERY_KEYWORDS`(핵심 키워드 1~3개, 공백 구분) 둘이고, 아래 블록은 그대로 실행할 수 있다.

STRUCT_DIR="${VAULT_PATH}/000-START-HERE"; STRUCT_DOCS=0; STRUCT_MISSING=""
for f in START-HERE VAULT-STRUCTURE MOC-Map; do
  if [ -f "$STRUCT_DIR/$f.md" ]; then STRUCT_DOCS=$((STRUCT_DOCS+1)); else STRUCT_MISSING="$STRUCT_MISSING $f"; fi
done
echo "STRUCT_DOCS=${STRUCT_DOCS}/3 missing=[${STRUCT_MISSING# }]"
# 허브 매핑: MOC-Map 앞 130줄에서 허브마다 «겹친 키워드 수»를 세어 많은 순 ≤3 · 동점 = 지도 위쪽(먼저 나온) 순
# 키워드는 awk 안에서 쪼갠다(zsh 는 $QUERY_KEYWORDS 를 안 쪼갬) · 대소문자 무시 글자 그대로 비교(정규식 ❌) · 허브명은 줄 단위(공백 든 이름 보존)
ROUTE_HUBS=""
if [ -f "$STRUCT_DIR/MOC-Map.md" ]; then
  ROUTE_HUBS="$(head -130 "$STRUCT_DIR/MOC-Map.md" | awk -v kws="$QUERY_KEYWORDS" '
    BEGIN { m = split(tolower(kws), T, " "); for (i = 1; i <= m; i++) if (!(T[i] in U)) { U[T[i]] = 1; K[++n] = T[i] } }
    { l = tolower($0); s = $0
      while (match(s, /\[\[[^]|#]*/)) { h = substr(s, RSTART + 2, RLENGTH - 2); s = substr(s, RSTART + RLENGTH)
        if (!(h in F)) F[h] = NR
        for (i = 1; i <= n; i++) if (index(l, K[i])) M[h SUBSEP i] = 1 } }
    END { for (h in F) { c = 0; for (i = 1; i <= n; i++) if ((h SUBSEP i) in M) c++; if (c) printf "%d\t%d\t%s\n", c, F[h], h } }' \
    | sort -t "$(printf '\t')" -k1,1nr -k2,2n | head -3 | cut -f3)"
fi
ROUTE_HUB_COUNT=$(printf '%s\n' "$ROUTE_HUBS" | awk 'NF' | wc -l | tr -d ' ')
echo "ROUTE_HUBS=[$(printf '%s\n' "$ROUTE_HUBS" | awk 'NF' | paste -sd '|' - | sed 's/|/ | /g')] count=${ROUTE_HUB_COUNT}"
  • `STRUCT_DOCS` 가 3 미만이면 답변에 「구조 문서 없음(<빠진 것>) — `/km:setup` 재실행으로 생성」 1줄을 적고 **그대로 계속 진행**한다(멈춤 ❌).

Phase 0.5: MOC 우선 라우팅

검색 결과 중 MOC 성격 노트(frontmatter `type`/`tags`에 MOC 포함, 또는 파일명에 `-MOC`)를 최상위로 고정한다: 0. `000-START-HERE/` 의 3문서가 결과에 있으면 파일명 축으로 MOC 로 «즉시» 분류하고, Phase 0.4 의 `ROUTE_HUBS` 를 📌 최상단 고정 후보에 합류시킨다. 1. 결과를 MOC / 원자 노트로 분류 2. 상위 최대 3개 MOC를 맨 위로 고정 (점수 순) 3. 원자 노트는 그 아래 점수 순 4. 표시: `📌 상위 MOC (N)` 섹션 + `📄 원자 노트 (N)` 섹션 분리 (MOC 0개면 📌 생략)

> Why: 노트가 많아질수록 원자 나열은 찾기 어려움 — MOC(지도 노트)가 허브·진입점 역할.

Phase 0.6: 대상 고정(target binding) (1.8.1 · Tier 0/1 «앞»에서 1회)

Tier 2 의 0-β 분해 JSON 을 **여기서 먼저** 산출한다(스폰 ❌ · 이 스킬을 실행하는 모델 자신이 도구 호출 전에 JSON 1개). 스키마(참조 없이 생성):

{"intent":"nav|content|relation|meta|tag|temporal|mixed","targets":["노트명 후보 ≤3, 확신순"],"keywords":["핵심어 ≤5"],"tags":["태그 ≤3, # 제거"],"props":{"key":"value"},"path_hint":"폴더 힌트 or null","time":{"recent":false,"date":null},"axes":["bl|ln|prop|ctx|tag|full 실행 순서"],"topn":2}

여기에 다음 2키를 더한다:

  • `target_status`: `resolved`(대상 개체 ≥1 을 질문에서 «근거 있게» 뽑음) · `unspecified`(대상 없는 일반·개념·비교 질문 — 개체를 지어내지 않는다) · `ambiguous`(같은 이름이 2+ 노트·허브에 걸림 — 둘 다 유지하고 라벨).
  • `target_provenance`: {대상: `quote|wikilink|tag|proper_noun|alias:<출처 경로>`} — 별칭(
Read more
Ships withkm

📖 English documentation is available at the bottom of this page. 읽은 글·영상·PDF를 Obsidian 노트로 정리해 주고, 나중에 그 노트를 찾아 주는 Claude Code 플러그인이에요. 링크 하나를 건네면 요약·태그·관련 노트 연결까지 마친 노트가 vault(볼트 — Obsidian 이 노트를 모아 두는 폴더)에 저장되고, 궁금할 땐 /km:search 한 줄로 되찾습니다.

Get the whole plugin

Other commands on km.

interview
Command

interview

지식관리 설계 상담 — 폴더·MOC·wiki 대상·스킬 추천을 KM-DESIGN 문서로

@treylom@treylomInstall Command