Skill: l-u-c-k-y/asana-pat (version 0.2.0)

--- name: asana description: "Manage Asana tasks, projects, briefs, status updates, custom fields, dependencies, attachments, events, and timelines via Personal Access Token (PAT)." homepage: https://developers.asana.com/docs/personal-access-token user-invocable: true metadata: {"openclaw":{"requires":{"env":["ASANA_PAT"]},"primaryEnv":"ASANA_PAT","homepage":"https://developers.asana.com/docs/personal-access-token"}} --- # Asana This skill provides a dependency-free Node.js CLI that calls the Asana REST API (v1) using a **Personal Access Token (PAT)**. - Script: `{baseDir}/scripts/asana.mjs` - Auth: `ASANA_PAT` (preferred) or `ASANA_TOKEN` - Output: **JSON only** (stdout), suitable for agents and automation ## Setup 1. Create an Asana PAT in your Asana account (Developer Console is **not** required for PAT usage). 2. Provide the token to OpenClaw/Clawdbot as `ASANA_PAT`. ### Common injection patterns - Shell env (local testing): `export ASANA_PAT="..."` - OpenClaw config (recommended): set `skills.entries.asana.apiKey` (or `env.ASANA_PAT`) so the secret is injected only for the agent run. ### Configure via OpenClaw CLI (recommended) This is the safest way to set the PAT because it keeps secrets out of prompts and ad-hoc shell history. **Recommended (apiKey → ASANA_PAT):** ```bash openclaw config set skills.entries.asana.enabled true openclaw config set skills.entries.asana.apiKey "ASANA_PAT_HERE" ``` `skills.entries.asana.apiKey` is a convenience field: for skills that declare `metadata.openclaw.primaryEnv`, OpenClaw injects `apiKey` into that env var for the agent run (this skill’s primary env is `ASANA_PAT`). **Alternative (explicit env):** ```bash openclaw config set skills.entries.asana.enabled true openclaw config set skills.entries.asana.env.ASANA_PAT "ASANA_PAT_HERE" ``` **Verify what is stored:** ```bash openclaw config get skills.entries.asana openclaw config get skills.entries.asana.enabled openclaw config get skills.entries.asana.apiKey ``` **Remove a stored token:** ```bash openclaw config unset skills.entries.asana.apiKey # or openclaw config unset skills.entries.asana.env.ASANA_PAT ``` #### Important: sandboxed runs When a session is sandboxed, skill processes run inside Docker and do **not** inherit the host environment. In that case, `skills.entries.*.env/apiKey` applies to host runs only. Set Docker env via: - `agents.defaults.sandbox.docker.env` (or per-agent `agents.list[].sandbox.docker.env`) - or bake the env into your sandbox image ## First calls (sanity + discovery) - Who am I: `node {baseDir}/scripts/asana.mjs me` - List workspaces: `node {baseDir}/scripts/asana.mjs workspaces` - (Recommended) Set a default workspace once: `node {baseDir}/scripts/asana.mjs set-default-workspace --workspace <workspace_gid>` ## ID resolution When the user provides names (project/task/user), resolve to GIDs using one of: - `typeahead --workspace <gid> --resource_type project|task|user --query "..."` (fast, best default) - `projects --workspace <gid> --all` (enumerate) - `users --workspace <gid> --all` (enumerate) Avoid guessing a GID when multiple matches exist. ## Core: tasks ### List tasks assigned to a user (personal productivity) `node {baseDir}/scripts/asana.mjs tasks-assigned --assignee me --workspace <workspace_gid> --all` ### List tasks in a project `node {baseDir}/scripts/asana.mjs tasks-in-project --project <project_gid> --all` ### Search tasks (Advanced Search API) Canonical primitive: `search-tasks` (supports many filters; preferred over adding narrow “search helper” commands). One-liner example (search within a project): `node {baseDir}/scripts/asana.mjs search-tasks --workspace <gid> --project <project_gid> --text "..." --all` Useful filters: - `--assignee me|<gid|email>` (maps to `assignee.any`) - `--completed true|false` - `--created_at.after <iso>` / `--modified_at.after <iso>` - `--due_on.before YYYY-MM-DD` / `--due_at.before <iso>` - `--is_blocked true|false` / `--is_blocking true|false` ### Create / update / complete - Create: `node {baseDir}/scripts/asana.mjs create-task --workspace <gid> --name "..." --projects <project_gid> --assignee me` - Update: `node {baseDir}/scripts/asana.mjs update-task <task_gid> --name "..." --due_on 2026-02-01` - Complete: `node {baseDir}/scripts/asana.mjs complete-task <task_gid>` ## Project manager workflows This skill supports the workflows commonly expected from a PM in Asana: - Keep a **project brief** up to date (`upsert-project-brief`) - Write **status updates** (`create-status-update`) - Work with **timelines** (start/due dates) and shift schedules safely - Use **custom fields** as first-class metadata - Interpret **blockers** and dependency graphs (`project-blockers`, `dependencies`, `dependents`) ### Project brief - Read: `node {baseDir}/scripts/asana.mjs project-brief <project_gid>` - Upsert (create or update): `node {baseDir}/scripts/asana.mjs upsert-project-brief <project_gid> --title "Project brief" --html_text "<body>...</body>"` ### Status updates - Create: `node {baseDir}/scripts/asana.mjs create-status-update --parent <project_gid> --status_type on_track --text "Weekly update..."` - List: `node {baseDir}/scripts/asana.mjs status-updates --parent <project_gid> --all` ### Sections and moving tasks - List sections: `node {baseDir}/scripts/asana.mjs sections --project <project_gid> --all` - Create section: `node {baseDir}/scripts/asana.mjs create-section --project <project_gid> --name "Blocked"` #### Add a task to a project Command: `add-task-to-project` Calls `POST /tasks/{task_gid}/addProject` and supports optional section placement and ordering. Examples: `node {baseDir}/scripts/asana.mjs add-task-to-project <task_gid> --project <project_gid>` With section + ordering: `node {baseDir}/scripts/asana.mjs add-task-to-project <task_gid> --project <project_gid> --section <section_gid> --insert_before null --insert_after null` (`--section`, `--insert_before`, and `--insert_after` are optional; when provided they are passed through in the request body.) #### Remove a task from a project Command: `remove-task-from-project` Calls `POST /tasks/{task_gid}/removeProject`. Example: `node {baseDir}/scripts/asana.mjs remove-task-from-project <task_gid> --project <project_gid>` ## Custom fields Custom fields are critical for reliable PM automation. - List a project’s custom fields: `node {baseDir}/scripts/asana.mjs project-custom-fields <project_gid> --all` - Read a custom field definition: `node {baseDir}/scripts/asana.mjs custom-field <custom_field_gid>` - Set task custom fields on create/update: `node {baseDir}/scripts/asana.mjs update-task <task_gid> --custom_fields '{"<custom_field_gid>":"<value>"}'` Notes: - For enums, the value is typically the enum option GID. - For numbers, send a JSON number. ## Rich text, mentions, and reliability Asana rich text fields are **XML-valid HTML fragments** wrapped in a `<body>` root element. The API rejects invalid XML or unsupported tags. Key points: - Use `html_notes` for task descriptions. - Use `html_text` for comments/stories and status updates. - Avoid unsupported tags like `<p>` and `<br>`; prefer literal newlines (`\n`) and `<hr/>` separators. - For mentions/links, use `<a data-asana-gid="..."></a>` (or a self-closing `<a .../>`). ### Mention notifications Creating a mention link does **not** guarantee notification delivery if the user is not already assigned or following. For reliable pings, do one of: - Assign the user first, then post the comment, OR - Add the user as a follower, wait a few seconds, then post the comment This skill supports the “add follower + wait” pattern: `node {baseDir}/scripts/asana.mjs comment <task_gid> --html_text "<body>Hi <a data-asana-gid=\"<user_gid>\"/>...</body>" --ensure_followers <user_gid> --wait_ms 2500` Plain text comments (`--text`) do **not** create real @-mentions via the API; they remain plain text. ## Attachments, uploads, and inline images - Upload a file attachment to a task: `node {baseDir}/scripts/asana.mjs upload-attachment --parent <task_gid> --file /path/to/file.png` - Embed an existing image attachment inline (tasks + project briefs only): `node {baseDir}/scripts/asana.mjs append-inline-image --attachment <attachment_gid> --task <task_gid>` ## Activity feed / “inbox-like” workflows Asana does not provide a single universal “inbox” API for all notifications. The closest stable primitive is the **Events** endpoint scoped to a specific resource (project, task, etc.). Use: - `events --resource <gid>` to pull incremental changes on a project (or a user's "My Tasks" project) - The command stores a sync token locally so subsequent runs fetch only changes ## Timeline shifting - Shift one task (optionally include subtasks): `node {baseDir}/scripts/asana.mjs shift-task-dates <task_gid> --delta_days 7 --dry_run true` - Shift an entire project’s tasks: `node {baseDir}/scripts/asana.mjs shift-project-tasks --project <project_gid> --delta_days -3 --dry_run true --all` Run with `--dry_run true` first, then re-run with `--dry_run false`. ## Out of scope - Portfolios (premium) are intentionally omitted. - “Bot personality” is not embedded here; configure behavior in your agent prompt.


Security scan verdicts — ClawScan: clean | static analysis: suspicious | VirusTotal: clean | SkillSpector: clean (LOW)