Skip to main content

KptnCook

A small command line client for downloading KptnCook recipes, including today's picks, discovery screens and lists, dailies, onboarding tags, and ingredient-based searches. It can also sync to Mealie and export recipes to Paprika, Tandoor, or Markdown.

Thanks to this blogpost for the url to get the json for today's recipes.

It's in pre alpha status and currently slightly unmaintained. If you want to step in, please let me know.

Maintenance disclosure

This repository is maintained with substantial assistance from coding agents. Most routine implementation, investigation, documentation, triage, and release-preparation work may be performed through agent-assisted workflows. Changes are still reviewed and accepted by the maintainer, and human contributors are welcome.

Dependencies

  • Python >=3.10
  • Mealie >=v1.0

Installation

$ uvx install kptncook

Docker

Build the image from this repository:

$ docker build -t kptncook .

The container sets KPTNCOOK_HOME=/data. Mount that directory and provide the required environment variables. Passing configuration with -e is the recommended approach for Docker: it avoids the need for an interactive setup and works the same on every run. For Mealie auth, set MEALIE_API_TOKEN or MEALIE_USERNAME/MEALIE_PASSWORD:

$ docker run --rm -v ~/.kptncook:/data \
    -e KPTNCOOK_API_KEY=6q7QNKy-oIgk-IMuWisJ-jfN7s6 \
    -e MEALIE_URL=https://mealie.example.com/api \
    -e MEALIE_USERNAME=user \
    -e MEALIE_PASSWORD=pass \
    kptncook sync

Alternatively, set MEALIE_API_TOKEN=... instead of MEALIE_USERNAME and MEALIE_PASSWORD.

To back up favorites, also set KPTNCOOK_ACCESS_TOKEN:

$ docker run --rm -v ~/.kptncook:/data \
    -e KPTNCOOK_API_KEY=... \
    -e KPTNCOOK_ACCESS_TOKEN=... \
    -e MEALIE_URL=https://mealie.example.com/api \
    -e MEALIE_USERNAME=user \
    -e MEALIE_PASSWORD=pass \
    kptncook backup-favorites

The guided setup is available as the kptncook setup subcommand, so it is reachable through the container's kptncook entrypoint. Because it prompts for your KptnCook account credentials, run it with an interactive TTY (-it). The .env it writes lives at $KPTNCOOK_HOME/.env (i.e. /data/.env), so the mounted volume persists it across runs:

$ docker run --rm -it -v ~/.kptncook:/data kptncook setup

To fetch only the access token after the API key is already configured, use docker run --rm -it -v ~/.kptncook:/data kptncook kptncook-access-token.

Usage

help

Usage: kptncook [OPTIONS] COMMAND [ARGS]...

Options:
  --install-completion [bash|zsh|fish|powershell|pwsh]
                                  Install completion for the specified
                                  shell.
  --show-completion [bash|zsh|fish|powershell|pwsh]
                                  Show completion for the specified shell,
                                  to copy it or customize the installation.
  --help                          Show this message and exit.

Commands:
  backup-favorites          Store kptncook favorites in local repository.
  dailies                   List daily recipes from the kptncook site.
  delete-recipes            Delete recipes from the local repository.
  discovery-list            List recipes from a discovery list.
  discovery-screen          List discovery screen lists and quick search entries.
  ingredients-popular       List popular ingredients.
  kptncook-access-token     Fetch and save the KptnCook access token.
  kptncook-today            List all recipes for today from the kptncook...
  list-recipes              List all locally saved recipes.
  onboarding                List onboarding recipes by tags.
  recipes-with-ingredients  List recipes that match ingredient ids.
  save-todays-recipes       Save recipes for today from kptncook site.
  search-by-id              Search for a recipe by id in kptncook api, id...
  sync                      Fetch recipes for today from api, save them to...
  sync-with-mealie          Sync locally saved recipes with mealie.
  export-recipes-to-paprika  Export a recipe by id or all recipes to Paprika app
  export-recipes-to-tandoor  Export a recipe by id or all recipes to Tandoor
  export-recipes-to-markdown Export a recipe by id or all recipes to Markdown files

Quick examples

Short snippets for the new discovery/dailies/onboarding/ingredient commands (see the detailed sections below for flag descriptions):

$ kptncook discovery-screen
$ kptncook discovery-screen --no-quick-search
$ kptncook discovery-list --list-type latest
$ kptncook discovery-list --list-type recommended
$ kptncook discovery-list --list-type curated --list-id 12345
$ kptncook discovery-list --list-type automated --list-id 67890
$ kptncook dailies --recipe-filter veggie --save
$ kptncook onboarding --tag rt:diet_vegetarian
$ kptncook onboarding --tag "low-carb,high-protein" --save
$ kptncook ingredients-popular
$ kptncook recipes-with-ingredients --ingredient-id 123,456 --save

