# 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 `oikos` → `bin/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/homelab` → `oikos` symlink; `homelab list` = `oikos homelab list` - `bin/oikos` removed ## Changelog - 2026-07-07 — plan created. Cataloged 27 Python subcommands vs 4 Go subcommands.