feat(honcho): add role + day1 playbook + traefik route for lincoln

Deploys Honcho (plastic-labs/honcho) as a rootful Podman + Quadlet
service on the lincoln VM (10.1.71.132). Three containers on a
user-defined network:

  - honcho-postgres  pgvector/pgvector:pg16
  - honcho-api       FastAPI on :8000
  - honcho-deriver   background worker for theory-of-mind derivations

LLM provider: Anthropic Claude (claude-sonnet-4-5). Switching providers
is two env-var changes — see README.

Traefik route hall-of-presidents.local.mk-labs.cloud -> lincoln:8000
added under boilerplates/traefik/dynamic/. JARVIS itself talks to
Honcho directly at lincoln:8000 (east-west); the Traefik alias exists
only for browser access to the Swagger /docs UI.

Requires three new vault entries before first run:
  - vault_honcho_database_password
  - vault_honcho_jwt_secret
  - vault_honcho_anthropic_api_key
This commit is contained in:
JARVIS
2026-05-30 22:41:33 -05:00
parent 09ae954085
commit 4d7766d1b1
17 changed files with 667 additions and 0 deletions

View File

@@ -0,0 +1,34 @@
---
# ============================================================================
# Honcho API container (Quadlet)
# ----------------------------------------------------------------------------
# Runs `fastapi run src/main.py` via the image's default CMD. The
# entrypoint.sh in the image runs the DB migration first; safe to do on
# every restart (idempotent).
# ============================================================================
- name: Deploy Honcho API Quadlet
ansible.builtin.template:
src: honcho-api.container.j2
dest: "{{ honcho_quadlet_dir }}/{{ honcho_container_name }}.container"
owner: root
group: root
mode: "0644"
register: honcho_api_quadlet
- name: Reload systemd to pick up Quadlet changes
ansible.builtin.systemd:
daemon_reload: true
when: honcho_api_quadlet.changed
- name: Ensure Honcho API container is started and enabled
ansible.builtin.systemd:
name: "{{ honcho_container_name }}.service"
state: started
enabled: true
- name: Restart Honcho API on Quadlet change
ansible.builtin.systemd:
name: "{{ honcho_container_name }}.service"
state: restarted
when: honcho_api_quadlet.changed

View File

@@ -0,0 +1,34 @@
---
# ============================================================================
# Honcho deriver worker container (Quadlet)
# ----------------------------------------------------------------------------
# Same image as the API container, but runs the deriver script instead of
# the FastAPI server. Pulls jobs off the in-database queue and calls the
# configured LLM provider for theory-of-mind derivations.
# ============================================================================
- name: Deploy Honcho deriver Quadlet
ansible.builtin.template:
src: honcho-deriver.container.j2
dest: "{{ honcho_quadlet_dir }}/{{ honcho_deriver_container_name }}.container"
owner: root
group: root
mode: "0644"
register: honcho_deriver_quadlet
- name: Reload systemd to pick up Quadlet changes
ansible.builtin.systemd:
daemon_reload: true
when: honcho_deriver_quadlet.changed
- name: Ensure Honcho deriver container is started and enabled
ansible.builtin.systemd:
name: "{{ honcho_deriver_container_name }}.service"
state: started
enabled: true
- name: Restart Honcho deriver on Quadlet change
ansible.builtin.systemd:
name: "{{ honcho_deriver_container_name }}.service"
state: restarted
when: honcho_deriver_quadlet.changed

View File

@@ -0,0 +1,42 @@
---
# ============================================================================
# honcho / main entrypoint
# ----------------------------------------------------------------------------
# Order matters:
# 1. Podman + Quadlet support installed and ready
# 2. Network created (containers reference it by name)
# 3. Volumes created (postgres data)
# 4. Postgres started (Honcho API + deriver depend on it being ready)
# 5. Honcho API started
# 6. Honcho deriver worker started
# 7. Verify reachable on listen port
# ============================================================================
- name: Install Podman and dependencies
ansible.builtin.import_tasks: podman.yml
tags: [honcho, podman]
- name: Ensure podman network exists
ansible.builtin.import_tasks: network.yml
tags: [honcho, network]
- name: Ensure podman volumes exist
ansible.builtin.import_tasks: volumes.yml
tags: [honcho, volumes]
- name: Deploy PostgreSQL (pgvector) container
ansible.builtin.import_tasks: postgres.yml
tags: [honcho, postgres]
- name: Deploy Honcho API container
ansible.builtin.import_tasks: api.yml
tags: [honcho, api]
- name: Deploy Honcho deriver worker
ansible.builtin.import_tasks: deriver.yml
when: honcho_deriver_enabled | bool
tags: [honcho, deriver]
- name: Verify Honcho is reachable
ansible.builtin.import_tasks: verify.yml
tags: [honcho, verify]