Mealie sync

sync-with-mealie (and sync) creates every locally saved recipe that is not yet in Mealie. Recipes are matched by the KptnCook id stored in the Mealie recipe's extras (source: kptncook), not by name. A native ZIP import creates the complete recipe with those identity extras already present. Distinct KptnCook recipes with the same title can both be imported: Mealie assigns a unique name and slug, which subsequent updates preserve.

Cover and step images are best-effort follow-ups. A media failure does not undo the core import, and step-image updates patch only the instructions. The summary means:

  • Created N recipes: recipes newly created in Mealie.
  • Failed to sync N recipes: each line names the recipe, its KptnCook id and the reason (HTTP status, connection error, timeout or local processing error). Other recipes are still synced, and the command exits with status 1. Name-collision errors are failures, not successful identity matches.

A timeout or malformed response may occur after Mealie committed the import. The client does not retry or delete the recipe after such an ambiguous result. Run the sync again: it first checks stored identity extras and skips any recipe already imported. Do not delete a recipe merely because its import response was lost.

Export metadata

Exports to Mealie and Tandoor include KptnCook active tags as tags/keywords (verbatim).

The Markdown export (export-recipes-to-markdown) writes one .md file per recipe into an export_md directory under the KptnCook home, with YAML front matter (servings, prep/cook time, link, image, tags) followed by ingredients and instructions. Section headings and image alt text follow KPTNCOOK_LANG (German, English, Spanish, French, and Portuguese are recognized; other languages fall back to English), and <timer> placeholders in steps are replaced with their durations.

The Paprika and Tandoor exports write their files into the current directory and never overwrite an existing file. If the preferred name (the asciified recipe title, or allrecipes.paprikarecipes for a Paprika export of several recipes) is taken, for example by an earlier export or by a second recipe with the same title, the recipe id and then a counter are appended (Title-<recipe id>.zip, Title-<recipe id>-2.zip, allrecipes-2.paprikarecipes). The command output lists the names that were actually written.

Repository warnings

Repository-backed commands now warn if kptncook.json contains stored entries that can no longer be parsed into full recipes. The command continues with the valid recipes instead of silently dropping the bad entries. If you need to recover, inspect ~/.kptncook/kptncook.json and the previous snapshot in ~/.kptncook/kptncook.json.backup.

Delete recipes

Use indices from kptncook list-recipes or pass one or more --oid values.

$ kptncook delete-recipes 0 2
$ kptncook delete-recipes --oid 635a68635100007500061cd7 --oid 635a68635100007500061cd8
$ kptncook delete-recipes 0 --force

Dailies

Filter dailies by API fields such as recipeFilter (for example veggie), zone (timezone offset like +02:00), and subscription status (--subscribed and --not-subscribed are mutually exclusive). Add --save to store the daily recipes in the local repository.

$ kptncook dailies
$ kptncook dailies --zone +02:00 --recipe-filter veggie --save
$ kptncook dailies --subscribed
$ kptncook dailies --not-subscribed --save

Discovery

Use discovery-screen to list discovery list ids and types. discovery-list requires --list-type (latest, recommended, curated, automated). List types are case-insensitive; short flags are -t for --list-type and -i for --list-id. For curated and automated, pass the list id from discovery-screen with --list-id. For latest and recommended, omit --list-id. Use --no-quick-search if you only want discovery list ids, and add --save to discovery-list to store the resolved recipes locally. Discovery screen entries are printed as id | title | type so you can copy the list id into discovery-list. Discovery list entries are recipe summaries; the CLI resolves them to full recipes before printing or saving.

$ kptncook discovery-screen
$ kptncook discovery-screen --no-quick-search
$ kptncook discovery-list --list-type recommended
$ kptncook discovery-list --list-type latest
# list ids for curated/automated lists come from discovery-screen output
$ kptncook discovery-list -t curated -i 12345 --save
$ kptncook discovery-list --list-type automated --list-id 67890

Ingredients

Ingredient discovery and ingredient-based recipes require KPTNCOOK_ACCESS_TOKEN. Ingredient ids can be repeated or comma-separated; use the _id.$oid value from kptncook ingredients-popular (output is id | name for easy copy/paste). Use kptncook kptncook-access-token if you need to generate one. The --ingredient-id flag is required and repeatable for recipes-with-ingredients (-i is the short flag). Add --save to recipes-with-ingredients to store matched recipes locally. Recipes are resolved to full recipe payloads before printing or saving.

