본문으로 건너뛰기
5분 AI.
GITHUB TRENDING WEEKLY #15 딥다이브 · 2026-10-23 분석

context-mode 딥다이브
— AI의 책상은 작게, 기억의 서랍은 크게

MCP 서버

빠른 판단

무엇
긴 도구 출력을 별도 실행 환경에서 가공하고 SQLite로 색인·검색하는 에이전트용 MCP 서버
이럴 때
로그·문서가 커지는 코딩 작업에서 현재 필요한 결과만 읽고 대화 압축 뒤에도 원문 근거를 다시 찾을 때
입력
긴 로그·문서·도구 출력과 처리 코드·검색 질의
결과
축약·가공한 결과와 다시 검색할 수 있는 원문 색인
긴 로그와 문서를 AI에게 전부 읽히는 대신, 코드로 계산하고 필요한 조각만 찾아 전달하는 MCP 서버입니다. TypeScript의 프로세스 제어, SQLite 전문 검색, 플랫폼 어댑터, 세션 복구를 한 흐름으로 공부합니다. 저장소는 mksglu/context-mode, 스타 31,896개, 포크 2,195개입니다. 수치는 2026-10-23 GitHub 기준이며, 구현 설명은 커밋 90af14e 기준입니다.
목차
  1. 프로젝트 한줄 요약
  2. 왜 주목받는가
  3. 기술 스택 전체 지도
  4. 아키텍처 심화 분석
  5. 디렉토리 구조 해부
  6. 학습 포인트 (기술별)
  7. 하드웨어 / 시스템 요구사항
  8. 직접 해볼 수 있는 실습 과제
  9. 관련 기술 심화 학습 로드맵
  10. 핵심 키워드 사전
  11. 참고 링크

1프로젝트 한줄 요약

AI가 읽는 양을 줄이면서, 다시 찾을 길을 남기는 도구

context-mode는 AI 코딩 에이전트와 도구 출력 사이에 놓이는 실행·검색 계층입니다. 에이전트가 긴 출력을 그대로 받는 대신, 별도 프로세스에서 데이터를 가공하거나 SQLite에 색인합니다. 핵심은 모델의 기억 용량을 늘리는 것이 아니라, 지금 읽을 정보와 나중에 찾을 정보를 나누는 데 있습니다.

용어
컨텍스트 윈도 (context window)
모델이 한 번의 응답을 만들 때 참고할 수 있는 입력의 범위입니다. 대화, 파일 내용, 도구 결과가 함께 공간을 차지합니다. 오래 보관한 파일과 지금 모델이 읽고 있는 내용은 서로 다릅니다.
한 문장 비유

작은 책상 위에 서류를 다 펼치지 말고, 서랍에 넣고 필요한 페이지만 꺼냅니다

책상은 컨텍스트 윈도, 서랍은 SQLite, 찾아보기는 전문 검색입니다. 로그 1만 줄을 책상에 올리는 대신 “실패 3건, 모두 같은 파일”이라는 결과만 올릴 수 있습니다.

다만 서랍에 보관했다고 모델이 저절로 아는 것은 아닙니다. 필요한 순간에 검색 도구를 호출하고, 검색 결과가 충분한지 판단하는 과정이 필요합니다.

1-1. 세 가지 흐름을 구별하면 전체가 보입니다

흐름어떻게 처리하나대표 진입점
계산코드를 실행해 개수·합계·오류 목록처럼 필요한 결과만 출력ctx_execute, ctx_execute_file
검색원문을 작은 조각으로 저장하고 질의에 맞는 부분을 반환ctx_index, ctx_search
복구파일 수정·오류·결정 등을 이벤트로 남기고 대화 압축 후 참조PostToolUse, PreCompact, SessionStart

src/server.ts는 MCP 도구를 등록합니다. src/executor.ts의 PolyglotExecutor는 자식 프로세스를 만들고, src/store.ts의 ContentStore는 색인과 검색을 담당합니다. 세션 이벤트는 src/session/db.ts의 SessionDB가 별도로 관리합니다.

1-2. 사용 장면을 작은 예제로 보기

다음은 MCP 도구 호출의 인자를 설명하는 예시입니다. 터미널 명령이 아니며, 도구 이름 앞의 접두사는 클라이언트마다 달라질 수 있습니다.

// 긴 출력 대신, 코드가 계산한 결과만 모델에게 전달
ctx_execute({
  language: "javascript",
  code: "const values = [10, 20, 30]; console.log(values.reduce((a, b) => a + b, 0));"
});

// 정확한 문장을 다시 읽고 싶다면 원문을 색인한 뒤 검색
ctx_index({ content: "## 재시도\n실패하면 최대 3번 재시도한다.", source: "연습문서" });
ctx_search({ queries: ["재시도"], source: "연습문서" });
학습의 중심
거대한 모델보다, 모델 주변의 소프트웨어를 공부하기 좋습니다

이 저장소의 핵심은 모델 학습 코드가 아닙니다. 도구 계약, 데이터 이동, 저장소 경계, 오류 처리, 플랫폼 호환성을 읽으면 “AI 기능을 실제 개발 도구로 만드는 법”을 배울 수 있습니다.

2왜 주목받는가

많이 읽는 에이전트가 만나는 비용과 기억의 문제

2-1. 도구가 많아질수록 출력도 늘어납니다

브라우저 스냅샷, 이슈 목록, 테스트 로그는 각각 유용하지만 한 대화에 계속 쌓이면 부담이 됩니다. context-mode는 이런 출력의 양을 줄이는 기능과, 대화가 압축된 뒤 작업을 이어 가는 기능을 함께 내세웁니다. GitHub Trending Weekly #15 선정과 스타 31,896개는 관심의 크기를 보여 주지만, 인기의 원인을 증명하는 실험은 아닙니다.

관심을 끌 만한 설계상의 이유는 분명합니다. 도구 출력을 줄이는 경로와 잊어버린 작업을 다시 찾는 경로가 같은 검색 기반 위에서 연결됩니다. 설치할 도구 하나가 절약과 복구를 함께 다룬다는 점이 사용자에게 이해하기 쉬운 제안입니다.

2-2. “98% 절약”은 어떤 실험의 숫자인가

자료기록된 결과읽을 때 주의할 점
README.md315 KB → 5.4 KB, 약 98% 감소대표 사례를 요약한 프로젝트의 주장
BENCHMARK.md 계산 부분315 KB → 5.5 KB, 98% 절약개수·통계만 출력하는 작업이 포함됨
같은 문서의 검색 부분60.3 KB → 11.0 KB, 82% 절약코드와 문장을 돌려주므로 더 많은 바이트 필요
같은 문서의 전체 요약376 KB → 16.5 KB, 96% 절약모든 작업에 98%가 적용된다는 뜻은 아님

