# phase-5.md — Go client package + llm.Foreman() in go-llm Re-ground: `CLAUDE.md` + ADR-0011 (integration levels). Plan, get approval, implement. Note this phase touches **two repos**. ## Objective Make foreman ergonomic from Go: a synchronous client over the async surface (Level 1), and the trivial `go-llm` target constructor (Level 0). ## Tasks — foreman repo - `client/` (the one public package): a `foreman.Client` with a synchronous `Complete(ctx, req) (Result, error)` that submits to `POST /jobs` with a `state_webhook_url` pointed at an ephemeral receiver it stands up, blocks until `done`, and returns the result + artifacts. Requirements: - Fall back to polling `GET /jobs/{id}` if it can't bind/receive callbacks (configurable; needed when foreman can't reach the caller). - Respect `ctx` cancellation/deadline; clean up the receiver and (optionally) best-effort cancel the job. - Constructor takes base URL + optional token; verify HMAC if a secret is set. - Tests against a stubbed foreman (or the real handlers): happy path returns the artifact; polling-fallback path works; context timeout is honored. ## Tasks — go-llm repo (via gitea MCP; open a branch/PR, do not push to main) - Add the `Foreman` constructor to `v2/constructors.go`, delegating to the ollama provider (exact form is specified in ADR-0011). Update `v2/CLAUDE.md` with the DD#9 entry. Keep it a thin pass-through (Level 0); do **not** build a dedicated provider yet. - Confirm it compiles and `go vet`/tests pass in the `v2` module. ## Definition of done - foreman: `go build/vet/test -race` green; `client.Complete()` returns a real result against a running foreman. - go-llm: `llm.Foreman("http://:8080", token).Model("qwen3:30b")` completes a chat. Changes are on a branch/PR for review, not committed to main. Wrap up: `progress.md`, commit `client/` on `phase-5-client`; report the go-llm branch name and PR link for me to review/merge.