Skip to Content

Asana Integration

Pilot integrates with Asana to receive tasks and post status updates. When a task is tagged with the pilot tag, Pilot implements it and reports progress back to Asana.

Asana uses tasks and tags as its primary organizational units. Pilot watches for tasks with a specific tag and processes them automatically.

Setup

1. Create an Asana Personal Access Token

  1. Go to AsanaSettingsAppsDeveloper apps
  2. Click Create new token
  3. Name it “Pilot Bot” and copy the token

Store your token securely. For production, use environment variables or a secrets manager. Personal access tokens have full access to your Asana account.

2. Find Your Workspace ID

Your workspace ID (GID) can be found:

  1. Go to any Asana project
  2. Look at the URL: https://app.asana.com/0/{workspace_gid}/{project_gid}
  3. The first number after /0/ is your workspace GID

Or use the Asana API:

curl -H "Authorization: Bearer $ASANA_ACCESS_TOKEN" \ https://app.asana.com/api/1.0/workspaces

3. Create the pilot Tag

In your Asana workspace:

  1. Open any task
  2. Click Add tags
  3. Type pilot and create the tag
  4. The tag is now available workspace-wide

4. Configure Pilot

# ~/.pilot/config.yaml adapters: asana: enabled: true access_token: ${ASANA_ACCESS_TOKEN} workspace_id: "1234567890123" pilot_tag: pilot polling: enabled: true interval: 30s

Configuration Reference

FieldTypeDefaultDescription
enabledboolfalseEnable the Asana adapter
access_tokenstringrequiredAsana personal access token
workspace_idstringrequiredAsana workspace GID
webhook_secretstringX-Hook-Secret for webhook verification
pilot_tagstring"pilot"Tag that triggers Pilot to process a task
polling.enabledboolfalseEnable polling for new tasks
polling.intervalduration30sPolling interval

Polling Mode

When polling is enabled, Pilot:

  1. Finds the pilot tag by name in the workspace
  2. Queries tasks with that tag
  3. Filters to active (non-completed) tasks
  4. Processes tasks in order of creation date (oldest first)

Task Processing Flow

1. Find task with 'pilot' tag 2. Skip if has 'pilot-in-progress', 'pilot-done', or 'pilot-failed' tag 3. Add 'pilot-in-progress' tag 4. Execute implementation 5. On success: remove 'pilot-in-progress', add 'pilot-done' 6. On failure: remove 'pilot-in-progress', add 'pilot-failed'

Webhook Mode

For real-time task detection, configure Asana webhooks:

1. Set Up Webhook

Webhooks are registered via the Asana API:

curl -X POST https://app.asana.com/api/1.0/webhooks \ -H "Authorization: Bearer $ASANA_ACCESS_TOKEN" \ -H "Content-Type: application/json" \ -d '{ "data": { "resource": "1234567890123", "target": "https://your-pilot.example.com/webhooks/asana" } }'

2. Webhook Handshake

Asana uses a handshake protocol for webhook registration:

  1. Asana sends a request with X-Hook-Secret header
  2. Pilot must respond with the same value in X-Hook-Secret
  3. This establishes the webhook and provides the secret for future verification

3. Configure Webhook Secret

adapters: asana: webhook_secret: ${ASANA_WEBHOOK_SECRET}

The webhook secret is provided by Asana during handshake. Store it securely after the initial registration.

Signature Verification

Asana webhooks use HMAC-SHA256 signatures. Pilot validates incoming webhooks against the stored secret.

Supported Events

EventActionBehavior
addedTask createdProcess if has pilot tag
changedTask updatedProcess if pilot tag was just added
removedTask deletedIgnored
deletedTask deletedIgnored
undeletedTask restoredIgnored

Tags

Pilot uses tags to track task status:

TagPurpose
pilotTriggers Pilot to process the task
pilot-in-progressApplied while Pilot is working
pilot-doneApplied after successful completion
pilot-failedApplied if execution fails

Tag Operations

Asana tags are managed via their GID. On startup, Pilot:

  1. Looks up the pilot tag by name
  2. Caches the GID for efficient polling
  3. Creates status tags if they don’t exist

Status Updates

Pilot posts comments (stories) to Asana tasks as it works:

PhaseComment
Started”Pilot started working on this task”
Completed”Successfully completed — PR #42” with link
Failed”Failed: error details”

