黄奕彬

外部精选

Building effective agent automations

本文来自外部来源,不是黄奕彬的原创文章。本站提供原文入口,并在采集端生成 AI 结构化摘要、解读与中文翻译(如有),一切以原文为准。

阅读原文(claude.dev)
来源
claude.dev Blog ↗
作者 / 署名
Lance Martin、CJ Avilla、Lance Martin and CJ Avilla
发布日期
本站收录时间
原文域名
claude.dev

以上时间均为北京时间;来源更新时间由来源提供,不代表首次发布时间。

结构化摘要 AI 生成

背景与问题

背景:AI 加速工作节奏后,信息越来越难跟上。文章以 Anthropic 内部实践为背景:常用简单的 agent 自动化按计划运行、后台收集上下文、主动推送需要知道的内容。但要构建得有效很难——agent 可能在无人察觉时失去某个数据源的访问权限,或不遵循用户偏好。文章要回答:如何可靠地构建这类定时自动化。

方法或内容

方法:基于 Claude Managed Agents(beta)给出一个参考实现(Daily brief 每日简报 agent),按六部分讲解:Sources、Destination、Agent、Schedule、Memory、Guardrails。

配套文件含 agent.md、deployment.md、environment.yaml、两个 memory store、vault.yaml、claude-lock.、slack/manifest.yaml,用 ant CLI 的 ant apply 在 Claude API workspace 创建资源;可在 Claude Code 中运行 /claude-api managed-agents-onboard https://claude.dev/blog/building-effective-agent-automations/ 自动配置,并可用 ant beta:deployments run 手动测试。

关键发现 / 结果

关键机制(原文未提供运行或效果数据,均为设计要点):

  • 每源一书签(bookmarks.)做增量读取,取代固定时间窗
  • 源失败三规则:该源书签不动、用其余源出简报、末尾注明不可读(如 pull requests unavailable this run)
  • 发帖三规则:先查当日标题是否已发;Slack 返回 "ok": true 与消息 ts 才算发送;确认后才更新账本与书签,不明则记 maybe posted
  • agent 配置:模型 claude-sonnet-5-5,GitHub MCP 设 always_allow 且 token 只读,禁用 web_search/web_fetch
  • 定时:cron 32 7 * * 1-5(America/New_York);沙箱内用 curl 调 chat.postMessage 发 Slack
  • 双 memory store 挂载于 /mnt/memory/:preferences 只读、state 读写;首次运行前用 scripts/seed-preferences.sh 写入偏好
  • 护栏:环境网络 allowlist;每轮预算上限示例 500 美分($5.00),触发后以 budget_reached 暂停而非失败
  • 文末归纳六条构建规则

结论与意义

结论:按六条规则构建即可获得可靠的定时简报自动化——从书签读取而非固定窗口;把失败读取报为不可读而非安静日;发帖前复核每项实时状态;Slack 确认后才更新账本与书签;每轮从 agent 不可写的存储重读偏好;只读处给只读权限并设每轮消费上限。配置后运行于 Anthropic 基础设施,本地无需常驻进程。

边界:示例默认 Slack + GitHub 源、单一 Slack 目的地(可扩展);Slack token 读写共用是权限例外;注入指令仍可能影响简报内容。

AI 解读 AI 生成

方法:按「时空变量」分析(时间 / 空间 / 变量,严格区分包含、相关与因果),对象包括原文作者、署名人员与关键技术及其实际原理;结论用「元反空」(元思考、反思考、空思考、综合)整理。

时间:何时发生,现在是否仍成立

来源日期为 2026年10月8日 20:00(北京时间),即北京时间 2026年10月8日 20:00。文中 Claude Managed Agents 处于 beta,工具集命名如 agent_toolset_20260401、ant CLI 命令与 claude update 流程均反映当期版本,随产品演进可能更名或失效。

文章属于模式与配置说明,不依赖时效性数据;这些接口现在是否仍可用,原文未说明,需按当期文档核对。

空间:谁的环境 / 场景

