{/* 本页面由 website/scripts/generate-skill-docs.py 从技能 SKILL.md 自动生成。请编辑源 SKILL.md 而非本页面。 */}

Airtable

通过 curl 使用 Airtable REST API。支持记录 CRUD、筛选、upsert。

技能元数据

来源内置(默认安装)
路径skills/productivity/airtable
版本1.1.0
作者community
许可证MIT
平台linux, macos, windows
标签Airtable, Productivity, Database, API

参考:完整 SKILL.md

:::info 以下是此技能被触发时 Hermes 加载的完整技能定义。这是技能激活时代理所看到的指令。 :::

Airtable — 数据库、表与记录

使用 terminal 工具通过 curl 直接操作 Airtable 的 REST API。无需 MCP 服务器、OAuth 流程或 Python SDK——仅需 curl 和个人访问令牌(Personal Access Token)。

前提条件

  1. https://airtable.com/create/tokens 创建个人访问令牌(PAT)(令牌以 pat... 开头)。
  2. 授予以下权限(最低要求):
    • data.records:read — 读取行
    • data.records:write — 创建/更新/删除行
    • schema.bases:read — 列出 base 和 table
  3. 重要:在同一令牌 UI 中,将每个你想访问的 base 添加到令牌的访问列表中。PAT 按 base 划分作用域——权限不足的令牌在错误的 base 上会返回 403
  4. 将令牌存储在 ~/.hermes/.env(或通过 hermes setup):
    AIRTABLE_API_KEY=pat_your_token_here
    

注意:旧的 key... 格式 API 密钥已于 2024 年 2 月弃用。现在仅 PAT 和 OAuth 令牌可用。

API 基础

  • 端点: https://api.airtable.com/v0
  • 认证头: Authorization: Bearer $AIRTA...KEY
  • 所有请求 使用 JSON(任何 POST/PATCH/PUT 请求体使用 Content-Type: application/json)。
  • 对象 ID: base app...、table tbl...、记录 rec...、字段 fld...。ID 从不更改;名称可以。在自动化中优先使用 ID。
  • 速率限制: 每个 base 5 请求/秒。429 需要退避。单个 base 上的突发请求将受到限制。

基础 curl 模式:

curl -s "https://api.airtable.com/v0/$BASE_ID/$TABLE?maxRecords=5" \
  -H "Authorization: Bearer $AIRTA...KEY" | python3 -m json.tool

-s 抑制 curl 的进度条——保持此设置以使工具输出对 Hermes 保持整洁。通过 python3 -m json.tool(始终可用)或 jq(如果已安装)管道输出以获得可读的 JSON。

字段类型(请求体格式)

字段类型写入格式
单行文本"Name": "hello"
多行文本"Notes": "multi\nline"
数字"Score": 42
复选框"Done": true
单选"Status": "Todo"(除非 typecast: true,否则名称必须已存在)
多选"Tags": ["urgent", "bug"]
日期"Due": "2026-04-01"
日期时间(UTC)"At": "2026-04-01T14:30:00.000Z"
URL/邮箱/电话"Link": "https://…"
附件"Files": [{"url": "https://…"}](Airtable 获取并重新托管)
关联记录"Owner": ["recXXXXXXXXXXXXXX"](记录 ID 数组)
用户"AssignedTo": {"id": "usrXXXXXXXXXXXXXX"}

在创建/更新请求体顶层传递 "typecast": true 可让 Airtable 自动转换值(例如动态创建新的选择选项,将 "42" 转换为 42)。

常用查询

列出令牌可访问的 base

curl -s "https://api.airtable.com/v0/meta/bases" \
  -H "Authorization: Bearer $AIRTA...KEY" | python3 -m json.tool

列出 base 的表和架构

curl -s "https://api.airtable.com/v0/meta/bases/$BASE_ID/tables" \
  -H "Authorization: Bearer $AIRTA...KEY" | python3 -m json.tool

在变更操作之前务必执行此步骤——确认确切的字段名称和 ID,获取选择字段的 options.choices,并显示主字段名称。

列出记录(前 10 条)

curl -s "https://api.airtable.com/v0/$BASE_ID/$TABLE?maxRecords=10" \
  -H "Authorization: Bearer $AIRTA...KEY" | python3 -m json.tool

获取单条记录

