Skip to content
Star11

Tasks and scheduling

This is the reference for CookDex task execution, scheduling, automations, safety policies and runtime settings. Every task is also documented in place on CookDex’s Help page.

The Web UI stores schedules through its API (POST /schedules); routes are relative to /cookdex/api/v1 by default, or your WEB_BASE_PATH.

CookDex supports two schedule kinds:

Kind Required fields Notes
interval seconds Runs repeatedly. Optional start_at, end_at, and run_if_missed values are stored in UTC.
once run_at Runs one time in the future. Optional run_if_missed controls restored missed runs.
calendar every (day or week), time (HH:MM), weekday (0 = Sunday), timezone A wall-clock time in a time zone, so it follows daylight saving. Used by automations; not accepted by POST /schedules.

POST /schedules accepts interval and once schedules; calendar schedules are made by automations.

An automation is an ordered list of steps (a task and its options) with settings for the whole run and a trigger. It’s stored by the Web UI and run by the hidden workflow task (python -m cookdex.workflow_runner), which builds every step up front, then runs them one after another in a single run with one log and one set of results.

Field Values Notes
steps 1 to 12 {task_id, options} Options are the task’s own, without dry_run, backup_first or apply_cleanups; those come from the automation.
mode preview, apply Preview runs every step as a dry run.
backup_first boolean With apply, one pre-change backup is made before the first step instead of one per step.
stop_on_error boolean Stop at the first step that fails, or carry on with the rest.
trigger manual, calendar (every: day/week, time, weekday 0 = Sunday, timezone), interval (seconds, start_at), once (run_at) Enabled automations with a time-based trigger own one schedule for the workflow task. Calendar triggers keep their wall-clock time across daylight-saving changes.

Approval to apply changes unattended is kept per automation (policy key workflow:<id>), not per task. Only an owner can give it; an editor who changes an approved automation’s steps or settings withdraws it. Four ready-made automations ship switched off. Plain task schedules, including older ones and ones made through POST /schedules, are turned into one-step automations with the same timing, options and approval.

Most write-capable tasks default to dry_run=true. Live runs (dry_run=false) and other dangerous options are blocked unless an owner enables the task policy through PUT /policies or the Web UI unlock flow.

Cleanup commands and reimport return a nonzero exit status when their reports contain failed operations, including partial failures. The maintenance pipeline stops on a failed cleanup stage unless continue_on_error=true.

The Backup First option is hidden while a task is in dry-run mode. When enabled for a live run, CookDex creates a Mealie backup before the main task starts.

Data Pipeline

Task ID Title Purpose
data-maintenance Data Maintenance Pipeline Run staged cleanup and audit steps in order, or select a subset of stages.
recipe-dredger Recipe Dredger Crawl configured recipe sites, verify recipe pages, filter by language, and import verified URLs into Mealie.
mealie-backup Mealie Backup Create a Mealie backup through the admin API and optionally delete older backups this task made.

Actions

Task ID Title Purpose
clean-recipes Clean Recipe Library Remove duplicate source URLs, filter junk content, and normalize messy import names.
slug-repair Repair Recipe Slugs Find recipes whose slug no longer matches their name and fix them.
ingredient-parse Ingredient Parser Parse raw ingredient text into structured food, unit, and quantity fields.
yield-normalize Yield Normalizer Fill missing yield text or parse yield text into numeric servings.
cleanup-duplicates Clean Up Duplicates Merge duplicate food, unit, tag, and category entries.
reimport-recipes Re-import Recipes Re-scrape source URLs while preserving recipe identity, favorites, and organization.

Organizers

Task ID Title Purpose
tag-categorize Tag & Categorize Recipes Assign categories, tags, and tools with rule matching and optional AI.

Audits

Task ID Title Purpose
health-check Health Check Run read-only recipe quality and taxonomy audits.
Option Type Default Description
dry_run boolean true Preview changes without writing anything.
backup_first boolean true Create a Mealie backup before a live run. Hidden while dry_run=true.
stages string list all stages Select stages: dedup, junk, names, parse, foods, units, categorize, yield, quality, audit. The retired labels, tools, taxonomy and cookbooks stages are skipped.
confidence_threshold integer 70 Ingredient parser NLP confidence percentage. Lower accepts more NLP results and reduces AI fallback.
max_recipes integer unset Limit ingredient parsing when the parse stage runs.
no_cache boolean false Ignore the ingredient parser scan cache.
reason string all categories Limit junk filtering to one category.
force_all boolean false Normalize all names, not only unformatted names.
provider string configured default Override AI provider for categorization: chatgpt, anthropic, or ollama.
nutrition_sample integer 200 Nutrition sample size for the quality stage. Not used when the database is connected (coverage is exact then).
continue_on_error boolean false Keep running later stages if one stage fails.
apply_cleanups boolean false Dangerous. Allows cleanup stages to write changes. Hidden while dry_run=true.

