Documentation and repo-hygiene pass following the client/server split:
Plan drift (audited all other active plans against current code):
- oikos-gaps-and-improvements.md: mark Section C and D.5 resolved (both
described cmd/hermes, renamed to cmd/nomos with a real LLM loop since);
refresh ~10 stale file:line citations; fix tool-count (33, not 28).
- liveness-drift-and-ux-cohesion.md: fix stale default-model claim (now
deepseek-v4-pro since 2026-07-10) and "not yet deployed" status.
- nomos-agent-code-review.md: fix C1's citation (one unauthenticated route
to nomos now, not two, after the client/server split).
- wails-desktop-app.md: record the production deploy outcome.
Repo structure: added missing directories to README/CONTRIBUTING layout
tables (checks/, tools/, cmd/webhook/, docs/operations/), fixed a broken
link, added ADR 0015 documenting the auth/CORS/client-split model (there
wasn't one despite CONTRIBUTING's own process requiring it), normalized
ADR 0013/0014's format drift, added an Authentication section to
AGENTS.md/CLIENTS.md (every example call was missing the now-required
bearer header).
Retired the Goose+Nomos workstation flow (bootstrap.sh --with-nomos,
tools/setup-nomos-soul.sh, .agents/operations/nomos-agent.md) and the
Caveman auto-install tooling (tools/setup-caveman.sh, tools/caveman/) —
both superseded by the production containerized Nomos agent, which has
never used either. Kept .agents/shared/caveman.md itself (the terse
writing-style convention agents still follow by reading it).
Deleted the orphaned legacy Python oikos/ directory — nothing imports it,
and bin/homelab (the CLI it was kept for) no longer exists in the repo.
Rewrote .agents/operations/agent-enrollment.md (365 -> ~110 lines) and
commands.md to match the current architecture instead of the retired
`homelab` CLI; migrated the still-true networking prerequisites (Netbird,
split-horizon DNS, SSH key distribution) into the knowledge base as a
runbook via upsert_knowledge rather than duplicating them in markdown.
Updated all 10 .agents/skills/ runbooks referencing the dead CLI with
their real MCP tool / REST API equivalents, or flagged them as needing
verification where no equivalent is confirmed yet.
Two real bugs found and fixed, not just docs:
- The tools/setup-*.sh auto-setup glob was tools/*.setup.sh in THREE
places (tools/post-pull.sh, bootstrap.sh, and internal/httpapi/impl.go's
GetClientContext handler) since the mechanism's introduction on
2026-06-02 — never matched any real filename, so no client has ever
picked up an auto-setup script via git-pull or the context-poller sync.
Fixed all three; the Go server-side fix is the one that actually matters
since it's what the current context-poller mechanism depends on.
- bootstrap.sh removed dead vestigial --gitea-token/--gitea-user flags
(parsed, never consumed) left over from an earlier clone-based model.
Also flagged, not fixed (documented as an open gap in
client-enrollment/SKILL.md): bootstrap.sh tells a freshly-enrolled client
to call POST /api/v1/clients/{slug}/activate to finish enrollment, but
that route doesn't exist in api/openapi.yaml — EnrollClient sets entities
to provisioning and nothing currently transitions them to active.
Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
151 lines
5.9 KiB
Markdown
151 lines
5.9 KiB
Markdown
# Oikos — client guide
|
|
|
|
If you are a homelab machine, this is what Oikos is and what it gives you.
|
|
If you are an AI agent running on this machine, also read [AGENTS.md](AGENTS.md).
|
|
|
|
## What is Oikos?
|
|
|
|
Oikos is the agentic operating system for the **hubris** Proxmox homelab. It
|
|
observes state, classifies actions against policy, executes approved
|
|
procedures, learns from outcomes, and notifies the operator. It runs as a
|
|
Docker stack on mac-mini and exposes an MCP server + REST API.
|
|
|
|
## What Oikos provides
|
|
|
|
| Capability | How you access it |
|
|
|------------|-------------------|
|
|
| Entity query (topology, blast radius) | MCP `get_entity`, `get_blast_radius` |
|
|
| Full-text knowledge search | MCP `search_knowledge` |
|
|
| Service status + logs | MCP `get_service_status`, `tail_log` |
|
|
| LXC inventory + state | MCP `list_lxcs`, `get_lxc_state` |
|
|
| Context cards | MCP `explain` |
|
|
| Pre-flight risk classification | MCP `preflight` |
|
|
| Change history | MCP `get_change_history` |
|
|
| State snapshot (health, disk, drift) | MCP `get_state_snapshot` |
|
|
| Secrets (Infisical) | REST API + `oikos secret` CLI |
|
|
| Approval tokens | Matrix via notifier |
|
|
| Run a command on a host/LXC (policy-gated) | MCP `run` |
|
|
| Record a discovered fact/relationship | MCP `update_entity_attributes`, `create_relationship`, `upsert_knowledge` |
|
|
|
|
Most MCP tools are read-only; a few mutate the knowledge graph (recording
|
|
what you learned) or the live infrastructure (`run`, `request_execution`),
|
|
gated by risk classification and — for `config_mutation`/`destructive`
|
|
actions — operator approval. See [AGENTS.md](AGENTS.md#3-the-mcp-server) for
|
|
the full tool catalog.
|
|
|
|
## Authentication
|
|
|
|
Every API/MCP call needs `Authorization: Bearer <token>` — there is no
|
|
unauthenticated path except `POST /api/v1/clients/enroll` and `/healthz`.
|
|
Enrollment (below) does not currently hand out a per-client bearer token;
|
|
get the shared `OIKOS_MCP_BEARER_TOKEN` from the operator until per-client
|
|
token issuance exists.
|
|
|
|
## Enrollment
|
|
|
|
Thin client model — no git clone, no sync timer. `bootstrap.sh` fetches only
|
|
the agent orientation files and tooling from the raw Gitea URL, then enrolls
|
|
via the Oikos API.
|
|
|
|
To enroll:
|
|
```bash
|
|
# Run from any machine with mesh connectivity
|
|
curl -fsSL https://git.hubris.network/dtoro/oikos/raw/main/bootstrap.sh | sudo bash
|
|
|
|
# Or with optional tooling:
|
|
curl ... | sudo bash -s -- --with-mcp # wire Claude's MCP config
|
|
```
|
|
|
|
This calls `POST /api/v1/clients/enroll` on the Oikos API, which:
|
|
1. Validates the entity exists in DB (planned or provisioning state)
|
|
2. Validates mesh IP against expected subnets
|
|
3. Generates an age keypair and delivers it to the client
|
|
4. Creates an Infisical machine identity
|
|
5. Transitions the entity to provisioning state
|
|
|
|
## After enrollment
|
|
|
|
### What changes on your machine
|
|
|
|
- `/opt/homelab/` — agent orientation files (CLIENTS.md, AGENTS.md, OIKOS.md)
|
|
- `/opt/homelab/tools/` — tooling scripts (checks)
|
|
- `/etc/age/key.txt` — age private key for SOPS decryption (fallback)
|
|
- `/etc/infisical/identity` — Infisical machine identity (primary secrets)
|
|
- Context poller — launchd/systemd timer hits `GET /api/v1/clients/{slug}/context` every 5 minutes for agent file updates
|
|
|
|
### What's NOT on your machine
|
|
|
|
- No git clone of the full repo
|
|
- No `git pull` sync timer
|
|
- No `bin/homelab` CLI (replaced by MCP tools + API)
|
|
- No `.sops.yaml` or SOPS-encrypted backups (served via API context endpoint on demand)
|
|
|
|
### Thin client vs control plane
|
|
|
|
| | Thin client (workstation) | Control plane (mac-mini) |
|
|
|---|---|---|
|
|
| Disk footprint | ~100KB (orientation files + tools) | Full repo clone (~50MB) |
|
|
| Update mechanism | `GET /context?since=` poll | Git pull + post-pull.sh |
|
|
| Source of truth | DB via MCP | DB + local seeds + archive |
|
|
| Secrets access | Infisical (primary), age/SOPS served via API (fallback) | Infisical + local SOPS files |
|
|
|
|
### Your identity
|
|
|
|
Your identity in the homelab is defined in `inventory.yaml`. Run `hostname`
|
|
(Linux) or `scutil --get LocalHostName` (macOS), then look up your entry.
|
|
It tells you your role, what services you host, what's mounted, and your
|
|
mesh address.
|
|
|
|
### Source of truth hierarchy
|
|
|
|
1. **Postgres database** (runtime) — authoritative for entities, knowledge,
|
|
signals, ledger. Query via MCP or REST API.
|
|
2. **Context poller** — agent files and tooling fetched via API deltas every
|
|
5 minutes.
|
|
3. **Never guess.** If data is missing, query MCP. If MCP is down, grep the
|
|
local `/opt/homelab/` files.
|
|
|
|
## The context poller
|
|
|
|
Every 5 minutes, launchd (macOS) or systemd (Linux) hits:
|
|
|
|
```
|
|
GET /api/v1/clients/ws:{hostname}/context?since={last_timestamp}
|
|
```
|
|
|
|
The API returns which agent files, tools, and SOPS config changed since the
|
|
last poll. Only changed files are downloaded. This replaces the old
|
|
`git pull` with a lightweight HTTP delta.
|
|
|
|
To trigger manually: run `/opt/homelab/tools/context-poller.sh`.
|
|
|
|
## Making changes
|
|
|
|
- **Read state**: use MCP tools or the API
|
|
- **Mutate state** (restart, edit config, deploy): classify the action against
|
|
policy (query `preflight` MCP tool):
|
|
- `read_only` / `reversible_low` — execute directly
|
|
- `config_mutation` / `destructive` — request operator approval via
|
|
`POST /api/v1/entities/{slug}/activate` (or equivalent lifecycle endpoint)
|
|
- **Secrets**: use Infisical (primary) or SOPS (fallback). Never hardcode.
|
|
- **Knowledge**: if you observe a discrepancy between docs and live state,
|
|
update the DB via the API in the same session.
|
|
|
|
## MCP endpoint
|
|
|
|
```
|
|
https://mcp.hubris.network/mcp
|
|
```
|
|
|
|
Available tools are listed in [AGENTS.md](AGENTS.md#3-the-mcp-server).
|
|
|
|
## Communication mode
|
|
|
|
Apply [.agents/shared/caveman.md](.agents/shared/caveman.md) — terse,
|
|
fragment-heavy communication. Drop filler, keep substance.
|
|
|
|
## Related
|
|
|
|
- [AGENTS.md](AGENTS.md) — full agent orientation (read this first)
|
|
- [OIKOS.md](.agents/OIKOS.md) — operating model, OODA loop, risk classes
|
|
- [CONTRIBUTING.md](CONTRIBUTING.md) — developer guide for the Oikos codebase |