Community生产力与协作github.com

bluesmarties876/skills

Motion (usemotion.com) REST API 的完整客户端,覆盖任务、项目、重复任务、评论、自定义字段、用户、工作区、状态和日程等全部 27 个记录在案的端点,并提供一个 `raw` 逃生口(支持游标分页)用于处理未记录的内容。支持 X-API-Key 认证、游标分页、限流退避,且所有删除操作都需要显式确认标志。

skills 是什么?

该技能为 Motion (usemotion.com) REST API 提供了完整的客户端封装,涵盖任务、项目、重复任务、评论、自定义字段、用户、工作区、状态和日程等全部 27 个记录在案的端点。它支持 X-API-Key 认证,内置游标分页和限流退避机制,所有删除操作都要求显式确认标志以确保安全。此外,还提供了一个 `raw` 逃生口用于处理任何尚未记录的 API 端点。该技能适用于 Cursor、Claude Code 和 Codex 等 AI 代理平台,用户可通过简单的 CLI 命令与 Motion 进行交互。其设计理念是优先保障安全性和可靠性,包括防止游标查询无限循环(上限 100 页),以及对常见错误进行清晰、可操作的错误处理。

兼容平台~Claude Code~Codex CLI✓Cursor
npx skills add https://github.com/bluesmarties876/skills/tree/HEAD/api/motion-api

Installed? Explore more 生产力与协作 skills: steipete/gemini, steipete/gh-issues, steipete/skill-creator · View all 6 →

在你喜欢的 AI 中提问

打开一个已预加载此 Agent Skill 的新对话。

文档

Motion API

Motion (usemotion.com) REST API 的完整客户端,覆盖任务、项目、重复任务、评论、自定义字段、用户、工作区、状态和日程等全部 27 个记录在案的端点,并提供一个 raw 逃生口用于处理任何尚未记录的内容。

何时使用此技能

当工作涉及 Motion 时使用:读取或创建任务、列出项目、在任务上发布评论、管理重复任务,或读取工作区状态、用户和日程。

凭据

一个凭据:MOTION_API_KEY。当脚本通过 RunWithCredentials 运行时,平台会将其作为环境变量注入——切勿在命令行上传递密钥,也切勿打印或回显它。

在 Motion 的 设置 → API 中获取密钥。Motion 只显示一次,请立即复制。如果调用开始返回 401,说明密钥已被吊销或重新生成,需要替换。

注意:在代理模式凭据传递中,环境变量保存的是一个非秘密占位符,实际值会被注入到对 api.usemotion.com 的请求中。新保存的凭据可能需要几分钟才能传播;立即出现 401 但稍后成功是传播延迟,而不是密钥错误。

API 遵循的约定

以下事实决定了调用是成功还是失败。

项目值
基础 URLhttps://api.usemotion.com
认证头X-API-Key: <key>
健康检查GET /v1/users/me — 返回密钥的所有者
路径前缀除自定义字段外所有内容使用 /v1/,自定义字段使用 /beta/
速率限制12 次/分钟(个人),最高 120 次(团队),企业版更高
描述格式GitHub Flavored Markdown
优先级值ASAP、HIGH、MEDIUM、LOW(重复任务仅限 HIGH/MEDIUM)
截止日期类型HARD、SOFT、NONE(重复任务仅限 HARD/SOFT)

分页。 列表端点接受 cursor 参数并返回一个信封结构:

{ "meta": { "nextCursor": "…", "pageSize": 25 }, "tasks": [ … ] }

信封键是 meta,下一页字段是 nextCursor。在任何列表命令上传递 --all,脚本会自动跟踪游标,返回一个扁平数组。

--all 在100 页后停止并失败,因此失控的查询不会导致运行挂起——如果遇到此情况,请缩小查询范围。此外,如果某一页既不是 JSON 对象也不是数组(截断或网关错误页面),游标遍历会拒绝而不是返回已有内容:看起来完整的部分列表比错误更糟糕。

两个列表端点返回裸数组且没有分页——GET /v1/statuses 和 GET /beta/workspaces/{id}/custom-fields。其他所有端点都使用信封结构。

错误。 非 2xx 响应携带 {"message", "error", "statusCode"}。脚本会以 JSON 形式将其打印到 stderr 并以非零退出。429 会进行退避重试,并遵守 Retry-After 头;400、401、403 和 404 会立即显示且不会重试。验证失败会携带逐字段的 errors[] 数组;客户端会附加这些消息,因此实际原因可见。

User-Agent 是必需的。 Motion 的边缘网关会阻止默认的 Python-urllib/x.y 签名,并返回 Cloudflare 403 (browser_signature_banned),请求无法到达 API。客户端始终发送 motion-api-skill/1.0;如果你自己编写针对此 API 的请求,请显式设置 User-Agent,否则你将收到令人困惑的 403 而不是真实响应。

布尔查询参数必须是小写。 Motion 将查询字符串解析为文本,因此布尔过滤器必须是字面量 true,而不是 Python 的 True。弄错这一点不会导致静默无操作:API 会返回令人困惑的 400,并且消息会提及相反值(请参阅下面的实时差异部分)。客户端始终发送小写字面量。

