refactor: restructure into hermes/ and openclaw/ directories

- Split cloudinit.tf into cloudinit-hermes.tf and cloudinit-openclaw.tf
- Split variables.tf into variables-common.tf, variables-hermes.tf, variables-openclaw.tf
- Move templates into hermes/templates/ and openclaw/templates/
- Move models/ into openclaw/models/
- Move hermes-openclaw.json to openclaw/openclaw-reference.json
- Move hermes docs to hermes/docs/
- OpenClaw cloudinit now uses variables instead of hardcoded values
- All 48 variable references verified against definitions
This commit is contained in:
Mermaid Man 2026-04-24 19:45:03 +00:00
parent 8a94313bd3
commit ea73745147
21 changed files with 277 additions and 216 deletions

View file

@ -0,0 +1,56 @@
{
"anthropic": {
"baseUrl": "https://api.anthropic.com/v1",
"api": "anthropic-messages",
"models": [
{
"id": "claude-3.5-sonnet",
"name": "Claude 3.5 Sonnet",
"reasoning": true,
"input": ["text", "image"],
"contextWindow": 200000,
"maxTokens": 8192
},
{
"id": "claude-3.5-sonnet-20241022",
"name": "Claude 3.5 Sonnet (New)",
"reasoning": true,
"input": ["text", "image"],
"contextWindow": 200000,
"maxTokens": 8192
},
{
"id": "claude-3.5-haiku",
"name": "Claude 3.5 Haiku",
"reasoning": false,
"input": ["text", "image"],
"contextWindow": 200000,
"maxTokens": 8192
},
{
"id": "claude-3-opus",
"name": "Claude 3 Opus",
"reasoning": true,
"input": ["text", "image"],
"contextWindow": 200000,
"maxTokens": 4096
},
{
"id": "claude-3-sonnet",
"name": "Claude 3 Sonnet",
"reasoning": false,
"input": ["text", "image"],
"contextWindow": 200000,
"maxTokens": 4096
},
{
"id": "claude-3-haiku",
"name": "Claude 3 Haiku",
"reasoning": false,
"input": ["text", "image"],
"contextWindow": 200000,
"maxTokens": 4096
}
]
}
}

View file

@ -0,0 +1,90 @@
{
"venice": {
"baseUrl": "https://api.venice.ai/api/v1",
"api": "openai-completions",
"models": {
"zai-org-glm-5": {
"name": "GLM 5",
"reasoning": true,
"input": ["text"],
"contextWindow": 202752,
"maxTokens": 8192
},
"olafangensan-glm-4.7-flash-heretic": {
"name": "GLM 4.7 Flash Heretic",
"reasoning": true,
"input": ["text"],
"contextWindow": 131072,
"maxTokens": 8192
},
"kimi-k2-5": {
"name": "Kimi K2.5",
"reasoning": true,
"input": ["text", "image"],
"contextWindow": 256000,
"maxTokens": 65536
},
"deepseek-v3.2": {
"name": "DeepSeek V3.2",
"reasoning": true,
"input": ["text"],
"contextWindow": 64000,
"maxTokens": 8192
}
}
},
"openai": {
"baseUrl": "https://api.openai.com/v1",
"api": "openai-completions",
"models": {
"gpt-4o": {
"name": "GPT-4o",
"reasoning": false,
"input": ["text", "image"],
"contextWindow": 128000,
"maxTokens": 16384
},
"gpt-4o-mini": {
"name": "GPT-4o Mini",
"reasoning": false,
"input": ["text", "image"],
"contextWindow": 128000,
"maxTokens": 16384
},
"o1": {
"name": "o1",
"reasoning": true,
"input": ["text", "image"],
"contextWindow": 200000,
"maxTokens": 100000
},
"o1-mini": {
"name": "o1 Mini",
"reasoning": true,
"input": ["text", "image"],
"contextWindow": 128000,
"maxTokens": 65536
}
}
},
"anthropic": {
"baseUrl": "https://api.anthropic.com/v1",
"api": "anthropic-messages",
"models": {
"claude-3.5-sonnet": {
"name": "Claude 3.5 Sonnet",
"reasoning": true,
"input": ["text", "image"],
"contextWindow": 200000,
"maxTokens": 8192
},
"claude-3.5-haiku": {
"name": "Claude 3.5 Haiku",
"reasoning": false,
"input": ["text", "image"],
"contextWindow": 200000,
"maxTokens": 8192
}
}
}
}