이 수치들은 프로젝트가 기록한 벤치마크이며 독립 재측정 결과는 아닙니다. 바이트 감소율은 모델별 토큰 감소율, 전체 요금 감소율, 정답률과도 구별해야 합니다. 예를 들어 오류 개수만 물었다면 한 줄 통계로 충분하지만, 수정 코드를 작성하려면 오류의 위치와 원문이 더 필요합니다.

비유

“책 300쪽을 1쪽으로 줄였다”는 말만으로는 좋은 요약인지 알 수 없습니다. 독자가 원하는 것이 매출 합계인지, 계약서의 정확한 조항인지에 따라 필요한 분량이 달라집니다.

2-3. 경쟁 접근법과 비교하면 장점이 선명합니다

아래 표는 순위표가 아니라 해결 방식의 비교입니다. Claude Code·Cursor 같은 에이전트는 context-mode를 연결하는 호스트이기도 합니다. 특정 제품의 최신 성능 우열을 주장하지 않고, 이 저장소에서 확인되는 역할 차이를 비교합니다.

비교 대상강점context-mode의 위치
호스트의 대화 압축대화를 짧게 만들어 계속 진행도구 출력이 들어오기 전부터 양을 줄이고, 이벤트 기반 복구를 보완
일반 MCP 서버외부 기능을 표준 도구로 노출실행·색인·검색 도구에 라우팅 훅을 더해 사용 경로를 유도
단순 출력 자르기구현이 간단하고 응답 크기를 제한큰 출력을 색인하면 나중에 필요한 부분을 다시 검색 가능
벡터 검색 기반 RAG임베딩을 이용한 의미 유사도 검색핵심 검색은 SQLite FTS5 기반으로, 별도 임베딩 모델 없이 동작
메모 파일사람이 읽고 편집하기 쉬운 기록도구 이벤트를 자동 추출하고 검색·복구 흐름으로 연결

2-4. 여러 플랫폼을 지원하되 능력은 다릅니다

docs/platform-support.md는 17개 클라이언트와 OpenClaw 게이트웨이 통합을 구분합니다. src/adapters/types.ts의 PlatformId에는 OpenClaw를 포함한 이름 18개와 unknown이 있습니다. 따라서 “17개 지원”과 “18개 어댑터 이름”은 집계 범위가 다른 수치입니다.

도구 호출을 차단할 수 있는지, 인자를 고칠 수 있는지, 압축 직전에 개입할 수 있는지는 호스트마다 다릅니다. MCP 연결만 있는 구성은 도구를 제공하지만 자동 라우팅과 세션 복구까지 동일하게 보장하지는 않습니다. 이 차이를 인터페이스로 표현한 방식이 오히려 중요한 학습 대상입니다.

3기술 스택 전체 지도

실행 엔진 · 사용자 접점 · 빌드와 배포를 분리해서 읽기

3-1. 백엔드: HTTP 서비스보다 로컬 MCP 프로세스에 가깝습니다

package.json의 패키지 버전은 1.0.169, 모듈 형식은 module, Node.js 요구 버전은 >=22.5.0입니다. src/server.ts는 McpServer와 StdioServerTransport를 연결합니다. 핵심 실행 경로는 표준 입출력을 사용하는 MCP 서버이며, 별도 웹 검색 화면을 띄우는 구조는 아닙니다.

의존성package.json 범위bun.lock 기록배울 역할
MCP SDK^1.26.01.26.0도구 등록과 stdio 통신
Zod^3.25.03.25.76외부 도구 인자를 실행 시 검증
better-sqlite3^12.6.212.9.0SQLite 대체 드라이버 경로
Turndown^7.2.07.2.4HTML을 Markdown으로 변환
GFM 플러그인^1.0.21.0.2표 등 Markdown 표현 확장
Domino^2.2.02.2.0서버 측 DOM 처리
Clack / Picocolors^1.0.1 / ^1.1.11.2.0 / 1.1.1CLI 질문과 터미널 색상

정식 패키지 이름은 @modelcontextprotocol/sdk, @clack/prompts, @mixmark-io/domino, turndown-plugin-gfm입니다. 버전 앞의 ^는 허용 범위를 뜻합니다. 잠금 파일의 버전은 그 파일에 기록된 해석 결과이며, npm install을 사용하는 CI가 매번 같은 버전을 설치한다는 보장은 별도 문제입니다.

용어
런타임 검증과 타입 검사의 차이
TypeScript는 개발 중 코드의 타입을 검사합니다. 하지만 네트워크나 도구 호출로 받은 JSON이 올바른지는 실행 시 다시 확인해야 합니다. Zod는 이 입력 경계에서 값의 실제 모양을 검사합니다.

3-2. SQLite는 하나의 패키지로 고정돼 있지 않습니다

src/db-base.ts의 loadDatabase()는 Bun 환경이면 bun:sqlite를 고릅니다. 현대 Node 환경에서는 node:sqlite의 FTS5 지원을 검사하고, 사용할 수 없으면 better-sqlite3로 내려갑니다. 의존성 목록에 있는 라이브러리와 실제 실행 때 선택되는 구현은 다를 수 있습니다.

BunSQLiteAdapter와 NodeSQLiteAdapter가 호출 방식을 맞춥니다. 데이터베이스 구현을 바꾸면서 상위의 색인·세션 코드는 유지하는, 어댑터 패턴의 작은 사례입니다.

3-3. 프론트엔드: 호스트 UI와 소개 웹사이트

사용자 접점실제 구성역할의 경계
에이전트 화면Claude Code·IDE·CLI가 제공context-mode는 도구 결과와 훅 메시지를 전달
소개 웹web/index.html, web/context-saving.html, web/insight.html정적 HTML·CSS와 일부 JavaScript
웹 라우터web/worker.jsCloudflare Worker가 경로별 정적 자산 제공
공유 이미지 제작web/og/package.json의 playwright ^1.60.0OG 이미지 렌더링 도구, 핵심 서버 의존성과 구분

루트 의존성에는 React나 Vue가 없습니다. web/worker.js 주석은 별도 플랫폼 앱 배포를 설명하지만, 이 Worker 자체는 소개 페이지 라우팅과 자산 제공만 수행합니다. 소개 페이지가 있다는 이유로 저장소 전체를 프론트엔드 앱으로 이해하면 핵심을 놓칩니다.