Default stage order:

dedup -> junk -> names -> parse -> foods -> units -> categorize -> yield -> quality -> audit

Option Type Default Description
dry_run boolean true Preview imports without writing to Mealie.
limit integer 50 Maximum recipes to import per configured site.
depth integer 1000 Maximum URLs to scan per site sitemap.
no_cache boolean false Ignore cached sitemaps and crawl fresh.
import_workers integer 2 Concurrent import workers, capped at 4.
precheck_duplicates boolean true Fetch existing Mealie recipes first and skip duplicates before import.
language_filter boolean true Skip recipes that do not match DREDGER_TARGET_LANGUAGE.
max_retry_attempts integer 3 Retry transient failures before marking a URL rejected.
Option Type Default Description
keep integer unset After creating a backup, delete older backups this task made, keeping this many.
prune_only boolean false Skip backup creation and only delete older backups this task made. Requires keep.

CookDex records every backup it creates in backup_ledger.json in the checkpoint directory (cache/maintenance by default), and pruning only ever deletes backups listed there. Backups made in Mealie, uploaded to it, or made before CookDex kept the ledger are never deleted. The backup taken before a change (Backup First) is recorded separately; CookDex keeps the newest 10 of those, and they don’t count against keep.

Option Type Default Description
dry_run boolean true Preview changes without writing anything.
backup_first boolean true Create a Mealie backup before a live run. Hidden while dry_run=true.
run_dedup boolean true Remove imported duplicates with the same source URL.
run_junk boolean true Remove records missing both meaningful ingredients and usable instructions; report ambiguous title matches for review.
run_names boolean true Normalize names derived from URL slugs.
reason string all categories Limit junk filtering to one category.
force_all boolean false Normalize all recipe names, not only unformatted names.
Option Type Default Description
dry_run boolean true Only list the recipes that would change.
backup_first boolean true Create a backup before repairing addresses.

Live runs fix each recipe through Mealie’s API (saving its name with a trailing space and back, which makes Mealie regenerate the slug), or in one database transaction when the database is connected. Recipes whose name would take a slug another recipe already has are skipped and listed.

Option Type Default Description
dry_run boolean true Preview changes without writing anything.
backup_first boolean true Create a Mealie backup before a live run. Hidden while dry_run=true.
max_recipes integer unset Limit parsing to at most N recipes.
no_cache boolean false Ignore the scan cache and reprocess all unparsed recipes.
confidence_threshold integer 70 Minimum NLP confidence percentage before accepting a parse. Low-confidence lines fall back to AI parsing.
Option Type Default Description
dry_run boolean true Preview changes without writing anything.
backup_first boolean true Create a backup before filling servings.
Option Type Default Description
dry_run boolean true Preview merges without writing anything.
backup_first boolean true Create a Mealie backup before a live run. Hidden while dry_run=true.
target string both Deduplicate both (foods and units), foods, units, taxonomy (tags and categories), tags, or categories.

Tags and categories are merged through Mealie’s POST /organizers/tags/merge and POST /organizers/categories/merge routes (Mealie v3.25+). Mealie moves every recipe from the duplicate to the kept entry and deletes the duplicate. Mealie does not update cookbook filters that name the duplicate, so CookDex repoints those cookbooks at the kept entry. The kept entry is the one used by the most recipes. Matching is conservative: names must differ only by case, spacing, punctuation, accents, & vs and, or a plural ending on the last word whose singular also exists (for example Gluten-Free / gluten free, or Cookie / Cookies). On an older Mealie the merge routes are missing; the run reports this and skips those merges without failing.

Option Type Default Description
dry_run boolean true Preview eligible recipes.
backup_first boolean true Create a Mealie backup before a live run. Hidden while dry_run=true.
max_recipes integer unset Limit reimport to at most N recipes.
workers integer 2 Concurrent scrape workers, capped at 4.
delay number 0.5 Seconds between requests per worker.
resume boolean false Skip recipes in the durable completion checkpoint; previews do not overwrite it.
slugs string unset Comma-separated recipe slugs to reimport. Leave blank for all eligible recipes.

When invoking python -m cookdex.recipe_reimporter directly, writes require --apply; DRY_RUN=true still overrides that flag.

Reimport uses the Mealie API. When the database is connected and an older Mealie rejects an update with a 403 because of a slug mismatch, it repairs the slug and retries.

Option Type Default Description
dry_run boolean true Preview changes without writing anything.
backup_first boolean true Create a Mealie backup before a live run. Hidden while dry_run=true.
method string both both runs rules first then AI, rules uses rules only, ai skips rules.
recat boolean false Re-process every recipe, including recipes that already have organization data. Hidden for rules.
provider string configured default Override AI provider for this run. Hidden for rules.
missing_targets string skip skip missing taxonomy targets or create them automatically. Hidden for ai.

