chore: sync accumulated infra changes and docs
Removals: openwebui and netclaw compose + Traefik routes (both decommissioned). Updates: litellm, n8n, vaultwarden, ai-agents, media, traefik routes, CLAUDE.md (nodes/ports/known-issues), agent definitions. Additions: Rongorongo tree, LinkedStorm plan, rename-bart spec, vllm brief, tls-options and security-headers Traefik config. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
This commit is contained in:
@@ -114,7 +114,7 @@ services:
|
||||
- /mnt/docker-data/configs/nzbhydra:/config
|
||||
ports:
|
||||
- "5076:5076"
|
||||
mem_limit: 512M
|
||||
mem_limit: 768M
|
||||
healthcheck:
|
||||
test: ["CMD-SHELL", "curl -f http://localhost:5076/ || exit 1"]
|
||||
interval: 30s
|
||||
|
||||
@@ -0,0 +1,17 @@
|
||||
# Overlay on the friday-voice app image that adds the docker CLI + a wrapper so
|
||||
# the container can reach the hermes agent via `docker exec hermes hermes ...`.
|
||||
# Runs as root to access the mounted /var/run/docker.sock.
|
||||
FROM friday-voice:latest
|
||||
|
||||
USER root
|
||||
|
||||
# Static docker *client* only (~small), for `docker exec` into the hermes container.
|
||||
RUN curl -fsSL https://download.docker.com/linux/static/stable/x86_64/docker-27.5.1.tgz \
|
||||
| tar -xz --strip-components=1 -C /usr/local/bin docker/docker \
|
||||
&& chmod +x /usr/local/bin/docker \
|
||||
&& docker --version
|
||||
|
||||
COPY hermes-wrap /usr/local/bin/hermes-wrap
|
||||
RUN chmod +x /usr/local/bin/hermes-wrap
|
||||
|
||||
# Keep the base image's CMD (uvicorn friday_voice.app:app :8320).
|
||||
@@ -0,0 +1,49 @@
|
||||
# FRIDAY Voice on .150 (Docker Desktop) — replaces VoiceCoach.
|
||||
# STT/TTS via local GPU speaches (:8000). Reasoning via the hermes container
|
||||
# (invoked through the docker-exec wrapper). Runs as root for socket access.
|
||||
services:
|
||||
friday-voice:
|
||||
build:
|
||||
context: .
|
||||
dockerfile: Dockerfile.hermes
|
||||
image: friday-voice-hermes:latest
|
||||
container_name: friday-voice
|
||||
restart: unless-stopped
|
||||
user: "0:0"
|
||||
ports:
|
||||
- "8320:8320"
|
||||
volumes:
|
||||
- friday-voice-data:/data
|
||||
- /var/run/docker.sock:/var/run/docker.sock
|
||||
environment:
|
||||
- DATA_DIR=/data
|
||||
- SPEACHES_URL=http://host.docker.internal:8000
|
||||
- HERMES_COMMAND=/usr/local/bin/hermes-wrap
|
||||
- HERMES_SOURCE=friday-voice
|
||||
- WHISPER_MODEL=deepdml/faster-whisper-large-v3-turbo-ct2
|
||||
- TTS_MODEL=speaches-ai/Kokoro-82M-v1.0-ONNX
|
||||
- TTS_VOICE=af_nova
|
||||
- SPEAKER_CONFIRMED_THRESHOLD=0.85
|
||||
- SPEAKER_PROBABLE_THRESHOLD=0.70
|
||||
extra_hosts:
|
||||
- "host.docker.internal:host-gateway"
|
||||
labels:
|
||||
- "com.centurylinklabs.watchtower.enable=false"
|
||||
healthcheck:
|
||||
test: ["CMD", "curl", "-fsS", "http://127.0.0.1:8320/health"]
|
||||
interval: 30s
|
||||
timeout: 10s
|
||||
retries: 3
|
||||
start_period: 20s
|
||||
logging:
|
||||
driver: "json-file"
|
||||
options:
|
||||
max-size: "20m"
|
||||
max-file: "3"
|
||||
|
||||
volumes:
|
||||
friday-voice-data:
|
||||
|
||||
networks:
|
||||
default:
|
||||
name: friday-voice
|
||||
@@ -0,0 +1,5 @@
|
||||
#!/bin/sh
|
||||
# friday-voice invokes: hermes-wrap chat -q "<text>" --source friday-voice
|
||||
# We forward into the hermes container and add -Q (quiet) so only the final
|
||||
# response text is returned (no banner/spinner/box art) for clean TTS.
|
||||
exec docker exec hermes hermes "$@" -Q
|
||||
@@ -36,6 +36,7 @@ services:
|
||||
- HOME=/home/glyptic
|
||||
- USER=glyptic
|
||||
- ANTHROPIC_API_KEY=${ANTHROPIC_API_KEY}
|
||||
- GEMINI_API_KEY=${GEMINI_API_KEY}
|
||||
- WIKIJS_API_KEY=${WIKIJS_API_KEY}
|
||||
- OPENCLAW_STATE_DIR=/home/glyptic/.spirit
|
||||
- OPENCLAW_CONFIG_PATH=/home/glyptic/.spirit/openclaw.json
|
||||
@@ -43,6 +44,8 @@ services:
|
||||
- /mnt/infrastructure/spirit:/home/glyptic/.spirit
|
||||
- /var/run/docker.sock:/var/run/docker.sock
|
||||
- /mnt/infrastructure/spirit/ssh:/root/.ssh:ro
|
||||
- /mnt/docker-data/configs/prometheus:/prometheus-config
|
||||
- /mnt/docker-data/configs/alertmanager:/alertmanager-config
|
||||
command: ["sh", "-c", "mkdir -p /home/glyptic && node --max-old-space-size=1500 /usr/local/lib/node_modules/openclaw/dist/index.js gateway --allow-unconfigured"]
|
||||
mem_limit: 3G
|
||||
memswap_limit: 3G
|
||||
@@ -52,74 +55,3 @@ services:
|
||||
max-size: "50m"
|
||||
max-file: "3"
|
||||
|
||||
bob:
|
||||
image: margaret-openclaw:latest
|
||||
container_name: bob
|
||||
restart: unless-stopped
|
||||
network_mode: host
|
||||
user: "0:0"
|
||||
environment:
|
||||
- NODE_ENV=production
|
||||
- HOME=/home/glyptic
|
||||
- USER=glyptic
|
||||
- ANTHROPIC_API_KEY=${ANTHROPIC_API_KEY}
|
||||
- OPENCLAW_STATE_DIR=/home/glyptic/.bob
|
||||
- OPENCLAW_CONFIG_PATH=/home/glyptic/.bob/openclaw.json
|
||||
volumes:
|
||||
- /mnt/infrastructure/bob:/home/glyptic/.bob
|
||||
command: ["sh", "-c", "mkdir -p /home/glyptic && node --max-old-space-size=1500 /usr/local/lib/node_modules/openclaw/dist/index.js gateway --allow-unconfigured"]
|
||||
mem_limit: 2G
|
||||
memswap_limit: 2G
|
||||
logging:
|
||||
driver: "json-file"
|
||||
options:
|
||||
max-size: "50m"
|
||||
max-file: "3"
|
||||
|
||||
clippy:
|
||||
image: margaret-openclaw:latest
|
||||
container_name: clippy
|
||||
restart: unless-stopped
|
||||
network_mode: host
|
||||
user: "0:0"
|
||||
environment:
|
||||
- NODE_ENV=production
|
||||
- HOME=/home/glyptic
|
||||
- USER=glyptic
|
||||
- ANTHROPIC_API_KEY=${ANTHROPIC_API_KEY}
|
||||
- OPENCLAW_STATE_DIR=/home/glyptic/.clippy
|
||||
- OPENCLAW_CONFIG_PATH=/home/glyptic/.clippy/openclaw.json
|
||||
volumes:
|
||||
- /mnt/infrastructure/clippy:/home/glyptic/.clippy
|
||||
command: ["sh", "-c", "mkdir -p /home/glyptic && node --max-old-space-size=1500 /usr/local/lib/node_modules/openclaw/dist/index.js gateway --allow-unconfigured"]
|
||||
mem_limit: 2G
|
||||
memswap_limit: 2G
|
||||
logging:
|
||||
driver: "json-file"
|
||||
options:
|
||||
max-size: "50m"
|
||||
max-file: "3"
|
||||
|
||||
travis:
|
||||
image: travis-nemoclaw:latest
|
||||
container_name: travis
|
||||
restart: unless-stopped
|
||||
network_mode: host
|
||||
user: "0:0"
|
||||
environment:
|
||||
- NODE_ENV=production
|
||||
- HOME=/home/glyptic
|
||||
- USER=glyptic
|
||||
- ANTHROPIC_API_KEY=${ANTHROPIC_API_KEY}
|
||||
- OPENCLAW_STATE_DIR=/home/glyptic/.travis
|
||||
- OPENCLAW_CONFIG_PATH=/home/glyptic/.travis/openclaw.json
|
||||
volumes:
|
||||
- /mnt/infrastructure/travis:/home/glyptic/.travis
|
||||
command: ["sh", "-c", "mkdir -p /home/glyptic && openclaw plugins install /opt/nemoclaw 2>/dev/null; node --max-old-space-size=1500 /usr/local/lib/node_modules/openclaw/dist/index.js gateway --allow-unconfigured"]
|
||||
mem_limit: 2G
|
||||
memswap_limit: 2G
|
||||
logging:
|
||||
driver: "json-file"
|
||||
options:
|
||||
max-size: "50m"
|
||||
max-file: "3"
|
||||
|
||||
@@ -17,7 +17,7 @@ services:
|
||||
litellm-db:
|
||||
condition: service_healthy
|
||||
healthcheck:
|
||||
test: ["CMD-SHELL", "curl -f http://localhost:4000/health || exit 1"]
|
||||
test: ["CMD-SHELL", "python3 -c \"import urllib.request,sys; sys.exit(0 if urllib.request.urlopen('http://localhost:4000/health/liveliness',timeout=5).status==200 else 1)\""]
|
||||
interval: 30s
|
||||
timeout: 10s
|
||||
retries: 3
|
||||
|
||||
@@ -1,29 +0,0 @@
|
||||
services:
|
||||
open-webui:
|
||||
image: ghcr.io/open-webui/open-webui:main
|
||||
container_name: open-webui
|
||||
restart: unless-stopped
|
||||
ports:
|
||||
- "3010:8080"
|
||||
env_file:
|
||||
- .env
|
||||
environment:
|
||||
- TZ=America/Chicago
|
||||
- OLLAMA_BASE_URL=http://192.168.86.196:11434
|
||||
volumes:
|
||||
- /mnt/docker-data/configs/openwebui:/app/backend/data
|
||||
mem_limit: 1G
|
||||
memswap_limit: 1G
|
||||
labels:
|
||||
- "com.centurylinklabs.watchtower.enable=false"
|
||||
healthcheck:
|
||||
test: ["CMD-SHELL", "curl -sf http://localhost:8080/health || exit 1"]
|
||||
interval: 30s
|
||||
timeout: 10s
|
||||
retries: 3
|
||||
start_period: 60s
|
||||
logging:
|
||||
driver: "json-file"
|
||||
options:
|
||||
max-size: "50m"
|
||||
max-file: "3"
|
||||
@@ -6,24 +6,13 @@ services:
|
||||
ports:
|
||||
- "5678:5678"
|
||||
environment:
|
||||
- DB_TYPE=postgresdb
|
||||
- DB_POSTGRESDB_HOST=n8n-db
|
||||
- DB_POSTGRESDB_PORT=5432
|
||||
- DB_POSTGRESDB_DATABASE=n8n
|
||||
- DB_POSTGRESDB_USER=n8n
|
||||
- DB_POSTGRESDB_PASSWORD=${N8N_DB_PASSWORD}
|
||||
- N8N_PORT=5678
|
||||
- GENERIC_TIMEZONE=America/Chicago
|
||||
- N8N_ENCRYPTION_KEY=${N8N_ENCRYPTION_KEY}
|
||||
- N8N_SECURE_COOKIE=false
|
||||
- NODE_OPTIONS=--max-old-space-size=1500
|
||||
volumes:
|
||||
- /mnt/docker-data/configs/n8n:/home/node/.n8n
|
||||
depends_on:
|
||||
n8n-db:
|
||||
condition: service_healthy
|
||||
networks:
|
||||
- n8n-internal
|
||||
mem_limit: 512M
|
||||
memswap_limit: 512M
|
||||
- n8n_data:/home/node/.n8n
|
||||
mem_limit: 2g
|
||||
memswap_limit: 2g
|
||||
healthcheck:
|
||||
test: ["CMD-SHELL", "wget -q --spider http://localhost:5678/healthz || exit 1"]
|
||||
interval: 30s
|
||||
@@ -36,35 +25,6 @@ services:
|
||||
max-size: "50m"
|
||||
max-file: "3"
|
||||
|
||||
n8n-db:
|
||||
image: postgres:15-alpine
|
||||
container_name: n8n-db
|
||||
restart: unless-stopped
|
||||
user: "1024:100"
|
||||
environment:
|
||||
- POSTGRES_DB=n8n
|
||||
- POSTGRES_USER=n8n
|
||||
- POSTGRES_PASSWORD=${N8N_DB_PASSWORD}
|
||||
volumes:
|
||||
- /mnt/docker-data/databases/n8n-db:/var/lib/postgresql/data
|
||||
networks:
|
||||
- n8n-internal
|
||||
labels:
|
||||
- "com.centurylinklabs.watchtower.enable=false"
|
||||
mem_limit: 256M
|
||||
memswap_limit: 256M
|
||||
healthcheck:
|
||||
test: ["CMD-SHELL", "pg_isready -U n8n -d n8n"]
|
||||
interval: 30s
|
||||
timeout: 10s
|
||||
retries: 3
|
||||
start_period: 30s
|
||||
logging:
|
||||
driver: "json-file"
|
||||
options:
|
||||
max-size: "50m"
|
||||
max-file: "3"
|
||||
|
||||
networks:
|
||||
n8n-internal:
|
||||
driver: bridge
|
||||
volumes:
|
||||
n8n_data:
|
||||
external: true
|
||||
|
||||
@@ -1,2 +0,0 @@
|
||||
ANTHROPIC_API_KEY=sk-ant-...
|
||||
MATRIX_ACCESS_TOKEN=syt_...
|
||||
@@ -1,38 +0,0 @@
|
||||
FROM node:20-bookworm
|
||||
|
||||
# Install system dependencies
|
||||
RUN apt-get update && apt-get install -y \
|
||||
python3 python3-pip python3-venv python3-full \
|
||||
git curl jq openssh-client iputils-ping net-tools \
|
||||
&& rm -rf /var/lib/apt/lists/*
|
||||
|
||||
# Install uv (Python package manager used by some MCP servers)
|
||||
RUN curl -LsSf https://astral.sh/uv/install.sh | sh
|
||||
ENV PATH="/root/.local/bin:$PATH"
|
||||
|
||||
# Install OpenClaw globally
|
||||
RUN npm install -g openclaw@latest
|
||||
|
||||
# Clone NetClaw
|
||||
WORKDIR /opt/netclaw
|
||||
RUN git clone https://github.com/automateyournetwork/netclaw.git .
|
||||
|
||||
# Create openclaw home directory
|
||||
RUN mkdir -p /root/.openclaw/workspace
|
||||
|
||||
# Copy NetClaw workspace config into openclaw home
|
||||
RUN cp -r workspace/skills /root/.openclaw/workspace/ 2>/dev/null || true
|
||||
RUN cp config/openclaw.json /root/.openclaw/openclaw.json 2>/dev/null || true
|
||||
|
||||
# Install Python dependencies for core MCP servers
|
||||
RUN python3 -m venv /opt/venv
|
||||
ENV PATH="/opt/venv/bin:$PATH"
|
||||
RUN pip install --no-cache-dir pyats genie netmiko paramiko requests pyyaml jinja2 2>/dev/null || true
|
||||
|
||||
# Create entrypoint script
|
||||
COPY entrypoint.sh /opt/entrypoint.sh
|
||||
RUN chmod +x /opt/entrypoint.sh
|
||||
|
||||
EXPOSE 1179
|
||||
|
||||
ENTRYPOINT ["/opt/entrypoint.sh"]
|
||||
@@ -1,20 +0,0 @@
|
||||
services:
|
||||
netclaw:
|
||||
build:
|
||||
context: .
|
||||
dockerfile: Dockerfile
|
||||
container_name: netclaw-aaron
|
||||
restart: unless-stopped
|
||||
environment:
|
||||
- ANTHROPIC_API_KEY=${ANTHROPIC_API_KEY}
|
||||
- MATRIX_ACCESS_TOKEN=${MATRIX_ACCESS_TOKEN}
|
||||
- MATRIX_HOMESERVER=http://192.168.86.192:8008
|
||||
volumes:
|
||||
- /mnt/docker-data/configs/netclaw:/root/.openclaw/data
|
||||
mem_limit: 2G
|
||||
memswap_limit: 2G
|
||||
logging:
|
||||
driver: "json-file"
|
||||
options:
|
||||
max-size: "50m"
|
||||
max-file: "3"
|
||||
@@ -1,72 +0,0 @@
|
||||
#!/bin/bash
|
||||
set -e
|
||||
|
||||
# Configure OpenClaw environment
|
||||
mkdir -p /root/.openclaw
|
||||
|
||||
# Write .env with API key
|
||||
cat > /root/.openclaw/.env << EOF
|
||||
ANTHROPIC_API_KEY=${ANTHROPIC_API_KEY}
|
||||
EOF
|
||||
|
||||
# Write openclaw config for gateway mode
|
||||
cat > /root/.openclaw/openclaw.json << 'OCEOF'
|
||||
{
|
||||
"mode": "gateway",
|
||||
"provider": "anthropic",
|
||||
"model": "claude-sonnet-4-6",
|
||||
"fallbackModel": "claude-haiku-4-5-20251001",
|
||||
"name": "Aaron",
|
||||
"identity": "Aaron - NetClaw AI Network Engineering Agent"
|
||||
}
|
||||
OCEOF
|
||||
|
||||
# Copy workspace skills if they exist
|
||||
if [ -d /opt/netclaw/workspace/skills ]; then
|
||||
cp -r /opt/netclaw/workspace/skills /root/.openclaw/workspace/ 2>/dev/null || true
|
||||
fi
|
||||
|
||||
# Copy personality/identity docs
|
||||
for doc in SOUL.md AGENTS.md IDENTITY.md USER.md TOOLS.md; do
|
||||
if [ -f /opt/netclaw/$doc ]; then
|
||||
cp /opt/netclaw/$doc /root/.openclaw/ 2>/dev/null || true
|
||||
fi
|
||||
done
|
||||
|
||||
# Send Matrix DM to Jeremy to announce availability
|
||||
if [ -n "$MATRIX_ACCESS_TOKEN" ] && [ -n "$MATRIX_HOMESERVER" ]; then
|
||||
echo "Sending Matrix DM to Jeremy..."
|
||||
|
||||
# Create a direct message room with Jeremy
|
||||
ROOM_RESPONSE=$(curl -sf -X POST "${MATRIX_HOMESERVER}/_matrix/client/r0/createRoom" \
|
||||
-H "Content-Type: application/json" \
|
||||
-H "Authorization: Bearer ${MATRIX_ACCESS_TOKEN}" \
|
||||
-d "{
|
||||
\"is_direct\": true,
|
||||
\"invite\": [\"@jeremy:hobbs.farm\"],
|
||||
\"preset\": \"trusted_private_chat\"
|
||||
}" 2>/dev/null || echo "")
|
||||
|
||||
ROOM_ID=$(echo "$ROOM_RESPONSE" | python3 -c "import sys,json; print(json.load(sys.stdin).get('room_id',''))" 2>/dev/null || echo "")
|
||||
|
||||
if [ -n "$ROOM_ID" ]; then
|
||||
# Send the message
|
||||
curl -sf -X PUT "${MATRIX_HOMESERVER}/_matrix/client/r0/rooms/${ROOM_ID}/send/m.room.message/$(date +%s%N)" \
|
||||
-H "Content-Type: application/json" \
|
||||
-H "Authorization: Bearer ${MATRIX_ACCESS_TOKEN}" \
|
||||
-d "{
|
||||
\"msgtype\": \"m.text\",
|
||||
\"body\": \"Hey Jeremy - Aaron here. I'm online and ready to help with network engineering tasks. I'm running NetClaw with CCIE-level networking skills. Ask me about device health checks, routing analysis, security audits, or anything network-related.\"
|
||||
}" 2>/dev/null || echo "Failed to send DM"
|
||||
echo "DM sent to @jeremy:hobbs.farm in room $ROOM_ID"
|
||||
else
|
||||
echo "Warning: Could not create DM room with Jeremy. Response: $ROOM_RESPONSE"
|
||||
fi
|
||||
fi
|
||||
|
||||
# Start OpenClaw gateway
|
||||
echo "Starting NetClaw (Aaron) gateway..."
|
||||
exec openclaw gateway 2>&1 || {
|
||||
echo "OpenClaw gateway failed to start, keeping container alive for debugging..."
|
||||
tail -f /dev/null
|
||||
}
|
||||
@@ -5,6 +5,8 @@ http:
|
||||
service: yoda
|
||||
entryPoints:
|
||||
- websecure
|
||||
middlewares:
|
||||
- security-headers-allow-frames
|
||||
tls:
|
||||
certResolver: letsencrypt
|
||||
|
||||
@@ -13,6 +15,8 @@ http:
|
||||
service: mess
|
||||
entryPoints:
|
||||
- websecure
|
||||
middlewares:
|
||||
- security-headers
|
||||
tls:
|
||||
certResolver: letsencrypt
|
||||
|
||||
@@ -21,6 +25,8 @@ http:
|
||||
service: mess
|
||||
entryPoints:
|
||||
- websecure
|
||||
middlewares:
|
||||
- security-headers
|
||||
tls:
|
||||
certResolver: letsencrypt
|
||||
|
||||
@@ -29,6 +35,8 @@ http:
|
||||
service: wellknown
|
||||
entryPoints:
|
||||
- websecure
|
||||
middlewares:
|
||||
- security-headers
|
||||
tls:
|
||||
certResolver: letsencrypt
|
||||
|
||||
@@ -37,6 +45,8 @@ http:
|
||||
service: solo
|
||||
entryPoints:
|
||||
- websecure
|
||||
middlewares:
|
||||
- security-headers-allow-frames
|
||||
tls:
|
||||
certResolver: letsencrypt
|
||||
|
||||
@@ -45,6 +55,8 @@ http:
|
||||
service: vault
|
||||
entryPoints:
|
||||
- websecure
|
||||
middlewares:
|
||||
- security-headers
|
||||
tls:
|
||||
certResolver: letsencrypt
|
||||
|
||||
@@ -53,9 +65,41 @@ http:
|
||||
service: git
|
||||
entryPoints:
|
||||
- websecure
|
||||
middlewares:
|
||||
- security-headers
|
||||
tls:
|
||||
certResolver: letsencrypt
|
||||
|
||||
middlewares:
|
||||
security-headers:
|
||||
headers:
|
||||
stsSeconds: 31536000
|
||||
stsIncludeSubdomains: true
|
||||
stsPreload: true
|
||||
contentTypeNosniff: true
|
||||
frameDeny: true
|
||||
referrerPolicy: "strict-origin-when-cross-origin"
|
||||
permissionsPolicy: "camera=(), microphone=(), geolocation=(), payment=()"
|
||||
browserXssFilter: true
|
||||
customResponseHeaders:
|
||||
X-Powered-By: ""
|
||||
Server: ""
|
||||
|
||||
security-headers-allow-frames:
|
||||
headers:
|
||||
stsSeconds: 31536000
|
||||
stsIncludeSubdomains: true
|
||||
stsPreload: true
|
||||
contentTypeNosniff: true
|
||||
frameDeny: false
|
||||
customFrameOptionsValue: "SAMEORIGIN"
|
||||
referrerPolicy: "strict-origin-when-cross-origin"
|
||||
permissionsPolicy: "camera=(), microphone=(), geolocation=(), payment=()"
|
||||
browserXssFilter: true
|
||||
customResponseHeaders:
|
||||
X-Powered-By: ""
|
||||
Server: ""
|
||||
|
||||
services:
|
||||
yoda:
|
||||
loadBalancer:
|
||||
|
||||
@@ -6,6 +6,7 @@ services:
|
||||
environment:
|
||||
- DOMAIN=https://vault.hobbs.farm
|
||||
- SIGNUPS_ALLOWED=false
|
||||
- ADMIN_TOKEN=${ADMIN_TOKEN}
|
||||
volumes:
|
||||
- /mnt/docker-data/configs/vaultwarden:/data
|
||||
ports:
|
||||
|
||||
Reference in New Issue
Block a user