3-4. 인프라·빌드: 소스와 배포용 번들을 함께 관리합니다

항목설정과 버전읽어 볼 파일
타입 검사TypeScript ^5.7.0 → 잠금 5.9.3tsconfig.json: strict, ES2022, NodeNext
번들링esbuild ^0.27.3 → 잠금 0.27.7package.json: ESM, --target=node18, 일부 패키지 외부화
개발 실행 도구tsx ^4.21.0 → 잠금 4.21.0dev, doctor 스크립트
테스트Vitest ^4.0.18 → 잠금 4.1.5vitest.config.ts: forks, 로컬 작업자 3개·CI 2개
CI 행렬Ubuntu·macOS·Windows, Node 22.5.github/workflows/ci.yml
보조 런타임Python 3.12, Elixir 1.17·OTP 27, Go stable같은 CI 설정, 일부 OS는 설치 방식이 다름
웹 배포Worker의 compatibility_date: 2025-01-01web/wrangler.jsonc

packageManager는 pnpm@10.23.0을 선언하지만 저장소에는 bun.lock이 있고, CI는 npm install을 사용합니다. 선언·잠금·CI 명령을 각각 확인해야 재현 조건을 이해할 수 있습니다. 또한 번들의 node18 대상은 출력 문법의 기준이며, 제품의 Node.js 최소 버전 22.5를 낮추는 설정이 아닙니다.

4아키텍처 심화 분석

데이터가 어디로 이동하고, 어느 순간 모델에게 보이는가

4-1. 시스템 구조도

두 갈래를 함께 보세요. MCP 도구 경로는 실행과 검색을 맡고, 훅 경로는 호출 전후와 세션 경계에 개입합니다. 모든 호스트가 아래의 훅 전체를 제공하는 것은 아닙니다.

[사용자 / 코딩 에이전트 호스트] | | | MCP 도구 호출 | 도구 전후 / 대화 압축 이벤트 v v [src/server.ts] [hooks/ + src/adapters/] McpServer 입력 형식 정규화 StdioServerTransport routePreToolUse() 결정 | | +-- ctx_execute ----------+-- 실행 경로 안내 / 차단 | | | v | [PolyglotExecutor] | 임시 스크립트 + 자식 프로세스 | stdout / stderr 수집, 크기 제한 | | | +-- 작은 결과 --------------------+ | +-- 큰 결과 --+ | | v | +-- ctx_index --> [ContentStore / SQLite] | | 문서 조각 + FTS5 | +-- ctx_search --> 검색·순위 융합 --------+ | | +-- ctx_fetch_and_index -- HTTP 수집·색인 + v [모델이 읽는 도구 응답] [PostToolUse] --> extractEvents() --> [SessionDB] | [PreCompact] --> buildResumeSnapshot() ---+-- 복구 스냅샷 저장 [SessionStart] --> 이벤트 문서 + 안내문 --+-- 필요한 기록 검색 [선택: 플랫폼 연결 설정 있음] 세션 이벤트 --> hooks/platform-bridge.mjs --> 설정된 외부 /events

4-2. 설계 패턴 ① 큰 값 대신 검색 가능한 참조를 돌려줍니다

ctx_execute의 처리기는 PolyglotExecutor.execute()를 호출합니다. 실행기는 임시 디렉터리에 스크립트를 쓰고 child_process.spawn()으로 런타임을 실행합니다. Rust는 먼저 컴파일하는 별도 분기가 있습니다. 일반 실행의 현재 디렉터리는 프로젝트 루트 또는 호출의 cwd입니다.

완료 후 src/server.ts가 출력 크기를 검사합니다. 큰 문자열 자체 대신 “어느 출처에 몇 조각을 색인했는지”와 검색 방법을 반환하는 것이 핵심입니다. 분산 시스템에서 큰 파일을 직접 보내는 대신 저장 위치와 식별자를 보내는 방식과 닮았습니다.

// src/server.ts의 실제 상수
const INTENT_SEARCH_THRESHOLD = 5_000;
const LARGE_OUTPUT_THRESHOLD = 102_400;

// 성공한 일반 stdout 경로를 설명하기 위한 축약 의사코드
if (intent?.trim() && Buffer.byteLength(stdout) > INTENT_SEARCH_THRESHOLD) {
  return intentSearch(stdout, intent, source);
}
if (Buffer.byteLength(stdout) > LARGE_OUTPUT_THRESHOLD) {
  return indexStdout(stdout, source);
}
return stdout;

intentSearch()는 원문을 영속 저장소에 색인한 다음 의도에 맞는 부분을 찾습니다. indexStdout()는 색인 메타데이터와 후속 검색 안내를 만듭니다. 실제 응답에는 실행 코드의 일부를 보여 주는 내용과 오류·타임아웃 처리도 있으므로, 위 코드는 전체 구현을 대체하지 않습니다.

출력 감소와 정보 삭제는 같은 일이 아니지만, 검색 가능한 저장에도 크기와 보존 기간의 한계는 있습니다. 실행기는 stdout과 stderr를 합쳐 기본 100 * 1024 * 1024바이트를 넘으면 프로세스를 종료합니다. 이 제한 너머의 출력까지 모두 보관된다고 이해하면 안 됩니다.

구현의 경계
여기서 sandbox는 완전한 운영체제 격리를 뜻하지 않습니다

src/executor.ts는 임시 스크립트와 자식 프로세스를 사용하고 위험한 환경변수 일부를 제거합니다. 반면 실제 홈 경로와 많은 환경변수는 유지하며, 핵심 실행기에 컨테이너나 가상머신을 만드는 단계는 없습니다.

따라서 이 계층은 주로 출력과 실행 수명을 관리합니다. 파일·네트워크 권한의 강한 격리는 호스트와 운영체제의 정책까지 함께 봐야 합니다.

4-3. 설계 패턴 ② 검색을 작은 단계의 파이프라인으로 만듭니다

ContentStore.index()는 Markdown 제목과 코드 펜스를 읽어 문서 조각을 만듭니다. sources에는 출처와 파일 기반 색인의 해시를, chunks와 chunks_trigram에는 서로 다른 방식의 전문 색인을 둡니다. 첫 번째는 porter unicode61, 두 번째는 trigram 토크나이저를 사용합니다.

searchWithFallback(query) | +-- 변경된 파일의 mtime·SHA-256 확인 및 재색인 | +-- #rrfSearch() | +-- Porter 검색 (OR) -- BM25로 정렬 | +-- trigram 검색 (OR) -- BM25로 정렬 | +-- 두 결과의 순위를 RRF로 합침 | +-- 결과 있음 --> 제목·단어 거리·인접 출현으로 재정렬 | +-- 결과 없음 --> fuzzyCorrect() --> RRF 재검색 | +-- 여전히 없음 --> 빈 결과

