feat: Add paperclip-docker Ansible role with OpenCode vLLM integration

- Create roles/paperclip-docker with full Docker Compose stack deployment
- Template OpenCode v1.2.24 config (provider structure) with Gemma-4-26B model
- Integrate vLLM endpoint (localhost:8000) with vault-injected API key auth
- Wire secrets from ansible vault: vllm_api_key, cloudflare_token, paperclip auth secrets
- Add pre-deployment checks (PostgreSQL, nginx, certbot cert management)
- Implement idempotent stack lifecycle (containers, volumes, networking)
- Deploy to RTX 3090 via muppet-vision.wdw-labs.cloud with nginx SSL termination

Paperclip now serves as CEO reasoning engine with local Gemma inference,
accessible to Hermes platform agents via OpenCode adapter on shared vLLM.
This commit is contained in:
rblundon committed 2026-09-27 19:39:08 -05:00
1 parent f701ad823f
commit 6112b6daea
7 files changed
+477 -398

No files matched your search

@@ -19,7 +19,7 @@ nginx_port: 443
nginx_http_port: 80
# HTTPS/SSL configuration
certbot_email: admin@wdw-labs.cloud
certbot_email: ryan.blundon@protonmail.com
certbot_provider: cloudflare
# Inference endpoint (vLLM or remote OpenAI-compatible)
+58 -31
View File
@@ -3,18 +3,18 @@
apt:
name: python3-docker
state: present
become: yes
become: true
- name: Download latest docker-compose from GitHub
shell: |
curl -L "https://github.com/docker/compose/releases/latest/download/docker-compose-$(uname -s)-$(uname -m)" -o /usr/local/bin/docker-compose
chmod +x /usr/local/bin/docker-compose
become: yes
become: true
- name: Verify docker-compose installation
shell: /usr/local/bin/docker-compose --version
register: compose_version
become: yes
become: true
- name: Show docker-compose version
debug:
@@ -32,44 +32,62 @@
- "{{ paperclip_data_dir }}"
- "{{ paperclip_certs_dir }}"
- "{{ paperclip_base_path }}/pgdata"
become: true
- name: Create OpenCode config directory
file:
path: "{{ paperclip_base_path }}/.config/opencode"
state: directory
mode: '0755'
owner: 1000
group: 1000
become: true
- name: Create OpenCode .local/share directory
file:
path: "{{ paperclip_base_path }}/.local/share/opencode"
state: directory
mode: '0755'
owner: 1000
group: 1000
become: yes
- name: Deploy OpenCode auth.json with vLLM credentials
template:
src: opencode-auth.json.j2
dest: "{{ paperclip_base_path }}/.local/share/opencode/auth.json"
mode: '0600'
owner: 1000
group: 1000
become: true
no_log: true
- name: Fix directory ownership for container user (UID 1000)
shell: |
chown -R 1000:1000 {{ paperclip_data_dir }}
chown -R 1000:1000 {{ paperclip_base_path }}/pgdata
become: yes
- name: Generate BETTER_AUTH_SECRET
shell: openssl rand -hex 24
register: better_auth_secret
changed_when: false
no_log: yes
- name: Generate PAPERCLIP_AGENT_JWT_SECRET
shell: openssl rand -hex 24
register: paperclip_jwt_secret
changed_when: false
no_log: yes
chown -R 1000:1000 {{ paperclip_base_path }}/.config
become: true
- name: Write secrets and configuration to .env
copy:
content: |
# Authentication secrets (auto-generated during deployment)
BETTER_AUTH_SECRET={{ better_auth_secret.stdout }}
PAPERCLIP_AGENT_JWT_SECRET={{ paperclip_jwt_secret.stdout }}
# Authentication secrets (from vault)
BETTER_AUTH_SECRET={{ vault_better_auth_secret }}
PAPERCLIP_AGENT_JWT_SECRET={{ vault_paperclip_agent_jwt_secret }}
# Infrastructure configuration
CLOUDFLARE_API_TOKEN={{ vault_cloudflare_api_token }}
CERTBOT_EMAIL={{ certbot_email }}
PAPERCLIP_DOMAIN={{ paperclip_domain }}
VLLM_ENDPOINT={{ vllm_endpoint }}
VLLM_API_KEY={{ vault_vllm_api_key }}
dest: "{{ paperclip_base_path }}/.env"
mode: '0600'
owner: root
group: root
become: yes
no_log: yes
become: true
no_log: true
- name: Template docker-compose.yml
template:
@@ -78,7 +96,7 @@
mode: '0644'
owner: root
group: root
become: yes
become: true
notify: Restart paperclip stack
- name: Template nginx config
@@ -88,7 +106,7 @@
mode: '0644'
owner: root
group: root
become: yes
become: true
notify: Reload nginx
- name: Template certbot init script
@@ -98,20 +116,30 @@
mode: '0755'
owner: root
group: root
become: yes
become: true
- name: Template OpenCode config
template:
src: opencode.jsonc.j2
dest: "{{ paperclip_base_path }}/.config/opencode/opencode.jsonc"
mode: '0644'
owner: 1000
group: 1000
become: true
notify: Restart paperclip stack
- name: Stop and remove old containers
shell: |
cd {{ paperclip_base_path }}
/usr/local/bin/docker-compose down --remove-orphans 2>/dev/null || true
become: yes
ignore_errors: yes
become: true
ignore_errors: true
- name: Deploy docker compose stack
shell: |
cd {{ paperclip_base_path }}
/usr/local/bin/docker-compose up -d
become: yes
become: true
register: compose_result
- name: Wait for Paperclip to be ready
@@ -122,7 +150,7 @@
until: result.status == 200
retries: 30
delay: 5
ignore_errors: yes
ignore_errors: true
- name: Wait for nginx to be ready
uri:
@@ -133,10 +161,9 @@
until: result.status in [200, 301, 302]
retries: 30
delay: 5
ignore_errors: yes
ignore_errors: true
- name: Verify Paperclip is accessible via https
debug:
msg: "Paperclip is accessible at https://{{ paperclip_domain }}"
when: result.status is defined and result.status in [200, 301, 302]
when: result.status is defined and result.status in [200, 301, 302]
@@ -38,6 +38,8 @@ services:
ANTHROPIC_API_KEY: "${ANTHROPIC_API_KEY:-}"
volumes:
- {{ paperclip_data_dir }}:/paperclip
- {{ paperclip_base_path }}/.config/opencode:/paperclip/.config/opencode
- {{ paperclip_base_path }}/.local/share/opencode:/paperclip/.local/share/opencode
depends_on:
db:
condition: service_healthy
@@ -0,0 +1,6 @@
{
"vllm": {
"type": "api",
"key": "{{ vault_vllm_api_key }}"
}
}
@@ -0,0 +1,22 @@
{
"$schema": "https://opencode.ai/config.json",
"provider": {
"vllm": {
"npm": "@ai-sdk/openai-compatible",
"name": "vLLM (Local)",
"models": {
"gemma-4-26b": {
"id": "Gemma-4-26B-A4B-it-AWQ",
"name": "Gemma 4 26B (Local AWQ)"
}
},
"options": {
"baseURL": "{{ vllm_endpoint }}/v1",
"headers": {
"Authorization": "Bearer {{ vault_vllm_api_key }}"
}
}
}
},
"model": "vllm/gemma-4-26b"
}