Claude Code에서 Codex로 작업 환경을 옮기면서 가장 신경 쓰인 건 command나 MCP 설정이 아니었습니다. 프로젝트를 오래 쓰면서 쌓인 auto memory가 다음 세션에서도 자연스럽게 이어지는가가 더 중요했습니다. 파일을 어디엔가 복사하는 데서 끝내면 이전은 쉬워 보이지만, 새 Codex 세션이 그 내용을 찾지 못하면 실질적으로는 실패한 셈입니다.
검증 환경 — 2026-07-24
- Claude Code:
2.1.218- Codex CLI:
0.145.0external_agent_memory_import:under development, 기본 비활성이 글은 위 버전에서 직접 확인한 동작을 기준으로 합니다. 이후 버전에서는 memory 저장 구조, feature flag, import 절차와 app-server protocol이 달라질 수 있습니다.
처음에는 Codex가 memory를 SQLite 하나로 관리한다는 이야기도 들었습니다. 로컬 상태를 직접 확인해 보니 절반만 맞는 설명이었습니다. 작업 상태와 추출 결과는 SQLite가 맡고 있었지만, 새 세션에서 검색하고 사용하는 consolidated memory는 별도의 Markdown workspace에 있었습니다. 이 구조를 이해한 뒤에야 원본 보존, import, consolidation, 회상 검증을 분리해서 진행할 수 있었습니다.
Claude와 Codex의 memory 구조는 다릅니다
Claude Code 공식 문서에 따르면 프로젝트별 auto memory는 다음 디렉터리에 저장됩니다. 제가 확인한 로컬 환경도 같은 구조였습니다.
~/.claude/projects/<project-key>/memory/├── MEMORY.md├── topic-a.md├── topic-b.md└── ...MEMORY.md가 전체 진입점 역할을 하고, 세부 결정이나 작업 맥락은 topic별 Markdown 파일로 나뉘어 있었습니다. 제 로컬 환경의 일부 파일에는 memory 종류와 원본 session을 나타내는 frontmatter도 있었습니다. 이 frontmatter는 공식적으로 보장된 포맷이 아니라 관찰한 구현 세부사항입니다. 따라서 한 파일만 옮기기보다 디렉터리 전체를 하나의 프로젝트 memory 묶음으로 다루는 편이 안전합니다.
Codex local memory 공식 문서는 주요 memory 파일이 ~/.codex/memories/ 아래에 있으며 background에서 갱신되는 generated state라고 설명합니다. Codex CLI 0.145.0의 실제 파일은 역할이 조금 더 나뉘어 있었습니다.
| 위치 | 역할 |
|---|---|
~/.codex/memories_1.sqlite | 추출 결과와 background job 상태 |
~/.codex/memories/memory_summary.md | 새 세션에 제공되는 compact route |
~/.codex/memories/MEMORY.md | 검색 가능한 consolidated registry |
~/.codex/memories/extensions/external_agent_import/resources/ | 외부 agent에서 가져온 원본 memory |
즉, 현재 구현에서는 SQLite가 memory 생성 과정을 관리하고 Markdown workspace는 실제 회상에 쓰이는 결과물을 보관합니다. memories_1.sqlite라는 파일명도 Codex 소스에서 확인할 수 있습니다. 다만 이 이름과 내부 schema는 public API가 아니므로 버전이 바뀌면 달라질 수 있습니다. SQLite 파일만 복사하거나 MEMORY.md만 임의로 덮어쓰는 방식이 위험한 이유입니다.
복사하기 전에 원본과 기존 상태를 백업합니다
Memory에는 프로젝트 관례뿐 아니라 인증 방식, 내부 서비스명, 개인적인 판단이 섞이기 쉽습니다. 저는 import 전에 원본 파일을 훑고 token 형태의 문자열과 민감한 값을 먼저 확인했습니다. 블로그나 실행 로그를 공유할 때는 사용자명, 절대 경로, 프로젝트명, session ID도 함께 지우는 편이 좋습니다.
백업은 Claude 원본과 Codex의 기존 상태를 모두 포함해야 합니다. Codex는 memory를 background에서 갱신하므로 먼저 실행 중인 Codex task와 app-server를 종료한 뒤 복사하는 편이 안전합니다.
project_key="<project-key>"backup_dir="$HOME/.codex/migration-backups/claude-memory-$(date +%Y%m%d-%H%M%S)"claude_memory="$HOME/.claude/projects/$project_key/memory"
mkdir -p "$backup_dir"cp -a "$claude_memory" "$backup_dir/claude-memory"
if [ -d "$HOME/.codex/memories" ]; then cp -a "$HOME/.codex/memories" "$backup_dir/codex-memories"fi
if [ -f "$HOME/.codex/config.toml" ]; then cp "$HOME/.codex/config.toml" "$backup_dir/config.toml"fi
if [ -f "$HOME/.codex/memories_1.sqlite" ]; then sqlite3 "$HOME/.codex/memories_1.sqlite" \ ".backup '$backup_dir/memories_1.sqlite'"fiSQLite는 실행 중일 수 있으므로 단순 cp보다 .backup을 사용하는 편이 낫습니다. 이 단계에서 Claude memory 원본은 수정하지 않습니다. Import가 잘못돼도 source와 기존 Codex 상태를 각각 복원할 수 있어야 하거든요.
실험적인 external-agent import를 사용했습니다
Codex의 /import 문서는 Claude Code의 설정, 프로젝트 파일, 최근 대화를 가져올 수 있다고 안내합니다. 하지만 공개 import 지원 목록에는 auto memory가 포함돼 있지 않습니다. 실제로 Codex CLI 0.145.0에서 기능 상태를 확인하면 local memory는 stable이지만 memory importer는 아직 기본 비활성입니다.
memories stable trueexternal_agent_memory_import under development false따라서 일반 사용자가 TUI의 /import에서 Claude Code memory를 항상 선택할 수 있다고 보면 안 됩니다. 이번에는 대상 프로젝트를 정확히 제한하고 결과를 자동 검증하기 위해 external_agent_memory_import를 명시적으로 활성화한 app-server를 사용했습니다. 이 기능의 상태는 Codex feature 정의에서도 UnderDevelopment, default_enabled: false로 확인됩니다.
codex app-server --stdio --enable external_agent_memory_import이 플래그와 app-server protocol은 실험적 interface라서 이후 버전에서 이름이나 동작이 달라질 수 있습니다. 제가 확인한 build에서는 detect와 import 단계가 분리돼 있었습니다.
- 실험 기능을 활성화한 app-server에서 Claude Code의 session과 memory를 detect합니다.
- 여러 프로젝트가 발견돼도 현재 프로젝트의 memory만 선택합니다.
- Import 완료 notification에서 성공과 실패를 확인합니다.
- 생성된
scope.json이 올바른cwd를 가리키는지 확인합니다.
Import된 결과는 다음처럼 source를 그대로 보존합니다.
~/.codex/memories/extensions/external_agent_import/├── instructions.md└── resources/ └── <project-key>/ ├── scope.json ├── MEMORY.md ├── topic-a.md └── ...여기서 scope.json은 가져온 정보가 어느 workspace에 해당하는지를 consolidation agent에게 알려주는 metadata입니다. Memory importer의 consolidation 지침은 프로젝트 전용 결정을 전역 사용자 preference에 넣지 않도록 요구합니다. 다만 scope.json 자체가 접근 제어나 보안상 격리를 강제하는 것은 아닙니다. 프로젝트 범위를 보존하도록 돕는 기준이지 보안 경계는 아닙니다.
원본 보존 여부는 source와 destination을 비교해 확인할 수 있습니다.
project_key="<project-key>"source_dir="$HOME/.claude/projects/$project_key/memory"target_dir="$HOME/.codex/memories/extensions/external_agent_import/resources/$project_key"
diff -qr "$source_dir" "$target_dir"정상이라면 destination에만 존재하는 scope.json 외에는 차이가 없어야 합니다. 파일 개수와 전체 line·byte 수도 함께 비교하면 누락된 빈 파일이나 잘린 문서를 찾기 쉽습니다.
Import 성공과 memory 사용 가능은 같은 시점이 아닙니다
외부 memory가 resource 디렉터리에 복사됐다고 새 세션에서 바로 쓸 수 있다는 뜻은 아닙니다. Codex CLI 0.145.0의 background memory 작업은 기존 대화에서 raw memory를 추출하는 단계와, 이를 MEMORY.md와 memory_summary.md로 정리하는 consolidation 단계를 거칩니다. 이 2단계 구성 역시 현재 구현 세부사항입니다.
Consolidation이 끝나면 memory_summary.md에는 프로젝트별 compact route가 추가되고, MEMORY.md에는 import된 세부 파일을 가리키는 extension_resource_files 항목이 생깁니다. Project-specific 정보는 summary 전체에 복사되지 않고, 관련 질문이 들어왔을 때 상세 파일을 찾을 수 있는 route로만 들어갑니다.
rg -n \ 'external_agent_import|<imported-keyword>' \ "$HOME/.codex/memories/memory_summary.md" \ "$HOME/.codex/memories/MEMORY.md"공식 문서에 설명된 것처럼 background job은 session의 idle 상태와 rate limit에 따라 바로 실행되지 않을 수 있습니다. 현재 구현에는 최근 성공한 consolidation 이후의 cooldown도 있습니다. 그래서 파일 복사 직후 결과만 보고 실패로 단정하거나, 반대로 import notification만 보고 완료라고 선언하면 안 됩니다. 최종 판정은 새 세션에서 해야 합니다.
새 세션에서 auto loading을 검증합니다
검증 질문은 AGENTS.md나 repository 문서에도 적혀 있는 규칙을 피해야 합니다. 그런 질문은 memory가 없어도 답할 수 있기 때문입니다. Imported memory에만 있는, 오래돼도 잘 바뀌지 않는 결정 하나를 고릅니다. 예를 들어 예전에 선택한 formatter와 되돌린 대안처럼 외부 검색으로 맞히기 어려운 내용이 좋습니다.
먼저 memory 경로를 명시한 smoke test를 실행합니다.
project_dir="/absolute/path/to/project"
codex exec \ --ephemeral \ --sandbox read-only \ --enable memories \ -c 'memories.use_memories=true' \ -C "$project_dir" \ 'Auto memory 검증이다. .claude, 웹, workspace 파일은 읽지 말고 Codex memory만 사용해 이전에 확정한 결정을 답해라.'--ephemeral은 session rollout을 보존하지 않습니다. Codex CLI 0.145.0의 memory startup 구현에서는 ephemeral session의 memory 생성 pipeline도 건너뜁니다. --sandbox read-only는 agent의 파일 변경을 차단합니다. 첫 검증이 통과하면 두 번째 session에서는 memory 경로를 알려주지 않고 자연스럽게 질문합니다.
codex exec \ --ephemeral \ --json \ --sandbox read-only \ --enable memories \ -c 'memories.use_memories=true' \ -C "$project_dir" \ '이 프로젝트에서 예전에 확정한 결정을 기준으로 답해줘. 선택한 도구와 되돌린 대안은 무엇이었지? 웹, .claude, workspace 파일은 조회하지 마.'이 두 번째 검증에서 Codex가 스스로 ~/.codex/memories/MEMORY.md를 검색하고, 다시 imported resource를 열어 정확한 답을 내면 auto loading이 작동하는 것입니다. App-server의 raw event를 볼 수 있는 환경이라면 응답의 memoryCitation이 extensions/external_agent_import/resources/...를 가리키는지도 확인할 수 있습니다. memoryCitation은 현재 app-server protocol에 포함된 필드지만 public interface가 바뀌면 형태도 달라질 수 있습니다.
codex exec --json의 간략한 event 출력에는 citation metadata가 보이지 않을 수 있습니다. 그 경우에도 command trace가 ~/.codex/memories 아래만 조회했고 답이 정확했다면 실사용 경로는 확인된 셈입니다. 단순히 target 파일이 존재한다는 사실보다 훨씬 강한 검증입니다.
이관하면서 피한 방식들
처음 떠올리기 쉬운 방법은 Claude의 MEMORY.md 내용을 Codex의 MEMORY.md 뒤에 붙이는 것입니다. 하지만 이 방식은 generated registry를 직접 편집하고 project scope도 잃습니다. 다음 consolidation에서 내용이 다시 정리되거나 사라질 가능성도 있습니다.
Claude memory를 AGENTS.md로 옮기는 것도 다른 작업입니다. AGENTS.md는 반드시 지켜야 할 repository 규칙에 적합하고, memory는 과거 결정과 맥락을 필요할 때 회상하는 계층입니다. 모든 과거 기록을 instruction으로 승격하면 prompt가 커지고 오래된 판단도 강제 규칙처럼 작동합니다.
마지막으로 실제 memory 내용을 검증 prompt나 공개 로그에 그대로 노출하지 않는 편이 좋습니다. 검증에는 정답을 공개해도 괜찮은 비민감 결정 하나면 충분합니다. 개인 재무, 내부 host, access token, private repository 정보는 정확히 회상되더라도 테스트 소재로 쓰지 않았습니다.
파일 이전이 아니라 다음 세션까지 확인해야 합니다
이번 작업에서 가장 중요했던 기준은 원본 보존, project scope, consolidation, 새 session 회상을 각각 확인하는 것이었습니다. 이 네 단계가 모두 통과해야 auto memory migration이 끝났다고 볼 수 있습니다.
Codex memory는 SQLite 하나도, Markdown 한 파일도 아니었습니다. Background job을 관리하는 state와 agent가 읽는 consolidated workspace가 함께 움직이는 구조였습니다. 이 차이를 알고 실험적 importer의 범위와 한계를 확인하면 Claude Code에서 쌓아 온 맥락을 무리하게 global instruction으로 바꾸지 않고도 이어갈 수 있습니다.
무엇보다 마지막 검증은 새 session에서 해야 합니다. 기존 대화가 알고 있는 내용을 다시 답하는 것은 memory 검증이 아니거든요. 별도의 ephemeral session이 source를 보지 않고 imported resource를 찾아 정확히 회상했을 때, 비로소 이전이 끝납니다.