메뉴
HN
Hacker News 13일 전

SSH 동기화를 지원하는 코딩 에이전트용 오픈소스 메모리 계층

IMP
8/10
핵심 요약

클로드 코드(Claude Code), 코덱스(Codex), 오픈코드(opencode) 등 코딩 에이전트의 로컬 대화 내역을 거대한 메모리 계층으로 변환하는 오픈소스 도구 'deja'가 공개되었습니다. 개발자는 이 도구를 통해 수개월 치의 과거 디버깅 기록을 수 밀리초 만에 검색하고, 에이전트가 과거에 해결했던 문제를 반복해서 디버깅하지 않도록 만들 수 있습니다. 또한 SSH를 통한 기기 간 메모리 동기화와 민감 정보(API 키 등) 자동 삭제 기능을 지원하여 개발 생산성과 보안을 크게 높여줍니다.

번역된 본문

여러분의 에이전트가 이미 이 문제를 해결했을지도 모릅니다. 'deja(데자뷰)'가 그것을 찾아줍니다. (vshulcz.github.io/deja-vu)

클로드 코드(Claude Code), 코덱스(Codex), 오픈코드(opencode)는 모든 대화 내용을 로컬 파일로 저장합니다. 하지만 이는 여러분이 검색할 수 없는 기가바이트 단위의 디버깅 문제 및 설계 결정들로 가득 차 있습니다. 'deja'는 의존성이 없는(zero-dependency) 단일 바이너리 프로그램으로, 이러한 기록들을 검색 가능한 메모리 계층으로 변환해 줍니다.

  • 검색(Search): deja "connection pool exhausted" 검색 시, 기가바이트(GB) 단위의 데이터에서 7~9밀리초 만에 결과를 제공합니다. 사후 적용이 가능하여 deja를 설치하기 수개월 전의 로그도 모두 검색됩니다.
  • 에이전트 리콜(Agent recall): MCP(Model Context Protocol) 리콜 도구를 통해 에이전트가 새로 디버깅을 시도하는 대신 "3주 전에 이 문제를 해결했습니다"라고 답변하게 만듭니다. (다양한 코딩 에이전트 환경 지원)
  • 자동 리콜(Auto-recall): install --auto 명령어는 SessionStart 훅을 추가하여, 질문하기도 전에 관련된 메모리가 에이전트의 컨텍스트에 자동으로 로드되도록 합니다.
  • 민감 정보 제거(Redaction): 인덱싱 시점에 API 키, JWT, 개인 키(Private keys) 등을 모두 걸러내어 캐시를 안전하게 보관합니다.
  • 통계(Stats): deja stats 명령어를 통해 에이전트의 작업 내역(사용 도구, 주요 프로젝트, 활동 추이 등)을 요약해 줍니다.
  • 공유(Share): deja share <id> 명령어로 동료에게 세션의 요약본을 전달할 수 있습니다. (비밀번호 등 민감 정보는 자동으로 말소됨)
  • 동기화(Sync): deja sync export/import를 통해 기기 간에 메모리를 이동시킵니다. 데이터는 추가 전용(append-only)이며 멱등성(idempotent)을 가집니다.

오직 하나의 바이너리 파일입니다. 다운로드할 모델도, 실행할 서비스도 없으며 어떤 데이터도 여러분의 컴퓨터를 떠나지 않습니다. (단, opencode 인덱싱 시 macOS와 대부분의 리눅스 배포판에 기본 설치된 sqlite3 CLI를 사용합니다.)

설치 방법

  • curl: curl -fsSL https://raw.githubusercontent.com/vshulcz/deja-vu/main/install.sh | sh
  • Go: go install github.com/vshulcz/deja-vu/cmd/deja@latest
  • npm: npx @vshulcz/deja-vu "query" (별도 설치 불필요)
  • Homebrew: brew install vshulcz/tap/deja-vu

에이전트 연동 사용 중인 에이전트에 연동합니다. (설정 파일을 수정하며 원본은 .bak으로 백업됩니다):

  • deja install --all : claude-code, codex, opencode를 위한 MCP 리콜 설정
  • deja install claude-code --auto : 세션 시작 시 자동 리콜 훅 추가

준비가 끝났습니다. 다음 세션에서 에이전트에게 물어보세요: "우리가 이전에 JWT 리프레시 토큰 갱신(Refresh rotation) 문제를 다룬 적이 있나?" 메모리를 확인해 보세요. --auto 옵션을 켜두었다면 묻지 않아도 됩니다. 에이전트가 각 세션을 시작할 때 프로젝트에서 해결했던 내용을 이미 알고 있는 상태로 시작할 것입니다.

CLI 사용 예시 $ deja "jwt refresh token" 검색 결과로 날짜, 에이전트 환경, 일치한 로그 메시지(예: 리프레시 토큰 갱신 이후 로그인 실패, jwks 캐시 리로드로 해결 등)를 보여줍니다.

