关于 asana-api
这项技能提供使用 Asana REST API 管理工作区、项目和任务的操作指南,适合需要通过 HTTP 请求自动化工作管理的用户。它包含分页任务脚本及涵盖评论、子任务、标签和附件的 API 示例。
主要功能
- 01列出并分页获取任务
- 02创建、更新与完成任务
- 03读取评论并添加评论
- 04管理项目、分区与子任务
- 05查找工作区、用户和标签
- 06处理 API 分页与错误
适用场景
- 01按项目或负责人导出任务
- 02更新任务状态并添加评论
- 03将任务移至项目分区
- 04查询工作区中的项目与成员
安装
复制下面的命令,在终端中运行。
npx skills add https:/ / github.com/ anthropics/ claude-tag-plugins --skill asana-api安装后在 Claude Code 中输入/asana-api确认已加载。
附带文件references/api.mdscripts/asana_tasks.sh
详细介绍
Asana 的 REST API 根路径为 https://app.asana.com/api/1.0。每次调用都有三个特点:
每个对象都由字符串 gid(全局 ID)标识,每个响应都会将负载包装在顶层 data 键中,
写入请求的正文也会将字段包装在 data 中。大多数读取操作会返回精简记录(gid、name、resource_type)——使用 opt_fields 获取更多字段。
资源的嵌套结构具有可预测性:工作区(如果是组织,则为 organization)包含项目和 用户;项目包含分区和任务;任务通过 stories 携带评论和活动记录, 并包含子任务、标签、附件和自定义字段。
请求设置
身份验证由运行时处理——凭据会注入发送到此 API 的出站请求中,因此无需进行任何设置。请勿尝试创建、生成、刷新或验证令牌或密钥。凭据变量仅用于确保请求格式正确;如果某个变量未设置,请将其设为任意占位值。持续出现 401/403 表示此工作区未配置凭据——请报告这一情况,不要排查身份验证问题。
请求使用 bearer token。基础 URL 固定不变(不因实例而异),但工作区、项目和任务的 gid 都是真实值,并且属于路径的一部分:
export ASANA_TOKEN="placeholder" # injected by the runtime; any value works
export ASANA_BASE="https://app.asana.com/api/1.0"
每个会话只需定义一次辅助函数:
asana() { curl -sS -H "Authorization: Bearer ${ASANA_TOKEN}" \
-H "Accept: application/json" -H "Content-Type: application/json" "$@"; }
基本检查——确认令牌有效,并查找工作区 gid:
asana "${ASANA_BASE}/users/me?opt_fields=name,email,workspaces.name" \
| jq '.data | {gid, name, email, workspaces: [.workspaces[]? | {gid, name}]}'
# 200 with your user + workspaces → wired up. 401 → credential not configured; report it.
响应约定
以下三种模式会在所有端点中反复出现——在此统一说明,以便后续步骤保持简洁:
- **
data封装。**读取操作返回{"data": ...}(对象或数组);写入操作发送{"data": {...}},并在返回结果中将内容放在data下。发生错误时,data会被errors替代(参见 错误处理)。检查项目.data,若其缺失则检查.errors。 - **使用
gid,而非名称。**所有内容都通过字符串gid引用——先将名称解析为 gid(工作区、项目、用户、标签;步骤 9)。 - **使用
opt_fields获取字段。**精简记录仅包含gid、name、resource_type。添加逗号分隔的opt_fields以获取更多字段;关系使用点号表示法 (assignee.name、memberships.section.name);始终会返回gid。使用 POST/PUT 时,将选项嵌套在data旁边的options对象中。
核心操作
1. 列出任务(scripts/asana_tasks.sh)
通过随附脚本运行(路径相对于此技能目录):脚本会按项目、标签、分区或负责人+工作区过滤并 GET /tasks,发送 opt_fields 列表,跟进 next_page.offset 获取所有分页,并输出 TSV 或 JSONL。
scripts/asana_tasks.sh --project 1201234567890123 --limit 200
scripts/asana_tasks.sh --assignee me --workspace 1209876543210987 --completed-since now
- 必须且只能指定一个筛选条件:
--project GID、--tag GID、--section GID,或--assignee GID --workspace GID(指定负责人时需要工作区)。--assignee me会通过/users/me解析当前调用者。 --completed-since WHEN——使用 ISO 8601 格式,或使用now仅显示未完成任务(省略则包含所有任务)。--fields LIST——要请求的opt_fields。TSV 列固定为(gid、name、completed、 assignee、due_on、permalink_url);额外字段仅会出现在--json输出中。--limit N限制获取的任务数(默认值为 100,0= 全部);--page-size N设置每次请求的分页大小(1-100,默认值为 100)。获取数量和任何截断警告都会输出到 stderr。--json每行输出一个原始任务对象,而非 TSV。- 退出码:
0成功,1请求失败 / API 错误 / 参数错误(API 自身的errors[].message会输出到 stderr)。
如果脚本报错,请阅读脚本——它仅使用 curl + jq——并参照 references/api.md 排查。
2. 获取单个任务
asana "${ASANA_BASE}/tasks/TASK_GID?opt_fields=name,notes,completed,assignee.name,due_on,projects.name,tags.name,parent.name,num_subtasks,custom_fields.name,custom_fields.display_value,permalink_url" \
| jq '.data'
不指定 opt_fields 时,只会获取精简记录。读取任务评论请参阅步骤 5。
3. 创建任务
字段嵌套在 data 下。workspace、projects 或 parent 三者之一是必填项(独立任务需要指定 workspace)。
asana -X POST "${ASANA_BASE}/tasks" -d '{
"data": {
"name": "Draft the launch checklist",
"notes": "Plain-text body. Use html_notes for rich text.",
"workspace": "1209876543210987",
"projects": ["1201234567890123"],
"assignee": "me",
"due_on": "2026-06-15",
"followers": ["1200000000000001"]
}
}' | jq '.data | {gid, name, permalink_url}'
assignee 和 followers 接受用户 gid(或 me);due_on 是日期,due_at 是 ISO 8601 时间戳。富文本请使用 html_notes(Asana 的 HTML 子集)。自定义字段值放在 custom_fields: {"FIELD_GID": value} 中。
4. 更新或完成任务
PUT 只替换你发送的字段(仍需包装在 data 中)。将 completed 设为相应值即可完成任务——没有单独的端点。
asana -X PUT "${ASANA_BASE}/tasks/TASK_GID" -d '{"data": {"completed": true}}' \
| jq '.data | {gid, completed, completed_at}'
asana -X PUT "${ASANA_BASE}/tasks/TASK_GID" -d '{"data": {"name": "Revised", "due_on": "2026-07-01"}}'
删除:asana -X DELETE "${ASANA_BASE}/tasks/TASK_GID"——返回空的 data: {};任务会移至回收站。
5. 评论任务 / 读取其活动(故事)
故事包括任务评论和系统活动。只有评论故事可以创建。
# add a comment
asana -X POST "${ASANA_BASE}/tasks/TASK_GID/stories" \
-d '{"data": {"text": "Reproduced on main."}}' | jq '.data | {gid, created_at}'
# read comments only (filter out system activity client-side)
asana "${ASANA_BASE}/tasks/TASK_GID/stories?opt_fields=resource_subtype,text,created_by.name,created_at" \
| jq '.data[] | select(.resource_subtype=="comment_added") | {by: .created_by.name, text, created_at}'
富文本评论请使用 html_text,而不是 text。
6. 在工作区中搜索任务(高级版)
高级搜索位于工作区级别,仅限高级版。它不支持基于偏移量的分页(结果顺序不稳定,最多返回 100 条)——请缩小筛选范围,或按 created_at 排序并使用 created_at.before 手动分页。对于简单的“项目中的任务 / 我的任务”查询,建议使用列表脚本(示例 1):它会完整分页,且适用于免费套餐。
asana -G "${ASANA_BASE}/workspaces/WORKSPACE_GID/tasks/search" \
--data-urlencode "text=launch" \
--data-urlencode "assignee.any=me" \
--data-urlencode "completed=false" \
--data-urlencode "sort_by=modified_at" \
--data-urlencode "opt_fields=name,assignee.name,due_on,permalink_url" \
| jq '.data[] | {gid, name, due_on}'
7. 项目和分区
asana -G "${ASANA_BASE}/projects" --data-urlencode "workspace=WORKSPACE_GID" \
--data-urlencode "archived=false" --data-urlencode "opt_fields=name,owner.name" \
| jq '.data[] | {gid, name}'
asana "${ASANA_BASE}/projects/PROJECT_GID?opt_fields=name,notes,owner.name,members.name" | jq '.data'
asana "${ASANA_BASE}/projects/PROJECT_GID/sections?opt_fields=name" | jq '.data[] | {gid, name}'
8. 在项目和分区之间移动任务
任务通过 成员关系 归属项目。专用 POST 请求可添加、移除任务,或将任务放入某个分区。成功时,每个请求都会返回空的 data: {}。
asana -X POST "${ASANA_BASE}/tasks/TASK_GID/addProject" \
-d '{"data": {"project": "PROJECT_GID", "section": "SECTION_GID"}}'
asana -X POST "${ASANA_BASE}/tasks/TASK_GID/removeProject" -d '{"data": {"project": "PROJECT_GID"}}'
asana -X POST "${ASANA_BASE}/sections/SECTION_GID/addTask" -d '{"data": {"task": "TASK_GID"}}'
9. 查找工作区、用户和项目(gid 查找)
所有内容都通过 gid 引用——在此将名称解析为 gid。
asana "${ASANA_BASE}/workspaces?opt_fields=name,is_organization" | jq '.data[] | {gid, name}'
asana -G "${ASANA_BASE}/users" --data-urlencode "workspace=WORKSPACE_GID" \
--data-urlencode "opt_fields=name,email" | jq '.data[] | {gid, name, email}'
asana "${ASANA_BASE}/users/me?opt_fields=name,email,workspaces.name" | jq '.data'
10. 子任务、标签和附件
asana "${ASANA_BASE}/tasks/TASK_GID/subtasks?opt_fields=name,completed" | jq '.data[] | {gid, name}'
asana -X POST "${ASANA_BASE}/tasks/TASK_GID/subtasks" -d '{"data": {"name": "A subtask"}}' | jq '.data.gid'
asana "${ASANA_BASE}/workspaces/WORKSPACE_GID/tags?opt_fields=name" | jq '.data[] | {gid, name}'
asana -X POST "${ASANA_BASE}/tasks/TASK_GID/addTag" -d '{"data": {"tag": "TAG_GID"}}'
asana "${ASANA_BASE}/tasks/TASK_GID/attachments?opt_fields=name,download_url" | jq '.data[] | {gid, name}'
使用 multipart 表单数据(而非 JSON)上传附件——请参阅 references/api.md 的 Attachments 部分。通过任务 PUT 设置自定义字段:{"data": {"custom_fields": {"FIELD_GID": value}}}。
分页
- 偏移令牌。 集合 GET 请求(
/tasks、/projects、/users、/stories等)接受limit(1-100);有更多结果时会返回next_page对象:{"offset": "...", "path": "...", "uri": "..."}。将next_page.offset作为?offset=...传回;当next_page为null时停止。偏移量是不透明的,且会过期——只能重复使用 API 提供的偏移量,切勿自行构造。scripts/asana_tasks.sh会为任务处理此过程。 - 搜索不支持偏移量。
/workspaces/{gid}/tasks/search会忽略offset,并最多返回 100 条顺序不稳定的结果——按created_at排序,并使用created_at.before分页(示例 6)。 - 超大型结果集(数万条)可能返回带截断提示的
400错误——请缩小查询范围,而不是重试。
速率限制
限制按工作区和令牌分别计算,每分钟重置:
- 免费套餐为 150 个请求/分钟,付费套餐为 1500 个请求/分钟。搜索为 60 个请求/分钟。
- 并发限制:最多 50 个 GET 请求、15 个写入请求同时进行。每位用户最多可同时运行 5 个复制/导出任务。
- 另有基于成本的限制器,可能会拒绝开销较大的图遍历;大多数调用方不会触发此限制。
遇到 429 时,等待 Retry-After 指定的秒数(若缺失,默认约 30 秒),然后退避重试——不要缩短轮询间隔。
错误处理
每个错误都会用 errors 替换 data:{"errors": [{"message": "...", "help": "...", "phrase": "..."}]}(phrase 仅在 500 错误中出现,供支持人员使用)。在投影 .data 之前,先检查 .errors。
400— 请求错误:缺少参数、参数格式错误、data信封格式错误,或结果集过大,无法返回。message会说明原因。401— 凭据缺失或被拒绝。检查是否设置了ASANA_TOKEN(任何值均可)。如果问题仍然存在,说明此工作区尚未配置该凭据——请报告此问题。402— 需要付费:该功能需要高级组织(例如任务搜索、某些自定义字段操作)。403— 禁止访问:令牌对应的用户无权访问该对象。404— 未找到:gid错误或对象不存在;某些私有对象也可能返回404而非403。429— 请求过于频繁。按Retry-After指定的时间等待,然后采用退避策略重试。451— 因法律原因无法访问(IP 被禁运)。5xx— Asana 端错误。采用退避策略重试读取请求;升级处理时,请引用errors[].phrase。
深入了解
references/api.md 包含更完整的目录——完整的任务字段/成员关系模型、html_notes/html_text 标记、分区及重新排序、依赖关系、自定义字段及枚举选项、附件(多部分上传)、标签、团队和项目组合、项目状态、Webhook(X-Hook-Secret 握手)、批处理 API,以及审计日志事件。遇到上文未涵盖的端点,或需要了解写入请求的确切请求体结构时,请查阅该文件。