View file

@ -0,0 +1,40 @@
{
"gemini": {
"baseUrl": "https://generativelanguage.googleapis.com/v1beta",
"api": "google-ai",
"models": [
{
"id": "gemini-2.0-flash",
"name": "Gemini 2.0 Flash",
"reasoning": true,
"input": ["text", "image", "video"],
"contextWindow": 1048576,
"maxTokens": 8192
},
{
"id": "gemini-1.5-pro",
"name": "Gemini 1.5 Pro",
"reasoning": true,
"input": ["text", "image", "video", "audio"],
"contextWindow": 2097152,
"maxTokens": 65536
},
{
"id": "gemini-1.5-flash",
"name": "Gemini 1.5 Flash",
"reasoning": false,
"input": ["text", "image", "video", "audio"],
"contextWindow": 1048576,
"maxTokens": 8192
},
{
"id": "gemini-1.5-flash-8b",
"name": "Gemini 1.5 Flash 8B",
"reasoning": false,
"input": ["text", "image"],
"contextWindow": 1048576,
"maxTokens": 8192
}
]
}
}

56
openclaw/models/groq.json Normal file
View file

@ -0,0 +1,56 @@
{
"groq": {
"baseUrl": "https://api.groq.com/openai/v1",
"api": "openai-completions",
"models": [
{
"id": "llama-3.3-70b-versatile",
"name": "Llama 3.3 70B Versatile",
"reasoning": false,
"input": ["text"],
"contextWindow": 128000,
"maxTokens": 8192
},
{
"id": "llama-3.1-70b-versatile",
"name": "Llama 3.1 70B Versatile",
"reasoning": false,
"input": ["text"],
"contextWindow": 131072,
"maxTokens": 8192
},
{
"id": "llama-3.1-8b-instant",
"name": "Llama 3.1 8B Instant",
"reasoning": false,
"input": ["text"],
"contextWindow": 131072,
"maxTokens": 8192
},
{
"id": "mixtral-8x7b-32768",
"name": "Mixtral 8x7B",
"reasoning": false,
"input": ["text"],
"contextWindow": 32768,
"maxTokens": 4096
},
{
"id": "gemma2-9b-it",
"name": "Gemma 2 9B",
"reasoning": false,
"input": ["text"],
"contextWindow": 8192,
"maxTokens": 8192
},
{
"id": "deepseek-r1-distill-llama-70b",
"name": "DeepSeek R1 Distill Llama 70B",
"reasoning": true,
"input": ["text"],
"contextWindow": 131072,
"maxTokens": 8192
}
]
}
}

View file

@ -0,0 +1,72 @@
{
"openai": {
"baseUrl": "https://api.openai.com/v1",
"api": "openai-completions",
"models": [
{
"id": "gpt-4o",
"name": "GPT-4o",
"reasoning": false,
"input": ["text", "image", "audio"],
"contextWindow": 128000,
"maxTokens": 16384
},
{
"id": "gpt-4o-mini",
"name": "GPT-4o Mini",
"reasoning": false,
"input": ["text", "image"],
"contextWindow": 128000,
"maxTokens": 16384
},
{
"id": "gpt-4-turbo",
"name": "GPT-4 Turbo",
"reasoning": false,
"input": ["text", "image"],
"contextWindow": 128000,
"maxTokens": 4096
},
{
"id": "gpt-4",
"name": "GPT-4",
"reasoning": false,
"input": ["text"],
"contextWindow": 8192,
"maxTokens": 4096
},
{
"id": "o1",
"name": "o1",
"reasoning": true,
"input": ["text", "image"],
"contextWindow": 200000,
"maxTokens": 100000
},
{
"id": "o1-mini",
"name": "o1 Mini",
"reasoning": true,
"input": ["text", "image"],
"contextWindow": 128000,
"maxTokens": 65536
},
{
"id": "o1-pro",
"name": "o1 Pro",
"reasoning": true,
"input": ["text"],
"contextWindow": 200000,
"maxTokens": 100000
},
{
"id": "gpt-3.5-turbo",
"name": "GPT-3.5 Turbo",
"reasoning": false,
"input": ["text"],
"contextWindow": 16385,
"maxTokens": 4096
}
]
}
}

