레퍼런스 구현을 따라가며 살펴보는 자주 발생하는 실패 유형
AI 덕분에 일의 속도가 빨라졌지만, 그만큼 따라가기는 더 어려워지고 있습니다. Anthropic에서는 이를 돕기 위해 간단한 에이전트 자동화를 자주 활용합니다. 이런 자동화는 대개 정해진 일정에 따라 백그라운드에서 맥락을 모으고, 우리가 알아야 할 내용을 먼저 알려 줍니다. 그러나 효과적인 에이전트 자동화를 만들기는 쉽지 않습니다. 아무도 모르는 사이에 소스에 접근하지 못하게 되거나, 우리가 원하는 방식을 따르지 못하는 경우가 생기기 때문입니다.
Claude Managed Agents(베타)를 사용해 레퍼런스 구현을 만들었습니다. 이 구현은 정해진 일정에 따라 사용자 지정 소스(예: Slack, GitHub 저장소)를 읽고, 지난 실행 이후 달라진 점을 추적해, 꼭 알아야 할 내용을 (예: Slack에) 게시합니다. 이 글에서는 각 단계를 차례로 살펴보고, 레퍼런스 구현을 공유하며, 에이전트 설정을 대신해 주는 Claude Code 명령어도 소개합니다.
레퍼런스 구현은 여기에서 볼 수 있습니다. 대화형으로 따라 해 보고 싶다면 Claude Code에서 아래 명령어를 실행하세요. claude-api 스킬이 이 글의 가이드에 따라 에이전트 설정을 도와줍니다.
/claude-api managed-agents-onboard https://claude.dev/blog/building-effective-agent-automations/이 레퍼런스 구현에는 Slack 앱(매니페스트로 만들기)과 GitHub 토큰이 필요합니다. 아래에 나오는 제공 파일은 에이전트, 환경, 메모리 스토어, 볼트, 디플로이먼트 등 Claude API 리소스의 설정 파일입니다.
daily-brief/
├── agent.md model, tools, instructions
├── deployment.md schedule, time zone, budget, input message
├── environment.yaml network allowlist
├── memory_store_preferences.yaml user preferences
├── memory_store_state.yaml the agent's bookmarks, ledger, notes, and run records
├── vault.yaml the vault that holds the credentials
├── claude-lock.json resource IDs, written by ant apply
└── slack/manifest.yaml one bot appant CLI 명령어인 ant apply는 이 파일들을 읽어 Claude API 워크스페이스(플랫폼이 리소스를 저장하고 실행하는 곳)에 리소스를 만들고, 각 ID를 claude-lock.json에 기록합니다.
이 명령어는 아래 여러 섹션에서 계속 사용합니다. 설정을 마치면 자동화는 Anthropic 인프라에서 일정에 맞춰 실행되므로, 내 컴퓨터에서 따로 켜 둘 필요가 없습니다.
이 글에서 만들 에이전트는 여섯 가지 구성 요소로 이루어져 있으며, 아래 순서대로 설명합니다.

에이전트는 기본으로 Slack 채널과 GitHub 풀 리퀘스트, 두 가지 소스를 읽습니다. 읽을 채널과 저장소는 preferences 파일에 나열합니다. 이 템플릿은 다른 소스도 읽도록 확장할 수 있습니다.