View File

@@ -0,0 +1,17 @@
---
# ============================================================================
# Podman network — single user-defined network shared by api/deriver/postgres
# ============================================================================
- name: Check if honcho network exists
ansible.builtin.command:
cmd: "podman network exists {{ honcho_network_name }}"
register: honcho_network_check
failed_when: false
changed_when: false
- name: Create honcho podman network
ansible.builtin.command:
cmd: "podman network create {{ honcho_network_name }}"
when: honcho_network_check.rc != 0
changed_when: true

View File

@@ -0,0 +1,24 @@
---
# ============================================================================
# Podman + Quadlet prerequisites
# ----------------------------------------------------------------------------
# Mirrors the pattern from the semaphore role. Ubuntu 24.04's podman is new
# enough that Quadlet ships out of the box (>= 4.4).
# ============================================================================
- name: Ensure Podman is installed
ansible.builtin.package:
name:
- podman
- podman-compose
state: present
become: true
- name: Ensure Quadlet drop-in directory exists
ansible.builtin.file:
path: "{{ honcho_quadlet_dir }}"
state: directory
owner: root
group: root
mode: "0755"
become: true

View File

@@ -0,0 +1,48 @@
---
# ============================================================================
# pgvector PostgreSQL container (Quadlet)
# ----------------------------------------------------------------------------
# Honcho stores embeddings in pgvector, so we use the pgvector-enabled
# image rather than stock postgres. Same env-var surface as the upstream
# image; the pgvector extension is created by Honcho's migration script
# on first start (scripts/provision_db.py).
# ============================================================================
- name: Deploy Honcho PostgreSQL Quadlet
ansible.builtin.template:
src: honcho-postgres.container.j2
dest: "{{ honcho_quadlet_dir }}/{{ honcho_postgres_container_name }}.container"
owner: root
group: root
mode: "0644"
register: postgres_quadlet
- name: Reload systemd to pick up Quadlet changes
ansible.builtin.systemd:
daemon_reload: true
when: postgres_quadlet.changed
- name: Ensure Honcho PostgreSQL container is started and enabled
ansible.builtin.systemd:
name: "{{ honcho_postgres_container_name }}.service"
state: started
enabled: true
- name: Wait for PostgreSQL to accept connections
ansible.builtin.command:
cmd: >-
podman exec {{ honcho_postgres_container_name }}
pg_isready -U {{ honcho_db_user }} -d {{ honcho_db_name }}
register: pg_ready
until: pg_ready.rc == 0
retries: 30
delay: 2
changed_when: false
# Quadlet does not auto-restart on .container changes — same pitfall as
# semaphore role. Force restart only when the template was modified.
- name: Restart Honcho PostgreSQL on Quadlet change
ansible.builtin.systemd:
name: "{{ honcho_postgres_container_name }}.service"
state: restarted
when: postgres_quadlet.changed

View File

@@ -0,0 +1,27 @@
---
# ============================================================================
# Post-deploy verification
# ----------------------------------------------------------------------------
# Polls the local Honcho API port until it responds. Fails loudly if the
# service doesn't come up — the operator should not get an "all green"
# playbook result while Honcho is silently broken.
# ============================================================================
- name: Wait for Honcho HTTP endpoint
ansible.builtin.uri:
url: "http://127.0.0.1:{{ honcho_listen_port }}/docs"
status_code: [200, 307]
return_content: false
register: honcho_ping
until: honcho_ping.status in [200, 307]
retries: "{{ honcho_health_check_retries }}"
delay: "{{ honcho_health_check_delay }}"
- name: Report Honcho status
ansible.builtin.debug:
msg: >-
Honcho API reachable on http://127.0.0.1:{{ honcho_listen_port }}/docs.
Traefik should now route hall-of-presidents.local.mk-labs.cloud to
this backend. Deriver enabled: {{ honcho_deriver_enabled }};
LLM transport: {{ honcho_llm_transport }};
deriver model: {{ honcho_deriver_model }}.

View File

@@ -0,0 +1,17 @@
---
# ============================================================================
# Named podman volumes
# ----------------------------------------------------------------------------
# Honcho itself is stateless; only postgres needs durable storage.
# ============================================================================
- name: Ensure named volumes exist
ansible.builtin.command:
cmd: "podman volume create {{ item }}"
register: volume_create
changed_when: "'already exists' not in (volume_create.stderr | default(''))"
failed_when:
- volume_create.rc != 0
- "'already exists' not in (volume_create.stderr | default(''))"
loop:
- "{{ honcho_postgres_volume }}"