Repo overview · mirrors README.md · updated 2026-07-03

oll.am — the platform, at a glance

An HTML rendering of the repo's README.md — the GitHub landing that greets anyone opening the tree: what the umbrella platform is, the picture of it, the service map, the repo conventions, the "dark factory" CI/CD, and how to run a service.

This page mirrors the repo's README.md. The Markdown file stays the canonical GitHub landing (GitHub needs the .md); this is the same content in the house style, wired into the site so it lives in the timeline and the artifact index. If the two ever drift, the README.md in the repo root wins.

What it is

The one-paragraph what-it-is, verbatim-faithful to the README.

oll.am is an umbrella platform for shipping small AI products on shared infrastructure. It is one monorepo with a frozen Core — auth, billing, and email, deployed and live at core.oll.am — plus a set of small product services that own only their product logic and call Core (and the oll-model gateway) over HTTP for everything else. Products carry zero auth / Stripe / email code, so Core can be built once, deployed once, and never touched again, while each product stays tiny and disposable.

Positioning: any AI model, pay once — no subscription.

The exit strategy is modular: each service is its own deploy unit, so you can sell one product or the whole platform.

Architecture in one picture

A frozen Core underneath; small product services on top; a frozen model gateway to the side — everything talks over HTTP.
Core Frozen core.oll.am
auth · billing · email — build once, deploy once, never touch
▲ HTTP · JWT / Stripe / Resend
foto
headshots via Replicate · guest checkout
write
writing-improvement (humaniz.me) · calls the gateway
more products…
each = product logic only, tiny + disposable
▼ HTTP · model call
oll-model gateway Frozen model.oll.am
one OpenAI-compatible surface in front of swappable providers · default provider: Groq

Service map

Each row is a directory that exists in this tree and deploys as its own Coolify app via its own Base Directory + Dockerfile + Watch Paths.
ServiceDirPurposeKey endpointsDeploy unit (Coolify)
Core frozen core/ Auth + billing + email spine. Magic-link passwordless auth (72h HS256 identity JWT), Stripe checkout/webhook/portal, transactional email. Owns its own Neon DB (oll_core). POST /api/auth/magic-link · POST /api/auth/verify · GET /api/auth/me · POST /api/auth/refresh · POST /api/billing/create-checkout-session · POST /api/billing/webhook · GET /api/billing/status · POST /api/billing/verify-session · POST /api/billing/portal · POST /api/email/send · GET /api/health{,/neon,/stripe} Base Directory /core, Watch Paths core/** → live at core.oll.am
oll-model frozen services/oll-model/ The oll-model gateway — an identity-free, OpenAI-compatible model-call relay. Default provider Groq (hosted Llama etc.); swap to claude or local ollama via LLM_PROVIDER. Adding a provider = one entry in llm_client._PROVIDERS. No database. POST /api/text/complete (requires X-Service-Token) · GET /api/text/health Base Directory /services/oll-model, Watch Paths services/**
write product services/write/ Writing-improvement product (the Core client behind humaniz.me). Honest clarity/rewrite tool only — never a detector-bypass. Delegates the model call to the gateway and billing/email to Core. POST /api/write/improve · GET /api/write/health Base Directory /services/write, Watch Paths services/**
foto product services/foto/ The headshot product (next-dollar ship). Guest checkout, no login: pay once, generate via Replicate, deliver by email — billing/email delegated to Core. POST /api/foto/checkout · GET /api/foto/fulfill · GET /api/foto/health Base Directory /services/foto, Watch Paths services/**
Run the tests for any service (same recipe everywhere):
# cd core — or services/oll-model · services/write · services/foto
cd core
pip install -r requirements.txt -r requirements-dev.txt
pytest

Repo conventions

Monorepo, one Dockerfile per service, database-per-service, HTTP-only integration.

Monorepo, one Dockerfile per service, independent deploys

One repo, unified version control. Each service folder has its own Dockerfile, requirements*.txt, openapi.yaml, tests/, and pyproject.toml. There is no shared Python package — services integrate only over HTTP, never by importing each other or touching another service's database (database-per-service on Neon; stateless services have none).

HTML is the interface

Live project status is not tracked in prose. The single source of truth is state/state.json, rendered by scripts/state.py into the Control Room at site/oll-am-status.html. site/ is the deployed build-in-public landing + docs (flat static HTML, served by the root Dockerfile → nginx). specs/ holds the API contract; CLAUDE.md carries the full living context.

CI/CD — the "dark factory" (merge ≠ deploy)

A change only runs the jobs it touches; deploy is a separate, deliberate act.
CI — GitHub Actions
path-filtered · a change only runs the jobs it touches
oll-core.ymlcore/** (pytest + contract + Schemathesis + DTO-drift)
services.ymlservices/** (matrix pytest: foto · write · oll-model)
site.ymlsite/** (design-conformance gate)
CD — Coolify on the Hetzner VPS
each service = a separate Coolify app keyed on its Base Directory + Watch Paths, so only the changed service redeploys.

Merging a PR does not deploy it — deploy is a separate Coolify action.
The full model — the stage integration line, the promotion ritual, the gate ladder, and the one-button dependency-ordered deploy — lives on The Factory.

Run a service locally

Same recipe in any service folder — install, test, boot.
cd services/foto            # any service folder
pip install -r requirements.txt -r requirements-dev.txt
pytest                      # run its test suite
python app.py               # or: flask --app app run — boots the Flask app

Product services expect Core reachable over HTTP (locally via the shared ollam Docker network → http://oll-core:5000, in production → https://core.oll.am); write additionally calls the gateway (OLL_MODEL_BASE_URL). For the full local stack, see docker-compose.local.yml and docker-compose.core.yml.

Where the live status lives

Status is HTML, not prose in a doc — three pointers.