Comment Formats

Pilot supports both plain text and HTML comments:

// Plain text client.AddComment(ctx, taskGID, "Pilot completed the task") // HTML (for rich formatting) client.AddHTMLComment(ctx, taskGID, "<p>✅ <strong>Completed</strong> — <a href='...'>PR #42</a></p>")

Priority Mapping

Asana doesn’t have a built-in priority field, but Pilot recognizes priority tags:

Tag NamePilot Priority
urgent, critical, URGENTUrgent
high, High, HIGHHigh
medium, MediumMedium
low, Low, LOWLow

Task Conversion

Asana tasks are converted to Pilot tasks:

Asana FieldPilot FieldFormat
gidTask IDASANA-{gid}
nameTitleDirect
notesDescriptionPlain text
html_notesDescription (alt)HTML stripped
tagsLabelsTag names
projects[0].nameProjectNameFirst project
permalink_urlTaskURLDirect
created_atCreatedAtISO 8601

PR Attachments

When Pilot creates a PR, it can add an external attachment to the Asana task:

client.AddAttachment(ctx, taskGID, prURL, "Pull Request #42")

This creates a clickable link in the task’s attachments section.

API Operations

Pilot uses these Asana API endpoints:

OperationEndpointPurpose
Get TaskGET /tasks/{gid}Fetch task details
Update TaskPUT /tasks/{gid}Update completion status
Add StoryPOST /tasks/{gid}/storiesPost comments
Add TagPOST /tasks/{gid}/addTagAdd status tags
Remove TagPOST /tasks/{gid}/removeTagRemove status tags
Get TagsGET /workspaces/{gid}/tagsList workspace tags
Find TagGET /workspaces/{gid}/tagsFind tag by name
Get Tasks by TagGET /tags/{gid}/tasksQuery tagged tasks
Add AttachmentPOST /tasks/{gid}/attachmentsLink PR

Multi-Project Support

Asana tasks can belong to multiple projects. Pilot uses the first project for context:

# Task belongs to "Backend" and "Sprint 42" projects # Pilot sees: ProjectName = "Backend"

Duplicate Prevention

Available since v2.10.0. All non-GitHub pollers now share this reliability feature.

The Asana poller persists processed task state to SQLite via a ProcessedStore. This means:

  • Survives restarts and hot upgrades — tasks that were already dispatched are not re-dispatched after a restart.
  • Automatic rollback on failure — if execution fails, the task is unmarked so Pilot can retry it on the next poll cycle.
  • Loaded on startup — previously processed tasks are restored from the database before the first poll.

No additional configuration is required. The store is enabled automatically when Pilot uses SQLite for memory.

Automatic Task Completion

When Pilot creates a PR for an Asana task, the task is automatically marked as completed in Asana via the CompleteTask API call.

  • Completion happens as part of the success notification flow (after the PR comment is posted).
  • Non-blocking — if the CompleteTask call fails (e.g., network error, permission issue), the PR is still created and the task is still marked as pilot-done via tags. A warning is logged instead.

Retry Behavior

If execution fails:

  1. pilot-in-progress tag is removed
  2. pilot-failed tag is added
  3. Task is NOT marked as processed (allowing retry)
  4. Removing pilot-failed tag allows Pilot to retry

Troubleshooting

Task Not Being Picked Up

  1. Verify the task has the pilot tag
  2. Check that task is not completed
  3. Ensure no pilot-in-progress or pilot-done tags exist
  4. Verify workspace ID is correct
  5. Check token has access to the workspace

Tag Not Found

  1. Ensure the tag exists in the workspace
  2. Tag names are case-sensitive
  3. Create the tag manually if it doesn’t exist
  4. Check Pilot logs for “pilot tag not found” errors

Webhook Not Triggering

  1. Verify webhook URL is publicly accessible
  2. Check webhook registration succeeded
  3. Ensure webhook handshake completed
  4. Verify webhook secret matches
  5. Check Asana webhook delivery status

Authentication Errors

  1. Verify token hasn’t expired
  2. Check token has workspace access
  3. Regenerate token if compromised
  4. Ensure token isn’t rate-limited

Rate Limiting

Asana has API rate limits. If you hit them:

  • Increase polling interval
  • Use webhooks instead of polling
  • Reduce concurrent operations
  • Check for runaway retry loops