knowledge-base
Ingests git commit history (git log) to make development changes and decisions searchable.
Indexes GitHub pull requests and repository code, enabling hybrid search over PRs and code content.
Ingests Slack messages via export or real-time connections, applying age decay to prioritize recent answers, and makes team discussions searchable.
Click on "Install Server".
Wait a few minutes for the server to deploy. Once ready, it will show a "Started" state.
In the chat, type
@followed by the MCP server name and your instructions, e.g., "@knowledge-basesearch for deployment lock timeout"
That's it! The server will respond to your query, and you can continue using it as needed.
Here is a step-by-step guide with screenshots.
knowledge-base
여러 소스(문서, git 로그, Slack, …)의 팀 지식을 하나의 Postgres 임베딩 테이블로 수집하고, 하이브리드 검색(전문검색 + 벡터 + RRF 융합)을 MCP 도구로 노출하는 지식 베이스 서버.
Inspired by Cerebras’ "How We Built Our Knowledge Base".
핵심 원칙:
정보가 사는 곳에서 그대로 추출 — 커넥터가 소스별로 행을 정규화해 같은 테이블에 쓴다. 테이블에 들어가면 즉시 같은 인터페이스로 검색된다.
하이브리드 검색 — 전문검색(정확 토큰: 에러 문자열·설정 키)과 벡터 검색(개념 질의)을 RRF(k=60)로 융합. Slack 문서에는 나이 감쇠("옛 답변은 만료된다") 적용.
MCP에는 LLM-free 검색 프리미티브만 — 합성된 답이 아니라 원시 증거 행을 반환. 오케스트레이션과 답변 생성은 Claude Code 같은 클라이언트 에이전트의 몫.
에이전트가 쓰는 지식 베이스 — 개발 중 내린 의사결정(
record_decision)과 삽질에서 얻은 교훈(record_learning)을 MCP로 직접 기록하면 즉시 팀 전체가 검색 가능. 작업 전pitfalls로 과거에 밟은 문제를 확인해 같은 실수를 반복하지 않는다 → 팀 워크플로 가이드.
SOURCES markdown · git log · Slack(export/실시간) · 코드 저장소 · GitHub PR · (커스텀)
│ sync (커넥터가 SourceRow 방출) ┌ 에이전트/사람이 MCP로 직접 기록
PIPELINE 해시 dedup → [대화형: LLM 증류] → 청킹(헤딩 인지) → [문맥 생성] → 임베딩
│ upsert └ record_decision / learning / note
POSTGRES documents(원문+FTS) + chunks(임베딩+문맥) — 단일 임베딩 테이블
│ query
SEARCH FTS(희귀토큰 OR/접두) + 벡터 + IDF + trigram + 문맥FTS → 가중 RRF(k=60)
│ → 나이 감쇠 · boost/숨김 · supersede 감점 · 소스별 중복 상한
INTERFACES kb CLI · MCP 서버(stdio 로컬 / Streamable HTTP 원격 — 토큰 또는 OAuth 인증)
읽기: search·get_document·list_sources·who_knows·recent_changes
·search_code·subsystem_index·recent_prs
쓰기: record_decision·learning·note·verify_note·search_feedback / 예방: pitfalls
웹 대시보드(:8080) — 운영 헬스 · 모델/API 비용 · 쿼리 분석 · 질문(/ask)
· 노트 재검증/중복 큐 · 토큰/프로젝트 관리1. 요구사항
항목 | 버전 | 비고 |
Python | 3.11+ | tomllib 사용 |
PostgreSQL | 14+ (16에서 테스트) | |
pgvector | 0.5+ (0.6에서 테스트) | HNSW 인덱스 사용. halfvec(2000차원 초과·메모리 절감)은 0.7+, 필터 검색 리콜 보정(iterative_scan)은 0.8+에서 자동 활성 |
pg_trgm | 선택 권장 | 한국어 복합어 내부 매칭(trigram 신호). Postgres 기본 동봉 확장 |
ripgrep ( | 선택 |
|
claude CLI 또는 | 선택 | LLM 기능(증류/요약/재순위/문맥/질문)용. 컨테이너 환경은 |
Related MCP server: Solarium
2. 설치
git clone https://github.com/riemannulus/knowledge-base && cd knowledge-base
python3 -m venv .venv && source .venv/bin/activate
pip install -e . # 개발용은 pip install -e ".[dev]"선택 기능은 extras로: [aws](Bedrock 임베딩) · [slack](실시간 수집) ·
[dashboard](웹 대시보드, §11) · [anthropic](LLM 기능 API 백엔드, §7.3).
Docker 이미지는 네 개를 모두 포함한다.
Postgres에 pgvector가 없다면 (Debian/Ubuntu 예시):
sudo apt-get install postgresql-16-pgvector
createdb kb # 원하는 이름의 DB 생성3. 빠른 시작 (5분)
Postgres 설치 없이 바로 띄우려면 §4.1의 Docker Compose 경로를 쓰면 된다 —
cp .env.example .env && docker compose up -d --build한 번으로 DB·MCP 서버·sync가 다 뜬다.
# 1) 설정 파일 작성
cp kb.toml.example kb.toml
$EDITOR kb.toml # dsn, 커넥터 경로 수정
# 2) 스키마 마이그레이션 (Alembic — 멱등, 여러 번 실행해도 안전)
kb migrate
# 3) 동기화 (커넥터 전체 실행, 증분)
kb sync
# {"connector": "markdown:kb-docs", "emitted": 4, "upserted": 4, ...}
# {"connector": "gitlog:kb-repo", "emitted": 12, "upserted": 12, ...}
# 4) 검색해 보기
kb search "배포 락 타임아웃"
kb search "ERR_MANIFEST_TIMEOUT" --source slack --limit 5
kb search "재색인 주기" --jsonkb sync는 커서 기반 증분이다: 다시 실행하면 변경된 것만 처리하고,
내용이 같으면(content_hash) 재임베딩도 건너뛴다. 주기 실행은 cron에 걸면 된다:
*/10 * * * * cd /path/to/kb && .venv/bin/kb sync >> /var/log/kb-sync.log 2>&14. Claude Code / Claude Desktop에 MCP로 연결
두 가지 모드가 있다:
로컬(stdio) — 혼자 쓸 때. 아래처럼 명령으로 등록.
원격(Streamable HTTP) — 팀 공유. §4.1의 Docker 배포 후 URL로 등록.
Claude Code (로컬 stdio)
claude mcp add kb --env KB_CONFIG=/absolute/path/kb.toml -- /absolute/path/.venv/bin/kb mcp또는 프로젝트의 .mcp.json:
{
"mcpServers": {
"kb": {
"command": "/absolute/path/.venv/bin/kb",
"args": ["mcp"],
"env": { "KB_CONFIG": "/absolute/path/kb.toml" }
}
}
}Claude Desktop (로컬 stdio)
claude_desktop_config.json의 mcpServers에 위와 동일한 블록을 추가한다.
4.1 팀 공유 원격 서버 (Docker Compose로 한 번에)
cp .env.example .env
$EDITOR .env # KB_AUTH_TOKEN만 채우면 됨 (openssl rand -hex 24)
docker compose up -d --build
# 확인: 401이 나오면 정상 (인증이 걸린 상태)
curl -s -o /dev/null -w "%{http_code}\n" -X POST http://localhost:8000/mcp -d '{}'db(pgvector) + migrate(Alembic 스키마 마이그레이션 — 1회 실행 후 종료) +
mcp(HTTP :8000/mcp, 헬스체크 포함) + sync(주기 동기화, KB_SYNC_INTERVAL
기본 300초) + dashboard(웹 UI :8080, §11) 서비스가 뜨고 재시작 정책이 걸려 있다.
앱 서비스들은 migrate가 성공해야 시작되므로 스키마 업그레이드가 배포에 자동
포함된다 (k8s도 동일 — mcp/dashboard의 initContainer, sync CronJob의 선행 단계).
기본값 그대로면 이 저장소 자신(docs/ + git log)을 인덱싱하는 데모로 즉시 동작하고,
실데이터는 .env의 KB_DOCS_DIR/KB_REPO_DIR와 deploy/kb.docker.toml을 수정한다.
커넥터 하나가 실패해도 나머지 sync는 계속된다(실패 격리). DB 데이터는
kb-pgdata 볼륨에 보존되므로 docker compose down(-v 없이)으로는 유실되지 않는다.
수동 실행도 가능: kb mcp --transport http --host 0.0.0.0 --port 8000
(KB_AUTH_TOKEN 환경변수가 있으면 Authorization: Bearer 검사).
팀원 등록 (Claude Code):
claude mcp add --transport http kb https://kb.example.com/mcp \
--header "Authorization: Bearer <KB_AUTH_TOKEN>"프로젝트 공유는 .mcp.json으로 (토큰은 각자 환경변수로 — 커밋 금지):
{
"mcpServers": {
"kb": {
"type": "http",
"url": "https://kb.example.com/mcp",
"headers": { "Authorization": "Bearer ${KB_AUTH_TOKEN}" }
}
}
}플러그인으로 한 번에 (권장): 수동 mcp add 대신 kb-workflow 플러그인을 설치하면
KB 연결(+워크플로 스킬 kb-brief/kb-log/kb-wrap + 기록 유실 방지 훅)이 함께 배선된다.
설치 시 서버 URL/토큰을 물어본다 — 로컬(compose)은 기본값 엔터, 원격은 팀 서버
URL + kbt_ 토큰 입력(마스킹·보안 저장소 저장). 이후 전환·재설정은 /plugin 메뉴의
플러그인 설정 또는 /kb-workflow:setup 참고. 프로젝트 .mcp.json에 동명 kb 서버를
정의하면 플러그인 정의를 덮는다(완전 오버라이드).
상세: plugins/kb-workflow/README.md.
/plugin marketplace add riemannulus/knowledge-base
/plugin install kb-workflow@knowledge-baseclaude.ai / Claude Desktop 커스텀 커넥터: 설정 → 커넥터 → 커스텀 커넥터에
https://kb.example.com/mcp 등록. 웹 커넥터 UI는 커스텀 헤더를 붙일 수 없으므로
OAuth로 붙인다 — §4.2. 자동화/봇은 Anthropic API MCP connector의
authorization_token에 kbt_ 토큰을 쓰면 된다.
상세 절차와 운영 팁: docs/05-team-workflow.md.
4.2 claude.ai 웹 커넥터 연결 (Google OAuth)
kb가 **스스로 OAuth 2.1 인가 서버(AS)**가 되고 "누구인가"만 Google에 위임한다. claude.ai가 커넥터를 연결할 때 브라우저로 Google 로그인을 띄우고, 허용 도메인 계정이면 kb가 자기 액세스 토큰을 발급한다. 팀원은 토큰을 복사·붙여넣을 일이 없다.
claude.ai ──OAuth 2.1(PKCE + 동적 등록)──▶ kb(/mcp)
└─OIDC─▶ Google (허용 도메인만 통과)Google이 아니라 kb가 AS인 이유: Google은 임의 리소스 서버를 위한 RFC 9728 리소스 메타데이터도, MCP 클라이언트의 동적 등록(RFC 7591)도 제공하지 않는다. MCP 스펙이 명시한 3rd-party IdP 위임 패턴이 이 구조다.
1) Google OAuth 클라이언트 만들기 (하나로 커넥터·대시보드 모두 커버)
Google Cloud Console → API 및 서비스 → 사용자 인증 정보 → OAuth 클라이언트 ID → 애플리케이션 유형 웹 애플리케이션. 승인된 리디렉션 URI에 둘을 등록한다 (외부에서 실제로 접속하는 주소여야 하고, 문자 하나까지 일치해야 한다):
https://kb.example.com/oauth/google/callback # MCP 서버 (= KB_PUBLIC_URL + 고정 경로)
https://kb-dash.example.com/auth/callback # 대시보드 (= KB_DASHBOARD_URL + 고정 경로)2) 서버 환경변수 (5개가 모두 있어야 켜진다 — 일부만 채우면 기동 시 예외로 알려준다)
환경변수 | 값 |
| 위에서 만든 클라이언트 |
| 허용 Google Workspace 도메인 (예: |
| state·세션 쿠키 서명 키. |
| MCP 서버 공개 주소 (예: |
선택: KB_OAUTH_ALLOWED_EMAILS(도메인 밖 개별 허용), KB_OAUTH_TOKEN_TTL(기본 3600),
KB_OAUTH_REFRESH_TTL(기본 30일). 설치는 pip install -e ".[oauth]"
(Docker 이미지에는 포함, compose는 .env만 채우면 된다).
3) 팀원 연결: claude.ai 설정 → 커넥터 → 커스텀 커넥터에 https://kb.example.com/mcp
입력 → 연결 → Google 계정 선택. 끝. Claude Desktop·MCP Inspector·Claude Code
(claude mcp add --transport http kb https://kb.example.com/mcp)도 같은 흐름을 탄다.
동작 확인:
# 무인증 요청은 401 + AS 위치를 알려주는 헤더를 돌려준다 (클라이언트가 이걸로 발견)
curl -si -X POST https://kb.example.com/mcp -d '{}' | grep -i www-authenticate
# WWW-Authenticate: Bearer error="invalid_token",
# resource_metadata="https://kb.example.com/.well-known/oauth-protected-resource/mcp"
curl -s https://kb.example.com/.well-known/oauth-authorization-server | jq .issuer노출되는 엔드포인트: /.well-known/oauth-authorization-server(RFC 8414),
/.well-known/oauth-protected-resource/mcp(RFC 9728), /register(RFC 7591 동적 등록),
/authorize, /token, /revoke(RFC 7009), /oauth/google/callback.
권한 모델: 허용 도메인 계정 = 팀 전체 접근(프로젝트 스코프 없음), 쓰기는
kb.write 스코프에 달려 있다(기본 발급에 포함 — 읽기 전용 클라이언트는 kb.read만
요청하면 된다). 신원 이름은 이메일이라 record_*의 author와 query_log에 그대로 남는다.
세부 스코프가 필요하면 kbt_ 토큰(§8.1)을 계속 쓰면 된다 — 두 경로는 공존한다.
운영: 등록된 커넥터와 활성 세션은 대시보드 토큰 페이지에서 보고 폐기한다
(kb oauth clients|sessions|revoke-client|revoke-user도 같은 일을 한다).
퇴사자 처리는 Google 계정 정지 + kb oauth revoke-user <email>.
액세스 토큰은 만료가 짧고(기본 1시간), 리프레시는 회전할 때 옛 쌍이 함께 폐기된다.
⚠ OAuth를 켜면 "등록 토큰 0개 = 무인증 admin" 완화가 꺼진다 (§8.1) — 토큰 없는 요청은 항상 401이다. HTTPS는 여전히 reverse proxy/터널 몫이다: OAuth 토큰은 베어러라 평문 HTTP로 노출하면 그대로 유출된다.
연결 후 이렇게 물어보면 된다:
"kb에서 검색해줘: staging 배포가 락 때문에 멈추는 문제 예전에 어떻게 해결했지?"
에이전트가 search → get_document를 호출해 근거 문서(document_id, URL)를 인용하며 답한다.
MCP 도구 레퍼런스
도구 | 파라미터 | 설명 |
|
| 하이브리드 검색. |
|
| 원문 전체 + (Slack이면) 증류 결과. |
| — | 소스/구획별 문서 수·최근 갱신·설명("무엇을 잘 답하나"), 프로젝트 목록. 도구 선택 전 상황 파악용 |
|
| 파일별 요약 인덱스 — "어느 파일에 구현돼 있나" 류 질문 (file_summary/file_head 대상) |
|
| 최근 PR 목록/검색 ( |
|
| 주제 관련 스레드 참여자·커밋 작성자 집계 → 실증 전문가 |
|
| 최근 갱신 문서 (커밋/스레드/문서) |
|
|
|
|
| 검색 결과 품질 피드백 — 골든셋/큐레이션 재료 |
|
| 쓰기: 의사결정 기록. |
|
| 쓰기: 삽질/버그 교훈 기록. prevention이 핵심. 특정 프로젝트에서만 성립하는 교훈이면 |
|
| 쓰기: 일반 지식 메모 |
|
| 재검증 큐 (대시보드와 동일): 참조 코드 변경( |
|
| 쓰기: 노트 재검증 표시 (stale 플래그 해제) |
|
| 작업 전 사전 점검: 주제 관련 과거 교훈·결정 조회. 대체된 노트 제외, |
모든 읽기 도구는 LLM을 호출하지 않아 빠르고 싸다. 쓰기 도구의 기록은 즉시
청킹·임베딩되어 바로 검색된다.
record_* 응답의 similar_existing은 비슷한 기존 기록이 이미 있다는 신호다 — 같은
문제라면 새 제목 대신 기존 제목으로 갱신하거나 supersedes를 쓰라. 단 후보의
project가 다르면 같은 증상이라도 원인이 다를 수 있다 — 힌트에 경고가 붙으니
같은 근본 원인임을 확인한 경우에만 갱신하고, 아니면 별도 기록을 유지하라.
record_*의 project는 등록된 프로젝트 이름 기준으로 해석된다: 등록명은 그대로,
저장소 이름(모노레포 하위 저장소 등 project_sources의 source_key)은 소유
프로젝트로 자동 교정, 등록되지 않았거나 여러 프로젝트에 걸려 모호한 이름은
라벨을 버리고 팀 공용으로 기록한다 — 잘못된 라벨은 자기 프로젝트 스코프 검색에서
억울한 감점을 만들기 때문. 결과는 응답의 project(최종 저장값)와
project_hint(교정/폐기 사유)로 알 수 있고, 같은 제목으로 다시 기록하면
갱신되므로 즉시 교정 가능하다.
에이전트가 이 루프(작업 전 pitfalls → 작업 후 record)를 스스로 돌게 만드는
CLAUDE.md 스니펫은 docs/05-team-workflow.md §3에 있다.
5. kb.toml 레퍼런스
[database]
dsn = "host=127.0.0.1 port=5432 user=kb dbname=kb" # $KB_DSN이 있으면 그것이 우선
[embedding]
backend = "hashing" # 'hashing' | 'openai' | 'bedrock'
dim = 1024
model = "" # openai: 기본 text-embedding-3-small / bedrock: 기본 amazon.titan-embed-text-v2:0
region = "" # bedrock 전용 AWS 리전 (비우면 $AWS_REGION)
[distill]
backend = "none" # 'none' | 'claude-cli'
model = "claude-haiku-4-5-20251001"
[[connector]] # 소스 하나당 하나. type: markdown | gitlog | slack_export
type = "markdown"
root = "docs" # 상대 경로는 kb.toml 위치 기준
source_key = "kb-docs"
url_prefix = "https://github.com/org/repo/blob/main/docs" # 선택: 결과 URL 생성
[[connector]]
type = "gitlog"
repo = "."
source_key = "kb-repo"
url_prefix = "https://github.com/org/repo/commit"
[[connector]]
type = "slack_export"
root = "/data/slack-export" # 워크스페이스 export(zip 해제) 디렉터리
channels = ["deploy", "infra"] # 생략 시 전체 채널
workspace_url = "https://your.slack.com" # 선택: 스레드 딥링크 생성
[[connector]]
type = "github_prs" # PR 본문+코멘트를 대화형 문서로 수집 (증류 경로 적용)
repo = "org/repo" # $GITHUB_TOKEN 권장
source_key = "prs"
[code_repos] # search_code(ripgrep) 대상
platform = "/srv/repos/platform"이 밖에 [context](청크 문맥 생성 — Contextual Retrieval), [ask](대시보드 질문
페이지), [rerank] pool, [chunking] max_chars, [search](RRF 가중치·다양성 캡),
[pricing](단가 오버라이드), 커넥터 description(소스 카탈로그) 옵션이 있다 —
전체 주석은 kb.toml.example 참고. LLM 백엔드는 공통으로
'none' | 'claude-cli' | 'anthropic' | 'bedrock'이며, API 백엔드는 컨테이너/k8s에서도
동작한다 (pip install '.[anthropic]', bedrock은 [anthropic,aws]).
[context]는 프롬프트 캐싱으로 동작한다: 문서 본문을 캐시 프리픽스로 한 번
기록(1.25×)한 뒤 나머지 청크가 캐시 적중(0.1×)으로 돌아, 청크마다 문서를
풀프라이스로 재전송하는 것 대비 첫 백필 비용이 ~85% 절감된다. 캐시 프라이밍
후 청크 호출은 4-way 병렬이라 백필 속도도 그만큼 빨라진다 (API 백엔드 한정 —
claude-cli는 캐싱 제어가 없어 프리픽스를 이어붙여 실행).
환경변수: KB_CONFIG(설정 파일 경로), KB_DSN(DSN 오버라이드),
OPENAI_API_KEY/OPENAI_BASE_URL(openai 임베딩), ANTHROPIC_API_KEY(anthropic LLM
백엔드), GITHUB_TOKEN(github_prs 커넥터).
6. CLI 레퍼런스
명령 | 설명 |
| 스키마를 최신 Alembic 리비전으로 (멱등). 구 init-db 스키마는 자동으로 baseline stamp 후 편입. compose/k8s 배포는 자동 실행 |
| 전체(또는 특정) 커넥터 증분 동기화. 이름은 |
| 하이브리드 검색. |
| 골든셋 검색 품질 평가 (Recall@k/MRR/nDCG). 모든 검색 튜닝의 판정 기준 |
| query_log에서 골든셋 스켈레톤 생성 (expect는 사람이 라벨링) |
| 재검증 필요 노트 (참조 코드 변경 또는 장기 미검증) |
| 유사 노트 쌍(병합 후보) — 자동 병합 안 함 |
| 노트 재검증 / 대체 표시 |
| 사용자별 접근 토큰 관리 (§8.1). default-project는 soft 기본 스코프 |
| OAuth 커넥터 등록·사용자 세션 조회/폐기 (§4.2). 대시보드 토큰 페이지와 같은 조작의 헤드리스 경로 |
| 쿼리 로그 분석 — 무응답 질의(커넥터/골든세트 백로그 후보), 상위 질의, 클라이언트별 사용량 |
| 전 문서 재청킹·재임베딩 — 임베딩 백엔드/차원 변경 후 필수 |
| 소스에서 사라진 문서(유령) 수거. sync에도 포함되므로 평소엔 불필요 — 미리보기/수동용 |
| Slack Socket Mode 실시간 수집 ( |
| MCP 서버 실행. http면 |
| 웹 대시보드 (기본 :8080) — 운영 헬스/모델·비용/검색/관리 (§11) |
공통 옵션: --config /path/kb.toml.
6.1 원본이 바뀌거나 사라지면 (드리프트 처리)
원본 변화 | 동작 |
내용 수정 | 커서에 걸려 재방출 → |
파일 삭제 | sync 말미의 reconcile이 소스의 현재 목록( |
파일 이름변경/이동 | 새 경로로 재인덱싱 + 옛 경로 유령 삭제 (파일별 mtime 커서라 rename도 감지) |
Slack 메시지 수정 (답글 없이) |
|
git 히스토리 리라이트 (force push) | 무효 커서 감지 → 전체 재스캔으로 자가 복구, 사라진 커밋은 reconcile로 제거 |
안전장치: reconcile은 소스 목록이 비어 있으면 삭제하지 않는다 — 진짜 빈 소스와
마운트/경로 오설정을 구분할 수 없어, 설정 실수 한 번으로 인덱스가 전멸하는 사고를 막는다.
커스텀 커넥터도 current_ids()(현재 전체 source_id 반환) 하나만 구현하면 같은 수거를 받는다.
7. Slack·코드 데이터 넣기
7.1 백필 (과거 이력, export 기반)
Slack 워크스페이스 관리자 메뉴에서 export를 받아 압축을 푼다 (
users.json,<채널>/YYYY-MM-DD.json구조).[[connector]] type="slack_export"를 설정하고kb sync.스레드 하나가 문서 한 행이 된다. 답글·수정(
edited.ts)이 생긴 스레드는 다음 sync에서 전체가 재수집되어 같은 행에 갱신된다.
7.2 실시간 수집 (Socket Mode)
Slack 앱을 만들어 Socket Mode를 켜고(앱 토큰 xapp-, connections:write),
봇 토큰(xoxb-)에 channels:history, channels:read, users:read,
reactions:read 스코프를 준 뒤 봇을 추적할 채널에 초대한다.
export SLACK_BOT_TOKEN=xoxb-... SLACK_APP_TOKEN=xapp-...
kb slack-listen # 또는: docker compose --profile slack up -d이벤트 도착 → 즉시 ack → event_id 중복 제거 → 스레드 전체 재수집 → 행 1개 upsert.
새 메시지·답글·수정·리액션 모두 스레드 재수집을 트리거한다.
삭제 전파: 스레드가 Slack에서 지워지면 재수집 결과가 비므로 행을 삭제한다 — export 백필이 못 하던 유령 정리가 실시간 경로에서 해결된다.
백필과 같은
source_id(채널명/thread_ts)를 쓰므로 export → 실시간 전환 시 중복 없이 이어진다.채널 필터:
[slack] channels(추적할 채널 allowlist, 빈 값 = 전체) ·[slack] exclude_channels(봇이 초대됐지만 인덱싱하지 않을 채널). 봇이 초대된 채널의 이벤트는 전부 도착하므로, 잡담·알림 채널은 초대를 유지하면서 여기서 제외한다. 두 목록 다 문자열 완전 일치와 정규식 둘 다 받는다 —/…/로 감싸면 정규식(/…/i는 대소문자 무시)이고,re.search라 부분 일치이니 전체 일치는^…$로 앵커한다. 겹치면exclude_channels가 이긴다.[slack] channels = [] # 전체 채널 추적 exclude_channels = ["random", '/^tmp-/', '/-notifications$/']정규식은 TOML 리터럴 문자열(
'…')로 쓰면 백슬래시 이스케이프가 필요 없다. 잘못된 정규식은 리스너 시작 시 즉시 에러다 (조용히 무시해서 필터가 새는 것보다 빨리 실패하는 게 낫다). 필터는 수집 대상만 정하므로reply응답은 제외 채널에서도 동작한다 — 멘션은 사람이 직접 부른 요청이다.봇 응답:
[slack] reply = true면 @봇 멘션에 지식 베이스 검색 상위 3건(제목+링크+스니펫)을 스레드로 회신한다. 의도적으로 LLM-free — 봇은 증거를 주고 판단은 사람이 한다. 합성 답변은 대시보드 질문 페이지(§11) 몫. 추가 스코프:app_mentions:read,chat:write.
7.3 증류와 버스트
LLM 증류: [distill] backend = "claude-cli"(로컬), "anthropic"(API,
컨테이너 가능), "bedrock"(Amazon Bedrock의 Claude — API 키 없이 AWS 자격증명
재사용, 임베딩을 Bedrock으로 쓰는 배포에 적합. 리전은 [llm] region) 중 하나로
두면 대화형 문서마다 {question, summary, resolution, systems, code_refs}를 추출해 distilled 청크로 임베딩한다. bedrock 백엔드에서 model에
1P 모델명을 쓰면 추론 프로파일 ID(global.anthropic.…)로 자동 변환되고, Claude 외
Bedrock 모델도 지정할 수 있다 — model = "nova-2-lite"(Amazon Nova 2 Lite,
Converse API 자동 라우팅)는 Haiku 대비 입력가 1/3.3에 프롬프트 캐싱도 지원한다.
전환 전 scripts/model_ab.py로 실데이터 A/B를 권장. 잡담 스레드는 LLM이 skip
판정하고, 그 전에 비용 게이트(기본: 메시지 4개 미만이고 800자 미만이면 증류
생략, [distill] min_messages/min_chars)와 재증류 델타(redistill_after,
기본 5 — 리스너의 답글당 전체 재증류 방지)가 백필·실시간 폭주를 막는다. 증류물이 있으면 대화 원문은 임베딩하지 않는다 (D12 비대칭 인덱싱:
raw는 FTS로만 검색, 벡터 공간은 정규화된 증류물+버스트만 — 자체 A/B에서도 증류물이
우세). 증류가 실패하거나 꺼져 있으면 원문 임베딩으로 폴백해 검색 공백을 막는다.
버스트: 긴 스레드 속 개별 답변(같은 저자의 연속 메시지 묶음)을 스레드 주제를 앞에 붙여 별도 임베딩한다 — 스레드 요약에 어휘가 안 들어가는 탄젠트 답변도 검색된다. 저신호 차단 게이트: 희귀 토큰(IDF ≥ 4.0) + 200자 이상 + 리액션의 가중 결합 점수가 임계값을 넘어야 임베딩된다.
7.4 코드 저장소 인덱싱 (Phase 3)
[[connector]]
type = "code"
repo = "/srv/repos/platform"
source_key = "platform"
include = ["src/*"] # 파일 경로 allowlist/denylist
exclude = ["*/generated/*"] # node_modules, vendor, dist 등은 기본 제외청킹: 언어별 경계 정규식으로 거친 단위 → 세밀한 단위 분할 (클래스/최상위 함수 → 메서드 → 고정 크기 폴백). Python/JS·TS/Go/Rust/JVM/C 계열 지원.
증분: cursor = HEAD sha,
git diff로 변경 파일만 재임베딩. 삭제·이름변경은 reconcile, 히스토리 리라이트는 자가 복구. 바이너리·256KB 초과 파일 자동 제외.file_summary:
[code_summary] backend를 켜면 파일마다 목적·핵심 API를 LLM이 요약해 별도 청크로 임베딩한다. "환불 웹훅 처리 어디 있지?"처럼 문제는 아는데 구현 위치를 모르는 자연어 질의가 코드에 닿는 다리다. 에러 문자열·심볼 정확 매칭은search_code(ripgrep)가 담당 — grep과 시맨틱은 보완재다 — 둘 다 유지한다 (Cursor 실측: 병용이 최고 성과, docs/07 §3).file_head (LLM 없는 파일 레벨 레코드): 심볼이 3개 이상인 코드 파일은 경로+심볼 목록이 자동으로 임베딩된다 — LLM 요약 없이도
subsystem_index도구가 동작한다.
7.5 GitHub PR 인덱싱
[[connector]] type = "github_prs"는 PR 제목·본문·이슈 코멘트를 스레드처럼 합쳐
대화형 문서로 수집한다 — Slack과 동일한 증류·버스트 파이프라인을 탄다.
커서는 updated_at 워터마크 증분이고, recent_prs
MCP 도구가 "최근에 누가 뭘 바꿨지" 질문에 답한다. GITHUB_TOKEN 권장.
7.6 Notion 인덱싱
[[connector]] type = "notion"은 Notion 통합(integration)에 공유된 페이지를
문서로 수집한다. 설정 3단계:
notion.so/profile/integrations에서 내부 통합 생성 → 토큰을
NOTION_TOKEN에.인덱싱할 최상위 페이지/스페이스에서 ⋯ → 연결(Connections) → 통합 추가. 하위 페이지는 자동 포함된다. 공유 범위가 곧 인덱싱 범위 — 민감 스페이스는 공유하지 않으면 절대 수집되지 않는다.
kb.toml에 커넥터 블록 추가 (kb.toml.example 참고) 후
kb sync.
동작: 검색 API를 last_edited_time 역순 워터마크로 증분 순회하고(타임스탬프가
분 단위 반올림이라 워터마크−5분 오버랩 창으로 되감아 스캔 — 재방출은 해시 dedup이
흡수), 블록 트리를
마크다운풍 텍스트(헤딩/리스트/코드 펜스)로 렌더링해 헤딩 인지 청킹을 그대로 태운다.
하위 페이지는 각자 별도 문서로 인덱싱된다. 아카이브/휴지통 페이지는 건너뛰며,
공유 해제·삭제된 페이지는 kb gc(reconcile)가 수거한다. 레이트리밋(≈3 req/s)은
429 Retry-After 재시도로 흡수. 1회 sync는 max_pages(기본 10,000)까지 — 상한에
잘리면 재개 커서를 저장해 다음 sync가 잘린 지점부터 이어서 백필하므로 큰
워크스페이스도 몇 주기에 걸쳐 전량 인덱싱된다.
7.7 Linear 인덱싱
[[connector]] type = "linear"는 이슈 제목·설명·코멘트를 스레드처럼 합쳐
대화형 문서로 수집한다 — GitHub PR과 동일한 증류·버스트 파이프라인. 설정:
인증 수단을 고른다 (아래 표). OAuth client_credentials 권장.
kb.toml에 커넥터 블록 추가 (kb.toml.example 참고) 후
kb sync.
OAuth client_credentials (권장) | 개인 API 키 | |
환경변수 |
|
|
발급 |
| Settings → Security & access → Personal API keys |
신원 | 워크스페이스 소유 app actor (사람 계정과 무관) | 키 소유자 |
인덱싱 범위 | 워크스페이스의 public 팀 — private 팀은 구조적으로 제외 | 키 소유자가 볼 수 있는 전부 (private 팀 포함) |
헤더 |
| 키를 접두 없이 그대로 |
인덱싱된 것은 KB 검색 사용자 전원이 볼 수 있으므로 범위가 곧 노출 범위다.
개인 키를 쓰면 소유자의 private 팀 이슈까지 들어오고, 이를 막는 건 teams
allowlist를 사람이 유지하는 것뿐이다 — 새 팀이 생기면 새는 쪽으로 기운다.
OAuth 쪽은 앱 상세 페이지에서 app user의 팀 접근을 더 조일 수도 있다.
어느 쪽이든 teams = ["ENG"]로 커넥터 단에서 더 좁힐 수 있다.
app actor 토큰은 30일 만료에 refresh_token이 없다. 커넥터는 sync 프로세스마다 새로 발급하므로(동일 스코프 병렬 토큰은 서로 무효화하지 않는다) 갱신 운영이 없다 — 영속 저장이 필요한 건 client id/secret뿐이다. 둘 중 하나만 설정하면 기동이 아니라 첫 호출에서 예외다(다른 수단으로 조용히 폴백하지 않는다). 둘 다 설정된 경우 OAuth가 개인 키를 이긴다 — 마이그레이션이 조용히 무효가 되지 않도록.
동작: GraphQL issues(filter: {updatedAt: {gt: 워터마크−5분}}) — 증분 필터가
서버측이라 무변경 sync는 요청 1회로 끝난다. 오버랩 창 5분은 필터 경계·복제
지연 보정이고 재방출은 해시 dedup이 흡수한다(§7.6 Notion과 동일 원칙). 아카이브·
휴지통 이슈는 건너뛰며 kb gc(reconcile)가 수거한다. source_id는 UUID라
이슈가 팀을 옮겨 식별자(ENG-123)가 바뀌어도 중복 문서가 생기지 않는다.
8. 프로젝트 스코프 (검색 범위 묶기)
프로젝트 = 소스 구획(source, source_key)의 이름 붙은 번들. 같은 구획을 여러 프로젝트가 공유할 수 있다.
INSERT INTO projects VALUES ('ml-infra', 'ML 학습 인프라');
INSERT INTO project_sources VALUES
('ml-infra', 'slack', '#ml-infra'),
('ml-infra', 'markdown', 'kb-docs'),
('ml-infra', 'gitlog', 'kb-repo');이후 kb search "..." --project ml-infra 또는 MCP search(project="ml-infra").
8.1 사용자별 접근 토큰 (Phase 4 authz)
원격 MCP에 사람/에이전트별 토큰을 발급해 프로젝트 스코프와 쓰기 권한을 강제할 수 있다:
kb token create june --projects ml-infra # ml-infra 소스만 검색/조회 가능
kb token create ci-bot --read-only # record_* 도구 금지
kb token list / kb token revoke june인증 규칙:
KB_AUTH_TOKEN(관리자, 전체 접근) →api_tokens등록 토큰(스코프 적용) → OAuth로 발급된kba_액세스 토큰(§4.2, 신원 = Google 이메일) → 셋 다 없으면 무인증 admin(사설망 모드). 등록 토큰이 하나라도 생기거나 OAuth가 켜져 있으면 무인증은 차단된다.스코프 토큰은 search/get_document/list_sources/recent_changes/who_knows 전부에서 허용 프로젝트의 소스만 본다. 예외:
note(팀 교훈·결정)는 항상 보인다 — pitfalls/record 루프는 팀 공용이기 때문.author를 생략한 record_* 기록에는 토큰 이름이 자동으로 들어가고, query_log에도 토큰 이름이 남는다(사용 분석·감사).평문 토큰은 발급 시 한 번만 출력된다 (DB에는 sha256만 저장).
9. 임베딩 백엔드 교체 (중요)
기본 hashing 백엔드는 외부 의존 없는 자리표시자다. 문자 n-gram 기반이라
정확 토큰·한국어 조사 변형은 잘 잡지만, 어휘가 겹치지 않는 패러프레이즈는 못 잡는다
(예: "학습 재개가 멈춰요" → "checkpoint restore stalls" 스레드).
실서비스에서는 의미 임베딩으로 교체할 것. 두 가지 API 백엔드를 지원한다:
OpenAI 호환 API
[embedding]
backend = "openai" # OpenAI 호환 API면 무엇이든 (OPENAI_BASE_URL)
model = "text-embedding-3-small"
dim = 1024export OPENAI_API_KEY=...
kb reindex # 전 문서 재임베딩 (차원이 바뀌면 kb migrate를 새 DB에 다시)AWS Bedrock
[embedding]
backend = "bedrock"
model = "global.cohere.embed-v4:0" # 한국어 포함 다국어 권장 (실측: docs/04 §S2)
dim = 1024
region = "ap-northeast-2"pip install "knowledge-base[aws]" # boto3 (Docker 이미지에는 이미 포함)
kb reindexBedrock 모델 | 차원 | 비고 |
| 256~1536 ( | 다국어(한국어) 권장 — 실측 최고 성적(docs/04 §S2). 추론 프로파일 ID라 |
| 256/512/1024 | 리전 내 상주. 한↔영 교차 어휘는 약함(실측). 텍스트 1건/호출 |
| 1024 | 리전에 따라 미제공(ap-northeast-2 없음). 96건 배치 |
가용 모델은 리전마다 다르다 — aws bedrock list-foundation-models --by-output-modality EMBEDDING으로 확인하고, INFERENCE_PROFILE 타입이면
모델 ID 대신 프로파일 ID(global.…/apac.…)를 쓴다.
자격 증명: AWS 표준 체인을 그대로 쓴다 — EC2/ECS의 IAM 롤이면 키 설정이 필요 없고, 아니면
AWS_ACCESS_KEY_ID/AWS_SECRET_ACCESS_KEY(+AWS_REGION) 환경변수. Bedrock API 키(AWS_BEARER_TOKEN_BEDROCK)도 boto3가 자동 인식한다. compose 사용 시.env와compose.yaml의 AWS_* 주석을 해제한다.실측 참고 (합성 골든 세트, docs/04 §S2): Titan v2로 교체 시 벡터 MRR 0.817→0.875, 증류물 임베딩이 원문 대비 우세(MRR 1.0 vs 0.927 — 증류를 켜는 게 좋다). 단 어휘가 전혀 안 겹치는 한↔영 교차 질의는 Titan v2도 약하다 — 다국어가 중요하면 Cohere multilingual 모델 접근을 활성화해 비교할 것.
IAM 권한: 해당 모델에 대한
bedrock:InvokeModel하나면 된다. Bedrock 콘솔에서 모델 접근(Model access) 활성화가 선행되어야 한다.스로틀링: adaptive 재시도(최대 8회)가 내장되어 있어 대량 백필도 견딘다.
모델 선정 근거와 평가 하네스는 docs/04-spike-results.md의
S2 항목 참고 — spikes/의 골든 세트 평가를 재실행해 비교할 수 있다. 어떤 백엔드든
모델/차원을 바꾸면 kb reindex가 필수이고, 차원이 바뀌면 chunks 테이블의 vector
차원도 바뀌어야 하므로 새 DB에 kb migrate부터 다시 하는 것이 안전하다.
10. 새 커넥터 만들기
커넥터는 "cursor 이후 변경분을 SourceRow로 방출"만 하면 된다. 증류·청킹·임베딩·
업서트는 엔진이 처리한다.
# src/kb/connectors/jira.py (예시)
from datetime import datetime, timezone
from typing import Iterator
from .base import SourceRow, SyncState
class JiraConnector:
def __init__(self, base_url: str, project: str):
self.name = f"jira:{project}"
...
def sync(self, state: SyncState) -> Iterator[SourceRow]:
last = state.cursor.get("updated_after") # 증분 커서
for issue in self._fetch_issues(updated_after=last):
yield SourceRow(
source="jira", source_key=self.project,
source_id=issue["key"], # upsert 키
title=issue["summary"],
text=f'{issue["summary"]}\n\n{issue["description"]}',
updated_at=issue["updated"],
url=f"{self.base_url}/browse/{issue['key']}",
doc_type="document", # document | conversation | code
metadata={"participants": issue["participants"]},
)
state.cursor["updated_after"] = datetime.now(timezone.utc).isoformat()doc_type 의미: document → 헤딩 인지 청킹 / conversation → 증류 경로(설정 시) /
code → 통짜 청킹. metadata.participants를 채우면 who_knows가 활용한다.
등록은 src/kb/connectors/registry.py의 build_connectors에 분기 추가 +
kb.toml에 [[connector]] 엔트리 — 이 두 곳 외에는 수정할 파일이 없다.
11. 웹 대시보드 (운영 · 비용 · 관리)
kb dashboard(기본 :8080)로 뜨는 팀용 웹 UI. compose에선 dashboard 서비스로
함께 올라온다 (http://localhost:8080).
페이지 | 내용 |
개요 | 사용 중인 모델(역할별 백엔드·단가), 수집 상태 요약(source 단위 롤업 + 동기화 지연 경고 → 상세는 소스 페이지), 임베딩 무결성(차원 불일치·NULL 청크 감지), 노트 요약(종류별 개수 · 재검증 필요 · 대체됨 + 최근 5건 → 상세는 노트 페이지) |
검색 | MCP |
질문 |
|
노트 | 기록 브라우저 — 제목·태그 검색 + 종류/상태(유효·재검증 필요·대체됨)/작성자/태그/프로젝트 필터, 정렬(최근 갱신·검증 오래된 순), 50건 페이지네이션(총 건수 표시). 뷰가 분리된다: 재검증 큐( |
소스 |
|
쿼리 분석 | 일별 검색량·문서 열람 수, 무응답 쿼리(커넥터 백로그 후보), 인기 쿼리, 클라이언트별 사용량, 지연 p50/p95, 피드백 요약(👍/👎 비율·부정 피드백 쿼리). 쿼리 지표는 |
운영·비용 | API 사용량·비용 집계 (§11.1) |
토큰/프로젝트 | §8.1 토큰 발급·폐기(평문 1회 표시), OAuth 커넥터 등록·사용자 세션 폐기(§4.2), 프로젝트-소스 구획 매핑 편집 — 관리자 전용 |
문서 상세 페이지에서는 관리자가 큐레이션을 할 수 있다: boost(검색 순위 ±, [-0.9, 2.0] 범위) 조정과 숨김(검색에서 제외, 원문은 유지) 토글. Onyx/Guru의 큐레이션 패턴을 따른 것으로, 자주 낡은 문서가 상위에 뜨면 지우는 대신 내리면 된다.
11.1 API 사용량·비용 계측
임베딩(bedrock/openai)과 LLM 기능(증류/코드 요약/재순위/문맥 생성/질문 —
claude-cli·anthropic·bedrock 백엔드)의 모든 호출이 api_usage 테이블에 자동
적재된다 — 호출 수, 입출력 토큰, 비용, 기능(kind)별 구분.
비용 = 공시 단가 × 토큰. 단가표는
src/kb/pricing.py, 변경·추가는 kb.toml[pricing]오버라이드 (모델 ID 부분 문자열 매칭이라global.프로파일 접두 무시 가능).토큰 수의 출처: Titan·OpenAI·anthropic·bedrock(Claude) 백엔드는 API가 돌려주는 실측값. Bedrock Cohere 임베딩은 토큰 수를 안 주므로 문자 수 기반 추정(대시보드에
≈표시). claude CLI는 응답의total_cost_usd를 그대로 기록 — 구독 인증으로 돌려도 "API로 돌렸다면"의 환산 비용이다. Bedrock Claude의 리전 고정 프로파일(us. 등)은 +10% 프리미엄이 있는데 단가표는 1P 공시가 기준이다.운영·비용 페이지: 일별 비용 차트, 기능·모델별 집계, 이번 달 누적(MTD)·일할 예상. 추정치이며 청구서가 아니다 — 실제 청구는 AWS/OpenAI 콘솔이 기준.
hashing 백엔드·비활성 기능은 호출 비용이 없으므로 계측하지 않는다.
11.2 인증 — Google 로그인 (권장) 또는 Cloudflare Access
대시보드는 사람용이므로 브라우저 SSO를 쓴다. 모드는 환경변수로 결정된다: Google OAuth > CF Access > 개발 모드(무인증).
(A) Google 로그인 — MCP 커넥터와 같은 인증. §4.2의 Google 클라이언트를 그대로
쓰고 리디렉션 URI만 하나 더 등록하면 된다(<대시보드 주소>/auth/callback).
Zero Trust 앱 설정이 필요 없고, 앱이 직접 검증하므로 "오리진 우회" 전제도 없다.
환경변수 | 의미 |
| §4.2와 동일한 클라이언트 |
| 허용 도메인/이메일 (§4.2와 공용) |
| 세션 쿠키·state 서명 키 (32자 이상, 레플리카 전체 동일) |
| 대시보드 공개 주소 (리디렉션 URI 계산) |
| 세션 수명(초, 기본 43200 = 12시간) |
동작: /auth/login → Google → /auth/callback에서 id_token을 검증하고 허용 도메인을
확인한 뒤 서명된 세션 쿠키(HttpOnly·SameSite=Lax, HTTPS면 Secure)를 굽는다.
서버 측 세션 저장소가 없어 대시보드도 레플리카 N개로 뜰 수 있다. 로그아웃은
헤더의 링크(/auth/logout).
(B) Cloudflare Access.
환경변수 | 의미 |
| Zero Trust 팀 이름 ( |
| Access 앱의 Application Audience(AUD) 태그 |
동작: CF Access가 SSO 통과 요청에 붙이는 Cf-Access-Jwt-Assertion 헤더(JWT)를
팀 도메인 JWKS로 서명 검증하고 aud/iss/exp를 확인한 뒤 email 클레임을 신원으로 쓴다.
⚠ CF 모드 전제: 오리진이 Cloudflare를 우회해서 접근될 수 없어야 한다. cloudflared tunnel(§11.3)로만 노출하거나 오리진 방화벽으로 잠글 것 — 헤더는 위조 가능하므로 우회 경로가 있으면 JWT 검증도 소용없다.
공통
환경변수 | 의미 |
| 관리 페이지(토큰/프로젝트/OAuth 커넥터) 허용 이메일, 쉼표 구분 |
| 개발 모드에서 표시할 사용자명 (기본 |
둘 다 비어 있으면 개발 모드(무인증, 전원 관리자, 배너 표시) — 사설망 밖 노출 금지.
11.3 Kubernetes 배포
deploy/k8s/에 kustomize 매니페스트 일체가 있다: Postgres StatefulSet(운영은 관리형
DB 권장), mcp Deployment(stateless ×2), dashboard, sync CronJob(git clone
initContainer 예시), slack-listener(선택), cloudflared tunnel(공인 LB/Ingress
불필요, CF Access 우회 원천 차단). mcp/dashboard에는 kb migrate initContainer가
붙어 있어 롤아웃마다 스키마가 자동으로 head까지 올라간다 (Alembic, advisory
lock으로 동시 기동 직렬화 — 레플리카 N개가 함께 떠도 안전). 빌드→시크릿→Zero
Trust 설정→kubectl apply -k 절차는 deploy/k8s/README.md.
이미지는 손으로 빌드하지 않는다 — main 머지 시 CD(.github/workflows/cd.yml)가
게이트(ruff + 실 Postgres pytest)를 통과한 커밋으로 멀티아치(amd64/arm64) 이미지를
빌드해 AWS ECR에 push하고, sha-<커밋> 좌표를 Actions summary에 남긴다. 자격증명은
GitHub OIDC 단기 토큰이라 저장된 AWS 키가 없다. 롤아웃은 그 좌표를
kustomization.yaml에 넣고 apply하는 수동 절차다 — 셋업·lifecycle 정책·롤백은
docs/08-cicd.md.
12. 개발
pip install -e ".[dev,dashboard,oauth]"
KB_TEST_DSN="host=127.0.0.1 port=5432 user=kb dbname=kb_test" pytest
ruff check src tests # 린트 (import 정렬·흔한 실수 검사)개발 규칙·아키텍처 지도·과거에 밟은 함정은 CLAUDE.md에 정리돼 있다 (Claude Code로 작업 시 자동 로드).
DB 계층은 SQLAlchemy 2.0이다: 스키마는 ORM 모델(kb/models.py)이 원본이고
마이그레이션은 Alembic(kb/migrations/) — 스키마를 바꾸려면 모델 수정 +
새 리비전 파일 한 쌍으로 (CLAUDE.md 불변 원칙 참고). 검색 신호 SQL은 의도적으로
text()를 유지한다 (pgvector/FTS/trgm 튜닝 문장 — 골든셋 재검증 없는 변형 금지).
테스트는 실제 Postgres에 붙는다(스키마는 매 세션 실제 Alembic 마이그레이션으로 생성 — 마이그레이션 경로가 상시 검증된다). MCP 왕복, 대시보드(TestClient), CF Access JWT 검증(RSA 실서명), OAuth 전 구간(동적 등록 → PKCE → Google 위임 → 토큰 발급·회전·폐기, 도메인 게이트, 대시보드 세션 쿠키 — Google HTTP 왕복만 대역), 사용량 계측, 검색 신호별 회귀(D12~D15 교정 포함), 노트 수명주기, ask 파이프라인(스크립트 LLM), 레거시 DB stamp 편입까지 포함.
13. 설계 문서
문서 | 내용 |
구현 전 스파이크 계획 (S0~S7) | |
데이터 모델, MCP 도구 설계, Phase 0~4 로드맵 | |
스파이크 실측 결과와 Decision Log — 왜 이렇게 만들었는지의 근거 | |
팀 배포·연결 절차와 "같은 실수 두 번 안 밟기" 워크플로 (CLAUDE.md 스니펫 포함) | |
웹 대시보드 + API 비용 계측 설계 (D8~D11, 밟은 함정 포함) | |
설계 재점검(D12 | |
OAuth 인증 설계 (D16~D18) — kb가 AS·Google이 IdP인 이유, 서명 state, 도메인 게이트, 밟은 함정 | |
main 머지 → ECR push CD: OIDC/IAM 셋업, 멀티아치 태그 규칙, lifecycle 함정, 롤백 (D16~D19 — oauth 문서와 번호 중복) |
spikes/는 검증에 쓴 버리는 코드다 (한국어 FTS 실험, RRF 랭킹 비교, 증류 A/B 등).
14. 현재 한계와 로드맵
임베딩: 기본 hashing 백엔드는 의미 검색 불가 — §9대로 교체 권장. Bedrock Titan v2는 실호출로 검증·측정 완료(docs/04 §S2), OpenAI 백엔드는 코드만 있고 미검증.
재순위는 opt-in: 기본은 RRF 순위 그대로 (LLM-free 원칙).
--rerank/rerank=true[rerank] backend를 켜야 소형 LLM 재채점이 동작한다.
인증: 공유/사용자별 베어러 토큰(§8.1)과 Google OAuth(§4.2)가 공존한다. TLS는 여전히 reverse proxy/터널 몫이다. OAuth 신원은 허용 도메인 = 팀 전체 접근이라 프로젝트 스코프를 걸 수 없다(세부 스코프가 필요하면
kbt_토큰을 쓴다 — 이메일별 스코프는 백로그). 스코프는 검색·조회 접근 제어일 뿐 DB 접근 권한이 아니므로 극도로 민감한 데이터는 여전히 인덱싱하지 않는 것이 원칙.쓰기 도구에 사전 검토 절차 없음: record_*는 즉시 반영된다. 대신 사후 장치가 있다 — 기록 시 유사 노트 힌트(
similar_existing), 대시보드 중복 병합 큐,supersedes/kb notes supersede로 대체(삭제가 아니라 감점+이력 보존).한국어 복합어:
simple파서 + 희귀 토큰 접두(:*) 질의가 어절 수준을 커버하고, pg_trgm trigram 신호(word_similarity 임계 0.2)가 띄어쓰기 없는 복합어 내부 매칭을 보완한다. 형태소 수준이 필요해지면 pgroonga 도입.pgvector 0.8 경로는 실측 미완: 필터 검색 리콜 보정(iterative_scan)과 halfvec(0.7+)은 버전 게이트로 구현했지만 개발 환경이 0.6이라 폴백 경로만 실검증됐다. compose/k8s의
pgvector/pgvector:pg16이미지는 0.8+이므로 거기서 자동 활성된다.실서비스 미검증 기능: github_prs(§7.5)·notion(§7.6)·linear(§7.7) 커넥터, Slack 멘션 자동응답(§7.2)은 페이크 API로 로직만 테스트했다 — 실제 토큰·워크스페이스 환경에서 첫 확인이 필요하다. bedrock 백엔드는 실호출 검증 완료(2026-08-05, Claude Haiku·Nova 2 Lite Converse+캐싱·Cohere embed v4 — 실측 A/B에서 Nova가 동일 작업 기준 3.0× 저렴). LLM 모델 전환은
scripts/model_ab.py로 실데이터 A/B 후 결정할 것.export 전용 운영 시 Slack 삭제 전파 안 됨: 실시간 리스너(§7.2)는 삭제를 전파하지만, export 백필만 쓰는 경우 export에 남아 있는 스레드는 지워졌는지 알 수 없다.
비용 계측은 추정치: 단가표가 하드코딩(+
[pricing]오버라이드)이라 공시가 변동을 자동 추적하지 않고, Bedrock Cohere는 토큰 수를 추정한다.api_usage는 계속 쌓이므로 수년 운영 시 오래된 행 정리(파티셔닝/DELETE)가 필요할 수 있다.평가 골든셋은 비어 있음:
kb eval하네스와--bootstrap(쿼리 로그 기반 스켈레톤 생성)은 있지만, 기대 문서(expect)를 채우는 건 팀의 몫이다. 검색 파라미터 ([search]가중치, 재순위 등)를 바꾸기 전에 골든셋부터 만드는 것을 권장한다.
15. 라이선스
This server cannot be installed
Maintenance
Resources
Unclaimed servers have limited discoverability.
Looking for Admin?
If you are the server author, to access and configure the admin panel.
Related MCP Servers
- Alicense-qualityCmaintenanceAn MCP server that enables AI agents to search, read, and contribute to a structured markdown knowledge base with citations, freshness tracking, and a safe write path, providing a shared, auditable company memory.6MIT
- Alicense-qualityDmaintenanceA knowledge base MCP server backed by Qdrant vector database with local embeddings for semantic search and document management.11ISC
- Alicense-qualityBmaintenanceSelf-hosted MCP server for storing and serving structured team knowledge, enabling AI sessions to load relevant team context without re-prompting.Apache 2.0
- Alicense-qualityAmaintenanceMCP server that enables AI agents to search, fetch, and analyze a self-maintaining markdown knowledge base with provenance, drift detection, and canonical definitions.MIT
Related MCP Connectors
Hosted MCP memory: save sessions/decisions once, search from Claude, Cursor, ChatGPT. EU-hosted FTS.
User-owned memory for AI agents, Copilot, Claude, IDEs, CLIs, and chat apps over remote MCP.
Your memory, everywhere AI goes. Build knowledge once, access it via MCP anywhere.
Latest Blog Posts
- Who's Calling? MCP Hosts Are an Identity Blind Spot (And the Spec Knows It)By Om-Shree-0709 on .mcpAgent IdentityOAuth 2.1
- Your AI Chatbot Just Exposed Your CEO's Salary to an InternBy Om-Shree-0709 on .Agent IdentityMCP SecurityOAuth Delegation
- Why MCP Servers Need Execution Sandboxing (And Why Your Current Stack Isn't Enough)By Om-Shree-0709 on .Agentic AiPrompt InjectionWebAssembly
MCP directory API
We provide all the information about MCP servers via our MCP API.
curl -X GET 'https://glama.ai/api/mcp/v1/servers/riemannulus/knowledge-base'
If you have feedback or need assistance with the MCP directory API, please join our Discord server