bluesmarties876/skills

Cliente completo para a API REST do Motion (usemotion.com) — todos os 27 endpoints documentados para tarefas, projetos, tarefas recorrentes, comentários, campos personalizados, usuários, espaços de trabalho, status e agendas, além de uma rota de escape 'raw' (com paginação por cursor) para qualquer coisa não documentada. Gerencia autenticação via X-API-Key, paginação por cursor, backoff de limite de taxa e protege cada exclusão com uma flag explícita de confirmação.

O que é skills?

Esta skill implementa um cliente completo para a API REST do Motion (usemotion.com), cobrindo todos os 27 endpoints documentados para recursos como tarefas, projetos, tarefas recorrentes, comentários, campos personalizados, usuários, espaços de trabalho, status e agendas. Ela também oferece um comando 'raw' como rota de escape para endpoints ainda não documentados, com suporte a paginação por cursor. A skill gerencia automaticamente a autenticação via cabeçalho X-API-Key, implementa backoff para limites de taxa (rate limiting) e exige uma flag explícita '--yes' para todas as operações de exclusão, prevenindo exclusões acidentais. Ela é útil para qualquer fluxo de trabalho que envolva o Motion, como criar tarefas, listar projetos, adicionar comentários, gerenciar tarefas recorrentes ou consultar status e usuários. A skill é compatível com plataformas como Claude Code, Cursor e Codex, usando a credencial 'MOTION_API_KEY' injetada como variável de ambiente.

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

Installed? Explore more Produtividade e Colaboração skills: steipete/gemini, steipete/gh-issues, steipete/skill-creator · View all 6 →

Perguntar na sua IA favorita

Abre um novo chat com esta habilidade de agente já pré-carregada.

Documentação

API do Motion

Cliente completo para a API REST do Motion (usemotion.com) — todos os 27 endpoints documentados para tarefas, projetos, tarefas recorrentes, comentários, campos personalizados, usuários, espaços de trabalho, status e agendas, além de uma rota de escape raw para qualquer coisa ainda não documentada.

Quando usar esta skill

Use-a sempre que o trabalho envolver o Motion: ler ou criar tarefas, listar projetos, postar comentários em tarefas, gerenciar tarefas recorrentes ou consultar status do espaço de trabalho, usuários e agendas.

Credenciais

Uma credencial, MOTION_API_KEY. A plataforma a injeta como uma variável de ambiente quando um script é executado via RunWithCredentials — nunca passe uma chave na linha de comando e nunca a imprima ou exiba.

Obtenha uma chave no Motion em Configurações → API. O Motion a exibe apenas uma vez, então copie-a imediatamente. Se as chamadas começarem a retornar 401, a chave foi revogada ou regenerada e precisa ser substituída.

Nota: com a entrega de credencial em modo proxy, a variável de ambiente contém um espaço reservado não secreto e o valor real é injetado nas requisições para api.usemotion.com. Uma credencial recém-salva pode levar alguns minutos para propagar; um 401 imediato que depois dá certo é propagação, não chave inválida.

Convenções que a API segue

Estes são os fatos que fazem a diferença entre uma chamada que funciona e uma que não funciona.

CoisaValor
URL Basehttps://api.usemotion.com
Cabeçalho de AuthX-API-Key: <chave>
Health checkGET /v1/users/me — retorna o proprietário da chave
Prefixos de caminho/v1/ para tudo, exceto campos personalizados, que são /beta/
Limites de taxa12 requisições/min (individual), até 120 (equipes), mais alto no enterprise
DescriçõesGithub Flavored Markdown
Valores de prioridadeASAP, HIGH, MEDIUM, LOW (tarefas recorrentes: apenas HIGH/MEDIUM)
Tipos de prazoHARD, SOFT, NONE (tarefas recorrentes: apenas HARD/SOFT)

Paginação. Endpoints de lista recebem um cursor e retornam um envelope:

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

A chave do envelope é meta, e o campo da próxima página é nextCursor. Passe --all em qualquer comando de lista e o script segue o cursor para você, retornando um único array achatado.

--all para em 100 páginas e então falha, para que uma consulta descontrolada não possa travar uma execução — restrinja a consulta se você vir isso. E se uma página não for nem um objeto JSON nem um array (truncada ou uma página de erro de gateway), a caminhada recusa em vez de retornar o que tem: uma lista parcial que parece completa é pior do que um erro.

Dois endpoints de lista retornam um array simples sem paginação — GET /v1/statuses e GET /beta/workspaces/{id}/custom-fields. Todo o resto é envelopado.

