왜 AI 에이전트가 당신의 프로젝트를 계속 잊어버리는가 (그리고 내가 해결한 방법)
I’m happy to translate the article for you, but I need the full text of the post (the paragraphs, headings, etc.) in order to do the translation. Could you please paste the content you’d like translated (excluding the source line you already provided)? Once I have the text, I’ll keep the source link at the top and translate everything else into Korean while preserving the original formatting.
Source: …
PROGRESS.md의 문제
새로운 AI 코딩 에이전트 세션을 시작할 때마다 같은 일이 반복됩니다: 어제 내가 무슨 작업을 했는지 전혀 모릅니다.
- 어떤 작업이 완료됐는지 모릅니다.
- 캐시용으로 Redis를 사용하기로 했다는 사실을 모릅니다.
- 인증 모듈이 의존성 업그레이드 대기 중이라 차단됐다는 것을 기억하지 못합니다.
그래서 대부분의 사람들이 하는 대로 PROGRESS.md 파일을 유지합니다. 매 세션이 끝날 때마다 에이전트에게 파일을 업데이트하도록 요청하고, 다음 세션이 시작될 때 에이전트가 파일을 읽고 이전 작업을 이어받으려 합니다.
그 방식은 약 일주일 정도는 잘 작동했습니다.
마크다운 문제
프로젝트가 성장함에 따라 파일도 커졌습니다.
50줄이 200줄이 되었고, 3주 전 상태 업데이트가 현재 차단 항목 옆에 섞여 있었습니다. 에이전트는 전체 파일을 읽어 3,000+ 토큰을 컨텍스트에 소모했지만, 오래된 진행 노트 사이에 묻혀 있던 차단된 작업을 놓치곤 했습니다.
근본적인 문제: 텍스트 파일을 데이터베이스처럼 사용하고 있었다는 점입니다.
- 전체 파일을 읽는 것이 아니라 “차단된 것이 뭐야?” 같은 쿼리가 필요했습니다.
- 평평한 글머리표가 아니라 프로젝트 → 에픽 → 작업 구조가 필요했습니다.
- 컨텍스트 윈도우를 부풀리지 않는 감사 로그가 필요했습니다.
AI 에이전트를 위한 프로젝트 트래커 구축
그래서 하나 만들었습니다. Saga는 AI 에이전트에게 로컬 SQLite 데이터베이스를 제공하는 MCP 서버로, 프로젝트 추적을 가능하게 합니다—Jira와 비슷하지만 에이전트가 실제로 작업하는 방식을 위해 설계되었습니다.
MCP(Model Context Protocol)에 익숙하지 않다면, Anthropic에서 만든 표준으로, AI 도구가 타입이 지정된 툴 호출을 통해 외부 서비스와 통신할 수 있게 합니다. Claude Code, Claude Desktop, Cursor, Windsurf 모두 이를 지원합니다. 에이전트는 시작 시 사용 가능한 툴을 발견하고 대화 중 필요에 따라 호출합니다.
Saga는 MCP를 통해 23개의 툴을 노출합니다:
- 전체 계층 구조에 대한 CRUD: 프로젝트 → 에픽 → 작업 → 서브작업
- 노트 시스템: 결정, 컨텍스트, 회의 노트, 차단 요소—타입이 지정되고 검색 가능
- 대시보드: 한 번의 호출로 전체 프로젝트 상태(완료 비율, 차단된 작업, 최근 활동)를 반환
- 활동 로그: 모든 변경 사항이 자동으로 이전/새 값과 함께 기록
- 세션 차이: “어제 이후에 무엇이 바뀌었는지 보여줘” — 한 번의 호출로 제공
모든 데이터는 단일 .tracker.db SQLite 파일에 저장됩니다. 서버도, API 키도, 계정도 필요 없습니다.
실제 작동 방식
새 프로젝트 시작
Me: "Set up tracking for the e-commerce API"
Agent calls:
tracker_init
epic_create (Auth)
epic_create (Catalog)
task_create (JWT auth)
subtask_create ([setup lib, create endpoint, add middleware])
다섯 번의 도구 호출. 이제 프로젝트는 에픽, 작업, 서브태스크로 구조화되고 SQLite에 영구 저장됩니다.
다음 날 이어서 작업
Me: "What's the status?"
Agent calls: tracker_dashboard
한 번의 호출이 다음과 같은 결과를 반환합니다:
{
"stats": {
"total_tasks": 12,
"tasks_done": 4,
"tasks_blocked": 1,
"completion_pct": 33.3
},
"blocked_tasks": [
{ "title": "Add rate limiting", "epic": "Authentication" }
],
"recent_activity": [
"Task 'JWT auth' status: in_progress → done",
"... (other entries)"
]
}
에이전트는 즉시 33 %가 완료되었고, 하나의 작업이 차단되었으며, 인증 에픽이 카탈로그보다 앞서 있다는 것을 알게 됩니다. 추가 설명 없이도 우선순위를 정할 수 있습니다.
결정 기록하기
Me: "We're going with Redis for caching. Mark the research tasks as done."
Agent calls:
note_save (decision: Redis for caching, reasons, trade‑offs)
task_batch_update (mark tasks 8, 9 as done)
결정은 타입이 지정된 노트로 저장되고, 해당 에픽에 연결됩니다. 다음 세션에서 에이전트가 왜 Redis를 선택했는지 이해해야 할 경우, 내가 다시 설명할 필요 없이 그 노트를 검색하면 됩니다.
토큰 수학
- Saga의 23개 도구 정의는 시스템 프롬프트에 약 1,500 토큰을 차지합니다. 이는 고정 비용이며 프로젝트 규모에 따라 증가하지 않습니다.
tracker_dashboard호출은 약 800 토큰의 구조화된 데이터를 반환합니다.- “show me blocked tasks”와 같은 필터링된 쿼리는 약 200 토큰을 반환합니다.
반면, 중간 규모 프로젝트의 PROGRESS.md 파일은 3,000–5,000 토큰을 차지하며, 매 세션마다 전체가 로드되고 시간이 지남에 따라 늘어납니다.
교차점: 약 15–20개의 작업. 이보다 많아지면 구조화된 접근 방식이 더 잘 확장됩니다. 에이전트가 요청한 것만 가져오고, 모든 것을 가져오지는 않기 때문입니다.
그리고 마크다운 파일과 달리 데이터는 쿼리할 수 있습니다. “What did we decide about caching?”는 note_search 호출이며, 전체 파일을 스캔하는 것이 아닙니다.
내부 구조
- SQLite with WAL mode – 쓰기 중에도 동시 읽기 가능, 잠금 충돌 시 5 초의 busy timeout
- Foreign keys enforced – 에픽을 삭제할 때 고아가 되는 작업이 없으며 (연쇄 삭제)
- Append‑only activity log – 생성, 업데이트, 삭제 모든 작업이 필드 수준의 세밀함으로 기록됩니다
- Parameterized queries with column allowlists – SQL 인젝션 위험이 없습니다
- MCP safety annotations on every tool – 클라이언트는 각 도구가 읽기 전용, 파괴적, 혹은 멱등인지 알 수 있습니다
전체 코드는 약 1,400줄의 TypeScript이며, 의존성은 MCP SDK와 better-sqlite3 두 개뿐입니다.
세션 차이: 내가 계획하지 않은 기능
런칭 후, Reddit 사용자 중 한 명이 물었습니다: “세션 간에 무엇이 바뀌었는지 보여줄 수 있나요?”
좋은 아이디어였습니다. 활동 로그는 이미 모든 것을 캡처하고 있었고, 단지 집계 레이어만 추가하면 되었습니다.
tracker_session_diff를 추가했습니다. 타임스탬프를 전달하면 다음과 같은 결과를 반환합니다:
{
"total_changes": 14,
"summary": {
"created": 3,
"status_changed": 4,
"updated": 5,
"deleted": 2
},
"highlights": [
"Task 'Fix auth bug' status: in_progress → done",
"Created epic 'API v2'",
"Note 'Sprint retro' deleted"
]
}
에이전트는 이를 호출해 마지막 세션 이후에 일어난 일들을 간결하게 파악할 수 있어, 대화를 집중시키고 토큰 사용을 효율적으로 유지할 수 있습니다.
시작하기
프로젝트의 .mcp.json 파일에 다음을 추가하세요:
{
"mcpServers": {
"saga": {
"command": "npx",
"args": ["-y", "saga-mcp"],
"env": {
"DB_PATH": "/absolute/path/to/your/project/.tracker.db"
}
}
}
}
이것으로 끝입니다. Claude Code, Claude Desktop, 혹은 MCP와 호환되는 모든 클라이언트에서 작동합니다. 데이터베이스 파일은 처음 사용할 때 자동으로 생성됩니다.
배운 점
Saga를 구축하면서 에이전트가 실제로 정보를 소비하는 방식에 대해 한 가지를 배웠습니다: 구조화된 형태가 prose(문장)보다 더 효율적입니다.
Markdown 파일은 인간이 문서를 스캔하기에 최적화되어 있습니다. 필터링된 JSON을 반환하는 타입된 툴 호출은 다음에 무엇을 할지 결정하는 LLM에 최적화되어 있습니다. 에이전트는 여러분의 프로젝트 상태를 “읽을” 필요가 없으며—쿼리할 필요가 있습니다.
MCP가 이를 실용적으로 만들어 줍니다. 이 프로토콜은 툴 탐색, 타입된 스키마, 그리고 전송을 처리합니다. 제가 해야 했던 것은 그 뒤에 데이터베이스를 두는 것뿐이었습니다.
멀티 세션 에이전트 워크플로를 구축하고 있으며 점점 커지는 컨텍스트 파일을 관리하고 있다면, 그 컨텍스트를 데이터베이스로 대체하는 것을 고려해 보세요.
Saga는 오픈소스(MIT)이며 npm에서 사용할 수 있습니다:
- GitHub:
- 설치:
npx -y saga-mcp