Async Coding Agents: Let AI Keep Working While You Decide

·14 min read·Evergreen Tools Team

💡 Tool TipWhile tuning coding agents, pair them with Evergreen Tools' JSON Formatter to inspect tool output, Base64 Encode/Decode for credentials, and UUID Generator for task IDs — everyday companions in agent workflows!

In August 2026, OpenAI merged send_user_message_async into the public Codex repository (as reported by The New Stack). The change looks small, but it reshapes the relationship between coding agents and the developers supervising them: instead of grinding to a halt every time the agent has a question, it can fire off a message, get an "accepted" acknowledgment, and keep working. This article explains async coding agents and why they are becoming a production necessity.

Async coding agents keeping developers in the loop

AI agents in the modern dev workflow

1. What Is an Async Coding Agent?

The core idea of an async coding agent is non-blocking. The New Stack's report contrasts two tools: Codex's existing request_user_input pauses the entire turn until the developer answers, while the newly merged send_user_message_async sends the question or update, receives an "accepted" response, and continues the current turn — the developer's reply comes back later as a new user message. In the integration test, Codex sent "Still investigating," immediately got another opportunity to respond, and never sat idle.

2. Why Production Teams Need Async

A real refactor asks 3-5 decision questions. With blocking tools, a 20-minute session burns half its time waiting. Async lets the agent finish work that does not depend on the answer: analyze the call graph, write tests, prepare the patch — and only interrupt you when a decision is actually required. The New Stack notes this proves OpenAI is building a different relationship between coding agents and the developers supervising them.

# The old blocking pattern: request_user_input
# Codex pauses the whole turn and waits for the developer
def verify_breaking_change(plan):
    # This tool BLOCKS: the agent stops generating
    answer = request_user_input(
        "This refactor touches auth/validator.ts. Proceed?"
    )
    if answer == "yes":
        return execute(plan)
    return plan.revised

3. Async Messages Are a Side Channel, Not Context Pollution

One detail is easy to miss: OpenAI avoids inserting a second, synthetic copy of the developer-facing update into the model's input. The original tool call and its accepted result stay in the exchange, but the message is not re-added as a normal assistant response — effectively a side channel. That saves tokens and prevents the agent from being derailed by its own progress reports. For teams that watch context budgets, this design matters.

# The new async pattern: send_user_message_async
# Codex sends the message, gets "accepted", and keeps working
def long_running_refactor():
    send_user_message_async(
        "Still investigating the cache invalidation path."
    )
    # No blocking: the agent continues the current turn
    graph = inspect_call_graph("src/cache")
    risky = find_write_cycles(graph)
    if risky:
        send_user_message_async(
            "Found 3 write cycles. Preparing a minimal patch."
        )
    return patch

4. The Boundary: Subagents and Async

Per the registration logic in the merged code, subagents do not receive this tool. A Codex task using several subagents still has exactly one agent responsible for communicating with the developer. This is deliberate — it prevents multiple agents from firing questions at you at once. Teams orchestrating multi-agent workflows should adopt the same rule: a single outward communication channel.

# Worker agent pattern: background jobs with a heartbeat
# A task queue keeps the human informed without stalling the agent
from codex import CodexSession

session = CodexSession(repo="evergreen-tools")

job = session.submit_async(
    prompt="Upgrade all lodash imports to native ES2024",
    notify_on=["progress", "question", "done"],
)

# The human sees updates as they arrive and answers only
# when a decision is actually needed
for update in job.stream():
    if update.kind == "question":
        update.answer(input("Decision needed: "))
    elif update.kind == "progress":
        print(f"[agent] {update.text}")

5. How to Roll It Out: Queues, Heartbeats, and Decision Points

To put async agents into real workflows, use three patterns: a task queue (submit background jobs and subscribe to notifications), heartbeats (long tasks report progress periodically), and decision-point splitting (only ask when you must make a call). The developer shifts from "chatting along" to "approving," and the agent shifts from "one step per question" to "continuous progress" — throughput improves by an order of magnitude.

# Review-loop pattern: async handoff between agent and reviewer
# The agent keeps the repo green while the reviewer thinks
pipeline = [
    ("agent", "implement feature X with tests"),
    ("async",  "notify reviewer: PR ready for early look"),
    ("agent", "continue on independent task Y"),  # no waiting
    ("human", "approve or request changes"),
    ("agent", "address review comments and rebase"),
]

for step in pipeline:
    run(step)   # async steps never block the queue

6. When NOT to Use Async

Async is not a silver bullet. High-risk operations (database schema changes, production config) should still use blocking confirmation; and without solid test coverage, letting an agent run free can manufacture junk changes. Best practice: default to async progress, force sync confirmation on critical paths — "ask when you must, don't bother me otherwise."

Async coding agents keeping developers in the loop

From research to production

📌 Frequently Asked Questions

What is the difference between async and normal coding agents?

A normal agent (like request_user_input) pauses the entire turn while asking the developer a question. An async agent (send_user_message_async) sends the message, immediately receives an 'accepted' acknowledgment, and continues the current turn; the reply arrives later as a new user message. The difference is whether the agent stays productive while waiting.

Do async messages waste tokens?

No. Per The New Stack's report, OpenAI deliberately avoids injecting a second copy of the developer-facing message into the model input as a normal assistant response. The original tool call and its accepted result remain, but the message travels through a side channel and does not consume extra context budget.

Can subagents send async messages to developers?

Not currently. The code merged into Codex shows subagents do not receive send_user_message_async; regardless of how many subagents a task uses, a single agent stays responsible for communicating with the developer to avoid a flood of questions from multiple agents.

Which tasks suit async mode?

Long-running and parallelizable work: large refactors, dependency upgrades, test completion, cross-file analysis. High-risk operations — database schema changes, production config edits — should still use blocking confirmation so the agent cannot barrel ahead into an incident.

How do I start using async coding agents?

Watch the changelog of your coding agent (Codex, Claude Code, Cursor, etc.) for async messaging or background-task capabilities. Start with progress reporting: have the agent send one progress message and verify it doesn't block, then convert decision points to async. Pair it with a task queue and heartbeat messages for the best results.