Merge pull request #5 from oswaldtheotter/cursor/opencode-ai-flatcar-47fc

Add OpenCode to goose ai Flatcar for n8n
This commit is contained in:
Nick Trochalakis authored and GitHub committed 2026-09-23 19:10:10 -07:00
commit bbcd097ccf
3 files changed
+83

No files matched your search

+81
View File
@@ -202,6 +202,47 @@ systemd:
RestartSec=5s
[Install]
WantedBy=multi-user.target
# OpenCode headless server for n8n (and anything else on the LAN).
#
# Prerequisites:
# - OPENCODE_SERVER_PASSWORD in Infisical (see secrets.tmpl)
# - model keys in /etc/opencode/opencode.json matching LiteLLM
# model_name values (Admin UI or GET /v1/models). Models live in
# the LiteLLM database, so this file cannot discover them.
#
# Listens on :4096 with HTTP Basic Auth (user "opencode"). n8n on
# oswald-runner reaches it at http://192.168.7.61:4096 -- install the
# n8n-nodes-opencode-ai community package, or use HTTP Request nodes
# against the OpenAPI at /doc. LLM calls go through LiteLLM on :4000
# using the same host-IP pattern as Open WebUI.
- name: opencode.service
enabled: true
contents: |
[Unit]
Description=OpenCode server
After=docker.service litellm.service
Requires=docker.service
[Service]
TimeoutStartSec=0
ExecStartPre=/usr/bin/docker pull ghcr.io/anomalyco/opencode:1.18.32
ExecStartPre=-/usr/bin/docker rm --force opencode
# /var/lib/opencode is the project workspace the agent edits. It
# survives container restarts; a VM taint wipes it (scratch space).
ExecStart=/usr/bin/docker run --name opencode \
-e OPENCODE_SERVER_USERNAME=opencode \
-e OPENCODE_SERVER_PASSWORD=${opencode_server_password} \
-e OPENCODE_CONFIG=/etc/opencode/opencode.json \
-v /etc/opencode/opencode.json:/etc/opencode/opencode.json:ro \
-v /var/lib/opencode:/workspace \
-w /workspace \
-p 4096:4096 \
ghcr.io/anomalyco/opencode:1.18.32 \
serve --hostname 0.0.0.0 --port 4096
ExecStop=/usr/bin/docker stop opencode
Restart=always
RestartSec=5s
[Install]
WantedBy=multi-user.target
# Rebuilds the vector store after a taint. Runs on every boot, but only
# acts when Qdrant holds no Open WebUI collections -- that is, when the
# local volume went with the VM.
@@ -248,6 +289,12 @@ storage:
# root-owned 0700 directory is what it expects.
- path: /var/lib/qdrant
mode: 0700
# OpenCode project workspace. Scratch space: survives container
# restarts, not a VM taint.
- path: /var/lib/opencode
mode: 0755
- path: /etc/opencode
mode: 0755
files:
# LiteLLM proxy settings. Models stay in the database
# (STORE_MODEL_IN_DB), so this file carries general_settings only --
@@ -317,3 +364,37 @@ storage:
use_x_forwarded_for: true
mcp_trusted_proxy_ranges:
- 192.168.0.0/24
# OpenCode provider config. LiteLLM is an OpenAI-compatible proxy, so
# we use @ai-sdk/openai-compatible rather than a first-party provider.
#
# Model keys under "models" must match LiteLLM model_name values exactly
# (they are stored in the LiteLLM DB, not in litellm/config.yaml). Edit
# this list to match what /v1/models returns, then taint the VM -- or
# PATCH http://192.168.7.61:4096/config at runtime. The default model
# below is the first key; change "model" when you change the set.
#
# apiKey is templated from Infisical (LITELLM_MASTER_KEY). Ignition
# snippets are plaintext on the node -- same caveat as the other units.
- path: /etc/opencode/opencode.json
mode: 0600
contents:
inline: |
{
"$schema": "https://opencode.ai/config.json",
"model": "litellm/claude-sonnet-4",
"provider": {
"litellm": {
"npm": "@ai-sdk/openai-compatible",
"name": "LiteLLM",
"options": {
"baseURL": "http://192.168.7.61:4000/v1",
"apiKey": "${litellm_master_key}"
},
"models": {
"claude-sonnet-4": {
"name": "Claude Sonnet 4"
}
}
}
}
}
+1
View File
@@ -14,6 +14,7 @@
{{- if eq $secret.Key "LITELLM_DATABASE_URL" }}"litellm_database_url": "{{$secret.Value}}",{{ end }}
{{- if eq $secret.Key "LITELLM_MASTER_KEY" }}"litellm_master_key": "{{$secret.Value}}",{{ end }}
{{- if eq $secret.Key "LITELLM_SALT_KEY" }}"litellm_salt_key": "{{$secret.Value}}",{{ end }}
{{- if eq $secret.Key "OPENCODE_SERVER_PASSWORD" }}"opencode_server_password": "{{$secret.Value}}",{{ end }}
{{- if eq $secret.Key "HEADSCALE_AUTHKEY" }}"headscale_authkey": "{{$secret.Value}}",{{ end }}
{{- if eq $secret.Key "OPENWEBUI_DATABASE_URL" }}"openwebui_database_url": "{{$secret.Value}}",{{ end }}
{{- if eq $secret.Key "OPENWEBUI_SECRET_KEY" }}"openwebui_secret_key": "{{$secret.Value}}",{{ end }}
+1
View File
@@ -222,6 +222,7 @@ nodes = {
cores = 2
disk_size = 32
qemu_guest_agent = false
# OPENCODE_SERVER_PASSWORD in Infisical; see butane/ai.yaml.tftpl.
butane_file = "butane/ai.yaml.tftpl"
}
# Headscale subnet router / exit node. Registers as an ephemeral node,