Erros. Respostas não-2xx carregam {"message", "error", "statusCode"}. Os scripts imprimem isso como JSON no stderr e saem com código diferente de zero. 429 é repetido com backoff respeitando Retry-After; 400, 401, 403 e 404 são exibidos imediatamente e nunca repetidos. Falhas de validação carregam um array errors[] por campo; o cliente anexa essas mensagens para que o motivo real fique visível.

Um User-Agent é obrigatório. O edge do Motion bloqueia a assinatura padrão Python-urllib/x.y com um Cloudflare 403 (browser_signature_banned) antes que a requisição chegue à API. O cliente sempre envia motion-api-skill/1.0; se você escrever sua própria requisição contra esta API, defina um User-Agent explicitamente ou você receberá um 403 confuso em vez de uma resposta real.

Parâmetros de consulta booleanos devem estar em minúsculas. O Motion analisa strings de consulta como texto, então um filtro booleano deve ser o literal true, não o True do Python. Errar isso não é um no-op silencioso: a API responde com um 400 confuso que fala sobre o valor oposto (veja a seção de diferenças reais abaixo). O cliente sempre envia literais minúsculos.

Referência de comandos

Cada comando imprime JSON no stdout. python3 motion.py <grupo> --help lista as flags.

Tarefas

ComandoEndpoint
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

Filtros de tasks list: --assignee-id, --project-id, --workspace-id, --name (substring sem diferenciar maiúsculas/minúsculas), --label (singular, um nome de rótulo), --status (repetível), --include-all-statuses. --status e --include-all-statuses são mutuamente exclusivos — enviar ambos é rejeitado pela API, e a CLI recusa antecipadamente com essa mensagem em vez de gastar uma requisição em um 400 garantido.

--include-all-statuses é a maneira de ver uma tarefa que passou do padrão do espaço de trabalho (por exemplo, tudo que está em Backlog ou Em Revisão); sem ele, GET /v1/tasks retorna apenas o status padrão e a lista parece vazia. Combiná-lo com --all retorna todas as tarefas atribuídas a alguém, em todos os status.

tasks create / tasks update aceitam os mesmos campos: --name, --workspace-id, --due-date (ISO 8601; obrigatório para tarefas agendadas), --duration, --status, --project-id, --description, --priority, --label (repetível), --assignee-id.

--duration aceita um número inteiro de minutos ou as strings NONE / REMINDER (sem diferenciar maiúsculas/minúsculas na entrada, normalizado para maiúsculas).

O auto-agendamento é triestado, e a distinção é importante:

  • omitir ambas as flags → o campo é deixado de fora da requisição completamente (inalterado)
  • --auto-scheduled '{"deadlineType":"HARD"}' → ativa **-**o; campos aninhados são startDate, deadlineType (HARD/SOFT/NONE) e schedule (padrão Work Hours)
  • --auto-scheduled-off → envia um null explícito, desativando-o

O status da tarefa deve ter auto-agendamento ativado, ou a API recusa.

Uma resposta de tarefa se parece com isto — reduzida aos campos dos quais o fluxo de trabalho de calendário abaixo depende:

{
  "id": "tsk_123",
  "name": "Rascunhar plano Q4",
  "description": "Esboçar os três cenários.",
  "status": { "name": "Em Andamento", "isResolvedStatus": false },
  "priority": "HIGH",
  "labels": ["q4"],
  "assignees": [{ "id": "usr_1", "name": "Sam Patel" }],
  "project": { "id": "prj_1", "name": "Planejamento" },
  "dueDate": "2026-11-01T17:00:00.000Z",
  "duration": 45,
  "scheduledStart": "2026-10-28T09:00:00.000Z",
  "startOn": "2026-10-28",
  "completedTime": null
}

Leia como: status é um objeto, não uma string — o filtro que você quer é status.isResolvedStatus, que se torna true quando uma tarefa é concluída ou cancelada. assignees e labels são arrays; project é um objeto ou null. scheduledStart e dueDate estão em UTC; startOn é uma data simples.

Não há endpoint de calendário. A posição de uma tarefa no calendário é seu scheduledStart (UTC ISO 8601), com duration em minutos e startOn como a data simples. Para responder "o que vem a seguir", busque as tarefas e ordene por scheduledStart — não vá procurar um endpoint de agenda que retorne eventos, porque schedules list retorna apenas as janelas de horário comercial (veja abaixo), não os itens agendados. Filtre tarefas com status.isResolvedStatus para excluir qualquer coisa já concluída ou cancelada.

Projetos