View file

@ -0,0 +1,72 @@
{
"openrouter": {
"baseUrl": "https://openrouter.ai/api/v1",
"api": "openai-completions",
"models": [
{
"id": "anthropic/claude-3.5-sonnet",
"name": "Claude 3.5 Sonnet (via OpenRouter)",
"reasoning": true,
"input": ["text", "image"],
"contextWindow": 200000,
"maxTokens": 8192
},
{
"id": "openai/gpt-4o",
"name": "GPT-4o (via OpenRouter)",
"reasoning": false,
"input": ["text", "image"],
"contextWindow": 128000,
"maxTokens": 16384
},
{
"id": "google/gemini-pro-1.5",
"name": "Gemini Pro 1.5 (via OpenRouter)",
"reasoning": true,
"input": ["text", "image", "video"],
"contextWindow": 1000000,
"maxTokens": 8192
},
{
"id": "meta-llama/llama-3.1-405b-instruct",
"name": "Llama 3.1 405B (via OpenRouter)",
"reasoning": false,
"input": ["text"],
"contextWindow": 131072,
"maxTokens": 4096
},
{
"id": "deepseek/deepseek-r1",
"name": "DeepSeek R1 (via OpenRouter)",
"reasoning": true,
"input": ["text"],
"contextWindow": 64000,
"maxTokens": 8192
},
{
"id": "qwen/qwen-2.5-72b-instruct",
"name": "Qwen 2.5 72B (via OpenRouter)",
"reasoning": false,
"input": ["text"],
"contextWindow": 131072,
"maxTokens": 8192
},
{
"id": "mistralai/mistral-large",
"name": "Mistral Large (via OpenRouter)",
"reasoning": true,
"input": ["text"],
"contextWindow": 131072,
"maxTokens": 8192
},
{
"id": "x-ai/grok-2",
"name": "Grok 2 (via OpenRouter)",
"reasoning": true,
"input": ["text", "image"],
"contextWindow": 131072,
"maxTokens": 8192
}
]
}
}

View file

@ -0,0 +1,80 @@
{
"venice": {
"baseUrl": "https://api.venice.ai/api/v1",
"api": "openai-completions",
"models": [
{
"id": "zai-org-glm-5",
"name": "GLM 5",
"reasoning": true,
"input": ["text"],
"contextWindow": 202752,
"maxTokens": 8192
},
{
"id": "zai-org-glm-4.7",
"name": "GLM 4.7",
"reasoning": true,
"input": ["text"],
"contextWindow": 202752,
"maxTokens": 8192
},
{
"id": "olafangensan-glm-4.7-flash-heretic",
"name": "GLM 4.7 Flash Heretic",
"reasoning": true,
"input": ["text"],
"contextWindow": 131072,
"maxTokens": 8192
},
{
"id": "kimi-k2-5",
"name": "Kimi K2.5",
"reasoning": true,
"input": ["text", "image"],
"contextWindow": 256000,
"maxTokens": 65536
},
{
"id": "deepseek-v3.2",
"name": "DeepSeek V3.2",
"reasoning": true,
"input": ["text"],
"contextWindow": 64000,
"maxTokens": 8192
},
{
"id": "qwen3-coder-480b-a35b-instruct",
"name": "Qwen3 Coder 480B",
"reasoning": true,
"input": ["text"],
"contextWindow": 131072,
"maxTokens": 16384
},
{
"id": "llama-3.1-405b",
"name": "Llama 3.1 405B",
"reasoning": false,
"input": ["text"],
"contextWindow": 131072,
"maxTokens": 4096
},
{
"id": "llama-3.1-70b",
"name": "Llama 3.1 70B",
"reasoning": false,
"input": ["text"],
"contextWindow": 131072,
"maxTokens": 4096
},
{
"id": "mistral-123b",
"name": "Mistral Large 2",
"reasoning": true,
"input": ["text"],
"contextWindow": 131072,
"maxTokens": 8192
}
]
}
}

View file