$ kptncook ingredients-popular
$ kptncook recipes-with-ingredients -i 123 -i 456 --save
$ kptncook recipes-with-ingredients --ingredient-id 123,456

Onboarding recipes

The --tag flag is required and repeatable; tags accept repeated values or comma-separated lists. Tags are KptnCook tag slugs (for example rt:diet_vegetarian). Recipes are resolved to full recipe payloads before printing or saving.

$ kptncook onboarding --tag rt:diet_vegetarian
$ kptncook onboarding --tag "low-carb,high-protein" --save

Environment

First, create the configuration directory and .env file:

$ mkdir -p ~/.kptncook
$ touch ~/.kptncook/.env

Alternatively, you can run the setup helper to create the .env file, prefill the default API key, and optionally fetch an access token. It is available both as a kptncook subcommand and as a standalone command:

$ kptncook setup
# or, equivalently:
$ kptncook-setup

The .env is written to $KPTNCOOK_HOME/.env when KPTNCOOK_HOME is set, otherwise to ~/.kptncook/.env.

Configuration is validated lazily. If you run a command before configuring the API key, kptncook will scaffold the .env file when that command first needs settings and then exit; just re-run the command after updating the file. help and other non-config commands do not force .env validation up front.

Then set environment variables in the ~/.kptncook/.env file (or directly in your shell). You'll need to set at least the KPTNCOOK_API_KEY variable. If you want to sync the recipes with mealie, set MEALIE_API_TOKEN or MEALIE_USERNAME/MEALIE_PASSWORD.

When kptncook creates or updates ~/.kptncook/.env, it applies owner-only read/write permissions (0600) where the platform supports it, because the file may contain access tokens, passwords, or trusted shell commands. Updates are written to an owner-only temporary file next to .env and then moved into place, so a failed write leaves the previous file intact.

Important: The .env file must be created in the ~/.kptncook/ directory, NOT in the installation directory or by editing the kptncook executable.

If you want to back up your favorite recipes from KptnCook, you have to set the KPTNCOOK_ACCESS_TOKEN variable as well. You can obtain the access token by running kptncook kptncook-access-token; the command fetches the token and saves KPTNCOOK_ACCESS_TOKEN into ~/.kptncook/.env instead of printing the raw token to stdout. But you need a kptncook account to do that. Beware: If you don't have a kptncook account, you'll lose all your favorites by creating a new one.

Optional API defaults for discovery/dailies/onboarding requests:

  • KPTNCOOK_LANG (default de)
  • KPTNCOOK_STORE (default de)
  • KPTNCOOK_PREFERENCES (for example rt:diet_vegetarian,)

Password Manager Integration

You can retrieve KptnCook credentials from a password manager instead of typing them interactively. Set these environment variables:

  • KPTNCOOK_USERNAME_COMMAND: Shell command to retrieve username
  • KPTNCOOK_PASSWORD_COMMAND: Shell command to retrieve password

Example for 1Password CLI:

KPTNCOOK_USERNAME_COMMAND="op read op://Personal/KptnCook/username"
KPTNCOOK_PASSWORD_COMMAND="op read op://Personal/KptnCook/password"

Example for pass (password-store):

KPTNCOOK_USERNAME_COMMAND="pass show kptncook/username"
KPTNCOOK_PASSWORD_COMMAND="pass show kptncook/password"

These commands are executed through your local shell. Only configure commands you trust and fully control, and treat the .env file as sensitive because it can contain shell commands as well as tokens and passwords.

Ingredient Grouping (Optional)

To split ingredient lists by ingredient.typ (e.g., "regular" vs "basic") across all exporters, set the toggle below. You can also customize the section labels.

KPTNCOOK_GROUP_INGREDIENTS_BY_TYP=true
KPTNCOOK_INGREDIENT_GROUP_LABELS="regular:You need,basic:Pantry"

Full Configuration Example

KPTNCOOK_API_KEY=6q7QNKy-oIgk-IMuWisJ-jfN7s6
KPTNCOOK_ACCESS_TOKEN=9353xxxx-xxxx-4fe1-xxxx-xxx4a173805  # replace with correct token
MEALIE_URL=https://mealie.staging.django-cast.com/api
# Mealie auth (choose one)
MEALIE_API_TOKEN=mealie-api-token
# or:
MEALIE_USERNAME=jochen
MEALIE_PASSWORD=password  # replace with correct password

# Optional: API defaults
KPTNCOOK_LANG=de
KPTNCOOK_STORE=de
KPTNCOOK_PREFERENCES=rt:diet_vegetarian,