ComandoEndpoint
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 também aceita --due-date, --description (HTML é aceito), --label (repetível), --priority (padrão é MEDIUM no servidor) e o par de modelo --project-definition-id + --stages. Os estágios devem corresponder exatamente à ordem e quantidade da definição, ou a API retorna 400. Para arrays longos de estágios, use --stages @stages.json. A CLI não impõe o par; a API rejeita uma lista de estágios sem um id de definição.

Tarefas recorrentes

ComandoEndpoint
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 requer --frequency, --name, --workspace-id e --assignee-id. Opcionais: --deadline-type (apenas HARD/SOFT — NONE é rejeitado aqui), --duration (minutos como um número inteiro, ou REMINDER; NONE não é aceito neste endpoint), --starting-on, --ideal-time (HH:mm), --schedule (padrão Work Hours), --description, --priority (apenas HIGH/MEDIUM).

--starting-on é enviado para a API exatamente como fornecido — sem cortes.

--frequency é uma string no próprio DSL do Motion, não um objeto. Isso pega as pessoas de surpresa. O vocabulário está documentado em https://docs.usemotion.com/cookbooks/frequency/:

  • Códigos de dia: MO, TU, WE, TH, FR, SA, SU
  • Diário: daily_every_day, daily_every_week_day, daily_specific_days_[MO, TU, FR]
  • Semanal: weekly_any_day, weekly_any_week_day, weekly_specific_days_[MO, FR]
  • Quinzenal: biweekly_first_week_any_day, biweekly_first_week_specific_days_[MO, TU], biweekly_second_week_any_week_day
  • Mensal por dia da semana: monthly_first_MO, monthly_second_TU, monthly_last_FR
  • Mensal por data: monthly_1, monthly_15, monthly_31 (um dia fora do intervalo cai no último dia do mês)
  • Mensal por semana: monthly_any_day_first_week, monthly_any_week_day_last_week, monthly_last_day_of_month
  • Trimestral: quarterly_first_day, quarterly_last_week_day, quarterly_any_day_first_week

Um array de dias deve sempre ser pareado com um tipo de frequência — [MO, FR] sozinho não é válido.

Uma chamada completa, já que a string de frequência é a parte difícil:

python3 motion.py recurring-tasks create \
    --name "Revisão semanal" --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

Observe os conjuntos mais restritos aqui: tarefas recorrentes aceitam apenas prioridade HIGH/MEDIUM e apenas tipos de prazo HARD/SOFT, enquanto o resto da API também permite ASAP/LOW e NONE. A CLI impõe ambos.

Comentários

ComandoEndpoint
comments list --task-id …GET /v1/comments
comments create --task-id … [--content …]POST /v1/comments

--content é Github Flavored Markdown na entrada e retorna como HTML. É opcional — sem --content o corpo da requisição carrega apenas o id da tarefa. Se o Motion aceita um comentário vazio não é verificado; passe --content quando você quiser dizer algo.

Campos personalizados — observe o prefixo /beta/

ComandoEndpoint
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}

Os 12 tipos de campo personalizado, exatamente como escritos: text, url, date, person, multiPerson, phone, select, multiSelect, number, email, checkbox, relatedTo.

Definir um valor precisa de --custom-field-instance-id (o campo no espaço de trabalho), --type, e --value. --value é JSON, então cite-o corretamente: --value '"olá"' para uma string, --value '42' para um número, --value '["A","B"]' para uma seleção múltipla, --value 'true' para uma caixa de seleção.

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

custom-fields create aceita --metadata como JSON — format (plain/formatted/percent, apenas números), toggle para caixas de seleção e options para campos de seleção:

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

Usuários, espaços de trabalho, status, agendas

ComandoEndpoint
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 é repetível, e --all segue o cursor.

users list deve ser escopado. Passe --workspace-id ou --team-id; o script recusa uma chamada sem escopo antecipadamente com essa mensagem em vez de gastar uma requisição no 400 que a API retorna. Para listar todos, itere sobre seus espaços de trabalho.

schedules list retorna janelas de horário comercial, não eventos. Cada agenda tem seu próprio timezone e um array por dia de blocos {start, end} — e um dia pode conter múltiplos blocos (por exemplo, uma agenda de transporte escolar com um bloco matinal e outro noturno). Não leia isso como "o usuário tem um bloco de trabalho por dia", e não trate como o calendário; para o que está realmente agendado, leia os valores scheduledStart das tarefas.

Rota de escape 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":"oi"}'
python3 motion.py raw DELETE /v1/tasks/t1 --yes

Use isso para qualquer coisa que os comandos nomeados não cobrem. --query CHAVE=VALOR é repetível e repetir a

…

[truncado para tradução]

Habilidades Relacionadas