@ -0,0 +1,122 @@
{
"auth": {
"profiles": {
"venice:default": {
"provider": "venice",
"mode": "api_key"
}
}
},
"models": {
"mode": "merge",
"providers": {
"venice": {
"baseUrl": "https://api.venice.ai/api/v1",
"api": "openai-completions",
"models": [
{
"id": "zai-org-glm-5",
"name": "GLM 5",
"reasoning": true,
"input": ["text"],
"contextWindow": 202752,
"maxTokens": 8192
},
{
"id": "zai-org-glm-4.7",
"name": "GLM 4.7",
"reasoning": true,
"input": ["text"],
"contextWindow": 202752,
"maxTokens": 8192
},
{
"id": "olafangensan-glm-4.7-flash-heretic",
"name": "GLM 4.7 Flash Heretic",
"reasoning": true,
"input": ["text"],
"contextWindow": 131072,
"maxTokens": 8192
},
{
"id": "kimi-k2-5",
"name": "Kimi K2.5",
"reasoning": true,
"input": ["text", "image"],
"contextWindow": 256000,
"maxTokens": 65536
},
{
"id": "deepseek-v3.2",
"name": "DeepSeek V3.2",
"reasoning": true,
"input": ["text"],
"contextWindow": 64000,
"maxTokens": 8192
},
{
"id": "qwen3-coder-480b-a35b-instruct",
"name": "Qwen3 Coder 480B",
"reasoning": true,
"input": ["text"],
"contextWindow": 131072,
"maxTokens": 16384
}
]
}
}
},
"agents": {
"defaults": {
"model": {
"primary": "venice/olafangensan-glm-4.7-flash-heretic",
"fallbacks": ["venice/zai-org-glm-5"]
},
"workspace": "/home/openclaw/.openclaw/workspace"
},
"list": [
{
"id": "hermes",
"default": true,
"workspace": "/home/openclaw/.openclaw/workspace"
}
]
},
"tools": {
"web": {
"search": {
"enabled": true,
"provider": "brave",
"apiKey": "${BRAVE_SEARCH_API_KEY}"
},
"fetch": { "enabled": true }
},
"exec": {
"security": "allowlist",
"ask": "on-miss"
}
},
"messages": {
"queue": { "mode": "collect" },
"ackReactionScope": "all"
},
"channels": {
"discord": {
"enabled": true,
"token": "${DISCORD_BOT_TOKEN}",
"groupPolicy": "allowlist",
"guilds": {
"YOUR_GUILD_ID": {
"requireMention": false,
"users": ["YOUR_USER_ID"],
"channels": { "*": { "allow": true } }
}
}
}
},
"gateway": {
"port": 18789,
"mode": "local",
"bind": "loopback"
}
}

View file