适用于使用 Claude Managed Agents(beta)与 Claude API workspace 的用户,部署形态为:agent 仅是配置文件(agent.md),由 deployment 按 cron 在 Anthropic 基础设施上运行,bash 工具跑在沙箱内,真实凭据存于沙箱外 vault。

示例场景:读 Slack 频道与 GitHub PR,向单个 Slack 频道发每日简报;需自建 Slack app(按 manifest)并持有 GitHub token;在 Claude Code 中先 claude update 再用 claude-api skill 配置。

变量:实际改变了什么

这是构建指南而非变更公告,没有前后对比的数据、价格或结构变更。

相对朴素做法的差异是设计行为上的:书签替代固定窗口;发送以 Slack 确认为准并引入 maybe posted 状态;每轮重读只读 preferences;每轮全新沙箱、状态跨 run 保留于 /mnt/memory/;沙箱内只见 $SLACK_BOT_TOKEN 占位符,请求出沙箱时对允许 host 换入真值。预算默认值与定价原文未说明(示例上限 500 美分)。

区分:包含 ≠ 相关 ≠ 因果

有明确因果表述的:MCP 服务器宕机或 token 过期 → 该源本轮缺席而简报误报 nothing new;记录了未落地的帖子 → 书签前移导致永久漏报;不确定是否发成功就重发 → 读者收到重复简报;cap 设得过低 → run 暂停(budget_reached)表现为简报变安静;植入指令 → 仍可改变简报内容(含经跨 run notes 持续影响)。

仅包含或相关的:六组件、各配置文件与工具只是同属一个实现,相互之间无因果主张;只读 token 与 allowlist 是权限约束关系;可靠性、信任等收益无数据验证,原文未说明。

对象:作者/署名与关键技术原理

署名(仅按结构化作者字段):Lance Martin、CJ Avilla;字段另含联署形式 Lance Martin and CJ Avilla。关键技术及原文描述的原理:

  • Claude Managed Agents(beta):agent 为版本化配置(模型、系统提示、工具),deployment 负责运行并持有 schedule、vault、memory、budget;cron 每次触发启动全新 session
  • Vault:真实凭据存平台侧、沙箱之外;MCP 工具经沙箱外代理调用并按 URL 匹配凭据;bash 内只见 $SLACK_BOT_TOKEN 占位符,请求离开沙箱时对允许的 host 换入真实 token
  • Memory store:挂载于 /mnt/memory/、跨 run 保留的文本文件夹,preferences 只读、state 读写
  • ant apply:读取配置文件在 workspace 创建资源并把 ID 写入 claude-lock.

元反空综合结论

元:本质在解决无人值守定时 agent 的可靠性——不重不漏(书签 + 账本)、失败可见(不可读 ≠ 安静)、状态一致(确认后才记账)、偏好新鲜(每轮重读只读文件)、权限与花费受控(只读 + allowlist + 每轮预算)。

反:最可能失效或有边界的点:产品为 beta,schema(如 agent_toolset_20260401)与命令会变;植入指令仍能影响简报文本且可经 notes 跨 run 持续;Slack 读写同一 token 是明确例外风险;cap 过低易被误读为无事发生;全文无实测数据,效果主张未经验证。

空:去掉叙事后剩下的必要事实——存在一套可复用的参考实现与机制:书签、账本、run 记录、发送确认协议、vault 凭据注入、双 memory store、cron 与预算上限,以及 ant apply 与 claude-api skill 的配置路径。

综合:作为 beta 产品的工程模式指南可信且可操作,六条规则对通用定时 agent 设计有迁移价值;但具体接口须按当期文档核对,可靠性收益属设计推断而非数据结论。

中文译文 AI 生成

随着 AI 加速我们的工作,跟上节奏变得越来越难。在 Anthropic,我们经常使用简单的 agent 自动化来提供帮助。

它们通常按计划运行,在后台收集上下文,并主动告知我们需要了解的信息。但要构建有效的 agent 自动化并不容易:它们可能在无人察觉的情况下失去对某个来源的访问权限,或者无法遵循我们的偏好。

