dtoro 1c12d40712
Some checks failed
ci / build-test (push) Has been cancelled
ci / docker-build (push) Has been cancelled
ci / web (push) Has been cancelled
Desktop App / Build Linux (amd64) (push) Has been cancelled
Desktop App / Attach to Release (push) Has been cancelled
feat(web): adopt shadcn context-menu for mascot + desktop right-click menus
Problem: the mascot's right-click menu was non-interactive — RadialMenu's
root div rendered inside MascotLayer's pointer-events-none root (and the
new DockedLayer wrapper compounded it) without re-enabling pointer-events,
so clicks passed straight through. The desktop right-click menu was a
hand-rolled positioned div, inconsistent with the rest of the UI.

Change: both menus now use the shadcn-svelte context-menu primitive
(bits-ui, portaled to <body>).
- Mascot: MascotMenu.svelte renders the action tree recursively —
  children become ContextMenu.Sub (native hover sub-menu navigation,
  replacing the manual breadcrumb stack), leaves become ContextMenu.Item
  with onSelect. MascotLayer wraps <Mascot> in a ContextMenu.Trigger;
  visibility predicates read reactively off ctx.model so items
  appear/disappear live. Removed the manual menuPos/openMenu/closeMenu
  machinery. RadialMenu.svelte deleted.
- Desktop: the surface's bare-desktop hit area is now a
  ContextMenu.Trigger layer (absolute inset-0, pointer-events-auto)
  placed before the icons/windows in the DOM. The DOM-structure gate
  (icons/windows are pointer-events-auto siblings that paint on top and
  intercept their own right-clicks; bare desktop falls through to the
  trigger) replaces the old fragile e.currentTarget === e.target check.
  Left-click blur moved onto the trigger; Undo/Redo disabled state
  snapshotted via onOpenChange (canUndo/canRedo are wmkit methods).

Risk: the blocker that made the mascot menu non-interactive in the first
place — Mascot.svelte's handleContextMenu called e.stopPropagation(),
which would have prevented a ContextMenu.Trigger wrapper from ever
seeing the right-click. Removed that handler; bits-ui now owns
right-click on the mascot, left-click drag/pet passes through. The
context-menu content portals to <body>, escaping the pointer-events-none
mascot and docked layers entirely — the structural fix, not just a
component swap.