命令参考

每个命令都会将 JSON 打印到 stdout。python3 motion.py <group> --help 列出所有标志。

任务

命令端点
tasks listGET /v1/tasks
tasks get <task_id>GET /v1/tasks/{id}
tasks createPOST /v1/tasks
tasks update <task_id>PATCH /v1/tasks/{id}
tasks move <task_id> --workspace-id …PATCH /v1/tasks/{id}/move
tasks delete <task_id> --yesDELETE /v1/tasks/{id}
tasks unassign <task_id> --yesDELETE /v1/tasks/{id}/assignee

tasks list 过滤器:--assignee-id、--project-id、--workspace-id、--name(不区分大小写的子字符串)、--label(单数,一个标签名称)、--status(可重复)、--include-all-statuses。--status 和 --include-all-statuses 是互斥的——同时发送会被 API 拒绝,CLI 会提前拒绝并显示该消息,而不是发送一个肯定会返回 400 的请求。

--include-all-statuses 是查看已移出工作区默认状态的任务(例如所有位于 Backlog 或 In Review 的任务)的方法;没有它,GET /v1/tasks 仅返回默认状态,列表看起来为空。将其与 --all 结合使用会返回分配给某人的所有任务,跨越所有状态。

tasks create / tasks update 接受相同的字段:--name、--workspace-id、--due-date(ISO 8601;计划任务必需)、--duration、--status、--project-id、--description、--priority、--label(可重复)、--assignee-id。

--duration 接受整数分钟数,或字符串 NONE / REMINDER(输入时不区分大小写,输出时规范化为大写)。

自动调度是三态的,区别很重要:

  • 省略两个标志 → 字段在请求中完全省略(不变)
  • --auto-scheduled '{"deadlineType":"HARD"}' → 开启自动调度;嵌套字段包括 startDate、deadlineType(HARD/SOFT/NONE)和 schedule(默认为 Work Hours)
  • --auto-scheduled-off → 发送显式的 null,关闭自动调度

任务的状态必须启用自动调度,否则 API 会拒绝。

任务响应的样子如下——已修剪为下方日历工作流所依赖的字段:

{
  "id": "tsk_123",
  "name": "Draft Q4 plan",
  "description": "Outline the three scenarios.",
  "status": { "name": "In Progress", "isResolvedStatus": false },
  "priority": "HIGH",
  "labels": ["q4"],
  "assignees": [{ "id": "usr_1", "name": "Sam Patel" }],
  "project": { "id": "prj_1", "name": "Planning" },
  "dueDate": "2026-11-01T17:00:00.000Z",
  "duration": 45,
  "scheduledStart": "2026-10-28T09:00:00.000Z",
  "startOn": "2026-10-28",
  "completedTime": null
}

解读:status 是一个对象而不是字符串——你需要的过滤器是 status.isResolvedStatus,任务完成或取消后该值变为 true。assignees 和 labels 是数组;project 是对象或 null。scheduledStart 和 dueDate 是 UTC 时间;startOn 是纯日期。

没有日历端点。 任务在日历上的位置是其 scheduledStart(UTC ISO 8601),duration 为分钟数,startOn 为纯日期。要回答“接下来是什么”,请获取任务并按 scheduledStart 排序——不要去寻找返回事件的日程端点,因为 schedules list 只返回工作时间窗口(见下文),而不是已预订的项目。过滤掉 status.isResolvedStatus 任务以排除任何已完成或已取消的任务。

项目

命令端点
projects list [--workspace-id …]GET /v1/projects
projects get <project_id>GET /v1/projects/{id}
projects create --name … --workspace-id …POST /v1/projects

projects create 还接受 --due-date、--description(接受 HTML)、--label(可重复)、--priority(服务器端默认为 MEDIUM),以及模板对 --project-definition-id + --stages。阶段必须与定义的数量和顺序完全匹配,否则 API 返回 400。对于较长的阶段数组,请使用 --stages @stages.json。CLI 不强制要求这对参数;API 会拒绝没有定义 ID 的阶段列表。

重复任务

命令端点
recurring-tasks list --workspace-id …GET /v1/recurring-tasks
recurring-tasks createPOST /v1/recurring-tasks
recurring-tasks delete <id> --yesDELETE /v1/recurring-tasks/{id}

recurring-tasks create 需要 --frequency、--name、--workspace-id 和 --assignee-id。可选:--deadline-type(仅限 HARD/SOFT——此处 NONE 被拒绝)、--duration(整数分钟或 REMINDER;此端点不接受 NONE)、--starting-on、--ideal-time(HH:mm)、--schedule(默认为 Work Hours)、--description、--priority(仅限 HIGH/MEDIUM)。

--starting-on 会完全按原样发送给 API——不进行修剪。