Managed Agents에서는 자격 증명을 볼트에 보관합니다. 에이전트는 이 자격 증명을 참조할 수는 있지만 실제 값은 Claude의 코드가 실행되는 샌드박스 바깥의 볼트에 남아 있습니다(여기와 여기 참고).
MCP 서버(GitHub): 에이전트는 샌드박스 밖에서 실행되는 프록시를 통해 MCP 도구를 호출합니다. 프록시는 서버의 URL과 일치하는 URL의 볼트 자격 증명을 찾아 사용합니다.
셸(Slack): 에이전트는 샌드박스 안에서 bash 도구로 curl을 실행해 Slack API를 호출합니다. 샌드박스에는 $SLACK_BOT_TOKEN라는 의미 없는 자리표시 값만 있습니다. 요청이 샌드박스를 벗어나는 시점에 플랫폼이 허용된 호스트에 한해 이 값을 실제 토큰으로 바꿔 줍니다.
ant CLI와 저장소의 템플릿 파일로 볼트를 만듭니다.
ant apply vault.yaml이 명령어는 플랫폼이 볼트를 저장하는 Claude API 워크스페이스에 볼트를 만들고, 그 ID를 claude-lock.json에 기록합니다. 그다음 TypeScript SDK로 각 자격 증명을 볼트에 추가합니다. 다음은 Slack 자격 증명을 추가하는 예시입니다.
const vaultId = process.env.VAULT_ID!; // the vault's ID, from claude-lock.json await client.beta.vaults.credentials.create(vaultId, { display_name: "SLACK_BOT_TOKEN", auth: { type: "environment_variable", secret_name: "SLACK_BOT_TOKEN", secret_value: process.env.SLACK_BOT_TOKEN!, networking: { type: "limited", allowed_hosts: ["slack.com"] }, injection_location: { header: true }, }, });
볼트를 만들고 자격 증명을 모두 추가했다면 볼트를 디플로이먼트에 연결합니다. claude-lock.json의 볼트 ID를 디플로이먼트 파일 deployment.md의 vault_ids에 복사하세요.
흔히 하는 실수는 에이전트에게 "최근 24시간"처럼 고정된 기간을 읽으라고 시키는 것입니다. 실행이 늦어지면 빈 구간이 생기고, 일찍 실행되면 같은 항목이 반복됩니다. 대신 소스마다 북마크를 하나씩 주세요. 에이전트는 매 실행이 끝날 때 각 소스에서 읽은 가장 최근 항목의 타임스탬프를 소스별 항목으로 "slack": "2026-09-14T13:02:11Z" 형태로 파일 하나(bookmarks.json)에 기록합니다.
다음 실행은 이 북마크에서 시작하므로, 읽는 구간이 늘거나 줄면서 지난 실행 이후의 모든 내용을 빠짐없이 다룹니다. 북마크는 state라는 메모리 스토어에 저장됩니다. 메모리 스토어는 텍스트 파일이 담긴 폴더로, 플랫폼이 매 실행의 샌드박스 /mnt/memory/ 아래에 마운트하고 실행 사이에도 유지합니다. 에이전트는 일반 파일 도구로 이를 읽고 쓰며, 방법은 agent.md의 지침에 적혀 있습니다.
MCP 서버가 다운됐거나 토큰이 만료돼도 실행은 시작되며, 해당 서버의 도구만 빠집니다. 세션에는 오류가 기록되지만 에이전트는 그 소스에서 아무것도 보지 못하고 "새로운 내용 없음"이라고 보고합니다.
agent.md의 규칙 세 가지가 이 문제를 해결합니다. 소스 읽기에 실패하면 에이전트는 그 소스의 북마크를 그대로 두고, 나머지 소스만으로 브리프를 작성하며, 브리프 끝에 읽지 못한 소스를 밝히는 한 줄("이번 실행에서는 풀 리퀘스트를 확인할 수 없음")을 덧붙여 독자가 알 수 있게 합니다.
이 템플릿은 실행할 때마다 날짜를 붙인 게시물을 Slack 채널 한 곳에 올립니다.

에이전트는 샌드박스의 bash 도구로 Slack에 게시하며, 읽을 때 쓰는 것과 같은 봇 토큰을 사용합니다.
게시에 별도의 승인 절차는 없습니다. 에이전트가 bash 명령으로 게시물을 보내는데, 내장 bash 도구는 기본적으로 승인을 요청하지 않고 실행됩니다. 또 slack.com는 에이전트가 실행되는 샌드박스인 환경의 허용 목록에도 들어 있습니다. 게시는 요청 한 번으로 끝납니다.
curl -s https://slack.com/api/chat.postMessage \ -H "Authorization: Bearer $SLACK_BOT_TOKEN" \ -H "Content-Type: application/json; charset=utf-8" \ -d '{"channel": "C0123456789", "text": "Daily brief, Tue Sep 15 ..."}'
게시가 확인되면 에이전트는 보고한 항목 원장과 북마크를 갱신합니다. 이 기록이 실제 게시 내용과 어긋나면 두 가지 문제가 생길 수 있습니다. 게시되지 않았는데 게시된 것으로 기록하면 북마크가 앞으로 넘어가 해당 항목이 영영 보고되지 않습니다. 반대로 첫 게시가 성공했는지 확신하지 못해 다시 게시하면 독자는 같은 브리프를 두 번 받게 됩니다.
agent.md의 규칙 세 가지가 이를 막아 줍니다. 첫째, 에이전트는 채널의 최근 메시지에서 오늘 날짜의 제목을 찾아보고, 이미 올라와 있으면 게시하지 않습니다. 둘째, Slack이 "ok": true와 메시지 ts를 반환해야만 전송된 것으로 간주합니다. 셋째, 이 확인이 끝난 뒤에만 원장과 북마크를 갱신합니다. 결과가 불분명하면 해당 실행을 "게시 여부 불확실"로 표시하고 다른 항목은 건드리지 않으므로 누락되는 것이 없습니다.
에이전트는 메모리 스토어(runs/<date>.md)에 실행 기록을 남깁니다. 게시 전에는 "게시 중"으로 표시하고, 이후 메시지 ID와 함께 "게시됨" 또는 "게시 여부 불확실"로 바꿉니다.
Claude Managed Agents에서 에이전트는 모델, 시스템 프롬프트, 도구로 이루어진 버전 관리되는 설정입니다. 실행할 때마다 실행 단계를 따라 작업하고 멈춥니다.