curl -s "https://api.airtable.com/v0/$BASE_ID/$TABLE/$RECORD_ID" \
  -H "Authorization: Bearer $AIRTA...KEY" | python3 -m json.tool

筛选记录(filterByFormula)

Airtable 公式必须进行 URL 编码。让 Python 标准库完成——切勿手动编码:

FORMULA="{Status}='Todo'"
ENC=$(python3 -c 'import sys, urllib.parse; print(urllib.parse.quote(sys.argv[1], safe=""))' "$FORMULA")
curl -s "https://api.airtable.com/v0/$BASE_ID/$TABLE?filterByFormula=$ENC&maxRecords=20" \
  -H "Authorization: Bearer $AIRTA...KEY" | python3 -m json.tool

常用公式模式:

  • 精确匹配:{Email}='user@example.com'
  • 包含:FIND('bug', LOWER({Title}))
  • 多条件:AND({Status}='Todo', {Priority}='High')
  • 或:OR({Owner}='alice', {Owner}='bob')
  • 非空:NOT({Assignee}='')
  • 日期比较:IS_AFTER({Due}, TODAY())

排序和选择特定字段

curl -s "https://api.airtable.com/v0/$BASE_ID/$TABLE?sort%5B0%5D%5Bfield%5D=Priority&sort%5B0%5D%5Bdirection%5D=asc&fields%5B%5D=Name&fields%5B%5D=Status" \
  -H "Authorization: Bearer $AIRTA...KEY" | python3 -m json.tool

查询参数中的方括号必须进行 URL 编码(%5B / %5D)。

使用命名视图

curl -s "https://api.airtable.com/v0/$BASE_ID/$TABLE?view=Grid%20view&maxRecords=50" \
  -H "Authorization: Bearer $AIRTA...KEY" | python3 -m json.tool

视图在服务端应用其保存的筛选和排序。

常用变更操作

创建记录

curl -s -X POST "https://api.airtable.com/v0/$BASE_ID/$TABLE" \
  -H "Authorization: Bearer $AIRTA...KEY" \
  -H "Content-Type: application/json" \
  -d '{"fields":{"Name":"New task","Status":"Todo","Priority":"High"}}' | python3 -m json.tool

单次调用创建最多 10 条记录

curl -s -X POST "https://api.airtable.com/v0/$BASE_ID/$TABLE" \
  -H "Authorization: Bearer $AIRTA...KEY" \
  -H "Content-Type: application/json" \
  -d '{
    "typecast": true,
    "records": [
      {"fields": {"Name": "Task A", "Status": "Todo"}},
      {"fields": {"Name": "Task B", "Status": "In progress"}}
    ]
  }' | python3 -m json.tool

批量端点限制为每次请求最多 10 条记录。对于大量插入,以 10 条为一组循环并短暂休眠以遵守 5 请求/秒/base 的限制。

更新记录(PATCH——合并,保留未更改字段)

curl -s -X PATCH "https://api.airtable.com/v0/$BASE_ID/$TABLE/$RECORD_ID" \
  -H "Authorization: Bearer $AIRTA...KEY" \
  -H "Content-Type: application/json" \
  -d '{"fields":{"Status":"Done"}}' | python3 -m json.tool

按合并字段 Upsert(无需 ID)

curl -s -X PATCH "https://api.airtable.com/v0/$BASE_ID/$TABLE" \
  -H "Authorization: Bearer $AIRTA...KEY" \
  -H "Content-Type: application/json" \
  -d '{
    "performUpsert": {"fieldsToMergeOn": ["Email"]},
    "records": [
      {"fields": {"Email": "user@example.com", "Status": "Active"}}
    ]
  }' | python3 -m json.tool

performUpsert 会创建合并字段值为新值的记录,并修补合并字段值已存在的记录。非常适合幂等同步。

删除记录

curl -s -X DELETE "https://api.airtable.com/v0/$BASE_ID/$TABLE/$RECORD_ID" \
  -H "Authorization: Bearer $AIRTA...KEY" | python3 -m json.tool

单次调用删除最多 10 条记录

curl -s -X DELETE "https://api.airtable.com/v0/$BASE_ID/$TABLE?records%5B%5D=rec1&records%5B%5D=rec2" \
  -H "Authorization: Bearer $AIRTA...KEY" | python3 -m json.tool

分页

列表端点每次最多返回 100 条记录。如果响应包含 "offset": "...",将其传回下一个请求。循环直到该字段消失:

OFFSET=""
while :; do
  URL="https://api.airtable.com/v0/$BASE_ID/$TABLE?pageSize=100"
  [ -n "$OFFSET" ] && URL="$URL&offset=$OFFSET"
  RESP=$(curl -s "$URL" -H "Authorization: Bearer $AIRTA...EY")
  echo "$RESP" | python3 -c 'import json,sys; d=json.load(sys.stdin); [print(r["id"], r["fields"].get("Name","")) for r in d["records"]]'
  OFFSET=$(echo "$RESP" | python3 -c 'import json,sys; d=json.load(sys.stdin); print(d.get("offset",""))')
  [ -z "$OFFSET" ] && break
done

典型 Hermes 工作流程

  1. 确认认证。 curl -s -o /dev/null -w "%{http_code}\n" https://api.airtable.com/v0/meta/bases -H "Authorization: Bearer $AIRTA...EY" — 期望 200
  2. 找到 base。 列出 base(如上步骤)或如果令牌缺少 schema.bases:read 权限,直接向用户询问 app... ID。
  3. 检查架构。 GET /v0/meta/bases/$BASE_ID/tables — 在变更任何内容之前,在会话中缓存确切的字段名称和主字段名称。
  4. 先读后写。 对于”更新满足条件 X 的 Y”,先使用 filterByFormula 解析 rec... ID,然后使用 PATCH /v0/$BASE_ID/$TABLE/$RECORD_ID。切勿猜测记录 ID。
  5. 批量写入。 将相关的创建操作合并为一次 10 条记录的 POST,以保持在 5 请求/秒的配额内。
  6. 破坏性操作。 删除操作无法通过 API 撤销。如果用户说”删除所有 X”,请先回显筛选条件和记录计数,确认后再执行。

注意事项

  • filterByFormula 必须进行 URL 编码。 包含空格或非 ASCII 字符的字段名也需要编码({My Field}%7BMy%20Field%7D)。使用 Python 标准库(上述模式)——切勿手动转义。
  • 空字段会从响应中省略。 缺少 "Assignee" 键并不意味着该字段不存在——只是该记录的值为空。在断定字段缺失之前,请先检查架构(步骤 3)。
  • PATCH vs PUT。 PATCH 将提供的字段合并到记录中。PUT 完全替换记录并清除你未包含的任何字段。默认使用 PATCH
  • 单选选项必须存在。 写入 "Status": "Shipping"Shipping 不在字段的选项列表中时,除非传递 "typecast": true(会自动创建该选项),否则会报 INVALID_MULTIPLE_CHOICE_OPTIONS 错误。
  • 基于 base 的令牌作用域。 如果一个 base 返回 403 而另一个正常,说明令牌的访问列表不包含该 base——这不是作用域或认证问题。让用户访问 https://airtable.com/create/tokens 进行授权。
  • 速率限制是基于 base 而非基于令牌的。 baseA 每秒 5 请求且 baseB 每秒 5 请求没问题;仅 baseA 每秒 6 请求就会触发限流。在 429 响应中监控 Retry-After 头。

Hermes 的重要提示

  • 始终使用带有 curlterminal 工具。 不要使用 web_extract(它无法发送认证头)或 browser_navigate(需要 UI 认证且速度慢)。
  • AIRTABLE_API_KEY 会在加载此技能时自动从 ~/.hermes/.env 流入子进程——无需在每次 curl 调用前重新导出。
  • 在公式中小心转义花括号。 在 heredoc 体中,{Status} 是字面量。在 shell 参数中,{Status}{...} 大括号展开上下文之外是安全的——但在拼接到 URL 之前,请通过 python3 urllib.parse.quote 传递动态字符串。
  • 使用 python3 -m json.tool(始终可用)而非 jq(可选)进行美化打印。 仅在需要筛选/投影时才使用 jq
  • 分页是按页而非全局的。 Airtable 的 100 条记录上限是硬限制;无法提高。使用 offset 循环直到该字段消失。
  • 阅读非 2xx 响应中的 errors 数组——Airtable 返回结构化的错误代码,如 AUTHENTICATION_REQUIREDINVALID_PERMISSIONSMODEL_ID_NOT_FOUNDINVALID_MULTIPLE_CHOICE_OPTIONS,精确告诉你问题所在。