Why this matters beyond the homelab: Evaluating build-vs-adopt, running hybrid local/cloud inference under a cost ceiling, and operating an LLM agent as a managed service are the exact patterns emerging in production AI platform work.
The Case Against My Own Code
BD-1 was a custom Node.js Discord bot I wrote and was proud of: Claude-powered, SQLite-backed, PM2-managed, under a $10/month API cap. It worked. It also logged 996 process restarts under PM2.
996 restarts is not a stability number, it is a verdict. Every new capability I wanted (tool use, skill loading, structured memory, local model fallback) meant building agent infrastructure from scratch inside a codebase designed to be a chatbot. At some point the honest engineering question stops being “can I build this” and becomes “should this be my code at all.”
The answer was no. This is the story of replacing a system I built with a system I operate, which is a harder decision than it sounds when the thing being replaced is your own work.
Framework Selection
The requirements: Discord-native, local model support through Ollama, cloud model elevation for hard queries, a skill/plugin system, and enough configurability to survive my opinions.
Hermes Agent (v0.18.0 at deployment) won the evaluation over extending BD-1. The deciding factors were the skill architecture and the model routing layer, both of which I would otherwise have spent months reinventing badly. Buying into a framework means accepting its opinions, but it also means bugs get fixed by a community instead of by me at midnight.
Architecture
Discord ←→ Jocasta (Hermes Agent v0.18.0)
│
├── Ollama: qwen3:14b-hermes (default, local)
├── Anthropic API: Haiku/Sonnet (elevation tier)
├── Skills: 76 loaded (SKILL.md format)
├── Fleet Codex: /root/.hermes/fleet-codex (Git-synced)
└── SOUL.md: persona definition
Host: Coruscant (VM 205, Node-B, 192.168.20.82)
Service: hermes-gateway.service (systemd)
Inference: RTX 4000 SFF Ada, 20GB VRAM (Tantive-III via Ollama)
Budget: $5/day, $50/month Anthropic hard cap
Search: Exa (semantic web extraction, free tier)
The VRAM Wall (ADR-010)
The original design specified qwen3:32b as the default local model. The RTX 4000 SFF Ada’s 20GB of VRAM disagreed. The 32b model exceeded available memory, and the options were quantize harder, offload to CPU and accept unusable latency, or drop to qwen3:14b.
I took the 14b substitution and documented it as an addendum to ADR-010 rather than pretending the original decision never existed. The hermes-tuned 14b variant handles function calling well, which matters more for agent workloads than raw parameter count. The lesson generalizes: model selection is a capacity planning problem before it is a quality problem.
The routing compensates for the smaller local model. Routine queries stay on local inference at zero marginal cost. Queries that need more capability elevate to Claude Haiku or Sonnet through the Anthropic API, inside a $5/day cap that makes a runaway loop an annoyance instead of an invoice.
Skills and the Codex
Jocasta currently loads 76 skills. A skill is a structured markdown document that teaches the agent a capability or a knowledge domain, loaded at runtime rather than baked into a prompt. The set includes operational skills for the fleet and a full study track for the Microsoft certification path: AZ-900, AZ-104, SC-300, MD-102, AZ-500, SC-200, and AZ-305. My cert prep agent runs on the same GPU that hosts it.
The knowledge layer is the Alliance Fleet Codex: BookStack documentation exported nightly to Gitea, then pulled by cron into Jocasta’s local codex directory at 4am. The agent answers infrastructure questions from version-controlled documentation that is never more than a day stale. That pipeline earned its own writeup, coming next.
Personality as Configuration
Hermes supports a SOUL.md file defining the agent’s persona. Jocasta’s blends the precision of its namesake (the Jedi Archives librarian) with a steadier, warmer advisory register. This sounds cosmetic. It is not. An agent that answers infrastructure questions needs a consistent voice for how it expresses uncertainty and how it pushes back, and defining that in a versioned file beats hoping it emerges from a system prompt. After a /reset in Discord, the persona reloads from file: personality as configuration, not as state.
Key Takeaways
- Replacing your own working code with a framework is an engineering decision, not a defeat. The 996 restarts were the data; the migration was the response.
- Hybrid inference under a hard budget cap is a genuinely production-shaped problem: local-first for cost, cloud elevation for capability, spend limits as a safety property.
- Skills plus a Git-synced knowledge base turn an LLM from a chat toy into an operations tool with auditable inputs.
- Document the substitutions. ADR-010’s addendum is the most honest artifact in this build.