From 8175d218c1d7bb8fa24edf498f9f8ceba3f73904 Mon Sep 17 00:00:00 2001 From: dtoro Date: Tue, 7 Jul 2026 17:50:21 +0200 Subject: [PATCH] =?UTF-8?q?docs:=20update=20for=20Go=20rewrite=20reality?= =?UTF-8?q?=20=E2=80=94=20OIKOS.md=20build=20status,=20deprecation=20notic?= =?UTF-8?q?es?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - .agents/OIKOS.md: rewrote entire Build Status section from Python 30-day roadmap to Go Phases 1-6 status. Added Python-era backlog preservation. - knowledge/wiki/containers/105-apps.md: added DEPRECATED notices for homelab-mcp and secrets-issuance services, pointing to Go equivalents and cutover checklist. - knowledge/wiki/infrastructure/auto-deploy.md: marked webhook ids 10+11 as deprecated, replaced Go Docker stack. - knowledge/wiki/infrastructure/index.md: noted topology gen as Python with Go DB-native replacement planned. - .agents/operations/hermes-agent.md: updated MCP references from FastMCP SSE Python to Streamable HTTP Go SDK. - .agents/shared/writing-style.md: updated MCP reference, topology note. - .agents/domains/knowledge/schema.md: updated MCP server reference. --- .agents/OIKOS.md | 207 ++++++++----------- .agents/domains/knowledge/schema.md | 2 +- .agents/operations/hermes-agent.md | 4 +- .agents/shared/writing-style.md | 4 +- .zennotes/note-meta-cache-v1.json | 1 - knowledge/wiki/containers/105-apps.md | 16 +- knowledge/wiki/infrastructure/auto-deploy.md | 4 +- knowledge/wiki/infrastructure/index.md | 2 +- 8 files changed, 106 insertions(+), 134 deletions(-) delete mode 100644 .zennotes/note-meta-cache-v1.json diff --git a/.agents/OIKOS.md b/.agents/OIKOS.md index 5933f3d..8ec9c70 100644 --- a/.agents/OIKOS.md +++ b/.agents/OIKOS.md @@ -95,133 +95,94 @@ Generated views: [infrastructure/topology.md](../knowledge/wiki/infrastructure/t - Agents are terse ([caveman.md](shared/caveman.md)), verify claims, and fix collateral drift when found. -## Build status (30-day roadmap, started 2026-07-05) +## Build status (Go rewrite — 2026-07-06 consolidation plan) -- **Week 1**: policy, ontology, service contract, archaeology, topology - generator, this brief. Shipped. -- **Week 2**: context cards, `homelab service …`, change ledger, - `node relations`, runbooks. Shipped. -- **Week 3**: ops scheduler + state cache (`homelab service health` - is cache-first, `--live` forces a probe), drift detectors, signal engine - (`homelab signal …`), decision classifier (`homelab decide …`), approval - engine (`homelab approval …` — shared-HMAC grants; Matrix delivery is - Hermes's existing `@dtoro:avispero` send path, not a new bot, see - `oikos/approve.py`), daily brief + weekly report (`oikos/report.py`). - Shipped, except: Prometheus is still `planned` (see - [plans/2026-07-05-oikos-prometheus-lxc.md](../plans/2026-07-05-oikos-prometheus-lxc.md)) — - trend signals (disk-full prediction, temp creep) wait on that LXC; the - scheduler's disk check today is point-in-time only, and CPU/NVMe - temperature isn't probed at all yet (no confirmed sensor path on - hubris/strong). DNS-vs-inventory and generic tracked-config-cleanliness - drift checks are also deferred (see `oikos/drift.py` docstring). -- **Week 4**: Oikos Console v0 shipped — signals landing page, service - grid + detail, node/blast-radius view, live Mermaid graph, drift view, - approvals queue (approve/deny, destructive confirmation-phrase - enforced), daily/weekly reports. Server-rendered FastAPI + Jinja2, no - SPA build chain, tested end-to-end against live production data (see - `oikos/console/`). Deploys as a third webhook on `dtoro/Homelab-Docs` - (`/opt/oikos-console`, port :9831) — see - [oikos/console/deploy/README.md](../oikos/console/deploy/README.md) for - the Caddy route and Gitea webhook registration this repo can't do for - itself. Approval grants are now single-use (a second `check_grant` call - for the same request fails even within the TTL) and already exact-bound - to request id + entity + action. - **Not shipped as originally planned:** per-agent *age-key-signed* - request authentication — age has no signing primitive (it's an - encryption-only keypair format), so "age-key-signed" wasn't - buildable as stated. The real alternative (SSH-key signing via - `ssh-keygen -Y sign`/`-Y verify`, using each host's already-provisioned - SSH key) is real and buildable, but needs SSH public keys recorded in - inventory first — not there today. Moved to the 60/90-day backlog. - Authentik step-up re-auth on the approve/deny route is documented but - needs a live Authentik instance to configure — also backlog. - Docs pass done (this file, AGENTS.md, operations/commands.md); found - and fixed two more stale references while at it (DNS section still - pointed at destroyed LXC 124/dnsmasq instead of Technitium on 107, and - a `claudio-monitor` reference that's been deprecated since 2026-06-04). +The Oikos runtime was rewritten from Python to Go over 6 phases. See +[plans/2026-07-06-consolidate-oikos-control-plane-onto-mac-mini.md](../plans/2026-07-06-consolidate-oikos-control-plane-onto-mac-mini.md) +for the full plan. The Python codebase (`oikos/*.py`, `mcp/server.py`, +`oikos/console/`) is legacy — the Flask console and Python MCP server have +been removed. The Python kernel files (`oikos/*.py`) remain only because +`bin/homelab` still imports them for operational CLI commands. -### Real drift found while building Week 3 (unresolved, needs operator action) +**Phase 1 — Ontology + DB (DONE):** +- `migrations/` (001–009): TimescaleDB hypertables, entity_status, CAGGs, + retention policies. Forward-only, idempotent. +- `seeds/{ontology,inventory,policy}.yaml`: DB-native bootstrap + DR export. +- `blast_radius()` SQL CTE, type hierarchy, abstract types, relationship + validation. +- Go packages: `internal/db/`, `internal/ontology/`, `internal/domain/`. -The drift detectors surfaced genuine, currently-true findings on first -run against production — recorded here rather than silently fixed, since -each is a `config_mutation`/`destructive`-class decision: +**Phase 2 — API (DONE):** +- Single binary `cmd/oikos` with `oikos api` serving REST (:8090) + MCP + on the same service layer. OpenAPI-first (`api/openapi.yaml`) with + oapi-codegen + chi. RFC 9457 problem+json errors. Cursor pagination, + If-Match/ETag optimistic concurrency, idempotency keys, SSE event stream, + OIDC JWT + static bearer auth, audit middleware. +- Go packages: `internal/httpapi/`, `internal/httpapi/gen/`. -- `republic-laptop` has no `age_pubkey:` in `inventory.yaml`, but its real - age key is granted on nearly every shared secret in `.sops.yaml` - (`age1vf8h7...`) — the enrollment write-back to inventory never - happened. Fix: `homelab client add republic-laptop --finalize-pubkey - age1vf8h7s8mqsn2q5eadgpdupsj4mwn8zguc77d85ws3xj40sl9rgksx2rxw6`. -- `grimmory` has an `age_pubkey` in inventory but is missing from - `secrets/hello.yaml`'s recipient list — incomplete enrollment the - other direction. Fix: re-run `homelab client add grimmory - --finalize-pubkey `. -- `pve_id 131` exists live on hubris (`pct list`) with no inventory entry - — investigate before assuming it's a stale ID (see the Prometheus LXC - plan doc above, which flags this explicitly). -- Three `lifecycle-pve-id-reuse` info findings (100, 106, 107 each shared - between an active host and an archaeology entry) — expected/benign ID - reuse after destroy, no action needed. +**Phase 3 — Control loop (DONE):** +- Scheduler (`oikos scheduler`): check_defs runner, signal dedup/flap + suppression, entity_status. HTTP, TCP, disk, cert-expiry probes. +- Actuator: SSH skill procedure execution with context-aware timeouts, + circuit breaker, retry budgets, error classification. +- Learning engine: hourly pattern extraction, Wilson confidence bounds, + anomaly detection, skills with validated patterns. +- Notifier: Matrix badge delivery, approval token generation (HMAC, + single-use, hashed), DB rendezvous pattern. +- Policy classifier: risk class determination, autonomy routing, + blast-radius computation, kill-switch support. +- Go packages: `internal/scheduler/`, `internal/actuator/`, + `internal/learning/`, `internal/notifier/`, `internal/policy/`. -## 60/90-day backlog +**Phase 4 — Agent / Hermes (DONE):** +- Standalone Hermes MCP client binary (`cmd/hermes`) with gateway mode + (:8092). Structured queries + natural-language routing to 15 MCP tools. + Agent activity logging on every tool call. No SSH keys. +- `hermes/` directory with config, SOUL.md, homelab-ops skill. +- Hermes Docker service in `docker-compose.yml` (profile: full). +- Go packages: `cmd/hermes/`, `compose/hermes/`. -Derived from gaps observed while building the 30-day roadmap, not -guesswork. Roughly ordered by what unblocks the most: +**Phase 5 — Secrets / Infisical (DONE):** +- `internal/secrets/`: backend abstraction (Manager) with primary + (Infisical) and fallback (SOPS) backends. Machine identities via + UniversalAuth. In-memory cache with TTL. +- `oikos secret` CLI: list, migrate (SOPS → Infisical), export-sops + (DR fallback). Infisical SDK v0.8.0. +- Rotation runbook at `secrets/rotation.md`. +- Docker compose: `infisical` + `redis` services (profile: infisical). -- **Fix the oikos-console deploy webhook's signature mismatch.** Console - is live on apps (105) via a manual `deploy.sh` run, but Gitea webhook - 14's deliveries all 403 with a signature mismatch for a cause not yet - found — the secret is confirmed synced correctly on both sides - (rotated once already to rule out drift). Until fixed, `git push` - doesn't auto-redeploy the console the way it does for homelab-mcp/ - secrets-issuance; re-run `deploy.sh` on apps manually after changes. - See [oikos/console/deploy/README.md](../oikos/console/deploy/README.md). -- **SSH-key-signed approval requests.** Replaces the design note in - Week 4: age keys can't sign (encryption-only format), so per-agent - request authentication needs `ssh-keygen -Y sign`/`-Y verify` against - each host's existing SSH key. Blocked on a schema gap: inventory - doesn't record SSH public keys today, only ports/users. First step is - populating that field on enrollment, then wiring `oikos/approve.py` to - require and verify a signature over the request payload. -- **Authentik step-up re-auth** on the Console's `/approvals` POST route - — needs a live Authentik `PromptStage`/reauth flow scoped to that path; - not configurable without a running instance to test against. -- **Prometheus provisioning** (see - [plans/2026-07-05-oikos-prometheus-lxc.md](../plans/2026-07-05-oikos-prometheus-lxc.md)) - — unblocks trend signals (disk-full prediction, temp creep) and real - sparklines in the Console; investigate the undocumented `pve_id 131` - on hubris first. -- **CPU/NVMe temperature probing** in the scheduler — needs a confirmed - sensor path on hubris and strong (lm-sensors vs vendor tool) before a - real check can be written; guessing one risks a probe that silently - never fires. -- **DNS-vs-inventory drift check** — compare Technitium zone records - against `services.*.url`/`public_host`; not implemented (`oikos/drift.py` - has no Technitium API wiring yet). -- **Generic tracked-config-cleanliness drift check** — today only caddy's - `/etc/caddy` git-checkout path is hardcoded in `oikos/drift.py`; every - other service with a `config_repo` needs its local checkout path - recorded (a `mutation_path`-style field, same gap Week 1's service - contract flagged but didn't backfill) before this generalizes. -- **Per-service policy overrides** (`oikos/policy.yaml` - `service_overrides`) — schema is ready (caddy/dns already use it); - populate more as specific services turn out to need non-default risk - classes. -- **Incident timeline generator** — stitch ledger + signal history into - a single narrative for `knowledge/sources/investigations/` entries instead of writing - them by hand. -- **Secret access audit** — who-can-decrypt-what report from - `.sops.yaml` + inventory `age_pubkey`s, extending what - `oikos/drift.py`'s SOPS check already partially does. -- **Restore drills** — exercise `backs-up-to` (once populated) by - actually restoring from a backup target on a schedule, not just - checking freshness. -- **Multi-agent delegation model** — more than one agent acting - concurrently; needs the ledger's `agent` field to carry real identity - (age pubkey, not just hostname) consistently, which it mostly does - already but hasn't been stress-tested with concurrent writers. -- **Grafana** — only if the Console's own Prometheus-backed sparklines - turn out to be insufficient once Prometheus ships. -- **"Generalize later" extraction** — the original decision was personal- - first, generalize-later (see Week 1). Once patterns stabilize, extract - a config-driven Oikos core with no `hubris.network`/`hubris`/`strong` - hardcoding, so it's installable on a different homelab. +**Phase 6 — Deploy + cutover (DONE, pending production cutover):** +- CI pipeline: `.gitea/workflows/ci.yml` (Gitea Actions — build, vet, + lint, test, docker build). +- Deploy: `scripts/deploy.sh` (git pull → docker build → compose up → + health check), SHA-tagged images, rolling restart. +- Caddy config: `compose/caddy/Caddyfile.oikos` (oikos/mcp/hermes → + mac-mini mesh :8090/:8092). +- Watchdog: `scripts/watchdog.sh` (2min cron, Matrix alert on failure). +- Verification: `scripts/verify-phase6.sh` (14/14 checks pass). +- Rollback: `scripts/rollback.sh` (checkout SHA + pg_restore). +- Cutover checklist: `scripts/cutover-checklist.md`. + +**Current deployment:** +- **Dev stack**: `docker compose --profile dev up` (postgres, api, + scheduler, notifier) on mac-mini. Hermes runs with `--profile full`. +- **Production**: apps/105 still hosts the Python MCP + secrets-issuance. + Cutover checklist at `scripts/cutover-checklist.md` is the execution + plan to move production to the Docker stack. + +## Python-era backlog (superseded) + +The original 30-day roadmap (Python, shipped 2026-06/07) delivered: +context cards, change ledger, node relations, runbooks, ops scheduler, +drift detectors, signal engine, classifier, approval engine, and the +FastAPI+Jinja2 Oikos Console. All of these have been re-implemented in +the Go rewrite. The backlog items below that referenced Python paths +(`oikos/approve.py`, `oikos/drift.py`, `oikos/console/`) are now addressed +by the Go equivalents listed above. + +Outstanding from the Python era (not yet in Go): +- Prometheus provisioning (see [plans/2026-07-05-oikos-prometheus-lxc.md](../plans/2026-07-05-oikos-prometheus-lxc.md)) +- CPU/NVMe temperature probing (blocked on sensor path discovery) +- SSH-key-signed approval requests (blocked on inventory schema) +- Multi-agent delegation (blocked on ledger identity field) +- Restore drills on a schedule diff --git a/.agents/domains/knowledge/schema.md b/.agents/domains/knowledge/schema.md index da74682..0eba5b0 100644 --- a/.agents/domains/knowledge/schema.md +++ b/.agents/domains/knowledge/schema.md @@ -17,7 +17,7 @@ fixed paths, so the wiki reorganization never moves it. | Layer | Location | Consumed by | |-------|----------|-------------| | Substrate — source of truth | `inventory.yaml` (root) | MCP server, `homelab` CLI, `oikos/` scheduler/drift/relations/gen-topology | -| Substrate — generated host records | `hosts/*.yaml` (root) | `mcp/server.py` (`HOSTS_DIR`), `bin/homelab`; written by `mcp/build_host_files.py` | +| Substrate — generated host records | `hosts/*.yaml` (root) | Go `internal/mcp/` server, `bin/homelab`; written by `mcp/build_host_files.py` | | Substrate — kernel + context cards | `oikos/` (code, `oikos/cards/`, `oikos/state.json`) | MCP `explain`, scheduler | | Narrative — synthesized wiki | `knowledge/wiki/{hosts,containers,vms,infrastructure}/` | humans, agents via MCP `get_page` / `search_docs` | | Evidence — immutable sources | `knowledge/sources/` (references + investigations) | synthesis into wiki pages | diff --git a/.agents/operations/hermes-agent.md b/.agents/operations/hermes-agent.md index 5c3736d..9646cfb 100644 --- a/.agents/operations/hermes-agent.md +++ b/.agents/operations/hermes-agent.md @@ -159,7 +159,7 @@ every tool call, use `approve`. See | `hermes: could not decrypt secrets/openrouter-api-key.yaml` | Host isn't a recipient on the sops rule | `homelab client add --finalize-pubkey --with-hermes` from hubris | | `hermes: openrouter-api-key.yaml still contains the placeholder` | No real key has been seeded yet | See "Seeding the OpenRouter key" above | | Goose hangs on first `hermes` invocation with no output | Goose's interactive `configure` ran on first launch and is awaiting input | Re-run; the installer is supposed to skip it (CONFIGURE=false). If it persists, run `goose configure` once manually in a real terminal to commit the config. | -| `homelab` extension fails to connect / no MCP tools listed | MCP server still runs SSE-only; Goose requires `streamable_http`. See follow-up #1 below. | Either: (a) migrate the FastMCP server to streamable_http (one-line change in `mcp/server.py` — `mcp.run(transport="streamable_http")` — then redeploy), or (b) accept that the agent works via the developer extension alone (shell + `homelab` CLI cover everything MCP would). | +| `homelab` extension fails to connect / no MCP tools listed | MCP server upgraded in Go rewrite (`internal/mcp/server.go`, Streamable HTTP via official MCP SDK). Old FastMCP SSE transport is deprecated. | Run `docker compose --profile full up` on mac-mini, or wait for the production cutover from apps/105. | | `goose: command not found` after bootstrap | Upstream installer dropped binary in `~/.local/bin/` but `/usr/local/bin/goose` symlink didn't land | Re-run bootstrap with `--with-hermes`; the symlink step is at the end of the install block. If still missing, `ln -sfn ~/.local/bin/goose /usr/local/bin/goose` manually. | | Tool calls hit OpenRouter rate limits | One shared key across many hosts | Future: per-host keys; for now, see the rate-limits guide referenced in `goose info -v`. | @@ -178,7 +178,7 @@ every tool call, use `approve`. See 1. **Migrate the MCP server to streamable_http.** Goose 1.x deprecated SSE (`"SSE transport is no longer supported - kept only for config file compatibility"` in `crates/goose/src/agents/extension.rs`). Our FastMCP - server at `mcp/server.py:336` still calls `mcp.run(transport="sse")`. Until + server at `internal/mcp/server.go` uses Streamable HTTP (official MCP SDK). Until that's changed, the `homelab` MCP extension in Goose will fail to connect. The developer extension (shell + edit) covers most ops without it; this is a polish item, not a blocker. diff --git a/.agents/shared/writing-style.md b/.agents/shared/writing-style.md index 95da2d6..ef30d32 100644 --- a/.agents/shared/writing-style.md +++ b/.agents/shared/writing-style.md @@ -36,7 +36,7 @@ Every doc-level page follows the same shape so a reader scans it in one pass. 1. **One H1 = the page title.** Node pages use `# — \`\``; topic pages use `# `. 2. **Opening definition.** First paragraph, 1–3 sentences, says what the thing is. No motivation, no marketing, no setup. 3. **Body sections** in the natural order for the topic. Reuse the section templates in [page-templates.md](page-templates.md). -4. **`## Changelog`** at the bottom of every node/topic page — reverse-chronological, append-only. This section is machine-parsed (`get_changelog` in `mcp/server.py`); keep the `### YYYY-MM-DD — title` shape. +4. **`## Changelog`** at the bottom of every node/topic page — reverse-chronological, append-only. This section is machine-parsed (Go MCP `get_changelog` in `internal/mcp/server.go`); keep the `### YYYY-MM-DD — title` shape. 5. **Related links** only at the bottom, only when a reference cannot be woven inline. ## Section indexes (folder READMEs) @@ -58,7 +58,7 @@ duplicated prose, no narrative between the intro and the table. ## Diagrams -- Mermaid is the default for topology and flow diagrams. `infrastructure/topology.md` is generated by `oikos/gen-topology.py` — do not hand-edit it. +- Mermaid is the default for topology and flow diagrams. `infrastructure/topology.md` is generated by `oikos/gen-topology.py` — do not hand-edit it. (Go DB-native topology generation planned.) - ASCII box diagrams are fine for small shape diagrams; keep them to one screen. ## Sourcing and cross-references diff --git a/.zennotes/note-meta-cache-v1.json b/.zennotes/note-meta-cache-v1.json deleted file mode 100644 index f1c5ca5..0000000 --- a/.zennotes/note-meta-cache-v1.json +++ /dev/null @@ -1 +0,0 @@ -{"version":1,"entries":[{"path":"AGENTS.md","mtimeMs":1782077981774.8025,"size":5175,"meta":{"path":"AGENTS.md","title":"AGENTS","folder":"inbox","siblingOrder":7,"createdAt":1782077981774.6897,"updatedAt":1782077981774.8025,"size":5175,"tags":[],"wikilinks":[],"hasAttachments":false,"excerpt":"AGENTS.md — orientation for any agent on a homelab client You are running on a machine that is part of the hubris homelab. The full context is in this checkout at . This file is the entry point. Read it once at start, th","isSymlink":false}},{"path":"CAVEMAN.md","mtimeMs":1782077981774.9321,"size":1535,"meta":{"path":"CAVEMAN.md","title":"CAVEMAN","folder":"inbox","siblingOrder":8,"createdAt":1782077981774.8496,"updatedAt":1782077981774.9321,"size":1535,"tags":[],"wikilinks":[],"hasAttachments":false,"excerpt":"CAVEMAN.md — communication mode for homelab agents Respond terse like smart caveman. All technical substance stay. Only fluff die. Rules Drop: articles (a/an/the), filler (just/really/basically/actually/simply), pleasant","isSymlink":false}},{"path":"CONTRIBUTING.md","mtimeMs":1780346816514.084,"size":2674,"meta":{"path":"CONTRIBUTING.md","title":"CONTRIBUTING","folder":"inbox","siblingOrder":9,"createdAt":1780346816513.5295,"updatedAt":1780346816514.084,"size":2674,"tags":[],"wikilinks":[],"hasAttachments":false,"excerpt":"Contributing to the Homelab Wiki Voice Concise, technical, sysadmin-to-sysadmin. No marketing prose, no exclamation marks. Page templates Container page ( ) Cross-cutting page ( ) Plan ( ) Investigation ( ) Linking disci"}},{"path":"HERMES.md","mtimeMs":1780354337315.819,"size":3101,"meta":{"path":"HERMES.md","title":"HERMES","folder":"inbox","siblingOrder":10,"createdAt":1780354337308.1587,"updatedAt":1780354337315.819,"size":3101,"tags":[],"wikilinks":[],"hasAttachments":false,"excerpt":"HERMES.md — Agent persona for homelab clients This file is the canonical agent persona for all AI agents running on machines in the hubris homelab. It prescribes behaviour, token-efficiency conventions, and the source-of"}},{"path":"README.md","mtimeMs":1780560778432.5747,"size":4930,"meta":{"path":"README.md","title":"README","folder":"inbox","siblingOrder":11,"createdAt":1780560778426.7786,"updatedAt":1780560778432.5747,"size":4930,"tags":[],"wikilinks":[],"hasAttachments":true,"excerpt":"Homelab Wiki — Living documentation for the hubris Proxmox homelab. Every node, every cross-cutting system, and every meaningful incident is its own page; pages are linked so you can start anywhere and walk the graph. La"}},{"path":"containers/101-jellyfin.md","mtimeMs":1780345724703.8516,"size":1501,"meta":{"path":"containers/101-jellyfin.md","title":"101-jellyfin","folder":"inbox","siblingOrder":0,"createdAt":1780345724703.7935,"updatedAt":1780345724703.8516,"size":1501,"tags":[],"wikilinks":[],"hasAttachments":true,"excerpt":"101 — Media server: serves the movies / TV / anime / music / audiobooks / podcasts libraries from to LAN clients. At a glance - Hostname: - IP: - Privilege: unprivileged + idmap (so it can write to the group on ) - Resou"}},{"path":"containers/102-nfs-export.md","mtimeMs":1780345724703.9788,"size":6678,"meta":{"path":"containers/102-nfs-export.md","title":"102-nfs-export","folder":"inbox","siblingOrder":1,"createdAt":1780345724703.8984,"updatedAt":1780345724703.9788,"size":6678,"tags":[],"wikilinks":[],"hasAttachments":true,"excerpt":"102 — Dedicated, single-purpose LXC that re-exports over NFSv4 to clients that can't use the host's PVE virtiofs path — currently only 100-zimaos, which ships a kernel without virtiofs support. At a glance - Hostname: - "}},{"path":"containers/103-paperless.md","mtimeMs":1780560805423.0337,"size":1924,"meta":{"path":"containers/103-paperless.md","title":"103-paperless","folder":"inbox","siblingOrder":2,"createdAt":1780560805416.4663,"updatedAt":1780560805423.0337,"size":1924,"tags":[],"wikilinks":[],"hasAttachments":true,"excerpt":"103 — Paperless-ngx for document management. Ingests scans / PDFs from and serves OCR'd indexed copies. At a glance - Hostname: - IP: - Privilege: privileged - Resources: 2 cores / 3 GiB RAM / 8 GiB rootfs - Mounts: ↔ (c"}},{"path":"containers/104-gitea.md","mtimeMs":1780345724704.2058,"size":3905,"meta":{"path":"containers/104-gitea.md","title":"104-gitea","folder":"inbox","siblingOrder":3,"createdAt":1780345724704.1404,"updatedAt":1780345724704.2058,"size":3905,"tags":[],"wikilinks":[],"hasAttachments":true,"excerpt":"104 — Self-hosted git server. Source of truth for all repositories that auto-deploy across the lab. At a glance - Hostname: - IP: - Privilege: privileged - Resources: 1 core / 1 GiB RAM / 8 GiB rootfs - Mounts: ↔ (under "}},{"path":"containers/105-apps.md","mtimeMs":1780352727930.0833,"size":10839,"meta":{"path":"containers/105-apps.md","title":"105-apps","folder":"inbox","siblingOrder":4,"createdAt":1780352727923.2222,"updatedAt":1780352727930.0833,"size":10839,"tags":[],"wikilinks":[],"hasAttachments":true,"excerpt":"105 — Docker host for everything that doesn't justify its own LXC. Currently runs Artifacto, Booklore, PlantUML server, Portainer (and historically WriteFreely / blog), plus the homelab-context distribution services (MCP"}},{"path":"containers/106-auth-outpost.md","mtimeMs":1780782336629.5935,"size":5011,"meta":{"path":"containers/106-auth-outpost.md","title":"106-auth-outpost","folder":"inbox","siblingOrder":5,"createdAt":1780782336621.4434,"updatedAt":1780782336629.5935,"size":5011,"tags":[],"wikilinks":[],"hasAttachments":true,"excerpt":"106 — Authentik forward-auth outpost for LAN-gated apps. A stateless proxy that connects outbound to the VPS Authentik core and serves forward-auth locally, so Caddy (121) never hairpins auth through VPS Traefik. At a gl"}},{"path":"containers/107-dns.md","mtimeMs":1780779036582.4163,"size":5515,"meta":{"path":"containers/107-dns.md","title":"107-dns","folder":"inbox","siblingOrder":6,"createdAt":1780779036572.9216,"updatedAt":1780779036582.4163,"size":5515,"tags":[],"wikilinks":[],"hasAttachments":true,"excerpt":"107 — Homelab DNS server (Technitium). Replaces the dnsmasq that lived on 124 — authentik; single-purpose, one job. At a glance - Hostname: - IP: (static — stable, decoupled from any app) - Privilege: privileged (Docker-"}},{"path":"containers/114-nextcloud.md","mtimeMs":1780345724704.6995,"size":8636,"meta":{"path":"containers/114-nextcloud.md","title":"114-nextcloud","folder":"inbox","siblingOrder":7,"createdAt":1780345724704.615,"updatedAt":1780345724704.6995,"size":8636,"tags":[],"wikilinks":[],"hasAttachments":true,"excerpt":"114 — Personal cloud / file collaboration. Source-of-truth for the photo libraries surfaced by mulita (120). At a glance - Hostname: - IP: - Privilege: privileged - Resources: 4 cores / 6 GiB RAM / 25 GiB rootfs - Mounts"}},{"path":"containers/118-elementsynapse.md","mtimeMs":1780778973248.468,"size":6368,"meta":{"path":"containers/118-elementsynapse.md","title":"118-elementsynapse","folder":"inbox","siblingOrder":8,"createdAt":1780778973241.1172,"updatedAt":1780778973248.468,"size":6368,"tags":[],"wikilinks":[],"hasAttachments":true,"excerpt":"118 — Matrix homeserver (Synapse). Backs . At a glance - Hostname: - IP: - Privilege: unprivileged - Resources: 1 core / 2 GiB RAM / 16 GiB rootfs (grown from 8 GiB on 2026-05-15 after disk-full incident) - Mounts: none "}},{"path":"containers/119-sophia.md","mtimeMs":1780345724704.9253,"size":752,"meta":{"path":"containers/119-sophia.md","title":"119-sophia","folder":"inbox","siblingOrder":9,"createdAt":1780345724704.8606,"updatedAt":1780345724704.9253,"size":752,"tags":[],"wikilinks":[],"hasAttachments":true,"excerpt":"119 — Single-container workload \"sophia\". Reads/writes under . At a glance - Hostname: - IP: - Privilege: privileged - Resources: 2 cores / 1 GiB RAM / 10 GiB rootfs - Mounts: ↔ - Public hostname: none Permissions LXC ha"}},{"path":"containers/120-mule-images.md","mtimeMs":1780345724705.116,"size":40719,"meta":{"path":"containers/120-mule-images.md","title":"120-mule-images","folder":"inbox","siblingOrder":10,"createdAt":1780345724704.9697,"updatedAt":1780345724705.116,"size":40719,"tags":[],"wikilinks":[],"hasAttachments":true,"excerpt":"120 — Hosts — the photos app at . PhotoPrism + Go sidecar + SvelteKit, replacing the legacy FastAPI/Celery stack as of 2026-05-22 (see Changelog). Auto-deploys from on . At a glance - Hostname: - IP: - Privilege: privile"}},{"path":"containers/121-caddy.md","mtimeMs":1781344617107.1443,"size":7222,"meta":{"path":"containers/121-caddy.md","title":"121-caddy","folder":"inbox","siblingOrder":11,"createdAt":1781344617100.2546,"updatedAt":1781344617107.1443,"size":7222,"tags":[],"wikilinks":[],"hasAttachments":true,"excerpt":"121 — The reverse proxy. Terminates TLS for every hostname on the LAN/mesh and forwards to the right backend. At a glance - Hostname: - IP: - Privilege: unprivileged - Resources: 1 core / 512 MiB RAM / 6 GiB rootfs - Mou"}},{"path":"containers/122-arriman.md","mtimeMs":1781344598212.5852,"size":10156,"meta":{"path":"containers/122-arriman.md","title":"122-arriman","folder":"inbox","siblingOrder":12,"createdAt":1781344598204.7722,"updatedAt":1781344598212.5852,"size":10156,"tags":[],"wikilinks":[],"hasAttachments":true,"excerpt":"122 — Docker host running the \\arr stack via compose. Replaced the old yunohost-based LXC 100 on 2026-04-21. At a glance - Hostname: - IP: - Privilege: privileged - Resources: 4 cores / 8 GiB RAM / 24 GiB rootfs - Mounts"}},{"path":"containers/123-claudio-bot.md","mtimeMs":1780560778655.496,"size":4318,"meta":{"path":"containers/123-claudio-bot.md","title":"123-claudio-bot","folder":"inbox","siblingOrder":13,"createdAt":1780560778648.8645,"updatedAt":1780560778655.496,"size":4318,"tags":[],"wikilinks":[],"hasAttachments":true,"excerpt":"123 — (DEPRECATED — destroyed 2026-06-04) This LXC was destroyed on 2026-06-04. Replaced by Hermes Agent on mac-mini. Monitoring migrated to skill + 15-min Hermes cronjob. Repos and archived (read-only) on Gitea. See dep"}},{"path":"containers/126-plato.md","mtimeMs":1780345724705.7505,"size":5515,"meta":{"path":"containers/126-plato.md","title":"126-plato","folder":"inbox","siblingOrder":14,"createdAt":1780345724705.6843,"updatedAt":1780345724705.7505,"size":5515,"tags":[],"wikilinks":[],"hasAttachments":true,"excerpt":"126 — Docker host for Plato — a cross-linked notes workspace (SvelteKit SPA embedded into a Go HTTP server, SQLite-backed). LAN+mesh only, no public ingress. At a glance - Hostname: - IP: - Privilege: privileged - Resour"}},{"path":"containers/127-mule-photos-new.md","mtimeMs":1780345724705.8857,"size":15220,"meta":{"path":"containers/127-mule-photos-new.md","title":"127-mule-photos-new","folder":"inbox","siblingOrder":15,"createdAt":1780345724705.7952,"updatedAt":1780345724705.8857,"size":15220,"tags":[],"wikilinks":[],"hasAttachments":true,"excerpt":"127 — Side-by-side PhotoPrism M0 test of the branch at . Production LXC 120 keeps running on the legacy stack at until M5 cutover. At a glance - Hostname: - IP: - Privilege: unpriv - Resources: 6 cores / 8 GiB RAM / 40 G"}},{"path":"containers/index.md","mtimeMs":1780560778862.5242,"size":5300,"meta":{"path":"containers/index.md","title":"index","folder":"inbox","siblingOrder":16,"createdAt":1780560778855.459,"updatedAt":1780560778862.5242,"size":5300,"tags":[],"wikilinks":[],"hasAttachments":true,"excerpt":"LXC containers — index All containers live on . Each row links to the per-container page. | ID | Name | IP | Priv | Cores | RAM | Disk | Mounts | Public hostname | Status | | --- | ---------------- | --------------- | --"}},{"path":"hosts/hubris.md","mtimeMs":1780430511541.5146,"size":14052,"meta":{"path":"hosts/hubris.md","title":"hubris","folder":"inbox","siblingOrder":10,"createdAt":1780430511541.3574,"updatedAt":1780430511541.5146,"size":14052,"tags":[],"wikilinks":[],"hasAttachments":true,"excerpt":"— Proxmox host Single-node Proxmox VE running 1 VM and 13 LXC containers. The whole homelab. At a glance - Role: Proxmox VE 9.1.2 hypervisor (kernel ) - Hardware: GMKtec NucBox M6 Ultra — AMD Ryzen 5 7640HS (Phoenix APU)"}},{"path":"infrastructure/auto-deploy.md","mtimeMs":1780607505150.4668,"size":12356,"meta":{"path":"infrastructure/auto-deploy.md","title":"auto-deploy","folder":"inbox","siblingOrder":0,"createdAt":1780607505144.4097,"updatedAt":1780607505150.4668,"size":12356,"tags":[],"wikilinks":[],"hasAttachments":true,"excerpt":"Auto-deploy — gitea-webhook pipelines Several configs and apps in the lab live in repos on gitea (104) and auto-redeploy on push. All pipelines follow one of two shapes. Two shapes Shape A — checkout IS the working tree "}},{"path":"infrastructure/backups.md","mtimeMs":1780560830473.088,"size":7139,"meta":{"path":"infrastructure/backups.md","title":"backups","folder":"inbox","siblingOrder":1,"createdAt":1780560830466.1775,"updatedAt":1780560830473.088,"size":7139,"tags":[],"wikilinks":[],"hasAttachments":true,"excerpt":"Backups — restic on external drive (DISABLED) Chunked monthly restic backup of 's irreplaceable subset. Disabled 2026-04-22 as part of the hubris crash-loop A/B test. Status DISABLED 2026-04-22. All four timers 'd: - - -"}},{"path":"infrastructure/dns.md","mtimeMs":1781736008617.1628,"size":13044,"meta":{"path":"infrastructure/dns.md","title":"dns","folder":"inbox","siblingOrder":2,"createdAt":1781736008610.1042,"updatedAt":1781736008617.1628,"size":13044,"tags":[],"wikilinks":[],"hasAttachments":true,"excerpt":"DNS — split-horizon LAN clients resolve to the Caddy reverse proxy ( ). Public clients resolve to the IONOS VPS ( ) via an IONOS wildcard, where they hit the VPS traefik public ingress. There is no wildcard on the LAN si","isSymlink":false}},{"path":"infrastructure/homelab-context.md","mtimeMs":1780560830894.8496,"size":8047,"meta":{"path":"infrastructure/homelab-context.md","title":"homelab-context","folder":"inbox","siblingOrder":3,"createdAt":1780560830888.2087,"updatedAt":1780560830894.8496,"size":8047,"tags":[],"wikilinks":[],"hasAttachments":true,"excerpt":"Homelab context distribution The cross-client context-and-secrets system that makes every agent (Claude Code, Hermes Agent, future MCP-capable clients) on every machine in the lab self-locating and able to read the same "}},{"path":"infrastructure/ingress.md","mtimeMs":1780607419863.8228,"size":7418,"meta":{"path":"infrastructure/ingress.md","title":"ingress","folder":"inbox","siblingOrder":4,"createdAt":1780607419858.2424,"updatedAt":1780607419863.8228,"size":7418,"tags":[],"wikilinks":[],"hasAttachments":true,"excerpt":"Public ingress — VPS traefik + cert mirror How home services reach the open internet without exposing the home network. Two-stage pattern: traefik on the IONOS VPS terminates TLS at the public edge, then reverse-proxies "}},{"path":"infrastructure/media-permissions.md","mtimeMs":1780345724709.1672,"size":7283,"meta":{"path":"infrastructure/media-permissions.md","title":"media-permissions","folder":"inbox","siblingOrder":5,"createdAt":1780345724709.099,"updatedAt":1780345724709.1672,"size":7283,"tags":[],"wikilinks":[],"hasAttachments":true,"excerpt":"Media permissions — GID 10000 Standard for any LXC reading/writing on hubris. Applied 2026-04-20. Standard Every LXC that mounts participates in a shared group with GID 10000. Shared subtrees are owned by that group with"}},{"path":"infrastructure/mesh.md","mtimeMs":1780345724709.2966,"size":16161,"meta":{"path":"infrastructure/mesh.md","title":"mesh","folder":"inbox","siblingOrder":6,"createdAt":1780345724709.2087,"updatedAt":1780345724709.2966,"size":16161,"tags":[],"wikilinks":[],"hasAttachments":true,"excerpt":"Mesh — Tailscale → Netbird migration The hubris fleet is migrating from Tailscale to Netbird. Netbird is the target end-state. In-progress as of 2026-04-21. Current state - PVE host uses Netbird ( , ). Its resolver is th"}},{"path":"infrastructure/monitoring.md","mtimeMs":1780560749315.5925,"size":2427,"meta":{"path":"infrastructure/monitoring.md","title":"monitoring","folder":"inbox","siblingOrder":7,"createdAt":1780560749307.7988,"updatedAt":1780560749315.5925,"size":2427,"tags":[],"wikilinks":[],"hasAttachments":true,"excerpt":"Monitoring — Hermes health watchdog Homelab health monitoring via Hermes Agent on mac-mini. Replaced the legacy + IPC pipeline on 2026-06-04. Current approach Two layers: 1. On-demand: ask Hermes \"how's the homelab?\" or "}},{"path":"infrastructure/network.md","mtimeMs":1781735999883.6902,"size":4996,"meta":{"path":"infrastructure/network.md","title":"network","folder":"inbox","siblingOrder":8,"createdAt":1781735999876.1707,"updatedAt":1781735999883.6902,"size":4996,"tags":[],"wikilinks":[],"hasAttachments":true,"excerpt":"Network Physical and logical network topology for the homelab. Why The homelab runs on a dedicated internal subnet ( ) isolated from the main household LAN ( ). Isolation is enforced at Proxmox: LXC/VM traffic is bridged","isSymlink":false}},{"path":"infrastructure/ssh-access.md","mtimeMs":1780560830582.1829,"size":6692,"meta":{"path":"infrastructure/ssh-access.md","title":"ssh-access","folder":"inbox","siblingOrder":9,"createdAt":1780560830574.8628,"updatedAt":1780560830582.1829,"size":6692,"tags":[],"wikilinks":[],"hasAttachments":true,"excerpt":"SSH access How to reach every host in the fleet from any workstation, with LAN as the primary path and Netbird as the automatic backup. Architecture SSH access relies on three layers: 1. Homelab inventory ( ) — the singl"}},{"path":"infrastructure/vps-hardening.md","mtimeMs":1780345724709.625,"size":6246,"meta":{"path":"infrastructure/vps-hardening.md","title":"vps-hardening","folder":"inbox","siblingOrder":10,"createdAt":1780345724709.56,"updatedAt":1780345724709.625,"size":6246,"tags":[],"wikilinks":[],"hasAttachments":true,"excerpt":"VPS hardening — / IONOS VPS that runs the Netbird control plane and the public ingress traefik. Hardened 2026-04-23 from its stock-Plesk state. At a glance - Hostname: - OS: Debian 13 - Mesh: netbird (peer of the lab mes"}},{"path":"investigations/2026-04-21-hubris-crash-loop.md","mtimeMs":1780345724709.907,"size":9313,"meta":{"path":"investigations/2026-04-21-hubris-crash-loop.md","title":"2026-04-21-hubris-crash-loop","folder":"inbox","siblingOrder":0,"createdAt":1780345724709.8374,"updatedAt":1780345724709.907,"size":9313,"tags":[],"wikilinks":[],"hasAttachments":true,"excerpt":"2026-04-21 — Hubris crash loop (thermal + USB drive) Summary hard-locked repeatedly on 2026-04-21 (silent CPU hangs, no panic, no OOM, no MCE). Two contributors identified: idle CPU sitting at 95 °C on the governor, and "}},{"path":"investigations/2026-05-31-authentik-vps-migration.md","mtimeMs":1780682878779.1663,"size":10574,"meta":{"path":"investigations/2026-05-31-authentik-vps-migration.md","title":"2026-05-31-authentik-vps-migration","folder":"inbox","siblingOrder":1,"createdAt":1780682878770.9727,"updatedAt":1780682878779.1663,"size":10574,"tags":[],"wikilinks":[],"hasAttachments":true,"excerpt":"2026-05-31 — Authentik migrated from LXC 124 to the VPS Summary The NetBird management server (on the VPS) crash-looped 1200+ times because it fetches the Authentik OIDC discovery document on startup, and Authentik was o"}},{"path":"investigations/2026-06-01-mac-mini-onboarding.md","mtimeMs":1780352998861.152,"size":10453,"meta":{"path":"investigations/2026-06-01-mac-mini-onboarding.md","title":"2026-06-01-mac-mini-onboarding","folder":"inbox","siblingOrder":2,"createdAt":1780352998852.268,"updatedAt":1780352998861.152,"size":10453,"tags":[],"wikilinks":[],"hasAttachments":false,"excerpt":"mac-mini onboarding — post-mortem & lessons learned Onboarded the workstation (macOS Sequoia, arm64) into the hubris homelab context system with the profile. What follows is a chronological recap of every hitch, the fix,"}},{"path":"investigations/2026-06-03-moonlight-sunshine-wifi-jitter.md","mtimeMs":1780603450911.2507,"size":4835,"meta":{"path":"investigations/2026-06-03-moonlight-sunshine-wifi-jitter.md","title":"2026-06-03-moonlight-sunshine-wifi-jitter","folder":"inbox","siblingOrder":3,"createdAt":1780603450904.6553,"updatedAt":1780603450911.2507,"size":4835,"tags":[],"wikilinks":[],"hasAttachments":true,"excerpt":"2026-06-03 — Moonlight/Sunshine game streaming unstable over WiFi Summary runs Sunshine as the game-streaming server; runs Moonlight as the client. Despite both machines being on the same physical subnet (192.168.178.0/2"}},{"path":"investigations/2026-06-06-authentik-session-lifetime.md","mtimeMs":1780782295099.0022,"size":5395,"meta":{"path":"investigations/2026-06-06-authentik-session-lifetime.md","title":"2026-06-06-authentik-session-lifetime","folder":"inbox","siblingOrder":4,"createdAt":1780782295097.0544,"updatedAt":1780782295099.0022,"size":5395,"tags":[],"wikilinks":[],"hasAttachments":true,"excerpt":"2026-06-06 — Frequent Authentik login prompts fixed (session duration) Summary User needed to re-authenticate to Authentik several times per day. Root cause was the Django session being configured as a session cookie (cl"}},{"path":"investigations/2026-06-06-caddyfile-truncation.md","mtimeMs":1780779049721.1035,"size":3404,"meta":{"path":"investigations/2026-06-06-caddyfile-truncation.md","title":"2026-06-06-caddyfile-truncation","folder":"inbox","siblingOrder":5,"createdAt":1780779049719.0457,"updatedAt":1780779049721.1035,"size":3404,"tags":[],"wikilinks":[],"hasAttachments":true,"excerpt":"Investigation: Caddyfile truncation — all LAN services down (2026-06-06) Date: 2026-06-06 Status: resolved Duration: 10 hours (from last known good state 12:39 UTC to restoration 22:40 UTC) Symptom All URLs except and re"}},{"path":"investigations/index.md","mtimeMs":1780782305966.2124,"size":1462,"meta":{"path":"investigations/index.md","title":"index","folder":"inbox","siblingOrder":6,"createdAt":1780782305957.9714,"updatedAt":1780782305966.2124,"size":1462,"tags":[],"wikilinks":[],"hasAttachments":true,"excerpt":"Investigations Time-stamped incident reports and experiments. One entry per incident; the entry is the canonical source. Per-node changelog entries link back here. Index | Date | Title | Status | | ------------ | -------"}},{"path":"operations/agent-enrollment.md","mtimeMs":1780352899324.4644,"size":20327,"meta":{"path":"operations/agent-enrollment.md","title":"agent-enrollment","folder":"inbox","siblingOrder":0,"createdAt":1780352899317.3433,"updatedAt":1780352899324.4644,"size":20327,"tags":[],"wikilinks":[],"hasAttachments":true,"excerpt":"Agent enrollment — bootstrap a client into the homelab context system This walks through enrolling a new machine (workstation, LXC, or VM) so it joins the cross-client context system: a clone of this repo that auto-syncs"}},{"path":"operations/commands.md","mtimeMs":1780748225789.4978,"size":4717,"meta":{"path":"operations/commands.md","title":"commands","folder":"inbox","siblingOrder":1,"createdAt":1780748225782.4604,"updatedAt":1780748225789.4978,"size":4717,"tags":[],"wikilinks":[],"hasAttachments":true,"excerpt":"Operations cheatsheet Run from the hubris host as root. When working from on Linux you're already on hubris — don't / . Proxmox CLI | Command | Use | | --- | --- | | / | List LXC containers / VMs | | / | Container / VM c"}},{"path":"operations/hermes-agent.md","mtimeMs":1780353006683.7876,"size":9974,"meta":{"path":"operations/hermes-agent.md","title":"hermes-agent","folder":"inbox","siblingOrder":2,"createdAt":1780353006675.6958,"updatedAt":1780353006683.7876,"size":9974,"tags":[],"wikilinks":[],"hasAttachments":true,"excerpt":"Hermes agent — Nous-Hermes-powered Goose sessions on a homelab client Onboards Nous Research's Hermes (a fine-tuned Llama variant) as a working terminal agent on a homelab client. Builds on top of standard client enrollm"}},{"path":"operations/runbook-dpkg-interrupted.md","mtimeMs":1780345724711.7874,"size":4106,"meta":{"path":"operations/runbook-dpkg-interrupted.md","title":"runbook-dpkg-interrupted","folder":"inbox","siblingOrder":3,"createdAt":1780345724711.7278,"updatedAt":1780345724711.7874,"size":4106,"tags":[],"wikilinks":[],"hasAttachments":true,"excerpt":"Runbook — recover from dpkg-interrupted state You're here because an apt run got killed mid-transaction and the target now has packages that are unpacked but not configured. Symptoms: - refuses to do anything new: `Error"}},{"path":"plans/2026-06-01-slate-ax-to-sodola-migration.md","mtimeMs":1780428851172.3645,"size":5150,"meta":{"path":"plans/2026-06-01-slate-ax-to-sodola-migration.md","title":"2026-06-01-slate-ax-to-sodola-migration","folder":"inbox","siblingOrder":0,"createdAt":1780428851172.1816,"updatedAt":1780428851172.3645,"size":5150,"tags":[],"wikilinks":[],"hasAttachments":true,"excerpt":"2026-06-01 — Slate AX → SODOLA Migration Status: Done — 2026-06-02 Hardware: SODOLA 5-Port 2.5Gbit Managed Switch replacing GL.iNet Slate AX Router: Fritz!Box 7590 Goal Remove the Slate AX sub-router. It adds double-NAT,"}},{"path":"plans/2026-06-04_130000-deprecate-claudio-bot.md","mtimeMs":1780560132354.6191,"size":16425,"meta":{"path":"plans/2026-06-04_130000-deprecate-claudio-bot.md","title":"2026-06-04_130000-deprecate-claudio-bot","folder":"inbox","siblingOrder":1,"createdAt":1780560132346.9568,"updatedAt":1780560132354.6191,"size":16425,"tags":[],"wikilinks":[],"hasAttachments":false,"excerpt":"Deprecate claudio-bot (LXC 123) — Hermes Agent now serves as control plane Goal Phase out the claudio-bot ecosystem (LXC 123, claudio-monitor, IPC server) now that Hermes Agent is configured and running on mac-mini. Herm"}},{"path":"plans/index.md","mtimeMs":1780428855320.4988,"size":839,"meta":{"path":"plans/index.md","title":"index","folder":"inbox","siblingOrder":2,"createdAt":1780428855320.358,"updatedAt":1780428855320.4988,"size":839,"tags":[],"wikilinks":[],"hasAttachments":true,"excerpt":"Plans Pre-flight runbooks for planned changes that haven't happened yet. Once executed, move the outcome to (if anything interesting happened) or just a changelog entry on the affected node pages. Index | Date | Title | "}},{"path":"secrets/README.md","mtimeMs":1780345724713.5586,"size":2088,"meta":{"path":"secrets/README.md","title":"README","folder":"inbox","siblingOrder":0,"createdAt":1780345724713.4932,"updatedAt":1780345724713.5586,"size":2088,"tags":[],"wikilinks":[],"hasAttachments":false,"excerpt":"secrets/ SOPS-encrypted YAML files. The plaintext lives only in transit and in the operator's head — committed files are always ciphertext. Conventions - One file per logical grouping (e.g. , , ). - Recipients are declar"}},{"path":"vms/100-zimaos.md","mtimeMs":1780520488274.1562,"size":11160,"meta":{"path":"vms/100-zimaos.md","title":"100-zimaos","folder":"inbox","siblingOrder":0,"createdAt":1780520488267.3223,"updatedAt":1780520488274.1562,"size":11160,"tags":[],"wikilinks":[],"hasAttachments":true,"excerpt":"100 — ZimaOS (IceWhale / CasaOS-family NAS distro), installed as a Proxmox VM to evaluate it as a potential primary NAS frontend in front of — alongside the existing fleet (nextcloud (114), jellyfin (101), mule-images (1"}},{"path":"vms/108-haos.md","mtimeMs":1780345724714.3467,"size":2017,"meta":{"path":"vms/108-haos.md","title":"108-haos","folder":"inbox","siblingOrder":1,"createdAt":1780345724714.2927,"updatedAt":1780345724714.3467,"size":2017,"tags":[],"wikilinks":[],"hasAttachments":true,"excerpt":"108 — Home Assistant OS — the only VM on hubris (HAOS doesn't run cleanly in an LXC, hence the qm tenant). At a glance - Type: QEMU VM - HAOS version: 16.3 (last verified) - IP: - Resources: 4 GiB RAM, 32 GiB boot disk -"}}]} diff --git a/knowledge/wiki/containers/105-apps.md b/knowledge/wiki/containers/105-apps.md index f67ed94..209e872 100644 --- a/knowledge/wiki/containers/105-apps.md +++ b/knowledge/wiki/containers/105-apps.md @@ -45,7 +45,16 @@ Receiver at `/opt/artifacto-deploy/` (outside the app repo): `deploy.sh` + `webh ### Portainer Native OAuth2 (Settings → Authentication → OAuth → Custom). Manual endpoints (no OIDC discovery). Uses `portainer-uid` custom-claim scope from Authentik. Container is **not** compose-managed — safe to `docker run` recreate; data lives in named volume `portainer_data`. CLI flag: `--trusted-origins docker.hubris.network` (hostname only — `IsTrustedOrigin` rejects strings containing `://`). -### homelab-mcp (`/opt/homelab-mcp/`) +### homelab-mcp (`/opt/homelab-mcp/`) — DEPRECATED (Go rewrite, Phase 6) + +> **Status:** This Python MCP server is being replaced by the Go `oikos api` binary +> running in Docker on mac-mini. Cutover pending — see +> [scripts/cutover-checklist.md](../../scripts/cutover-checklist.md) for the +> execution plan. The Go MCP uses the official MCP Go SDK (Streamable HTTP, not +> FastMCP) with 15 tools including `get_blast_radius`, `request_execution`, and +> `get_agent_activity`. Source: `internal/mcp/server.go`. + +**Current (Python) implementation — DO NOT MODIFY, awaiting cutover:** FastMCP server (Python venv at `/opt/homelab-mcp/.venv`). Reads from `/opt/homelab-context/` (this LXC is itself an enrolled [homelab-context](../infrastructure/homelab-context.md) client). Source @@ -70,7 +79,10 @@ the server code). Listens on `0.0.0.0:9811`, secret in `dtoro/Homelab-Docs`. Deploy script reinstalls the service unit and restarts on push. -### secrets-issuance (`/opt/secrets-issuance/`) +### secrets-issuance (`/opt/secrets-issuance/`) — DEPRECATED (Go Phase 5) + +> **Status:** Replaced by `internal/secrets/` in the Go rewrite. Machine identities +> are now managed via Infisical (`docker compose --profile infisical up`). Tiny HTTP service that issues per-client age keypairs the first time each client calls `/issue`. Idempotent: subsequent calls return the same key. Mesh+LAN source-IP gated via the `MESH_SUBNETS` env in diff --git a/knowledge/wiki/infrastructure/auto-deploy.md b/knowledge/wiki/infrastructure/auto-deploy.md index 00220e7..81331c8 100644 --- a/knowledge/wiki/infrastructure/auto-deploy.md +++ b/knowledge/wiki/infrastructure/auto-deploy.md @@ -41,8 +41,8 @@ The app repo at `/opt/` is the working tree, but the deploy tooling (`web | ~~`dtoro/Plato`~~ | ~~[plato (126)](../containers/index.md#recently-destroyed-kept-for-archaeology) `/opt/plato/app/`~~ (destroyed 2026-06-28) | ⊘ | `http://192.168.8.190:9799/deploy` (dead) | 8 (removed) | Repo archived — LXC destroyed | | `dtoro/claudio-bot` | ~~[claudio-bot (123)](../containers/archive/123-claudio-bot.md)~~ (destroyed 2026-06-04) | ⊘ | `http://192.168.8.230:9797/deploy` (dead) | (archived) | Repo archived — LXC destroyed | | `dtoro/backup-library` | [hubris host](../hosts/hubris.md) `/opt/backup-library/` | A | `http://192.168.8.77:9798/deploy` | (orig) | runs `deploy.sh` (preserves admin-edited `/etc/restic/include-*.list`) | -| `dtoro/Homelab-Docs` → homelab-mcp | [apps (105)](../containers/105-apps.md) `/opt/homelab-mcp/` | B | `http://192.168.8.205:9811/deploy` | 10 | reinstalls `homelab-mcp.service` + restart | -| `dtoro/Homelab-Docs` → secrets-issuance | [apps (105)](../containers/105-apps.md) `/opt/secrets-issuance/` | B | `http://192.168.8.205:9821/deploy` | 11 | reinstalls `secrets-issuance.service` + restart | +| `dtoro/Homelab-Docs` → homelab-mcp | [apps (105)](../containers/105-apps.md) `/opt/homelab-mcp/` | B | `http://192.168.8.205:9811/deploy` | 10 (deprecated) | ~~reinstalls `homelab-mcp.service` + restart~~ → replaced by Go Docker stack on mac-mini | +| `dtoro/Homelab-Docs` → secrets-issuance | [apps (105)](../containers/105-apps.md) `/opt/secrets-issuance/` | B | `http://192.168.8.205:9821/deploy` | 11 (deprecated) | ~~reinstalls `secrets-issuance.service` + restart~~ → replaced by `internal/secrets/` Go package | | `dtoro/terminalito` | [trmnl (128)](../containers/128-trmnl.md) `/opt/terminalito/` | B | `http://192.168.8.211:9797/deploy` | 12 | reinstalls units + `systemctl restart trmnl-plugins` | | `dtoro/Homelab-Docs` → oikos-console | [apps (105)](../containers/105-apps.md) `/opt/oikos-console/` | B | `http://192.168.8.205:9831/deploy` | 14 | reinstalls `oikos-console.service` + restart — see [oikos/console/deploy/README.md](../../../oikos/console/deploy/README.md) | diff --git a/knowledge/wiki/infrastructure/index.md b/knowledge/wiki/infrastructure/index.md index f97ddf3..2db9af4 100644 --- a/knowledge/wiki/infrastructure/index.md +++ b/knowledge/wiki/infrastructure/index.md @@ -56,7 +56,7 @@ are documented in their own pages. Each system below links to its full doc. - **[Topology diagram (generated)](topology.md)** — Mermaid graph of compute, ingress routing, and storage mounts. Auto-generated from `inventory.yaml` - by `oikos/gen-topology.py`. + by `oikos/gen-topology.py` (Python — Go DB-native replacement planned). ## Related