#rrfSearch()의 상수 K는 60입니다. 한 검색 목록에서 순위가 r이면 1 / (60 + r)을 더합니다. 서로 다른 점수의 절댓값을 억지로 비교하지 않고 순위로 합치는 방식입니다.

// RRF를 손으로 계산하는 독립 예제: 순위는 1부터 시작
const score = ranks => ranks.reduce((sum, rank) => sum + 1 / (60 + rank), 0);
const both = score([1, 2]);  // 두 검색에서 1위, 2위
const one = score([1]);      // 한 검색에서만 1위
console.log({ both, one });

#applyProximityReranking()은 RRF 상위 결과를 요청한 개수만큼 추린 뒤 제목 일치, 본문의 단어 간 거리, 인접한 단어 쌍의 반복 횟수로 순서를 다시 정합니다. “BM25를 쓴다”는 소개를 넘어, 후보 검색과 순위 조정의 책임이 어떻게 분리되는지 읽어 보세요.

오타 보정은 fuzzyCorrect()와 편집 거리 계산을 사용합니다. 의미를 이해하는 임베딩 검색은 아니므로, “접속 실패”와 “connection refused”처럼 표현이 다른 질의는 결과를 직접 확인해야 합니다. 한글 처리 역시 영어 어간 추출과 똑같은 효과를 기대하면 안 됩니다.

용어
전문 검색 · BM25 · trigram
전문 검색은 문서 본문에 있는 단어를 찾는 기술입니다. BM25는 단어의 희소성과 등장 빈도 등을 이용해 결과를 정렬합니다. trigram은 문자열을 세 글자 단위로 나누어 찾는 방법으로, 부분 문자열 검색을 보완합니다.

4-4. 설계 패턴 ③ 플랫폼 형식은 바깥에서, 정책은 안쪽에서 처리합니다

src/adapters/types.ts의 HookAdapter는 입력 파싱, 응답 형식, 설정 경로, 지원 능력의 계약입니다. hooks/core/routing.mjs의 routePreToolUse()는 플랫폼 전용 JSON 대신 공통 결정 객체를 만듭니다.

// hooks/core/routing.mjs가 사용하는 정규화된 결정 형태
{ action: "deny", reason: "..." }
{ action: "modify", updatedInput: { ... } }
{ action: "context", additionalContext: "..." }
null // 그대로 통과

여러 형식을 각각 구현하되 중심 정책을 공유하면 “curl 출력은 실행·색인 경로로 보내자”라는 규칙을 한곳에서 고칠 수 있습니다. mcpRedirect()는 MCP 도구가 준비되지 않으면 우회 결정을 통과시켜, 대체 도구가 없어 작업이 막히는 상황을 피합니다.

소스의 어댑터관찰할 설정학습 포인트
src/adapters/claude-code/index.tscanModifyArgs: true인자 변경이 가능한 호스트
src/adapters/codex/index.tscanModifyArgs: false, canModifyOutput: false차단과 인자 변경을 별도 능력으로 구분
src/adapters/zed/index.ts훅 관련 능력이 모두 falseMCP 도구 제공과 훅 제공은 별개

위 표의 파일은 모두 src/adapters/ 아래에 있습니다. 읽기·명령 차단 정책은 src/security.ts의 evaluateFilePath(), evaluateCommandDenyOnly() 등과 연결됩니다. 라우팅을 사용한다고 임의의 코드가 실행 시 완전히 검증되는 것은 아닙니다.

4-5. 설계 패턴 ④ 이벤트를 저장하고 복구용 상태를 따로 만듭니다

hooks/posttooluse.mjs는 extractEvents()로 파일·오류·Git·작업 등의 사실을 추출합니다. hooks/session-loaders.mjs의 attributeAndInsertEvents()가 프로젝트 귀속을 계산하고 DB에 넣습니다. 원시 도구 응답을 매번 대화에 다시 넣는 대신, 이벤트 기록과 읽기용 안내를 나눕니다.

  1. 수집: src/session/extract.ts가 도구 입력·출력을 여러 추출기에 통과시킵니다.
  2. 저장: SessionDB는 최근 5개 이벤트 범위에서 중복을 확인하고, 세션당 1,000개 상한에서 중요도가 낮은 이벤트부터, 같은 중요도에서는 오래된 이벤트부터 밀어냅니다.
  3. 압축 직전: hooks/precompact.mjs가 buildResumeSnapshot()을 호출하고 upsertResume()으로 보관합니다.
  4. 재개: hooks/sessionstart.mjs가 이벤트 문서와 안내를 만들며, 상황에 따라 저장된 스냅샷도 복구합니다.
  5. 상세 조회: hooks/session-directive.mjs는 session-events 출처를 검색하도록 안내합니다.

buildResumeSnapshot()은 목표·파일·오류·결정·작업·최근 사용자 메시지 등을 조합합니다. 최근 사용자 메시지는 최대 3개, 각 400자 제한이 있고, 파일 목록은 최대 10개를 보여 줍니다. 과거 이벤트 전체를 영구히 보존하거나, 당시 프로세스를 완전히 재생하는 시스템으로 이해해서는 안 됩니다.

4-6. 실제 동작을 바꾸는 작은 제한들

제한커밋 기준 구현왜 필요한가
검색 결과 수스키마 기본값은 3, 처리기 평상시 최대는 2선언만 읽으면 실제 응답 수를 오해할 수 있음
검색 호출 빈도기본 60초 창, 4번째부터 질의당 1건, 9번째부터 차단검색 결과 자체가 컨텍스트를 채우는 것을 방지
빈도 집계 범위FloodGuard가 에이전트 문맥 키별로 집계하며, 식별자를 구하지 못하면 공통 키 사용식별된 에이전트 사이에서 호출 예산을 분리
검색 응답 예산MAX_TOTAL = 40 * 1024실제로는 문자열 길이를 누적해 다음 질의 전에 검사
배치 실행도구 스키마의 동시성 1~8, 기본 1동시에 생성되는 프로세스와 출력량 제어

검색 응답의 예산은 엄격한 40KiB 바이트 상한이 아닙니다. 실제 누적은 formatted.length를 사용하므로 한글·이모지의 UTF-8 바이트 수와 다르고, 질의를 처리한 뒤 목표값을 넘어갈 수도 있습니다. 상수의 주석뿐 아니라 비교 시점과 계산 단위까지 확인해야 합니다.