@ -0,0 +1,372 @@
#cloud-config
# OpenClaw Gateway Bootstrap
# Update packages
package_update: true
package_upgrade: true
# Install required packages
packages:
- curl
- git
- fail2ban
- ufw
- jq
- gnupg
- ca-certificates
- software-properties-common
# Create admin user (if different from root)
users:
- name: ${admin_user}
sudo: ALL=(ALL) NOPASSWD:ALL
shell: /bin/bash
ssh_authorized_keys: ${jsonencode(admin_ssh_keys)}
groups: [sudo, systemd-journal]
# Write system configuration files
write_files:
# SSH hardening configuration
- path: /etc/ssh/sshd_config.d/99-hardening.conf
content: |
# SSH Security Hardening
Port ${ssh_port}
PermitRootLogin no
PasswordAuthentication no
PubkeyAuthentication yes
AuthorizedKeysFile .ssh/authorized_keys
ChallengeResponseAuthentication no
UsePAM yes
X11Forwarding no
PrintMotd no
AcceptEnv LANG LC_*
Subsystem sftp /usr/lib/openssh/sftp-server
permissions: '0644'
# Fail2ban SSH configuration
%{if enable_fail2ban}
- path: /etc/fail2ban/jail.d/sshd.local
content: |
[sshd]
enabled = true
port = ${ssh_port}
filter = sshd
logpath = /var/log/auth.log
maxretry = 3
bantime = 3600
findtime = 600
permissions: '0644'
%{endif}
# OpenClaw environment file
- path: /etc/openclaw.env
content: |
# Secrets injected during provisioning - DO NOT commit to version control
# Inference API keys
%{if venice_api_key != ""}
VENICE_API_KEY=${venice_api_key}
%{endif}
%{if brave_search_api_key != ""}
BRAVE_SEARCH_API_KEY=${brave_search_api_key}
%{endif}
# Discord configuration
%{if discord_bot_token != ""}
DISCORD_BOT_TOKEN=${discord_bot_token}
%{endif}
%{if discord_server_id != ""}
DISCORD_SERVER_ID=${discord_server_id}
%{endif}
%{if length(discord_user_id) > 0}
DISCORD_USER_ID=${jsonencode(discord_user_id)}
%{endif}
# Tailscale auth key (if enabled)
%{if enable_tailscale && tailscale_auth_key != ""}
TAILSCALE_AUTH_KEY=${tailscale_auth_key}
%{endif}
permissions: '0600'
# OpenClaw configuration file (uses env var references for secrets)
- path: /home/${admin_user}/.openclaw/openclaw.json
content: |
{
"auth": {
"profiles": {
"venice:default": {
"provider": "venice",
"mode": "api_key"
}
}
},
"models": {
"mode": "merge",
"providers": ${models_config}
},
"agents": {
"defaults": {
"model": {
"primary": "${primary_model}",
"fallbacks": ${fallback_models}
},
"workspace": "/home/${admin_user}/.openclaw/workspace"
},
"list": [
{
"id": "${agent_name}",
"default": true,
"workspace": "/home/${admin_user}/.openclaw/workspace"
}
]
},
"tools": {
"web": {
"search": {
"enabled": true,
"provider": "brave",
"apiKey": "$${BRAVE_SEARCH_API_KEY}"
},
"fetch": { "enabled": true }
},
"exec": {
"security": "allowlist",
"ask": "on-miss"
}
},
"messages": {
"queue": { "mode": "collect" },
"ackReactionScope": "all"
},
"channels": {
"discord": {
"enabled": true,
"token": "$${DISCORD_BOT_TOKEN}",
"groupPolicy": "allowlist",
"guilds": {
"${discord_server_id}": {
"requireMention": false,
"users": ${jsonencode(discord_user_id)},
"channels": { "*": { "allow": true } }
}
}
}
},
"gateway": {
"port": 18789,
"mode": "local",
"bind": "loopback"
}
}
permissions: '0644'
# Systemd service for OpenClaw Gateway
- path: /etc/systemd/system/openclaw-gateway.service
content: |
[Unit]
Description=OpenClaw Gateway Service
After=network.target
Wants=network-online.target
[Service]
Type=simple
ExecStart=/usr/local/bin/openclaw gateway run
Restart=on-failure
RestartSec=10
StandardOutput=journal
StandardError=journal
SyslogIdentifier=openclaw-gateway
EnvironmentFile=/etc/openclaw.env
WorkingDirectory=/home/${admin_user}/.openclaw
[Install]
WantedBy=multi-user.target
permissions: '0644'
# Health check script
- path: /usr/local/bin/openclaw-health-check.sh
content: |
#!/bin/bash
# OpenClaw Gateway Health Check
set -e
echo "=== OpenClaw Health Check ==="
echo ""
# Check if OpenClaw is installed
if command -v openclaw &> /dev/null; then
echo "✓ OpenClaw installed: $(openclaw --version)"
else
echo "✗ OpenClaw not found"
exit 1
fi
# Check if gateway is running
if systemctl is-active --quiet openclaw-gateway; then
echo "✓ Gateway service running"
else
echo "✗ Gateway service not running"
fi
# Check if gateway is listening
if lsof -i :18789 > /dev/null 2>&1; then
echo "✓ Gateway listening on port 18789"
else
echo "✗ Gateway not listening on port 18789"
fi
# Check firewall
if ufw status | grep -q "Status: active"; then
echo "✓ Firewall active"
else
echo "⚠ Firewall not active"
fi
# Check fail2ban
%{if enable_fail2ban}
if systemctl is-active --quiet fail2ban; then
echo "✓ fail2ban running"
else
echo "⚠ fail2ban not running"
fi
%{endif}
echo ""
echo "=== End Health Check ==="
permissions: '0755'
%{if enable_swap}
# Swap creation script
- path: /usr/local/bin/create-swap.sh
content: |
#!/bin/bash
set -e
if [ ! -f /swapfile ]; then
fallocate -l ${swap_size}G /swapfile
chmod 600 /swapfile
mkswap /swapfile
swapon /swapfile
echo '/swapfile none swap sw 0 0' >> /etc/fstab
echo "Created ${swap_size}GB swap"
else
echo "Swap already exists"
fi
permissions: '0755'
%{endif}
%{if enable_tailscale}
# Tailscale setup script
- path: /usr/local/bin/setup-tailscale.sh
content: |
#!/bin/bash
set -e
curl -fsSL https://tailscale.com/install.sh | sh
tailscale up --authkey=${tailscale_auth_key} --ssh
# Wait for Tailscale to connect
sleep 5
# Enable Tailscale Serve for gateway access
# This exposes the gateway on the tailnet via HTTPS
tailscale serve --bg 18789 || echo "Note: Tailscale serve may require 'Serve' to be enabled in admin console"
echo "Tailscale configured and serving on port 18789"
permissions: '0755'
%{endif}
# Run commands
runcmd:
# Create admin user home directory
- mkdir -p /home/${admin_user}
- chown ${admin_user}:${admin_user} /home/${admin_user}
%{if enable_swap}
# Create swapfile
- /usr/local/bin/create-swap.sh
%{endif}
# Install Node.js ${node_version}
- curl -fsSL https://deb.nodesource.com/setup_${node_version}.x | bash -
- apt-get install -y nodejs
- node --version
- npm --version
# Install OpenClaw
%{if openclaw_version == "latest"}
- curl -fsSL https://openclaw.ai/install.sh | bash
%{else}
%{if openclaw_version == "lts"}
- curl -fsSL https://openclaw.ai/install.sh | bash -s -- --version lts
%{else}
- curl -fsSL https://openclaw.ai/install.sh | bash -s -- --version ${openclaw_version}
%{endif}
%{endif}
- openclaw --version || echo "OpenClaw installed, needs configuration"
# Create OpenClaw config directory
- mkdir -p /home/${admin_user}/.openclaw/workspace
- chown -R ${admin_user}:${admin_user} /home/${admin_user}/.openclaw
# Configure firewall (SSH only)
- ufw default deny incoming
- ufw default allow outgoing
- ufw allow ${ssh_port}/tcp
- ufw --force enable
%{if enable_fail2ban}
# Enable fail2ban
- systemctl enable fail2ban
- systemctl start fail2ban
%{endif}
%{if enable_unattended_upgrades}
# Enable automatic security updates
- apt-get install -y unattended-upgrades
- dpkg-reconfigure --priority=low unattended-upgrades
%{endif}
# Set up SSH hardening
- systemctl restart sshd
%{if enable_tailscale}
# Install and configure Tailscale
- /usr/local/bin/setup-tailscale.sh
%{endif}
# Set permissions on environment file
- chown root:root /etc/openclaw.env
- chmod 600 /etc/openclaw.env
# Enable and start OpenClaw gateway service
# Config is pre-seeded, so gateway can start immediately
- systemctl daemon-reload
- systemctl enable openclaw-gateway.service
- systemctl start openclaw-gateway.service
# Print completion message
- |
echo ""
echo "======================================="
echo " OpenClaw Gateway Bootstrap Complete!"
echo "======================================="
echo ""
echo "Server is ready."
echo ""
%{if enable_tailscale}
echo "Access via Tailscale:"
echo " https://${server_name}.TAILNET.ts.net/"
echo ""
echo "If Tailscale Serve didn't start, run:"
echo " sudo tailscale serve --bg 18789"
echo ""
%{else}
echo "SSH into this server:"
echo " ${ssh_port != 22 ? "ssh -p ${ssh_port}" : "ssh"} ${admin_user}@$(curl -s http://169.254.169.254/metadata/v1/interfaces/public/0/ipv4/address)"
echo ""
%{endif}
echo "Check gateway status:"
echo " systemctl status openclaw-gateway"
echo ""
echo "View logs:"
echo " journalctl -u openclaw-gateway -f"
echo ""