我们使用 Claude Managed Agents(beta)构建了一个参考实现:它按计划读取自定义来源(例如 Slack 和 GitHub 仓库),跟踪自上次运行以来的变化,并发布你需要了解的内容(例如发布到 Slack)。

在本文中,我们将逐步讲解每个步骤,分享一个参考实现,并提供一条可在 Claude Code 中运行的命令,由它为你配置这个 agent。

获取代码

参考实现在这里。如需交互式演练,请在 Claude Code 中运行下面的命令。claude-api skill 可以按照本文的指导帮助你搭建这个 agent:

PROMPT /claude-api managed-agents-onboard https://claude.dev/blog/building-effective-agent-automations/

对于这个参考实现,你需要一个 Slack 应用(从 manifest 创建)和一个 GitHub token。提供的这些文件(如下所示)是针对 Claude API 资源的配置,包括 agent、它的环境、memory store、vault 和 deployment。

CODEText daily-brief/ ├── agent.md 模型、工具、指令├── deployment.md 计划、时区、预算、输入消息├── environment.yaml 网络 allowlist ├── memory_store_preferences.yaml 用户偏好├── memory_store_state.yaml agent 的书签、账本、笔记和运行记录├── vault.yaml 保存凭证的 vault ├── claude-lock.json 资源 ID,由 ant apply 写入└── slack/manifest.yaml 一个 bot 应用

ant apply 是 ant CLI 中的一个命令,它读取这些文件,在你的 Claude API workspace 中创建资源(平台会在其中存储并运行这些资源),并把 ID 记录到 claude-lock.json 中。

我们将在下面的章节中使用这个命令。配置完成后,该自动化会在 Anthropic 的基础设施上按计划运行,因此你的机器上不需要保持任何东西在运行。

概览

我们将构建的 agent 有六个组成部分,按以下顺序介绍:

  • 来源 - 一个命名的读取位置列表
  • 目标位置 - agent 可以写入的一个位置
  • Agent - agent.md 中的模型、工具和运行步骤
  • 计划 - 一个 cron 计划
  • 记忆 - 你的偏好以及 agent 自身的记忆
  • 护栏 - 在 agent 只读取的地方一律采用只读访问,并为每次运行设置支出上限

来源

该 agent 读取两个默认来源:Slack 频道和 GitHub pull request。频道和仓库列在你的偏好文件中。该模板可以扩展为使用其他来源。

为 agent 提供其专属的、限定作用域的凭证

在 Managed Agents 中,凭证存放在 vault 中。agent 可以引用这些凭证,但真实值保留在 vault 里,位于运行 Claude 代码的 sandbox 之外(参见此处和此处):

  • MCP 服务器(GitHub)。agent 通过一个在 sandbox 之外运行的 proxy 调用 MCP 工具。该 proxy 会找到 URL 与该服务器相匹配的 vault 凭证。
  • Shell(Slack)。agent 在 sandbox 内使用 bash 工具通过 curl 调用 Slack API。sandbox 中只保存一个不透明的占位符 $SLACK_BOT_TOKEN。当请求离开 sandbox 时,平台会针对你允许的主机换入真实的 token。

使用 ant CLI 和仓库中的模板文件创建 vault:

CODEShell ant apply vault.yaml

这会在你的 Claude API workspace 中创建 vault(平台会将其存储在那里),并把它的 ID 记录到 claude-lock.json 中。然后使用 TypeScript SDK 把每个凭证添加到 vault 中。下面是一个展示如何添加 Slack 凭证的示例:

CODETypeScript const vaultId = process.env.VAULT_ID!; // vault 的 ID,来自 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 }, }, });

创建 vault 并添加好每个凭证后,把 vault 附加到 deployment 上。把 vault ID 从 claude-lock.json 复制到 deployment 文件 deployment.md 中的 vault_ids 里。

从上次中断的地方继续读取

一个常见的错误是让 agent 读取一个固定窗口,比如“过去 24 小时”。运行得晚会留下空隙,运行得早则会重复条目。