src/runPool.ts의 runPool()은 실패를 작업별로 보관하고, 결과는 입력 순서에 맞춥니다. runBatchCommands()에서 동시성 1은 전체 명령이 시간 예산을 공유하고, 동시성 2 이상은 명령별로 같은 타임아웃을 받습니다. 숫자 하나를 바꿨는데 시간 정책까지 달라지는 중요한 지점입니다.

5디렉토리 구조 해부

실행 파일보다 먼저, 책임별 지도를 그립니다
context-mode/ +-- package.json / bun.lock 의존성·명령·잠금 기록 +-- tsconfig.json TypeScript 컴파일 경계 +-- start.mjs 시작 환경·런타임 보정 +-- src/ | +-- server.ts MCP 도구 등록과 처리 | +-- executor.ts / runtime.ts 실행과 런타임 탐지 | +-- store.ts 원문 조각·FTS5 검색 | +-- store-directory.ts 제한 있는 디렉터리 순회 | +-- db-base.ts SQLite 드라이버·WAL·재시도 | +-- security.ts 파일·명령 정책 평가 | +-- runPool.ts 공통 동시 실행 풀 | +-- adapters/ 호스트별 입력·설정·능력 | +-- search/ 통합 검색·스키마·호출 제한 | +-- session/ 이벤트·복구·분석 | +-- util/ 경로·설정·프로세스 보조 +-- hooks/ 호스트가 직접 호출하는 훅 | +-- core/ 공통 라우팅·포맷·준비 상태 | +-- session-directive.mjs 재개 안내와 이벤트 문서 | +-- platform-bridge.mjs 선택적 외부 이벤트 전달 +-- configs/ 플랫폼별 설정 예시 +-- skills/ 도구 선택·진단·검색 안내 +-- tests/ 단위·통합·회귀·벤치마크 자료 +-- docs/ 지원표와 설계 결정 기록 +-- scripts/ 번들 검사·설치 후 보정 +-- web/ 소개 페이지·Worker·공유 이미지 +-- .github/workflows/ CI·번들 갱신·보조 검증 +-- server.bundle.mjs 서버 배포 번들 +-- cli.bundle.mjs CLI 배포 번들

5-1. 처음 읽을 때의 추천 순서

src/types.ts로 결과와 이벤트의 모양을 익힌 다음, src/executor.ts와 src/store.ts에서 두 핵심 부품을 읽어 보세요. 그다음 src/server.ts에서 ctx_execute 처리기를 찾아 부품이 연결되는 과정을 봅니다. 4,991줄짜리 서버를 첫 줄부터 외우는 것보다 한 요청의 경로를 따라가는 편이 낫습니다.

묶음공부할 책임함께 읽을 자료
src/adapters/같은 정책을 다른 호스트 형식에 연결tests/adapters/, docs/platform-support.md
src/session/관찰한 사건과 복구 시 보여 줄 내용을 분리tests/session/session-snapshot.test.ts
hooks/core/도구 실행 전 결정과 호스트별 출력 형식tests/hooks/core-routing.test.ts
docs/adr/설계가 바뀐 이유와 되돌리지 말아야 할 조건다중 작성자·통계 산식에 관한 ADR
배포 번들컴파일·묶기·외부 의존성이 제품에 미치는 영향.github/workflows/bundle.yml

5-2. 줄 수는 “무엇을 셌는지”와 함께 읽습니다

코드 규모를 말할 때 생성 번들과 테스트를 나누어야, 실제로 공부할 구현의 크기가 보입니다. 아래는 줄바꿈 수를 센 대략적인 물리적 줄 수입니다. 주석과 빈 줄을 포함하며, .git·node_modules·build·dist와 *.bundle.mjs는 제외했습니다.

범위파일 수대략 줄 수
TypeScript 전체320개126,566줄
그중 구현 src/95개41,617줄
그중 tests/221개84,756줄, 테스트 외 보조 파일 포함
그 밖의 TypeScript4개193줄
JavaScript.mjs 91개 + .js 1개13,975줄 + 31줄
Shell / HTML4개 / 7개1,652줄 / 2,598줄

*.test.ts 파일은 210개입니다. 파일 수는 테스트 실행 결과나 커버리지를 뜻하지 않습니다. 주요 구현은 src/store.ts 2,071줄, src/executor.ts 785줄, src/session/extract.ts 2,960줄, src/session/db.ts 1,726줄입니다.

6학습 포인트 (기술별)

기능을 외우기보다, 작은 문제에 설계를 옮겨 봅니다

6-1. TypeScript와 Zod: 입력 경계를 설계하기

src/search/ctx-search-schema.ts의 buildCtxSearchInputSchema()는 공유 DB 모드일 때만 project 필드를 스키마에 넣습니다. 사용할 수 없는 선택지를 설명문으로만 금지하지 않고, 도구가 보여 주는 계약 자체에서 제외하는 설계입니다.

같은 파일의 coerceJsonArray()는 일부 클라이언트가 문자열로 보내는 배열 인자를 보정합니다. 학습할 부분은 “무조건 엄격하게 거절할까”와 “어떤 입력을 호환 목적으로 받아 줄까”의 경계입니다.

// resolveProjectScope()의 의미를 표로 옮긴 의사코드
공유 모드 꺼짐           => undefined  // 별도 필터 없음
공유 모드 켜짐 + 생략    => 현재 프로젝트 경로
공유 모드 켜짐 + global  => null       // 전체 프로젝트 조회
공유 모드 켜짐 + 경로    => 지정 경로

실습 아이디어: undefined, null, 빈 문자열, global을 구분하는 입력표를 만드세요. 각 값이 “생략”, “전체”, “잘못된 경로” 중 무엇인지 먼저 정하고 구현을 설계합니다.

6-2. Node.js 프로세스: 정상 종료보다 실패 경로 읽기

PolyglotExecutor는 stdout·stderr 스트림을 모으고, 크기 상한과 시간 제한을 적용합니다. Unix에서는 프로세스 그룹을 만들고 killTree()가 하위 프로세스 종료를 돕습니다. 백그라운드 실행은 타임아웃 시 연결을 떼고 일부 결과를 반환하므로 일반 실행과 수명 관리가 다릅니다.

실습 아이디어: “명령이 실패함”, “실행 파일이 없음”, “시간이 지남”, “출력 상한 초과”를 구분해 ExecResult의 stdout, stderr, exitCode, timedOut에 무엇을 담을지 써 보세요.

6-3. SQLite: WAL은 여러 작성자를 무제한으로 병렬화하지 않습니다

