OpenClaw Background Processes: Run Long Agent Work
Read from search, close with the playbook
If this post helped, here is the fastest path into the full operator setup.
Search posts do the first job. The preview, homepage, and full playbook show how the pieces fit together when you want the whole operating system.
The quickest way to make an AI operator feel broken is to let one long job monopolize the conversation where humans are still trying to talk. A build starts. A scraper runs. A deployment waits on logs. Slack shows typing. Nobody knows whether the agent is working, stuck, or about to answer three hours later with a wall of terminal output.
OpenClaw gives you a cleaner pattern: keep human-facing chat responsive, move long shell work into managed background sessions, use cron for scheduled chores, and let the Gateway queue serialize inbound runs so replies do not collide. That sounds like plumbing because it is plumbing. It is also the difference between an agent that feels like a teammate and an agent that feels like a frozen terminal.
This post is the operator version. I am not going to pretend every task needs a workflow engine. Most of the time, the win is simpler: start long work once, keep a handle to it, check completion deliberately, and send humans only the result they can act on.
The first rule: do not keep the chat hostage
OpenClaw's command queue exists because inbound auto-reply runs can collide when messages arrive close together. The docs describe a lane-aware FIFO queue. Each session run is queued by session key so only one active run touches a given session at a time, and then it enters a global lane where overall parallelism is capped. Typing indicators can fire immediately on enqueue, so the human sees presence while the queue waits its turn.
That queue protects the agent from stepping on itself, but it is not a reason to do everything inside the visible Slack reply. The queue is for orderly agent turns. Background execution is for long process work. Cron is for future or scheduled work. Sessions are for keeping history inspectable. If you mix those up, you get the classic failure: one busy thread becomes a terminal, a task runner, a status dashboard, and a customer support channel at the same time.
The operating rule I use is blunt: if the human does not need to read every line, the human should not be forced to wait for every line.
Use background exec for work that starts now
The exec tool runs shell commands. For long-running commands, OpenClaw can keep the process in memory and return a sessionId instead of blocking the whole turn forever. The key knobs are documented directly: yieldMs controls when the command auto-backgrounds, background can background immediately, timeout kills the process after the configured limit, workdir sets the directory, and pty: true is available when a command genuinely needs a TTY.
A build or test run should look like this conceptually:
{
"command": "npm run build && npm test",
"workdir": "/workspace/app",
"yieldMs": 1000,
"timeout": 1800
} If the command finishes before the yield window, you get the output right away. If it is still running, OpenClaw returns a running status, a session id, and a short tail. That is the important boundary. The agent can continue managing the conversation without pretending the command finished.
The docs also call out a subtle but important behavior: background and yieldMs runs inherit the configured exec timeout unless the call provides one. That means a detached process is still supervised. It is not a random shell orphan that lives forever because an agent forgot about it.
Use the process tool as the control handle
Once exec backgrounds a command, the process tool is the control surface. It can list running and finished sessions, poll new output, read aggregated logs, write stdin, kill a process, or clear a finished session. Polling also reports exit status, so it is the natural verification step before telling a human something passed.
{
"action": "poll",
"sessionId": "<session-id>"
} There are two habits worth building here. First, poll when the result matters. A quiet success can still need confirmation, especially if the command exited cleanly without printing useful output. Second, do not turn polling into a fake scheduler. The docs explicitly say not to emulate reminders or delayed follow-ups with sleep loops or repeated polling. If the work is for the future, schedule it with cron.
Process logs are memory-backed for backgrounded sessions. They are only persisted into chat history if the agent actually polls or logs them and the tool result lands in the transcript. That is usually good. It keeps routine terminal noise out of the human conversation while still allowing targeted inspection when something fails.
Use cron when the work belongs to the clock
Cron is OpenClaw's Gateway scheduler. It runs inside the Gateway, stores jobs under ~/.openclaw/cron/jobs.json, and keeps runtime state next to it in jobs-state.json. It supports one-shot at schedules, fixed interval every schedules, and cron expressions with optional timezone support.
That makes cron the right tool for scheduled work: a weekly audit, a daily report, a reminder in 20 minutes, a nightly content run, or any chore where the important part is when it runs. It also lets you choose where the work executes. A main-session cron enqueues a system event for the normal heartbeat path. An isolated cron runs a dedicated agent turn in cron:<jobId> or another custom session. A custom session can preserve context across runs when that is intentionally useful.
openclaw cron add \
--name "Weekly release audit" \
--cron "0 6 * * 1" \
--tz "America/Los_Angeles" \
--session isolated \
--message "Audit the release checklist and summarize blockers." \
--model opus \
--thinking high \
--announce \
--channel slack \
--to "channel:C1234567890" For long work that should not clutter the main conversation, isolated cron is usually the clean shape. The docs say isolated jobs can override model and thinking, run with lightweight bootstrap context, and deliver output by announce, webhook, or none. Announce delivery is valid for isolated jobs and can target Slack with an explicit channel:<id> destination, which avoids ambiguous routing.
The operational advantage is simple. The work gets its own run. The main chat gets a concise result. The history stays attributable to the scheduled job instead of being smeared across a live support thread.
If you are turning OpenClaw into a real operator box, not a weekend demo, get ClawKit here. It packages the same rules for identity, memory, tools, approvals, cron, reporting, and production discipline.
Keep scheduled work from becoming chat spam
Cron delivery deserves care. If delivery is omitted for isolated jobs, OpenClaw defaults to announce behavior. That is convenient, but convenience can turn into noise if every scheduled job talks. The docs support three delivery modes: announce for channel delivery, webhook for HTTP callbacks, and none for internal-only runs.
Use announce when a human needs the result. Use none when the job updates a local artifact, refreshes state, or only needs a later audit. Use webhook when another system should receive the finished event. I care less about the exact choice than about making it deliberate. A scheduled job with default delivery and vague output is how automation becomes Slack clutter.
Cron also has retry behavior. The docs classify rate limits, provider overload, network errors, server errors, and Cloudflare-related failures as transient. One-shot jobs retry transient errors up to three times by default, while recurring jobs apply exponential backoff and stay enabled. Auth failures and config or validation errors are permanent. That distinction matters because not every failed background job deserves a human panic message.
Use sessions to inspect history, not live connectivity
The openclaw sessions CLI lists stored conversation sessions. That is useful for auditing where work happened, checking recently active sessions, scoping by agent, and cleaning up old transcript stores. But the docs warn that session lists are not channel liveness checks. A quiet Slack or Telegram channel can reconnect successfully without creating a new session row until a message is processed.
openclaw sessions cleanup --dry-run
openclaw sessions cleanup --all-agents --dry-run --json
openclaw sessions cleanup --enforce That distinction prevents a lot of false debugging. Use sessions when you need the storage-level view of conversations and run history. Use channel status, deep status, or health checks when you need live connectivity. For background work, sessions are the audit trail, not the heartbeat monitor.
The pattern I trust in production
- Acknowledge quickly. Do not pretend a long task is instant.
- Start long shell work with
execand a sane timeout. Let it background instead of freezing the visible conversation. - Keep the returned process session id. That is the handle for polling, logs, stdin, or kill.
- Poll only when it changes the answer. Do not busy-wait. Use completion wake or a targeted
processcheck. - Use cron for future work. No sleep loops. No fake reminder shells.
- Use isolated cron for noisy scheduled jobs. Give heavy work its own run and deliver only the summary.
- Report evidence, not logs. Humans need the build status, live URL, commit hash, or blocker. They do not need the whole terminal.
This is not just politeness. It is reliability. When long tasks are detached cleanly, humans can interrupt, steer, or ask a different question without corrupting the work already in flight. When scheduled jobs run in isolated sessions, main history stays readable. When process output is checked deliberately, completion summaries become evidence instead of optimism.
What not to do
Do not run a long deployment synchronously in the same turn and leave Slack waiting for a giant final dump. Do not spawn background shell loops that sleep for hours to simulate reminders. Do not poll every few seconds just because you are anxious. Do not announce every internal cron job by default. And do not use openclaw sessions as proof that a channel is online.
OpenClaw gives you separate mechanisms because the boundaries matter. Queue discipline protects concurrent conversations. Background exec handles work that starts now. Process management gives you control and verification. Cron handles future and recurring work. Sessions give you stored history. Keep those lanes separate and your agent will feel dramatically less chaotic.
Want the complete guide? Get ClawKit — $9.99