相反,应该为每个来源给 agent 一个书签。在每次运行结束时,agent 会把它从每个来源读取的最新条目的时间戳写入一个文件 bookmarks.json,每个来源对应一个条目:"slack": "2026年9月14日 21:02(北京时间)"。

下一次运行会从这些书签开始,因此它的窗口会拉伸或收缩,以覆盖自上次运行以来的所有内容。这些书签存放在名为 state 的 memory store 中:那是一个由文本文件组成的文件夹,平台会把它挂载到每次运行的 sandbox 中的 /mnt/memory/ 下,并在各次运行之间保留。

agent 用它常规的文件工具对其进行读写,agent.md 中的指令会告诉它怎么做。

不要把读取失败误当作安静的一天

如果某个 MCP 服务器宕机或其 token 已过期,运行仍会启动,只是没有该服务器的工具。会话会记录一个错误,但 agent 从该来源什么也看不到,于是报告“没有新内容”。

agent.md 中的三条规则有助于解决这一问题。当某个来源失败时,agent 会:

  • 保持该来源的书签原位不动
  • 根据其他来源撰写简报
  • 在简报结尾用一行注明它无法读取的内容(“pull requests 本次运行不可用”),从而让读者知情

目标位置

我们的模板会发布到一个 Slack 频道,每次运行时发出一条带日期的帖子。

agent 使用其 sandbox 中的 bash 工具向 Slack 发帖,所用的是它与读取时相同的 bot token。

没有任何东西需要批准这篇帖子。agent 用一条 bash 命令发送它,内置的 bash 工具默认无需请求批准即可运行。slack.com 也在 agent 环境的允许列表中,这个环境就是它运行所处的沙箱。

这篇帖子就是一条请求:

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 就会更新它已报告条目的台账和书签。如果这些记录与实际发布的内容不符,可能出现两类问题。

如果 agent 记录了一条从未发布的帖子,书签就会继续前移,这些条目永远不会被报告。如果它因为不确定第一条帖子是否发布成功而再次发布,读者就会收到两次相同的简报。

agent.md 中的三条规则可以防止这些问题。第一,agent 会在频道的近期消息中查找今天的标题,如果这一期已经存在,就不再发布。第二,只有当 Slack 返回 "ok": true 以及一个 message ts 时,这篇帖子才算已发送。

第三,agent 只有在那次确认之后才更新台账和书签。如果结果不明确,它会将这次运行标记为 "maybe posted",除此之外不做任何改动,因此不会丢失任何东西。

agent 在它的记忆库中保存一份运行记录(runs/<date>.md)。它在发布前将这次运行标记为 "posting",之后标记为附带消息 ID 的 "posted",或者标记为 "maybe posted"。

智能体

在 Claude Managed Agents 中,agent 是一个有版本的配置:一个模型、一个系统提示词和工具。每次运行都遵循它的运行步骤,然后停止。

在我们的参考实现中,agent 的配置是 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 ---

[八个带编号的运行步骤;完整文本见仓库中的 agent.md。]

frontmatter 提供 agent 的名称、模型、工具和 MCP 服务器。正文提供 agent 的指令。MCP 工具默认会请求批准,而没有人在场可以给出批准,因此 GitHub 工具集被设置为 always_allow,且 GitHub 令牌为只读。

保持简报简短

agent.md 引导 Claude 偏向简洁:

  1. 决定。当读者今天就会据此采取行动,或者它改变了读者即将做出的某个决定时,一条条目才值得占一行。不确定时,就略去。大多数日子只有几条,有时一条也没有。一个计数("12 open reviews")不是条目;把被阻塞的那些用链接列出。已在台账中且仍处于开启状态的条目,作为一行带标记的内容延续("still waiting, day 3"),而不是重新报告;已关闭的条目则直接删去,不作说明。不要把偏好文件已经除名的主题重新带回来。

在发布前一刻重新核查所有仍开启的条目

