# 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 ```bash # Start dependencies (Postgres + Redis) 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 ``` ## Project structure ``` cmd/oikos/ Single-binary entry point cmd/hermes/ Hermes MCP client gateway 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 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 hermes/ Hermes config, persona, skills .agents/ Agent instruction files + skills plans/ Design documents docs/adr/ Architecture decision records ``` ## 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 | ## 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