945 lines
27 KiB
Markdown
945 lines
27 KiB
Markdown
# 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'
|
|
<?xml version="1.0" encoding="UTF-8"?>
|
|
<configuration version="37">
|
|
<gui enabled="true" tls="false">
|
|
<address>127.0.0.1:8384</address>
|
|
</gui>
|
|
<options>
|
|
<globalAnnounceEnabled>false</globalAnnounceEnabled> <!-- Disable public relays -->
|
|
<localAnnounceEnabled>true</localAnnounceEnabled> <!-- Local discovery only -->
|
|
<relaysEnabled>false</relaysEnabled> <!-- No relay servers -->
|
|
</options>
|
|
</configuration>
|
|
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*
|