# Optional: Password manager integration
KPTNCOOK_USERNAME_COMMAND="op read op://Personal/KptnCook/username"
KPTNCOOK_PASSWORD_COMMAND="op read op://Personal/KptnCook/password"

# Optional: Ingredient grouping
KPTNCOOK_GROUP_INGREDIENTS_BY_TYP=true
KPTNCOOK_INGREDIENT_GROUP_LABELS="regular:You need,basic:Pantry"

Troubleshooting

Common Issues

"SyntaxError: invalid decimal literal" after defining API key

This error occurs if you accidentally edited the kptncook executable file instead of creating a .env file.

Solution:

  1. Restore the original kptncook executable (reinstall if needed)
  2. Create the configuration directory: mkdir -p ~/.kptncook
  3. Create the .env file: touch ~/.kptncook/.env
  4. Add your environment variables to ~/.kptncook/.env

"Field required" validation errors

This happens when the required environment variables are not set. Make sure you have created the .env file in the correct location (~/.kptncook/.env) and added at least the KPTNCOOK_API_KEY variable.

Contribute

See CONTRIBUTING.md for notes on how this repository uses coding-agent assisted maintenance.

Install Development Version

  • Checkout source repository
  • Install uv if not already installed
  • Install just if not already installed

Install the development environment:

$ uv sync

Install the git hooks:

$ uv run prek install -f

Quality Gates (Required)

$ just check

This runs just lint, just typecheck, and just test in sequence. You can also run each step individually:

The same three gates run in GitHub Actions for pushes and pull requests.

Update hook revisions:

$ just update-hooks

Target a single test:

$ just test-one tests/test_file.py::TestClass::test_case

Run Tests (Direct)

Run tests using uv:

$ uv run pytest

Disposable Mealie Integration Tests

tests/mealie_integration_test.py exercises real HTTP against an externally provisioned disposable Mealie instance. It is skipped by default and requires all three variables below; never point it at your personal or production server. The URL is the API base (including /api), and the token must permit recipe creation, inventory reads, media uploads, and deletion.

$ export MEALIE_TEST_URL=http://127.0.0.1:19001/api
$ read -rs MEALIE_TEST_TOKEN  # paste a disposable server token, then press Enter
$ export MEALIE_TEST_TOKEN
$ export MEALIE_TEST_DISPOSABLE=1
$ uv run pytest -q tests/mealie_integration_test.py
$ unset MEALIE_TEST_TOKEN MEALIE_TEST_URL MEALIE_TEST_DISPOSABLE

Run the same tests separately against pinned ghcr.io/mealie-recipes/mealie:v1.12.0 and ghcr.io/mealie-recipes/mealie:v3.28.0 instances. For example, start an isolated SQLite container on a localhost-only port (use another name/port for the other version):

$ docker run -d --name kptncook-mealie-v1-test \
    -p 127.0.0.1:19001:9000 \
    -e DB_ENGINE=sqlite -e ALLOW_SIGNUP=false \
    ghcr.io/mealie-recipes/mealie:v1.12.0

Wait until GET /api/app/about succeeds before obtaining a token from the instance's login/API-token UI. The upstream installation checklists for v1.12.0 and v3.28.0 list the initial login as changeme@example.com / MyPassword (unless overridden). The client discovers the server version via GET /app/about; no test-specific version override is needed. Keep tokens out of logs, shell history, and tracked files. No KptnCook account or external KptnCook media is used: repository/conversion fixtures are local, and a tiny step image is served from an ephemeral localhost HTTP server.

Coverage includes same-title recipes with distinct KptnCook identities, a second sync with no writes, ingredients/tags/instructions/nutrition roundtrip, and step-media enrichment via PATCH. A real HTTP transport also injects a read timeout after the server successfully commits an archive import; the next sync must discover the persisted identity without deleting or retrying it. Extras assertions allow Mealie to add ownership metadata.

A finally inventory cleanup deletes only recipes carrying the exact randomly generated test identities, even when a committed response is lost. Recipe tags, foods, and units may remain, so discard the whole instance after testing. Stop and remove every test container (including after a failed run):

$ docker rm -f -v kptncook-mealie-v1-test
# If provisioned:
$ docker rm -f -v kptncook-mealie-v3-test

Lines of Code

Show a Rich-formatted summary of lines by language, area (src, tests, scripts, tooling), and directory:

$ just loc

During the slopscope pre-release phase, this uses a sibling ../slopscope checkout. It uses cloc when available and falls back to Python physical-line counting when cloc is not installed. Compared to the previous project-local counter, totals no longer include that removed counter implementation itself; for example, the previous cloc total was 51 files and 6867 code lines, while the migrated slopscope report is 50 files and 6437 code lines.

