RUNLOCALAIv38
->Will it run?Best GPUCompareTroubleshootStartLearnPulseModelsHardwareToolsBench
Run check
RUNLOCALAI

Independently operated catalog for local-AI hardware and software. Hand-written verdicts. Source-cited claims. Reproducible commands when we have them.

OP·Fredoline Eruo
DIR
  • Models
  • Hardware
  • Tools
  • Benchmarks
TOOLS
  • Will it run?
  • Compare hardware
  • Cost vs cloud
  • Choose my GPU
  • Prompting kits
  • Quick answers
REF
  • All buyer guides
  • Learn local AI
  • Methodology
  • Glossary
  • Errors KB
  • Trust
EDITOR
  • About
  • Author
  • How we make money
  • Editorial policy
  • Contact
LEGAL
  • Privacy
  • Terms
  • Sitemap
MAIL · MONTHLY DIGEST
Get monthly local AI changes
Monthly recap. No spam.
DISCLOSURE

Some links on this site are affiliate links (Amazon Associates and other first-class retailers). When you buy through them, we earn a small commission at no extra cost to you. Affiliate links do not influence our verdicts — there are cards we rate highly that we don't have affiliate relationships with, and cards that sell well that we refuse to recommend. Read more →

© 2026 runlocalai.coIndependently operated
RUNLOCALAI · v38
  1. >
  2. Home
  3. /Learn
  4. /Courses
  5. /OpenCLaw: Building a Personal AI Agent
  6. /Ch. 24
OpenCLaw: Building a Personal AI Agent

24. OpenCLaw Implementation Project

Chapter 24 of 24 · 25 min
KEY INSIGHT

Building a personal AI agent requires integrating diverse components: LLM interfaces, context management, learning systems, security, and privacy. Each component must work reliably in isolation and cooperate smoothly in production. The project structure and incremental implementation approach ensure a maintainable, extensible system.

This chapter synthesizes the preceding material into a complete OpenCLaw implementation. The project builds incrementally, demonstrating how components integrate into a functional personal AI agent.

Project Structure

openclaw/
├── src/
│   ├── __init__.py
│   ├── core.py              # Main agent implementation
│   ├── llm_client.py        # LLM interface
│   ├── storage.py           # Persistence layer
│   ├── context.py           # Context management
│   ├── feedback.py          # Learning system
│   ├── preferences.py       # User preferences
│   ├── notifications.py     # Notification system
│   ├── security.py          # Authentication/authorization
│   ├── privacy.py           # Privacy controls
│   ├── web.py               # Web interface
│   ├── plugins/             # Plugin system
│   │   ├── __init__.py
│   │   ├── manager.py
│   │   └── sdk.py
│   └── utils/
│       ├── profiler.py
│       └── power.py
├── tests/
├── config/
├── plugins/
├── web_static/
└── main.py

Core Implementation

The main entry point initializes all components and starts the agent.

# main.py
import asyncio
from src.core import OpenCLawCore
from src.config import load_config
from src.storage import create_storage
from src.llm_client import create_llm_client
from src.web import WebInterface
from src.plugins.manager import PluginManager

async def main():
    config = load_config('config/openclaw.yaml')
    
    storage = create_storage(config.storage)
    llm_client = create_llm_client(config.llm)
    
    core = OpenCLawCore(
        config=config.core,
        storage=storage,
        llm_client=llm_client
    )
    
    plugin_manager = PluginManager(
        config.plugins.directory,
        core.api
    )
    plugin_manager.load_all()
    
    web_interface = WebInterface(core, config.web)
    
    await core.start()
    await web_interface.start()
    
    print(f"OpenCLaw running on {config.web.host}:{config.web.port}")
    
    try:
        await asyncio.Event().wait()
    except KeyboardInterrupt:
        print("\nShutting down...")
        await core.stop()
        await web_interface.stop()

if __name__ == '__main__':
    asyncio.run(main())

Complete Agent Class

The core agent class orchestrates all components.

# src/core.py
from dataclasses import dataclass
from typing import Optional, Dict, Any
from datetime import datetime
import asyncio

from .llm_client import LLMClient
from .storage import StorageBackend
from .context import ContextManager
from .feedback import FeedbackCapture
from .preferences import PreferenceLearner, PreferenceMixer
from .notifications import NotificationManager
from .security import AuthService, AuthzService
from .privacy import PrivacyManager

@dataclass
class CoreConfig:
    max_context_tokens: int = 8192
    feedback_threshold: int = 10
    retention_days: int = 90