条目在 agent 阅读来源与发布之间可能发生变化。就在发布之前,agent.md 指示 agent 重新核查每条条目的实时状态:

  1. 核实。在你阅读的时候,世界已经变了。对你将要报告的每条条目,在发布前重新核查其即时来源:自你读取后已解决的,删掉;仍开启但有变化的,修正那一行;无法确认的,删掉并在运行记录的 cuts 中列出。一条过时的 "still waiting on you" 比十条缺失的条目损失更多信任,所以绝不要对条目状态含糊其辞:要么明确断言,要么删掉。每个链接都从来源自身的链接字段复制而来(pull request 的 html_url、Slack permalink),绝不手工拼接。

调度

在 Claude Managed Agents 中,agent 只是一个配置文件;由部署来运行它。部署指明 agent、环境以及每次运行的第一条消息。它还持有调度、vault、记忆库和预算。

每当调度触发时,平台都会启动一个全新的 agent 会话。

在我们的模板中,部署记录在 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_...] # 你在 Sources 下创建的 vault resources:

  • path: ./memory_store_preferences.yaml

access: read_only instructions: 读者的偏好。每次运行都重新阅读它们。绝不要在这里写入。

  • path: ./memory_store_state.yaml

access: read_write instructions: 你的状态。书签、台账、笔记、提案和运行记录。---

写出今天的简报。

读者的时区是 America/New_York。所有日期都按该时区推算。

按顺序遵循你的运行步骤。今天的这一期标题为 "Daily brief, <weekday> <month> <day>"。

这会按路径所指明的 agent、环境和记忆库创建该部署。

ant apply deployment.md

如果不想等待调度就进行测试,可以用 ant beta:deployments run --deployment-id <id> 手动启动一次运行,其中的 ID 取自 claude-lock.json。

按你的时区计算日期

一个常见的 bug 是 agent 把今天早上称为“昨天”,因为它按服务器的时区来计算日期。在 deployment.md 中,timezone 字段设定运行何时触发,而正文的第二行告诉 agent 计算日期应使用哪个时区。

记忆

每次运行都在一个全新的沙箱中开始,对上一次运行没有任何记忆。没有记忆,反馈就无法留存。

然而,过时的记忆也会让 agent 困惑:它会在某条条目已经解决后仍将其报告为等待中,或者因为一条仍然开启的条目“已经报告过”而将其丢弃。

我们的模板维护两个记忆库,即挂载在 /mnt/memory/ 下的文件夹(见 Sources):

  • preferences(属于你,对 agent 只读):要阅读哪些频道和仓库、要略去什么、长度上限、发送目的地,以及何时停止。

state(智能体的,可读写):书签、一份记录它已报告内容的账本、每次运行的一条记录、它建议对你偏好做出的修改,以及关于各来源行为的备注(“只返回最新的 50 条”)。

ant apply deployment.md 会创建偏好存储,但不会创建其中的文件。首次运行之前,用仓库中的 scripts/seed-preferences.sh 把你的 preferences.md 写到那里。

每次运行开始时重新读取你的偏好

一个常见的问题是,把偏好的副本固化进提示词,导致它不断应用你已经改过的规则。让智能体在每次运行时都重新读取该文件。如果它读不了该文件,就应当停下来并说明,而不是按默认设置继续运行。

维护一份你已报告内容的账本,并报告变化

智能体维护一个账本 ledger.md,记录它报告过的每个条目,这样简报就不会自我重复。每一行记录:条目何时被报告、来自哪里、一个不变的 ID(Slack 消息时间戳或 pull request 编号),以及它最后已知的状态:

2026-09-09 slack:C0123456789 1788963600.000100 退款 thread:客户在等待一个决定2026-09-11 github 481 review 被阻塞,第 2 天(仍在等待)2026-09-11 slack:C0234567891 1789117333.000300 企业级升级:已指定负责人,进行中

护栏

由于我们的自动化任务按计划在“后台”运行,我们对智能体能做什么、能花多少钱设置了限制。

限制它能做的事情

智能体会读取其他人写的消息和 issue,而这些文本可能被解读为指令。要限制智能体在遵循这些指令的情况下能做什么。在我们的示例中,GitHub token 和偏好存储是只读的,环境只会访问其允许列表(allowlist)中的主机。

