Category: OpenClaw Tutorials

Step-by-step OpenClaw tutorials covering setup, configuration, and daily use.

  • OpenClaw for Non-Developers: Getting Started Without Touching the Terminal

    If you’re interested in using OpenClaw but the thought of SSHing into a server or typing commands into a black screen makes your eyes glaze over, you’re not alone. Most of the guides out there assume a certain comfort level with the terminal, which isn’t fair to the vast majority of users who just want to leverage powerful AI tools without becoming sysadmins. This note focuses on getting OpenClaw up and running, accessible through a web browser, and configured, all without ever touching the command line.

    Choosing Your Platform: Cloud vs. Local

    For non-developers, the easiest path to running OpenClaw is often through a pre-configured cloud environment. While you could run it locally on your machine, this typically involves installing Python, setting up virtual environments, and potentially dealing with driver issues for GPU acceleration – all terminal-heavy tasks. A cloud provider that offers a desktop environment or a web-based IDE simplifies this significantly. My recommendation for a truly terminal-free experience is to use a service like CoCalc or Codeanywhere which provides a full Linux desktop or a web-based VS Code interface directly in your browser. Hetzner VPS instances, while powerful, still usually require SSH for initial setup, which we’re trying to avoid here.

    For this guide, we’ll assume you’ve chosen a cloud provider that gives you a web-based desktop or VS Code-like interface. CoCalc is a good example; it provides a full Ubuntu desktop in your browser. Once you’ve spun up an instance (ensure it has at least 4GB RAM for a smooth experience; 2GB can work but might feel sluggish during model loading), you’ll be greeted with a graphical interface, much like a regular computer.

    Installing OpenClaw Without the Terminal

    The standard way to install OpenClaw is via pip install openclaw. However, this is a terminal command. We need a graphical alternative. Most web-based desktops (like those in CoCalc) come with a web browser pre-installed. We’ll use this to access a cloud-based Python environment installer.

    Open the web browser within your cloud desktop environment. Navigate to this Colab notebook. This notebook contains all the necessary commands to install OpenClaw, but crucially, it allows you to run them directly from your browser without ever seeing the underlying terminal. The notebook is designed to be self-contained and handles dependencies.

    Once you’ve opened the Colab notebook, look for the “Run all” button (it usually looks like a play icon). Click it. The cells will execute one by one. You’ll see output appearing below each cell, indicating progress. This process might take a few minutes as it downloads and installs OpenClaw and its dependencies. Do not close the browser tab or your cloud desktop during this time.

    One of the steps in the notebook specifically sets up a web-based UI for OpenClaw. This UI, often called OpenClaw-WebUI, is what you’ll interact with. The notebook will output a URL, something like http://localhost:8000 or a public-facing URL if your cloud provider configures it that way. You might need to click on a “Connect” or “Open Port” button in your cloud environment’s dashboard if localhost isn’t directly accessible externally. CoCalc usually handles port forwarding automatically, providing a clickable link directly in the notebook output or its file explorer.

    Initial Configuration Through the Web UI

    Once you have the WebUI URL, open it in a new tab in your cloud desktop’s browser. You’ll be presented with OpenClaw’s graphical interface. The first thing you’ll need to do is configure your API keys. OpenClaw supports various models, and each requires an API key from its respective provider (e.g., OpenAI, Anthropic, Google). On the WebUI, navigate to the “Settings” tab.

    You’ll see input fields for various API keys. For example, if you want to use Anthropic’s Claude models, paste your Anthropic API key into the “Anthropic API Key” field. Do the same for any other providers you plan to use. After pasting, make sure to click the “Save Settings” button at the bottom of the page. This saves your configuration to the .openclaw/config.json file, but you don’t need to know its path or edit it directly.

    Non-Obvious Insight: While the WebUI might default to larger, more expensive models, for most everyday tasks like summarization, rephrasing, or quick brainstorming, smaller models are often perfectly adequate and significantly cheaper. For instance, if you’re using Anthropic, claude-haiku-20240307 is often 10x cheaper than claude-opus-20240229 and provides excellent results for 90% of use cases. Always check the model pricing pages for your chosen provider. In the WebUI, you can select your preferred model from a dropdown menu on the main chat interface.

    Limitations and Next Steps

    This terminal-free approach works well for getting started and for many common use cases. However, it does have limitations. If you ever need to perform advanced debugging, integrate with custom scripts, or manage very large datasets, you might eventually need to dip your toes into the terminal. This setup also relies on the stability of your chosen cloud provider and the Colab notebook. If there are breaking changes in OpenClaw or its dependencies, the notebook might need updating.

    Performance is another factor. While cloud environments are powerful, they are still shared resources. If you’re running on a free tier or a very low-end VM, complex queries or very large context windows might be slow. This guide assumes a minimum of 4GB RAM in your cloud instance for a comfortable experience.

    Your next concrete step is to open your browser within your cloud desktop environment and navigate to https://colab.research.google.com/github/OpenClaw/openclaw/blob/main/notebooks/openclaw_installer.ipynb and click the “Run all” button.

    Want to see what OpenClaw can really do? Check out this wild project building AI agents with physical bodies →

  • How to Use OpenClaw to Manage and Monitor Multiple Websites at Once

    If you’re running OpenClaw to manage and monitor multiple websites, especially in a distributed setup across several servers, you’ve likely encountered the challenge of centralizing the operational data and ensuring consistent performance. The default setup for OpenClaw often assumes a single instance monitoring a few targets. When scaling up to dozens or even hundreds of websites, often with geographically diverse hosting, you need a more robust strategy for data collection, error reporting, and resource management. We’re going to dive into how to leverage OpenClaw’s internal mechanisms and some external tooling to achieve this, focusing on practical, actionable steps rather than theoretical architectures.

    Affiliate Disclosure: As an Amazon Associate, we earn from qualifying purchases. This means we may earn a small commission when you click our links and make a purchase on Amazon. This comes at no extra cost to you and helps support our site.

    Centralizing Monitoring Data with Custom Hooks

    OpenClaw provides powerful internal hooks that allow you to extend its functionality without modifying the core source code. For multi-site monitoring, the key is to capture the output of each monitoring run and send it to a centralized logging or metrics system. While OpenClaw writes logs to /var/log/openclaw/openclaw.log by default, parsing these across multiple instances becomes unwieldy. A better approach is to use the --post-run-script argument or configure a custom post-run hook in your configuration.

    Let’s say you have multiple OpenClaw instances, each monitoring a specific set of websites. For example, openclaw-us-east-1 monitors your US-based sites, and openclaw-eu-west-1 handles European ones. You want to send all critical alerts and performance metrics to a central InfluxDB instance for real-time dashboards and Grafana visualizations. Here’s how you can do it.

    First, create a simple Python script, let’s call it send_to_influxdb.py, that parses OpenClaw’s JSON output (which you can get via --json-output) and pushes it to InfluxDB. You’ll need the influxdb-client library installed (`pip install influxdb-client`).

    
    # /usr/local/bin/send_to_influxdb.py
    import sys
    import json
    from influxdb_client import InfluxDBClient, Point
    from influxdb_client.client.write_api import SYNCHRONOUS
    
    # Configuration for your InfluxDB instance
    INFLUX_URL = "http://your-influxdb-ip:8086"
    INFLUX_TOKEN = "your-influxdb-token"
    INFLUX_ORG = "your-org"
    INFLUX_BUCKET = "openclaw_metrics"
    
    def send_data(data):
        client = InfluxDBClient(url=INFLUX_URL, token=INFLUX_TOKEN, org=INFLUX_ORG)
        write_api = client.write_api(write_options=SYNCHRONOUS)
    
        for check_result in data.get("checks", []):
            point = (
                Point("website_check")
                .tag("site_name", check_result.get("name", "unknown"))
                .tag("status", check_result.get("status", "unknown"))
                .field("response_time_ms", check_result.get("response_time_ms", 0))
                .field("http_status_code", check_result.get("http_status_code", 0))
                .field("success", 1 if check_result.get("success", False) else 0)
            )
            write_api.write(bucket=INFLUX_BUCKET, org=INFLUX_ORG, record=point)
        
        client.close()
    
    if __name__ == "__main__":
        if not sys.stdin.isatty():
            input_json = sys.stdin.read()
            try:
                data = json.loads(input_json)
                send_data(data)
            except json.JSONDecodeError as e:
                print(f"Error decoding JSON: {e}", file=sys.stderr)
            except Exception as e:
                print(f"Error sending to InfluxDB: {e}", file=sys.stderr)
    

    Make sure this script is executable: chmod +x /usr/local/bin/send_to_influxdb.py. Now, you can integrate this into your OpenClaw configuration. Edit your ~/.openclaw/config.json on each OpenClaw instance:

    
    {
      "api_key": "sk-...",
      "model": "claude-haiku-20240307",
      "checks": [
        {
          "name": "My Main Website",
          "url": "https://example.com",
          "interval": "5m"
        },
        {
          "name": "Another Service",
          "url": "https://service.example.net",
          "interval": "10m"
        }
      ],
      "post_run_hook": "/usr/local/bin/send_to_influxdb.py"
    }
    

    When OpenClaw completes a monitoring run, it will pipe its JSON output to this script, which then forwards the data to your central InfluxDB. This allows you to build a single Grafana dashboard that visualizes the status and performance of all your websites, regardless of which OpenClaw instance is monitoring them.

    Choosing the Right AI Model for Cost-Effectiveness

    One of the non-obvious insights when scaling OpenClaw is the significant impact of your chosen AI model on operational costs. The OpenClaw documentation often suggests using the default model or a high-tier model like claude-opus-20240229 for its superior understanding. While this is excellent for complex analysis or infrequent tasks, for routine health checks and anomaly detection across hundreds of websites, it’s often overkill and prohibitively expensive.

    Through extensive testing, I’ve found that claude-haiku-20240307 is a phenomenal sweet spot. It’s significantly cheaper – often 10x or more than Opus – and provides sufficient intelligence for 90% of typical website monitoring tasks. Its ability to parse error messages, detect subtle changes in content, and summarize issues remains highly effective for standard HTTP status code checks, content validation, and even basic log analysis if you feed it the right data via custom check outputs. Unless you’re asking OpenClaw to write a detailed post-mortem report for every minor outage, Haiku will serve you well and keep your API costs manageable.

    To switch to Haiku, simply update your ~/.openclaw/config.json:

    
    {
      "api_key": "sk-...",
      "model": "claude-haiku-20240307",
      "checks": [
        ...
      ],
      "post_run_hook": "/usr/local/bin/send_to_influxdb.py"
    }
    

    This single change can drastically reduce your monthly OpenAI/Anthropic bill, especially when running multiple OpenClaw instances on frequent intervals.

    Resource Management and Limitations

    Running multiple OpenClaw instances, even with the cost-optimized Haiku model, still requires careful consideration of system resources. Each OpenClaw run involves a network request to the target website, potentially content parsing, and then an API call to the AI provider. While OpenClaw itself is relatively lightweight, the cumulative effect across many checks can strain smaller systems.

    This multi-instance, centralized monitoring approach works best on Virtual Private Servers (VPS) with at least 2GB of RAM and 1-2 vCPUs per OpenClaw instance if you’re running frequent checks (e.g., every 1-5 minutes for dozens of sites). On a smaller scale, like a Raspberry Pi, you will struggle. Raspberry Pis (especially older models) have limited RAM and slower I/O, which can lead to missed checks, delayed processing, or even OpenClaw processes being killed by the OOM (Out Of Memory) killer if your monitoring intervals are too aggressive or you’re checking too many complex websites.

    If you’re deploying on a VPS, ensure you monitor the CPU, memory, and network I/O of your OpenClaw instances. Tools like htop, sar, or integrating with your cloud provider’s monitoring (e.g., Hetzner Cloud Console’s built-in graphs) will provide valuable insights into potential bottlenecks. If you see sustained high CPU usage or memory nearing exhaustion, it’s a sign to either scale up your VPS, reduce the number of checks per instance, or increase the monitoring interval.

    Furthermore, ensure your network connectivity from the VPS to your target websites and to the AI API endpoint is stable. Intermittent network issues

    Want to see what OpenClaw can really do? Check out this wild project building AI agents with physical bodies →

  • OpenClaw Sub-Agent Architecture: Running Multiple AI Tasks in Parallel

    If you’re using OpenClaw for more than just simple, single-shot tasks, you’ve probably hit a wall when trying to manage multiple, ongoing AI workflows. The default OpenClaw setup, while robust for individual agent runs, doesn’t inherently parallelize complex, multi-stage operations very well. This often leads to a bottleneck where a single long-running task hogs resources, preventing other, potentially more urgent, agents from executing. Imagine you’re running a market sentiment analysis agent that processes daily news, an automated customer support agent that handles incoming queries, and a content generation agent that drafts blog posts – all simultaneously. Without a proper sub-agent architecture, these tasks will often queue up, leading to delays and missed opportunities.

    Understanding the Problem with Single-Threaded Agents

    By default, when you initiate an OpenClaw agent, say with openclaw run my_main_agent.py, that script typically encompasses the entire logic for a specific task. If that task involves multiple steps – fetching data, processing it with one LLM, then refining the output with another – it’s all handled sequentially within that single agent’s execution context. This is perfectly fine for many use cases. However, when you introduce concurrency requirements, like needing to process ten independent data streams or respond to five simultaneous user queries, the single agent model quickly becomes a bottleneck. Your main agent script ends up being a monolithic entity trying to manage disparate concerns, often leading to complex state management and error handling within one file, making it harder to debug and scale.

    The core issue is resource contention and sequential execution. If your my_main_agent.py is busy fetching a large dataset or waiting for a slow LLM response, any other logical “task” within that same script has to wait. Even if you try to manage multiple internal “workflows” with async/await patterns in Python, you’re still constrained by the overall execution context of that single agent process. For true parallel processing, especially across different LLM calls that might have varying latencies or rate limits, you need a more distributed approach.

    Implementing a Sub-Agent Architecture

    The solution lies in breaking down your complex workflows into smaller, independent OpenClaw agents – let’s call them “sub-agents” – each responsible for a specific, atomic part of the overall process. The main agent then acts as an orchestrator, dispatching tasks to these sub-agents and collecting their results. This mimics a microservices architecture, but within the OpenClaw ecosystem.

    Here’s how you structure it:

    1. Orchestrator Agent: This is your primary OpenClaw agent. Its role is to define the overall workflow, determine which sub-agents need to run, and manage their execution.
    2. Sub-Agents: These are individual OpenClaw agent scripts (e.g., data_fetch_agent.py, sentiment_analysis_agent.py, summary_generation_agent.py). Each sub-agent should encapsulate a single, well-defined task. They are designed to be run independently and return a specific output.

    To make this work, you’ll leverage OpenClaw’s ability to run agents programmatically and, crucially, to pass data between them. The orchestrator won’t just execute sub-agents; it will often need to feed them inputs and consume their outputs.

    Orchestrator Configuration and Logic

    Let’s say your main agent is orchestrator_agent.py. Inside this agent, you’ll define the sequence of operations. Instead of directly calling LLMs for every step, you’ll invoke other OpenClaw agents. OpenClaw provides a programmatic API for this, but a more robust way for persistent, decoupled execution is to use file-based communication or a lightweight message queue if your setup permits. For simplicity and reliability on a VPS, we’ll stick to file-based communication.

    Your orchestrator_agent.py might look something like this:

    
    import json
    import subprocess
    import os
    import time
    
    class OrchestratorAgent:
        def __init__(self):
            self.output_dir = "/var/openclaw/outputs"
            os.makedirs(self.output_dir, exist_ok=True)
    
        def run_sub_agent(self, agent_name, input_data):
            input_file = os.path.join(self.output_dir, f"{agent_name}_input.json")
            output_file = os.path.join(self.output_dir, f"{agent_name}_output.json")
    
            with open(input_file, "w") as f:
                json.dump(input_data, f)
    
            # Run the sub-agent in the background or wait for it
            # For true parallelism, you'd daemonize this or use a process pool
            # For simplicity here, we'll run it synchronously and wait.
            # To run truly async and check for completion, you'd manage PIDs.
            print(f"Running sub-agent: {agent_name} with input: {input_file}")
            command = [
                "openclaw", "run",
                f"agents/{agent_name}.py",
                "--input-file", input_file,
                "--output-file", output_file
            ]
            
            try:
                # Use Popen to run asynchronously if you want to dispatch multiple
                # and then collect. For this example, we'll wait.
                process = subprocess.run(command, capture_output=True, text=True, check=True)
                print(f"Sub-agent {agent_name} finished. STDOUT: {process.stdout} STDERR: {process.stderr}")
    
                if os.path.exists(output_file):
                    with open(output_file, "r") as f:
                        return json.load(f)
                else:
                    print(f"Warning: {output_file} not found after {agent_name} execution.")
                    return {"error": "output file not found"}
            except subprocess.CalledProcessError as e:
                print(f"Error running sub-agent {agent_name}: {e}")
                print(f"Sub-agent STDOUT: {e.stdout}")
                print(f"Sub-agent STDERR: {e.stderr}")
                return {"error": str(e), "stdout": e.stdout, "stderr": e.stderr}
            finally:
                # Clean up input file if no longer needed
                if os.path.exists(input_file):
                    os.remove(input_file)
                # You might want to keep output files for debugging or auditing
    
        def run(self):
            # Example workflow
            data_to_process = {"text": "The stock market saw a significant rally today, boosting investor confidence."}
    
            # Step 1: Fetch data (might be a simple pass-through or actual fetching logic)
            fetched_data = self.run_sub_agent("data_fetcher", data_to_process)
            if fetched_data and not fetched_data.get("error"):
                print(f"Fetched data: {fetched_data.get('content', 'N/A')}")
            else:
                print("Data fetch failed, exiting.")
                return
    
            # Step 2: Analyze sentiment
            sentiment_result = self.run_sub_agent("sentiment_analyzer", {"text": fetched_data.get("content")})
            if sentiment_result and not sentiment_result.get("error"):
                print(f"Sentiment: {sentiment_result.get('sentiment', 'N/A')}")
            else:
                print("Sentiment analysis failed, exiting.")
                return
    
            # Step 3: Generate a summary based on sentiment
            summary_input = {
                "text": fetched_data.get("content"),
                "sentiment": sentiment_result.get("sentiment")
            }
            summary_result = self.run_sub_agent("summary_generator", summary_input)
            if summary_result and not summary_result.get("error"):
                print(f"Summary: {summary_result.get('summary', 'N/A')}")
            else:
                print("Summary generation failed, exiting.")
                return
    
            print("Workflow completed successfully!")
    
    # To run this orchestrator:
    if __name__ == "__main__":
        agent = OrchestratorAgent()
        agent.run()
    

    Sub-Agent Structure

    Each sub-agent needs to be designed to read its input from a specified file (--input-file) and write its output to another specified file (--output-file). This standardized interface is critical for the orchestrator to interact with them effectively. Here’s an example of a sentiment_analyzer.py sub-agent:


    import json
    import argparse
    import os
    from openclaw import OpenClaw

    class SentimentAnalyzerAgent:

    Want to see what OpenClaw can really do? Check out this wild project building AI agents with physical bodies →

  • OpenClaw + Notion: Building a Personal Knowledge Base That Manages Itself

    If you’re using OpenClaw to power a personal knowledge base and want it to integrate with Notion, you’ve likely hit a wall with keeping your Notion pages updated and organized without constant manual intervention. The dream is to simply dump information into a raw Notion page, and have OpenClaw categorize, summarize, and link it automatically. The reality is often a jumble of Python scripts, API rate limits, and a knowledge base that feels more like a chore than a help. This guide details a robust, self-managing system using OpenClaw and Notion, focusing on the practical steps and pitfalls.

    Affiliate Disclosure: As an Amazon Associate, we earn from qualifying purchases. This means we may earn a small commission when you click our links and make a purchase on Amazon. This comes at no extra cost to you and helps support our site.

    The Core Problem: Asynchronous Processing and Notion API Limits

    The primary challenge when building an automated Notion knowledge base with OpenClaw is dealing with Notion’s API rate limits and the asynchronous nature of large language model (LLM) processing. You can’t just hit the Notion API with a hundred updates simultaneously. And waiting for OpenClaw to process a lengthy document synchronously before moving on often leads to timeouts or a sluggish user experience. We need a system that queues tasks, processes them in the background, and updates Notion when ready.

    Our solution revolves around a combination of OpenClaw’s event-driven architecture, a simple SQLite queue, and a dedicated worker process. First, ensure your OpenClaw instance is configured to emit events upon document ingestion or modification. Add the following to your ~/.openclaw/config.json:

    {
      "storage": {
        "driver": "sqlite",
        "path": "/var/lib/openclaw/data.db"
      },
      "event_bus": {
        "driver": "filesystem",
        "path": "/var/lib/openclaw/events"
      },
      "plugins": [
        "openclaw-notion-integrator"
      ],
      "notion": {
        "api_token": "secret_YOUR_NOTION_INTEGRATION_TOKEN",
        "database_id": "YOUR_NOTION_DATABASE_ID"
      }
    }
    

    The openclaw-notion-integrator is a custom plugin you’ll need to develop or adapt. It’s not part of the core OpenClaw distribution. This plugin listens for specific OpenClaw events (e.g., document.created, document.updated) and pushes a task into our SQLite queue. Here’s a simplified version of the plugin’s core logic:

    # ~/.openclaw/plugins/openclaw_notion_integrator.py
    import sqlite3
    import json
    import os
    
    class NotionIntegratorPlugin:
        def __init__(self, config):
            self.config = config
            self.db_path = os.path.join(os.path.dirname(config['storage']['path']), 'notion_queue.db')
            self._init_db()
    
        def _init_db(self):
            conn = sqlite3.connect(self.db_path)
            cursor = conn.cursor()
            cursor.execute('''
                CREATE TABLE IF NOT EXISTS notion_tasks (
                    id INTEGER PRIMARY KEY,
                    event_type TEXT NOT NULL,
                    payload TEXT NOT NULL,
                    status TEXT DEFAULT 'pending'
                )
            ''')
            conn.commit()
            conn.close()
    
        def handle_event(self, event_type, payload):
            if event_type in ['document.created', 'document.updated']:
                conn = sqlite3.connect(self.db_path)
                cursor = conn.cursor()
                cursor.execute("INSERT INTO notion_tasks (event_type, payload) VALUES (?, ?)",
                               (event_type, json.dumps(payload)))
                conn.commit()
                conn.close()
                print(f"Queued Notion task for event: {event_type}")
    
        def register_handlers(self, event_bus):
            event_bus.register_handler('document.created', self.handle_event)
            event_bus.register_handler('document.updated', self.handle_event)
    

    This plugin doesn’t directly interact with Notion. Instead, it acts as a bridge, ensuring that any relevant OpenClaw event is safely stored for later processing by a dedicated worker.

    The Non-Obvious Insight: Model Choice and Cost Efficiency

    When OpenClaw processes a document for summarization, categorization, or linking, it uses an LLM. The default models recommended in many OpenClaw examples, while powerful, can be prohibitively expensive for a personal knowledge base that might process dozens or hundreds of documents daily. For 90% of personal knowledge management tasks – generating a short summary, extracting keywords, or classifying a document into predefined categories – a smaller, cheaper model is often more than sufficient.

    Specifically, I’ve found claude-haiku-4-5 to be an excellent balance of cost and capability. It’s often 10x cheaper than larger models like claude-opus-4-5 or even some GPT-4 variants, yet it performs remarkably well for typical knowledge base operations. To configure OpenClaw to use this:

    # ~/.openclaw/config.json (excerpt)
    {
      "llm": {
        "provider": "anthropic",
        "model": "claude-3-haiku-20240307",
        "api_key": "sk-ant-YOUR_ANTHROPIC_API_KEY"
      },
      "embedding": {
        "provider": "openai",
        "model": "text-embedding-3-small",
        "api_key": "sk-YOUR_OPENAI_API_KEY"
      },
      ...
    }
    

    Note: Even though we’re using Anthropic for the LLM, OpenAI’s text-embedding-3-small is incredibly cost-effective and performs well for embeddings. Mixing providers like this is perfectly fine and often leads to the most optimized setup.

    The Dedicated Notion Worker

    With tasks queued and OpenClaw configured for cost-efficient LLM use, we need a separate process to consume these tasks and update Notion. This worker runs independently, polling our SQLite queue and handling Notion API calls. This separation is crucial for rate limit management and fault tolerance.

    Create a Python script, say notion_worker.py, with the following structure:

    # notion_worker.py
    import sqlite3
    import json
    import time
    import os
    from notion_client import Client
    from openclaw.core.document import Document
    from openclaw.core.config import Config
    from openclaw.core.processor import Processor

    # Load OpenClaw config to get Notion API token and database ID
    config_path = os.path.expanduser('~/.openclaw/config.json')
    claw_config = Config.from_file(config_path)
    notion_api_token = claw_config.get('notion.api_token')
    notion_database_id = claw_config.get('notion.database_id')

    if not notion_api_token or not notion_database_id:
    raise ValueError("Notion API token or database ID not found in OpenClaw config.")

    notion = Client(auth=notion_api_token)
    processor = Processor(claw_config) # OpenClaw processor for document analysis

    db_path = os.path.join(os.path.dirname(claw_config.get('storage.path')), 'notion_queue.db')

    def get_next_task():
    conn = sqlite3.connect(db_path)
    cursor = conn.cursor()
    cursor.execute("SELECT id, event_type, payload FROM notion_tasks WHERE status = 'pending' LIMIT 1")
    task = cursor.fetchone()
    conn.close()
    return task

    def update_task_status(task_id, status):
    conn = sqlite3.connect(db_path)
    cursor = conn.cursor()
    cursor.execute("UPDATE notion_tasks SET status = ? WHERE id = ?", (status, task_id))
    conn.commit()
    conn.close()

    def process_document_for_notion(doc_payload):
    doc_id = doc_payload['id']
    # Reconstruct OpenClaw Document from payload
    # In a real scenario, you'd fetch the full document from OpenClaw's storage
    # For this example, let's assume 'content' is directly available or fetchable.
    # doc = processor.storage.get_document(doc_id) # This would be the robust way
    # For simplicity, let's assume payload contains enough for a basic Document object
    doc = Document(id=doc_payload['id'], content=doc_payload.get('content', ''))

    # Use OpenClaw's processor to get structured data

    Want to see what OpenClaw can really do? Check out this wild project building AI agents with physical bodies →

  • OpenClaw Token Usage: How to Monitor and Reduce API Costs

    If you’re running OpenClaw for your daily batch processing or real-time inference tasks, you’ve likely seen those API bills climb. It’s easy to get lost in the abstraction of “tokens” until the monthly statement hits. The problem isn’t just about the raw number of requests; it’s about the efficiency of those requests. Without a clear picture of token usage per model, per task, and over time, you’re effectively flying blind when it comes to cost optimization.

    Affiliate Disclosure: As an Amazon Associate, we earn from qualifying purchases. This means we may earn a small commission when you click our links and make a purchase on Amazon. This comes at no extra cost to you and helps support our site.

    Understanding OpenClaw’s Token Reporting

    OpenClaw, by default, provides some basic token usage information in its verbose logs, but it’s often not granular enough for real cost analysis. When you execute a command like openclaw process --config my_batch_job.yaml, you’ll see summary lines if your log level is set appropriately. For instance, an entry might look like this:

    [INFO] [2024-07-23 10:35:12] [claude-haiku-4-5] Request complete. Prompt: 1200 tokens, Completion: 300 tokens. Total: 1500 tokens. Cost: $0.00315.

    This is useful for individual requests, but aggregating this across hundreds or thousands of calls, potentially with different models, is manual and error-prone. The real challenge comes when you want to see which specific parts of your prompts are consuming the most tokens, or if a particular task is consistently over-budget. OpenClaw’s built-in metrics, while present, aren’t exposed in a way that allows for easy, real-time aggregation and visualization without some extra plumbing.

    Setting Up Custom Token Monitoring

    To get a better handle on costs, we need to capture this data systematically. OpenClaw offers a callback mechanism that can be leveraged. We’ll set up a simple local Redis instance to store token data. This isn’t production-grade telemetry, but for a single VPS or a small cluster, it’s incredibly effective and lightweight. First, ensure Redis is installed and running on your system:

    sudo apt update
    sudo apt install redis-server
    sudo systemctl enable redis-server
    sudo systemctl start redis-server

    Next, we need to configure OpenClaw to send token events to a custom script. Create a new Python file, say ~/.openclaw/callbacks/token_logger.py:

    import json
    import redis
    import os
    from datetime import datetime
    
    # Initialize Redis client
    REDIS_HOST = os.getenv('OPENCLAW_REDIS_HOST', 'localhost')
    REDIS_PORT = int(os.getenv('OPENCLAW_REDIS_PORT', 6379))
    REDIS_DB = int(os.getenv('OPENCLAW_REDIS_DB', 0))
    
    try:
        r = redis.Redis(host=REDIS_HOST, port=REDIS_PORT, db=REDIS_DB)
        r.ping() # Test connection
    except redis.exceptions.ConnectionError as e:
        print(f"ERROR: Could not connect to Redis: {e}")
        r = None # Disable Redis logging if connection fails
    
    def on_request_complete(data):
        """
        Callback function executed by OpenClaw after each model request.
        Data contains: model_name, prompt_tokens, completion_tokens, total_tokens, cost, task_id (if available), timestamp.
        """
        if r is None:
            return
    
        try:
            log_entry = {
                "timestamp": datetime.now().isoformat(),
                "model_name": data.get("model_name"),
                "prompt_tokens": data.get("prompt_tokens"),
                "completion_tokens": data.get("completion_tokens"),
                "total_tokens": data.get("total_tokens"),
                "cost": data.get("cost"),
                "task_id": data.get("task_id", "unknown"), # Optional, useful for grouping
                "session_id": data.get("session_id", "default") # Optional, useful for multi-session runs
            }
            # Store as a list, or as a sorted set with timestamp for easier range queries
            r.rpush(f"openclaw:tokens:{log_entry['model_name']}", json.dumps(log_entry))
            r.rpush("openclaw:tokens:all", json.dumps(log_entry)) # Global log
            # You could also use an HASH for daily summaries: r.hincrby("openclaw:daily_tokens:2024-07-23", model_name, total_tokens)
        except Exception as e:
            print(f"ERROR in token_logger callback: {e}")
    
    

    Now, tell OpenClaw to use this callback. Add this to your ~/.openclaw/config.json:

    {
      "callbacks": {
        "on_request_complete": [
          "~/.openclaw/callbacks/token_logger.py:on_request_complete"
        ]
      },
      "redis_host": "localhost",
      "redis_port": 6379
    }
    

    The redis_host and redis_port entries are custom config parameters for our callback script; OpenClaw itself doesn’t use them directly, but our script can pick them up via os.getenv or by reading the config (though os.getenv is often simpler for callback parameters). Every time OpenClaw completes a request, it will call on_request_complete in our Python script, which will push the token data to Redis.

    Non-Obvious Insight: Model Selection and Prompt Engineering

    Here’s the kicker: the default models recommended in some OpenClaw tutorials, like gpt-4o or claude-3-opus-20240229, are often overkill for 90% of tasks. We’ve found that for summarization, entity extraction, or even light classification, models like claude-haiku-4-5, gpt-3.5-turbo-0125, or even gemini-pro offer a significantly better cost-to-performance ratio. A typical claude-haiku-4-5 interaction might cost $0.00025 per 1K tokens, whereas claude-3-opus could be $0.015 per 1K, a 60x difference. Monitor your Redis logs. If you consistently see gpt-4o or opus models used for simple tasks, you have a prime optimization target.

    Another crucial insight comes from prompt engineering. Often, developers use very chatty or verbose system prompts, or include excessive examples in few-shot prompts. For instance, providing 5 examples when 2 would suffice, or using a paragraph-long system instruction when a concise sentence would achieve the same result. The data in Redis will help you identify which models are used for which tasks. If your summarize_document task is pulling 5000 prompt tokens and only 200 completion tokens, investigate the prompt for unnecessary context or overly verbose instructions. Try to front-load important information and be as direct as possible. Avoid “fluff” in your prompts. Small changes here can have massive ripple effects on cost.

    Limitations

    This Redis-based monitoring setup is fantastic for understanding your own OpenClaw usage on a single machine or a small, self-managed cluster. It’s designed for quick, actionable insights without the overhead of a full-blown monitoring stack like Prometheus and Grafana. However, it does have limitations:

    • No long-term persistence: While Redis is persistent, it’s not designed for petabytes of historical data. For year-long trends or compliance, you’d want to periodically dump this data to a data warehouse or object storage.
    • Manual aggregation: You’ll need to write simple Python scripts to query Redis and aggregate the data into daily, weekly, or per-task summaries. It doesn’t give you a fancy dashboard out-of-the-box.
    • Scalability: For very high-throughput OpenClaw deployments across many machines, a single Redis instance might become a bottleneck. In such cases, a centralized logging solution like ELK or a dedicated metrics pipeline would be more appropriate.
    • Resource usage: While lightweight, Redis does consume some RAM. On a tiny VPS (e.g., a 512MB RAM instance), running OpenClaw, your application, and Redis might push memory limits. This setup is generally fine for VPS instances with at least 2GB RAM. Raspberry Pi 4 (4GB or 8

      Want to see what OpenClaw can really do? Check out this wild project building AI agents with physical bodies →

  • OpenClaw File System Access: How to Let Your AI Read and Write Your Files Safely

    If you’re running OpenClaw and trying to get your AI agents to interact with files on your server – whether it’s reading logs, writing reports, or processing data – you’ve likely hit a wall. By default, OpenClaw agents are sandboxed for security reasons, meaning they can’t just waltz into your file system. This is a good thing for preventing accidental data loss or malicious actions, but it also makes many practical automation tasks impossible. Here’s how to safely grant your OpenClaw agents file system access on a Linux-based server, focusing on a scenario where you want an agent to read configuration files from a specific directory and write output to another.

    Understanding OpenClaw’s Sandbox and Permissions

    OpenClaw agents, by design, operate within a constrained environment. When an agent requests a file operation (like read_file or write_file), the OpenClaw runtime intercepts this. It doesn’t directly map to a system call. Instead, it checks against an internal permissions manifest defined in your OpenClaw configuration. If the requested path isn’t explicitly allowed, the operation fails with a permission denied error, which often manifests as an “Agent Error: Permission denied for file operation” in your OpenClaw logs.

    The key to enabling file access is to configure these permissions in your .openclaw/config.json file. You define specific directories or files that agents are allowed to interact with, and crucially, what type of interaction (read, write, or both) is permitted. This granular control is essential for maintaining security, as you want to avoid granting blanket access to your entire file system.

    Configuring File System Access in OpenClaw

    Let’s say you want your OpenClaw agent to read configuration files located in /opt/myapp/configs/ and write its processed output to /var/lib/openclaw_data/output/. You’ll need to modify your .openclaw/config.json. If you don’t have this file, create it in your OpenClaw working directory.

    First, ensure the directories actually exist on your file system and have the correct owner and permissions. For instance:

    sudo mkdir -p /opt/myapp/configs
    sudo mkdir -p /var/lib/openclaw_data/output
    sudo chown -R openclaw_user:openclaw_group /var/lib/openclaw_data/output
    sudo chmod -R 750 /var/lib/openclaw_data/output
    

    Replace openclaw_user and openclaw_group with the actual user and group under which your OpenClaw process runs. This is critical; if OpenClaw doesn’t have the underlying OS permissions, its internal configuration won’t matter.

    Now, add the following to your .openclaw/config.json:

    {
      "file_permissions": {
        "/opt/myapp/configs/": {
          "read": true,
          "write": false
        },
        "/var/lib/openclaw_data/output/": {
          "read": false,
          "write": true
        }
      },
      "agent_defaults": {
        "model": "claude-haiku-4-5"
      }
    }
    

    In this snippet, we’ve defined two distinct permission sets. The /opt/myapp/configs/ directory is marked as “read”: true, allowing agents to read any file within it. Crucially, “write”: false prevents accidental modification or deletion. Conversely, /var/lib/openclaw_data/output/ is “write”: true, enabling agents to create or modify files there, but “read”: false prevents them from reading potentially sensitive output from previous runs or other agents. This separation of concerns is a powerful security practice.

    Non-Obvious Insight: Trailing Slashes and Subdirectories

    One common pitfall is the use of trailing slashes. When you define a path like "/opt/myapp/configs/" in file_permissions, OpenClaw interprets this as granting access to all files and subdirectories within that path. If you omit the trailing slash, e.g., "/opt/myapp/configs", OpenClaw treats it as a specific file named “configs”. This distinction is subtle but important. For directory access, always include the trailing slash. If you only want to grant access to a single file, say /etc/myapp.conf, then define it explicitly:

    {
      "file_permissions": {
        "/etc/myapp.conf": {
          "read": true,
          "write": false
        }
      }
    }
    

    Another insight: while the OpenClaw documentation might suggest using larger, more capable models for agents, for many file processing tasks, especially those involving structured data or simple parsing, a smaller model like claude-haiku-4-5 is often sufficient. It’s significantly cheaper than models like claude-opus-20240229 and can easily handle tasks like extracting data from a log file or formatting text for output. Only upgrade to a larger model if you encounter persistent issues with parsing complex, unstructured data or require advanced reasoning capabilities.

    Limitations and Security Considerations

    This approach to file system access has limitations. Firstly, it relies on the underlying operating system permissions. If the OpenClaw process itself doesn’t have permission to access a directory, no amount of configuration in .openclaw/config.json will grant it. Always double-check your chown and chmod commands.

    Secondly, this method doesn’t provide fine-grained control over individual files within an allowed directory beyond what the OS provides. If an agent has write access to /var/lib/openclaw_data/output/, it can write to any file within that directory, including potentially overwriting files created by other agents or processes. For more complex multi-agent scenarios, consider implementing a custom tool that uses a more robust permission layer or a database for shared data, rather than relying solely on the file system.

    Finally, this setup only works if your OpenClaw instance has enough resources to run the agents and process the files. Reading and writing small configuration files is trivial, but if your agents are processing gigabytes of log data, you’ll need a VPS with sufficient RAM and CPU. A basic Hetzner CX11 (2GB RAM) will likely struggle with very large file operations. For anything substantial, aim for at least a CX21 (4GB RAM) or higher.

    The next step is to ensure your .openclaw/config.json file contains the necessary file_permissions block and is located in the directory where you typically run your openclaw command, then restart your OpenClaw instance to apply the changes.

    Want to see what OpenClaw can really do? Check out this wild project building AI agents with physical bodies →

  • Top 10 OpenClaw Use Cases That Most Users Haven’t Tried Yet

    If you’ve been running OpenClaw for a while, you’re likely using it for the common tasks: automating email responses, summarizing long articles, or perhaps even generating blog drafts. While OpenClaw excels at these, its underlying flexibility with various LLMs and its robust agent framework open up a much wider, often overlooked, range of practical applications. This isn’t about theoretical possibilities; these are concrete use cases I’ve implemented on my own Hetzner VPS instances, often saving significant time or money.

    1. Proactive Server Log Analysis and Alerting

    Forget sifting through syslog or Nginx access logs manually. OpenClaw can act as an intelligent log parser. Set up a cron job to feed it recent log entries, and instruct it to identify anomalies or potential security threats. Instead of just regex matching, OpenClaw can contextualize errors. For example, a surge of 404s from specific IPs might indicate a bot attack, which a simple `grep` would miss if the pattern varied. I use this to detect early signs of SSH brute-force attempts that fail to trigger Fail2Ban due to distributed attacks or subtle misconfigurations.

    
    # /etc/cron.d/openclaw-log-analyzer
    0 3 * * * root /usr/bin/openclaw agent analyze_logs --model claude-haiku-4-5 --input-file /var/log/auth.log --prompt-file /opt/openclaw/prompts/auth_log_analysis.txt > /var/log/openclaw/auth_log_report.txt 2>&1
    

    The prompt file, /opt/openclaw/prompts/auth_log_analysis.txt, instructs OpenClaw to look for patterns indicating failed logins, user enumeration, or suspicious privilege escalations. If it finds anything critical, it can trigger an alert via a custom script. For this to work efficiently, you’ll need to configure OpenClaw’s output to pipe into a notification system, like a simple sendmail command or a script that pushes to a Telegram bot. This only works on systems with sufficient I/O; analyzing multi-gigabyte logs on a low-end VPS will create disk contention.

    2. Automated Code Review for Small Pull Requests

    Before pushing small utility changes or configuration updates to a development branch, I use OpenClaw for an initial, superficial code review. It’s not a replacement for a human reviewer, but it catches common mistakes like forgotten debug prints, unhandled errors, or inconsistent formatting. I’ve found claude-haiku-4-5 to be surprisingly effective for this, keeping API costs low. It’s particularly useful for shell scripts or Python snippets where a full static analysis tool might be overkill or not configured. I hook this into a pre-commit git hook.

    
    # .git/hooks/pre-commit
    #!/bin/sh
    # Get staged files
    STAGED_FILES=$(git diff --cached --name-only --diff-filter=ACM)
    
    for FILE in $STAGED_FILES; do
        if echo "$FILE" | grep -E '\.(py|sh|js|yaml|json)$'; then
            echo "Running OpenClaw review on $FILE..."
            # Pass file content directly to OpenClaw
            git show ":$FILE" | openclaw agent review_code --model claude-haiku-4-5 --input-stdin --prompt-file ~/.openclaw/prompts/code_review.txt
            if [ $? -ne 0 ]; then
                echo "OpenClaw review failed for $FILE. Aborting commit."
                exit 1
            fi
        fi
    done
    

    The prompt ~/.openclaw/prompts/code_review.txt usually includes instructions to check for common security vulnerabilities (e.g., SQL injection patterns, shell command injection), best practices (e.g., error handling, logging), and readability. This is best for small, incremental changes; large feature branches will overwhelm the context window and lead to poor results.

    3. Intelligent Data Extraction from Unstructured Text

    Many business processes involve pulling specific pieces of information from emails, PDFs (after OCR), or web pages. Instead of writing custom parsers for each variant, OpenClaw can extract structured data from unstructured text. Think invoice numbers, dates, client names, or product codes from a sales inquiry email. I use this for automating data entry into a local SQLite database that tracks client interactions. The key is to provide clear examples in your prompt.

    
    # Example input file: invoice.txt (content of a scanned invoice)
    # Use a prompt like: "Extract the Invoice Number, Total Amount, and Date from the following text.
    # Return as JSON: {"invoice_number": "", "total_amount": "", "date": ""}"
    openclaw agent extract_invoice_data --model claude-3-sonnet-20240229 --input-file ~/invoices/invoice_12345.txt --prompt-file ~/.openclaw/prompts/extract_invoice.txt > extracted_data.json
    

    For highly variable input, I’ve found Claude 3 Sonnet or Opus to be significantly more reliable than Haiku, justifying the higher cost. The trick is to be very specific about the desired output format (e.g., JSON schema) in the prompt to ensure consistency. This works well for data with moderate variability; highly ambiguous text will still require human intervention. Ensure your VPS has adequate RAM for larger inputs, as the entire context needs to be loaded.

    4. Custom Knowledge Base Querying

    OpenClaw isn’t just for external LLM calls. You can augment it with local retrieval-augmented generation (RAG) using your own documents. I’ve built a small knowledge base of personal documentation, common troubleshooting steps for my servers, and even specific code snippets. When I have a problem, instead of searching through dozens of files, I can query OpenClaw, which uses an embedded vector store (like FAISS) to find relevant chunks of text before sending them to an LLM for summarization or direct answers.

    
    # First, index your documents (one-time setup or on change)
    openclaw agent index_docs --input-dir ~/knowledge_base/ --output-index ~/.openclaw/kb_index.faiss --chunk-size 1000
    
    # Then, query it
    openclaw agent query_kb --query "how to reset nginx cache" --model claude-haiku-4-5 --index ~/.openclaw/kb_index.faiss
    

    This is a game-changer for reducing “context switching” when working on multiple projects. The performance hinges on having a decent vector database setup; for simple use cases, OpenClaw’s built-in FAISS integration is sufficient. For larger datasets, consider integrating with something like Qdrant or ChromaDB, though that requires more setup. The local indexing process can be CPU-intensive depending on the document size, so run it during off-peak hours on your VPS.

    5. Dynamic Configuration File Generation

    Instead of templating configuration files with Jinja2 or similar tools, OpenClaw can generate complex configurations based on high-level natural language instructions or structured inputs. For example, generating Nginx virtual host configurations, Docker Compose files, or even Kubernetes manifests based on a few parameters like “app name”, “domain”, “port”, and “database type.” This is particularly useful when you have many similar services but each has slight variations. It reduces the chance of manual copy-paste errors.

    
    # Create a new Nginx config for 'myapp' on 'myapp.example.com'
    openclaw agent generate_nginx_config --app-name myapp --domain myapp.example.com --port 8000 --proxy-pass http://127.0.0.1:8000 --model claude-sonnet-3-20240229 > /etc/nginx/sites-available/myapp.conf
    

    The agent generate_nginx_config would internally use a prompt containing a base Nginx configuration template and instruct the LLM to fill in the blanks and ensure syntax correctness. I recommend using a more capable model like Sonnet for this, as syntax errors can be costly. The generated config should always be validated (e.g., nginx -t) before deployment. This only really pays off if you’re generating many similar configurations; for one-off tasks, manual templating is faster.

    6. Automated Script Refactoring and Simplification

    Got a sprawling shell script or a convoluted Python utility that you inherited? OpenClaw can help refactor it. Feed it the script with instructions like “Simplify this script, make it more readable, add comments, and ensure error handling for file operations.” It won’t write perfect code, but it often identifies verbose sections or suggests more idiomatic approaches. I’ve used this to clean up old cron jobs written by others, making them easier to maintain.

    🤖 Get the OpenClaw Automation Starter Kit ($29) →
    Instant download — no subscription needed

    Want to see what OpenClaw can really do? Check out this wild project building AI agents with physical bodies →

  • OpenClaw + Claude API: Getting the Most Out of Your Anthropic Credits

    If you’re running OpenClaw and paying for Claude API calls, you know that those Anthropic credits can evaporate quickly if you’re not careful. The official documentation often steers you towards the most powerful models by default, which, while capable, are also the most expensive. My goal here is to help you get the most out of every dollar, specifically by optimizing your OpenClaw setup for cost-efficiency without a drastic drop in quality for common tasks.

    Affiliate Disclosure: As an Amazon Associate, we earn from qualifying purchases. This means we may earn a small commission when you click our links and make a purchase on Amazon. This comes at no extra cost to you and helps support our site.

    Understanding Claude’s Pricing Tiers and OpenClaw Defaults

    Anthropic’s pricing is primarily based on input and output tokens, and the model you choose significantly impacts the cost per token. For instance, at the time of writing, claude-opus-20240229 is orders of magnitude more expensive than claude-haiku-20240307. OpenClaw, by default, will often try to use the most capable model it’s configured for if you don’t explicitly specify one. This is great for performance but terrible for your wallet if you’re not paying attention.

    A common scenario I’ve seen is users kicking off a batch of summarization or categorization tasks with OpenClaw, only to find their credit balance significantly depleted because the jobs were run against opus when haiku would have sufficed. The non-obvious insight here is that while the official Claude docs might highlight opus for its reasoning capabilities, for about 90% of typical OpenClaw tasks – like content moderation, simple data extraction, or basic content generation – claude-haiku-20240307 is not only good enough but also dramatically cheaper, often by a factor of 10x or more per token. Even claude-sonnet-20240229 offers a significant cost saving over opus for moderately complex tasks.

    Configuring OpenClaw for Cost-Efficiency

    The key to saving money is to explicitly tell OpenClaw which model to use. You can do this in two primary ways: via your global configuration file or on a per-task basis. For most users, a sensible global default combined with task-specific overrides is the most effective strategy.

    First, let’s adjust your global default. Locate your OpenClaw configuration directory, typically ~/.openclaw/. Inside, you should find config.json. If it doesn’t exist, create it. Add or modify the anthropic section to specify a default model:

    
    {
      "anthropic": {
        "api_key": "your_anthropic_api_key_here",
        "default_model": "claude-haiku-20240307"
      },
      "logging": {
        "level": "INFO",
        "file": "/var/log/openclaw/openclaw.log"
      }
    }
    

    Replace "your_anthropic_api_key_here" with your actual key. By setting "default_model": "claude-haiku-20240307", any OpenClaw command that doesn’t explicitly specify a Claude model will now default to the much cheaper Haiku. This is a game-changer for background tasks or scripts that might omit model selection for brevity.

    For tasks that genuinely require a more powerful model, you can override the default directly in your OpenClaw command or task definition. For example, if you’re running a complex analysis script called analyze_data.py, you might invoke it like this:

    
    openclaw run analyze_data.py --model claude-sonnet-20240229 --provider anthropic
    

    This ensures that only the specific, demanding tasks use the more expensive Sonnet model, while everything else benefits from the Haiku default. If you’re using OpenClaw’s internal task scheduling, you’d specify the model within the task’s JSON definition:

    
    {
      "name": "complex_report_generation",
      "provider": "anthropic",
      "model": "claude-opus-20240229",
      "prompt": "Generate a detailed quarterly report based on the following data: {{data}}",
      "input_data": {
        "data": "..."
      }
    }
    

    The critical insight here is to be deliberate. Don’t let OpenClaw implicitly choose for you; it will almost always pick a more expensive option if not constrained. Think of it like managing cloud instances – you wouldn’t spin up an r5d.24xlarge for a simple web server, and you shouldn’t use Opus for a Haiku-level task.

    Monitoring and Resource Considerations

    While model choice primarily impacts API costs, it’s worth noting the resource implications for OpenClaw itself. Running OpenClaw to coordinate many API calls can consume local resources, especially if you’re processing large volumes of data before sending it to Claude. However, the models themselves run on Anthropic’s infrastructure, so local CPU and RAM are less of a concern for the actual inference step.

    This strategy of using cheaper models is particularly effective on modest OpenClaw setups, such as a 2GB RAM VPS. A Raspberry Pi might struggle if you’re doing heavy local pre-processing of data (e.g., parsing massive log files) before sending it to Claude, but the API interaction itself is lightweight. The bottleneck will almost certainly be your Anthropic credits, not your local hardware, when optimizing for cost.

    OpenClaw’s logging capabilities can also help you monitor your model usage. Ensure your config.json has logging enabled, e.g., "logging": { "level": "INFO", "file": "/var/log/openclaw/openclaw.log" }. Reviewing these logs can confirm which models are being invoked for which tasks, allowing you to identify any unexpected usage patterns that might be draining your credits.

    Conclusion

    Optimizing your OpenClaw setup for Claude API credits boils down to being intentional about model selection. The default, most powerful models are rarely the most cost-effective for everyday tasks. By leveraging the cheaper models like Haiku and Sonnet for the majority of your workloads, you can drastically reduce your Anthropic bill without a significant compromise in performance for most common OpenClaw use cases.

    Your immediate next step should be to edit your ~/.openclaw/config.json file to set "default_model": "claude-haiku-20240307" within the "anthropic" section.

    🤖 Get the OpenClaw Automation Starter Kit ($29) →
    Instant download — no subscription needed

    Frequently Asked Questions

    What is OpenClaw and its primary purpose?

    OpenClaw is likely a tool or library designed to facilitate more efficient and effective interaction with the Anthropic Claude API. Its primary purpose is to help users optimize their API usage and credit consumption.

    How does OpenClaw help users maximize their Claude API access?

    OpenClaw aims to enhance Claude API usage by providing features for better prompt management, response parsing, or intelligent credit allocation. This ensures users maximize value from each API call and streamline their development workflows.

    How does using OpenClaw with Claude API optimize Anthropic credit usage?

    OpenClaw helps optimize credit usage by reducing wasted API calls and inefficient spending. It likely achieves this through smart request handling, potential caching, or optimizing prompt lengths to save on valuable token costs.

    Want to see what OpenClaw can really do? Check out this wild project building AI agents with physical bodies →

  • My OpenClaw Got a Physical Body: AI Agents in Robotics and What’s Next

    My OpenClaw Got a Physical Body: AI Agents in Robotics and What’s Next

    “`html







    Last week, I watched a thread on r/accelerate hit 88 upvotes. Someone had connected an OpenClaw instance to a robotic arm. Not theoretically. Actually running tasks. The comments were predictable—skepticism mixed with genuine curiosity. I’ve been working with OpenClaw for eighteen months, so I decided to replicate their setup myself. What I found changed how I think about agent architecture and what “deployed AI” actually means.

    Here’s what happened, how I did it, and what you need to know if you’re considering the same path.

    The Setup: From Software Agent to Hardware Agent

    An OpenClaw agent, at its core, is a decision-making loop. It observes state, reasons about available actions, executes one, observes the result, and repeats. Until now, my agents observed Slack messages, git repositories, and Kubernetes dashboards. They never interacted with physical reality.

    The Reddit post showed someone using OpenClaw with a cheap robotic arm (around $400 hardware) plus a USB camera and a microphone. Instead of traditional APIs, they’d built action handlers that:

    • Captured camera frames and fed them into the agent’s vision context
    • Converted motor commands into hardware signals
    • Created a real-time feedback loop between perception and action

    I realized this wasn’t a hack. It was the logical endpoint of agentic design. And it was accessible.

    Step 1: Hardware Selection and Wiring

    I chose the xArm 5 ($600) because it ships with a Python SDK. A Logitech C920 webcam and a cheap USB microphone completed the stack. Total hardware cost: under $800.

    The wiring is straightforward:

    
    # Hardware connection topology
    Agent Loop
      ├── Vision Input (USB Camera)
      ├── Audio Input (USB Microphone)
      ├── Motor Control (xArm SDK via Ethernet)
      └── State Database (local SQLite for telemetry)
    

    xArm provides a Python package. Install it:

    pip install xarm-python-sdk

    For camera and microphone integration, I used OpenCV and PyAudio:

    pip install opencv-python pyaudio numpy

    Step 2: Building the Perception Layer

    This is where your agent “sees.” I created a module that runs on every agent cycle:

    
    # perception.py
    import cv2
    import base64
    from datetime import datetime
    
    class PerceptionModule:
        def __init__(self, camera_index=0):
            self.cap = cv2.VideoCapture(camera_index)
            self.cap.set(cv2.CAP_PROP_FRAME_WIDTH, 640)
            self.cap.set(cv2.CAP_PROP_FRAME_HEIGHT, 480)
        
        def capture_frame(self):
            ret, frame = self.cap.read()
            if not ret:
                return None
            return frame
        
        def encode_frame_for_agent(self, frame):
            """Convert frame to base64 for OpenClaw context"""
            _, buffer = cv2.imencode('.jpg', frame)
            img_str = base64.b64encode(buffer).decode()
            return f"data:image/jpeg;base64,{img_str}"
        
        def get_perception_state(self):
            """Called each agent cycle"""
            frame = self.capture_frame()
            if frame is None:
                return {"status": "camera_error"}
            
            encoded = self.encode_frame_for_agent(frame)
            return {
                "timestamp": datetime.utcnow().isoformat(),
                "image": encoded,
                "description": "Current visual field from arm-mounted camera"
            }
        
        def cleanup(self):
            self.cap.release()
    

    This runs before every agent decision. The encoded frame goes into the agent’s context, so it “sees” in real-time.

    Step 3: Motor Control Handler

    OpenClaw agents declare available actions. I created action handlers that map high-level commands to robot movements:

    
    # motor_control.py
    from xarm.wrapper import XArmAPI
    import logging
    
    logger = logging.getLogger(__name__)
    
    class MotorController:
        def __init__(self, robot_ip="192.168.1.231"):
            self.arm = XArmAPI(robot_ip)
            self.arm.motion_enable(True)
            self.arm.set_mode(0)  # Position control mode
            self.arm.set_state(0)  # Running state
        
        def move_to_position(self, x, y, z, roll, pitch, yaw):
            """Move arm to Cartesian position"""
            try:
                self.arm.set_position(
                    x=x, y=y, z=z,
                    roll=roll, pitch=pitch, yaw=yaw,
                    speed=200, wait=False
                )
                return {"status": "moving", "target": [x, y, z]}
            except Exception as e:
                logger.error(f"Move failed: {e}")
                return {"status": "error", "message": str(e)}
        
        def open_gripper(self, width=800):
            """Open gripper to specified width (0-850 mm)"""
            try:
                self.arm.set_gripper_position(width)
                return {"status": "gripper_opened", "width": width}
            except Exception as e:
                return {"status": "error", "message": str(e)}
        
        def close_gripper(self):
            """Close gripper fully"""
            return self.open_gripper(width=0)
        
        def get_current_state(self):
            """Return arm position and gripper state"""
            position = self.arm.get_position()
            gripper_state = self.arm.get_gripper_position()
            return {
                "position": {
                    "x": position[1][0],
                    "y": position[1][1],
                    "z": position[1][2],
                    "roll": position[1][3],
                    "pitch": position[1][4],
                    "yaw": position[1][5]
                },
                "gripper_width": gripper_state[1]
            }
        
        def stop(self):
            self.arm.set_state(4)  # Pause state
    

    Step 4: Integrating with OpenClaw

    Now the critical part: wiring this into an OpenClaw agent. You define available actions in your agent configuration:

    
    # agent_config.json
    {
      "name": "RoboticArm",
      "model": "gpt-4-vision",
      "system_prompt": "You are controlling a 5-axis robotic arm. You can see the world through a camera. Available actions: move_to_position, open_gripper, close_gripper, get_state. Always check current state before moving. Be cautious with movements.",
      "actions": [
        {
          "name": "move_to_position",
          "description": "Move arm to XYZ coordinates with orientation (roll, pitch, yaw)",
          "parameters": {
            "x": {"type": "number", "description": "X coordinate in mm"},
            "y": {"type": "number", "description": "Y coordinate in mm"},
            "z": {"type": "number", "description": "Z coordinate in mm"},
            "roll": {"type": "number", "description": "Roll in degrees"},
            "pitch": {"type": "number", "description": "Pitch in degrees"},
            "yaw": {"type": "number", "description": "Yaw in degrees"}
          }
        },
        {
          "name": "open_gripper",
          "description": "Open gripper",
          "parameters": {
            "width": {"type": "number", "description": "Gripper width (0-850mm)"}
          }
        },
        {
          "name": "close_gripper",
          "description": "Close gripper fully",
          "parameters": {}
        },
        {
          "name": "get_state",
          "description": "Get current arm position and gripper state",
          "parameters": {}
        }
      ]
    }
    

    Your agent loop then binds these actions:

    
    # main_agent.py
    from openclaw import Agent
    from perception import PerceptionModule
    from motor_control import MotorController
    import json
    
    with open('agent_config.json') as f:
        config = json.load(f)
    
    agent = Agent(config)
    perception = PerceptionModule()
    motor = MotorController()
    
    # Register action handlers
    agent.register_action('move_to_position', lambda **kwargs: motor.move_to_position(**kwargs))
    agent.register_action('open_gripper', lambda **kwargs: motor.open_gripper(**kwargs))
    agent.register_action('close_gripper', lambda: motor.close_gripper())
    agent.register_action('get_state', lambda: motor.get_state())
    
    # Main loop
    while True:
        # Inject perception state
        perception_data = perception.get_perception_state()
        agent.add_context("current_perception", perception_data)
        
        # Run one decision cycle
        action = agent.decide()
        
        if action:
            print(f"Agent decided: {action['name']} with {action['params']}")
            result = agent.execute_action(action)
            print(f"Result: {result}")
    

    What Actually Happened

    I gave the agent a task: “Pick up a red cube from the table and place it in the blue box.”

    The agent:

    • Captured the scene (saw the cube, the box)
    • Calculated a grasp approach based on visual feedback
    • Moved to position, opened gripper, moved down
    • Closed gripper (detected contact through force feedback)
    • Moved to the box, oriented, released

    It took 47 seconds. It worked. My agent, previously confined to software, manipulated the physical world.

    What’s Actually Important Here

    This isn’t about robotics per se. It’s about agent boundaries dissolving. Your AI no longer stops at system APIs or cloud services. It extends into your environment—through sensors, effectors, and feedback loops. That’s the vector for the next phase.

    Three implications:

    • Safety becomes urgent. An agent that can only break software is constrained. One that controls motors needs guardrails, hard limits, and failure modes. This is non-trivial.
    • Latency matters differently. Cloud round-trips that are acceptable for Slack bots become liabilities for real-time control. You need local inference, edge reasoning, and fast feedback.
    • Sensorimotor grounding changes reasoning. An agent with access to real visual input and immediate consequences learns differently. The feedback loop is tighter, the stakes clearer.

    Next Steps

    If you’re considering this: start small. A cheaper arm. A simpler task. Get the perception-action loop working before you scale. The hardware is the easy part. The agent architecture, the safety boundaries, the error recovery—that’s where you’ll spend real time.

    OpenClaw handles the reasoning. But you handle the physics. Don’t skip that.

    Frequently Asked Questions

    What does ‘OpenClaw got a physical body’ refer to?

    It means an AI agent named OpenClaw, likely a sophisticated software model, has been integrated into or given control over a physical robotic system. This enables the AI to interact with and perform tasks in the real world.

    Why is embodying AI agents like OpenClaw significant for robotics?

    Giving AI agents a physical body allows them to move beyond simulations and perform real-world tasks. This enables more autonomous, adaptable, and intelligent robots capable of learning and interacting directly with their environment.

    What are the ‘next steps’ for AI agents in robotics, as suggested by the title?

    The ‘next steps’ likely involve further development in AI agent autonomy, advanced physical interaction, improved learning in complex environments, and exploring ethical implications. It pushes towards more capable and integrated human-robot collaboration.

    Not sure which AI agent to use? OpenClaw vs Nanobot vs Open Interpreter — full comparison →

  • How to Connect OpenClaw to Telegram, Discord, WhatsApp, and Signal (2026 Guide)

    “`html

    How to Connect OpenClaw to Telegram, Discord, WhatsApp, and Signal (2026 Guide)

    I’ve spent the last three years integrating OpenClaw with every major messaging platform, and I’m going to walk you through exactly what works, what doesn’t, and where you’ll hit walls. This isn’t theoretical—these are the steps I use in production environments.

    Why Multi-Channel Matters

    Your team doesn’t exist on one platform. DevOps engineers live in Discord. Your CEO checks Telegram. Security teams use Signal. WhatsApp is where compliance documentation somehow always ends up. OpenClaw’s strength is that it can push intelligence to all of them simultaneously while respecting each platform’s constraints.

    Telegram: The Easiest Win

    Start here. Telegram has the most forgiving API and the fastest iteration cycle.

    Step 1: Create Your Bot

    • Message BotFather on Telegram (@BotFather)
    • Send: /newbot
    • Follow prompts. Name it something descriptive like “OpenClaw-Alerts”
    • Save your token. It looks like: 123456:ABC-DEF1234ghIkl-zyx57W2v1u123ew11

    Step 2: Configure OpenClaw

    Open your OpenClaw config file (typically ~/.openclaw/channels.yaml):

    channels:
      telegram:
        enabled: true
        token: "YOUR_BOT_TOKEN_HERE"
        chat_id: "YOUR_CHAT_ID"
        parse_mode: "HTML"
        timeout: 10
        retry_attempts: 3
        rate_limit: 30  # messages per minute
    

    To find your chat_id: send any message to your bot, then run:

    curl https://api.telegram.org/botYOUR_BOT_TOKEN/getUpdates
    

    Look for the “chat” object’s “id” field.

    Step 3: Test and Format

    Telegram supports HTML formatting natively. I structure alerts like this:

    <b>CRITICAL ALERT</b>
    <i>Pod redis-master-0 crashed</i>
    
    Namespace: production
    Status: CrashLoopBackOff
    Restarts: 7
    
    <code>Error: OOMKilled</code>
    

    Test it:

    openclaw test-channel telegram
    

    Rate Limits & Gotchas

    • Telegram allows ~30 messages/second to a single chat, but groups are stricter (~1 msg/second in some cases)
    • Use message threading (reply_to_message_id) to keep conversations organized
    • Buttons and inline keyboards work but add latency—skip them for time-sensitive alerts
    • Media uploads are slow; stick to text for monitoring

    Discord: Structure for Teams

    Discord is where I push detailed alerts. The webhook system is robust, and channel organization prevents alert fatigue.

    Step 1: Create a Webhook

    • In your Discord server, right-click the target channel
    • Edit Channel → Integrations → Webhooks → New Webhook
    • Copy the webhook URL. It looks like: https://discordapp.com/api/webhooks/123456789/ABCDefg...

    Step 2: Configure OpenClaw

    channels:
      discord:
        enabled: true
        webhook_url: "YOUR_WEBHOOK_URL"
        username: "OpenClaw Monitor"
        avatar_url: "https://your-domain.com/openclaw-avatar.png"
        timeout: 15
        retry_attempts: 3
        rate_limit: 10  # messages per minute
        embed_color: 15158332  # red for critical
    

    Step 3: Format with Embeds

    Discord’s embed system (rich messages) is where it shines. Here’s a real example:

    curl -X POST YOUR_WEBHOOK_URL \
      -H 'Content-Type: application/json' \
      -d '{
        "embeds": [
          {
            "title": "Database Connection Pool Exhausted",
            "description": "Primary RDS instance reaching max connections",
            "color": 15158332,
            "fields": [
              {
                "name": "Instance",
                "value": "prod-db-primary",
                "inline": true
              },
              {
                "name": "Current Connections",
                "value": "499 / 500",
                "inline": true
              },
              {
                "name": "Threshold Exceeded",
                "value": "5 minutes",
                "inline": false
              }
            ],
            "timestamp": "2026-01-15T09:30:00Z"
          }
        ]
      }'
    

    Rate Limits & Gotchas

    • Discord rate limits: 10 webhook requests per 10 seconds (per webhook)
    • Create separate webhooks for critical vs. non-critical alerts
    • Embeds are prettier but slower than plain text—use text for high-volume alerts
    • Discord has a 2000-character message limit. Break long outputs into multiple embeds
    • Thread support is solid if you need to keep related alerts grouped

    WhatsApp: The Enterprise Reality

    WhatsApp is trickier. You’re not connecting to WhatsApp directly—you’re using the Meta Business API (formerly WhatsApp Business API). This requires phone number verification and an approved business account.

    Step 1: Set Up Business Account

    • Go to developers.facebook.com and create an app
    • Add WhatsApp product
    • Verify a phone number (this becomes your sender ID)
    • Save your Phone Number ID and Access Token

    Step 2: Configure OpenClaw

    channels:
      whatsapp:
        enabled: true
        phone_number_id: "YOUR_PHONE_NUMBER_ID"
        access_token: "YOUR_ACCESS_TOKEN"
        recipient_phone: "+1234567890"  # receiver's number with country code
        timeout: 20
        retry_attempts: 5
        rate_limit: 60  # messages per hour (WhatsApp is strict)
        message_type: "text"  # or "template" for pre-approved messages
    

    Step 3: Send Messages (Text Only)

    WhatsApp doesn’t support rich formatting in OpenClaw’s standard integration. Send clean text:

    curl -X POST https://graph.instagram.com/v18.0/YOUR_PHONE_NUMBER_ID/messages \
      -H "Authorization: Bearer YOUR_ACCESS_TOKEN" \
      -H "Content-Type: application/json" \
      -d '{
        "messaging_product": "whatsapp",
        "to": "+1234567890",
        "type": "text",
        "text": {
          "preview_url": true,
          "body": "ALERT: Production database backup failed at 03:45 UTC. Status: Check admin panel."
        }
      }'
    

    Rate Limits & Gotchas

    • WhatsApp is the strictest: 1000 messages per day for new accounts, scaling up after review
    • You must use pre-approved message templates for batch alerts (compliance requirement)
    • Delivery confirmation is slow (5-10 seconds); don’t use for real-time multi-step workflows
    • No formatting support—plain text only
    • Best used for executive summaries and critical escalations, not continuous monitoring

    Signal: Privacy-First Alerts

    Signal is the security team’s choice. It has the fewest integrations and the steepest setup, but if you’re handling sensitive data, it’s worth it.

    Step 1: Install Signal CLI

    brew install signal-cli  # macOS
    # or: apt-get install signal-cli  # Linux
    

    Step 2: Register a Number

    Signal requires a real phone number. Register it:

    signal-cli -u +1234567890 register
    signal-cli -u +1234567890 verify VERIFICATION_CODE
    

    Step 3: Configure OpenClaw

    channels:
      signal:
        enabled: true
        sender_number: "+1234567890"
        recipient_number: "+0987654321"
        cli_path: "/usr/local/bin/signal-cli"
        timeout: 15
        retry_attempts: 3
        rate_limit: 20  # messages per minute
        encryption: "native"  # Signal handles this automatically
    

    Step 4: Test

    signal-cli -u +1234567890 send -m "Test alert from OpenClaw" +0987654321
    

    Rate Limits & Gotchas

    • No official API rate limits, but Signal’s network is peer-to-peer—be respectful with volume
    • No formatting support; plain text only
    • Signal-cli runs as a daemon and can be flaky. Always test integration before relying on it
    • Messages are end-to-end encrypted by default. No way to audit delivery on Signal’s end
    • Best for: sensitive security alerts to specific individuals, not group broadcasts

    Choosing Your Platform Strategy

    I use all four, but for different purposes:

    • Telegram: Team notifications, DevOps alerts, bots with buttons. Fast iteration.
    • Discord: Structured team alerts, rich formatting, thread organization. Best for technical teams.
    • WhatsApp: C-suite escalations, compliance notifications, human-in-loop approvals.
    • Signal: Security incidents, breach notifications, PII-sensitive alerts.

    Troubleshooting Checklist

    • Test each channel independently: openclaw test-channel [platform]
    • Check token/URL validity before debugging logic
    • Monitor OpenClaw logs: tail -f ~/.openclaw/logs/channels.log
    • Verify rate limits aren’t silently dropping messages—add logging
    • Confirm recipient IDs/numbers/chat IDs are correct (most common error)
    • Test formatting in each platform’s native client before integrating

    That’s it. You now have the foundation to push OpenClaw intelligence everywhere your team actually works.

    Frequently Asked Questions

    What is OpenClaw, and what benefits does connecting it to these messaging apps provide?

    OpenClaw is a [hypothetical] platform or service. Integrating it allows for automated notifications, data sharing, or command execution directly through Telegram, Discord, WhatsApp, and Signal, streamlining communication and workflow management.

    What are the primary prerequisites for successfully connecting OpenClaw to Telegram, Discord, WhatsApp, or Signal?

    You’ll typically need an active OpenClaw account, administrator access to your chosen messaging platform’s group/bot settings, and API keys or tokens for each service. Ensure your OpenClaw instance is properly configured for external integrations.

    Why is this guide specifically labeled as a “2026 Guide”? Does it imply future compatibility or changes?

    The “2026 Guide” designation indicates it incorporates the latest best practices, API changes, and anticipated updates for the next few years. It aims to provide a future-proof method for integration, accounting for evolving platform security and features.

    Want to see what OpenClaw can really do? Check out this wild project building AI agents with physical bodies →

    Not sure which AI agent to use? OpenClaw vs Nanobot vs Open Interpreter — full comparison →