# @kody/asana — agent notes Human setup and intent live in [`README.md`](./README.md). This file is for agents: imports, smoke/dryRun execute snippets, and edge cases. Secrets by **name** only — never paste key values. Do not disable live webhooks or jobs. ## Auth | Lane | Credential | Notes | | --- | --- | --- | | A (recommended) | Integration `asana` (or `asana-`) | BYO OAuth + PKCE. Host `app.asana.com`. | | B | User secret `asanaPat` (or `asanaPat-`) | PAT Bearer. `account: "work"` → `asana-work` / `asanaPat-work`. | Every export accepts `integrationName` / `integration`, `account`, `secretName`, and `auth: "oauth" | "pat"` when both exist. Placeholder: `{{secret:asanaPat|scope=user}}`. Do not hard-code a personal workspace GID. ## Import paths | Export | Import | | --- | --- | | package overview | `kody:@kody/asana` | | accounts | `kody:@kody/asana/accounts` | | smoke-test | `kody:@kody/asana/smoke-test` | | viewer | `kody:@kody/asana/viewer` | | list-workspaces | `kody:@kody/asana/list-workspaces` | | get-workspace | `kody:@kody/asana/get-workspace` | | list-projects | `kody:@kody/asana/list-projects` | | get-project | `kody:@kody/asana/get-project` | | create-project | `kody:@kody/asana/create-project` | | list-tasks | `kody:@kody/asana/list-tasks` | | get-task | `kody:@kody/asana/get-task` | | create-task | `kody:@kody/asana/create-task` | | update-task | `kody:@kody/asana/update-task` | | list-stories | `kody:@kody/asana/list-stories` | | create-story | `kody:@kody/asana/create-story` | | request (escape hatch) | `kody:@kody/asana/request` | | types | `kody:@kody/asana/types` | Prefer static `kody:@kody/asana/...` imports from `execute`. Do not lead with `packages.invoke`. ## Smoke test (read-only) ```js import smokeTest from 'kody:@kody/asana/smoke-test' export default async function main() { return await smokeTest() // without creds => { ok: true, live: false, setup: { ...URLs } } // with creds => { ok: true, live: true, hasViewerGid, ... } (no email) } ``` ## Common snippets List workspaces then projects: ```js import listWorkspaces from 'kody:@kody/asana/list-workspaces' import listProjects from 'kody:@kody/asana/list-projects' export default async function main() { const { items: workspaces } = await listWorkspaces() return await listProjects({ workspaceGid: workspaces[0]?.gid, limit: 20, }) } ``` Unwrapped REST: ```js import request from 'kody:@kody/asana/request' export default async function main() { return await request({ path: '/users/me', query: { opt_fields: 'gid,name' }, }) } ``` ## dryRun / confirm (writes) `create-project`, `create-task`, `update-task`, `create-story`, and mutating `./request` (POST/PUT/PATCH/DELETE) require `confirm: true`. Pass `dryRun: true` to inspect the REST payload without calling Asana. ```js import createTask from 'kody:@kody/asana/create-task' export default async function main() { const preview = await createTask({ name: 'Investigate checkout timeout', workspaceGid: '123', assignee: 'me', dryRun: true, }) // Only after explicit user confirmation of workspace + title: const created = await createTask({ name: 'Investigate checkout timeout', workspaceGid: '123', assignee: 'me', confirm: true, }) return { preview, created } } ``` ## Edge cases / fork notes - REST base: `https://app.asana.com/api/1.0` - Helpers project slim objects with `opt_fields`. Use `./request` for extra fields. - `assignee: 'me'` is the authorizing user. - List tasks requires `projectGid`, or both `assignee` and `workspaceGid`. - Fork/adapt: keep secret/integration names documented; do not hard-code personal workspace GIDs or treat live `@kody/asana` storage as yours. - Never paste Asana PATs or OAuth client secrets into chat or logs.