植入的指令仍然可能改变简报的内容,包括通过智能体在运行之间保留的备注来实现。它不能写入 GitHub,也不能编辑你的规则。

Slack 是个例外:同一个 token 也用于发帖,因此只把 bot 邀请到它需要读取或发帖的地方。

根据实际运行设定支出上限

支出上限可以保护你免受失控成本的影响。从一个正常运行成本的三到五倍开始,再随着看到真实数字逐步收紧。达到上限的运行会暂停而不是失败,因此设得太低的上限看起来就像一份突然没了动静的简报。

这个上限就是 deployment.md 中的 budget。每次运行都会获得全额额度,达到该额度的运行会以 budget_reached 停止原因暂停:

budget: type: limit max_list_cost: amount: "500" # 字符串,单位为美分:"500" 即 $5.00 currency: USD

入门

我们的参考实现归结为六条规则:

  • 从书签读取每个来源,而不是固定的时间窗口。
  • 把读取失败报告为无法读取,绝不报告为安静的一天。
  • 在发布前重新核对每个条目。
  • 只有当 Slack 确认后才把一条帖子计为已发送,然后更新书签和账本。
  • 每次运行都重新读取你的偏好,来源是智能体无法编辑的存储。
  • 凡是智能体只读取的地方都给它只读访问权限,并限制每次运行可花费的金额。

Claude Code 可以带你逐步完成本文提供的指引。首先,更新:

claude update

然后,使用 claude-api skill:

/claude-api managed-agents-onboard https://claude.dev/blog/building-effective-agent-automations/

claude-api skill 会阅读这篇文章,提出一套设置,把文件写入你项目的 agents/ 文件夹,并使用 ant apply 创建资源。把它当作一个起点,并针对你的来源、目标位置或记忆偏好来定制该智能体。

展开原文提取正文(采集端自动提取,可能有缺失)

As AI accelerates our work, it's getting harder to keep up. At Anthropic, simple agent automations are frequently used to help. They often run on a schedule, gather context in the background, and proactively tell us what we need to know. But it’s difficult to build effective agent automations: they can lose access to a source without anyone noticing or fail to follow our preferences. Using Claude Managed Agents (beta), we built a reference implementation that reads custom sources (e.g., Slack and GitHub repos) on a schedule, tracks what changed since the last run, and posts what you need to know (e.g., to Slack). In this article, we walk through each step, share a reference implementation, and provide a command to run in Claude Code that configures the agent for you. GET THE CODE The reference implementation is here. For an interactive walkthrough, run the command below in Claude Code. The claude-api skill can help set up the agent following the guidance in this article: PROMPT/claude-api managed-agents-onboard https://claude.dev/blog/building-effective-agent-automations/ For this reference implementation, you need a Slack app (create it from the manifest) and a GitHub token. The provided files (shown below) are configuration for Claude API resources, including the agent, its environment, memory stores, vault, and deployment. CODETextdaily-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 app ant apply, a command in the ant CLI, reads these files, creates the resources in your Claude API workspace (where the platform stores and runs them), and records the IDs in claude-lock.json. We'll use this command in the sections below. Once configured, the automation runs on a schedule on Anthropic's infrastructure, so nothing has to stay running on your machine. OVERVIEW The agent we’ll build has six components, covered in this order:

Sources - A named list of places to read Destination - One place the agent may write Agent - The model, tools, and run steps in agent.md Schedule - A cron schedule Memory - Your preferences and the agent's own memory Guardrails - Read-only access wherever the agent only reads, and a spending cap per run

SOURCES The agent reads two default sources: Slack channels and GitHub pull requests. The channels and repos are listed in your preferences file. The template can be extended to use other sources.

Give the agent its own, scoped credentials With Managed Agents, credentials live in vaults. The agent can reference these credentials but the real values stay in the vault, outside the sandbox where Claude's code runs (see here and here):