Retired: taxonomy-refresh and cookbook-sync

Section titled “Retired: taxonomy-refresh and cookbook-sync”

Both pushed CookDex’s own copy of the taxonomy to Mealie. Organize now edits Mealie directly, so they were removed along with the Taxonomy Editor. On upgrade, CookDex saves whatever the old copy held (and any unpublished editor draft) to reports/retired-managed-taxonomy-<time>.json, which you can import in Organize, and turns off schedules that used either task with a note saying why.

Each cookbook’s queryFilterString is a list of clauses joined with AND. CookDex accepts these clauses:

Filter Fields Operators Example
Categories recipeCategory.name, recipe_category.id IN, NOT IN, CONTAINS ALL recipeCategory.name IN ["Dinner"]
Tags tags.name, tags.id IN, NOT IN, CONTAINS ALL tags.name NOT IN ["Dessert"]
Tools tools.name, tools.id IN, NOT IN, CONTAINS ALL tools.name IN ["Air Fryer"]
Foods recipeIngredient.food.name, recipeIngredient.food.id IN, NOT IN, CONTAINS ALL recipeIngredient.food.name IN ["Chicken"]
Food labels recipeIngredient.food.label.name, recipe_ingredient.food.label_id IN, NOT IN, CONTAINS ALL recipeIngredient.food.label.name IN ["Seafood"]
Rating rating =, <>, >, >=, <, <= rating >= 4
  • Filters in an imported taxonomy file can use names. Organize resolves category, tag, tool and food-label names to Mealie ids when the change is applied, after any tags or categories created in the same batch. A name that can’t be found fails that cookbook with a message.
  • rating is the recipe’s average rating across all users, from 0 to 5. Unrated recipes never match a rating clause, including rating < 3.
  • Rating filters need Mealie v3.25 or later, and food-label filters need v3.28 or later. When an older Mealie rejects one of these filters, Mealie’s error is shown for that cookbook.

Example: rating >= 4 AND recipeIngredient.food.label.name IN ["Seafood"].

Option Type Default Description
scope_quality boolean true Score recipe completeness for categories, tags, tools, ingredients, cook time, yield, and nutrition.
scope_taxonomy boolean true Scan taxonomy for unused entries, duplicate names, and recipes missing categories or tags.
nutrition_sample integer 200 Nutrition sample size. Not used when the database is connected (coverage is exact then).

health-check is read-only and does not expose a dry_run option.

Every task works through Mealie’s API. When a database connection string is saved in Settings -> Faster database access (MEALIE_DB_URL), tasks that can use it do so on their own, and fall back to the API with a warning in the log if it can’t be reached. There is no per-task switch. The --use-db flag on the command-line modules still forces it.

The Docker image includes the PostgreSQL and SSH drivers. Source installs are covered in Local Dev.

See Database connection for setup, what it speeds up, and what CookDex reads and writes.

Runtime settings are managed through GET /settings and PUT /settings.

  • Non-secret values are stored in the app state database.
  • Secret values are encrypted at rest.
  • Task runs receive the effective runtime environment built from the settings catalog.
  • .env is only for container settings (port, base path, HTTPS, headless bootstrap). On first start, older .env values for catalog settings are copied into Settings once, and the Settings page is the source of truth from then on.

Main setting groups:

Group Examples
Connection MEALIE_URL, MEALIE_API_KEY
AI CATEGORIZER_PROVIDER, OPENAI_API_KEY, ANTHROPIC_API_KEY, OLLAMA_URL, model settings
Dredger DREDGER_TARGET_LANGUAGE, DREDGER_CRAWL_DELAY, DREDGER_CACHE_EXPIRY_DAYS
Faster database access MEALIE_DB_URL, optional SSH settings (MEALIE_DB_SSH_HOST, _USER, _KEY)
Runner MAX_RUN_DURATION_SECONDS

Every setting is editable in Settings, which is also the complete reference — each field shows its group, default, and description. A few that are easy to miss:

Setting Default Purpose
UPDATE_CHECK_ENABLED true Check GitHub for releases on startup and about daily. Disabled means no update request. Only the app version is sent; GitHub sees the server network address. Failures show no banner.
AI_BATCH_HEARTBEAT_SECONDS 30 Seconds between progress messages while an AI batch is in flight. Set 0 to disable.
OLLAMA_REQUEST_TIMEOUT 300 Seconds to wait for each Ollama request before retrying.
OLLAMA_NUM_THREAD 4 CPU threads used by Ollama generation. Raise it if the host has cores to spare.

The Web UI keeps the most recent 500 runs. Older run records are pruned by a periodic housekeeping job, along with their log entries; task log files are rotated separately by the runner. Export anything you need to retain long-term before it ages out.