adam-agent-folder

Compare original and translation side by side

🇺🇸

Original

English
🇨🇳

Translation

Chinese

Write an adam agent as a folder

将 adam Agent 编写为文件夹

An adam agent with no Rust is a folder of files that the
adam-agent
binary reads once at startup and serves over A2A. The binary ships inside the coder image (
ghcr.io/vymalo/another-adam-rs/coder
), so a deployment needs the image and the folder, no build.
Every adam-rs path below is in
vymalo/another-adam-rs
at the revision you pin (replace
main
by that revision). The reference is https://github.com/vymalo/another-adam-rs/blob/main/bin/adam-agent/README.md; read it at your rev before you rely on a detail here.
不含 Rust 的 adam Agent 是一个文件文件夹,
adam-agent
binary 会在启动时读取一次,并通过 A2A 提供服务。该 binary 随 coder 镜像一起分发(
ghcr.io/vymalo/another-adam-rs/coder
),因此部署只需要镜像和文件夹,无需构建。
下述所有 adam-rs 路径都位于
vymalo/another-adam-rs
仓库中你固定的 revision 对应的版本里(将
main
替换为该 revision)。参考文档位于 https://github.com/vymalo/another-adam-rs/blob/main/bin/adam-agent/README.md;在依赖本文任何细节之前,请先阅读你所用 revision 对应的文档。

When to use

何时使用

  • Adding an agent to a stack that already runs adam agents (a chat assistant, a researcher on a web-search MCP server, a reviewer).
  • Changing an agent's persona, card, tools list, skills, subagents or MCP servers.
  • Diagnosing a start that exits 78 or 69.
  • Not for an agent that needs its own Rust tools: that is
    adam-embed
    . Not for Docker Agent (cagent)
    agent.yaml
    : a different product with a different format.
  • 向已经运行 adam agents 的技术栈中添加 Agent,例如聊天助手、使用 web-search MCP server 的 researcher 或 reviewer。
  • 修改 Agent 的 persona、card、tools 列表、skills、subagents 或 MCP servers。
  • 排查启动时以 78 或 69 退出的问题。
  • 不适用于需要自有 Rust tools 的 Agent,此类 Agent 应使用
    adam-embed
    。也不适用于 Docker Agent(cagent)的
    agent.yaml
    ,后者是采用不同格式的另一种产品。

Procedure