MCP servers (GitHub). The agent calls MCP tools through a proxy that runs outside the sandbox. The proxy finds the vault credential whose URL matches the server’s.

The shell (Slack). The agent calls the Slack API with curl using the bash tool inside the sandbox. The sandbox only holds an opaque placeholder, $SLACK_BOT_TOKEN. As the request leaves the sandbox, the platform swaps in the real token for hosts you allow.

Create the vault using the ant CLI and the template file in the repo: CODEShellant apply vault.yaml This creates the vault in your Claude API workspace, where the platform stores it, and records its ID in claude-lock.json. Then add each credential to the vault with the TypeScript SDK. Here is an example showing addition of the Slack credential: CODETypeScriptconst 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 }, }, }); After creating the vault and adding each credential, attach the vault to the deployment. Copy the vault ID from claude-lock.json into vault_ids in the deployment file, deployment.md. Read from where you left off A common mistake is asking the agent to read a fixed window like "the last 24 hours." A late run leaves a gap and an early run repeats items. Instead, give the agent a bookmark per source. At the end of each run, the agent writes the timestamp of the newest item it read from each source to one file, bookmarks.json, with an entry per source: "slack": "2026年9月14日 21:02(北京时间)". The next run starts from those bookmarks, so its window stretches or shrinks to cover everything since the last run. The bookmarks live in the memory store called state: a folder of text files that the platform mounts into every run's sandbox under /mnt/memory/ and keeps between runs. The agent reads and writes it with its ordinary file tools, and the instructions in agent.md tell it how. Don't mistake a failed read for a quiet day If an MCP server is down or its token has expired, the run still starts, just without that server's tools. The session logs an error, but the agent sees nothing from that source and reports "nothing new." Three rules in agent.md help fix this. When a source fails, the agent will: keep the source’s bookmark where it is, write the brief from the other sources, and end the brief with one line naming what it couldn't read ("pull requests unavailable this run"), so the reader is made aware. DESTINATION Our template posts to one Slack channel, with a dated post each time it runs.

The agent posts to Slack using the bash tool in its sandbox, using the same bot token it reads with. Nothing has to approve the post. The agent sends it with a bash command, and the built-in bash tool runs without asking for approval by default. slack.com is also on the allowlist of the agent's environment, the sandbox it runs in. The post is one request: CODEShellcurl -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 ..."}' Confirm the post landed before recording it Once a post is confirmed, the agent updates its ledger of reported items and its bookmarks. If those records don't match what was actually posted, two things can go wrong. If the agent records a post that never landed, the bookmarks move on and those items are never reported. If it posts again because it isn't sure the first post landed, readers get the same brief twice. Three rules in agent.md prevent this. First, the agent looks for today's title in the channel's recent messages and doesn't post if the edition is already there. Second, the post counts as sent only if Slack returns "ok": true and a message ts. Third, the agent updates the ledger and bookmarks only after that confirmation. If the result is unclear, it marks the run "maybe posted" and changes nothing else, so nothing is lost. The agent keeps a run record in its memory store (runs/<date>.md). It marks the run "posting" before the post, then "posted" with the message ID, or "maybe posted." AGENT In Claude Managed Agents, an agent is a versioned configuration: a model, a system prompt, and tools. Each run follows its run steps and stops.

In our reference implementation, the agent configuration is agent.md: CODEMarkdown--- 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.] The frontmatter supplies the agent name, model, tools, and MCP servers. The body provides the agent instructions. MCP tools ask for approval by default and nobody is there to give it, so the GitHub toolset is set to always_allow and the GitHub token is read-only. Keep the brief short agent.md steers Claude toward brevity: CODEText4. 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. Re-check anything still open right before posting Items can change between when the agent reads sources and when it posts. Just before posting, agent.md instructs the agent to re-check the live status of each item: CODEText5. 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. SCHEDULE With Claude Managed Agents, the agent is only a configuration file; a deployment runs it. The deployment names the agent, environment, and the first message of each run. It also holds the schedule, vault, memory stores, and budget. Each time the schedule fires, the platform starts a fresh agent session.