주요 명령어

  • deja <query>: 모든 기록 검색. 단어 조합(AND), 부분 문자열 일치 등을 지원합니다. --re, --harness, --project, --since 30d, --role, --json 등의 필터를 사용할 수 있습니다.
  • deja ctx <query>: 최적의 일치 항목에 대한 간결한 마크다운 요약본을 제공하며, 이를 프롬프트에 파이프(|)로 연결할 수 있습니다.
  • deja share <id>: 민감 정보가 제거된 세션 요약본을 생성합니다.
  • deja stats: 총계, 에이전트별 사용량, 주요 프로젝트, 월간 활동 추이를 보여줍니다.
  • deja sync export / import / ssh: 공유 폴더나 단일 SSH 명령을 통해 기기 간 메모리를 이동시킵니다. 데이터는 추가 전용 및 멱등성을 유지합니다.
  • deja show <id> / deja last [n]: 특정 세션을 읽거나 최근 세션 목록을 봅니다.
  • deja sources: 발견된 저장소, 크기, 메시지 및 민감 정보 제거 횟수를 표시합니다.
  • deja mcp: stdio MCP 서버를 실행합니다.
  • deja warmup: 검색 없이 인덱스를 빌드/새로고침 합니다. (cron이나 쉘 시작 시 유용)

MCP 없이 컨텍스트 파이프하기 claude "Prior context: $(deja ctx 'database migration')" 와 같이 직접 컨텍스트를 주입할 수도 있습니다.

기기 간 동기화 두 대의 컴퓨터를 하나의 공유 폴더(Syncthing, iCloud, git repo 등 파일을 동기화하는 수단)와 연결할 수 있습니다:

  • A 머신: deja sync export ~/Sync/deja (마지막 내보내기 이후 새로운 배치를 추가)
  • B 머신: deja sync import ~/Sync/deja (아직 보지 못한 데이터를 가져옴)

또는 다른 머신이 SSH로 연결되어 있다면 공유 폴더를 생략할 수 있습니다:

  • deja sync ssh mini : 'mini' 호스트로 새 기록을 푸시하고 가져옵니다.
  • deja sync ssh mini --pull : 'mini' 호스트의 새 기록을 현재 머신으로 가져옵니다.

SSH 모드는 시스템의 ssh/scp 및 원격지의 deja 바이너리를 사용합니다. 데이터 배치는 일반 JSONL 형식이며 내보낼 때 민감 정보가 제거됩니다. 가져오기 프로세스는 멱등성을 가지므로 cron을 통해 양쪽 명령을 실행해도 안전합니다. 기록은 출처로 다시 에코되지 않습니다.