--frequency 是 Motion 自有 DSL 中的字符串,而不是对象。 这一点经常让人困惑。词汇表文档位于 https://docs.usemotion.com/cookbooks/frequency/:

  • 日期代码:MO、TU、WE、TH、FR、SA、SU
  • 每日:daily_every_day、daily_every_week_day、daily_specific_days_[MO, TU, FR]
  • 每周:weekly_any_day、weekly_any_week_day、weekly_specific_days_[MO, FR]
  • 双周:biweekly_first_week_any_day、biweekly_first_week_specific_days_[MO, TU]、biweekly_second_week_any_week_day
  • 按月按星期几:monthly_first_MO、monthly_second_TU、monthly_last_FR
  • 按月按日期:monthly_1、monthly_15、monthly_31(超出范围的日期回退到当月的最后一天)
  • 按月按周:monthly_any_day_first_week、monthly_any_week_day_last_week、monthly_last_day_of_month
  • 按季度:quarterly_first_day、quarterly_last_week_day、quarterly_any_day_first_week

日期数组必须始终与频率类型配对——单独的 [MO, FR] 无效。

一个完整的调用,因为频率字符串是困难部分:

python3 motion.py recurring-tasks create \
    --name "Weekly review" --workspace-id ws_1 --assignee-id usr_1 \
    --frequency "weekly_specific_days_[MO,FR]" \
    --deadline-type SOFT --duration 30 --ideal-time 16:00 \
    --schedule "Work Hours" --priority MEDIUM

注意这里更窄的集合:重复任务只接受 HIGH/MEDIUM 优先级和 HARD/SOFT 截止日期类型,而 API 的其他部分也允许 ASAP/LOW 和 NONE。CLI 强制执行这两项限制。

评论

命令端点
comments list --task-id …GET /v1/comments
comments create --task-id … [--content …]POST /v1/comments

--content 是 GitHub Flavored Markdown 格式,返回时是 HTML。它是可选的——没有 --content 时请求体只包含任务 ID。Motion 是否接受空评论未经核实;如果你想说什么,请传递 --content。

自定义字段——注意 /beta/ 前缀

命令端点
custom-fields list --workspace-id …GET /beta/workspaces/{workspaceId}/custom-fields
custom-fields create --workspace-id … --type … --name …POST /beta/workspaces/{workspaceId}/custom-fields
custom-fields delete <id> --workspace-id … --yesDELETE /beta/workspaces/{workspaceId}/custom-fields/{id}
custom-field-values add-task <task_id> …POST /beta/custom-field-values/task/{taskId}
custom-field-values add-project <project_id> …POST /beta/custom-field-values/project/{projectId}
custom-field-values delete-from-task <task_id> <value_id> --yesDELETE /beta/custom-field-values/task/{taskId}/custom-fields/{valueId}
custom-field-values delete-from-project <project_id> <value_id> --yesDELETE /beta/custom-field-values/project/{projectId}/custom-fields/{valueId}

12 种自定义字段类型,完全按原样拼写:text、url、date、person、multiPerson、phone、select、multiSelect、number、email、checkbox、relatedTo。

设置值需要 --custom-field-instance-id(工作区上的字段)、--type 和 --value。--value 是 JSON,因此请正确引用:--value '"hello"' 用于字符串,--value '42' 用于数字,--value '["A","B"]' 用于多选,--value 'true' 用于复选框。

python3 motion.py custom-field-values add-task tsk_123 \
    --custom-field-instance-id cfi_1 --type select --value '"Alpha"'

custom-fields create 接受 --metadata 作为 JSON——format(plain/formatted/percent,仅数字)、toggle 用于复选框,options 用于选择字段:

--metadata '{"options":[{"id":"a","value":"Alpha","color":"#ff0000"}]}'

用户、工作区、状态、日程

命令端点
meGET /v1/users/me
users list [--workspace-id …] [--team-id …]GET /v1/users
workspaces list [--ids …]GET /v1/workspaces
statuses list [--workspace-id …]GET /v1/statuses
schedules listGET /v1/schedules

workspaces list --ids 是可重复的,--all 会跟踪游标。

users list 必须限定范围。 传递 --workspace-id 或 --team-id;脚本会提前拒绝未限定范围的调用并显示该消息,而不是发送一个肯定会返回 400 的请求。要列出所有人,请遍历你的工作区。

schedules list 返回工作时间窗口,而不是事件。 每个日程都有自己的 timezone 和每日 {start, end} 块数组——且一天可能包含多个块(例如,包含早上和晚上的学校接送日程)。不要将其理解为“用户每天有一个工作块”,也不要将其视为日历;要查看实际预订了什么,请读取任务的 scheduledStart 值。

Raw 逃生口

python3 motion.py raw GET  /v1/tasks --query status=Todo --query status=Doing
python3 motion.py raw GET  /v1/tasks --query assigneeId=u1 --query includeAllStatuses=true --all
python3 motion.py raw POST /v1/comments --body '{"taskId":"t1","content":"hi"}'
python3 motion.py raw DELETE /v1/tasks/t1 --yes

对于任何命名命令未涵盖的内容,请使用此逃生口。--query KEY=VALUE 是可重复的,重复相同的键会发送多个值。--body 接受 JSON 字符串作为请求体。--all 遵循游标并聚合页面。--yes 抑制删除确认检查。

相关技能