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>
171 lines
6.2 KiB
Markdown
171 lines
6.2 KiB
Markdown
# Contributing to Oikos
|
|
|
|
Developer guide for the Oikos codebase. If you are a homelab client consuming
|
|
Oikos, see [CLIENTS.md](CLIENTS.md). If you are an AI agent working on the
|
|
repo, see [.agents/dev/CONTRIBUTING.md](.agents/dev/CONTRIBUTING.md).
|
|
|
|
## Dev setup
|
|
|
|
- **Go 1.26+** (see `go.mod` for pinned version)
|
|
- **PostgreSQL with TimescaleDB** — the compose stack includes `timescale/timescaledb:2.17.2-pg16`
|
|
- **Docker** for the full dev stack
|
|
- **Node 22+** for `web/` (the control-room SPA — standalone, not part of the
|
|
compose stack or the `oikos` binary)
|
|
|
|
```bash
|
|
# Start dependencies (Postgres + Redis). api/nomos require a shared bearer
|
|
# token — no dev-open bypass — so set one even for local dev.
|
|
OIKOS_MCP_BEARER_TOKEN=dev-token docker compose --profile dev up -d
|
|
|
|
# Run all tests
|
|
make test
|
|
|
|
# Run integration tests (needs compose Postgres)
|
|
make test-db
|
|
|
|
# Build the binary
|
|
make build
|
|
|
|
# SPA dev server (proxies to api/nomos, injecting the same token)
|
|
cd web && OIKOS_API_TOKEN=dev-token npm run dev
|
|
```
|
|
|
|
## Project structure
|
|
|
|
```
|
|
cmd/oikos/ Single-binary entry point
|
|
cmd/nomos/ Nomos MCP client gateway
|
|
cmd/webhook/ Gitea deploy-webhook receiver (push-to-deploy on mac-mini)
|
|
internal/ All Go packages
|
|
httpapi/ REST + MCP server (OpenAPI-generated)
|
|
mcp/ MCP tool implementations
|
|
db/ Connection pool, migrations, seeds, sqlc queries
|
|
scheduler/ Observe loop, probes, signals
|
|
actuator/ SSH execution
|
|
learning/ Pattern recognition, anomaly detection
|
|
notifier/ Matrix notifications, approval tokens
|
|
policy/ Risk classifier
|
|
secrets/ Infisical + SOPS backend
|
|
domain/ Core types: entities, approvals, signals, patterns
|
|
ontology/ Type hierarchy, relationship validation
|
|
knowledge/ Knowledge YAML seed ingestion
|
|
web/ Control-room SPA (Svelte 5) — standalone, not embedded
|
|
in the oikos binary; see plans/2026-07-12-wails-desktop-app.md
|
|
api/openapi.yaml API contract — the source of truth for endpoints
|
|
migrations/ Forward-only SQL migrations (TimescaleDB)
|
|
seeds/ Bootstrap YAML: ontology, inventory, policy, knowledge
|
|
compose/ Dockerfiles + Caddy config
|
|
scripts/ Deploy, watchdog, rollback
|
|
checks/ Host health-check scripts run over SSH by the scheduler
|
|
tools/ Client auto-setup scripts (checks)
|
|
nomos/ Nomos config, persona, skills
|
|
.agents/ Agent instruction files + skills
|
|
plans/ Design documents
|
|
docs/adr/ Architecture decision records
|
|
docs/operations/ Runbooks (rollback, etc.)
|
|
```
|
|
|
|
## Commands
|
|
|
|
| Command | Purpose |
|
|
|---------|---------|
|
|
| `make build` | Build `oikos` binary |
|
|
| `make test` | Run all tests with race detection |
|
|
| `make test-db` | Run integration tests against compose Postgres |
|
|
| `make lint` | `go vet` + `golangci-lint` |
|
|
| `make generate` | Regenerate OpenAPI + sqlc code |
|
|
| `make generate-check` | CI drift guard — fail if generated code is stale |
|
|
| `make migrate` | Apply DB migrations |
|
|
| `make seed` | Ingest seeds into DB |
|
|
| `make export` | Export DB state to YAML seeds |
|
|
| `make dev` | Start compose dev stack |
|
|
| `make clean` | Remove binary + test cache |
|
|
| `make ui` | Build the SPA (`web/dist/`) |
|
|
| `make deploy-ui` | Build + deploy the SPA to the Caddy host |
|
|
| `make webhook` | Build `cmd/webhook` (deploy-webhook receiver) |
|
|
| `make tidy` | `go mod tidy` |
|
|
|
|
## Conventions
|
|
|
|
### APIs are OpenAPI-first
|
|
|
|
The REST API is defined in `api/openapi.yaml`. Server code is generated with
|
|
`oapi-codegen` into `internal/httpapi/gen/`. To add an endpoint:
|
|
|
|
1. Add the path + schema to `api/openapi.yaml`
|
|
2. Run `make generate`
|
|
3. Implement the handler in `internal/httpapi/impl.go`
|
|
4. Add tests in `internal/httpapi/api_test.go`
|
|
|
|
Never hand-edit `internal/httpapi/gen/api.gen.go`.
|
|
|
|
### Database access is sqlc-first
|
|
|
|
SQL queries live in `internal/db/queries/*.sql`. Go code is generated with
|
|
`sqlc` into `internal/db/sqlcgen/`. Config in `sqlc.yaml`.
|
|
|
|
- Queries target pgx/v5 with UUID + timestamptz overrides
|
|
- Never hand-edit generated sqlc code
|
|
|
|
### Migrations are forward-only
|
|
|
|
SQL migrations live in `migrations/` as `NNN_name.up.sql`. There are no down
|
|
migrations (see [ADR 0008](docs/adr/0008-forward-only-migrations.md)).
|
|
Migrations are idempotent where possible (`IF NOT EXISTS`, `DO $$` blocks).
|
|
|
|
To add a migration:
|
|
|
|
1. Create `migrations/NNN_name.up.sql` with the next sequence number
|
|
2. Write the DDL
|
|
3. Run `make migrate` to apply
|
|
|
|
### Seeds are DB-generated
|
|
|
|
`seeds/*.yaml` are the bootstrap files used by `oikos seed`. After making
|
|
changes via the API, run `make export` to regenerate the seed files. These
|
|
files are version-controlled and serve as DR fallback.
|
|
|
|
### Writing style
|
|
|
|
Follow [.agents/shared/writing-style.md](.agents/shared/writing-style.md).
|
|
Documentation is reference prose, not marketing. Banned vocabulary includes
|
|
"robust", "seamless", "leverage", "utilize", "delve", "cutting-edge".
|
|
|
|
### Risk classification
|
|
|
|
Every mutation is classified against `seeds/policy.yaml` before execution.
|
|
Four risk classes: `read_only`, `reversible_low`, `config_mutation`,
|
|
`destructive`. The classifier can only lower autonomy relative to policy,
|
|
never raise it. When in doubt, escalate.
|
|
|
|
## CI
|
|
|
|
Gitea Actions runs on push to `main` and pull requests (`ci.yml`):
|
|
|
|
1. `go vet` + `golangci-lint` + `govulncheck`
|
|
2. Generated code drift check (`make generate-check`)
|
|
3. Build (`go build ./...`)
|
|
4. Test with race detector + coverage
|
|
5. Docker build verification (no push)
|
|
|
|
Coverage gates: policy + learning packages ≥ 80%, others ≥ 60%.
|
|
|
|
## PR workflow
|
|
|
|
1. Create a branch from `main`
|
|
2. Make changes, write tests
|
|
3. Run `make lint test generate-check`
|
|
4. Commit with a message following: problem → change → risk → verification
|
|
5. Push to Gitea; CI gates PRs on green
|
|
|
|
## Secrets
|
|
|
|
Secrets are managed by Infisical (primary) with SOPS as DR fallback. Never
|
|
hardcode secrets. Use environment variables from `.env` for local dev.
|
|
The `.env` and `.infisical-credentials` files are gitignored.
|
|
|
|
## Related
|
|
|
|
- [OIKOS.md](.agents/OIKOS.md) — operating model, OODA loop, ontology
|
|
- [CLIENTS.md](CLIENTS.md) — for homelab clients consuming Oikos
|
|
- [docs/adr/](docs/adr/) — architecture decision records |