원문 보기
원문 보기 (영어)
Your agents already solved this. deja finds it. vshulcz.github.io/deja-vu Claude Code, Codex and opencode write every conversation to local files — gigabytes of debugged problems and design decisions you can't search. deja is a zero-dependency binary that turns those histories into a memory layer: Search deja "connection pool exhausted" — 7–9 ms over gigabytes, retroactive: months of logs from before you installed it Agent recall MCP recall tool — the agent answers "we fixed this three weeks ago" instead of re-debugging, across harnesses Auto-recall install --auto adds a SessionStart hook: relevant memory lands in context before you ask Redaction API keys, JWTs, private keys are stripped at index time — the cache is safe to keep Stats deja stats — your agent work, wrapped: harnesses, top projects, activity sparkline Share deja share <id> — hand a colleague a sanitized digest of a session, secrets already scrubbed Sync deja sync export/import — move memory between machines, append-only, idempotent One binary. No models to download, no services to run, nothing leaves your machine. (opencode indexing shells out to the sqlite3 CLI, preinstalled on macOS and most Linux distros.) Install curl -fsSL https://raw.githubusercontent.com/vshulcz/deja-vu/main/install.sh | sh or: go install github.com/vshulcz/deja-vu/cmd/deja@latest # Go npx @vshulcz/deja-vu " query " # npm, no install brew install vshulcz/tap/deja-vu # Homebrew Wire it into the agents you use (edits config, keeps a .bak ): deja install --all # MCP recall for claude-code, codex, opencode deja install claude-code --auto # + SessionStart auto-recall hook That's it. Next session, ask your agent: have we dealt with jwt refresh rotation before? check your memory — or with --auto , don't ask: the agent starts each session already knowing what you solved in that project. CLI $ deja "jwt refresh token" [claude] api · Jul 8 · 8f31c0a9 — 2 matches login started failing after refresh token rotation; jwt kid mismatch in tests fixed by reloading jwks cache after rotateKey and adding a clock-skew test [codex] web · Jul 1 · b77d91e2 — 1 match refresh token cookie needed SameSite=Lax in local callback flow Command What it does deja <query> Search all histories. Multi-word = AND, substrings match ( code finds opencode ). --re , --harness , --project , --since 30d , --role , --json . deja ctx <query> Compact markdown digest of the best match — pipe it into a prompt. deja share <id> Sanitized session digest for a colleague: secrets redacted, tool noise stripped. deja stats Totals, per-harness split, top projects, monthly sparkline. --json too. deja sync export <dir> [--full] / import <dir> / ssh <host> [--pull] Move memory between machines — via a shared folder or one ssh command. Watermarked, append-only, idempotent. deja show <id> / deja last [n] Read one session / list recent ones. deja sources Discovered stores, sizes, message and redaction counts. deja mcp The stdio MCP server (what deja install wires in). deja warmup Build/refresh the index without searching — handy in cron or shell startup. Context piping without MCP: claude " Prior context: $( deja ctx ' database migration ' ) " Sync between machines Point both machines at one shared folder (Syncthing, iCloud, a git repo — anything that moves files): deja sync export ~ /Sync/deja # machine A: appends new batches since last export deja sync import ~ /Sync/deja # machine B: picks up what it hasn't seen Or skip the shared folder when the other machine is a ssh hop away: deja sync ssh mini # push new records to mini and import them there deja sync ssh mini --pull # fetch mini's new records into this machine ssh mode uses your system ssh/scp and the deja binary on the remote (looked up on PATH, falling back to ~/.local/bin/deja ). Batches are plain JSONL, redacted on the way out. Import is idempotent, so keep the folder as an append-only log and run both commands from cron if you like. Records never echo back to their origin. --full re-exports everything regardless of watermarks — useful when adding a machine after old batches are gone. Synced sessions show up under imported:<project> in search, recall , and session-start auto-recall. Teach your agent to remember deja install --all wires up MCP recall and the session-start hook. To make the agent reach for memory on its own, add this to your CLAUDE.md / AGENTS.md : Before debugging or re-implementing something, run `deja "<query>"` (or the MCP recall tool) — past agent sessions across Claude Code, Codex and opencode are indexed locally. Cite what you reuse. MCP tools Tool Arguments Returns recall query , harness? , limit? Dense matching snippets, ≤4KB — cheap on context. recall_context query Markdown digest of the best-matching session. With --auto , a SessionStart hook also feeds the current project's recent memory in automatically — read-only, capped at 2KB, and it never delays or breaks agent startup. Security Credentials are redacted at index time: AWS keys, generic api_key= / token= assignments, bearer tokens and raw JWTs, PEM private key blocks, provider tokens ( ghp_ , sk- , npm_ , xox. , AIza ), and scheme://user:pass@host URLs. The value is replaced with [redacted:<kind>] ; surrounding text stays searchable. deja sources shows per-store counts. Opt out with DEJA_NO_REDACT=1 (unsafe). deja share and deja sync export re-apply redaction on the way out. Supported harnesses Harness Store Status Claude Code ~/.claude/projects/**/*.jsonl ✅ Codex CLI ~/.codex/sessions/** + history.jsonl ✅ opencode ~/.local/share/opencode/opencode.db ✅ aider, Gemini CLI #6 , #7 planned Custom locations via DEJA_CLAUDE_ROOT , DEJA_CODEX_ROOT , DEJA_OPENCODE_DB , DEJA_INDEX_DIR . Performance Measured on a real corpus — 1,250+ sessions, ~3.3GB across three harnesses: Warm search 7–9 ms typical, ~40 ms worst-case Cold index (once) ~10 s Index size ~2.4% of corpus The index is incremental: when a session file grows, only that file is re-read. How it works Local inverted index in ~/.cache/deja : parse JSONL/SQLite stores → redact credentials → records.bin + token buckets → manifest.json tracks per-file state so repeat runs only ingest what changed. The MCP server, stats, share and sync all read the same index. Details: docs/ARCHITECTURE.md . Privacy: no network path exists in the indexing or search code. Local files in, local cache out. FAQ Does anything leave my machine? No. There is no network code in the tool. sync writes files to a directory you choose; moving them is up to you. How is this different from cass? cass is the kitchen-sink take on session search: 22 providers, Rust, optional semantic embeddings, a TUI. deja is the opposite bet — one small Go binary, pure lexical, three harnesses, zero setup — plus the memory-layer pieces around it: auto-recall, redaction, share, sync. And from MemPalace / Mem0 / Letta? Those are memory platforms : embeddings, vector stores, capture hooks or APIs that record going forward. deja has no capture step at all — it indexes what your agents already wrote to disk, including months of history from before you installed it. They can coexist. What about secrets already in my logs? They stay in the original harness files (that's your agent's data), but they don't enter deja's index, digests, shares or sync exports. What about Windows? Builds exist, CI runs the suite on Windows; macOS/Linux are the battle-tested paths. Field reports welcome: #9 . Can I exclude a project? Not yet — planned as --exclude ( #8 ). Today you can point DEJA_*_ROOT at a filtered copy. How do I wipe everything? deja uninstall --all rm -rf ~ /.cache/deja Contributing make build test lint — see CONTRIBUTING.md . Adding a harness is one parser file: docs/ARCHITECTURE.md . Good first issues are labeled. License MIT © Vladislav Shulcz