이 레퍼런스 구현에서 에이전트 설정은 agent.md입니다.
--- name: Daily brief model: claude-sonnet-5-5 mcp_servers: - type: url name: github url: https://api.githubcopilot.com/mcp/ tools: - type: agent_toolset_20260401 configs: - name: web_search enabled: false - name: web_fetch enabled: false - type: mcp_toolset mcp_server_name: github default_config: permission_policy: type: always_allow --- [Eight numbered run steps; the full text is in agent.md in the repo.]
프런트매터에는 에이전트 이름, 모델, 도구, MCP 서버를 지정하고, 본문에는 에이전트 지침을 적습니다. MCP 도구는 기본적으로 승인을 요구하는데 승인해 줄 사람이 없으므로, GitHub 툴셋은 always_allow로, GitHub 토큰은 read-only로 설정합니다.
agent.md는 Claude가 간결하게 쓰도록 유도합니다.
4. Decide. An item earns a line when the reader would act on it today, or it changes a decision they are about to make. When unsure, leave it out. Most days that is a few items, sometimes none. A count ("12 open reviews") is not an item; link the ones that are blocked. An item already in the ledger and still open is carried as one marked line ("still waiting, day 3"), not re-reported; a closed item is dropped without comment. Do not bring back a topic the preferences file has retired.에이전트가 소스를 읽은 시점과 게시하는 시점 사이에 항목 상태가 바뀔 수 있습니다. agent.md는 게시 직전에 각 항목의 최신 상태를 다시 확인하도록 에이전트에게 지시합니다.
5. Verify. The world moved while you read. For every item you will report, re-check its live source just before posting: resolved since you read it, drop it; still open but changed, fix the line; cannot confirm, drop it and list it in the run record's cuts. One stale "still waiting on you" costs more trust than ten missing items, so never hedge an item's status: assert it or drop it. Every link is copied from the source's own link field (a pull request's html_url, a Slack permalink), never assembled by hand.Claude Managed Agents에서 에이전트는 설정 파일일 뿐이며, 이를 실제로 실행하는 것은 디플로이먼트입니다. 디플로이먼트에는 에이전트와 환경, 그리고 매 실행의 첫 메시지를 지정합니다. 스케줄, 볼트, 메모리 스토어, 예산도 여기에 들어갑니다. 스케줄이 작동할 때마다 플랫폼은 새 에이전트 세션을 시작합니다.

이 템플릿에서는 디플로이먼트를 deployment.md에 정의하며, 본문이 곧 첫 메시지입니다.
--- name: Daily brief agent: ./agent.md environment_id: ./environment.yaml schedule: type: cron expression: "32 7 * * 1-5" timezone: America/New_York vault_ids: [vlt_...] # the vault you create under Sources resources: - path: ./memory_store_preferences.yaml access: read_only instructions: The reader's preferences. Re-read them every run. Never write here. - path: ./memory_store_state.yaml access: read_write instructions: Your state. Bookmarks, ledger, notes, proposals, and run records. --- Write today's brief. The reader's time zone is America/New_York. Work out every date in that zone. Follow your run steps in order. Today's edition is titled "Daily brief, <weekday> <month> <day>".
이 명령은 경로로 지정한 에이전트, 환경, 메모리 스토어를 연결해 디플로이먼트를 만듭니다.
ant apply deployment.md스케줄을 기다리지 않고 테스트하려면 claude-lock.json의 ID를 사용해 ant beta:deployments run --deployment-id <id>로 직접 실행을 시작하면 됩니다.
에이전트가 서버의 시간대로 날짜를 계산하는 바람에 오늘 아침을 "어제"라고 부르는 버그가 흔합니다. deployment.md에서 timezone 필드는 실행 시각을 정하고, 본문의 두 번째 줄은 날짜 계산에 쓸 시간대를 에이전트에게 알려 줍니다.
매 실행은 지난 실행을 전혀 기억하지 못하는 새 샌드박스에서 시작합니다. 메모리가 없으면 피드백이 반영되지 않습니다. 반대로 낡은 메모리는 에이전트를 혼란스럽게 할 수 있습니다. 이미 해결된 항목을 아직 대기 중이라고 보고하거나, 아직 열려 있는 항목을 "이미 보고했다"는 이유로 빠뜨리기도 합니다.