Release Process

Use the helper commands below from a clean worktree:

  1. Prepare the release metadata:
    $ just release-prepare <version>
    
    This moves the current Unreleased section into a dated changelog entry and bumps version in pyproject.toml. kptncook.__version__ is derived from package metadata, so no second version file needs updating.
  2. Run quality gates:
    $ just check
    
  3. Review the generated release notes if needed:
    $ just release-notes <version>
    
  4. Commit the release prep and create a tag:
    $ git commit -am "release: v<version>"
    $ git tag -a v<version> -m "v<version>"
    
  5. Push commits and tags:
    $ git push
    $ git push --tags
    
  6. Draft the GitHub release from the matching changelog section:
    $ just release-draft <version>
    
  7. Publish the GitHub release and package when ready.

Publish Packages

After running just check, publish the package to PyPI using uv:

$ uv publish --token your_token

Metadata

Release files for kptncook 0.0.35

For a detailed explanation of source distributions (sdists) and built distributions (wheels), please see the package formats documentation.

Source distribution (sdist)

Source distribution for kptncook 0.0.35
File Size Uploaded
kptncook-0.0.35.tar.gz 47.8 kB Details

Built distribution (wheel)

Table of built distributions (wheels) for kptncook 0.0.35
File Interpreter ABI Platform
kptncook-0.0.35-py3-none-any.whl Python 3 none any Details

Total release size: 105.6 kB

Release files / kptncook-0.0.35.tar.gz

Download URL kptncook-0.0.35.tar.gz
Size 47.8 kB
Tags Source
SHA-256 checksum
How to use checksums
17b9c0bf8b5fa2291b37fdb0e3e4574b651d1af37678cf2f5af880322c0e2af4
BLAKE2b-256 checksum
How to use checksums
25d7d4efe5636b27125174de65153c4f56986c9542eda9f6b6c23c8b81873a2f
Upload date
Uploaded using Trusted Publishing?
What is trusted publishing?
No
Uploaded via uv/0.12.24 {"installer":{"name":"uv","version":"0.12.24","subcommand":["publish"]},"python":null,"implementation":{"name":null,"version":null},"distro":{"name":"macOS","version":null,"id":null,"libc":null},"system":{"name":null,"release":null},"cpu":null,"openssl_version":null,"setuptools_version":null,"rustc_version":null,"ci":null}

Release files / kptncook-0.0.35-py3-none-any.whl

Download URL kptncook-0.0.35-py3-none-any.whl
Size 57.8 kB
Tags Python 3
SHA-256 checksum
How to use checksums
d10032c5cf804656d3690841d171b4420e77d2a3536cf639349ce929742b0d91
BLAKE2b-256 checksum
How to use checksums
cbdbc83a42948c505c368fde4168960c4779157fe53c5bc3a13ffa4f213b09b0
Upload date
Uploaded using Trusted Publishing?
What is trusted publishing?
No
Uploaded via uv/0.12.24 {"installer":{"name":"uv","version":"0.12.24","subcommand":["publish"]},"python":null,"implementation":{"name":null,"version":null},"distro":{"name":"macOS","version":null,"id":null,"libc":null},"system":{"name":null,"release":null},"cpu":null,"openssl_version":null,"setuptools_version":null,"rustc_version":null,"ci":null}

Release history Release notifications | RSS feed

This release

0.0.35 This release

2 release files

0.0.34

2 release files

0.0.32

2 release files

0.0.31

2 release files

0.0.29

2 release files

0.0.28

2 release files

0.0.27

2 release files

0.0.26

2 release files

0.0.25

2 release files

0.0.23

2 release files

0.0.22

2 release files

0.0.21

2 release files

0.0.20

2 release files

0.0.19

2 release files

0.0.17

2 release files

0.0.16

2 release files

0.0.14

2 release files

0.0.12

2 release files

0.0.10

2 release files

0.0.9

2 release files

0.0.8

2 release files

0.0.7

2 release files

0.0.6

2 release files

0.0.5

2 release files

0.0.4

2 release files

0.0.3

2 release files

0.0.2

2 release files

Anthropic, PBC Visionary sponsor Bloomberg Visionary sponsor Hudson River Trading Visionary sponsor Meta Visionary sponsor NVIDIA Visionary sponsor Microsoft Sustainability sponsor Depot Continuous Integration AWS Cloud computing and Security Sponsor Datadog Monitoring Fastly CDN Google Download Analytics Sentry Error logging StatusPage Status page