Verification: vitest 38/38; svelte-check + tsc clean for changed files;
eslint clean (the shadcn-generated ui/context-menu/* files carry the
same baseline custom_element_props_identifier warnings as the rest of
the ui/ folder, not from this change); vite build green; runtime
confirmed — right-click mascot opens the action tree with hover
sub-menus, right-click bare desktop opens Cascade/Tile/Show/Reset/
Undo/Redo, right-click on an icon or window does not.
2026-07-21 16:03:57 +02:00

Oikos

Agentic homelab operating system written in Go. Single binary (cmd/oikos), Docker-deployed on mac-mini, with a standalone Nomos MCP agent gateway (cmd/nomos). Manages the hubris Proxmox homelab autonomously — observes state, classifies actions against policy, executes approved procedures over SSH, learns from outcomes, and escalates when uncertain.

For agents running on enrolled clients: start with AGENTS.md. For client machines: see CLIENTS.md. For developers: see CONTRIBUTING.md.

Quick start

# Dev stack (postgres + api + scheduler + notifier). The api/nomos
# services need a shared token — every route requires a real bearer
# credential, there's no dev-open bypass.
OIKOS_MCP_BEARER_TOKEN=dev-token docker compose --profile dev up -d

# Full stack (adds Nomos agent gateway)
OIKOS_MCP_BEARER_TOKEN=dev-token docker compose --profile full up -d

# Build standalone binary
go build -o bin/oikos -tags timetzdata ./cmd/oikos

# Run all roles in one process (dev mode)
OIKOS_DATABASE_URL="postgres://oikos:oikos_dev@localhost:5432/oikos?sslmode=disable" \
  OIKOS_API_TOKEN=dev-token \
  go run ./cmd/oikos all

# Control-room SPA (separate from the Go binary — see web/)
cd web && OIKOS_API_TOKEN=dev-token npm run dev   # http://localhost:5173

Architecture

                  ┌──────────────────────────────────┐
                  │         mac-mini (Docker)         │
                  │                                   │
  Workstation ─── │  nomos (8092) ──MCP── api (8090) │
  (mesh)          │    MCP gateway      REST + MCP    │
                  │                                   │
                  │  scheduler ── notifier ── postgres │
                  │  (observe)    (Matrix)   (Timescale)│
                  └──────────────────────────────────┘
Component Port Role
oikos api 8090 REST API + MCP server (tool list in AGENTS.md §3)
oikos scheduler Probe runner, signal lifecycle, metrics
oikos notifier Approval tokens, Matrix alerts
nomos serve 8092 MCP client gateway, query routing

Phases

Phase Status Description
1 — Ontology + DB TimescaleDB, migrations, seeds, blast_radius
2 — API OpenAPI-first REST + MCP, auth, SSE, audit
3 — Control loop Scheduler, actuator, learning, classifier, notifier
4 — Nomos agent Standalone MCP client gateway, agent activity
5 — Secrets Infisical backend + SOPS fallback, rotation runbooks
6 — Deploy CI pipeline, cutover checklist, watchdog, rollback

Full plan: plans/done/2026-07-06-consolidate-oikos-control-plane-onto-mac-mini.md.

Operations

API endpoints

curl -H "Authorization: Bearer $OIKOS_API_TOKEN" \
  http://localhost:8090/api/v1/entities?type=service  # fleet
curl -H "Authorization: Bearer $OIKOS_API_TOKEN" \
  http://localhost:8090/api/v1/health                  # fleet health
curl -H "Authorization: Bearer $OIKOS_API_TOKEN" \
  http://localhost:8090/api/v1/agent-activity          # agent log

Nomos queries

# Structured tool call
curl -X POST localhost:8092/query -H "Content-Type: application/json" \
  -d '{"tool":"get_blast_radius","args":{"entity_id":"service:authentik"}}'

# Natural language
curl -X POST localhost:8092/query -H "Content-Type: application/json" \
  -d '{"query":"what depends on authentik?"}'

CLI

oikos migrate     # apply DB migrations
oikos seed        # ingest ontology/inventory/policy seeds
oikos export      # export DB state to YAML
oikos api         # serve REST + MCP
oikos scheduler   # run observe loop
oikos notifier    # run notification loop
oikos all         # all roles in one process
oikos secret list # enumerate SOPS secrets
oikos secret migrate  # SOPS → Infisical

Web UI

web/ is a standalone Svelte 5 SPA — not embedded in the oikos binary, not part of docker-compose.yml. It talks to api/nomos over HTTP with a bearer token entered on first launch (see web/src/pages/Config.svelte). Build with make ui, deploy with make deploy-ui (Caddy serves the static output). A native desktop wrapper exists at cmd/desktop/ — see plans/done/2026-07-12-wails-desktop-app.md.

Repo layout

cmd/oikos/          Go entry point — single binary
cmd/nomos/          Nomos MCP client gateway
cmd/webhook/        Gitea deploy-webhook receiver (push-to-deploy on mac-mini)
cmd/desktop/        Wails desktop wrapper around the SPA
internal/           Go packages (actuator, checkdefaults, config, db, domain,
                    httpapi, knowledge, learning, mcp, notifier, observability,
                    ontology, policy, safego, scheduler, secrets)
web/                Control-room SPA (Svelte 5) — standalone, not embedded
api/openapi.yaml    API contract (OpenAPI 3.1)
migrations/         Forward-only SQL migrations (TimescaleDB)
seeds/              Bootstrap YAML (ontology, inventory, policy, knowledge)
compose/            Dockerfiles + Caddy config
scripts/            Deploy, watchdog, verification, rollback
checks/             Host health-check scripts run over SSH by the scheduler
tools/              Client auto-setup scripts (checks)
ssh/                Deploy keys + authorized_keys management
vps/                Caddy/TURN config templates for the netbird VPS
nomos/              Nomos config, persona, skills
.agents/            Agent instruction files, shared conventions, skills
archive/            Historical reference (legacy wiki, plans, SOPS backups)
plans/              Design documents (active + done)
docs/adr/           Architecture decision records
docs/operations/    Runbooks (rollback, etc.)

For agents

See AGENTS.md for the full orientation. Quick reference:

  • Source of truth: DB (runtime) then seeds (bootstrap). Old wiki is archived at archive/knowledge/ — use MCP search_knowledge instead.
  • Mutations: classify against policy, request approval for destructive/config_mutation
  • Secrets: Infisical (primary) or SOPS (fallback) — never hardcode
Description
Agentic OS for running a Homelab
Readme 37 MiB
Languages
Go 53.1%
Svelte 25.7%
TypeScript 14%
Shell 3.8%
Python 1.7%
Other 1.5%