Chat-based AI is semi-synchronous by default. You prompt, you wait, the response pings, and you’re pulled back in. As a result, we often end up running three or four sessions in parallel just to stay busy between replies. If you allow yourself to move on to something else, you risk losing the thread on a reply and the work. I wrote a few months back about how much I love AI Teammates becsuse they flip the script on this. In this post I’m sharing how I recreated the concept in Claude with two-way communication through Asana.
The setup before this
Before I set this up, working with Claude meant several chat windows open at once, checking each one within seconds of a reply landing. My focus was completely scattered when working with Claude. Compare that to how I work with the humans on my team: We get synced on an idea, then they go off and do some work. After they deliver I come back to it on my own schedule, not the moment they finish. Asana AI Teammates give you that natively, and while Claude can connect to Asana through the MCP it doesn’t package two-way communication as a native flow — but you can build the channel yourself.
Output: Deliver in Asana, and description vs. comment
The key to this skill is that I deliberately instruct Claude to “deliver in Asana,” meaning: when you’re done with whatever I’ve asked, put the result in Asana instead of — not in addition to — this chat.
How Claude does that follows a fixed order of priority:
- By default it will create a new task assigned to me, so nothing goes unassigned and orphaned.
- If I named a specific task in the trigger, it comments on that task.
- If I didn’t but a task is already active in the session (from an earlier check or deliver, see below), it comments there too so I never have to repeat the ID mid-thread.
Regardless of where it delivers in Asana, its in-session reply stays minimal — “You got it,” or nothing — because I specifically don’t want to get tempted by the chat notification.
Within the task, the description carries context only: what was asked, what the task is. The actual deliverable — reasoning, output, open questions, file references — goes in a comment:
🦀 Claude:
<deliverable starts here>
The split keeps the description reusable and skimmable instead of bloated with delivery text.
Input: Take context and command from Asana
Once Claude’s delivered its work in Asana, I want to be able to respond in the same place.
When I instruct Claude to “check Asana [id]” (using either the task ID or URL) it pulls the task description and the full comment thread, then figures out whose turn it is. Claude prefixes its own comments with a crab emoji and bold text (more on that below); so if the last comment has no prefix that means it’s my response and gets treated as the next instruction. That task becomes “active” for the session, so I don’t have to repeat the ID on the next exchange.
Narrow trigger phrases, not intent-guessing
Because I need to differentiate between chatting with Claude – when I want live back and forth – and when I want Claude to go do work and deliver without interrupting, the skill only fires on exact phrases:
auto-load-triggers:
- deliver in Asana
- deliver this in Asana
- deliver to Asana
- check Asana
It deliberately does not fire on “update Asana” or “create a task” — those stay on the normal project-management workflow. A skill that tries to infer intent from loose phrasing either over-fires or under-fires. A narrow, literal trigger is boring, and boring is what you want from something you’re going to rely on daily.
What worked: zero false fires so far. What we’d watch for: phrasing drift if my own habits change — if I start saying “ship this to Asana” instead, the skill won’t hear it.
The identity workaround
Claude posts through my own Asana account. There’s no separate seat for a third-party coding agent yet, so every comment shows as authored by me. The fix is the crab emoji and bold “Claude:” label at the top of every comment Claude writes. It’s not a real solution — just a visible-enough hack until Asana, or Anthropic, ships proper agent identities outside the native Teammate product.
The AutoHotkey layer
I use AutoHotkey text-expansion for this: type /das anywhere and it expands into “Deliver in Asana”; /cas does the same for “Check Asana.” Removes the “type a full sentence every time” friction. It’s a small thing, but it’s the difference between using this daily and eventually not bothering.
Results so far
There’s no time-saved figure to give you. The skill is just a few days old. What I have instead are two real examples:
- The skill fixing itself. It delivered three improvements to its own SKILL.md — project-optional creation, the description/comment split, comment-only mode — through the skill, within hours of first deploying it.
- A cross-session, cross-model handoff. A planning session with Opus closed out by delivering an execution plan as a task, scoped for a Sonnet session to run. A separate Code session picked it up later and executed it.
Take these as evidence the mechanism works as designed, not as a productivity metric.
What I learned
- The delay-is-a-feature idea only holds if the handoff artifact is durable and inspectable. A task and its comment thread are. A chat window isn’t.
- Solve attribution before you scale it. The shared-identity gap is manageable as a single operator but a risk and inevitable mess the moment more than one is posting under the same account.
- Narrow, literal triggers beat clever intent-detection in this case.
- A handoff artifact has to carry enough context to stand alone. The description-as-context plus a Session ID and Harness line is what lets a different session — or a different model — pick the work up cold.
What I don’t know yet
There’s no native agent identity for third-party coding agents in Asana. I haven’t tested whether the crab-emoji convention holds up cleanly once more than one agent is posting to the same thread. And there’s no long-run time data — it’s too early for that.
The skill itself
Here’s the whole thing, stripped of anything specific to me, so you can drop it in and adjust the identity/assignee bits for your own workspace:
---
name: work-in-asana
description: >
Two-way working channel through Asana. DELIVER session output into Asana (as a new task, or as a
comment on an existing task), and RESUME work from an Asana task by pulling its context and acting
on the latest instruction. Triggers ONLY on the exact phrases "deliver in Asana" / "deliver this in
Asana" / "deliver to Asana" (optionally followed by a task ID), or "check Asana [id]". Does NOT fire
on general "update Asana", "log to Asana", "sync Asana", or create/track-a-task requests — those
follow your standard Asana project-management workflow.
user-invocable: true
auto-load-triggers:
- deliver in Asana
- deliver this in Asana
- deliver to Asana
- check Asana
---
# Work in Asana
A two-way working channel through Asana. Two things this skill does:
- **Deliver** — push session output into Asana (a new task, or a comment on an existing task).
- **Resume** — pull an Asana task's context and pick up the work from its latest instruction.
Narrow, deliberate triggers. Only fire on the exact phrases in the frontmatter. Do not fire on
"update Asana," "log to Asana," "sync Asana," "create a task," or similar — those follow your standard
project-management rules, not this skill.
## Shared-identity rule (critical)
Claude posts to Asana through your own Asana identity, so **every comment's author shows as you** —
authorship alone does not tell you who wrote it. Distinguish by the prefix instead:
- **Claude's comments** always start with `🦀 ***Claude:***`.
- **Your comments** do not.
Any comment without the crab prefix is from you.
## The active task
An "active Asana task" is the task this session is currently working through. It becomes active when:
- you run `check Asana <id>`, or
- a task is created by a `deliver` in this session, or
- you otherwise put a specific Asana task ID in the session context.
Once a task is active, `deliver in Asana` defaults to commenting on it (see delivery target rules).
---
# Resume — "check Asana <id>"
When you say `check Asana <id>` (an ID or task URL), the session is communicating **through
that Asana task**. Steps:
1. Get the task description and the full comment thread.
2. Read the description (context/framing) and the full comment thread (the running back-and-forth).
Apply the shared-identity rule to tell Claude's turns from yours.
3. Set that task as the **active task** for the session.
4. Determine the instruction:
- **If the most recent comment is yours** (no crab prefix), treat it as the prompt for what to
do next. Act on it, then deliver the result back as a comment on this task (comment mode).
- **If the most recent comment is Claude's** (crab prefix) — Claude already delivered and nothing
new has been asked. Don't invent work; briefly say what the task is waiting on and ask what's
next.
This is a loop: resume → work → deliver comment → (you comment back) → resume again.
---
# Deliver — "deliver in Asana [id]"
## In-session response
Minimize chat output on a deliver:
- If nothing needs confirming, reply with nothing beyond what's structurally required.
- If a reply is needed, the entire reply is **"You got it"** — nothing else.
All substance goes into Asana, not the chat.
## Delivery target — where it goes
Resolve in this order:
1. **You explicitly say create a new task** → create mode, even if a task is active.
2. **A task ID is in the deliver trigger** (`deliver in Asana <id>`) → comment mode on that task.
3. **A task is active in this session** (from `check Asana`, an earlier deliver, or an ID in context)
→ comment mode on that task. This is the default — you don't need to repeat the ID.
4. **None of the above** → create mode (new task).
## Comment mode — deliver into an existing task
Post a single comment and stop. Do **not** create a task, write a description, or set a title —
those exist. Do **not** repeat context already in the description or earlier comments. Write only the
deliverable (see "The comment"), with a metadata line carrying **Session ID + Harness** (no Task ID —
it's the task you're already in). These change session to session, so they're always included.
## Create mode — new task
### Where the task goes
1. If a project is clearly connected — active this session or an obvious match — create the task there.
2. If no project is obviously connected, **create the task with no project. Do not ask which project
to use.** You'll file it yourself if needed.
3. Either way, **assign the task to yourself**. Every delivered task must be assigned to you — that's
what makes an unfiled task recoverable. No project is fine; no assignee is not.
Do not create a new project — this skill delivers into existing structure. (No-project creation uses
`assignee` + your workspace instead of a `project_id`.)
### Title
Short and descriptive of the deliverable itself (what it is), not the process used to get there.
### The task description — context only
Set via `html_notes`. This is framing, not the work. Include: what was requested, what the task is,
what you were working on. Then, at the bottom, under a horizontal rule, an *italic* metadata block:
<hr/>
<em>- Session ID: <session ID></em>
<em>- Harness: <Code CLI, VSCode, Cowork, or Chat></em>
<em>- Task ID: <Asana task ID></em>
The Task ID doesn't exist until the task is created, so the flow is:
1. Create the task with the description (leave the Task ID value blank).
2. Read the returned task GID.
3. Update the task to backfill the Task ID line.
4. Post the comment.
## The comment — the deliverable (both modes)
Set via a task comment/story using `html_text`. Start with the crab and a bold-italic label,
then a line break, then the content on a new line:
<body>🦀 <strong><em>Claude:</em></strong>
<deliverable starts here></body>
Write like a direct report delivering finished work — not an assistant recapping a conversation. Do
**not** re-set context here (that's the description's job): no "as requested," no restating the ask.
Do include:
- The work itself, delivered directly (the actual output)
- Thought process or findings that shaped it, stated plainly ("checked X, ruled out Y because Z")
- Anything worth flagging — risks, assumptions, open questions, decisions needed
- Artifact links where applicable; local files as full absolute paths, not just filenames
- If a deliverable can't be linked or pathed, clear directions for finding it in the session
`html_text` typically allows only a limited tag set (`<body> <strong> <em> <u> <s> <code> <ol> <ul>
<li> <a> <blockquote> <pre>`) — check your Asana integration's supported tags. (The description side
usually allows more, including `<hr/>` and headers.)
## Determining Session ID and Harness
- **Harness** is where this session runs: `Code CLI`, `VSCode`, `Cowork`, or `Chat` — pick from
runtime signals; if genuinely ambiguous, choose the closest and don't stall.
- **Session ID** is the current session identifier from the runtime/environment. If it truly can't be
determined, write `unknown` rather than blocking delivery.
## After delivering
That's it. Don't post a chat summary afterward — the "You got it" (or silence) covers it. Don't
re-list what went into the task or comment.
Swap in your own assignee and workspace details, and adjust the tag set to whatever your Asana integration actually supports.
Over to you: if you’re also drawing a hard line between AI as an always-on second brain and AI as a colleague with boundaries, what’s your version of this?
- Do you feel the same pain with the semi-synchronous chat and scattered focus? Or are you loving the always-on, always-moving productivity?
- Have you tried a deliver/resume pattern with a coding agent, rather than a native Teammate?
- How are you handling attribution when the agent doesn’t have its own seat?
Liohn Sherer - In Transition
