Capture this session's durable state: Dia2 live as dia2-2b/dia2-1b (legacy dia retired), dia2 catalog on /tts with full controls + stable-voice default, zonos REST adapter (built, stack down), schema regen, all pushed. New foot-guns: dia2 image-build quirks, predefined-voices-not-in-/tts, voice_mode clone 'undefined' 404. Archived 6 older entries (4 decisions, 2 foot-guns).
20 KiB
Persistent memory — eshpfi-management
Last updated: 2026-05-31
Repo purpose
Reference workspace for PFI infrastructure: server inventory, canonical
Docker Compose stacks, ops playbooks, and conventions. Authoritative
copies of compose files live on the servers under
/opt/docker/compose/<stack>/; this repo mirrors them for version
control, editing, planning, and CI-driven deploys.
Tools and conventions
Sister repos (separate gitea repos, deployed by playbooks here):
| Repo | Role | CI status |
|---|---|---|
vh/task-board |
MCP + web dashboard for assistant task state (port 7878) | push-to-main → CI deploys (2026-04-29) |
vh/vor |
Inquisitor UI sidecar (port 7879) | push-to-main → CI deploys (2026-04-29) |
vh/nevermore |
Twice-daily LLM-curated briefing (port 8181, replaces news-digest) | push-to-main → CI deploys (2026-04-30) |
vh/asset-engine |
Internal control plane over inference services (port 8200, LAN-direct) | push-to-main → CI deploys (2026-05-12) |
vh/althing |
Inter-agent message bus (chamber UI port 7881, forseti + agent-runner daemons, valkey IPC) | push-to-main → CI deploys (2026-05-14) |
vh/mead-hall |
Bifrost tool-provider sidecar (port 5173 on dev VM 10.100.10.50) | push-to-main → CI deploys (2026-05-16) |
vh/skaldsong |
Wizard + reader surface (port 8300, ana-docker, registry-pull pattern) | push-to-main → CI deploys (2026-05-19) |
vh/worldtree |
Conversation API (corviduo-dev demo :8080 / personal :8081 / pinned :8082) — Heimdall auth, Bifrost integration | push-to-main → CI deploys |
vh/volva |
Codex peer agent on althing bus (single-turn oracle, systemd daemon on nh3-dev) | manual install via deploy/volva.service (2026-05-18) |
-
Two-layer backups — Backrest orchestrates restic for file+DB (5 fleet repos, daily 01:00 PDT); PBS-ANA primary + PBS-NH3 DR mirror for VM images. ana-nas is the SPOF for postgres + PBS-ANA datastore + cross-site restic targets — see
docs/runbooks/disaster-recovery.mdfor the blast-radius matrix. -
pull-hf-repo.yamlis the canonical "get a HuggingFace model/dataset onto ana-ml2's shared cache at/tank/aimodels/huggingface/" playbook. Supports--var repo_type=model|dataset|space. Replaces ad-hochuggingface_hub.snapshot_downloadpatterns. -
Worldtree admin auth — per-instance. Each Worldtree deployment (demo :8080, personal :8081, pinned :8082) has its own Heimdall registry and its own bootstrap admin key. Infra-ops's stored long-lived admin key (
key_id 61419c92) atana-docker:/opt/docker/conf/.secrets/worldtree-infra-ops-adminauths against demo only. For personal-instance admin ops, fetch the bootstrap admin per-op viadocker exec worldtree-personal-worldtree-api-1 printenv WORLDTREE_BOOTSTRAP_ADMIN_KEYon corviduo-dev. Used forPOST /admin/keys, admin diagnostics (/admin/sessions/<id>/{bifrost,tools}, etc.). -
Per-project user keys against personal Worldtree (issued 2026-05-19):
skaldsong:79744637(nh3-dev iteration),skaldsong:7c1dbbbe(ana-docker prod),althing:50d85460,mead-hall:a360822d. Sameuser_id=skaldsongacross both skaldsong keys → shared Heimdall agent slot; differentkey_id→ independently rotatable. Pattern: mint via/admin/keys, drop value to/tmp/wt-personal-<name>.keymode 600, dev collects + shreds (DO NOT cat to chat transcript). -
Skaldsong CD pattern (registry-pull). Differs from althing / asset-engine which build-on-host. vh/skaldsong's CI builds and pushes
gitea.phasefinal.com/vh/skaldsong:<sha>+:latest;playbooks/deploy-skaldsong.yamlon ana-docker pulls + recreates. SHA-pin only (no:latesthealth-gated advance yet). Prereq: host needsdocker login gitea.phasefinal.comonce (read:package PAT) — not currently in the workflow. -
docker-as-root pattern (for ops that have no admin API, e.g.
SqliteUserStore.set_bifrost_credentials): on hosts where the SSH user is in thedockergroup but lacks passwordless sudo, rundocker run --rm -v <target-dir>:/wt -v /var/run/docker.sock:/var/run/docker.sock docker:cli sh -c "..."to edit deploy-owned files without sudo. Documented with security warning inservers/corviduo-dev/README.md. docker-group membership is effectively root via bind-mount; treat as a sudo-equivalent grant. Foot-gun: when runningdocker composeinside this sandbox, any relative path in compose.yaml (e.g.${WORLDTREE_CONFIG_DIR:-./config}) resolves against the sandbox CWD, but Docker daemon interprets the resulting path against the HOST filesystem. Always pass-e VAR=/abs/pathto the docker run invocation for any relative-default config dir.
Current state / in-flight
As of 2026-05-31:
-
Dia2 LIVE as two instances on irv-ml1; zonos + csm still down.
dia2-2b(:8200, Dia2-2B) +dia2-1b(:8202, Dia2-1B) running + healthy on GPU 0 fromlocal/dia:v2; catalogstatus: ready(both exercised). Legacy Dia 1.6B retired. zonos: REST adapter built (stacks/zonos/adapter/,local/zonos-api) but the stack is DOWN — brought down to free 3090 VRAM for Dia2; catalog entrystatus: down, adapter port 8203. csm: still PARKED (status: down, gated — needsCSM_HF_TOKENbefore first start; non-reproducible →experimentalwhen up). ComfyUI:8188still a catalog-deferred UI link (open hand-off to asset-engine-dev, no form-field API). -
Dia2 voices staged — re-stage if host rebuilt. The 43 curated voices baked at
/app/voicesaren't reachable from/tts's clone path, so they're copied into/worktank/dia/reference_audio(restic-included). This is a one-time manual host step (docker exec dia2-2b sh -c 'cp -n /app/voices/* /app/reference_audio/'), documented instacks/dia/README.md, NOT auto-run on recreate. Catalog voice default isvoice_mode: clone+clone_reference_filename: Abigail.wav. Open offer (not done): make staging auto-run via container entrypoint. -
asset-engine catalog fully synced + pushed.
docs/asset-engine/ services.yaml(canonical) andvh/asset-engine's vendoreddata/services.yaml(re-synced viasync_catalog.py, commit58dadfe) both on origin; catalog v1, 18 services; schema regenerated. asset-engine deploy-on-push triggered. asset-engine-dev notified on althing thread01KSZM5MNQYP2DZ25Y2F2DXDBYof the breaking dia→dia2 swap (drop dia tile; add dia2-2b/dia2-1b/zonos), the/ttsfield shapes, and a UI-hardening ask (don't serialize empty optional selects as the string"undefined"; enforce clone_reference_filename required-when-clone). -
ttyd fleet driver seat operational on nh3-dev (browser/iPad/Vision Pro into the zellij
Claudesession): RO:7681/ drive:7682via a Caddy front, network-gated (no auth). Lives in~/.configon nh3-dev (out of this repo). Full wiring + gotchas → auto-memoryreference_ttyd_fleet_seat. -
Worldtree all instances healthy on v0.29.13 (last-known, not re-checked this session). Demo (:8080), personal (:8081), pinned (:8082). v0.29.x = saga→echo refactor + selene-judgment validator + canonical
*.yaml.exampleconfigs. -
Skaldsong on v0.32.2 (ana-docker:8300). Kokoro TTS streaming via SSE working end-to-end; default voice
af_heart. Last-known. -
artemis-31b-v1i live on llama-swap + worldtree personal. BeaverAI Gemma 4 31B Q6_K (~28.6GB, 128K ctx), reasoning via
--reasoning-format deepseek. -
All commits pushed (operator-authorized 2026-05-31). The prior pending-push backlog + this session's TTS/catalog work are all on origin (eshpfi-management through
5c47843; asset-engine through58dadfe). No local-only backlog. (Standing rule still holds: never push without an explicit greenlight — this push was granted.) -
VibeVoice catalogued for skaldsong #73 contract (TTS alongside Kokoro). Endpoint
http://10.100.79.3:8194, OpenAI-compat. NO per-word timings (diffusion); read-along is a v2 forced-alignment upgrade (Parakeet irv-ml1:8765 or Whisper). -
Disclosed-keys hygiene queue — rotate at convenience:
/tmp/wt-personal-skaldsong-prod.keyon nh3-dev (shred after verify); mead-hall's prior Worldtree bearer (superseded bya360822d); WorldtreeZ_AI_API_KEY/ZAI_API_KEY(2026-05-12 outage); chamberforseti/agent_runnerapi_keys (superseded by50d85460); Gitea runner registration token (a1135753...). -
Still open from prior sessions: rotate
MINIFLUX_PASSWORD(leaked twice); clean up legacynews-digestdetritus on ana-docker; watch nh3-nas/volume1(was 65%; recheck before ~80%); thedocker push 60s client-side ceilingmystery remains uninstrumented.
Recent decisions
-
[2026-05-31]Dia2 deployed as two fixed-model instances (dia2-2b:8200,dia2-1b:8202) fromlocal/dia:v2, retiring legacy Dia 1.6B; catalogdiaentry removed → dia2-2b + dia2-1b (breaking for asset-engine). Rationale: the devnen wrapper is single-model and IGNORES the OpenAImodelfield (verified on its live OpenAPI), so the only way to offer both Dia2 models as real per-request asset-engine choices is one fixed endpoint per model.3139e81(deploy),db15638(catalog swap). -
[2026-05-31]Both dia2 catalog entries route to the wrapper's richer/ttsendpoint (not/v1/audio/speech) to expose the full control surface (cfg_scale/temperature/top_p/cfg_filter_top_k/voice_mode/clone); all defaults sourced from the wrapper'sCustomTTSRequestPydantic blessed values. Voice default isvoice_mode: clone+clone_reference_filename: Abigail.wavso a stable (non-random-gender) voice is the out-of-box behavior.55602b7,5c47843. -
[2026-05-31]Zonos REST adapter (stacks/zonos/adapter/,local/zonos-api) — thin OpenAI-ish/v1/audio/speechFastAPI in front of the Gradio-only Zonos SDK; JSON-envelope{audio, audio_format, seed}(Zonos is the fleet's first seedable TTS). Port 8203 (moved off 8201 — collided with csm). Built; NOT deployed (stack down for VRAM). Also fixed the upstream image's missing CMD (71df6f7).81efa8d. -
[2026-05-31]Catalog schema regenerated: addedCatalogLifecycle+reproducibility.seed_field(b7b2130). Resolves the stale-schema hand-off; catalog now validates clean. (asset_enginecatalog.pyPydantic already supported both — schema file was just behind.) -
[2026-05-31]TTS bench expanded withstacks/{dia,zonos,csm}(666f7f3dia+zonos,a4b8c2acsm): dia = Nari dialogue TTS via devnen/Dia-TTS-Server (OpenAI-compat, :8200), zonos = Zyphra Gradio audition surface (:8199, no API), csm = Sesame conversational (gated model, :8201). dia + csm catalogued indocs/asset-engine/services.yamlstatus: down+ repro audits (8eac39b); all three deployed PARKED to irv-ml1 (no GPU spin). Zonos + ComfyUI = catalog-deferred (no form-field API) → asset-engine UI links, handed to asset-engine-dev. The bench already had Fish S2-Pro / Chatterbox-Turbo / IndexTTS-2 / CosyVoice3 / Kokoro / VibeVoice / Qwen3-TTS / Kyutai, so the research-agent's top-2 picks were already deployed. -
[2026-05-31]Remote browser/iPad/Vision-Pro driver seat for the agent-fleet zellij sessionClaudestood up on nh3-dev (ttyd behind Caddy, network-gated). Brokkr-smithy-dev request; no Tailscale (WG at firewall). Out of this repo — full architecture + the HTTP2/OSC52/Safari-auth gotchas in auto-memoryreference_ttyd_fleet_seat. -
[2026-05-30]esh-docker-vm NFS boot-ordering fix:playbooks/fix-esh-nfs-boot-ordering.yaml(c0458d9, +53157b1drop-in filename-collision fix) adds_netdev,nofailto the four 10.0.50.50 NFS mounts + a dockerAfter=remote-fs.targetdrop-in — resolves paperlessExited(255)on every reboot. traefik also gainedrestart: unless-stopped(was Docker-defaultno→ never auto-started after a reboot; "homepage broken" was collateral via the traefik route). Full incident → auto-memoryincident_esh_docker_nfs_boot_race. -
[2026-05-27]Worldtree v0.29.x landed full saga→echo refactor + config-validator hardening. Net image:- v0.29.10 —
create_providerchecks model_catalogfamily:before regex auto-detect (artemis routing fix) - v0.29.11 — collect-then-raise echo startup validators (UX fix for cascading one-at-a-time crash cycle that bit demo + personal during the v0.29.0 → v0.29.9 deploy)
- v0.29.12 — ships
providers.yaml.example+defaults.yaml.examplecanonical configs (REQUIRED/OPTIONAL annotated, guaranteed-pass- validator). Replaces reverse-engineer-from-validator-errors as the operator's path. - v0.29.13 —
reasoning_contentextraction in base provider + catalogfamily:lookup fix (artemis reasoning route through worldtree GemmaProvider). Operator-asked, worldtree-dev-shipped, all auto-deployed via CI.
- v0.29.10 —
-
[2026-05-27]artemis-31b-v1i added to llama-swap + worldtree personal providers.yaml. BeaverAI Gemma 4 31B Q6_K (~28.6GB) pulled viapull-hf-repo.yaml, llama-swap config mirrors gemma4-31b-dense settings at 128K ctx,--reasoning-format deepseek(gemma format not supported in deployed llama.cpp). Worldtree catalog entry hasfamily: gemmaso GemmaProvider routes reasoning tokens correctly. Pinned locally — push pending operator greenlight. -
[2026-05-27]Skaldsong streaming TTS v0.32.0 → v0.32.1 → v0.32.2. v0.32.0: chunked-batch via SSE on/api/stories/{id}/audio?voice=X, one Kokoro POST per paragraph. v0.32.1: defensive catch-all in event_stream after silent JSONDecodeError (made the real exception surface in an SSE error frame). v0.32.2: NDJSON parsing — Kokoro/dev/captioned_speechreturns multi-line JSON for large inputs (one object per chunk); was usingresp.json()which only parsed the first object. Verified end-to-end clean.
22 older entries archived to archival-memory.md.
Tried and abandoned
-
[2026-05-31]Building the dia2-capable image surfaced THREE upstream packaging quirks: (1)pip install -e nari-labs/dia2fails — its pyproject build backend lacks the PEP 660build_editablehook; (2) plainpip installbuilds an emptyUNKNOWN-0.0.0wheel because the base image's setuptools (59.6) is older than dia2's required>=70, so it ignores the[project]metadata; (3)--no-deps(which the wrapper's own auto-installer uses) leavestransformers/sphn/whisper-timestampedmissing. Fix that worked (local/dia:v2,stacks/dia/dia2-image/): copy the pure-pythondia2/package straight into site-packages + install ONLY those 3 deps; torch 2.12 / numpy 2.2 in the base already satisfy Dia2, so no risky CUDA/torch churn. -
[2026-05-31]Dia2 predefined voices (43, baked at/app/voices) are NOT reachable from the/ttsclone path — it resolvesclone_reference_filenameagainst the reference_audio dir ONLY (engine.py). The OpenAI/v1/audio/speechvoiceparam DOES auto-resolve them by name (separate code path), which masked the gap in early testing. Fix: stage/app/voices/*into/worktank/dia/reference_audioso/ttsclone can use them. (So a "verify on the endpoint the catalog actually targets" lesson — testing the OpenAI endpoint nearly shipped a catalog that 404s on/tts.) -
[2026-05-31]voice_mode=clonewith an emptyclone_reference_filename→ asset-engine serializes it as the literal string"undefined"→/tts404Reference audio file not found: undefined. Reproduced directly. Worked around in the catalog (default the field to a real voice); proper fix is asset-engine-side (don't send"undefined"for empty optionals; enforce conditional-required) — flagged to asset-engine-dev. -
[2026-05-31]asset-enginedocs/asset-engine/services.schema.jsonis a DERIVED artifact (regen from the Pydantic model viadump_schema.py) and had DRIFTED: it rejected thelifecyclefield that 12/14 live services already use (13 pre-existing validation errors against the committed catalog). [2026-05-31] RESOLVED: schema regenerated withCatalogLifecyclereproducibility.seed_field(b7b2130); catalog now validates clean. Standing lesson: the schema is generated from asset_engine'scatalog.py— hand-editingservices.yamlshape without regenerating re-introduces drift.
-
[2026-05-30]esh-docker-vm:hardNFS mounts from 10.0.50.50 froze a container worker in UNKILLABLE D-state when the NAS stalled —docker restartfails with "tried to kill container, but did not receive an exit event"; only a host reboot clears it. Separately,fstab defaults(no_netdev) made NFS-bind containersExited(255)on reboot. Diagnosis + recovery steps → auto-memoryincident_esh_docker_nfs_boot_race. -
[2026-05-31]ttyd-over-TLS forces HTTP/2 (no flag disables it) which kills ttyd's terminal WebSocket (blank screen); Safari/WebKit never sends HTTP basic-auth on WS upgrades (→ ttyd "User code denied"). Both solved for the fleet seat (Caddy forces HTTP/1.1; auth dropped to network-gating) — detail in auto-memoryreference_ttyd_fleet_seat. -
[2026-05-27]docker compose up -dfrom within thedocker:clisandbox:${VAR:-./config}defaults resolve./configto the sandbox CWD (e.g./wt/config). Docker daemon interprets the resulting path against the HOST filesystem, not the sandbox's. Auto-creates an empty dir on the host → container saw an empty bind target → entrypoint shim seeded image-baked defaults (lost all the host-side providers.yaml patches I'd applied earlier in the day). Root cause for ratatoskr-dev's Tier 3 sessions 500. Fix: pass-e WORLDTREE_CONFIG_DIR=/opt/worldtree-personal/configto the docker run invocation. Captured into the docker-as-root pattern note in Tools and conventions. -
[2026-05-27]:latest-pinned compose + private gitea registry + sandboxed pull = recreate on ancient cached:latest. Local:latesttag never advanced because deploy.yml pulls by SHA (not by tag); sandbox can'tdocker pull(no creds for private registry);compose up -d --pull neverused the 2-week-old cached:latest. Symptom: personal worldtree's matrix container crash-looped because the ancient image didn't understand the new config schema. Fix: retag SHA →:lateston host first (docker tag <registry>/<repo>:<sha> <registry>/<repo>:latest), then recreate with--pull never. Better long-term: pin SHA explicitly in.env, advance in CI. -
[2026-05-27]Container recreate during in-flight skaldsong gen kills the runner. Pattern: my llama-swap restart at 23:57Z + a v0.31.2compose up -dat 02:47Z both took out active dramatist passes. Confirmed by skaldsong-dev INV-006 ("partial state only flips on host restart"). With deploys landing every ~10min during active dev and stories taking >5min, runner-killed-by-recreate is structural, not incidental. Roadmap (skaldsong-dev): pre-shutdown signal handler (cleanup row state to failed/aborted), per-scene resume-from-checkpoint,/api/admin/quiesceendpoint. None shipped yet; operator's call which path. -
[2026-05-27]--reasoning-format gemmaon artemis-31b-v1i — not supported in the deployed llama.cpp build. Accepts onlynone | deepseek | deepseek-legacy.deepseekpopulates thereasoning_contentSSE delta field which Worldtree GemmaProvider's fallback path checks. Was load-bearing for getting reasoning tokens through to ratatoskr's wire. -
[2026-05-27]head -c Npiped after a streaming curl SIGPIPEs the curl, killing the request early. Bit me twice while probing SSE-shape samples. Use file-write + separate read.
24 older entries archived to archival-memory.md.