Files
oikos/plans/2026-07-07-migrate-bin-homelab-to-go.md

4.4 KiB

Plan: Migrate bin/homelab CLI to Go oikos homelab

Status: Planned (2026-07-07)

Goal

Replace bin/homelab (265-line Python CLI) with the Go oikos homelab subcommand already in cmd/oikos/main.go. The Python CLI imports the now-deleted Python kernel modules (oikos.approve, oikos.decide, etc.) and reads from /opt/homelab-context/inventory.yaml — it's disconnected from the new DB-backed Go stack. Once the Go CLI matches the Python one, bin/homelab becomes ln -s "$(which oikos)" bin/homelab and the oikos binary resolves its role from os.Args[0].

Current state

Layer Python Go Gap
list inventory.yaml scan DB-backed list_entities done
whoami hostname → inventory lookup hostname() → DB query done
ssh resolve mesh IP → ssh same done
secret sops -d wrapper secret list/migrate/export-sops done (Infisical)

Subcommand migration plan

Phase 1 — Operational commands (P0, this week)

Core CLI ops every homelab operator uses daily.

Subcommand Risk Notes
pct low SSH to Proxmox host + pct exec/list. Currently proxies via SSH. Trivial Go wrapper.
logs low journalctl SSH wrapper. Reuse ssh path from existing Go code.
restart low systemctl restart SSH wrapper.
status medium Ping + HTTP health check of every host/service. Use DB entity data + scheduler health checks.
ssh-config low Generate ~/.ssh/config.d/homelab from DB hosts list. Output-only.
open low Open a service's URL via open (macOS) / xdg-open (Linux).

Phase 2 — Agentic layer (P1, next 2 weeks)

Oikos agentic commands that already have Go equivalents in internal/.

Subcommand Risk Notes
doctor low Health check enrollment: verify age key, homelab-context clone, mesh connectivity.
service medium Service Console: explain/health/docs/log/actions/history. DB-backed — get_entity_knowledge() + tail_log().
decide low Policy classification. Go: internal/policy/classify.go already exists.
approval low Approval requests. Go: internal/domain/approval.go exists.
signal medium Attention layer. Go: internal/domain/signal.go exists.
node low Ontology queries. Go: internal/ontology/ exists.
change medium Mutation workflow. Combine decide + approval + actuator execution log.

Phase 3 — Infrastructure management (P2, 2-4 weeks)

Subcommand Risk Notes
render-vps-configs medium Renders vps/*.tmpl with Infisical secrets. Needs template engine + SSH to VPS.
sync low Trigger homelab-context sync via launchd/systemd timer.
apt-audit low dpkg audit per host. SSH wrapper.
apt-upgrade medium apt update/upgrade in detached screen. Needs confirmation.

Phase 4 — Cleanup (P3, when ready)

Action Risk Notes
refresh-creds low Drop. Infisical handles secrets now.
nuke destructive Port or drop. Rarely used; destructive — keep as manual SSH.
client add/remove medium Client enrollment. Needs secrets-issuance replacement (manual age-keygen now).
mcp low MCP tool wrapper. Could call the Go MCP client library.
Remove bin/homelab high Replace with symlink oikosbin/homelab. The oikos binary checks os.Args[0] for the homelab role.
Remove bin/oikos low Stale pre-built arm64 binary. Delete.

Implementation approach

Each subcommand is a separate file in cmd/oikos/homelab/. The dispatcher in main.go's runHomelabSubcommand() routes os.Args to the right handler. All subcommands use internal/config for DB connection and share the SSH helper from the existing ssh subcommand.

SSH connectivity (for pct, logs, restart) reuses the mesh-address resolution from internal/domain/ — entity slug → inventory attributes → mesh IP → ssh user@ip.

Verification

  • oikos homelab without args prints subcommand list (matching Python parity)
  • Each P0 subcommand works end-to-end from mac-mini
  • bin/homelaboikos symlink; homelab list = oikos homelab list
  • bin/oikos removed

Changelog

  • 2026-07-07 — plan created. Cataloged 27 Python subcommands vs 4 Go subcommands.