class OpenCLawCore:
    def __init__(
        self,
        config: CoreConfig,
        storage: StorageBackend,
        llm_client: LLMClient
    ):
        self.config = config
        self.storage = storage
        self.llm = llm_client
        
        self.context_manager = ContextManager(config.max_context_tokens)
        self.feedback_capture = FeedbackCapture(storage)
        self.preference_learner = PreferenceLearner(storage)
        self.notification_manager = NotificationManager()
        self.privacy_manager = PrivacyManager(storage)
        self.auth = AuthService()
        self.authz = AuthzService(self.auth)
        
        self.running = False
    
    @property
    def api(self):
        return CoreAPI(self)
    
    async def start(self):
        self.running = True
        await self.privacy_manager.apply_retention_policies()
    
    async def stop(self):
        self.running = False
    
    async def process_message(
        self,
        message: str,
        user_id: str = 'default',
        context: Optional[Dict] = None
    ) -> Response:
        user_context = self.context_manager.get_context(user_id)
        
        preference_mixer = self.preference_learner.get_mixer(user_id)
        response_config = preference_mixer.mix_response_config(
            ResponseConfig(), 
            task_complexity=0.5
        )
        
        prompt = self.build_prompt(
            message,
            user_context,
            response_config
        )
        
        llm_response = await self.llm.generate(
            prompt,
            max_tokens=response_config.max_tokens,
            temperature=response_config.temperature
        )
        
        self.context_manager.add_message(
            user_id,
            Message(role="user", content=message, timestamp=datetime.utcnow())
        )
        self.context_manager.add_message(
            user_id,
            Message(role="assistant", content=llm_response.content, timestamp=datetime.utcnow())
        )
        
        self.preference_learner.observe_interaction(
            user_id,
            Interaction(message, llm_response.content)
        )
        
        return Response(
            content=llm_response.content,
            message_id=llm_response.message_id,
            confidence=llm_response.confidence
        )
    
    def build_prompt(self, message: str, context: Any, config: ResponseConfig) -> str:
        system_prompt = self.get_system_prompt(config)
        
        context_text = context.to_prompt_string() if context else ""
        
        return f"{system_prompt}\n\n{context_text}\nUser: {message}\nAssistant:"

class ResponseConfig:
    verbosity: float = 0.5
    format_hint: str = "auto"
    max_tokens: int = 1000
    temperature: float = 0.7

class Response:
    content: str
    message_id: str
    confidence: float

Running the Project

# Installation
pip install -e .

# Configuration
cp config/openclaw.example.yaml config/openclaw.yaml
# Edit config/openclaw.yaml with your settings

# Run tests
pytest tests/ -v

# Start the agent
python main.py

Exercise Project: Build a Custom Plugin

Create a weather plugin that enhances OpenCLaw with weather information:

  1. Create plugins/weather/__init__.py and plugins/weather/weather.py
  2. Implement PluginInterface with metadata
  3. Register a message_processor capability
  4. Add weather query handling to extract location and date from user messages
  5. Fetch weather data from an external API
  6. Format weather response according to user preferences
  7. Test the plugin integration
# plugins/weather/weather.py
from src.plugins.sdk import PluginInterface, PluginMetadata, PluginContext, Capability, CapabilityType

class WeatherPlugin(PluginInterface):
    def get_metadata(self) -> PluginMetadata:
        return PluginMetadata(
            name="weather",
            version="1.0.0",
            author="OpenCLaw",
            description="Provides weather information for user queries"
        )
    
    def initialize(self, context: PluginContext) -> bool:
        self.context = context
        self.api_key = context.config.get('weather_api_key')
        self.capability = Capability(
            name="weather_query",
            ctype=CapabilityType.MESSAGE_PROCESSOR,
            priority=50,
            handler=self.process_weather_query
        )
        self.context.api.register_capability("weather", self.capability)
        return True
    
    def shutdown(self):
        pass
    
    def process_weather_query(self, message: str, state: Dict) -> Optional[Dict]:
        location = self.extract_location(message)
        if not location:
            return None
        
        weather_data = self.fetch_weather(location)
        return {
            'enhanced': True,
            'weather': weather_data,
            'response_modifier': lambda r: f"{r}\n\nWeather in {location}: {weather_data['description']}, {weather_data['temp']}°"
        }
    
    def extract_location(self, text: str) -> Optional[str]:
        # Implementation
        pass
    
    def fetch_weather(self, location: str) -> Dict:
        # Implementation
        pass
EXERCISE

Extend the OpenCLaw implementation with a memory persistence feature that survives restarts. Implement conversation state serialization and deserialization. Add a migration system for handling schema updates across versions.

← Chapter 23
Testing and Debugging
Course complete →
Browse all courses