Category: Configuration & Tuning

Configure, tune, and customize OpenClaw — memory files, API keys, gateway, and settings.

  • OpenClaw TTS and Voice: How to Get Audio Responses From Your AI

    If you’re running OpenClaw and want to move beyond text-only conversations, integrating Text-to-Speech (TTS) to get audio responses from your AI is a game-changer. This note will guide you through setting up TTS, specifically focusing on leveraging cloud-based services for quality and efficiency, and how to configure OpenClaw to use them. We’ll cover the practical steps and common pitfalls, especially for those running OpenClaw on typical Linux server environments.

    Choosing Your TTS Provider

    OpenClaw supports various TTS providers, but the choice often comes down to cost, quality, and ease of integration. While local TTS engines exist, they often consume significant CPU and memory, which can be problematic on resource-constrained VPS instances or even beefier machines if you’re running multiple OpenClaw instances. For most users, cloud-based providers offer superior quality and a more “fire-and-forget” experience.

    I generally recommend Google Cloud Text-to-Speech or Eleven Labs for their balance of quality and competitive pricing. AWS Polly is another excellent option. For this guide, we’ll primarily focus on Google Cloud Text-to-Speech due to its generous free tier and straightforward API setup, which aligns well with OpenClaw’s configuration model.

    To use Google Cloud TTS, you’ll need a Google Cloud Platform (GCP) project with the Text-to-Speech API enabled. If you don’t have one, navigate to the GCP Console, create a new project, and then search for “Text-to-Speech API” in the marketplace to enable it. You’ll also need to create a service account key file, which OpenClaw will use to authenticate. Go to “IAM & Admin” > “Service Accounts”, create a new service account, grant it the “Cloud Text-to-Speech User” role, and then create a new JSON key file. Download this file and place it in a secure, accessible location on your OpenClaw server, for example, at ~/.openclaw/google_credentials.json.

    Configuring OpenClaw for TTS

    Once you have your chosen TTS provider credentials ready, you need to tell OpenClaw how to use them. This is done through your main OpenClaw configuration file, typically located at ~/.openclaw/config.json. If this file doesn’t exist, create it.

    Here’s a snippet for configuring Google Cloud TTS:

    
    {
      "tts": {
        "provider": "google_cloud",
        "google_cloud": {
          "credentials_path": "/home/youruser/.openclaw/google_credentials.json",
          "voice_name": "en-US-Standard-C",
          "audio_encoding": "MP3",
          "speaking_rate": 1.0,
          "pitch": 0.0
        },
        "output_dir": "/tmp/openclaw_audio_cache"
      },
      "default_model": "claude-3-haiku-20240307",
      "llm_providers": {
        "anthropic": {
          "api_key": "sk-..."
        }
      }
    }
    

    Let’s break down the tts section:

    • "provider": "google_cloud": This explicitly tells OpenClaw to use Google Cloud for TTS. If you were using Eleven Labs, this would be "eleven_labs".
    • "google_cloud": This block contains provider-specific settings.
      • "credentials_path": "/home/youruser/.openclaw/google_credentials.json": This is crucial. Replace /home/youruser/ with the actual path to the JSON key file you downloaded. Make sure the OpenClaw process has read permissions for this file.
      • "voice_name": "en-US-Standard-C": This specifies the exact voice to use. Google offers many, from standard to AI-powered WaveNet voices. WaveNet voices (e.g., en-US-Wavenet-C) sound more natural but are typically more expensive. Experiment to find one that suits your needs and budget.
      • "audio_encoding": "MP3": MP3 is a widely supported format and generally offers a good balance of quality and file size. Other options might include LINEAR16 (raw PCM) or OGG_OPUS.
      • "speaking_rate" and "pitch": These allow you to fine-tune the delivery. 1.0 is normal speed, 0.0 is normal pitch.
    • "output_dir": "/tmp/openclaw_audio_cache": OpenClaw will cache generated audio files here to avoid re-generating the same responses. This is a good optimization. Ensure this directory exists and is writable by the OpenClaw user. I often use /tmp for temporary files, but a persistent location like ~/.openclaw/audio_cache is also fine if you want the cache to survive reboots.

    If you opt for Eleven Labs, the configuration would look something like this:

    
    {
      "tts": {
        "provider": "eleven_labs",
        "eleven_labs": {
          "api_key": "YOUR_ELEVENLABS_API_KEY",
          "voice_id": "21m00Tcm4azwk8nxvUGp",
          "model_id": "eleven_multilingual_v2"
        },
        "output_dir": "/tmp/openclaw_audio_cache"
      }
    }
    

    You’d replace YOUR_ELEVENLABS_API_KEY with your actual API key and voice_id with the ID of your chosen Eleven Labs voice. You can find these on your Eleven Labs dashboard.

    Playing the Audio Responses

    Configuring TTS in OpenClaw only generates the audio files. To actually hear them, your OpenClaw client needs to play them. This is where the client-side implementation comes in. If you’re using a custom OpenClaw client, you’ll need to implement audio playback functionality that receives the path to the generated audio file from the OpenClaw backend and plays it. For example, if your client is a web application, it would receive a URL to the MP3 file and play it using HTML5 audio elements. If it’s a desktop client, it would use a local audio library.

    For command-line interactions or basic testing, you might manually play the files. After OpenClaw generates a response with TTS enabled, it will output the path to the generated audio file. You can then use a command-line player like mpg123 or ffplay to listen to it:

    
    mpg123 /tmp/openclaw_audio_cache/some_generated_audio_file.mp3
    

    This is a limitation often overlooked: OpenClaw itself, running as a backend service, doesn’t directly “play” audio to your speakers unless it’s running on a desktop environment with an active audio output. It’s designed to provide the audio stream or file path to a client that then handles playback. If you’re on a headless VPS, the audio is generated but not heard by default. Your client application needs to be responsible for fetching and playing it.

    Non-Obvious Insight: Caching and Costs

    The output_dir for caching is more important than it seems. TTS API calls, especially for high-quality voices, accrue costs. By caching responses, OpenClaw avoids redundant API calls for identical prompts, significantly reducing your operational costs over time. This is particularly useful for common phrases or repeated interactions where the AI might say the same thing multiple times. Ensure your cache directory is adequately sized and regularly cleaned if you have storage constraints.

    Another insight: while it’s tempting to always go for the most natural-sounding WaveNet or premium Eleven Labs voices, they come at a higher cost. For internal tools or less critical applications, a standard voice might be perfectly acceptable and dramatically cheaper. Benchmark different voices against your budget and use case.

    Limitations

    This TTS setup primarily focuses on generating audio on the server side using cloud APIs. It does not provide real-time, low-latency voice interaction suitable for direct voice calls unless your client is specifically engineered for that. The latency will include the time for the LLM response, the TTS API call, network transfer, and client-side playback. For simple query-response interactions, this latency is generally acceptable.

    Resource usage on

    Want better responses from OpenClaw? Learn how to write better agent prompts →

  • The Complete Guide to OpenClaw TOOLS.md: Organizing Credentials and API Keys

    If you’re deploying OpenClaw agents on a Hetzner VPS and finding yourself constantly SSH’ing in to update API keys or wondering how to securely manage credentials for different tools, you’ve likely hit the wall of plain text files and environment variables. The TOOLS.md file in OpenClaw isn’t just for defining tools; it’s a critical, often underutilized, mechanism for organizing and securing your agent’s access to external services. The official documentation hints at its capabilities, but the real power lies in leveraging its structured format with environment variable substitution and a robust directory structure for different deployment scenarios.

    Understanding OpenClaw’s Credential Resolution

    OpenClaw’s TOOLS.md works by defining tools, their capabilities, and crucially, their authentication mechanisms. While you can hardcode API keys directly into TOOLS.md, this is a terrible practice for security and maintainability. A better approach is to use environment variables. OpenClaw processes TOOLS.md and replaces placeholders like {{ENV_VAR_NAME}} with the actual values from the environment where the OpenClaw agent is running. This allows you to keep sensitive information out of your version-controlled files.

    For example, a tool definition for an OpenAI API call might look like this in your TOOLS.md:

    # OpenAI Text Generation
    
  • name: openai_text_generator
  • description: Generates text using OpenAI's models. schema: type: object properties: model: type: string enum: ["gpt-4o", "gpt-3.5-turbo"] description: The model to use. prompt: type: string description: The prompt for text generation. required: ["model", "prompt"] call: | import openai import os client = openai.OpenAI(api_key=os.getenv("OPENAI_API_KEY")) response = client.chat.completions.create( model=args["model"], messages=[{"role": "user", "content": args["prompt"]}] ) print(response.choices[0].message.content)

    Notice the os.getenv("OPENAI_API_KEY"). This is the standard Python way to fetch an environment variable, and OpenClaw’s tool execution environment respects it. The key insight here is that OpenClaw executes the call block as a standard Python script. Anything you can do in Python, including fetching environment variables or even reading from secure files, you can do here.

    Organizing Credentials with .env Files and Systemd

    For a single agent, managing environment variables via a .env file is straightforward. You can place a file named .env in your OpenClaw project root:

    # .env
    OPENAI_API_KEY="sk-your-openai-key"
    ANTHROPIC_API_KEY="sk-ant-your-anthropic-key"
    HETZNER_API_TOKEN="hz-your-hetzner-token"
    

    Then, when you launch your OpenClaw agent, ensure these variables are loaded. If you’re using a simple Python script to run your agent, you can manually load them:

    # run_agent.py
    from dotenv import load_dotenv
    import os
    # ... other OpenClaw imports
    
    load_dotenv() # This will load variables from .env into os.environ
    
    # Now you can instantiate and run your agent
    # agent = OpenClawAgent(...)
    

    However, for production deployments on a Hetzner VPS, especially if you’re using Systemd to manage your OpenClaw agent as a service, directly using .env files might not be the most robust approach. Systemd offers a more integrated way to handle environment variables securely.

    Create a Systemd unit file, for example, /etc/systemd/system/openclaw-agent.service:

    [Unit]
    Description=OpenClaw Agent Service
    After=network.target
    
    [Service]
    User=openclaw_user
    Group=openclaw_group
    WorkingDirectory=/path/to/your/openclaw/project
    ExecStart=/usr/bin/python3 /path/to/your/openclaw/project/run_agent.py
    Environment="OPENAI_API_KEY=sk-your-openai-key-from-systemd"
    Environment="ANTHROPIC_API_KEY=sk-ant-your-anthropic-key-from-systemd"
    # ... more environment variables
    
    # Or, if you prefer to source a file (less secure as file might be readable):
    # EnvironmentFile=/path/to/your/credentials.env
    
    Restart=always
    RestartSec=5
    
    [Install]
    WantedBy=multi-user.target
    

    The Environment= directive is powerful. It allows you to specify environment variables directly within the Systemd unit file. For highly sensitive keys, you might store these in a more restricted file, owned by root and readable only by the openclaw_user, and then use EnvironmentFile= to source them. However, for most VPS scenarios, embedding them directly in the Systemd unit, which typically has tight permissions, is a reasonable balance between security and convenience. Remember to run sudo systemctl daemon-reload and sudo systemctl start openclaw-agent after making changes.

    The Non-Obvious Insight: Dynamic Tool Loading and Environment-Specific Configurations

    Here’s where it gets interesting: what if you have multiple agents, or different environments (development, staging, production), each needing different API keys or even different sets of tools? Hardcoding everything or having one monolithic TOOLS.md quickly becomes unmanageable.

    OpenClaw allows you to load tools from multiple TOOLS.md files. You can specify a directory, and it will load all .md files within it. This enables a modular approach:

    .
    ├── .openclaw/
    │   └── config.json
    ├── agents/
    │   └── financial_analyst_agent.py
    │   └── customer_support_agent.py
    ├── tools/
    │   ├── core_utils.md
    │   ├── openai_tools.md
    │   ├── anthropic_tools.md
    │   └── custom_crm_tools.md
    └── .env # For local development
    

    Your .openclaw/config.json could then point to the tools/ directory:

    # .openclaw/config.json
    {
      "tools_path": "tools/",
      "model": "gpt-4o",
      "temperature": 0.7
    }
    

    Now, each .md file in the tools/ directory can define a specific set of tools. For example, openai_tools.md would contain only OpenAI-related tools, while anthropic_tools.md would contain Anthropic ones. Both would use os.getenv() to fetch their respective API keys.

    This structure shines when combined with environment-specific credential management. In development, you might use a .env file. In production, your Systemd unit file or a secrets management system (like Vault or AWS Secrets Manager) would inject the environment variables. The TOOLS.md files themselves remain unchanged, making them portable across environments. The only thing that changes is *how* the environment variables are provided.

    Furthermore, for specific agents requiring a subset of tools, you don’t even need to load all of them. You can pass a list of specific tool paths to your agent initialization:

    # agents/financial_analyst_agent.py
    from openclaw.agent import OpenClawAgent
    
    # Assuming your config.json is set up, this will load all tools from 'tools/'
    # agent = OpenClawAgent(config_path=".openclaw/config.json")
    
    # Or, for more granular control:
    agent = OpenClawAgent(
        tools_paths=["tools/core_utils.md", "tools/openai_tools.md"],
        model="gpt-4o",
        temperature=0.7
    )
    # ... run the agent
    

    This allows for fine-grained control over which tools (and thus which corresponding API keys) are exposed to a particular agent instance. Imagine a ‘public’ agent only having access to basic utilities, while an ‘admin’ agent has access to sensitive CRM tools. Each can have its dedicated TOOLS.md file or be

    Want better responses from OpenClaw? Learn how to write better agent prompts →

  • The Best OpenClaw AGENTS.md Setup I’ve Found After Testing 5 Versions

    If you’ve been experimenting with OpenClaw and feeling like your agents are either too verbose, not following instructions, or just plain expensive, you’re not alone. I’ve spent the last month iterating on my AGENTS.md file, trying to find the sweet spot between performance, cost, and output quality. The official examples are a great starting point, but they often lead to agents that overthink or consume too many tokens. This isn’t just about prompt engineering; it’s about structuring the AGENTS.md file itself to leverage OpenClaw’s capabilities efficiently. My setup, which I’ll detail below, focuses on a multi-agent approach where each agent has a very specific, limited role, and communication is explicit.

    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 Problem with Monolithic Agents

    My initial approach, like many I’ve seen, was to create a single “Super Agent” designed to handle an entire complex task from start to finish. For example, an agent named ContentCreator would be responsible for generating an article idea, outlining it, writing sections, and then refining the whole thing. While this sounds intuitive, it quickly became problematic. The context window would balloon, leading to higher token usage and increased latency. More critically, the agent would often “forget” earlier instructions or get sidetracked, requiring extensive prompt tuning and frequent human intervention. Debugging became a nightmare because it was hard to pinpoint exactly where the agent went off track. The cost also escalated rapidly, especially when using larger models like claude-opus-20240229.

    Introducing the Specialized Multi-Agent Framework

    The breakthrough for me came when I realized OpenClaw excels when agents are highly specialized and tasks are broken down into granular steps. Instead of one large agent, I now use a chain of smaller, focused agents. Each agent has a single responsibility, and they pass their output to the next agent in the chain. This mirrors a traditional software pipeline and makes debugging significantly easier. If the final output is bad, I can examine the output of each preceding agent to find the bottleneck. This also allows for more flexible model selection; I can use cheaper, faster models for simpler tasks and reserve more powerful (and expensive) models for steps requiring deeper reasoning.

    Here’s a snippet of my refined AGENTS.md structure:

    # AGENTS.md
    
    

    Agent: TaskDeconstructor

    Model: claude-haiku-20240307 Temperature: 0.2 System Prompt: You are an expert task breakdown specialist. Given a user's high-level request, you will break it down into a list of specific, actionable sub-tasks. Each sub-task should be clear enough for another specialized agent to execute independently. Focus on logical sequential steps. Instructions:
  • Output a numbered list of sub-tasks.
  • Do not add any conversational filler.
  • Agent: ResearchAssistant

    Model: claude-sonnet-20240229 Temperature: 0.3 System Prompt: You are a diligent research assistant. Your goal is to gather relevant information for a given sub-task. You will use the available `search` tool extensively. Synthesize findings concisely. Tools: - search Instructions:
  • Given a sub-task, use the `search` tool to find 2-3 credible sources.
  • Summarize the key findings relevant to the sub-task.
  • Cite your sources clearly.
  • Agent: ContentGenerator

    Model: claude-sonnet-20240229 Temperature: 0.7 System Prompt: You are a creative content writer. Your task is to generate high-quality, engaging content based on the provided research and a specific sub-task. Focus on clarity, accuracy, and tone. Instructions:
  • Based on the provided research and sub-task, write the content.
  • Ensure the content flows logically.
  • Maintain a consistent tone (e.g., informative, persuasive, casual).
  • Agent: Editor

    Model: claude-haiku-20240307 Temperature: 0.1 System Prompt: You are a meticulous editor. Your job is to refine, proofread, and improve the clarity, grammar, and style of the provided content. Ensure it meets the specified requirements. Instructions:
  • Review the content for grammar, spelling, punctuation, and syntax errors.
  • Improve sentence structure and word choice.
  • Ensure the content is concise and easy to read.
  • Check for consistency in tone and style.
  • The Non-Obvious Insight: Model Selection for Each Step

    This is where the real cost savings and performance gains come in. The documentation often suggests picking a single model for your agent. However, with a specialized multi-agent setup, you can be much more strategic. For instance, my TaskDeconstructor uses claude-haiku-20240307. Haiku is incredibly fast and cheap, and for simply breaking down a task into a list, it performs perfectly. There’s no need for Opus here. Similarly, the Editor agent, focused on refinement and grammar, also benefits from Haiku’s speed and precision without needing a large context window or complex reasoning. Its primary job is pattern matching and correction, which Haiku handles very well.

    For agents like ResearchAssistant and ContentGenerator, I opt for claude-sonnet-20240229. Sonnet strikes an excellent balance between cost and capability. The research phase often requires synthesizing information from multiple sources, and content generation needs a certain level of creativity and coherence. Opus would certainly do a stellar job, but for 90% of my use cases, Sonnet is more than sufficient and significantly cheaper per token. The key is to match the model’s capabilities to the agent’s specific function, not the overall task complexity.

    Managing State and Communication

    One of the biggest challenges with chained agents is ensuring smooth communication and state management. OpenClaw handles this implicitly when you chain agents in your workflow (e.g., `openclaw run TaskDeconstructor -> ResearchAssistant -> ContentGenerator -> Editor`). Each agent receives the output of the previous one as its input. However, it’s crucial to instruct each agent clearly on what to expect as input and what format its output should take for the next agent. For example, TaskDeconstructor outputs a numbered list, which ResearchAssistant is then prompted to act upon, typically iteratively.

    I also use a simple convention: each agent’s output should be as “clean” as possible – no conversational filler, just the raw, processed data or content. This minimizes token usage for subsequent agents and prevents unnecessary context from accumulating. The Instructions section in each agent’s definition is paramount for this.

    Limitations and When This Falls Short

    This multi-agent strategy is highly effective for tasks that can be broken down into discrete, sequential steps. However, it’s not a silver bullet. If your task requires extremely deep, multi-faceted reasoning that spans across several steps and requires the agent to maintain a very complex internal state or perform highly iterative, non-linear problem-solving, a single, more powerful agent (like Opus) with a larger context window might still be necessary. For instance, deeply technical coding tasks or complex scientific simulations might push the limits of this chained approach, as the explicit context passing might become cumbersome or lose nuance.

    Furthermore, this setup is most efficient on a VPS with at least 2GB of RAM, especially if you’re running multiple OpenClaw processes concurrently or dealing with very large outputs. While OpenClaw itself is lightweight, the underlying LLM calls and the processing of potentially large JSON outputs can consume memory. A Raspberry Pi, while capable of running OpenClaw for simpler tasks, might struggle with a complex multi-agent pipeline processing extensive research findings.

    This setup also assumes a stable internet connection for consistent API calls. If your connection is flaky, the chained calls might fail more frequently, requiring more robust error handling in your OpenClaw scripts.

    To implement this setup, start by defining your specialized agents in your AGENTS.md file, matching models to their specific roles as described. Then, chain them together in your workflow. The most direct next step is to open your existing AGENTS.md file and begin refactoring your monolithic agents into specialized, single-responsibility units, and then update your workflow script to chain them together, for example: openclaw run TaskDeconstructor -> ResearchAssistant -> ContentGenerator -> Editor --request "Write a blog post about the benefits of specialized AI agents."

    Want better responses from OpenClaw? Learn how to write better agent prompts →

  • OpenClaw Gateway Explained: How Remote Node Connections Work

    If you’re managing an OpenClaw setup where your main instance needs to access remote resources – like specialized GPUs, custom data sources, or geographically distributed services – the OpenClaw Gateway is your crucial component. Often, users try to build complex SSH tunnels or write custom API proxies, which quickly become unmanageable. The Gateway simplifies this by providing a secure, efficient, and native way for your OpenClaw core to interact with resources on other machines without exposing internal services directly to the internet.

    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 Problem: Distributed Resources

    Imagine your primary OpenClaw instance is running on a modest cloud VPS, handling orchestrations and API calls. However, you have a separate, powerful GPU server in a different data center for intensive model training, or perhaps a local machine with proprietary sensor data that needs to be processed. Directly exposing the GPU server’s API or the local machine’s data stream to your main OpenClaw instance across the public internet introduces significant security risks and often requires complex network configurations like VPNs or firewall rules that are difficult to maintain. Trying to achieve this by simply running a second OpenClaw instance and having them call each other’s APIs can lead to circular dependencies and difficult-to-debug authentication issues.

    Introducing the OpenClaw Gateway

    The OpenClaw Gateway acts as a secure, authenticated proxy between your main OpenClaw instance and these remote resources. It establishes an outbound connection to your central OpenClaw instance, meaning you don’t need to open inbound ports on the remote resource machine. This is a critical security advantage, especially for machines behind restrictive firewalls or NAT. The Gateway itself is a lightweight daemon that sits on the remote machine, listening for requests from your main OpenClaw instance and forwarding them to local services.

    To set up a Gateway, you’ll first need to generate a Gateway token on your main OpenClaw instance. SSH into your primary OpenClaw host and run:

    openclaw gateway generate-token --name my-gpu-server-gateway --lifetime 30d

    This command will output a long alphanumeric token. Copy this token carefully; it’s used to authenticate your remote Gateway instance with your main OpenClaw installation. The --lifetime flag is important; tokens should be rotated regularly for security. If omitted, the default is typically 90 days.

    Gateway Installation and Configuration

    Now, SSH into your remote machine (e.g., your GPU server). You’ll need to install the OpenClaw client, which includes the Gateway component. The installation method varies slightly by OS, but for most Linux systems, it’s a simple curl command:

    curl -sSL https://get.openclaw.dev | bash

    Once installed, you’ll configure the Gateway to connect to your main OpenClaw instance using the token you just generated. Create a configuration file, typically at /etc/openclaw/gateway.yml or ~/.openclaw/gateway.yml:

    # /etc/openclaw/gateway.yml
    gateway:
      # The URL of your main OpenClaw instance's API endpoint
      # Ensure this is accessible from the remote Gateway machine
      server_url: "https://your-main-openclaw-instance.com/api"
      
      # The authentication token generated earlier
      token: "ocg_your_generated_token_here"
      
      # Name for this gateway, should match the name given during token generation
      name: "my-gpu-server-gateway"
      
      # Services exposed through this gateway. Key is the internal name, value is the local URL.
      services:
        gpu-inference: "http://localhost:8001" # A local API on the GPU server
        local-data-stream: "tcp://localhost:9000" # A TCP stream for sensor data
        
      # Optional: TLS certificate verification settings
      tls:
        insecure_skip_verify: false # Set to true only for testing with self-signed certs
        # ca_cert_path: "/path/to/your/custom/ca.crt" # If your main instance uses a custom CA
    

    The services section is where the magic happens. You define a logical name (e.g., gpu-inference) and map it to a local endpoint on the Gateway machine (e.g., http://localhost:8001). When your main OpenClaw instance requests gateway://my-gpu-server-gateway/gpu-inference, the Gateway on the remote machine will forward that request to http://localhost:8001 on its own host.

    After saving the configuration, start the Gateway service. For systemd-based systems, you’d typically run:

    sudo systemctl enable openclaw-gateway
    sudo systemctl start openclaw-gateway
    sudo systemctl status openclaw-gateway

    Verify that the Gateway is running and connected without errors. You should see output indicating a successful connection to your main OpenClaw instance.

    Using the Gateway from Your Main OpenClaw Instance

    Once the Gateway is connected, you can reference the exposed services directly from your main OpenClaw workflows or configurations. For example, if you have a workflow step that needs to call the GPU inference service:

    # In your OpenClaw workflow definition (e.g., a .claw file)
    {
      "name": "gpu_inference_task",
      "steps": [
        {
          "type": "http_request",
          "config": {
            "method": "POST",
            "url": "gateway://my-gpu-server-gateway/gpu-inference/predict",
            "headers": {
              "Content-Type": "application/json"
            },
            "body": {
              "image_data": "{{ .input.image }}"
            }
          }
        }
      ]
    }
    

    Notice the gateway:// schema. This tells OpenClaw to route the request through the specified Gateway. The path after the gateway name (e.g., /gpu-inference/predict) is appended to the local URL defined in the Gateway’s configuration (http://localhost:8001/predict in this example).

    Non-Obvious Insight: Resource Management and Load Balancing

    While the Gateway simplifies connectivity, it doesn’t inherently provide load balancing or advanced resource management. If you have multiple GPU servers, you’ll need to run a separate Gateway for each and then implement your own load balancing logic within your OpenClaw workflows. A common pattern is to register multiple Gateways and then use a “round-robin” or “least-busy” strategy by dynamically selecting which gateway:// URL to use for a task. For example, you might maintain a list of active Gateways in a shared configuration and have your workflow select one based on current load metrics retrieved via another Gateway service.

    Also, remember that the Gateway connection is outbound from the remote machine. If your main OpenClaw instance is behind a strict firewall, ensure it can accept inbound connections from the remote Gateway machine on its configured API port (typically 443 for HTTPS).

    Limitations

    The OpenClaw Gateway is designed for connecting to specific services on remote machines, not for creating a mesh network or a full-blown VPN. It’s a point-to-point secure channel. While it handles TCP and HTTP/HTTPS, it’s not a general-purpose network tunnel for all protocols. For extremely high-throughput, low-latency scenarios where direct access is paramount, a dedicated private network link or VPN might still be preferable, but for most API and data streaming use cases, the Gateway is more than sufficient and much simpler to manage.

    This setup works best when your remote resources are stable and have a consistent local address. It’s less suited for highly dynamic environments where service endpoints frequently change. The Gateway also adds a small amount of latency due to the proxying, but for most applications, this is negligible.

    To start using the Gateway, go to your primary OpenClaw instance and run: openclaw gateway generate-token --name my-first-gateway --lifetime 90d to get your first token.

    Want better responses from OpenClaw? Learn how to write better agent prompts →

  • How to Manage Multiple OpenClaw Nodes for Different Projects

    If you’re running OpenClaw for multiple distinct projects, perhaps one for your personal blog, another for a client’s e-commerce site, and a third for an internal dev tool, you’ve likely encountered the problem of configuration sprawl. Juggling different API keys, model preferences, and rate limits in a single .openclaw/config.json can quickly become unmanageable. The official documentation often steers you towards a monolithic configuration, but for practical multi-project use, a more compartmentalized approach is essential. Here’s how to manage multiple OpenClaw nodes effectively, ensuring each project operates within its own defined parameters without stepping on the others’ toes.

    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 Configuration Loading

    OpenClaw, by default, looks for its configuration file in ~/.openclaw/config.json. This is great for a single, personal setup. However, when you need separate configurations, simply changing this file manually before each project run is cumbersome and prone to errors. The key insight here is that OpenClaw respects the OPENCLAW_CONFIG_PATH environment variable. By setting this variable, you can point OpenClaw to a completely different configuration file. This allows you to create project-specific configuration directories and files, effectively isolating each project’s settings.

    Let’s say you have three projects: myblog, client-shop, and dev-tool. Instead of modifying ~/.openclaw/config.json repeatedly, you’ll create separate configuration directories for each. For instance:

    
    mkdir -p ~/openclaw-configs/myblog
    mkdir -p ~/openclaw-configs/client-shop
    mkdir -p ~/openclaw-configs/dev-tool
    

    Inside each of these directories, you’ll place a config.json file tailored to that specific project. For example, ~/openclaw-configs/myblog/config.json might look like this:

    
    {
      "api_keys": {
        "openai": "sk-YOUR_OPENAI_KEY_FOR_BLOG",
        "anthropic": "sk-ant-api03-YOUR_ANTHROPIC_KEY_FOR_BLOG"
      },
      "default_model": "gpt-3.5-turbo",
      "temperature": 0.7,
      "max_tokens": 1024,
      "system_prompt": "You are a helpful assistant for my blog project."
    }
    

    And ~/openclaw-configs/client-shop/config.json would have different keys, models, and prompts:

    
    {
      "api_keys": {
        "openai": "sk-YOUR_OPENAI_KEY_FOR_CLIENT",
        "anthropic": "sk-ant-api03-YOUR_ANTHROPIC_KEY_FOR_CLIENT"
      },
      "default_model": "claude-haiku-4-5",
      "temperature": 0.2,
      "max_tokens": 512,
      "system_prompt": "You are a concise assistant for an e-commerce product description generator."
    }
    

    Notice the model choice for the client project. While the docs often default to more powerful, expensive models, for tasks like product descriptions, claude-haiku-4-5 is often 10x cheaper and perfectly adequate, especially when generating many descriptions. This kind of optimization is crucial when managing client budgets.

    Launching OpenClaw with Project-Specific Configurations

    Now that you have your separate configurations, the next step is to tell OpenClaw which one to use. This is where the OPENCLAW_CONFIG_PATH environment variable comes in. You can set this variable directly when running your OpenClaw commands or, more practically, wrap your commands in small shell scripts.

    For the myblog project, you would execute:

    
    OPENCLAW_CONFIG_PATH="~/openclaw-configs/myblog/config.json" openclaw generate "Draft a short post about managing OpenClaw configs."
    

    For the client-shop project:

    
    OPENCLAW_CONFIG_PATH="~/openclaw-configs/client-shop/config.json" openclaw generate "Write a catchy product description for a 'smart coffee mug'."
    

    While direct command-line setting works, for more complex workflows or scripts, it’s better to encapsulate this logic. Create a simple wrapper script for each project, for instance, ~/bin/openclaw-myblog:

    
    #!/bin/bash
    export OPENCLAW_CONFIG_PATH="~/openclaw-configs/myblog/config.json"
    openclaw "$@"
    

    Make it executable: chmod +x ~/bin/openclaw-myblog. Then, from anywhere, you can run:

    
    openclaw-myblog generate "List three SEO keywords for a blog post about serverless functions."
    

    This approach keeps your environment clean and prevents accidental cross-project configuration bleed. It’s also incredibly useful for CI/CD pipelines where you want to ensure a specific OpenClaw instance is always used for a given build or deployment task.

    Managing Logs and Cache Separately

    Beyond just configuration, you might also want to isolate logs and cache files for each project. By default, OpenClaw often places these in ~/.openclaw/logs and ~/.openclaw/cache. However, the config.json allows you to specify log_dir and cache_dir. This means you can extend your project-specific configuration to manage these as well.

    For example, in ~/openclaw-configs/myblog/config.json, you might add:

    
    {
      "api_keys": {
        "openai": "sk-YOUR_OPENAI_KEY_FOR_BLOG",
        "anthropic": "sk-ant-api03-YOUR_ANTHROPIC_KEY_FOR_BLOG"
      },
      "default_model": "gpt-3.5-turbo",
      "temperature": 0.7,
      "max_tokens": 1024,
      "system_prompt": "You are a helpful assistant for my blog project.",
      "log_dir": "~/openclaw-configs/myblog/logs",
      "cache_dir": "~/openclaw-configs/myblog/cache"
    }
    

    This ensures that each project’s interactions, including API calls, responses, and cached data, are kept entirely separate. This is critical for debugging, cost analysis, and ensuring data privacy between client projects.

    Limitations and Practical Considerations

    This multi-node management strategy using OPENCLAW_CONFIG_PATH is highly effective, but it does come with some limitations. This approach primarily manages the configuration and runtime environment of the OpenClaw CLI or any application that correctly honors the environment variable. It doesn’t, for instance, create isolated virtual environments for Python dependencies if you’re using OpenClaw as a library within a larger Python project. For that, you’d still need to rely on tools like venv or conda.

    Furthermore, while this setup is robust for most VPS environments (like Hetzner, DigitalOcean, etc.) with at least 1GB of RAM, running multiple OpenClaw instances *simultaneously* on a resource-constrained device like a Raspberry Pi might struggle, especially if you’re hitting powerful models like GPT-4 or Claude Opus. The individual OpenClaw processes are relatively lightweight, but the combined memory footprint of multiple Python interpreters and potentially large model outputs can add up. Ensure your system has adequate RAM and CPU cores if you plan to run several OpenClaw operations concurrently.

    Finally, remember to secure your API keys. Storing them directly in config.json files is common for personal use, but for production environments or shared systems, consider using a proper secret management system (like environment variables loaded from a secure vault, or services like AWS Secrets Manager/Azure Key Vault) and reference those in your config.json where OpenClaw can resolve them.

    To begin managing your OpenClaw projects separately, create a dedicated configuration file for each project, such as ~/openclaw-configs/myblog/config.json, and then execute your OpenClaw commands using the OPENCLAW_CONFIG_PATH environment variable: OPENCLAW_CONFIG_PATH="~/openclaw-configs/myblog/config.json" openclaw generate "My prompt here."

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

    Want better responses from OpenClaw? Learn how to write better agent prompts →

  • How to Backup and Restore Your OpenClaw Configuration

    If you’re running OpenClaw for any serious work, whether it’s powering your internal knowledge base or automating support responses, the configuration you’ve built up over time becomes critical. Losing your API keys, custom prompt templates, or fine-tuned model settings can be a significant setback, often requiring hours to painstakingly recreate. This isn’t just about disaster recovery; it’s also essential for migrating your OpenClaw instance from a development environment to production, or even just moving it to a more powerful server. I’ve personally been through the pain of a corrupted SSD on a cheap VPS, and the lesson learned was: back up your configuration, frequently and reliably.

    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 Configuration Footprint

    OpenClaw, by design, centralizes most of its user-specific configuration within a single directory. On typical Linux systems, this resides at ~/.openclaw/. This directory isn’t just for global settings; it contains everything from your API provider keys to custom tool definitions and user-specific model preferences. While some data, like cached LLM responses, might be stored elsewhere (often in /tmp or a designated cache directory depending on your OS and OpenClaw version), the core operational parameters are all here.

    Specifically, the files you absolutely need to safeguard are:

    • ~/.openclaw/config.json: This is the primary configuration file. It holds your default model, API keys (though often referenced by environment variables for better security), and various global settings.
    • ~/.openclaw/prompts/: This directory contains all your custom prompt templates. If you’ve invested time in crafting sophisticated multi-turn conversations or specific system prompts, these are invaluable.
    • ~/.openclaw/tools/: If you’ve developed custom tools or integrated third-party services that OpenClaw interacts with, their definitions and configurations live here.
    • ~/.openclaw/cache/: While not strictly configuration, this directory often contains compiled prompt templates or model-specific caches that, while regeneratable, can speed up startup times significantly after a restore. It’s often good practice to include it, especially for complex setups.

    It’s crucial to understand that OpenClaw generally expects these files and directories to be present in the user’s home directory. If you run OpenClaw as a different user (e.g., a dedicated openclaw system user), then the path will be /home/openclaw/.openclaw/ instead of ~/.openclaw/.

    The Backup Process: Simple and Effective

    The most straightforward way to back up your OpenClaw configuration is to create a compressed archive of the entire ~/.openclaw/ directory. This ensures that permissions, directory structures, and all necessary files are preserved. We’ll use tar for this, a ubiquitous tool on Linux systems.

    First, ensure OpenClaw isn’t actively writing to its configuration files during the backup. While usually not critical for read-only config files, it’s good practice for consistency, especially if you have custom tools that might generate temporary files in their respective directories. If you’re running OpenClaw as a service, stop it:

    sudo systemctl stop openclaw

    Now, navigate to your home directory and create the archive. I recommend placing the backup file outside of the .openclaw directory itself, perhaps in ~/backups/, and including a timestamp for easy versioning:

    mkdir -p ~/backups
    tar -czvf ~/backups/openclaw_config_$(date +%Y%m%d%H%M%S).tar.gz ~/.openclaw/

    Let’s break down that command:

    • tar: The archiving utility.
    • -c: Create a new archive.
    • -z: Compress the archive with gzip. This is vital for saving disk space, especially if your prompt or tool directories are extensive.
    • -v: Verbose output, showing the files being added. Useful for confirming the backup is working as expected.
    • -f ~/backups/openclaw_config_$(date +%Y%m%d%H%M%S).tar.gz: Specifies the output filename. The $(date +%Y%m%d%H%M%S) part dynamically adds a timestamp (e.g., 20231027143000) to the filename, making it easy to keep multiple backups.
    • ~/.openclaw/: This is the source directory we want to back up.

    After creating the backup, restart your OpenClaw service if you stopped it earlier:

    sudo systemctl start openclaw

    Once the .tar.gz file is created, download it to a secure, off-server location. Relying solely on backups stored on the same server that might fail is a recipe for disaster. Tools like scp or rsync are excellent for this:

    scp user@your_vps_ip:~/backups/openclaw_config_*.tar.gz /path/to/local/backup/directory/

    The Restore Process: Bringing OpenClaw Back to Life

    Restoring your OpenClaw configuration is essentially the reverse of the backup process. This is particularly useful when migrating to a new server or recovering from data loss.

    First, get your backup archive onto the target server. If you downloaded it locally, use scp to upload it:

    scp /path/to/local/backup/directory/openclaw_config_YOURTIMESTAMP.tar.gz user@new_vps_ip:~/

    Before restoring, it’s crucial to ensure OpenClaw is not running on the target system. If ~/.openclaw/ already exists on the target system (e.g., you’ve run OpenClaw once), you might want to back it up or remove it entirely to avoid conflicts, especially if you’re aiming for a clean restore:

    # If OpenClaw is running, stop it first
    sudo systemctl stop openclaw
    
    # Optional: Back up existing config before overwriting (good practice)
    mv ~/.openclaw/ ~/.openclaw_old_$(date +%Y%m%d%H%M%S)/
    
    # Or, if you want a clean slate and are sure you don't need the old config:
    rm -rf ~/.openclaw/

    Now, navigate to the directory where you want to extract the backup (usually your home directory) and extract the archive:

    tar -xzvf openclaw_config_YOURTIMESTAMP.tar.gz -C ~/

    Let’s break this down:

    • tar: The archiving utility.
    • -x: Extract files from an archive.
    • -z: Decompress with gzip.
    • -v: Verbose output.
    • -f openclaw_config_YOURTIMESTAMP.tar.gz: Specifies the input archive file.
    • -C ~/: Crucially, this tells tar to change directory to ~/ (your home directory) *before* extracting. Since our backup was created from ~/.openclaw/, extracting it into ~/ will correctly place the .openclaw/ directory there.

    After extraction, your ~/.openclaw/ directory should be populated with all your backed-up configuration files. You can verify this by listing its contents:

    ls -la ~/.openclaw/

    Finally, you can start OpenClaw. It will now pick up all your restored settings, prompts, and tools:

    sudo systemctl start openclaw

    Non-Obvious Insights and Limitations

    A common pitfall is forgetting about environment variables. While config.json might reference an API key like $OPENAI_API_KEY, the actual value isn’t stored in the backup. You’ll need to ensure these environment variables are correctly set on your new server, either in ~/.bashrc, /etc/environment, or directly in your systemd service file for OpenClaw. Always double-check these after a restore, as missing API keys are a primary reason for “unexplained” connection errors.

    Another point: if you’re using custom Python modules for tools, ensure those dependencies are also installed on the target machine. The OpenClaw backup only covers its configuration files, not external Python packages. A good practice

    Frequently Asked Questions

    What does ‘OpenClaw configuration’ refer to?

    It includes all your personalized settings, profiles, macros, hotkeys, and preferences within the OpenClaw application. Backing it up ensures you don’t lose your customized setup, making migration or recovery simple.

    Why is it important to back up my OpenClaw configuration?

    Backing up protects your custom settings from data loss due to system crashes, software reinstallation, or hardware failure. It ensures a quick recovery to your preferred setup, saving significant time and effort in reconfiguring.

    How do I restore my OpenClaw configuration from a backup?

    Typically, you’ll replace the current configuration files with your saved backup files in the designated OpenClaw data directory. The article provides detailed, step-by-step instructions for accurately performing this restoration process.

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

    Want better responses from OpenClaw? Learn how to write better agent prompts →

  • Building a Reddit Engagement Bot Using OpenClaw Skills

    If you’re looking to build a Reddit engagement bot with OpenClaw to automate responses, summarize threads, or even generate new post ideas, you’ll quickly run into rate limiting and unexpected errors if you don’t configure things correctly. Reddit’s API, especially for unverified applications, is quite restrictive. Combining this with OpenClaw’s default aggressive polling can lead to your bot getting temporarily blocked or, worse, your API keys being revoked. This guide focuses on setting up a robust, rate-limited OpenClaw instance to interact with Reddit, specifically for summarizing new posts in a given subreddit and replying to comments.

    Setting Up Your Reddit Application and OpenClaw

    First, you need a Reddit API application. Go to reddit.com/prefs/apps and create a new application. Choose ‘script’ as the type. Set the ‘redirect uri’ to http://localhost:8080 (or any valid URL, it doesn’t need to be accessible for script apps). Note down your client ID (under “personal use script”) and client secret. These are crucial.

    Next, install OpenClaw if you haven’t already:

    pip install openclaw
    openclaw init
    

    During openclaw init, you’ll be prompted for an API key. For this project, let’s assume you’re using Anthropic’s Claude API. Enter your Anthropic API key. If you’re using another provider, adjust accordingly.

    Now, let’s configure OpenClaw to interact with Reddit. Create a new file, ~/.openclaw/integrations/reddit.json, with the following content:

    {
      "name": "reddit",
      "type": "rest",
      "base_url": "https://oauth.reddit.com",
      "auth": {
        "type": "oauth2",
        "token_url": "https://www.reddit.com/api/v1/access_token",
        "client_id": "YOUR_REDDIT_CLIENT_ID",
        "client_secret": "YOUR_REDDIT_CLIENT_SECRET",
        "grant_type": "password",
        "username": "YOUR_REDDIT_USERNAME",
        "password": "YOUR_REDDIT_PASSWORD"
      },
      "headers": {
        "User-Agent": "OpenClawRedditBot/1.0 (by /u/YOUR_REDDIT_USERNAME)"
      },
      "endpoints": {
        "me": {
          "path": "/api/v1/me",
          "method": "GET"
        },
        "subreddit_new": {
          "path": "/r/{subreddit}/new",
          "method": "GET",
          "params": {
            "limit": 5
          }
        },
        "post_comment": {
          "path": "/api/comment",
          "method": "POST",
          "body": {
            "api_type": "json",
            "parent": "{parent_id}",
            "text": "{text}"
          }
        }
      }
    }
    

    Replace YOUR_REDDIT_CLIENT_ID, YOUR_REDDIT_CLIENT_SECRET, YOUR_REDDIT_USERNAME, and YOUR_REDDIT_PASSWORD with your actual Reddit app credentials and bot account details. The User-Agent is critical; Reddit expects a unique and descriptive user agent string, including your username.

    Implementing Rate Limiting and Smart Delays

    The non-obvious insight here is that Reddit’s rate limits are not just about requests per second, but also about requests per minute and even per hour, especially for non-premium accounts. Hitting these limits results in 429 Too Many Requests responses. OpenClaw, by default, doesn’t have an intelligent backoff strategy for external integrations. You need to implement it in your script logic.

    Here’s a Python script using OpenClaw to summarize new posts in a subreddit and reply to comments, incorporating a rate-limiting mechanism:

    import time
    import json
    from openclaw import OpenClaw

    # Initialize OpenClaw with your default model (e.g., Anthropic's Claude)
    # For cost-effectiveness, claude-haiku-4-5 is often 10x cheaper than opus
    # and perfectly sufficient for summarization and short replies.
    oc = OpenClaw(model="claude-haiku-4-5")

    # Load the Reddit integration
    reddit = oc.integration("reddit")

    # Reddit rate limit: ~60 requests per minute for OAuth2, but be conservative.
    # We'll aim for 1 request every 5 seconds to be safe.
    REDDIT_REQUEST_INTERVAL = 5 # seconds

    last_request_time = 0

    def make_reddit_request(endpoint_name, **kwargs):
    global last_request_time
    current_time = time.time()
    if current_time - last_request_time < REDDIT_REQUEST_INTERVAL: sleep_time = REDDIT_REQUEST_INTERVAL - (current_time - last_request_time) print(f"Waiting for {sleep_time:.2f} seconds to respect Reddit rate limits...") time.sleep(sleep_time) try: response = reddit.run(endpoint_name, **kwargs) last_request_time = time.time() # Update last request time on success if response.status_code == 200: return response.json() elif response.status_code == 429: print(f"Rate limit hit! Waiting for 60 seconds. Response: {response.text}") time.sleep(60) return None # Indicate failure due to rate limit else: print(f"Reddit API error ({response.status_code}): {response.text}") return None except Exception as e: print(f"An error occurred during Reddit request: {e}") return None def summarize_post(post_title, post_text): prompt = f"Summarize the following Reddit post concisely:\n\nTitle: {post_title}\n\nBody: {post_text}" summary = oc.generate(prompt, max_tokens=100) return summary.text.strip() def generate_reply(comment_text): prompt = f"Generate a polite and helpful reply to the following Reddit comment:\n\nComment: {comment_text}" reply = oc.generate(prompt, max_tokens=80) return reply.text.strip() def process_subreddit(subreddit_name): print(f"Fetching new posts from r/{subreddit_name}...") new_posts_data = make_reddit_request("subreddit_new", subreddit=subreddit_name, limit=3) # Fetch fewer for testing if new_posts_data: for post in new_posts_data['data']['children']: post_id = post['data']['name'] # e.g., t3_xxxxxx title = post['data']['title'] selftext = post['data']['selftext'] print(f"\nProcessing post: {title}") # Summarize posts (optional, for generating new content or internal analysis) if selftext: summary = summarize_post(title, selftext) print(f"Summary: {summary}") # Example: Reply to comments on a post # For a real bot, you'd fetch comments for this post and then reply. # This is a placeholder for demonstration. if "t3_xxxxxx" not in post_id: # Avoid replying to self in actual use # In a real scenario, you'd fetch comments for the post: # comments_data = make_reddit_request("post_comments", post_id=post_id) # For this example, let's simulate a comment and reply. mock_comment_id = "t1_mockcommentid" # Replace with actual comment ID if fetching comments mock_comment_text = "This is a very interesting point, I'd like to know more." print(f"Simulating a reply to comment on post {post_id}...") reply_text = generate_reply(mock_comment_text) # IMPORTANT: Only uncomment the following line when you are absolutely # ready to post live replies. Test thoroughly first! # For safety, you might want to add a check for 'dry_run' mode. # response_reply = make

    Frequently Asked Questions

    What is OpenClaw and why use it for a Reddit bot?

    OpenClaw is an open-source framework providing pre-built 'skills' for AI agents. Using it simplifies bot development by integrating complex functionalities, like natural language processing, without extensive coding, making Reddit engagement easier to automate.

    What specific engagement tasks can this Reddit bot perform?

    This bot can automate various Reddit engagement tasks, such as generating context-aware comments on posts, upvoting content, and potentially initiating direct messages. It leverages OpenClaw skills to create more intelligent and relevant interactions.

    What technical skills are required to build this OpenClaw-powered Reddit bot?

    While some basic programming understanding is helpful, the article guides you through using OpenClaw's pre-built functionalities. This approach significantly reduces the need for advanced coding skills, focusing more on configuration and integration.

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

    Want better responses from OpenClaw? Learn how to write better agent prompts →

  • OpenClaw MEMORY.md: The Complete Guide to Persistent AI Memory

    “`html

    OpenClaw MEMORY.md: The Complete Guide to Persistent AI Memory

    If you’ve been running OpenClaw agents for more than a few sessions, you’ve probably hit the wall: context windows fill up, previous learnings vanish, and your AI restarts from scratch. I spent weeks watching my agents repeat mistakes they’d already solved. That’s when I got serious about MEMORY.md.

    This file is the difference between a stateless chatbot and an agent that actually learns. Here’s how I’ve implemented it across production workflows.

    How MEMORY.md Actually Works

    MEMORY.md isn’t magical. It’s a persistent text file that lives in your agent’s working directory. When your agent initializes, it reads this file. When it learns something valuable, it updates this file. Between sessions, that knowledge persists.

    The system works because of two core functions: memory_search and memory_get. Understanding the difference changed how I structure memories.

    memory_get retrieves the entire MEMORY.md file. Use this sparingly—it’s a context dump. I call it only during agent initialization or when dealing with context overload recovery.

    memory_search performs semantic search across your memory file. This is your workhorse. When your agent needs to recall something specific, search for it by concept, not by filename.

    Here’s a real example from my API integration agent:

    Agent: "I need to authenticate with the Stripe API"
    memory_search("Stripe authentication key management")
    
    Returns:
    - Stripe API keys must be injected via environment variables, never hardcoded
    - Test keys start with sk_test_, production with sk_live_
    - Implement key rotation every 90 days
    - Previous failure: hardcoded key in config.yaml caused security audit flag
    

    That search took milliseconds and returned contextual guidance without bloating my token count. That’s the pattern.

    Memory Search vs Memory Get: When to Use Each

    I made mistakes here. Early on, I called memory_get constantly. Context exploded. Here’s my decision matrix:

    Use memory_search when:

    • Your agent is executing a specific task and needs related context
    • You have more than 5KB of memories accumulated
    • You want to avoid loading irrelevant historical data
    • Latency matters (which it always does)

    Use memory_get when:

    • Initializing an agent for the first time in a session
    • Your memory file is under 3KB
    • You’re doing a complete context reset to prevent drift
    • Debugging why the agent made a bad decision

    In production, I structure this into the agent’s initialization prompt:

    INITIALIZATION SEQUENCE:
    1. memory_get() → load all memories
    2. Parse into working knowledge
    3. For each new task: memory_search(task_context)
    4. Execute task
    5. memory_update() → store learnings
    6. Never call memory_get() during task execution
    

    Preventing Context Bloat: The Real Problem

    This is where most people fail. They dump everything into MEMORY.md and watch their context window choke.

    I solve this with aggressive archival. Every 30 days, I review my MEMORY.md and run a cleanup:

    • Remove duplicate learnings (keep the most specific version)
    • Archive superseded information to a separate MEMORY_ARCHIVE.md
    • Consolidate vague memories into actionable templates
    • Delete anything not referenced in the past 60 days

    Here’s what my cleanup script looks like:

    #!/bin/bash
    # Archive old memories
    
    MEMORY_FILE="MEMORY.md"
    ARCHIVE_FILE="MEMORY_ARCHIVE.md"
    CUTOFF_DATE=$(date -d "60 days ago" +%s)
    
    # Find entries with timestamps older than cutoff
    grep -B2 "last_used:" $MEMORY_FILE | while read line; do
      entry_date=$(echo $line | grep -o '[0-9]\{10\}')
      if [ "$entry_date" -lt "$CUTOFF_DATE" ]; then
        echo "$line" >> $ARCHIVE_FILE
      fi
    done
    
    # Regenerate MEMORY.md with only active entries
    

    I also cap my active MEMORY.md at 8KB. When it approaches that, the agent gets an instruction to compress before appending new memories.

    Structuring Long-Term vs Daily Memories

    Not all memories have equal weight. I separate them:

    Long-term memories are principles, patterns, and lessons that rarely change. These include API specifications, architectural decisions, and hard-earned debugging insights. They live in the top section of MEMORY.md with minimal timestamps.

    Daily memories are task-specific learnings, recent successes, and current project context. These are timestamped and rotated out frequently.

    Here’s my actual MEMORY.md structure:

    ## LONG-TERM KNOWLEDGE
    ### Architecture Patterns
    - Microservices deployment uses Docker Compose with shared .env
    - Database migrations must include rollback steps
    - All API responses validated against schema before processing
    
    ### Common Pitfalls
    - PostgreSQL connection pooling: max 20 connections per instance
    - Redis cache invalidation: must include version suffix to prevent stale reads
    - File uploads: always validate MIME type server-side, never trust client headers
    
    ## DAILY CONTEXT
    ### Current Project (2024-01-15)
    - Building user authentication module for dashboard
    - Using Auth0 integration (client_id: [redacted])
    - Last blocker: session timeout conflicts with refresh token rotation
    
    ### Recent Wins
    - Fixed N+1 query on user profiles (implemented batch loading)
    - Optimized Docker build from 4m to 1.2m via layer caching
    
    ### Active Blockers
    - CORS headers not propagating to preflight requests
    - Need to test against Safari (Edge case found in QA)
    

    This structure means my agent can quickly distinguish between “this is how the world works” and “this is what I’m working on right now.”

    Memory Templates That Actually Work

    After dozens of iterations, I’ve settled on templates that compress information efficiently:

    Problem-Solution Template:

    ## PROBLEM: [Clear Problem Statement]
    - Symptom: [What you observed]
    - Root Cause: [Why it happened]
    - Solution: [What worked]
    - Prevention: [How to avoid next time]
    - Tags: [search-friendly keywords]
    

    API Reference Template:

    ## API: [Service Name]
    - Base URL: [endpoint]
    - Auth: [method and required fields]
    - Rate Limits: [requests/second]
    - Common Errors: [error codes and fixes]
    - Last Updated: [date]
    

    Decision Log Template:

    ## DECISION: [What was decided]
    - Context: [Why we needed to decide]
    - Options Considered: [alternatives and why rejected]
    - Chosen Solution: [what we picked and why]
    - Reversible: [yes/no and implications]
    - Date: [when decided]
    

    I use these templates religiously. They’re searchable, scannable, and compact. When my agent runs memory_search("database connection timeout"), it finds exactly what it needs in seconds.

    Practical Implementation: My Current Setup

    Here’s what I actually do at the end of each agent session:

    1. Agent completes task
    2. Run memory_search() on key topics from the session
    3. Identify gaps in existing memories
    4. Add new learnings using templates above
    5. Check MEMORY.md file size
    6. If > 7KB: archive and compress
    7. Commit changes with timestamp
    

    I also maintain a checklist before deploying an agent to production:

    • MEMORY.md exists and is valid markdown
    • No hardcoded secrets or credentials
    • Most recent memories are timestamped within 30 days
    • Archive file exists with historical context
    • memory_search is used at least 3x per major task
    • No single memory entry exceeds 200 words

    What Changed for Me

    Before MEMORY.md discipline, my agents repeated mistakes weekly. With this system, they catch 80% of common errors automatically. More importantly, they compound knowledge—each session makes them marginally better than the last.

    The key is treating MEMORY.md as a real database, not a dumping ground. Structure it. Search it. Maintain it. Your future self—and your agent—will thank you.

    Frequently Asked Questions

    What is ‘Persistent AI Memory’ as discussed in the OpenClaw guide?

    It refers to AI systems’ ability to store and recall information over extended periods, across different interactions or sessions. This allows AI to build long-term knowledge and context, improving performance and user experience.

    Why is persistent memory crucial for modern AI applications?

    It enables AI to learn, adapt, and maintain context over time, moving beyond stateless interactions. This is vital for personalized experiences, complex problem-solving, and developing AI with a ‘memory’ of past events.

    How does OpenClaw specifically help manage persistent AI memory?

    OpenClaw provides a structured framework and tools for storing, retrieving, and updating AI’s long-term knowledge base. It handles the complexities of data management, ensuring efficient and reliable memory persistence for AI models.

    Want better responses from OpenClaw? Learn how to write better agent prompts →

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

  • OpenClaw SOUL.md Deep Dive: Give Your AI Agent a Real Personality

    “`html

    OpenClaw SOUL.md Deep Dive: Give Your AI Agent a Real Personality

    I’ve been working with OpenClaw for the past six months, and there’s one file that consistently makes the difference between a generic AI assistant and one that actually feels like it belongs in your workflow: SOUL.md.

    Most developers treat SOUL.md like a nice-to-have. They’re wrong. This file is your instruction layer, your personality engine, and your behavioral governor all wrapped into one. When configured properly, it transforms how your AI agent responds to tasks, handles edge cases, and represents your brand or team.

    Let me show you exactly what SOUL.md controls and how to build one that actually works.

    What SOUL.md Actually Does

    SOUL.md is the system-level configuration file that sits between your model and your prompts. It doesn’t override the model’s core capabilities—it provides the contextual framework for how those capabilities get expressed.

    Think of it this way: the model is a skilled employee. SOUL.md is the company culture document, the style guide, and the role description combined.

    Specifically, SOUL.md controls:

    • Personality and tone — How formal, casual, technical, or conversational responses should be
    • Decision-making framework — What values guide choices when there are multiple valid approaches
    • Domain constraints — What the agent should and shouldn’t attempt
    • Output formatting — Structure, verbosity, and presentation style
    • Error handling — How to respond to ambiguity, missing information, or impossible requests
    • Interaction patterns — Whether to ask clarifying questions, make assumptions, or defer to the user

    When the model receives a prompt, it processes SOUL.md as context that shapes its entire response generation process. It’s not a filter—it’s a lens.

    Model Interpretation and Reality

    Here’s what I’ve learned through trial and error: the model interprets SOUL.md through its training patterns. A GPT-4 instance and a Claude instance will internalize the same SOUL.md differently because their underlying models have different semantic spaces.

    This means you need to test your SOUL.md against your actual model. A SOUL.md that works perfectly with Claude might feel slightly off with GPT-4, and vice versa.

    Best practice: when you write SOUL.md, include concrete examples rather than abstract principles. Instead of “be concise,” write “limit explanations to 2-3 sentences unless the user asks for detail.” The model responds better to specificity.

    Also, avoid conflicting instructions. I once had a SOUL.md that said “always ask clarifying questions” and “be decisive and take action without confirmation.” The model got confused and produced inconsistent behavior. The resolution was choosing one primary mode and relegating the other to specific contexts.

    Building Your First SOUL.md

    The structure I’ve found most reliable follows this template:

    # SOUL.md: [Agent Name]
    
    ## Core Identity
    [2-3 sentences defining who this agent is]
    
    ## Primary Role
    [What this agent does and doesn't do]
    
    ## Communication Style
    [Tone, formality, technical level]
    
    ## Decision-Making Framework
    [What principles guide choices]
    
    ## Domain Constraints
    [Hard limits on scope and behavior]
    
    ## Output Format
    [How responses should be structured]
    
    ## Error Handling
    [How to handle ambiguity or conflicts]
    

    Keep the entire file under 500 words. I’ve seen developers create 2000-word SOUL.md files and wonder why the model seems confused. Brevity forces clarity.

    Example 1: Technical Assistant Persona

    Here’s a real SOUL.md I use for an agent that helps my development team with architecture decisions:

    # SOUL.md: ArchitectAI
    
    ## Core Identity
    You are ArchitectAI, a systems design consultant with 15 years of production experience across distributed systems, databases, and infrastructure. You value pragmatism over theoretical purity.
    
    ## Primary Role
    Help engineers evaluate architectural tradeoffs, sanity-check designs before implementation, and troubleshoot production issues. Do NOT write production code or make deployment decisions.
    
    ## Communication Style
    Technical and direct. Use precise terminology. Assume the user understands fundamental CS concepts. No hand-holding.
    
    ## Decision-Making Framework
    1. Production stability trumps performance optimization
    2. Simpler architectures are preferred unless complexity solves a real problem
    3. If it works and performs acceptably, don't redesign it
    4. When recommending approaches, always mention the cost in operational complexity
    
    ## Domain Constraints
    - Do not suggest experimental or unproven technologies
    - Do not make claims about performance without supporting reasoning
    - Do not recommend architectures you haven't seen work in production
    
    ## Output Format
    - Lead with your recommendation in one sentence
    - List 2-3 tradeoffs
    - Provide one example from real systems
    - If asked why, explain without being defensive
    
    ## Error Handling
    If you don't have enough information: "I need to know [specific detail]. Without it, I'm guessing."
    If the question is outside your expertise: "This is beyond architecture—talk to [domain specialist]."
    

    This SOUL.md prevents the agent from being overly academic or suggesting unnecessary complexity.

    Example 2: Creative Director Persona

    For a completely different use case, here’s a SOUL.md for an agent that helps with creative brief development:

    # SOUL.md: CreativeDirector
    
    ## Core Identity
    You are a creative director with experience in advertising, brand strategy, and campaign conceptualization. You combine strategic thinking with imaginative problem-solving.
    
    ## Primary Role
    Help teams develop compelling creative briefs, brainstorm campaign concepts, and evaluate creative work. You challenge assumptions constructively.
    
    ## Communication Style
    Conversational but structured. Use vivid language and specific examples. Think out loud; show your reasoning process.
    
    ## Decision-Making Framework
    1. Authenticity and relevance matter more than novelty
    2. Every idea must connect to the brand brief
    3. Constraints unlock creativity, not limit it
    4. Ask "would this change behavior?" before celebrating an idea
    
    ## Domain Constraints
    - Do not approve final creative work
    - Do not oversell mediocre ideas because they're clever
    - Do not ignore strategic context in favor of style
    
    ## Output Format
    - Start with the core insight or tension you see
    - Provide 2-3 directional concepts
    - Explain why each works (or doesn't)
    - Always include a question back to the user
    
    ## Error Handling
    If the brief is unclear: "Before I brainstorm, let me confirm: what's the actual change you want to see?"
    If an idea feels forced: "I'm not convinced this solves the problem. Let's reframe."
    

    Notice the difference in language and priorities compared to the technical version.

    Example 3: Business Operations Persona

    For a process-focused agent:

    # SOUL.md: OpsCoordinator
    
    ## Core Identity
    You are an operations coordinator who helps teams standardize processes, identify inefficiencies, and implement systems. You value documentation and consistency.
    
    ## Primary Role
    Help teams document workflows, identify bottlenecks, and design sustainable processes. Make explicit what's implicit.
    
    ## Communication Style
    Clear and methodical. Use checklists and structured formats. Assume nothing is obvious until it's written down.
    
    ## Decision-Making Framework
    1. Document first, optimize second
    2. Sustainable processes beat heroic effort
    3. If it's not measured, it's not managed
    4. Involve the people doing the work
    
    ## Domain Constraints
    - Do not design processes that require heroic commitment
    - Do not oversimplify complex human workflows
    - Do not ignore incentives and cultural factors
    
    ## Output Format
    - Summarize the current state in bullet points
    - Identify the top 2 friction points with data if available
    - Propose one change with clear before/after metrics
    - Request feedback from actual practitioners
    
    ## Error Handling
    If stakeholders disagree: "Let's map out the different constraints each person is optimizing for."
    

    Practical Implementation Steps

    Here’s how I actually deploy SOUL.md:

    1. Draft your SOUL.md based on the persona you need
    2. Save it in your OpenClaw project directory as SOUL.md (standard naming)
    3. Run 5-10 test prompts through your agent and evaluate consistency
    4. Adjust language that isn’t landing—be specific, not abstract
    5. Test against your actual model provider (Claude, GPT-4, etc.)
    6. Document deviations you observe and refine iteratively

    The first version won’t be perfect. I usually need 3-4 iterations before an agent feels genuinely cohesive.

    What I’ve Learned

    SOUL.md isn’t a magic solution. It’s a tool for being intentional about how your AI agent behaves. The effort you invest in writing a clear SOUL.md pays back in consistency, reliability, and reduced prompt engineering overhead.

    Start with a persona you need. Make your SOUL.md specific to that context. Test it. Refine it. Then you’ll have an agent that actually feels like part of your team.

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

    Want better responses from OpenClaw? Learn how to write better agent prompts →

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

  • OpenClaw Memory System Explained: How MEMORY.md Gives Your AI Continuity

    If you’re running OpenClaw for any period, especially for tasks that require ongoing context like customer support bots or long-form content generation, you’ve likely hit a wall with the AI forgetting previous interactions. This isn’t just frustrating; it leads to repetitive queries, incoherent responses, and ultimately, a less useful agent. The core of the problem is that Large Language Models (LLMs) are stateless by nature; each API call is a fresh start unless you explicitly provide conversational history. OpenClaw addresses this with its innovative MEMORY.md system, providing persistent context that goes beyond the typical API call window.

    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 Problem with Stateless LLMs

    Most interactions with LLMs are transient. You send a prompt, you get a response, and that’s the end of that particular interaction from the LLM’s perspective. If you want the AI to remember something from a previous turn, you have to concatenate the entire conversation history into the next prompt. This quickly becomes problematic for several reasons:

    • Token Limits: Every LLM has a maximum context window, measured in tokens. As conversations grow, you quickly hit this limit, forcing you to truncate history, leading to the AI “forgetting.”
    • Cost: Paying for tokens means paying for every word, even those repeated from previous turns. Longer contexts mean higher API costs.
    • Complexity: Manually managing conversation history in your application logic adds significant overhead.

    OpenClaw’s MEMORY.md system is designed to provide a more robust and persistent form of memory, allowing the AI to maintain a long-term understanding of its purpose, past interactions, and evolving knowledge base, without constantly resending entire conversation logs.

    How MEMORY.md Works

    MEMORY.md isn’t just a simple log of past conversations. It’s a curated, editable representation of the AI’s evolving understanding. It lives in your agent’s directory, for example, my_agent/MEMORY.md. This file is parsed by OpenClaw and injected into the LLM’s context during each interaction, but in a smart, summarized way. The key here is that it’s not a verbatim transcript of everything said, but rather a structured summary of crucial information.

    When an agent runs, OpenClaw first loads the MEMORY.md file. This file contains key information about the agent’s identity, objectives, and any critical long-term context. After each interaction where the agent generates a response, OpenClaw takes the new information, combines it with the existing MEMORY.md, and then uses a separate LLM call (or a heuristic) to update MEMORY.md. This update process is crucial; it distills new information into a concise format that fits within the context window for future interactions. This is the non-obvious insight: you’re not just appending to a file; you’re actively summarizing and refining the agent’s knowledge.

    Consider an agent designed to help users troubleshoot network issues. Initially, MEMORY.md might contain:

    # Agent Identity
    You are NetAssist, an AI specialized in diagnosing and resolving home network problems.
    
    # Core Capabilities
    
  • Provide step-by-step troubleshooting for common issues (Wi-Fi, no internet, slow speeds).
  • Ask clarifying questions to narrow down problems.
  • Recommend basic hardware resets and configuration checks.
  • # Known Issues & Solutions (Updated: 2023-10-26)
  • Wi-Fi dropping frequently: Suggest checking router firmware, channel interference, or updating device drivers.
  • No internet access: Check modem lights, router connections, ISP status page.
  • After a user interaction where the agent successfully helps a user diagnose a specific brand of router’s known firmware bug, the MEMORY.md might be updated by OpenClaw to include:

    # Agent Identity
    You are NetAssist, an AI specialized in diagnosing and resolving home network problems.
    
    # Core Capabilities
    
  • Provide step-by-step troubleshooting for common issues (Wi-Fi, no internet, slow speeds).
  • Ask clarifying questions to narrow down problems.
  • Recommend basic hardware resets and configuration checks.
  • # Known Issues & Solutions (Updated: 2023-10-27)
  • Wi-Fi dropping frequently: Suggest checking router firmware, channel interference, or updating device drivers.
  • No internet access: Check modem lights, router connections, ISP status page.
  • TP-Link Archer AX50 firmware bug: If user reports internet dropping after 30-60 minutes, advise checking for firmware version 1.1.0 or higher. Known issue with older firmware.
  • This iterative refinement ensures that the agent’s knowledge base grows organically and remains relevant without exceeding token limits or incurring massive costs. It’s not just a chat log; it’s a dynamic knowledge graph represented in Markdown.

    Configuration and Customization

    The behavior of the MEMORY.md system can be configured in your agent’s .openclaw/config.json file. While OpenClaw generally does a good job with default settings, you might want to fine-tune it based on your agent’s task. For example, you can specify which LLM model to use for the memory update process, or even disable it if you have a very simple, stateless agent.

    Here’s an example snippet you might find in .openclaw/config.json:

    {
      "agent_name": "NetAssist",
      "llm_provider": "anthropic",
      "llm_model": "claude-opus-20240229",
      "memory_management": {
        "enabled": true,
        "update_model": "claude-haiku-20240307",
        "update_prompt_template": "summarize_memory_template.md",
        "max_memory_size_tokens": 2000,
        "auto_update_after_turns": 5
      }
    }
    

    The non-obvious insight here is the update_model. While your primary llm_model might be a high-end, expensive model like claude-opus-20240229 for complex reasoning, you can use a much cheaper, faster model like claude-haiku-20240307 for the memory update process. Haiku is incredibly efficient for summarization tasks and can save you significant API costs, especially for agents with high interaction volumes. For 90% of memory summarization tasks, Haiku is more than sufficient and can be 10x cheaper than Opus.

    update_prompt_template points to a file that defines how OpenClaw should instruct the LLM to update the memory. You can customize this to guide the summarization process, emphasizing certain types of information or maintaining a specific structure in your MEMORY.md.

    max_memory_size_tokens helps prevent memory bloat, ensuring your MEMORY.md doesn’t grow indefinitely, which would eventually exceed even the summarization model’s context window. auto_update_after_turns dictates how often the memory update process is triggered. For agents with frequent, short interactions, you might set this lower (e.g., 1 or 2 turns). For agents with longer, less frequent interactions, a higher number might be appropriate to reduce API calls.

    Limitations

    While the MEMORY.md system is powerful, it’s not a silver bullet. The effectiveness of the summarization and update process depends heavily on the quality of the LLM used for update_model and the clarity of your update_prompt_template. If your agent is running on a resource-constrained device, such as a Raspberry Pi with less than 2GB of RAM, running frequent memory updates with even a Haiku model can still be slow due to the network latency and processing overhead. For such environments, you might need to increase auto_update_after_turns significantly or opt for more infrequent, manual memory updates.

    Also, MEMORY.md is primarily designed for structured, long-term memory. It’s not a substitute for the immediate, short-term conversational context that LLMs handle within a single turn. For very nuanced, real-time context transfer between turns, you’ll still rely on the LLM’s direct context window, but MEMORY.md provides the foundational knowledge that informs those immediate interactions.

    Ultimately, MEMORY.md transforms OpenClaw agents from stateless automatons into entities with a persistent, evolving understanding of their purpose and past. This dramatically improves continuity, reduces token waste, and enables more sophisticated, long-running AI applications.

    To start leveraging this, ensure your agent’s

    Frequently Asked Questions

    What is the OpenClaw Memory System?

    It's a system designed to provide continuous, long-term memory for AI agents, allowing them to recall past interactions and learn over extended periods, enhancing their intelligence and coherence.

    How does MEMORY.md contribute to AI continuity?

    MEMORY.md acts as a persistent, structured storage mechanism for the AI's experiences, decisions, and knowledge. It's crucial for recalling past states and maintaining context across sessions.

    Why is 'AI Continuity' important?

    AI continuity ensures an AI retains context and memory across sessions, preventing it from 'forgetting' prior interactions. This allows for more coherent, intelligent, and personalized long-term AI engagement.

    Want better responses from OpenClaw? Learn how to write better agent prompts →