AI 에이전트에서 작업 맥락을 관리하기 위해 사용한 방법
AI 에이전트의 불편함
Codex CLI와 같은 AI 코딩 에이전트를 통해서 프로젝트 개발 속도를 높일 수 있다. 그리고 혼자 작업했을 때는 놓칠 수 있는 부분도 발생할 수 있는데 AI 에이전트를 통해 보완할 수 있었다.
컴포넌트에 대해서 접근성 태그 작성
API 호출하는 비동기 코드 작성할 때 에러 처리
그리고 AI 에이전트를 잘 활용하면 불가능하다고 생각했던 기능 개발도 가능했던 경험이 있었다.
로컬 번역 모델을 웹 브라우저 내부 캐시에 저장해서, 앞으로 인터넷이 불가능한 상황에서도 텍스트 번역 기능을 제공하는 웹 애플리케이션
레거시 프론트엔드의 입력 상태 관리를 React Hook Form 기반으로 리팩토링하여 렌더링 성능 개선
하지만 AI 에이전트를 통해 오랫동안 작업을 진행했을 때는 여러 문제점이 발생하는 것을 목격할 수 있었다.
이미 결정된 방식에 대해서 고민하거나 번복한다.
주어진 작업 범위가 아닌 임의의 작업을 진행한다.
이미 작업된 사항에 대해서 다시 되돌린다.
코딩 에이전트의 구조
코딩 에이전트는 기본적으로 작업 상태를 대화 컨텍스트에 관리한다. 컨텍스트의 크기에는 제한이 있기 때문에 작업을 계속 하게 되면 컨텍스트 압축이 발생한다. 대표적으로 Codex CLI를 사용하다보면 컨텍스트가 압축되었다는 메시지를 종종 볼 수 있다.
Context compacted
컨텍스트가 압축되고 나서 AI 에이전트는 다음과 같은 사항을 파악하지 못하는 문제가 발생할 수 있다.
사용자가 컨텍스트 압축 이전에 결정한 사항
작업의 목표
현재까지의 진행 상황
컨텍스트를 유지하는 방법
ChromaDB
처음 생각한 방법은 ChromaDB MCP를 사용하는 것이었다. AI 에이전트를 사용하기 시작한 뒤 얼마 안 된 상황이라서 MCP를 어떻게 세팅하는지 헤매느라 시간을 너무 많이 소비했던 기억이 있다.
MCP를 세팅하고 AGENTS.md 파일에 작업을 진행할 때마다 항상 MCP를 사용하도록 지침을 작성해도 데이터베이스가 작동하지 않아서 작업 사항이 기록되지 않는 문제도 있었다.
그래서 MCP를 세팅하는 대신 ChromaDB를 PC에 아예 세팅한 다음 Codex CLI가 제공하는 notify 훅을 사용하는 것이었다. Codex CLI가 작업을 완료할 때 특정 스크립트를 실행시키는 방식이었다.
스크립트를 작성하여 작업을 완료할 때마다 작업 맥락을 ChromaDB에 저장하고, 작업을 시작할 때 ChromaDB에서 필요한 정보를 가져오도록 AGENTS.md에 지침을 작성했다.
하지만 작업을 계속할수록 데이터베이스에서 작업 맥락을 파악하기 위해서 더 많은 데이터를 가져와야 했다. 컨텍스트를 압축하고 나서도 작업을 3-4번 실행하면 다시 컨텍스트 압축이 발생했고, 빈번한 압축이 발생하다보니 낭비되는 시간이 많아졌다.
PLANS.md
OpenAI 쿡북 페이지에는 PLANS.md 파일을 세팅하여 7시간 이상 작업을 진행하는 예시에 대해서 설명하고 있었다.
컨텍스트 압축이 발생해도 PLANS.md 파일을 참고하도록 하면 AI 에이전트가 무슨 작업을 해야 하는지는 파악하게 할 수 있었다. 하지만 사용자가 결정한 사항 & 진행 상황을 유지하지 못하는 문제가 여전히 남아있었다.
파일로 관리
결국 데이터베이스 대신 파일로 관리하는 방식을 사용했다.
처음에는 각 작업을 끝낼 때마다 CONTEXT-0001.md 파일에 기록하고 컨텍스트가 압축되면 파일을 읽어서 작업 내용을 파악하는 방법을 사용했다. 이 방법은 이미 진행한 작업 사항을 파악하는 데에는 문제가 없었다. 하지만 다음과 같은 상황에서 문제가 있었다.
현재 작업을 진행한 것이 아닌 작업을 계획
AI 에이전트가 작업을 하기 위해 인터넷에서 자료를 조사할 경우 어떤 자료를 조사했는지 한번에 확인할 수 없음.
그래서 현재는 다음과 같은 역할을 하는 파일들을 세팅했다.
PLANS
- 해당 세션에서 어떤 작업을 진행해야 할지에 대해서 정의한 파일
TICKETS
AI 에이전트가 프로젝트에 대해서 미리 세팅한 작업을 관리하는 파일
tickets 폴더 내에 각 티켓에 대한 상세 내용을 작성한다.
DECISIONS
AI 에이전트가 질문을 제시했을 때 내가 결정한 사항을 따로 관리하는 파일
decisions 폴더 내 각 결정사항에 대한 상세 내용을 작성한다.
PROGRESS
- 각 작업에 대한 진행 상황을 작성
REFERENCES
- 작업할 때 참고한 외부 자료를 URL 단위로 관리
세션
파일로 관리했을 때에는 벡터 데이터베이스를 사용했을 때보다 세팅 난이도도 낮고 작업 맥락도 잘 유지되었다.
하지만 한번에 여러 작업을 진행해야 할 때에는 여러 작업 맥락이 겹치는 문제가 있을 수 있었다.
예를 들어 프론트엔드 프로젝트의 경우 터미널 한 쪽은 코드 작성 작업을 진행하고, 다른 쪽은 레거시 코드를 리팩토링하는 작업을 진행할 수 있었다. 각 작업 맥락을 분리하지 않으면 컨텍스트 압축이 발생했을 때 잘못된 작업 맥락을 가져오는 문제가 있을 수 있었다.
Codex CLI는 명령어 /status를 입력하면 현재 세션에 대한 세션 아이디를 알아낼 수 있다. 하지만 Codex CLI가 현재 세션 아이디를 저절로 알아내지는 못한다는 점을 파악했다.
그래서 Codex CLI에 세션 아이디를 파악하도록 하려면 Codex를 실행할 때 환경변수를 직접 입력해줘야 한다.
CODEX_SESSION_ID=<session_id> codex resume <session_id>
Codex CLI를 실행할 때마다 세션 아이디를 두 번 입력하는 건 귀찮아서 세션 아이디를 한 번만 입력해도 환경변수와 codex resume 명령어에 전달할 수 있는 쉘 스크립트를 작성했다. 다음과 같이 실행시킬 수 있다.
./invoke-session.sh <"session_id">
그리고 사용자가 일일이 파일을 세팅할 필요가 없도록 세션 아이디를 입력하면 필요한 파일을 자동으로 세팅해주는 스크립트도 작성하여 작업에 활용하고 있다. 해당 스크립트를 다음과 같이 실행하여 해당 세션에 대한 작업 맥락 관리 파일을 세팅한다.
./create-session.sh <"session_id">
AGENTS.md
Codex CLI가 어떻게 작업을 해야 하는지에 대한 기본적인 지침을 AGENTS.md 파일에 작성할 수 있다.
Codex CLI가 작업 사항을 기록하는 것을 누락하는 상황을 방지하기 위해 작업을 시작하고 끝낼 때마다 파일에 작업 사항을 기록하도록 지침을 작성했다.
AGENTS.md 파일에서 세션에 대한 지침 예시는 글 후반에 참고할 수 있다.
결과
해당 사항의 경우 두 번 이상 Codex CLI에 전달할 필요가 없어졌다.
작업 범위
사용자가 결정한 사항
작업 범위에 대해서 세팅한 작업 계획
코드 예시
AGENTS.md
## 세션
- 사용자는 `codex resume <session_id>`로 Codex를 실행할 때 해당 세션 ID에 대해서 작업을 시작하거나 이어나갈 수 있음.
- 사용자는 `CODEX_SESSION_ID=<session_id>` 환경변수를 같이 주입.
- 세션 ID는 환경변수 CODEX_SESSION_ID로 파악.
- `codex resume <session_id_1>`와 `CODEX_SESSION_ID=<session_id_2>`에서, session_id_1과 session_id_2는 서로 같다고 가정할 것.
- 인터넷 연결 요청에 대해서는 세션 ID를 확인하지 않음.(세션 ID를 확보하기 위한 작업)
- 만약 세션 아이디가 없다면 사용자에게 세션을 임시로 세팅할지를 질문
- 세팅한다면 현재 작업에 대해서 임의로 세션 아이디를 세팅하고 진행
- 세팅하지 않는다면 무시하고 진행.
- 사용자가 프롬프트를 Codex CLI에 입력하여, Codex CLI가 작업을 시작할 때, 그리고 끝낼 때마다 TICKETS.md(+ tickets 폴더), PROGRESS.md, DECISIONS.md(+ decisions 폴더), RESEARCH.md에 내용을 적절한 위치에 기록한다.
- 작업을 시작할 때에도 세션 파일을 기록하는 이유는 작업 도중 컨텍스트 압축이 발생했을 때 작업 및 대화 맥락과 흐름을 유지하기 위함.
- 만약 갑작스럽게 컨텍스트 압축(compaction)이 발생한다면, 우리가 작업 맥락과 대화 맥락을 유지하기 위해서는 어떤 파일에 어떤 내용을 기록해야 하는가?
- 작업이 끝날 때에도 반드시 적절한 파일을 찾아서 내용을 기록한다.
### PLANS.md
- ./store/<session_id>/PLANS.md 파일
- 이번 프로젝트에서 무엇을 하고, 무엇을 금지하는지를 정의한다.
- 목표, 완료 기준을 결정한다.
- 우리가 진행할 작업의 범위를 해당 PLANS.md 파일에서 확인 가능.
- 특정 작업이 해당 PLANS.md의 범위를 벗어나게 되면 작업 전 우선 사용자에게 검토 질문을 제공.
- 작업 상태의 경우 PLANS.md 파일 대신 TICKETS.md 파일에 기록
### TICKETS.md
- `./store/<session_id>/TICKETS.md`
- 현재 무엇을 해야 하고, 무엇이 진행 중이며, 무엇을 완료했는지 판단하는 기준 문서이다.
- 작업의 진행 상황을 확인하기 위한 용도이다.
- 각 항목에 대해서 상세 정보는 `./store/<session_id>/tickets` 폴더 내 중첩 폴더 없이 파일로 관리한다.
- 파일 규칙: `TICKETS-####-{제목}.md`
- 파일 내 날짜를 분 단위까지 포함하여 명시한다.
- 규칙
- 작업 시작 전에 반드시 티켓으로 정의한다.
- 다음과 같은 상황에서 즉시 업데이트한다.
- 작업 시작할 때: 체크박스를 생성하거나 상태를 진행 중으로 표시
- 작업이 막힌 경우: 별도의 아이콘으로 명시하고 사유를 한 줄로 기록한다.
- 작업 완료: 체크박스 완료 처리
- 상태 판단은 항상 TICKETS.md 파일 기준이다.
- 작업의 상세 일지는 TICKETS 대신 PROGRESS.md 파일에 작성한다.
- 의사결정의 근거 및 논의를 TICKETS에 적는 대신 DECISIONS.md 파일에 자세하게 기록한다.
### PROGRESS.md
- `./store/<session_id>/PROGRESS.md`
- 언제 무엇이 바뀌었는지를 날짜 순으로 누적 기록하는 작업 로그이다.
- 사람(리뷰어, 관리자)이 프로젝트 흐름을 빠르게 파악하는 용도이다.
- 규칙
- 작업 세션 종료 시마다(최소 하루 1회) 반드시 업데이트한다.
- 다음 형식을 기본으로 유지한다:
- Done: 완료된 작업(티켓/PR 링크 포함)
- In progress: 진행 중인 작업
- Blocked: 막힌 작업과 원인
- Next: 다음 세션에서 우선 처리할 작업
- 중요한 변경, 리스크, 이슈가 발생한 날은 반드시 기록한다.
- 티켓 ID를 기록할 수 있으면 함께 남긴다.
- 결정이 수반된 경우, DECISIONS.md의 해당 항목을 링크한다.
- 최종 결정의 근거는 PROGRESS 대신 DECISIONS.md 파일에 상세히 서술한다.
- 계획 범위나 완료 기준을 수정하는 대신 일관되게 유지한다.
### DECISIONS.md
- `./store/<session_id>/DECISIONS.md`
- 프로젝트 진행 중 내려진 중요한 결정과 그 이유를 기록한다.
- "왜 이렇게 했는가?"에 대한 단일 참조 지점이다.
- 각 항목에 대해서 상세 정보는 `./store/<session_id>/decisions` 폴더 내 중첩 폴더 없이 파일로 관리한다.
- 파일 규칙: `DECISIONS-####-{제목}.md`
- 파일 내 날짜를 분 단위까지 포함하여 명시한다.
- 규칙
- 다음 중 하나라도 해당되면 즉시 작성 또는 갱신한다.
- 범위 또는 완료 기준 변경
- 기술/구현 방식 선택
- 되돌리기 어려운 결정
- 팀 내 이견이 있었던 쟁점의 결론
- 성능/보안/비용/운영에 영향을 주는 선택
- 결정은 결정 직후 기록하는 것을 원칙으로 한다.
- 각 결정에는 다음 정보를 포함한다.
- 결정 일자
- 문제 상황(컨텍스트)
- 고려한 대안
- 최종 결정
- 결정 근거 및 트레이드오프
- 예상 영향
- 관련 티켓, PR, 연구 자료(RESEARCH.md)를 링크한다.
- 작업 진행 로그는 DECISIONS 대신 PROGRESS.md에 작성한다.
- 단순 참고 링크의 경우 DECISIONS 대신 RESEARCH.md의 사용법을 확인한다.
### RESEARCH.md
- `./store/<session_id>/RESEARCH.md`
- 작업 및 결정에 실제로 사용한 외부 자료를 프로젝트 맥락에 맞게 정리한다.
- 사용자가 작업 이해도를 높이기 위해 참고하는 문서이다.
- 규칙
- 다음 경우에만 추가한다:
- 외부 자료가 실제로 의사결정 또는 구현에 영향을 준 경우
- DECISIONS.md에서 근거로 참조되는 자료가 생긴 경우
- 사용자가 작업 및 프로젝트의 이해도를 높일 수 있는데 사용할 수 있을 경우
- 단순히 “읽어본 자료”는 기록하지 않는다.
- 각 항목에는 다음을 포함한다,
- 출처 링크
- 핵심 요지 요약
- 우리 프로젝트에서의 적용 방식
- 관련된 Decision ID(있는 경우)
- 링크만 나열하는 큐레이션 문서로 사용하는 대신 다른 방법을 찾는다.
- 최종 결론이나 결정을 RESEARCH 보다는 DECISIONS.md 파일에서 결정한다.
### 임시 파일
- PC 루트에 접근하는 대신 `./store/<session_id>/temps` 폴더에 기록한다.
- "/tmp" 위치도 사용하지 않음.
- Playwright MCP에서 발생하는 파일도 PC 루트 대신 `./store/<session_id>/temps` 위치여야 한다.
create-session.sh
#!/bin/sh
set -eu
usage() {
cat <<'EOF'
사용법:
scripts/create-session.sh <session_id>
설명:
./store/<session_id>/ 아래에 세션 기록용 표준 파일/폴더 구조를 생성합니다.
(기존 파일이 있으면 덮어쓰지 않습니다.)
EOF
}
if [ \(# -lt 1 ] || [ -z "\){1:-}" ]; then
usage
exit 1
fi
SESSION_ID="$1"
case "$SESSION_ID" in
*"/"* | *".."* )
echo "잘못된 session_id 입니다: $SESSION_ID" >&2
exit 1
;;
esac
SCRIPT_DIR="\((CDPATH= cd -- "\)(dirname -- "$0")" && pwd)"
ROOT_DIR="\((CDPATH= cd -- "\)SCRIPT_DIR/.." && pwd)"
STORE_DIR="\(ROOT_DIR/store/\)SESSION_ID"
mkdir -p "$STORE_DIR"
mkdir -p "$STORE_DIR/tickets"
mkdir -p "$STORE_DIR/decisions"
mkdir -p "$STORE_DIR/temps"
write_if_missing() {
path="$1"
shift
if [ -f "$path" ]; then
return 0
fi
tmp="$path.tmp.$$"
cat > "$tmp" <<EOF
$*
EOF
mv "\(tmp" "\)path"
}
write_if_missing "$STORE_DIR/PLANS.md" "# PLANS.md
## 목표
- (여기에 이번 세션의 목표를 적습니다.)
## 유의점
"
write_if_missing "$STORE_DIR/TICKETS.md" "# TICKETS.md
> 작업 상태의 단일 진실원천(SSOT)
> 현재 무엇이 남아 있고, 무엇이 완료되었는지를 판단할 때 이 파일을 기준으로 한다.
## Active
- [ ] T-001 사용자 로그인 API 구현
- tickets/T-001-login-api.md
- [ ] T-002 에러 처리 공통 모듈 정리 (Blocked: 스펙 미확정)
- tickets/T-002-error-handling.md
## Done
- [x] T-000 프로젝트 초기 세팅
- tickets/T-000-bootstrap.md
"
write_if_missing "$STORE_DIR/PROGRESS.md" "# PROGRESS.md
## 2026-01-22 00:00
### Done
- T-000 초기 세팅 완료 (PR #12)
### In Progress
- T-001 로그인 API 구현
### Blocked
- 없음
### Next
- 인증 토큰 설계 검토
---
## 2026-01-23 00:01
### Done
- 없음
### In Progress
- T-001
### Blocked
- T-002 (에러 정책 미확정)
### Notes
- 에러 코드 체계 결정 필요 (DECISIONS 예정)
"
write_if_missing "$STORE_DIR/DECISIONS.md" "# DECISIONS.md
## Active
- D-001 인증 방식으로 JWT 사용
- decisions/D-001-jwt-auth.md
## Superseded
- D-000 세션 기반 인증
- decisions/D-000-session-auth.md
"
write_if_missing "$STORE_DIR/REFERENCES.md" "# REFERENCES.md
## Authentication
### JWT Best Practices
- Source: https://example.com/jwt-best-practices
- Key Takeaways:
- 토큰 만료 시간은 짧게
- 알고리즘 명시
- How We Use This:
- 로그인 API 토큰 만료 15분 적용
- Related Decisions:
- D-001
---
## Error Handling
### REST API Error Codes
- Source: https://example.com/api-errors
- Key Takeaways:
- 표준 HTTP 상태 코드 사용
- How We Use This:
- 공통 에러 응답 포맷 설계 참고
"
echo "완료: $STORE_DIR"
echo "생성됨(또는 기존 유지):"
echo " - PLANS.md / PROGRESS.md / TICKETS.md / REFERENCES.md / DECISIONS.md"
echo " - tickets/ temps/ decisions/"
invoke-session.sh
#!/bin/sh
set -eu
if [ \(# -lt 1 ] || [ -z "\){1:-}" ]; then
echo "세션 ID가 없습니다."
exit 1
fi
CODEX_SESSION_ID="\(1" codex resume "\)1"
