Skip to main content

Command Palette

Search for a command to run...

AI 에이전트에서 작업 맥락을 관리하기 위해 사용한 방법

Published
10 min read

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"

More from this blog

지시사항을 분할하여 Codex로 효율적인 작업하기

이슈 Codex와 같은 AI 기반 코드 에이전트는 출력 토큰의 수가 제한되어 있다. 그래서 다양한 작업을 하나의 프롬프트에 전부 몰아서 작성하면 원하는 결과가 나오지 않을 수 있다. Codex와 같은 LLM 기반 서비스는 출력 토큰 수를 초과하게 되면 일부 단계가 누락되거나 특정 요소를 과하게 요약할 수 있고 이는 전체적인 답변 퀄리티를 낮출 수 있기 때문이다. 그래서 다양한 AI 공식문서는 특정 작업을 더 작은 단위로 분할하는 방식을 강조한다...

Nov 3, 20255 min read

Key를 활용하여 컴포넌트 상태를 초기화하기

개요 컴포넌트의 상태가 업데이트되어도 컴포넌트 내부에 배치된 컴포넌트의 상태는 그대로 유지되는 경우가 있었다. 예전에는 Props 전달 및 내부에서 useEffect를 통해서 상태를 초기 상태로 업데이트하도록 했는데 useEffect를 남용하게 되면 상태 변화 추적이 어려워지는 문제가 있었다. 그런데 useEffect 외에도 Key를 통해서 컴포넌트 상태를 초기화할 수 있다는 사실을 알게 되었다. 리스트 렌더링 React 프론트엔드에서 목록 형...

Sep 21, 20253 min read

내가 AGENTS.md를 작성하는 방법

Codex CLI 요즘 프로젝트 개발에 Codex CLI를 활용하는 이유는 다음과 같다. 특정 프로젝트를 작업할 때 Claude Code는 종종 사용량을 초과한 것과 다르게 Codex CLI는 ChatGPT Plus 요금제만으로도 토큰 사용량 초과 걱정 없이 충분하게 활용할 수 있었다. 타 CLI 기반 AI 개발 도구에 비해서 요구사항을 더 정확하게 구현하고 꼭 필요한 작업만 진행하기 때문에 코드를 검토하는 시간을 줄일 수 있다. 반복적인 코드...

Sep 21, 20254 min read
N

Nowon Lee

22 posts