asanadw
Sync Asana data to a local SQLite data warehouse for offline queries, metrics, and LLM-powered summaries.
Quick start
Monitoring
Before syncing, you tell asanadw which entities to track. Monitored entities are synced when you run sync all.
# Add all your favorited projects and portfolios
# Add individual entities
# Asana URLs work too
# List and remove
Syncing
Sync pulls data from the Asana API into the local database.
# Sync all monitored entities
# Sync a single entity
What each entity type syncs:
- project -- tasks, comments, custom fields, sections
- user -- tasks assigned to the user
- team -- team members and team projects
- portfolio -- contained projects (and their tasks)
Filtering by date
Incremental sync
After the first full sync of a project, subsequent syncs use the Asana Events API to fetch only what changed. This is significantly faster for large projects.
How it works
- After a full sync, asanadw stores an events sync token for each project.
- On the next sync, it asks the Events API "what changed since this token?"
- Only the changed tasks are fetched individually.
- If more than 50 tasks changed, asanadw falls back to a full bulk fetch (faster than 50+ individual GETs).
Token expiry
Asana event sync tokens expire after 24 hours. When a token expires:
- The next sync does a one-time full sync for that project
- A fresh token is stored automatically
- Subsequent syncs resume the fast incremental path
Forcing a full sync
Scheduling syncs
To stay on the fast incremental path, run sync all at least once every 24 hours. Running every 15-30 minutes is recommended for near-real-time data.
cron (every 15 minutes):
*/15 * * * * ASANA_TOKEN="your-token" /path/to/asanadw sync all >> /tmp/asanadw-sync.log 2>&1
launchd (macOS, every 15 minutes):
Save as ~/Library/LaunchAgents/com.asanadw.sync.plist:
Label
com.asanadw.sync
ProgramArguments
/path/to/asanadw
sync
all
EnvironmentVariables
ASANA_TOKEN
your-token
StartInterval
900
StandardOutPath
/tmp/asanadw-sync.log
StandardErrorPath
/tmp/asanadw-sync.log
Load with:
Querying
Query synced tasks with filters.
Filters
| Flag | Description |
|---|---|
--project <GID> |
Filter by project |
--portfolio <GID> |
Filter by portfolio |
--team <GID> |
Filter by team |
--assignee <GID or email> |
Filter by assignee |
--mine |
Tasks assigned to you |
--completed |
Completed tasks only |
--incomplete |
Incomplete tasks only |
--overdue |
Overdue tasks only |
--created-after <YYYY-MM-DD> |
Created after date |
--created-before <YYYY-MM-DD> |
Created before date |
--due-after <YYYY-MM-DD> |
Due after date |
--due-before <YYYY-MM-DD> |
Due before date |
--limit <N> |
Max results (default: 100) |
Output formats
Search
Full-text search across tasks, comments, projects, and custom fields.
| Flag | Description |
|---|---|
--type <TYPE> |
Filter by type: task, comment, project, custom_field |
--assignee <GID or email> |
Filter by assignee |
--mine |
Tasks assigned to you |
--project <GID> |
Filter by project |
--limit <N> |
Max results (default: 20) |
--json |
JSON output |
Metrics
Compute task metrics for a user, project, portfolio, or team over a time period.
Period formats
| Period | Description |
|---|---|
qtd |
Quarter to date (default) |
ytd |
Year to date |
rolling-30d |
Rolling 30 days |
2024-Q1 |
Specific quarter |
2024-M03 |
Specific month |
Summaries
Generate LLM-powered narrative summaries. Requires an LLM provider to be configured (see Configuration).
| Flag | Description |
|---|---|
--period <PERIOD> |
Time period (same formats as metrics, default: qtd) |
--force |
Bypass cached summary and regenerate |
--json |
JSON output |
Configuration
| Key | Description |
|---|---|
workspace_gid |
Asana workspace GID (auto-detected on first sync) |
llm_provider |
bedrock (default) or anthropic |
llm_model |
Model name (e.g. claude-sonnet-4-5, claude-haiku-4-5) |
Database
Data is stored in a SQLite database at ~/.asanadw/asanadw.db. Override with --db:
The database uses WAL mode and can be queried directly with any SQLite client:
Schema
The database follows a star schema:
- dim_ tables (dimensions):
dim_users,dim_teams,dim_projects,dim_portfolios,dim_sections,dim_date,dim_period,dim_custom_fields,dim_enum_options - fact_ tables (facts):
fact_tasks,fact_comments,fact_status_updates,fact_task_custom_fields,fact_task_summaries,fact_user_period_summaries,fact_project_period_summaries,fact_portfolio_period_summaries,fact_team_period_summaries - bridge_ tables (many-to-many):
bridge_task_projects,bridge_portfolio_projects,bridge_task_tags,bridge_task_dependencies,bridge_task_followers,bridge_team_members,bridge_task_multi_enum_values
Full-text search is powered by FTS5 virtual tables (tasks_fts, comments_fts, projects_fts, custom_fields_fts).
Environment variables
| Variable | Required | Description |
|---|---|---|
ASANA_TOKEN |
Yes | Asana personal access token |
ANTHROPIC_API_KEY |
For summarize with anthropic provider |
Anthropic API key |
AWS_* |
For summarize with bedrock provider (default) |
Standard AWS credentials (e.g. AWS_PROFILE, AWS_REGION) |
Development
License
MIT