Async Command

Other

Async command execution and progress reporting for OpenClaw agents. Use when running shell commands that take time (more than 5 seconds), and especially when...

Install

openclaw skills install async-command

async-command

When to use async and how to stop long-running commands.

The Core Insight

Every long command is an opportunity to do something useful while waiting — or a trap that freezes you out.

Blocking: You run make build, wait 5 minutes, do nothing. Async: You start make build, it runs in background, you do other things, check back later.

Rule of thumb: If a command takes longer than you want to wait, it should run async.

When to Go Async

SituationBlock or Async?
Database migration (30s+)Async
pip install 50 packagesAsync
Build a Docker imageAsync
curl a quick APIBlock
Read a config fileBlock
File search in small dirBlock
Compiling large projectAsync
Running testsAsync
Watching logsAsync

The Pattern (Universal)

# 1. Start in background, yield to not block
exec(command="...", yieldMs=30000)

# 2. While waiting, do other things
# (this is the key benefit - you're not frozen)

# 3. When ready, check result
process(action="poll", sessionId="<session_id>", timeout=60000)

The Universal Steps

Step 1: Start without blocking

exec(command="your command here", yieldMs=60000)

yieldMs = how long to wait before backgrounding. Longer = more output captured.

Step 2: Manage the background job

# Check if done
process(action="poll", sessionId="<session_id>", timeout=0)

# Wait for completion
process(action="poll", sessionId="<session_id>", timeout=60000)

# Get partial output
process(action="log", sessionId="<session_id>")

# Stop it
process(action="kill", sessionId="<session_id>")

Step 3: Done.

Common Mistakes

Mistake 1: Blocking a long command with a 5-minute timeout

# ❌ What most people do
exec(command="make build", timeout=300)
# Waits 5 minutes, then fails anyway

# ✅ Async approach
exec(command="make build", yieldMs=10000)
# Starts building, returns immediately, you decide when to check

Mistake 2: Not using process tool to check results

# ❌ Re-running to "check"
exec(command="make build", yieldMs=60000)
# ...then running it again with exec!
# This starts a SECOND build, wastes resources

# ✅ Use the process session
process(action="poll", sessionId="<session_id>", timeout=120000)

Mistake 3: Forgetting about background jobs

# Start something, then forget about it
exec(command="python train_model.py", yieldMs=10000)
# (goes on with other work, never checks back)

# ✅ Track it, check back periodically
exec(command="python train_model.py", yieldMs=10000)
# ...later:
process(action="poll", sessionId="<session_id>", timeout=60000)

Emergency Stop: "Stop Now"

Scenario: You started a long operation, need to abort immediately.

How it works:

  1. Run long commands with yieldMs (background mode) — the agent stays responsive
  2. Ken says "stop" or runs nek_stop
  3. Agent kills the background job immediately

Why yieldMs matters: Commands run in background (yieldMs > 0), agent can respond to messages and process actions even while command is running. Without yieldMs, the agent is blocked and cannot respond.

To stop immediately: Say "stop", "停止", or any clear stop signal. The agent checks for stop on every heartbeat and before any new command, and will immediately kill all background jobs.

Key rule: For any command that might need interruption, always use yieldMs. The agent stays alive and responsive.

When NOT to Use

  • Command is fast (< 5 seconds)
  • You need the result before proceeding
  • It's destructive and you want to confirm first

Mental Model

Think of async like a餐厅点菜:

  1. 你点了菜(exec → 开始运行)
  2. 等着的时候可以做别的事(做其他任务)
  3. 好了叫你来取(poll → 检查结果)
  4. 可以中途退菜(kill → 停止进程)

不要站在厨房门口等菜做完了才去结账。