操作步骤

  1. Create
    agent/instructions.md
    .
    The folder you point
    ADAM_AGENT_DIR
    at holds
    agent/
    (or is
    agent/
    itself) and exactly one agent: a folder with
    agents/
    of several is refused. Start from
    dev/agents/assistant/agent/instructions.md
    (a chat agent) or
    dev/agents/researcher/agent/
    (
    instructions.md
    plus
    mcp.json
    ) in the repository.
  2. Frontmatter, from the table in
    bin/adam-agent/README.md
    ("The agent folder"):
    • name
      : the registered name, which is the key of the agent's stored runs. Renaming it strands the runs of the old name. Two folders with the same
      name
      share their runs.
    • description
      (or
      card.description
      ): the A2A card needs one.
    • card:
      (
      name
      ,
      skills
      with
      id
      ,
      name
      ,
      description
      ,
      tags
      ,
      examples
      ),
      limits:
      (
      max_turns
      ,
      max_tool_calls
      ,
      max_output_tokens
      ,
      max_history_tokens
      ),
      model:
      (an alias, only when it should not be
      MODEL
      ),
      tools:
      (optional selection;
      linear__*
      takes a server's tools; an unknown name is refused with a suggestion).
    • vars:
      are the
      {{placeholders}}
      of the body. Every var needs a value in the file. A var declared without a value, a var the body does not use, or a placeholder not declared, stops the process at startup.
    • Secrets and endpoints never go in the file: the validator rejects
      api_key
      ,
      apiKey
      ,
      token
      ,
      secret
      ,
      password
      and
      base_url
      (
      docs/authoring.md
      , "File formats").
  3. Body: the system prompt. Optional
    skills/<name>/SKILL.md
    (Agent Skills format, loaded on demand by
    load_skill
    and
    read_skill_file
    ) and
    subagents/
    (each one tool of the parent, a child run with only the tools it lists and never
    ask_user
    ; registered as
    <name>/<subagent>
    ). Formats:
    docs/authoring.md
    .
  4. Built-in tools the agent has without writing any:
    ask_user
    ,
    show
    ,
    ui_catalog
    (
    crates/adam-ui/README.md
    ). Everything else comes from the folder, mainly MCP.
  5. MCP servers:
    agent/mcp.json
    with
    {"mcpServers": {...}}
    ; tools are named
    <server>__<tool>
    ,
    tools
    in a server entry is the allow-list. Credentials go in
    headers
    as
    ${VAR}
    (unset without default: exit 78 naming the variable). What kinds of server are allowed is the deployment's, not the file's:
    • MCP_ALLOW_STDIO=true
      for a local process (
      command
      ); the coder image sets none.
    • MCP_ALLOW_INSECURE=true
      for plain
      http
      to another machine (development only).
    • MCP_ALLOW_URL_VARS=true
      to allow
      ${VAR}
      inside a
      url
      .
    • type: sse
      is not supported.
  6. Make it readable by uid 10001 (the image's user) and mount it read-only. Run the image with the entrypoint overridden (the coder's entrypoint is
    adam-coder
    ):
    sh
    docker run --rm --entrypoint tini \
      -v "$PWD/my-agent/agent:/etc/adam/agent:ro" -e ADAM_AGENT_DIR=/etc/adam/agent \
      -e DATABASE_URL=... -e MODEL_BASE_URL=... -e MODEL_API_KEY=... -e MODEL=... \
      -e A2A_BEARER_TOKENS=... -e PUBLIC_URL=... -p 8080:8080 \
      ghcr.io/vymalo/another-adam-rs/coder:sha-<7> -- adam-agent
    Pin the image by
    sha-<7>
    tag and digest (
    adam-upgrade
    ).
    A2A_BEARER_TOKENS
    and
    PUBLIC_URL
    are required by roles that serve A2A (fail closed: no token, no server);
    MODEL_*
    by roles that run workers. All variables: "Configuration" in
    bin/adam-agent/README.md
    .
  7. In a compose stack, copy the service
    agent
    of
    compose.yaml
    in the repository (profile
    app
    : the folder mounted at
    /etc/adam/agent
    ,
    AGENT_FOLDER
    to choose it, port from
    AGENT_PORT
    , the coder's database). A new agent is a folder and about a dozen lines of that service.
  8. Edits apply at the next start (ADR 0004,
    docs/decisions/0004-agent-folders-at-run-time.md
    ): restart the service, no rebuild. There is no hot reload in release images.
  1. 创建
    agent/instructions.md
    。
    ADAM_AGENT_DIR
    指向的文件夹应包含
    agent/
    (也可以本身就是
    agent/
    ),且其中只能有一个 Agent;如果
    agents/
    下有多个 Agent,则会被拒绝。可以从仓库中的
    dev/agents/assistant/agent/instructions.md
    (聊天 Agent)或
    dev/agents/researcher/agent/
    (包含
    instructions.md
    和
    mcp.json
    )开始。
  2. Frontmatter:参考
    bin/adam-agent/README.md
    中“The agent folder”的表格:
    • name
      :注册名称,也是该 Agent 存储运行记录的键。重命名后,旧名称对应的运行记录将无法访问。两个具有相同
      name
      的文件夹会共享运行记录。
    • description
      (或
      card.description
      ):A2A card 必须包含此项。
    • card:
      (
      name
      ,以及包含
      id
      、
      name
      、
      description
      、
      tags
      、
      examples
      的
      skills
      )、
      limits:
      (
      max_turns
      、
      max_tool_calls
      、
      max_output_tokens
      、
      max_history_tokens
      )、
      model:
      (alias,仅当不应使用
      MODEL
      时设置)、
      tools:
      (可选的选择列表;
      linear__*
      表示采用某个 server 的 tools;未知名称会被拒绝并给出建议)。
    • vars:
      是正文中的
      {{placeholders}}
      。每个 var 都必须在文件中提供值。声明了 var 却未提供值、正文未使用该 var,或使用了未声明的 placeholder,都会导致进程在启动时停止。
    • Secrets 和 endpoints 绝不能写入文件:validator 会拒绝
      api_key
      、
      apiKey
      、
      token
      、
      secret
      、
      password
      和
      base_url
      。参见
      docs/authoring.md
      的“File formats”章节。
  3. 正文:即 system prompt。可选内容包括
    skills/<name>/SKILL.md
    (采用 Agent Skills 格式,由
    load_skill
    和
    read_skill_file
    按需加载)以及
    subagents/
    (每个 subagent 都是其 parent 的一项 tool;child run 只能使用列出的 tools,且绝不能使用
    ask_user
    ;注册名称为
    <name>/<subagent>
    )。格式参见
    docs/authoring.md
    。
  4. 内置 tools:无需编写任何内容,Agent 就具备
    ask_user
    、
    show
    和
    ui_catalog
    (参见
    crates/adam-ui/README.md
    )。其他所有 tools 均来自该文件夹,主要是 MCP。
  5. MCP servers:使用
    agent/mcp.json
    ,格式为
    {"mcpServers": {...}}
    ;tools 命名为
    <server>__<tool>
    ,server 条目中的
    tools
    是 allow-list。Credentials 应以
    ${VAR}
    形式放入
    headers
    (如果变量未设置且没有默认值,则以 78 退出并指出对应变量)。允许哪些类型的 server 由部署环境控制,而不是由文件控制:
    • 对本地进程(
      command
      )使用
      MCP_ALLOW_STDIO=true
      ;coder 镜像未设置此项。
    • 对其他机器使用普通
      http
      时使用
      MCP_ALLOW_INSECURE=true
      (仅限开发环境)。
    • 使用
      MCP_ALLOW_URL_VARS=true
      可允许在
      url
      中使用
      ${VAR}
      。
    • 不支持
      type: sse
      。
  6. 确保 uid 10001(镜像用户)具有读取权限,并以只读方式挂载。运行镜像时需要覆盖 entrypoint(coder 的 entrypoint 是
    adam-coder
    ):
    sh
    docker run --rm --entrypoint tini \
      -v "$PWD/my-agent/agent:/etc/adam/agent:ro" -e ADAM_AGENT_DIR=/etc/adam/agent \
      -e DATABASE_URL=... -e MODEL_BASE_URL=... -e MODEL_API_KEY=... -e MODEL=... \
      -e A2A_BEARER_TOKENS=... -e PUBLIC_URL=... -p 8080:8080 \
      ghcr.io/vymalo/another-adam-rs/coder:sha-<7> -- adam-agent
    使用
    sha-<7>
    tag 和 digest 固定镜像版本(
    adam-upgrade
    )。承担 A2A 服务角色的部署必须设置
    A2A_BEARER_TOKENS
    和
    PUBLIC_URL
    (采用 fail-closed 策略:没有 token 就不会启动 server);运行 workers 的角色必须设置
    MODEL_*
    。全部变量参见
    bin/adam-agent/README.md
    的“Configuration”章节。
  7. 在 compose 技术栈中,复制仓库
    compose.yaml
    中的
    agent
    service(使用
    app
    profile:文件夹挂载到
    /etc/adam/agent
    ,通过
    AGENT_FOLDER
    选择,通过
    AGENT_PORT
    设置端口,并使用 coder 的 database)。创建一个新 Agent 只需要一个文件夹和该 service 中约十几行配置。
  8. 修改会在下次启动时生效(ADR 0004,
    docs/decisions/0004-agent-folders-at-run-time.md
    ):重启 service 即可,无需重新构建。release 镜像不支持热重载。

Verify

验证

  • Exit codes: 78 is configuration (a missing
    ADAM_AGENT_DIR
    , a bad file, a
    vars
    mistake, an unset
    ${VAR}
    , a refused MCP policy); every finding is listed as
    path:line: error: ...
    in the one
    adam-agent failed
    log line. 69 is a dependency that is down (Postgres, an MCP server): a supervisor can restart until it is up.
  • Startup logs one
    agent files
    line (
    path
    ,
    digest
    ,
    agent
    ,
    warnings
    ) and each warning as
    path:line: warning: ...
    : read it to see which files run.
  • The card is public at the agent's URL and is the folder's; a call without a bearer token gets 401.
  • End to end in the repository's stack:
    sh dev/agent-e2e.sh
    (the card, "hi" answered in role, then a restart on an edited copy of the folder). The container smoke test is
    sh docker/coder/test/agent-smoke.sh <image>
    (
    AGENT_FOLDER
    names an
    agent/
    folder).
  • 退出码:78 表示配置错误(缺少
    ADAM_AGENT_DIR
    、文件错误、
    vars
    错误、未设置的
    ${VAR}
    、MCP 策略拒绝);所有问题都会以
    path:line: error: ...
    的形式列在一条
    adam-agent failed
    日志中。69 表示依赖服务不可用(Postgres 或 MCP server);supervisor 可以反复重启,直到依赖恢复。
  • 启动日志会输出一条
    agent files
    日志(包含
    path
    、
    digest
    、
    agent
    、
    warnings
    ),并以
    path:line: warning: ...
    的形式记录每条 warning;可据此确认实际运行了哪些文件。
  • Card 可通过 Agent 的 URL 公开访问,并对应文件夹中的 card;没有 bearer token 的调用会返回 401。
  • 在仓库技术栈中进行端到端验证:运行
    sh dev/agent-e2e.sh
    (检查 card,确认“hi”会按照对应 role 得到回答,然后使用修改后的文件夹副本重启)。容器 smoke test 为
    sh docker/coder/test/agent-smoke.sh <image>
    (
    AGENT_FOLDER
    指定一个
    agent/
    文件夹)。

Pitfalls

常见问题

  • ADAM_AGENT_DIR
    has no default and the binary has no embedded agent: unset is exit 78.
  • The folder's
    name
    is the key of the runs: a rename is a new agent with no history.
  • A subagent inherits nothing and, without
    tools:
    , has no tools (
    docs/authoring.md
    ).
  • ${VAR}
    in agent frontmatter does not exist; it is only for
    mcp.json
    .
  • One agent per process. Several agents share one database by running several processes with different folders (runs are scoped by the agent's name).
  • The coder image sets no
    MCP_ALLOW_STDIO
    , and has no extra interpreters for stdio MCP servers that need
    node
    or
    python
    .
  • A folder that follows the persona convention (the body opens with
    Your name is {{display_name}}.
    and a line
    In one sentence: <summary>.
    ) is greeted by the repository's mock models in role. A live model follows the whole prompt.
  • ADAM_AGENT_DIR
    没有默认值,且 binary 中未嵌入 Agent;未设置它会触发退出码 78。
  • 文件夹中的
    name
    是运行记录的键:重命名会创建一个没有历史记录的新 Agent。
  • Subagent 不会继承任何内容;如果没有
    tools:
    ,它将没有任何 tools(参见
    docs/authoring.md
    )。
  • Agent Frontmatter 中不存在
    ${VAR}
    ;该语法仅适用于
    mcp.json
    。
  • 每个进程只能运行一个 Agent。多个 Agent 可以通过使用不同文件夹运行多个进程来共享同一个 database(运行记录按 Agent 的
    name
    划分范围)。
  • coder 镜像未设置
    MCP_ALLOW_STDIO
    ,也没有为需要
    node
    或
    python
    的 stdio MCP servers 提供额外解释器。
  • 遵循 persona 约定的文件夹(正文以
    Your name is {{display_name}}.
    开头,并包含一行
    In one sentence: <summary>.
    )会被仓库中的 mock models 按照对应 role 问候。live model 则会遵循完整 prompt。

See also

参见