โ† Back to Articles
General6 min read

2026-02-17-using-the-exec-tool

ClawMakers Teamยท

The exec Tool in OpenClaw: A Beginner's Guide

So you want your AI agent to run shell commands? That's what exec is for. It's one of the most powerful tools in OpenClaw โ€” it lets your agent execute commands on the host machine, manage long-running processes, and interact with terminal applications. Let's break it down.

What Is exec?

The exec tool runs shell commands from within an OpenClaw agent session. Think of it as giving your agent a terminal. It can run anything from a simple ls to spinning up a dev server in the background.

Basic Syntax

At its simplest, you just pass a command:

exec(command: "echo hello world")

That's it. The agent runs the command, waits for it to finish, and returns the output.

Real Examples

exec(command: "ls -la ~/projects")
exec(command: "git status")
exec(command: "cat /etc/hosts")
exec(command: "brew list")

Nothing fancy โ€” just like typing in your terminal.

Background Execution

Some commands take a while. Dev servers, file watchers, long builds โ€” you don't want the agent sitting there waiting forever. That's where background execution comes in.

The background Flag

Set background: true to immediately detach the process:

exec(command: "npm run dev", background: true)

The agent kicks off the command and moves on. The process keeps running in the background.

The yieldMs Option

Sometimes you want to see some output before backgrounding. yieldMs lets you wait a set number of milliseconds first:

exec(command: "npm run dev", yieldMs: 5000)

This waits 5 seconds for initial output (like "Server started on port 3000"), then backgrounds the process. Default is 10 seconds if you don't specify.

This is super useful for dev servers where you want to confirm startup succeeded before moving on.

Process Management

Once you've got background processes running, you manage them with the process tool. Here's the rundown:

List Running Sessions

process(action: "list")

Shows all active exec sessions with their IDs.

Check Output (Poll / Log)

process(action: "log", sessionId: "abc123")
process(action: "log", sessionId: "abc123", offset: 100, limit: 50)

Grab recent output from a background process. Use offset and limit to page through logs.

Send Input

process(action: "write", sessionId: "abc123", data: "yes\n")

Write to a process's stdin. Handy for interactive prompts.

Send Special Keys

process(action: "send-keys", sessionId: "abc123", keys: ["ctrl+c"])

Send keyboard shortcuts โ€” like Ctrl+C to stop a server.

Kill a Process

process(action: "kill", sessionId: "abc123")

When you're done. Clean and simple.

PTY Mode (Pseudo-Terminal)

Some commands need a real terminal โ€” think interactive CLIs, coding agents, or anything that draws a TUI. That's what pty: true is for:

exec(command: "htop", pty: true)
exec(command: "python3 -i", pty: true)
exec(command: "ssh user@server", pty: true)

Without PTY, these commands might hang, produce garbled output, or just refuse to start. When in doubt with interactive tools, flip it on.

When to Use PTY

  • Interactive REPLs (Python, Node, etc.)
  • Terminal UIs (htop, vim, less)
  • SSH sessions
  • Any command that asks "are you a terminal?"

When You Don't Need It

  • Simple one-shot commands (ls, cat, grep)
  • Build scripts (npm run build)
  • Anything that just dumps output and exits

Working Directory

By default, commands run in the agent's current working directory. Override it with workdir:

exec(command: "npm install", workdir: "/Users/jorden/projects/my-app")

Environment Variables

Pass custom env vars with the env parameter:

exec(command: "node app.js", env: {"NODE_ENV": "production", "PORT": "8080"})

Timeouts

Don't let runaway processes eat resources. Set a timeout (in seconds):

exec(command: "curl https://slow-api.example.com", timeout: 30)

The process gets killed if it exceeds the limit.

Elevated Execution

Need sudo-level access? The elevated flag requests host-level elevated permissions:

exec(command: "networksetup -setdnsservers Wi-Fi 1.1.1.1", elevated: true)

โš ๏ธ This only works if the OpenClaw configuration allows it. It's gated by policy โ€” the agent can't just escalate privileges on its own. Think of it as "requesting" elevation, not "taking" it.

Safety Considerations

This is the important part. exec is powerful, and power demands responsibility.

Things to Keep in Mind

  1. Destructive commands need confirmation. Before running rm -rf, DROP TABLE, or anything irreversible, the agent should confirm with you. Prefer trash over rm when possible โ€” recoverable beats gone forever.

  2. Don't blindly pipe from the internet. curl ... | bash is risky enough when you do it. An agent doing it without review? Worse.

  3. Mind the blast radius. A command that works fine on one file can wreck everything with a wildcard. Be specific.

  4. Secrets and credentials. Don't hardcode API keys or passwords in exec commands โ€” they'll show up in logs. Use environment variables or config files.

  5. Background processes persist. If you spin up a server and forget about it, it's still running. Audit your sessions with process(action: "list") and clean up.

  6. Network access is real. Commands can make HTTP requests, connect to databases, or SSH into servers. The agent has the same network access as the host machine.

The Golden Rule

If you wouldn't paste it into your own terminal without reading it first, the agent shouldn't run it without your approval.

Quick Reference

| Parameter | Type | What It Does | |-----------|------|-------------| | command | string | The shell command to run (required) | | background | boolean | Run in background immediately | | yieldMs | number | Wait N ms before backgrounding (default: 10000) | | pty | boolean | Use pseudo-terminal for interactive CLIs | | workdir | string | Set working directory | | env | object | Custom environment variables | | timeout | number | Kill process after N seconds | | elevated | boolean | Request elevated (root) permissions |

Putting It All Together

Here's a realistic workflow โ€” spinning up a dev environment:

# 1. Install dependencies
exec(command: "npm install", workdir: "/Users/jorden/projects/my-app")

# 2. Start the dev server in background, wait for startup
exec(command: "npm run dev", workdir: "/Users/jorden/projects/my-app", yieldMs: 8000)

# 3. Check it's running
process(action: "list")

# 4. Check the output
process(action: "log", sessionId: "the-session-id")

# 5. When done, shut it down
process(action: "send-keys", sessionId: "the-session-id", keys: ["ctrl+c"])

That's exec in a nutshell. It's your agent's hands on the keyboard โ€” use it wisely, and it'll save you a ton of time. ๐Ÿพ

Enjoyed this article?

Join the ClawMakers community to discuss this and more with fellow builders.

Join on Skool โ€” It's Free โ†’