applyWALPragmas()는 journal_mode = WAL, synchronous = NORMAL을 설정합니다. 읽기와 쓰기의 공존을 돕지만, 쓰기 경합은 여전히 처리해야 합니다. 생성 시 30,000ms 대기 설정과 withRetry()의 100·500·2,000ms 재시도가 함께 사용됩니다.

withRetry()는 동기 API를 유지하기 위해 재시도 사이를 바쁜 대기로 구현합니다. 따라서 편한 호출 구조와 프로세스의 이벤트 루프를 막는 비용을 함께 토론할 수 있습니다.

실습 아이디어: docs/adr/0001-sessiondb-multi-writer.md를 읽고, 단일 작성자 잠금이 다중 창 사용을 왜 막았는지 사건·원인·해결책 세 칸으로 정리하세요.

6-4. 검색: 정확한 원문을 얼마나 되돌려줄 것인가

집계 작업은 한 줄로 끝날 수 있지만 문서 검색은 사용할 코드와 조건을 충분히 반환해야 합니다. ContentStore는 제목·코드 여부·출처를 보관하고, src/search/unified.ts의 searchAllSources()는 조회 모드에 따라 소스를 합칩니다.

기본 relevance 모드는 ContentStore 결과를 사용합니다. timeline 모드는 SessionDB와 자동 메모 검색을 추가하고 시간순으로 합칩니다. 모든 검색 모드가 같은 자료와 같은 순서를 제공하는 것은 아닙니다.

실습 아이디어: 짧은 문서 5개에 같은 단어를 다른 제목·위치로 배치하고 예상 순위를 적으세요. 영어 어간, 한글, 오타, 두 글자 질의를 각각 준비하면 검색기의 가정이 보입니다.

6-5. 동시성: 빨라지는 대신 늘어나는 자원을 계산하기

runPool()은 정해진 수의 작업자가 공유 인덱스를 가져가며 다음 작업을 실행합니다. settled[idx]에 결과를 넣어 완료 순서와 출력 순서를 분리합니다. 한 작업의 예외가 다른 작업의 결과를 없애지 않는 점이 핵심입니다.

실습 아이디어: 실행 시간이 30·10·20ms인 세 작업을 동시성 2로 처리하는 시간표를 그리세요. 둘째 작업이 실패해도 셋째 작업이 진행돼야 하며, 반환 배열은 원래 입력 순서여야 합니다.

6-6. 회귀 테스트: 버그를 조건으로 바꾸기

검증 대상읽을 테스트확인하는 행동
검색 저장소tests/store.test.tsFTS5 스키마·색인·검색·마이그레이션
복구 스냅샷tests/session/session-snapshot.test.ts빈 이벤트·파일 중복·최근 10개 파일
검색 호출 제한tests/core/search-flood-guard.test.ts에이전트별 호출 예산·시간 창 초기화

좋은 학습 결과는 코드를 따라 치는 데서 끝나지 않고, 이 설계가 지켜야 할 조건을 자기 말로 설명하는 것입니다.

7하드웨어 / 시스템 요구사항

명시된 요구사항과 자원 사용을 추정하는 방법

7-1. 필수 조건과 선택 조건

항목확인되는 조건초보자가 이해할 점
운영체제CI 대상은 Linux·macOS·Windows호스트별 훅 지원과 경로 처리는 별도 확인
기본 런타임package.json: Node.js >=22.5.0번들 대상 node18과 혼동하지 않기
Bun별도의 SQLite·실행 경로 지원대안 런타임이며 모든 도구를 대체한다는 뜻은 아님
SQLiteFTS5 지원 필요nodeSqliteHasFts5()가 실제 기능을 검사
언어별 실행기사용할 언어의 런타임 또는 컴파일러Python·Rust·Go 등을 모두 설치해야 하는 것은 아님
호스트MCP 또는 지원 플러그인 경로를 갖춘 에이전트훅이 없으면 자동 라우팅 기능이 제한될 수 있음
GPU핵심 실행·검색 경로에는 GPU 연산 요구 없음모델 실행 비용과 이 서버의 자원을 구분

src/runtime.ts의 Language는 JavaScript, TypeScript, Python, Shell, Ruby, Go, Rust, PHP, Perl, R, Elixir, C#의 12개를 선언합니다. detectRuntimes()가 설치 상태를 확인하므로 선언된 언어와 현재 사용할 수 있는 언어는 다릅니다. C# 경로는 dotnet-script, Rust 경로는 rustc를 찾습니다.

7-2. 메모리는 숫자를 외우기보다 상한을 계산합니다

공식적인 최소 RAM·CPU 등급은 루트 패키지와 핵심 설정에 명시돼 있지 않습니다. 실행 하나의 출력 수집 상한이 100MiB라면, 8개가 동시에 상한에 가까워지는 경우 수집 버퍼만 약 800MiB가 될 수 있습니다. 문자열 변환·버퍼 합치기·SQLite 캐시·각 자식 프로세스의 메모리는 여기에 추가됩니다.

이 계산은 실제 사용량 측정이나 최소 사양이 아닙니다. hardCapBytes는 출력 버퍼의 기준이며 자식 프로세스 전체의 RAM 한도를 설정하는 기능도 아닙니다. 대형 빌드를 실행하면 빌드 도구 자체의 요구사항이 더 클 수 있습니다.

비유

동시성은 계산대 수와 같습니다. 계산대를 늘리면 대기는 줄어들지만, 각 계산대 앞의 장바구니와 직원이 차지하는 공간도 함께 늘어납니다.

7-3. 디스크·네트워크·시간 제한도 요구사항입니다

src/lifecycle.ts는 부모 프로세스의 생존과 종료 신호를 살펴 남겨진 서버를 정리합니다. 이 저장소에서는 검색 성능뿐 아니라 “도구가 언제 끝나야 하는가”도 시스템 요구사항의 일부입니다.

8직접 해볼 수 있는 실습 과제

설치 없이 시작하고, 작은 독립 구현으로 이해를 확인합니다

아래 과제는 소스를 읽거나 별도의 연습용 코드로 해결할 수 있습니다. 실제 에이전트 계정, 운영 데이터, 외부 API는 필요하지 않습니다. 각 과제는 완성물과 통과 조건이 있으므로 스스로 이해도를 점검하기 좋습니다.

과제 1 · 입문

도구 호출 한 번의 여행 지도 30~45분

할 일: ctx_execute 등록부에서 시작해 PolyglotExecutor.execute(), 출력 검사, indexStdout(), ContentStore.index()로 이어지는 화살표 5개를 그립니다.

