모든 코딩 에이전트에게 '동일한 기억'을 부여하는 방법에 대한 글을 초보자를 위해 정리했습니다.
※ 전제 지식부터 설명하고 있으니, 꼭 읽어보시길 바랍니다.
■ 전제 지식
-
코딩 에이전트 (Coding Agent):
Claude Code, Codex, Cursor, OpenCode 등 AI가 코드를 읽고 쓰는 도구입니다.
대화(세션)를 시작할 때마다 기억은 빈 상태에서 시작합니다.
-
리포지토리 (Repository):
프로젝트의 소스 코드 일체를 담은 폴더입니다 (일반적으로 Git으로 관리합니다).
-
AGENTS.md:
리포지토리에 두는, 에이전트들을 위한 지침서입니다. 많은 도구가 시작 시 자동으로 읽어 들입니다.
Claude Code는 원래 CLAUDE.md를 읽지만, 현재는 AGENTS.md도 읽을 수 있습니다.
-
컨텍스트 (Context):
AI가 한 번에 읽을 수 있는 정보의 범위(틀)입니다. 지침서가 길수록 이 틀을 많이 소비하며, 지시 사항을 잘 따르기 어려워집니다.
-
MCP (Model Context Protocol):
AI 에이전트를 외부 도구나 데이터에 연결하기 위한 공통 규격입니다.
-
SSH:
네트워크를 통해 다른 컴퓨터(여기서는 자신의 PC에서 작동하는 서버)로 명령을 보내는 시스템입니다.
-
grep / cat / jq:
grep은 파일 내에서 특정 문자열을 찾는 명령어이고,
cat은 파일의 내용을 표시하는 명령어이며,
jq는 JSON 데이터를 걸러내는 명령어입니다.
■ 본 기사의 요지
AGENTS.md를 사용하면 '규칙'은 모든 에이전트가 공유할 수 있습니다.
하지만, 운영 절차서(프로시저), API 사양, 설계 판단의 이유와 같은 '지식'은 공유되지 않습니다.
또한, Claude Code의 자동 메모리는 머신마다 저장되어 다른 머신이나 다른 도구와는 공유되지 않습니다.
이 때문에 동일한 코드베이스를 다루고 있어도 에이전트마다 답변이 달라지는(서로 충돌하는) 현상이 발생합니다.
필자의 해결책은, 규칙은 각 리포지토리의 AGENTS.md에 두고, 지식은 하나의 공유 서버(OpenLore)에 모으는 것입니다.
그 위에 모든 에이전트가 같은 장소를 검색하도록 만듭니다.
이를 5가지 계층으로 나누어 정리하는 것이 이 기사의 요지입니다.
■ 합격 테스트: 동일한 질문을 두 개의 리포지토리에서 수행하기
두 개의 리포지토리에 있는 두 에이전트에게 '결제 API의 재시도 정책은?'이라는 같은 질문을 합니다.
-
도입 전:
api/에 있는 Claude Code는 우연히 그 리포지토리에 있던 문서를 찾아냅니다.
반면, web/에 있는 Codex는 아무것도 찾지 못하고 그럴듯한 오답을 반환합니다.
기사 그림에서처럼, 두 에이전트는 각각의 리포지토리에서 내용이 다른 파일을 읽고 있으며,
하나는 '지수 백오프(exponential backoff)',
다른 하나는 '1초 간격으로 3회'라고 적혀 있습니다.
참조하는 출처가 제각각이라 답변이 일치하지 않습니다.
-
도입 후:
두 에이전트 모두 같은 서버에 대해 grep -r 'retry' / 를 실행하여, 동일한 파일(/runbooks/payments-retries.md)에서 동일한 답을 얻습니다.
문서를 한 번 수정하면 양쪽의 에이전트에 반영됩니다.
필자는 이 테스트를 통과하지 못하는 구성에 대해, 에이전트가 기억을 공유하는 것이 아니라 '명명 규칙(naming convention)'만을 공유하고 있다고 지적합니다.
■ 제1계층: 규칙과 지식을 분리하기
AGENTS.md에는 '모든 세션에서 항상 옳은 것'만 작성해야 합니다.
AGENTS.md는 매번 전체가 읽히기 때문에, 절차서 등을 추가하면 변수명을 하나 바꿀 정도의 작업에도 그만큼의 컨텍스트를 소비하게 됩니다.
Claude Code 공식 문서는 지침 파일을 200줄 미만으로 유지할 것을 권장합니다.
@경로(path)로 다른 파일을 가져와도, 그 파일 역시 시작 시 읽히기 때문에 절약에는 도움이 되지 않습니다.
기사 그림에 제시된 정보의 배치 방법은 다음과 같습니다.
-
모든 세션 공통 규칙 (빌드, 테스트, 금지 사항)은 AGENTS.md에 작성합니다.
-
코드 일부에만 관련된 규칙은 경로를 한정한 규칙(.claude/rules/ 또는 .cursor/rules)에 작성합니다.
해당 파일을 건드릴 때만 읽힙니다.
-
절차서, API 사양, 설계 판단, 장애 기록 등은 지식 계층(knowledge layer)에 둡니다.
필요할 때만 읽히며, 리포지토리나 에이전트를 넘어서 공유됩니다.
-
개인의 취향은 내장 메모리 또는 CLAUDE.local.md에 작성합니다. 머신마다, 사람마다 달라도 괜찮습니다.
-
'이 한 줄이 왜 이렇게 되어 있는지'는 코드 주석(code comment)에 작성합니다. 설명할 대상 바로 옆에 두기 위함입니다.
AGENTS.md
빌드 및 테스트
- 설치:
pnpm install
- 테스트:
pnpm test (커밋 전에 반드시 실행)
- 린트(Lint):
pnpm lint
규약
- TypeScript는 strict 모드를 사용한다. 새로운 코드에
any를 사용하지 않는다.
- API 핸들러는
src/api/handlers/에 위치시킨다.
- 재시도(Retry)에는 공통의
retry() 헬퍼를 사용한다. 재시도 처리를 직접 만들지 않는다.
금지 사항
- main 브랜치에 직접 push 하지 않는다.
- 이미 병합된(
merged) migrations/ 이하 폴더의 파일을 수정하지 않는다.
.env 파일을 커밋하지 않는다.
팀 지식 (Team Knowledge)
절차서, API 사양, 설계 결정, 장애 기록은 이 리포지토리에 없다.
공유 지식 리포지토리(MCP 서버 openlore)에 있다.
시스템 작동 방식, 설계 이유, 운영 방법에 대해 답변하기 전에 다음을 수행한다.
- 검색:
grep -ril '<키워드>' /
- 발견된 파일을
cat으로 읽는다.
- 답변에 파일 경로를 명시한다.
찾지 못했다면, 그렇게 전달한다. 추측하여 답변하지 않는다.
마지막 '팀 지식' 섹션은 OpenLore를 실행한 상태에서 ssh -p 2222 localhost agents >> AGENTS.md를 실행하면 자동으로 추가될 수 있다 (>>는 파일 끝에 추가하는 기호이다).
주의할 점이 하나 있다.
Claude Code가 작업 폴더 또는 그 상위 폴더에 CLAUDE.md, .claude/CLAUDE.md, CLAUDE.local.md 중 어느 것이라도 존재하면, AGENTS.md를 읽지 않는다. CLAUDE.md가 필요한 경우, 해당 파일의 첫 줄에 @AGENTS.md 라고 작성해야 한다.
확인 방법:
wc -l AGENTS.md로 줄 수를 세어 200줄 미만인지 확인한다.
- Claude Code에서는
/memory를 실행하여 AGENTS.md 경로가 표시되는지 본다.
- 다른 에이전트에게는 “테스트에 대해, 프로젝트 지침에는 무엇이라고 쓰여 있나요?”라고 물어보고, AGENTS.md의 내용을 인용하여 답변하는지 확인한다.
■ 2단계: 사람이 읽기 위함이 아니라, grep으로 발견되도록 작성하기
에이전트는 문서를 '읽는' 것이 아니라 '검색'한다. 검색에 걸리지 않는 문서는 존재하지 않는 것과 같다.
필자는 초기에 사내 Wiki를 그대로 옮겨와 “Backend 메모”, “기타” 같은 긴 페이지를 두었다.
그 결과, “retry”로 검색했을 때 4개의 거대한 파일에서 12건이 히트했고, 에이전트는 첫 번째 항목만 읽고 멈춰버렸다.
그래서 지식 폴더를 다음과 같이 분리했다.
-
runbooks/:
“어떻게 하는지”에 답한다. 배포(Deploy), 롤백(Rollback), 키 업데이트 등을 번호가 매겨진 절차와 정확한 커맨드로 작성한다.
-
decisions/:
“왜 이렇게 되었는지”에 답한다. 하나의 파일에 하나의 설계 결정을 기록한다.
에이전트에게 가장 필요하지만, 찾기 가장 어려운 정보이다.
-
api/:
“무엇이 반환되는지”에 답한다.
사양(Specification), 제한(Limit), 에러 코드 등을 작성한다.
-
incidents/:
“전에 발생한 적이 있는지”에 답한다. 에이전트가 과거의 장애를 반복하지 않도록 대비하는 역할을 한다.
-
glossary.md:
사내 용어와 일반적인 단어의 대응표이다.
“ledger”로 검색했을 때 “LDG”도 발견되도록 한다.
■ 작성 규칙은 4가지가 있다.
-
한 파일에 하나의 토픽만 작성한다.
payments.md 대신 payments-retries.md로 만든다. grep 결과에서 가장 먼저 보이는 것은 파일 이름이기 때문이다.
-
검색될 법한 단어(retry, backoff, timeout 등)를 제목과 첫 번째 문단에 포함시킨다.
-
코드와 같은 이름으로 작성한다.
함수명이 retryWithBackoff라면, 문서에도 retryWithBackoff라고 작성한다.
-
파일을 짧게 유지한다.
스크롤이 필요한 길이라면, 분할하여 링크로 연결한다.
OpenLore에서는 폴더 단위로 줄 수 제한을 강제할 수 있다.
docs/runbooks/.lore/config.yaml에 다음 내용을 작성하면, 150줄을 초과하는 작성을 거부하고 다른 파일로 나누도록 유도하는 메시지가 반환된다.
rules:
runbook-length:
match: ["*.md"]
use: size/lines
with: { max: 150 }
확인 방법:
팀에서 자주 나오는 질문 3가지를 선택하고, 자신의 문서를 grep으로 검색해 본다.
정확한 파일이 상위에 나오지 않으면, 파일 이름이나 시작하는 문장을 수정한다.
■제3층: 하나의 서버를 모든 에이전트가 사용하기
지식을 각 리포지토리에 복사하면, 리포지토리마다 여기저기 흩어지고 오래된 정보로 남는다.
그래서 필자는 OpenLore를 사용한다.
OpenLore는 오픈 소스(Apache 2.0 라이선스)이며, Go 언어로 작성된 단일 실행 파일이다. Markdown 폴더를 MCP와 SSH를 통해 모든 에이전트에 제공한다. 벡터 데이터베이스도, 데이터 가져오기 메커니즘도, SDK도 필요 없으며, 에이전트는 cat, grep, find 같은 일반적인 명령어로 문서를 읽을 수 있다.
시도하는 절차는 다음과 같다.
-
설치하기.
brew install --cask aakarim/tap/lore를 실행한다. 이것은 Homebrew라는 패키지 관리 도구의 명령어이다.
Windows의 경우, OpenLore README에 있는 Quickstart 지침을 따른다.
-
서버 시작하기.
제2층 구성으로 만든 폴더를 지정하여 openlore ./docs를 실행한다.
SSH는 2222번 포트, MCP와 웹 화면은 8080번 포트에서 대기한다.
docs 폴더의 내용이 서버상의 루트 / 로 보이게 된다.
-
각 에이전트 연결하기.
- Claude Code:
claude mcp add --transport http openlore http://localhost:8080/mcp
- Codex:
codex mcp add openlore --url http://localhost:8080/mcp
- Cursor:
.cursor/mcp.json에 {"mcpServers":{"openlore":{"url":"http://localhost:8080/mcp"}}} 라고 작성한다.
- OpenCode:
opencode.json에 {"mcp":{"openlore":{"type":"remote","url":"http://localhost:8080/mcp","enabled":true"}}} 라고 작성한다.
- CI 등 쉘 사용 환경:
ssh -p 2222 localhost "grep -r 'retry' /"
초보자가 특히 주의해야 할 점이 있다.
기사 중의 grep -r 'retry' / 에서의 /는 OpenLore 서버상의 루트, 즉 docs 폴더를 가리킨다.
자신의 PC 터미널에서 그대로 실행하면 디스크 전체를 검색해 버린다.
반드시 SSH 또는 MCP를 통해 실행해야 한다.
필자가 안전성에 대해 확인한 점도 언급한다.
에이전트가 사용하는 쉘은 실제 OS 쉘이 아니라 메모리 위에서 동작하는 Go 인터프리터이다.
쉘 외부로 빠져나갈 수도, 프로그램을 실행할 수도 없으며, 일반적인 세션에서는 네트워크에도 연결할 수 없다.
또한, 초기 설정에서는 읽기 전용(read-only) 상태이다.
■확인 방법:
합격 테스트를 실행한다.
Claude Code를 하나의 리포지토리에서, Codex를 다른 리포지토리에서 구동하여 같은 질문을 던지고, 둘 다 동일한 파일 경로를 보여주면 성공이다.
codex mcp list를 실행하여 openlore가 목록에 나타나는지도 확인한다.
서버를 사용하지 않는 대안:
같은 docs/ 구성을 메인 리포지토리에 두고, AGENTS.md에서 그곳을 참조하도록 한다.
제1층과 제2층의 효과는 얻을 수 있지만, 리포지토리를 넘나드는 공유와 접근 통제는 할 수 없다.
필자는 공정한 주의점도 적고 있다.
OpenLore README 자체에서도 '에이전트 1개, 리포지토리 1개라면, Markdown은 리포지토리에 두면 된다'라고 언급하고 있다.
서버가 유용한 경우는 여러 에이전트, 리포지토리, 사람이 같은 지식을 필요로 할 때이다.
또한, 자신의 PC 외부로 공개하기 전에는 인증(authentication), 권한 설정(permission setting), HTTPS, 영구 저장소(persistent storage)를 갖추어야 한다.
■제4층: 접근 범위를 처음부터 제한하기
모든 것을 읽을 수 있는 에이전트는 읽어서는 안 될 문서까지 인용해 버린다.
인증이 없는 상태에서는 MCP 클라이언트는 내장된 'guest'(게스트)로 연결하여 모든 파일을 읽을 수 있다.
자신의 PC에서만 사용할 것이라면 문제가 없지만, 고객 관련 장애 기록과 공개용 API 사양이 같은 장소에 있다면 위험하다.
다음 lore.json은 게스트가 읽을 수 있는 범위를 /public 폴더로만 제한하는 설정이다.
다음은 권한 설정 파일의 내용과 그 의미입니다.
{
"allow_keyless": true,
"unknown_identity": "allow",
"default_cwd": "/public",
"docsets": {
"public": {
"paths": ["/public"],
"access": { "allow": { "guest": "ro" } }
}
}
}
각 항목의 의미는 다음과 같습니다. allow_keyless는 키리스(keyless) 연결을 허용할지 여부, unknown_identity는 신원 미상의 접속자를 받아들일지 여부를 나타냅니다.
default_cwd는 접속 직후에 위치하게 될 폴더입니다. docsets은 문서 묶음(document set)의 정의이며, 여기서는 'public'이라는 묶음에 게스트 사용자에게 읽기 전용(ro) 권한을 부여하고 있습니다.
이 파일을 사용하려면 서버 설정 파일인 openlore.yml에 auth_file: ./lore.json이라고 작성해야 합니다.
권한은 역할별(role) 및 문서 세트(document set)별로 다음 3가지 중 하나를 선택할 수 있습니다.
- ro: 읽기 전용(Read Only)
- publish: 받은 편지함(inbox)에만 게시 가능
- rw: 읽기/쓰기(Read Write)
이름이 지정된 사용자들을 구분하고 싶다면, mcp: require_auth: true를 설정하여 에이전트가 패스키(passkey)로 로그인하도록 해야 합니다.
제가 초기적으로 수립한 방침은 다음과 같습니다. 에이전트에게는 작업에 필요한 범위에 한해서만 ro 권한을 부여하고, 하나의 받은 편지함에만 publish 권한을 주고, rw 권한은 누구에게도 주지 않는 것입니다.
확인 방법:
ssh -p 2222 localhost "lore docsets"를 실행하여 해당 사용자가 볼 수 있는 문서 세트만 표시되는지 확인합니다.
■ 제5단계: 지식의 부패 방지 (Knowledge Decay Prevention)
문서는 자신도 모르는 사이에 오래됩니다. 어떤 문서가 오래되었는지 쿼리(query, 문의)를 통해 확인할 수 있도록 준비해야 합니다. 먼저, 각 문서의 맨 앞부분에 다음과 같은 '프론트매터(frontmatter)' (---로 둘러싸인 메타 정보)를 작성합니다.
---
title: Payments API retry policy
owner: payments-team
last_reviewed: "2026-09-14"
applies_to: [api, web]
---
owner는 문서의 담당자, last_reviewed는 최종 검토일, applies_to는 대상이 되는 리포지토리입니다.
OpenLore의 lore meta 명령어는 각 문서의 프론트매터를 한 줄씩 JSON 형식으로 출력합니다. 이를 jq로 필터링하면 오래된 문서를 목록화할 수 있습니다. 다음 명령어들은 ssh -p 2222 localhost에 접속한 후의 셸에서 실행해야 합니다.
lore meta | jq -r 'select(.owner == null) | .path'
lore meta | jq -r 'select(.last_reviewed < "2026-07-01") | .path'
lore meta | jq -r 'select(.applies_to | index("web")) | .path'
날짜를 "로 감싸는 것은 날짜를 단순한 문자열(string)로 비교하도록 하기 위함입니다. 또한, lore meta는 실행한 사용자가 읽을 수 있는 문서만을 대상으로 하므로, 제4단계의 권한 제한은 여기서도 지켜집니다.
다음으로 쓰기 흐름을 결정합니다.
에이전트가 학습한 내용은 기록하고 싶지만, 매뉴얼에 직접 작성하게 하고 싶지는 않습니다. 따라서 publish 권한을 사용하여 받은 편지함(inbox)에만 게시하도록 합니다.
echo "# Retry findings" | ssh -p 2222 -i ~/.ssh/research_agent localhost publish /backend/retry-findings.md
이 명령어는 'Retry findings'라는 내용을 research_agent 키를 사용하는 사용자로 게시하는 것입니다. 이 내용은 /backend/inbox/에 들어갑니다.
기존 문서를 덮어쓰려고 하면, 'read-only file system'이라는 오류로 거부됩니다.
변경이 있을 때마다 누가 변경했는지와 내용의 해시값(hash value)이 기록됩니다.
사람이 내용을 확인한 후에 정식 문서로 승격시키는 과정을 거칩니다.
마지막으로 문서 정리(document organization)에 대해 다룹니다. OpenLore는 문서의 열람 상황을 기록합니다.
공식 문건에는 에이전트가 잘 읽히지 않는 문서를 순위 매기게 하고, 날짜가 포함된 정리 보고서(report)를 작성하게 하는 절차가 있습니다. 에이전트는 제안만 할 뿐이며, 승인하는 것은 사람입니다. 아무것도 자동으로 삭제되지 않습니다.
기사의 그림에서는 이 흐름이 9단계의 순환으로 그려져 있습니다. 에이전트가 작업하고, 접수함(inbox)에 게시하며, 사람이 확인하고, docs/로 승격시키고, 에이전트가 읽고, lore meta를 통해 오래된 문서나 담당자가 없는 문서를 찾아내며, 열람 분석을 통해 읽히지 않은 문서를 찾고, 정리 보고서를 만들고, 사람이 재확인하는 순서로 한 바퀴를 돕니다.
확인 방법:
위에 언급된 두 개의 jq 쿼리(담당자가 없는 문서, 오래된 문서)가 이번 주 내에 대응할 수 있는 정도의 짧은 목록을 반환하면 됩니다.
■자주 발생하는 실패 사례와 대책
-
오래된 문서:
에이전트가 리팩토링(refactoring) 전의 절차서를 인용해 버립니다. 모든 파일에 owner와 last_reviewed를 기록하고, 오래된 문서를 조사하는 쿼리를 주기적으로 실행합니다.
-
모순되는 문서:
두 파일의 내용이 상충되어 에이전트가 한쪽을 선택해 버립니다. 1파일 1토픽(topic)을 지키고, 판단이 변경되었을 때는 새로운 메모를 옆에 추가하는 것이 아니라, 원래 설계 결정 기록(ADR)의 상태를 업데이트합니다.
-
에이전트가 검색하지 않음:
Claude Code 공식 문건에 나와 있듯이, 지시 파일은 강제성이 있는 설정이 아니라 어디까지나 참고 정보입니다. "답변하기 전에 검색하고, 경로를 제시하며, 찾지 못하면 그렇게 말하라"고 구체적으로 작성하고, 합격 테스트(passing test)로 확인합니다.
-
권한이 너무 넓음:
모든 에이전트가 게스트로서 모든 문서를 읽을 수 있는 상태가 됩니다. 서버를 자신의 PC 외부로 내보내기 전에, 제4층(Layer 4) 설정을 완료합니다.
-
아무도 접수함을 보지 않음:
게시물이 쌓인 채 방치됩니다. 풀 리퀘스트(Pull Request) 리뷰와 마찬가지로, 정해진 요일에 확인합니다.
■요약
이 기사의 진정한 의도는 특정 도구를 추천하는 것이 아닙니다.
"규칙"과 "지식"을 분리하고, 지식을 검색하기 쉬운 형태로 한 곳에 모으고, 권한으로 보호하며, 주기적으로 관리합니다. 바로 이 평범한 메커니즘이야말로 여러 에이전트가 동일한 답변을 내놓게 하는 열쇠라는 점에 있습니다.
OpenLore는 그 메커니즘을 구현하는 수단 중 하나일 뿐입니다.
필자 본인이 인정했듯이, 에이전트 1개, 리포지토리(repository) 1개의 규모라면 제1층과 제2층만으로 충분합니다.
자신의 환경에서 시도할 경우에는, 먼저 AGENTS.md를 200줄 미만으로 정리하고, docs/ 폴더를 제2층 구성으로 나눕니다. 그 후에 합격 테스트(같은 질문을 두 개의 리포지토리에서 수행)로 효과를 확인해 보는 것이 좋습니다.
원문 기사: Arindam_1729 "How I give every coding agent the same memory", OpenLore의 README
#memory #Claude #Caludecode #Codex #Cursor #OpenLore