Background Exec and Process Tool for Shell Commands

Learn how OpenClaw uses the exec tool to run shell commands and the process tool to manage background sessions. This guide is for developers needing to execute and control long-running tasks.

Read this when

  • Adding or modifying background exec behavior
  • Debugging long-running exec tasks

OpenClaw uses the exec tool to execute shell commands and holds long running tasks in memory. Background sessions are managed by the process tool.

exec tool

Parameters:

ParameterDescription
commandMandatory. The shell command that will be executed.
workdirSets the working directory; if not provided, the default cwd is used.
envAdditional environment variables passed to the command.
yieldMsTime in milliseconds before the process is moved to the background (default is 10000).
backgroundForces the command to run in the background right away.
timeoutA timeout value in seconds (default tools.exec.timeoutSeconds); the process is killed when this time expires. To disable the exec process timeout for a specific call, use timeout: 0.
ptyWhen a pseudo-terminal is available, runs inside one (useful for TTY requiring CLIs and coding agents).
elevatedIf elevated mode is enabled and permitted, runs outside the sandbox (gateway by default, or node when the exec target is node).
hostSpecifies the exec target: auto, sandbox, gateway, or node.
nodeA node ID or name, used together with host: "node".

Behavior:

  • Direct output is returned for foreground executions.
  • When a command is backgrounded (either explicitly or after the yieldMs timeout), the tool provides status: "running" plus sessionId along with a short tail of the output.
  • Backgrounded and yieldMs runs adopt tools.exec.timeoutSeconds unless an explicit timeout is provided in the call.
  • Output remains in memory until the session is either polled or cleared.
  • If the process tool is not allowed, exec executes synchronously and yieldMs and background are ignored.
  • Exec commands that are spawned receive OPENCLAW_SHELL=exec to support context aware shell and profile rules.
  • For long running work that must begin immediately: start it once and let automatic completion wake (when enabled) trigger when the command produces output or fails.
  • If automatic completion wake is not available, or you need confirmation of a clean exit for a command that produces no output, use process to poll.
  • Do not use sleep loops or repeated polling to simulate reminders or delayed follow ups; use cron for future scheduled tasks.

Env overrides

VariableEffect
OPENCLAW_BASH_YIELD_MSDefault delay before backgrounding, in milliseconds. Default is 10000, clamped between 10 and 120000.
OPENCLAW_BASH_MAX_OUTPUT_CHARSMaximum number of characters kept in memory for output.
OPENCLAW_BASH_PENDING_MAX_OUTPUT_CHARSPer stream cap for pending stdout and stderr, measured in characters.
OPENCLAW_BASH_JOB_TTL_MSTime to live for finished sessions, in milliseconds, bounded between 1 minute and 3 hours.
OPENCLAW_PROCESS_INPUT_WAIT_IDLE_MSIdle output threshold in milliseconds; writable background sessions that exceed this are marked as likely waiting for input. Default is 15000.

Config (preferred over env overrides)

KeyDefaultEffect
tools.exec.backgroundMs10000Identical to OPENCLAW_BASH_YIELD_MS.
tools.exec.timeoutSeconds1800Default timeout applied per call.
tools.exec.cleanupMs1800000Identical to OPENCLAW_BASH_JOB_TTL_MS.
tools.exec.notifyOnExittrueWhen a backgrounded exec exits, enqueues a system event and requests a heartbeat.
tools.exec.notifyOnExitEmptySuccessfalseAlso enqueues completion events for backgrounded runs that succeed but produce no output.

Child process bridging

When long running child processes are spawned outside the exec or process tools (such as CLI respawns or gateway helpers), attach the child process bridge helper. This ensures termination signals are forwarded and listeners are detached on exit or error. Orphaned processes on systemd are prevented, and shutdown remains consistent across all platforms.

process tool

Actions:

ActionEffect
listSessions that are running or have completed.
pollPull fresh output from a session (also provides the exit code).
logRetrieve combined output together with input recovery suggestions. Works with offset and limit.
writeFeed data to stdin (data, optionally eof).
send-keysTransmit explicit key codes or byte sequences to a PTY session.
submitDispatch an Enter or carriage return to a PTY session.
pasteSend plain text, optionally enclosed in bracketed paste mode.
killStop a background session.
clearErase a completed session from memory.
removeStop it if active; otherwise delete it if done.

Notes:

  • Only background sessions are tracked and retained, kept solely in memory, never written to disk. They disappear when the process restarts.
  • An active background session prevents cooperative host suspension and a safe Gateway restart until the process owner confirms the session has actually exited.
  • process remove can conceal a running session right after a termination request; suspension and restart remain blocked until exit is confirmed.
  • Session logs enter the chat history only when you run process poll/log and the tool's result gets recorded.
  • process is agent scoped; it only sees sessions that agent itself launched.
  • Use poll/log to check status, logs, or completion confirmation when automatic completion wake is not available.
  • Use log before resuming an interactive CLI so the current transcript, stdin state, and input wait hint are all visible at once.
  • Use write/send-keys/submit/paste/kill when you need to supply input or take action.
  • process list contains a generated name (command verb plus target) for quick scanning.
  • process list, poll, and log report waitingForInput only when the session still has writable stdin and has been idle longer than the input wait threshold (default 15000 ms, OPENCLAW_PROCESS_INPUT_WAIT_IDLE_MS).
  • process log uses line oriented offset/limit. When both are omitted, it returns the last 200 lines with a paging hint. When offset is set and limit is not, it returns from offset to the end (not limited to 200).
  • poll's timeout waits up to that many milliseconds before returning; values above 30000 are clamped to 30000.
  • Polling is meant for on demand status checks, not for loop based waiting. If the work should run later, use cron.

Examples

Run a long task and check back later:

{ "tool": "exec", "command": "sleep 5 && echo done", "yieldMs": 1000 }
{ "tool": "process", "action": "poll", "sessionId": "<id>" }

Examine an interactive session before sending input:

{ "tool": "process", "action": "log", "sessionId": "<id>" }

Launch immediately in background:

{ "tool": "exec", "command": "npm run build", "background": true }

Send stdin:

{ "tool": "process", "action": "write", "sessionId": "<id>", "data": "y\n" }

Send PTY keys:

{ "tool": "process", "action": "send-keys", "sessionId": "<id>", "keys": ["C-c"] }

Submit current line:

{ "tool": "process", "action": "submit", "sessionId": "<id>" }

Paste literal text:

{ "tool": "process", "action": "paste", "sessionId": "<id>", "text": "line1\nline2\n" }