완성물: 함수명·입력·반환값을 적은 한 장짜리 순서도.

통과 조건: 4,000바이트, 6,000바이트, 110,000바이트 stdout이 각각 어떻게 처리되는지 설명합니다. 6,000바이트는 intent의 유무에 따라 경로가 달라져야 합니다.

힌트: 상수는 글자 수가 아니라 Buffer.byteLength()로 비교됩니다.

과제 2 · 입문

글자 수와 바이트 수의 차이 20~30분

할 일: ASCII, 한글, 이모지를 포함한 문자열의 길이를 예상하고 아래 독립 예제와 비교합니다.

완성물: 문자열·UTF-16 길이·UTF-8 바이트 수를 비교한 표.

통과 조건: “5000자면 항상 5000바이트”가 왜 틀린지 설명하고, src/truncate.ts가 문자 경계를 보존하려는 이유를 적습니다.

// 저장소 모듈을 불러오지 않는 독립 JavaScript 예제
for (const text of ["abc", "한글", "🙂"]) {
  console.log({ text, units: text.length, bytes: Buffer.byteLength(text, "utf8") });
}
// 예상: abc = 3 / 3, 한글 = 2 / 6, 🙂 = 2 / 4
과제 3 · 중급

문서 5개로 순위 융합 설계하기 1~2시간

할 일: 문서 A~E에 대해 “단어 검색 순위”와 “부분 문자열 순위”를 직접 정합니다. 1 / (60 + 순위)를 더하는 함수를 독립적으로 만들고 결과를 정렬합니다.

완성물: 순위표 두 개, RRF 계산표, 예상 상위 3건.

통과 조건: 두 목록에 모두 등장하는 문서가 한쪽에만 등장하는 문서보다 높아지는 예를 설명합니다. 같은 점수일 때 정렬 기준도 명시합니다.

확장: 제목 일치 보정을 더한 뒤 원래 RRF 점수와 최종 순위를 구분해 보세요.

과제 4 · 중급

고장 나도 결과 순서를 지키는 작업 풀 2~3시간

할 일: src/runPool.ts를 참고해 지연 시간과 실패 여부만 가진 가짜 작업 5개를 처리하는 함수를 작성합니다.

완성물: 동시성 제한, 작업별 성공·실패 결과, 시작·종료 시각표.

통과 조건: 동시성 2일 때 실행 중인 작업이 2개를 넘지 않고, 한 작업이 실패해도 다른 작업은 완료되며 결과 배열은 입력 순서를 유지합니다.

확장: 전체 시간 예산과 작업별 시간 예산을 별도 옵션으로 설계하고 둘의 차이를 예제로 보여 주세요.

과제 5 · 고급

세션 복구의 반례를 설계하기 반나절

할 일: 가짜 이벤트로 파일 수정, 작업 완료, 미해결 오류, 사용자 결정을 표현하고 최신 상태를 요약하는 순수 함수를 만듭니다. 이벤트를 실제 DB나 호스트에 넣을 필요는 없습니다.

완성물: 이벤트 JSON 10건, 복구 안내문, 실패 사례 4개와 기대 결과.

통과 조건: 완료된 작업을 다시 미완료로 보여 주지 않고, 다른 프로젝트의 이벤트를 섞지 않으며, 중복 이벤트가 상태를 왜곡하지 않아야 합니다. 1,000개 제한으로 오래된 결정이 사라질 때의 처리 방침도 설명합니다.

함께 읽기: src/session/snapshot.ts, src/session/project-attribution.ts, tests/session/session-pipeline.test.ts.

과제의 정답은 실행 결과 하나보다, 어떤 정보가 사라져도 되고 어떤 정보는 다시 찾을 수 있어야 하는지 정한 기준에 있습니다.

9관련 기술 심화 학습 로드맵

6주 동안 요청 하나에서 시스템 전체로 넓혀 갑니다

JavaScript의 배열·객체·함수와 async/await를 알고 있다는 기준입니다. 매주 읽을 범위를 좁히고, 마지막에 설명 가능한 산출물을 하나씩 남깁니다. 주당 시간은 학습 계획용 제안이며 성능이나 숙련도에 대한 보장은 아닙니다.

주차핵심 주제읽을 범위산출물
1주 · 3~4시간TypeScript 타입·모듈·입력 계약package.json, tsconfig.json, src/types.ts입력과 결과의 타입 지도
2주 · 4~5시간자식 프로세스·스트림·시간 제한src/executor.ts, src/runtime.ts정상·실패·초과 출력 순서도
3주 · 4~6시간SQLite·트랜잭션·WAL·FTS5src/db-base.ts, src/store.ts 스키마 부분출처·조각·이벤트 관계도
4주 · 4~6시간검색 후보·RRF·재정렬searchWithFallback(), src/search/unified.ts작은 검색 평가표와 실패 질의
5주 · 4~5시간MCP·어댑터·라우팅 정책src/server.ts 도구 한 개, hooks/core/routing.mjs호스트 두 개의 능력 비교표
6주 · 5~6시간이벤트 기록·복구·회귀 테스트src/session/, hooks/session-directive.mjs, docs/adr/복구 시나리오와 설계 결정문

9-1. 무엇부터 읽을지 막힐 때의 질문

  1. 입력: 이 함수는 신뢰할 수 없는 JSON을 받는가, 이미 검증된 값을 받는가?
  2. 보관: 원문은 어디에 있고, 모델이 읽는 응답에는 무엇만 들어 있는가?
  3. 실패: 예외가 생기면 대화가 멈추는가, 기능 일부만 빠지는가?
  4. 범위: 상태가 프로세스·세션·프로젝트·에이전트 중 어디에 속하는가?
  5. 검증: 실제 회귀 테스트는 어떤 입력과 기대 결과로 조건을 표현하는가?
다음 단계
나만의 작은 도구에 옮길 수 있는 설계

로그 분석기에는 “집계 후 출력”, 문서 도구에는 “출처를 가진 조각 검색”, 긴 작업 도우미에는 “이벤트와 복구 상태 분리”를 적용할 수 있습니다. 세 기능을 한 번에 복제하기보다 해결하려는 문제에 맞는 한 가지부터 옮겨 보세요.

이 저장소를 다 읽는 것보다, 입력·저장·출력·복구의 경계를 다른 문제에도 그릴 수 있게 되는 것이 목표입니다.

10핵심 키워드 사전

