docs: public-facing README + generic configuration docs

Rewrite the README for external users, neutralize example identities in
code comments, generalize the OIDC group note, and simplify the gitleaks
workflow header.
This commit is contained in:
Sulkta 2026-06-28 13:25:25 -07:00
parent b746eacb3e
commit 8a410b0c3c
12 changed files with 118 additions and 58 deletions

119
README.md
View file

@ -1,35 +1,90 @@
# cauldron
# Cauldron
Mealie-backed meal planner + shopping-list aggregator. Wraps a Mealie
instance with: an ingredient sterilizer (free-form quantities → structured
parses), a weekly meal-plan generator, and a household shopping list that
collapses cross-recipe duplicates.
Cauldron is a self-hosted companion app for [Mealie](https://mealie.io) that
adds AI-assisted meal planning and a smart, household-shared shopping list.
Mealie stays the source of truth for your recipes, plans and shopping lists;
Cauldron layers extra automation on top and stores only per-user preferences
and cached metadata.
## Features
- **Ingredient sterilizer** — turns free-form quantities ("about 2 cups",
"a couple handfuls") into structured `{qty, unit, food}` parses and writes
them back to Mealie, so downstream tooling has clean data to work with.
- **Weekly meal-plan generator** — builds a per-week plan from your recipe
library, honouring pinned picks, dietary targets (calories / macros) and
allergen exclusions.
- **Household shopping list** — aggregates ingredients across every recipe in
a plan and collapses duplicates into single lines (e.g. "2 cups rice +
1.25 lb rice" → "~2 lb rice") using a USDA-derived food-density table.
- **Recipe discovery, dedupe and enrichment** — scrape-and-import new recipes,
cluster and merge duplicates, and enrich recipes with structured metadata
for smarter planning.
- **Multi-user, OIDC-secured** — every user connects their own Mealie token
(encrypted at rest); an optional operator tier exposes the destructive admin
tools.
## Stack
- Flask + gunicorn, Python 3.12
- Authentik (or any OIDC provider) for sessions
- MariaDB for per-user prefs + Fernet-encrypted Mealie tokens
- [clawdforge](https://github.com/Sulkta-Coop/clawdforge) for the AI layer
- Flask + gunicorn (Python 3.12+)
- Any OpenID Connect provider for authentication (tested with Authentik)
- MariaDB for per-user preferences and Fernet-encrypted Mealie tokens
- An LLM runner reachable over HTTP for the AI features. This project targets
[clawdforge](https://github.com/Sulkta-Coop/clawdforge), but any service
exposing the same `POST /run` contract works.
Mealie remains the source of truth for recipes / plans / shopping lists.
Cauldron stores per-user prefs + cached metadata only.
## Quick start
## Run
Cauldron ships as a container and is configured entirely through environment
variables.
```bash
cp .env.example .env # fill in secrets
cp .env.example .env # then fill in the blanks (see Configuration)
docker compose up -d --build
curl http://localhost:7790/healthz
```
`CAULDRON_ENV_FILE=/path/to/secrets.env docker compose up -d` if your env
file lives outside the repo.
If you prefer to keep your secrets file outside the repo:
```bash
CAULDRON_ENV_FILE=/path/to/cauldron.env docker compose up -d
```
### Requirements
- A running Mealie instance and an API token.
- An OIDC provider with a client configured for Cauldron's redirect URI.
- A MariaDB database and user.
- An LLM HTTP runner for the AI features (sterilize / plan / discover /
enrich). Without it the app still runs; AI-backed endpoints return an error.
## Configuration
All settings are read from the environment. See `.env.example` for the full,
documented list. The most important variables:
| Variable | Purpose |
| --- | --- |
| `SECRET_KEY` | Flask session signing key |
| `BIND_HOST` / `BIND_PORT` | Listen address (defaults `0.0.0.0:7790`) |
| `MEALIE_BASE_URL` | Base URL of your Mealie instance |
| `MEALIE_API_TOKEN` | System Mealie token for admin batch operations |
| `CLAWDFORGE_URL` / `CLAWDFORGE_TOKEN` | LLM runner endpoint + auth |
| `OIDC_ISSUER` / `OIDC_CLIENT_ID` / `OIDC_CLIENT_SECRET` / `OIDC_REDIRECT_URI` | OpenID Connect login |
| `DB_HOST` / `DB_PORT` / `DB_NAME` / `DB_USER` / `DB_PASSWORD` | MariaDB connection |
| `CAULDRON_FERNET_KEY` | Key used to encrypt per-user Mealie tokens at rest |
| `ADMIN_BEARER` | Bearer token for the batch (`/api/...`) endpoints |
| `CAULDRON_ADMIN_SUBS` | OIDC subjects granted the operator-tier admin tools |
| `CAULDRON_BASE_URL` / `CAULDRON_BEHIND_TLS` / `CAULDRON_TRUSTED_PROXIES` | Public-deploy hardening (CSRF origin guard, HSTS, secure cookies, trusted-proxy `X-Forwarded-*` handling) |
When deployed behind a reverse proxy, set `CAULDRON_BASE_URL`,
`CAULDRON_BEHIND_TLS=true` and list the proxy peer in
`CAULDRON_TRUSTED_PROXIES` so forwarded headers are honoured safely.
## Endpoints
```
GET /healthz liveness + clawdforge upstream
GET /healthz liveness + LLM-runner upstream check
GET /login /auth/callback OIDC flow
GET /me account + integration status
GET /plan /list household plan + shopping list
@ -40,21 +95,37 @@ POST /api/sterilize/apply/<slug> (admin bearer) write parses back
Admin-bearer endpoints expect `Authorization: Bearer $ADMIN_BEARER`.
## Layout
## Project layout
```
cauldron/
config.py env-driven config
forge.py clawdforge HTTP client
config.py env-driven configuration
forge.py LLM-runner HTTP client
mealie.py Mealie API client
sterilizer.py ingredient parse + apply pipeline
aggregator.py cross-recipe shopping aggregator
server.py Flask app
aggregator.py cross-recipe shopping-list aggregator
foods.py USDA-seeded food catalogue + density lookup
recipe_index.py local fuzzy recipe search index
server.py Flask app + routes
data/ seed data (USDA SR Legacy foods)
scripts/
build_foods_seed.py USDA → foods seed
clean_foods_seed.py clawdforge-curated cleanup pass
build_foods_seed.py build the foods seed from a USDA dataset
clean_foods_seed.py LLM-curated cleanup pass over the seed
tests/ unit tests
```
## Development
```bash
pip install -r requirements.txt
python -m pytest # run the test suite
```
## Contributing
Issues and pull requests are welcome. Please keep changes focused, add tests
for new behaviour, and make sure `pytest` passes before opening a PR.
## License
MIT.
MIT — see [LICENSE](LICENSE).