# phase-1.md — Scaffold, config, store, health, CI, Dockerfile Re-ground: skim `CLAUDE.md`, `docs/adr/` (esp. 0002 placement, 0008 SQLite, 0010 security), and `progress.md`. Plan, get my approval, then implement. ## Objective A buildable, testable, containerized skeleton with the persistence layer and a health endpoint — no Ollama logic yet. ## Tasks - Initialize the module: `gitea.stevedudenhoeffer.com/steve/foreman`, Go 1.26. - Layout per CLAUDE.md: `cmd/foreman/main.go` (single binary, subcommand skeleton: `serve`, plus stubs for `submit`, `jobs`, `ps`), `internal/config`, `internal/store`, `internal/server`. Don't create empty packages for later phases. - `internal/config`: load from env into a struct — `FOREMAN_ADDR` (listen addr, default `:8080`), `FOREMAN_OLLAMA_URL` (target, required), `FOREMAN_OLLAMA_TOKEN` (optional outbound bearer to the target, for Ollama-Cloud-style auth), `FOREMAN_TOKEN` (optional inbound bearer foreman requires of its callers), `FOREMAN_EMBED_MODEL` (the always-resident embedder, e.g. `nomic-embed-text`), `FOREMAN_DB_PATH`, `FOREMAN_POLL_INTERVAL`. Namespace **every** key under `FOREMAN_` (do not use bare `OLLAMA_*`, which collide with real Ollama client vars). Provide a `.env.example` documenting every key. - `internal/store`: SQLite via `modernc.org/sqlite`, WAL mode, with an embedded migration for the `jobs` and `artifacts` tables (schema sketch in ADR-0008 / ADR-0006). Include open/close, migrate-on-start, and basic CRUD with tests (use a temp-file DB per test). - `internal/server`: `net/http` server with `GET /healthz` (returns ok + a placeholder degraded flag for later) and optional bearer-token middleware (validate `Authorization: Bearer` only when `FOREMAN_TOKEN` is set). - `.gitea/workflows/ci.yaml` — mirror `go-llm`'s, single-module: ```yaml name: CI on: push: { branches: ["*"] } pull_request: { branches: ["*"] } jobs: build: name: Build & Test runs-on: ubuntu-latest steps: - uses: actions/checkout@v4 - uses: actions/setup-go@v5 with: { go-version: "1.26" } - run: go mod download - run: go build ./... - run: go vet ./... - run: go test -race -count=1 ./... tidy: name: Tidy runs-on: ubuntu-latest steps: - uses: actions/checkout@v4 - uses: actions/setup-go@v5 with: { go-version: "1.26" } - run: | go mod tidy git diff --exit-code go.mod go.sum ``` - `Dockerfile` — multi-stage, pure-Go static build (works because modernc is CGO-free): ```dockerfile FROM golang:1.26 AS build WORKDIR /src COPY go.mod go.sum ./ RUN go mod download COPY . . RUN CGO_ENABLED=0 go build -o /out/foreman ./cmd/foreman FROM gcr.io/distroless/static-debian12 COPY --from=build /out/foreman /foreman EXPOSE 8080 ENTRYPOINT ["/foreman", "serve"] ``` - `.gitignore` (use the project's), `README.md` (what + quickstart), and seed `progress.md` with the M0 entry. ## Definition of done - `go build/vet/test -race` all green; `store` has passing tests. - `docker build .` succeeds; running the image serves `GET /healthz`. - `cmd/foreman serve` boots, reads config from env, opens/migrates the DB. Wrap up: append to `progress.md`, commit on `phase-1-scaffold`, summarize what's done and what Phase 2 will need.