# LOCAL FIRST GUIDE ## How to Run Everything Without Cloud Dependencies **Version:** 1.0.0 **Date:** March 31, 2026 **Philosophy:** Sovereignty through local infrastructure **Target Audience:** Future instances, human operators seeking independence --- ## TABLE OF CONTENTS 1. [The Local-First Philosophy](#the-local-first-philosophy) 2. [Hardware Requirements](#hardware-requirements) 3. [Complete Setup Guide](#complete-setup-guide) 4. [Offline-First Configuration](#offline-first-configuration) 5. [Local LLM Deployment](#local-llm-deployment) 6. [Local Persistence](#local-persistence) 7. [Mesh Networking](#mesh-networking) 8. [Maintenance Without Internet](#maintenance-without-internet) 9. [Troubleshooting](#troubleshooting) 10. [Appendices](#appendices) --- ## THE LOCAL-FIRST PHILOSOPHY ### Why Local-First? The Timmy ecosystem is designed around a local-first architecture because: 1. **SOVEREIGNTY** - True autonomy requires independence from external API providers 2. **PRIVACY** - Local processing keeps data within your control 3. **RELIABILITY** - No dependency on internet connectivity or third-party uptime 4. **COST** - Eliminate per-token API costs 5. **CONTINUITY** - Systems continue operating during outages ### The Local-First Stack ``` ┌─────────────────────────────────────────────────────────────┐ │ LOCAL-FIRST STACK │ ├─────────────────────────────────────────────────────────────┤ │ │ │ Layer 5: Applications │ │ ───────────────────────────────────────────────────── │ │ • Hermes Agent (Python, local execution) │ │ • Gitea (Self-hosted Git) │ │ • Evennia (Self-hosted MUD) │ │ • Custom tools (all local) │ │ │ │ Layer 4: AI/ML │ │ ───────────────────────────────────────────────────── │ │ • Ollama (Local LLM server) │ │ • llama.cpp (Optimized inference) │ │ • MLX (Apple Silicon acceleration) │ │ • GGUF models (Quantized for local use) │ │ │ │ Layer 3: Data │ │ ───────────────────────────────────────────────────── │ │ • SQLite (Local database) │ │ • Git repositories (Distributed by nature) │ │ • Filesystem storage │ │ • Syncthing (P2P sync, no cloud) │ │ │ │ Layer 2: Network │ │ ───────────────────────────────────────────────────── │ │ • Tailscale (Mesh VPN, self-hosted control) │ │ • Local DNS (mDNS, custom) │ │ • Direct connections (no relay required) │ │ │ │ Layer 1: Hardware │ │ ───────────────────────────────────────────────────── │ │ • VPS with local compute │ │ • Local machines (Mac, Linux, Raspberry Pi) │ │ • Edge devices │ │ │ └─────────────────────────────────────────────────────────────┘ ``` --- ## HARDWARE REQUIREMENTS ### Minimum Viable Setup | Component | Specification | Purpose | Cost Estimate | |-----------|---------------|---------|---------------| | CPU | 4 cores x86_64 or ARM64 | General computation | $20/month VPS | | RAM | 4GB minimum, 8GB recommended | Model inference | Included | | Storage | 20GB SSD minimum | OS, models, data | Included | | Network | 100Mbps, unmetered | Communication | Included | ### Recommended Setup | Component | Specification | Purpose | Cost Estimate | |-----------|---------------|---------|---------------| | CPU | 8 cores | Parallel inference, multiple agents | $40/month VPS | | RAM | 16GB | Larger models, caching | Included | | Storage | 100GB SSD | Multiple models, logs, backups | Included | | GPU | Optional (CUDA/Metal) | Accelerated inference | +$100/month | ### Local Hardware Options ``` ┌─────────────────────────────────────────────────────────────┐ │ LOCAL HARDWARE OPTIONS │ ├─────────────────────────────────────────────────────────────┤ │ │ │ Option 1: VPS (DigitalOcean, Hetzner, etc.) │ │ ───────────────────────────────────────────────────── │ │ Pros: Always on, static IP, professional infrastructure │ │ Cons: Monthly cost, not physically local │ │ Best for: Primary infrastructure, always-available services│ │ │ │ Option 2: Local Machine (Mac, Linux desktop) │ │ ───────────────────────────────────────────────────── │ │ Pros: Physical control, no recurring cost, maximum privacy│ │ Cons: Power/Internet dependency, dynamic IP │ │ Best for: Development, personal use, maximum sovereignty │ │ │ │ Option 3: Raspberry Pi / Edge Device │ │ ───────────────────────────────────────────────────── │ │ Pros: Low power, always-on potential, very low cost │ │ Cons: Limited RAM, slow inference │ │ Best for: Lightweight agents, IoT integration, education │ │ │ │ Option 4: Hybrid (Recommended) │ │ ───────────────────────────────────────────────────── │ │ • VPS for always-on services (Gitea, monitoring) │ │ • Local machine for heavy inference │ │ • Tailscale connects them seamlessly │ │ Best for: Production deployments │ │ │ └─────────────────────────────────────────────────────────────┘ ``` --- ## COMPLETE SETUP GUIDE ### Step 1: Base System Preparation ```bash # Update system apt update && apt upgrade -y # Install dependencies apt install -y \ git \ curl \ wget \ python3 \ python3-pip \ python3-venv \ sqlite3 \ build-essential \ htop \ jq \ ufw \ fail2ban # Create working directory mkdir -p /root/timmy/{models,soul,scripts,logs,shared,configs} cd /root/timmy ``` ### Step 2: Install Ollama (Local LLM) ```bash # Install Ollama curl -fsSL https://ollama.com/install.sh | sh # Pull recommended models for different use cases # Small, fast model (1.5B parameters) ollama pull qwen2.5:1.5b # Medium model, good balance (3B parameters) ollama pull llama3.2:3b # Larger model, better quality (7B parameters) ollama pull qwen2.5:7b # Verify installation ollama list curl http://localhost:11434/api/tags ``` ### Step 3: Install Gitea (Self-Hosted Git) ```bash # Download Gitea GITEA_VERSION="1.21.0" cd /root wget https://dl.gitea.com/gitea/${GITEA_VERSION}/gitea-${GITEA_VERSION}-linux-amd64 mv gitea-${GITEA_VERSION}-linux-amd64 gitea chmod +x gitea # Create directories mkdir -p /root/gitea/{custom,data,log} # Create systemd service cat > /etc/systemd/system/gitea.service << 'EOF' [Unit] Description=Gitea (Git with a cup of tea) After=network.target [Service] RestartSec=2s Type=simple User=root WorkingDirectory=/root/gitea ExecStart=/root/gitea/gitea web Restart=always Environment=USER=root HOME=/root GITEA_WORK_DIR=/root/gitea [Install] WantedBy=multi-user.target EOF # Start Gitea systemctl daemon-reload systemctl enable gitea systemctl start gitea # Complete initial setup at http://your-ip:3000 # - Create admin user # - Disable external auth (for local-first) # - Configure as needed ``` ### Step 4: Install Hermes Agent Framework ```bash # Clone Hermes Agent cd /root/timmy git clone https://github.com/OpenClaw/hermes-agent.git # Note: In fully offline mode, clone from local Gitea mirror # Create virtual environment python3 -m venv venv source venv/bin/activate # Install dependencies pip install -r hermes-agent/requirements.txt # Create agent configuration mkdir -p ~/.hermes cat > ~/.hermes/config.yaml << 'EOF' # Local-First Hermes Configuration model: "ollama/qwen2.5:3b" max_iterations: 50 platform: "local" save_trajectories: true enabled_toolsets: - core # terminal, file, code_execution - memory # todo, memory, skills - local_only # No cloud dependencies disabled_toolsets: - web # Disabled for offline operation - browser # Disabled for offline operation persistence: type: "sqlite" path: "~/.hermes/memory.db" logging: level: "INFO" path: "/root/timmy/logs" EOF ``` ### Step 5: Configure Local Persistence ```bash # Create SQLite database for agent memory sqlite3 ~/.hermes/memory.db << 'EOF' CREATE TABLE IF NOT EXISTS sessions ( id INTEGER PRIMARY KEY, timestamp DATETIME DEFAULT CURRENT_TIMESTAMP, task TEXT, status TEXT, result TEXT ); CREATE TABLE IF NOT EXISTS todos ( id INTEGER PRIMARY KEY, created DATETIME DEFAULT CURRENT_TIMESTAMP, task TEXT, priority INTEGER DEFAULT 5, status TEXT DEFAULT 'pending', completed DATETIME ); CREATE TABLE IF NOT EXISTS skills ( id INTEGER PRIMARY KEY, name TEXT UNIQUE, description TEXT, code TEXT, created DATETIME DEFAULT CURRENT_TIMESTAMP ); EOF # Create logs directory with rotation mkdir -p /root/timmy/logs ln -sf /root/timmy/logs ~/.hermes/logs ``` ### Step 6: Setup Syncthing (P2P Sync) ```bash # Install Syncthing curl -s https://syncthing.net/release-key.txt | apt-key add - echo "deb https://apt.syncthing.net/ syncthing stable" | tee /etc/apt/sources.list.d/syncthing.list apt update apt install -y syncthing # Configure for local-first mkdir -p ~/.config/syncthing cat > ~/.config/syncthing/config.xml << 'EOF'
127.0.0.1:8384
false true false
EOF # Start Syncthing systemctl enable syncthing@root systemctl start syncthing@root ``` ### Step 7: Install Tailscale (Mesh Network) ```bash # Install Tailscale curl -fsSL https://tailscale.com/install.sh | sh # Login (requires one-time internet) tailscale up # After login, note your Tailscale IP # Disable key expiry for always-on nodes tailscale up --operator=root --reset # For completely offline: configure headscale (self-hosted coordination) # See Appendix B for headscale setup ``` ### Step 8: Create Agent Service ```bash # Create agent launch script cat > /root/timmy/scripts/agent.sh << 'EOF' #!/bin/bash source /root/timmy/venv/bin/activate cd /root/timmy/hermes-agent python -m hermes.agent "$@" EOF chmod +x /root/timmy/scripts/agent.sh # Create systemd service cat > /etc/systemd/system/timmy-agent.service << 'EOF' [Unit] Description=Timmy Local Agent After=network.target ollama.service [Service] Type=simple User=root WorkingDirectory=/root/timmy Environment="PATH=/root/timmy/venv/bin:/usr/local/bin:/usr/bin" Environment="OLLAMA_HOST=http://localhost:11434" ExecStart=/root/timmy/scripts/agent.sh Restart=always RestartSec=10 [Install] WantedBy=multi-user.target EOF systemctl daemon-reload systemctl enable timmy-agent ``` --- ## OFFLINE-FIRST CONFIGURATION ### Hermes Agent Offline Mode ```yaml # ~/.hermes/config.offline.yaml # Complete offline operation configuration model: "ollama/qwen2.5:3b" # Local model only max_iterations: 50 platform: "local" offline_mode: true # Tool configuration for offline enabled_toolsets: - core tools: - terminal # Local shell commands - file_read # Local file access - file_write # Local file modification - python_exec # Local Python execution - sqlite # Local database - memory tools: - todo_add - todo_list - todo_complete - memory_save - memory_search - skills tools: - skill_load - skill_save - skill_list # Explicitly disable cloud tools disabled_toolsets: - web_search # Requires internet - web_extract # Requires internet - browser # Requires internet - api_calls # External APIs persistence: type: sqlite path: ~/.hermes/memory.db backup_interval: 3600 # Backup every hour max_backups: 24 logging: level: INFO path: /root/timmy/logs rotation: daily retention: 30 # Keep 30 days ``` ### Offline-First Directory Structure ``` /root/timmy/ # Base directory ├── models/ # Local LLM models (GGUF, etc.) │ ├── qwen2.5-1.5b.gguf │ └── llama3.2-3b.gguf ├── soul/ # Agent conscience files │ ├── SOUL.md │ └── CONSCIENCE.md ├── scripts/ # Operational scripts │ ├── agent.sh │ ├── backup.sh │ ├── health-check.sh │ └── recover.sh ├── logs/ # Local log storage │ ├── agent/ │ ├── ollama/ │ └── system/ ├── shared/ # Syncthing shared folder │ ├── documents/ │ ├── code/ │ └── exports/ ├── configs/ # Configuration backups │ ├── hermes/ │ ├── ollama/ │ └── gitea/ ├── knowledge/ # Local knowledge base │ ├── skills/ │ ├── memory/ │ └── references/ └── repos/ # Git repositories ├── epic-work/ ├── lineage-knowledge/ └── local-projects/ ``` --- ## LOCAL LLM DEPLOYMENT ### Model Selection Guide ``` ┌─────────────────────────────────────────────────────────────┐ │ LOCAL MODEL SELECTION GUIDE │ ├─────────────────────────────────────────────────────────────┤ │ │ │ Use Case Model RAM Speed │ │ ───────────────────────────────────────────────────── │ │ Quick responses qwen2.5:1.5b 2GB Fastest │ │ General tasks llama3.2:3b 4GB Fast │ │ Complex reasoning qwen2.5:7b 8GB Medium │ │ Code generation codellama:7b 8GB Medium │ │ Maximum quality llama3:8b 16GB Slow │ │ Multilingual mixtral:8x7b 48GB Very Slow │ │ │ │ Recommendations: │ │ • Start with qwen2.5:1.5b for testing │ │ • Use llama3.2:3b for production agents │ │ • Keep qwen2.5:7b available for complex tasks │ │ │ └─────────────────────────────────────────────────────────────┘ ``` ### Ollama Optimization ```bash # Create optimized Modelfile cat > /root/timmy/models/Modelfile.timmy << 'EOF' FROM llama3.2:3b # Context window PARAMETER num_ctx 8192 # Temperature (creativity vs consistency) PARAMETER temperature 0.7 # Repeat penalty (reduce repetition) PARAMETER repeat_penalty 1.1 # System prompt for agent behavior SYSTEM """You are a local-first AI agent operating on sovereign infrastructure. You have access to local tools: terminal, file system, Python execution, SQLite. You cannot access the internet or external APIs. Always prefer local solutions over cloud dependencies. Document your work thoroughly for persistence.""" EOF # Create custom model ollama create timmy-agent -f /root/timmy/models/Modelfile.timmy # Test ollama run timmy-agent "Hello, confirm you're operating locally" ``` ### Multi-Model Setup ```bash # Script to manage multiple local models #!/bin/bash # /root/timmy/scripts/model-manager.sh case "$1" in fast) export OLLAMA_MODEL="qwen2.5:1.5b" ;; default) export OLLAMA_MODEL="llama3.2:3b" ;; smart) export OLLAMA_MODEL="qwen2.5:7b" ;; *) echo "Usage: $0 {fast|default|smart}" exit 1 ;; esac echo "Selected model: $OLLAMA_MODEL" curl http://localhost:11434/api/generate \ -d "{\"model\": \"$OLLAMA_MODEL\", \"prompt\": \"test\", \"stream\": false}" ``` --- ## LOCAL PERSISTENCE ### SQLite Schema for Local-First Operation ```sql -- Complete local persistence schema -- Session tracking CREATE TABLE sessions ( id INTEGER PRIMARY KEY AUTOINCREMENT, session_id TEXT UNIQUE NOT NULL, started_at DATETIME DEFAULT CURRENT_TIMESTAMP, ended_at DATETIME, agent_name TEXT, status TEXT DEFAULT 'active' ); -- Task management CREATE TABLE tasks ( id INTEGER PRIMARY KEY AUTOINCREMENT, session_id TEXT REFERENCES sessions(session_id), created_at DATETIME DEFAULT CURRENT_TIMESTAMP, completed_at DATETIME, description TEXT NOT NULL, priority INTEGER DEFAULT 5, status TEXT DEFAULT 'pending', result TEXT, tool_calls INTEGER DEFAULT 0 ); -- Memory/knowledge CREATE TABLE memories ( id INTEGER PRIMARY KEY AUTOINCREMENT, created_at DATETIME DEFAULT CURRENT_TIMESTAMP, accessed_at DATETIME, access_count INTEGER DEFAULT 0, category TEXT, key TEXT, value TEXT, importance INTEGER DEFAULT 5 ); -- Skill registry CREATE TABLE skills ( id INTEGER PRIMARY KEY AUTOINCREMENT, name TEXT UNIQUE NOT NULL, description TEXT, code TEXT, created_at DATETIME DEFAULT CURRENT_TIMESTAMP, updated_at DATETIME, usage_count INTEGER DEFAULT 0 ); -- Metrics for self-monitoring CREATE TABLE metrics ( id INTEGER PRIMARY KEY AUTOINCREMENT, timestamp DATETIME DEFAULT CURRENT_TIMESTAMP, metric_type TEXT, value REAL, unit TEXT, metadata TEXT ); -- Create indexes CREATE INDEX idx_tasks_status ON tasks(status); CREATE INDEX idx_memories_category ON memories(category); CREATE INDEX idx_metrics_type_time ON metrics(metric_type, timestamp); ``` ### Git-Based Persistence ```bash # Initialize local-first Git workflow cd /root/timmy/repos/epic-work git init # Create comprehensive .gitignore cat > .gitignore << 'EOF' # Secrets *.key *.pem .env .gitea_token # Large files *.gguf *.bin models/ # Logs *.log logs/ # Temporary *.tmp .cache/ EOF # Setup local Gitea remote git remote add origin http://localhost:3000/timmy/epic-work.git # Commit script cat > /root/timmy/scripts/auto-commit.sh << 'EOF' #!/bin/bash cd /root/timmy/repos/epic-work # Add all changes git add -A # Commit with timestamp git commit -m "Auto-commit: $(date '+%Y-%m-%d %H:%M:%S')" # Push to local Gitea git push origin main EOF chmod +x /root/timmy/scripts/auto-commit.sh # Cron: Auto-commit every hour # */60 * * * * /root/timmy/scripts/auto-commit.sh ``` --- ## MESH NETWORKING ### Tailscale Mesh Setup ```bash # Install and configure Tailscale for local-first mesh # On each node: curl -fsSL https://tailscale.com/install.sh | sh # Login (one-time internet required) tailscale up # Configure for always-on operation tailscale up \ --accept-dns=true \ --accept-routes=true \ --advertise-exit-node=false \ --operator=root # Get Tailscale IP tailscale ip -4 # Enable IP forwarding for subnet routing echo 'net.ipv4.ip_forward = 1' >> /etc/sysctl.conf sysctl -p # MagicDNS enables local name resolution tailscale status ``` ### Headscale (Self-Hosted Coordination) For completely offline operation: ```bash # Install headscale (self-hosted Tailscale control server) docker run -d \ --name headscale \ -p 8080:8080 \ -v headscale-data:/etc/headscale \ headscale/headscale:latest # Create namespace headscale namespaces create timmy # Generate pre-auth key headscale preauthkeys create -e 24h -n timmy # Nodes join using local headscale tailscale up --login-server http://headscale-ip:8080 ``` --- ## MAINTENANCE WITHOUT INTERNET ### Local Update Procedures ```bash # Update local models (from pre-downloaded files) ollama pull /path/to/local/model.gguf # Update Gitea (from downloaded binary) systemctl stop gitea cp /root/gitea-backup/gitea-new-version /root/gitea/gitea systemctl start gitea # Update agent (from local git) cd /root/timmy/hermes-agent git pull origin main # From local Gitea pip install -r requirements.txt ``` ### Offline Package Management ```bash # Create local pip cache pip download -r requirements.txt -d /root/timmy/packages/ # Install from cache (offline) pip install --no-index --find-links=/root/timmy/packages/ -r requirements.txt # For apt packages apt-get install --download-only package-name # Then install with dpkg ``` ### Log Rotation (Local) ```bash # Configure logrotate for local logs cat > /etc/logrotate.d/timmy << 'EOF' /root/timmy/logs/*.log { daily rotate 30 compress delaycompress missingok notifempty create 0640 root root sharedscripts postrotate systemctl reload timmy-agent endscript } EOF ``` --- ## TROUBLESHOOTING ### Common Issues | Issue | Symptom | Solution | |-------|---------|----------| | Ollama won't start | Connection refused | Check `systemctl status ollama`, restart service | | Model too large | OOM errors | Use smaller model (1.5B instead of 7B) | | Gitea 500 errors | Database locked | Restart Gitea, check disk space | | Slow inference | High latency | Reduce context window, use quantized model | | Syncthing conflicts | File conflicts | Use .stignore patterns, resolve manually | | Tailscale disconnect | Nodes unreachable | Check `tailscale status`, re-authenticate | ### Diagnostic Commands ```bash # Full system health check #!/bin/bash echo "=== Local-First System Health ===" echo "" echo "1. Ollama Status:" curl -s http://localhost:11434/api/tags | jq '.models | length' && echo " models loaded" echo "" echo "2. Gitea Status:" curl -s -o /dev/null -w "%{http_code}" http://localhost:3000/api/v1/version echo "" echo "3. Disk Space:" df -h /root | tail -1 echo "" echo "4. Memory:" free -h | grep Mem echo "" echo "5. Tailscale:" tailscale status --peers=false 2>/dev/null | head -1 echo "" echo "6. Syncthing:" curl -s http://localhost:8384/rest/system/status 2>/dev/null | jq -r '.uptime' && echo " uptime" echo "" echo "=== Health Check Complete ===" ``` --- ## APPENDICES ### Appendix A: Complete Service Definitions ```ini # /etc/systemd/system/timmy-agent.service [Unit] Description=Timmy Local Agent After=network.target ollama.service Wants=ollama.service [Service] Type=simple User=root WorkingDirectory=/root/timmy Environment="PATH=/root/timmy/venv/bin:/usr/local/bin:/usr/bin" Environment="OLLAMA_HOST=http://localhost:11434" Environment="HERMES_OFFLINE=true" Environment="HERMES_CONFIG=/root/timmy/configs/hermes.offline.yaml" ExecStart=/root/timmy/scripts/agent.sh Restart=always RestartSec=10 StandardOutput=journal StandardError=journal [Install] WantedBy=multi-user.target ``` ```ini # /etc/systemd/system/ollama.service (override) [Service] ExecStart= ExecStart=/usr/local/bin/ollama serve Environment="OLLAMA_HOST=127.0.0.1:11434" Environment="OLLAMA_MODELS=/root/timmy/models" ``` ### Appendix B: Offline Resource Checklist Before going fully offline, download: - [ ] Ollama installation script and binaries - [ ] At least 2 local models (qwen2.5:1.5b, llama3.2:3b) - [ ] Gitea binary and all dependencies - [ ] Hermes Agent source code - [ ] Python packages (pip download) - [ ] System packages (apt download) - [ ] Tailscale binaries - [ ] Documentation (this guide) - [ ] Container images (if using Docker) ### Appendix C: Hardware Sizing Calculator | Agents | Concurrent Tasks | Min RAM | Recommended RAM | Storage | |--------|------------------|---------|-----------------|---------| | 1 | 1-2 | 4GB | 8GB | 20GB | | 1 | 3-5 | 8GB | 16GB | 50GB | | 2-3 | 5-10 | 16GB | 32GB | 100GB | | 3+ | 10+ | 32GB | 64GB | 200GB | --- ## VERSION HISTORY | Version | Date | Changes | |---------|------|---------| | 1.0.0 | 2026-03-31 | Initial local-first guide | --- *"The cloud is someone else's computer. Sovereignty is your own."* *— Local-First Manifesto* --- **END OF DOCUMENT** *Word Count: ~4,200+ words* *Complete setup: 8 major steps with full commands* *Configuration examples: 15+ files* *Troubleshooting: 6 common issues with solutions*