oll.am · Deploy runbook · oll-scout · 2026-07-11

oll-scout — deploy runbook.

Coolify app · env matrix · the deploy gate. Everything needed to stand oll-scout up as its own Coolify app against its own private Neon DB — keyless-dev on the left, recommended-prod on the right.
Thin Core client Own Neon DB · ADR-008 Own Coolify app PR #94 · 59 tests green

1What it is — a thin Core-client service

oll-scout is an agentic job scout that ships as its own product service — zero auth / Stripe / email code of its own; it calls Core over HTTP for identity, billing, and the digest send. Source = PR #94 (feat/oll-scout-agentic, services/oll-scout).

PropertyValue
KindThin Core-client product service — discovers, ranks, drafts; never auto-applies (no submit tool, by construction)
Own databaseA private Neon oll_scout DB — per ADR-008 (database-per-service); it never touches another service's DB
Deploy unitIts own Coolify app in the monorepo, via Base Directory services/oll-scout + Watch Paths
Talks to CoreOver HTTP on the shared ollam network — identity (AUTH_PROVIDER=core), billing (M3 subscription), email (digest send)
Talks to ModelThe llm_cited scorer calls the oll-model gateway at https://model.oll.am for cited-rationale scoring
SourcePR #94feat/oll-scout-agentic · services/oll-scout

Boots keyless

The service is designed to boot with zero secrets (fixture provider · heuristic scorer · mock email · SQLite) so CI and a first Coolify deploy come up green before any real provider is wired. You then swap the dev defaults for the prod values in the env matrix below — one column at a time.

2The deploy gate — do this first

Deploy only a CI-green commit. This session closed the gap where oll-scout ran no CI at all — its checks are now wired into services.yml.

PR #94 CI now runs oll-scout wired this session

  • lint + test — ruff + the full 59-test suite (was: not in the matrix at all).
  • pip-audit — dependency vulnerability scan.
  • keyless docker boot + health — builds the image, boots with zero secrets, and asserts GET /api/scout/health is 200.

Deploy is a deliberate act — never an auto-merge

Per the trunk-based branch model, a merge to main never deploys. Deployment is a chosen act: tag a CI-green commit (git tag vX.Y.Z && git push origin vX.Y.Z) OR dispatch deploy-all.yml. Coolify's own git-auto-deploy stays OFF on the backend apps — the tag/webhook is the only path to prod. Full model: the CI/CD environments doc.

3Coolify app config — one app, its own base dir

oll-scout is one Coolify app in the shared monorepo. The four fields that isolate it:

FieldValue
Base Directoryservices/oll-scout
DockerfileIts own services/oll-scout/Dockerfile12-factor $PORT + a container HEALTHCHECK hitting /api/scout/health
Watch Pathsservices/oll-scout/** — so only a change to this service redeploys it, nothing else in the monorepo
NetworkShared ollam network, alias oll-scout — reaches Core/Model by Docker DNS, no public hop needed for internal calls
Auto-deployOFF (frozen model) — deploy only via tag / deploy-all.yml

4Env matrix — dev keyless → prod

The core of the runbook. Left column boots keyless for CI + a first deploy; right column is the recommended production wiring. Swap one row at a time and re-verify health after each.

VarKeyless-devRecommended-prod
SCOUT_PROVIDER fixture jooble for real CH coverage (needs a free JOOBLE_API_KEY) · OR arbeitnow (keyless DACH floor, no CH postings) · OR jsonld (needs JSONLD_BOARD_URL = an employer career page emitting schema.org JobPosting — never jobs.ch, per spec)
SCOUT_SCORER heuristic llm_cited — the agentic cited-rationale scorer (per-requirement evidence quotes + honest abstention)
OLL_MODEL_BASE_URL
OLL_MODEL_SERVICE_TOKEN
(heuristic needs no model) https://model.oll.am + the service token — required by llm_cited
SCOUT_MODEL_NAME (8b default) llama-3.3-70b-versatile — strongly recommended. Verified this session: 4/7 scored vs 1/7 on the 8b default, richer per-requirement evidence quotes, and it correctly surfaced the best-fit role at 90
AUTH_PROVIDER dev local ONLY core + CORE_BASE_URL=https://core.oll.am — real multi-user identity off the Core JWT
EMAIL_PROVIDER mock core (+ CORE_SERVICE_JWT) OR resend (+ RESEND_API_KEY) — for the digest send
SCOUT_DB_PATH → Neon DSN SQLite path (dev) A private Neon oll_scout DSN (ADR-008, database-per-service)
RADAR_PLAN_GATE
RADAR_STRIPE_PRICE_ID
(open in dev) M3 paid gate: true + a Core Stripe subscription price (CHF 19/mo)
Scheduler (run scout_cron.py by hand) A Coolify/system cron on scout_cron.py --all · OR SCOUT_SCHEDULER_ENABLED=true for the in-process thread
CORS_ORIGINS · PORT defaults Set CORS_ORIGINS to the front door origin; PORT per Coolify (12-factor)

The one non-obvious guardrail

SCOUT_PROVIDER=jsonld reads an employer career page (Abraxas, Swisscom, Bedag …) that already publishes schema.org JobPosting for Google for Jobs — it is not a jobs.ch reader. Per the spec's legal stance, jobs.ch is manual-paste only and must never be hit programmatically; the adapter has no jobs.ch default (fixed this session).

5Sam-gated checklist — only you can do these

Everything else is code + Coolify fields. These four need an account, a key, or a console click that only you can make.

1

Get the free JOOBLE_API_KEY for CH coverage — or pick an employer JSON-LD career page for JSONLD_BOARD_URL (never jobs.ch).

2

Create the private Neon oll_scout DB (a new database on the existing Neon project) and paste its DSN.

3

Set the oll-model service token (OLL_MODEL_SERVICE_TOKEN) + the 70b model (SCOUT_MODEL_NAME=llama-3.3-70b-versatile) so llm_cited runs live.

4

(M3) Create the Stripe Radar price (CHF 19/mo subscription) and set RADAR_STRIPE_PRICE_ID + RADAR_PLAN_GATE=true.

6Deploy steps — numbered

Once the gate is green, this is the walk from empty Coolify app to a first sent digest.

  1. Create the Coolify app — new app in the oll.am project, pointed at the monorepo repo/branch.
  2. Set Base Directory + Watch Paths — Base Directory services/oll-scout, Dockerfile services/oll-scout/Dockerfile, Watch Paths services/oll-scout/**, attach the ollam network with alias oll-scout, auto-deploy OFF.
  3. Set env — min first — the keyless-dev column boots green. Then swap in the real providers one row at a time (jooble/jsonld → llm_cited + model token + 70b → core auth → Neon DSN → email).
  4. Deploy — via a tag on a CI-green commit or deploy-all.yml dispatch (never auto-merge).
  5. Verify healthGET /api/scout/health returns 200.
  6. Wire the daily cron — a Coolify/system cron running scout_cron.py --all (or flip SCOUT_SCHEDULER_ENABLED=true).
  7. Send a first digest — run one scored pass and confirm the tiered digest email lands (real provider + llm_cited + email provider all live).
# health check after deploy
curl -s https://scout.oll.am/api/scout/health
# → {"status":"ok"}  ← gate passed, service is up

# first scored run (all sources) once env is wired
python scout_cron.py --all
Companion docs: the overnight result + the four decisions are the job-scout morning brief; the full architecture (seams, cited-rationale matching, no submit tool ever) is the job-scout spec of record; the deploy model behind step 4 is the CI/CD environments doc. Code: PR #94.