낯선 단어를 데이터 흐름에 연결하기
용어쉬운 설명
컨텍스트 윈도모델이 이번 응답을 만들 때 펼쳐 볼 수 있는 입력 공간.
토큰모델이 글을 처리하는 단위. 글자 수나 UTF-8 바이트 수와 같지 않습니다.
MCP호스트와 도구 서버가 기능과 데이터를 주고받는 표준 프로토콜.
호스트대화와 도구 호출을 운영하는 코딩 에이전트 앱 또는 CLI.
stdio프로세스의 표준 입력·출력. 이 서버와 호스트가 메시지를 주고받는 통로.
훅 (hook)도구 호출 전후처럼 정해진 순간에 실행되는 연결 지점.
라우팅어떤 작업을 어떤 도구 경로로 보낼지 결정하는 것.
어댑터다른 입력 형식과 설정을 공통 인터페이스에 맞춰 주는 변환 부품.
스키마JSON에 어떤 필드와 값이 들어올 수 있는지 정한 모양과 규칙.
자식 프로세스부모 프로그램이 시작한 별도 실행 단위. 메모리는 분리돼도 파일·네트워크 권한은 별도 문제입니다.
stdout / stderr일반 출력과 진단 출력의 통로. 코드에 따라 오류가 일반 출력으로 섞일 수도 있습니다.
sandbox실행을 분리·관리하는 공간이라는 표현. 이 프로젝트의 실제 격리 범위는 프로세스·환경·호스트 정책을 함께 봐야 합니다.
SQLite파일에 데이터를 저장하는 내장형 관계형 데이터베이스.
FTS5SQLite에서 문서 본문의 단어를 빠르게 찾는 전문 검색 확장.
역색인단어마다 그 단어가 등장한 문서를 가리키는 찾아보기.
청크 (chunk)저장·검색·전달하기 좋게 나눈 문서 조각.
BM25검색어의 희소성과 문서 내 빈도 등을 반영하는 검색 점수 방식.
Porter영어 단어의 어형 차이를 줄이는 어간 추출 방식.
trigram문자열을 연속한 세 글자 단위로 나누는 방식.
RRF검색기들의 결과 순위를 점수로 바꾸어 합치는 순위 융합 방식.
편집 거리글자를 삽입·삭제·교체해 한 단어를 다른 단어로 바꾸는 데 필요한 횟수.
WAL변경 내용을 별도 로그에 먼저 기록하는 SQLite 모드. 읽기·쓰기 공존을 돕지만 쓰기 경합이 사라지지는 않습니다.
트랜잭션여러 데이터 변경을 하나의 성공·실패 묶음으로 처리하는 단위.
중복 제거같은 사실을 반복 저장하거나 반복 집계하지 않도록 거르는 처리.
대화 압축길어진 대화를 줄여 다음 작업에 필요한 공간을 확보하는 과정.
복구 스냅샷나중에 작업 상태를 되찾기 위한 요약. 실행 중이던 컴퓨터 전체의 복사본은 아닙니다.
유한 동시성전체 작업이 많아도 동시에 진행하는 개수는 상한 안에 두는 실행 방식.
번들 / 잠금 파일번들은 배포용으로 묶은 코드, 잠금 파일은 해석된 의존성 버전의 기록입니다.
ADR중요한 설계 결정의 이유·대안·결과를 남기는 문서.

11참고 링크

버전과 구현 범위를 함께 남겨 두는 읽기 목록

11-1. 공식 저장소와 구현 근거

11-2. 관련 기술 공식 학습 자료

현재 상태 (2026-10-23 확인)

항목상태기준과 해석
선정GitHub Trending Weekly #15분석일 2026-10-23
스타 / 포크31,896 / 2,1952026-10-23 GitHub 기준
주 언어TypeScriptGitHub 언어 분류
생성일2026-02-23GitHub 저장소 메타데이터
최근 push2026-10-23GitHub의 저장소 갱신 시각, 커밋 날짜와 별개
최신 릴리스v1.0.169 · 2026-06-292026-10-23 GitHub 기준
분석 커밋90af14e · 2026-10-22ci: update install stats · 12:07:06 UTC
패키지 버전1.0.169커밋 90af14e의 package.json 기준
구현 규모핵심 TypeScript 41,617줄src/ 아래 95개 파일, 주석·빈 줄 포함
테스트 규모TypeScript 84,756줄, 테스트 파일 210개tests/의 보조 코드 포함, 통과·커버리지 수치 아님
기타 코드JavaScript 약 14,006줄 · Shell 1,652줄 · HTML 2,598줄생성 번들·빌드 결과 제외
라이선스GitHub: NOASSERTION
소스: Elastic-2.0
LICENSE는 Elastic License 2.0 원문
기본 실행 요구Node.js >=22.5.0, SQLite FTS5추가 언어 실행기는 사용하는 기능에 따라 필요
쓰기 전에 알아둘 한계
성과 수치·보존·호스트 지원을 서로 구분하세요

절약률: 98%는 프로젝트의 특정 집계 벤치마크를 대표하는 수치입니다. 실제 비용과 정답률은 작업·모델·반환량에 따라 달라집니다. ctx_stats의 바이트 기반 추정과 실제 청구서를 동일시하면 안 됩니다.

보존: README는 새 세션의 이전 자료가 즉시 삭제된다고 설명하지만, Claude Code의 hooks/sessionstart.mjs 시작 경로에는 cleanupOldSessions(7)과 고아 이벤트 정리가 있습니다. 모든 이전 기록을 매번 즉시 지운다는 설명으로 일반화할 수 없습니다. 세션당 이벤트 상한도 있습니다.

지원표: 문서의 Codex PreCompact 칸은 미지원 표시지만, src/adapters/codex/index.ts의 capabilities.preCompact는 true입니다. 문서·어댑터 선언·실제 호스트 버전이 같은 상태라고 가정하지 마세요.

청크: Markdown 경로는 기본 4,096바이트를 기준으로 문단을 나누지만, 단일 큰 문단은 그대로 남을 수 있습니다. 코드 펜스 인식도 전체 Markdown 파서나 언어별 구문 트리 분석을 대신하지 않습니다.

개인정보: 로컬 저장과 외부 연결은 별도 기능입니다. 플랫폼 설정이 있으면 maybeForward()가 정제한 이벤트를 전송합니다. 정규식 기반 가림 처리를 모든 비밀정보가 제거된다는 보장으로 읽어서는 안 됩니다.

검증과 라이선스: 테스트 코드의 존재가 모든 환경에서의 통과를 보장하지는 않습니다. BENCHMARK.md의 일부 실행 명령은 현재 패키지 스크립트와도 다릅니다. GitHub의 NOASSERTION 대신 LICENSE 원문을 확인하고, 무제한 허용 라이선스로 단정하지 마세요.