이 템플릿은 /mnt/memory/ 아래에 마운트되는 폴더인 메모리 스토어를 두 개 사용합니다(소스 섹션 참고).
preferences(사용자 소유, 에이전트는 읽기 전용): 읽을 채널과 저장소, 제외할 내용, 길이 제한, 목적지, 중단 조건을 담습니다.
state(에이전트 소유, 읽기·쓰기 가능): 북마크, 보고한 항목의 원장, 실행별 기록, 에이전트가 제안하는 선호 설정 변경안, 각 소스의 동작 특성 메모("최신 50개 항목만 반환함" 등)를 담습니다.
ant apply deployment.md는 preferences 스토어를 만들지만 그 안의 파일까지 만들지는 않습니다. 첫 실행 전에 저장소의 scripts/seed-preferences.sh로 preferences.md를 해당 스토어에 작성해 두세요.
프롬프트에 선호 설정의 사본을 박아 두면, 이미 바꾼 규칙이 계속 적용되는 문제가 자주 생깁니다. 에이전트가 매 실행마다 파일을 새로 읽게 하세요. 파일을 읽지 못하면 기본값으로 실행하지 말고 중단한 뒤 그 사실을 알려야 합니다.
에이전트는 보고한 모든 항목을 ledger.md 원장에 기록해 브리프가 같은 내용을 반복하지 않게 합니다. 각 줄에는 항목을 보고한 시점, 출처, 변하지 않는 ID(Slack 메시지 타임스탬프나 풀 리퀘스트 번호), 마지막으로 확인한 상태가 담깁니다.
2026-09-09 slack:C0123456789 1788963600.000100 refund thread: customer waiting on a decision
2026-09-11 github 481 review blocked, day 2 (still waiting)
2026-09-11 slack:C0234567891 1789117333.000300 enterprise escalation: owner named, in progress이 자동화는 일정에 따라 "백그라운드"에서 실행되므로, 에이전트가 할 수 있는 일과 쓸 수 있는 비용에 한도를 둡니다.

에이전트는 다른 사람이 쓴 메시지와 이슈를 읽는데, 그 텍스트가 지시로 해석될 수 있습니다. 에이전트가 그 지시를 따르더라도 할 수 있는 일이 제한되도록 하세요. 이 예시에서는 GitHub 토큰과 preferences 스토어가 읽기 전용이고, 환경은 허용 목록에 있는 호스트에만 접근할 수 있습니다. 심어 둔 지시가 에이전트가 실행 사이에 남기는 메모를 포함해 브리프의 내용을 바꿀 수는 있습니다. 하지만 GitHub에 쓰거나 사용자의 규칙을 수정할 수는 없습니다.
Slack은 예외입니다. 같은 토큰으로 게시까지 하므로 봇은 읽거나 게시해야 하는 곳에만 초대하세요.
지출 한도는 비용이 걷잡을 수 없이 늘어나는 것을 막아 줍니다. 일반적인 실행 비용의 3~5배로 시작해, 실제 수치를 보면서 점차 낮추세요. 한도에 도달한 실행은 실패하지 않고 일시 중지되므로, 한도를 너무 낮게 잡으면 브리프가 조용히 끊긴 것처럼 보입니다. 한도는 deployment.md의 budget입니다. 모든 실행에 같은 금액이 적용되며, 한도에 도달한 실행은 budget_reached 중단 사유와 함께 일시 중지됩니다.
budget: type: limit max_list_cost: amount: "500" # a string, in cents: "500" is $5.00 currency: USD
이 레퍼런스 구현은 여섯 가지 규칙으로 요약됩니다.
Claude Code로 이 글의 가이드를 차근차근 따라 할 수 있습니다. 먼저 업데이트합니다.
claude update그다음 claude-api 스킬을 사용합니다.
/claude-api managed-agents-onboard https://claude.dev/blog/building-effective-agent-automations/claude-api 스킬은 이 글을 읽고 설정안을 제안한 뒤, 프로젝트의 agents/ 폴더에 파일을 작성하고 ant apply로 리소스를 만듭니다. 이는 출발점일 뿐이니, 소스, 목적지, 메모리 설정에 맞게 에이전트를 자유롭게 바꿔 사용하세요.