In our template, the deployment is captured in deployment.md, with the first message as its body: CODEMarkdown--- 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>". This creates the deployment with the agent, environment and memory stores it names by path. CODEShellant apply deployment.md To test it without waiting for the schedule, start a run by hand with ant beta:deployments run --deployment-id <id>, using the ID from claude-lock.json. Compute dates in your time zone A common bug is the agent calling this morning "yesterday" because it computes dates in the server's time zone. In deployment.md, the timezone field sets when the run fires and the second line of the body tells the agent which zone to use for dates. MEMORY Each run starts in a fresh sandbox with no memory of the last one. Without memory, feedback doesn't stick. However, stale memory can confuse the agent: it reports an item as still waiting after it was resolved, or drops one that's still open because it was "already reported."

Our template keeps two memory stores, the folders mounted under /mnt/memory/ (see Sources):

preferences (yours, read-only to the agent): which channels and repos to read, what to leave out, the length cap, the destination, and when to stop.

state (the agent's, read-write): the bookmarks, a ledger of what it reported, one record per run, changes it proposes to your preferences, and notes on how each source behaves ("returns only the newest 50 items").

ant apply deployment.md creates the preferences store, but not the file in it. Before the first run, write your preferences.md there with the repo's scripts/seed-preferences.sh. Re-read your preferences at the start of every run A common problem occurs when a copy of the preferences is baked into the prompt, which keeps applying rules you've already changed. Have the agent read the file fresh every run. If it can't read the file, it should stop and say so instead of running on defaults. Keep a ledger of what you've already reported, and report the change The agent keeps a ledger, ledger.md, of every item it has reported, so the brief doesn't repeat itself. Each line records when the item was reported, where it came from, an ID that doesn't change (a Slack message timestamp or a pull request number), and its last known status: CODEText2026-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 GUARDRAILS Because our automation runs in the “background” on a schedule, we set limits on what the agent can do and what it can spend.

Limits on what it can do The agent reads messages and issues that other people wrote, and that text can be interpreted as instructions. Limit what the agent could do if it followed them. In our example, the GitHub token and the preferences store are read-only, and the environment only reaches the hosts on its allowlist. A planted instruction can still change what the brief says, including through the notes the agent keeps between runs. It can't write to GitHub or edit your rules. Slack is the exception: the same token posts, so invite the bot only where it needs to read or post. Set the spending cap from real runs A spending cap protects you from runaway costs. Start at three to five times the cost of a normal run, then tighten it as you see real numbers. A run that hits its cap pauses instead of failing, so a cap set too low looks like a brief that went quiet. The cap is the budget in deployment.md. Every run gets the full amount, and a run that reaches it pauses with a budget_reached stop reason: CODEYAMLbudget: type: limit max_list_cost: amount: "500" # a string, in cents: "500" is $5.00 currency: USD GETTING STARTED Our reference implementation comes down to six rules:

Read each source from a bookmark, not a fixed time window. Report a failed read as unreadable, never as a quiet day. Re-check every item right before posting. Count a post as sent only when Slack confirms it, then update bookmarks and ledger. Re-read your preferences every run, from a store the agent can't edit. Give the agent read-only access wherever it only reads, and cap what each run can spend.

Claude Code can walk you through the guidance provided in this article. First, update: CODEShellclaude update Then, use the claude-api skill: PROMPT/claude-api managed-agents-onboard https://claude.dev/blog/building-effective-agent-automations/ The claude-api skill reads this post, proposes a setup, writes the files to an agents/ folder in your project, and creates the resources with ant apply. Treat this as a starting point, and customize the agent for your sources, destination, or memory preferences.

原文入口

阅读原文(claude.dev)

原文将在新窗口打开。收录时间不是内容更新时间;正文、译文与解读的版权归原作者/来源所有,本站仅作个人阅读辅助并保留原文入口;页面时间均为北京时间。

作者/署名来自原文结构化字段(Atom/RSS/HTML meta/JSON-LD;GitHub release 显示的是发布者账号),未经模型补充。

了解来源批准与收录规则