skills$openclaw/asana
l-u-c-k-y7.5k

by l-u-c-k-y

asana – OpenClaw Skill

asana is an OpenClaw Skills integration for coding workflows. Manage Asana tasks, projects, briefs, status updates, custom fields, dependencies, attachments, events, and timelines via Personal Access Token (PAT).

7.5k stars3.3k forksSecurity L1
Updated Feb 7, 2026Created Feb 7, 2026coding

Skill Snapshot

nameasana
descriptionManage Asana tasks, projects, briefs, status updates, custom fields, dependencies, attachments, events, and timelines via Personal Access Token (PAT). OpenClaw Skills integration.
ownerl-u-c-k-y
repositoryl-u-c-k-y/asana-agent-skill
languageMarkdown
licenseMIT
topics
securityL1
installopenclaw add @l-u-c-k-y/asana-agent-skill
last updatedFeb 7, 2026

Maintainer

l-u-c-k-y

l-u-c-k-y

Maintains asana in the OpenClaw Skills directory.

View GitHub profile
File Explorer
8 files
.
references
REFERENCE.md
2.6 KB
scripts
asana.mjs
72.4 KB
_meta.json
277 B
AGENTS.md
4.2 KB
README.md
6.0 KB
SKILL.md
9.2 KB
SKILL.md

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.
  • 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):

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):

openclaw config set skills.entries.asana.enabled true
openclaw config set skills.entries.asana.env.ASANA_PAT "ASANA_PAT_HERE"

Verify what is stored:

openclaw config get skills.entries.asana
openclaw config get skills.entries.asana.enabled
openclaw config get skills.entries.asana.apiKey

Remove a stored token:

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.
README.md

Asana skill (PAT) for OpenClaw / Clawdbot

A dependency-free AgentSkill that integrates Asana via the Asana REST API (v1) using a Personal Access Token (PAT).

  • No npm dependencies
  • Node.js 18+ (uses built-in fetch, FormData, Blob)
  • JSON-only output (designed for agent tool calls)
  • Supports both:
    • Personal task management (My Tasks / triage)
    • Project manager workflows (briefs, status updates, timelines, custom fields, blockers, stakeholder comments)

Repo layout

  • SKILL.md — skill instructions for the agent runtime
  • README.md — human-facing quickstart (this file)
  • scripts/asana.mjs — CLI (the only executable)
  • references/REFERENCE.md — implementation notes and API links
  • LICENSE

Prerequisites

  • Node.js 18+
  • An Asana account
  • An Asana Personal Access Token (PAT)
  1. Create a PAT: Asana → Developer App / PAT settings (see Asana docs: Personal access token).
  2. Provide it to the runtime as ASANA_PAT.

Recommended: store the PAT in OpenClaw config (non-interactive)

This keeps secrets out of prompts and reduces accidental token leakage.

Recommended (apiKey → ASANA_PAT):

openclaw config set skills.entries.asana.enabled true
openclaw config set skills.entries.asana.apiKey "ASANA_PAT_HERE"

Alternative (explicit env):

openclaw config set skills.entries.asana.enabled true
openclaw config set skills.entries.asana.env.ASANA_PAT "ASANA_PAT_HERE"

Verify what is stored:

openclaw config get skills.entries.asana
openclaw config get skills.entries.asana.enabled
openclaw config get skills.entries.asana.apiKey

Remove a stored token:

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, skills run inside Docker and do not inherit the host environment. Set Docker env via agents.defaults.sandbox.docker.env (or per-agent agents.list[].sandbox.docker.env).

Local smoke test

export ASANA_PAT="YOUR_TOKEN"
node scripts/asana.mjs me

Common workflows

1) Set a default workspace once (recommended)

node scripts/asana.mjs workspaces
node scripts/asana.mjs set-default-workspace --workspace <workspace_gid>

After this, commands that require a workspace can omit --workspace.

2) List projects in a workspace

node scripts/asana.mjs projects --workspace <workspace_gid> --all

(or omit --workspace if you set a default)

3) Personal productivity: tasks assigned to me

node scripts/asana.mjs tasks-assigned --assignee me --workspace <workspace_gid> --all

4) Project: list tasks in project

node scripts/asana.mjs tasks-in-project --project <project_gid> --all

5) Search tasks (Advanced Search)

This is the canonical primitive for “search within a project” (and many other filters):

node scripts/asana.mjs search-tasks --workspace <gid> --project <project_gid> --text "invoice" --all

6) Create / update a task

Create:

node scripts/asana.mjs create-task   --workspace <workspace_gid>   --name "TEST - Asana formatting"   --projects <project_gid>   --assignee me

Update:

node scripts/asana.mjs update-task <task_gid> --due_on 2026-02-01

7) Add/remove a task to/from a project

Add:

node scripts/asana.mjs add-task-to-project <task_gid> --project <project_gid>

Add with section placement:

node scripts/asana.mjs add-task-to-project <task_gid> --project <project_gid>   --section <section_gid> --insert_before null --insert_after null

Remove:

node scripts/asana.mjs remove-task-from-project <task_gid> --project <project_gid>

8) Rich text + mentions (reliable pattern)

Asana rich text must be XML-valid and wrapped in <body>...</body>. Avoid unsupported tags like <p> / <br>. Use literal newlines and <hr/> separators.

Task description (rich):

node scripts/asana.mjs update-task <task_gid> --html_notes '<body>Rich description: <a data-asana-gid="USER_GID"/>
<hr/>
Plain-ish description: @Lucky</body>'

Comment (rich) with reliable notification delivery:

node scripts/asana.mjs comment <task_gid>   --html_text '<body>Rich comment: <a data-asana-gid="USER_GID"/> hello from rich text.</body>'   --ensure_followers USER_GID   --wait_ms 2500

Plain text comments (--text) do not create real @mentions via the API; they remain plain text.

9) Upload a file and embed an inline image

Upload:

node scripts/asana.mjs upload-attachment --parent <task_gid> --file ./screenshot.png

Embed inline (tasks + project briefs only):

node scripts/asana.mjs append-inline-image --attachment <attachment_gid> --task <task_gid>

Install as a local skill

OpenClaw loads skills from (highest precedence first):

  1. <workspace>/skills
  2. ~/.openclaw/skills
  3. bundled skills

Copy this folder into your workspace skills directory, e.g.:

<your_openclaw_workspace>/skills/asana/

Publishing to ClawHub

You can publish directly from a local folder; a GitHub repo is optional.

Install the CLI

npm i -g clawhub
clawhub --help

First-time publish (run from this folder)

clawhub publish . --slug asana --name "Asana" --version 1.0.0 --tags latest --changelog "Initial release (PAT)"

Notes:

  • --slug must be unique on ClawHub. If asana is taken, use something like asana-pat or asana-skill.
  • To publish an update, bump --version (semver) and publish again.

Troubleshooting

  • 401 Unauthorized: PAT missing/invalid. Verify ASANA_PAT is set and has not been revoked.
  • 400 xml_parsing_error: invalid rich text XML or unsupported tags. Use <body>...</body>, avoid <p>/<br>, and keep markup minimal.
  • Mention didn’t notify: ensure the mentioned user is assigned or a follower before posting the comment (and add a short wait after adding followers).

See references/REFERENCE.md for links and implementation notes.

Permissions & Security

Security level L1: Low-risk skills with minimal permissions. Review inputs and outputs before running in production.

Requirements

  • OpenClaw CLI installed and configured.
  • Language: Markdown
  • License: MIT
  • Topics:

Configuration

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

FAQ

How do I install asana?

Run openclaw add @l-u-c-k-y/asana-agent-skill in your terminal. This installs asana into your OpenClaw Skills catalog.

Does this skill run locally or in the cloud?

OpenClaw Skills execute locally by default. Review the SKILL.md and permissions before running any skill.

Where can I verify the source code?

The source repository is available at https://github.com/openclaw/skills/tree/main/skills/l-u-c-k-y/asana-agent-skill. Review commits and README documentation before installing.