feat(image): add auto recipe runner (MK-5 Layer 2) #26

Merged
nrupard merged 2 commits from feat/image-auto-detect-MK-5 into main 2026-05-21 17:09:07 +02:00
Member

What

Implements Layer 2 of MK-5: monkey image auto <input> <output>. It classifies the input with the Layer 1 classifier (MK-6), loads the recipe for the resulting class, and applies an ordered chain of existing image filters. No new DSL, no new operators - the runner is a thin dispatcher over the same functions the CLI subcommands already call.

Interface

monkey image auto <input> <output> [--class X] [--recipe-dir DIR]. With --class omitted the input is auto-detected; --class forces a class and skips detection. The chosen class and each step are reported on stderr, the final summary on stdout.

A recipe is plain TOML, one table per step: op is the kebab-case filter name, args mirror that filter's flags, and any omitted arg falls back to the filter's own CLI default.

[[step]]
op = "local-contrast"
args = { strength = 60, sigma = 0.75, iterations = 1 }

Config resolution

Defaults ship embedded via include_str! for all seven classes (unknown is a passthrough copy). Overrides are read from --recipe-dir DIR/<class>.toml when given, else $XDG_CONFIG_HOME/monkey/recipes/<class>.toml (falling back to $HOME/.config/monkey/recipes/). This mirrors the existing classify.toml override mechanism.

Changes

  • src/image/recipe.rs: recipe schema, class -> recipe resolution, op dispatcher, arg-coercion helpers, tests.
  • src/image/recipes/*.toml: seven embedded default recipes.
  • src/image/classify.rs: ImageClass::from_label (inverse of as_str) to parse --class.
  • src/image/mod.rs: Auto subcommand variant + dispatch.
  • README.md: new monkey image auto section; updated the Layer 1 forward reference.

Testing

just pre-commit green (fmt, clippy -D warnings, build, 66 tests). A unit test loads every embedded recipe and runs every named op end-to-end so a typo in a default recipe fails the suite. Manually verified in the builder image: auto-detect into a color-photo recipe, --class binary-scan forcing, and a --recipe-dir override each produced the expected steps and output.

Closes MK-5 Layer 2. Layers 1 (classify, MK-6) done; Layer 3 (feedback log + tuner) remains.

🤖 Generated with Claude Code

## What Implements **Layer 2 of MK-5**: `monkey image auto <input> <output>`. It classifies the input with the Layer 1 classifier (MK-6), loads the recipe for the resulting class, and applies an ordered chain of existing image filters. No new DSL, no new operators - the runner is a thin dispatcher over the same functions the CLI subcommands already call. ## Interface `monkey image auto <input> <output> [--class X] [--recipe-dir DIR]`. With `--class` omitted the input is auto-detected; `--class` forces a class and skips detection. The chosen class and each step are reported on stderr, the final summary on stdout. A recipe is plain TOML, one table per step: `op` is the kebab-case filter name, `args` mirror that filter's flags, and any omitted arg falls back to the filter's own CLI default. ```toml [[step]] op = "local-contrast" args = { strength = 60, sigma = 0.75, iterations = 1 } ``` ## Config resolution Defaults ship embedded via `include_str!` for all seven classes (`unknown` is a passthrough copy). Overrides are read from `--recipe-dir DIR/<class>.toml` when given, else `$XDG_CONFIG_HOME/monkey/recipes/<class>.toml` (falling back to `$HOME/.config/monkey/recipes/`). This mirrors the existing `classify.toml` override mechanism. ## Changes - `src/image/recipe.rs`: recipe schema, class -> recipe resolution, op dispatcher, arg-coercion helpers, tests. - `src/image/recipes/*.toml`: seven embedded default recipes. - `src/image/classify.rs`: `ImageClass::from_label` (inverse of `as_str`) to parse `--class`. - `src/image/mod.rs`: `Auto` subcommand variant + dispatch. - `README.md`: new `monkey image auto` section; updated the Layer 1 forward reference. ## Testing `just pre-commit` green (fmt, clippy `-D warnings`, build, 66 tests). A unit test loads every embedded recipe and runs every named op end-to-end so a typo in a default recipe fails the suite. Manually verified in the builder image: auto-detect into a `color-photo` recipe, `--class binary-scan` forcing, and a `--recipe-dir` override each produced the expected steps and output. Closes MK-5 Layer 2. Layers 1 (classify, MK-6) done; Layer 3 (feedback log + tuner) remains. 🤖 Generated with [Claude Code](https://claude.com/claude-code)
feat(image): add auto recipe runner (MK-5 Layer 2)
All checks were successful
Check / fmt + clippy + build + tests (pull_request) Successful in 19s
77daf1b838
Add `monkey image auto <input> <output>`: classifies the input via the Layer 1 classifier (or takes `--class` to force one), loads the matching class recipe, and applies an ordered list of existing image filters to the pixels. The runner is a thin dispatcher over the same filter functions the CLI already calls, so there is no new DSL or operator set.

Recipes are TOML (`[[step]] op = "<filter>" args = {...}`); each omitted arg falls back to that filter's CLI default. Defaults ship embedded via `include_str!` for every class, with `unknown` as a passthrough copy. Users override a class by writing `recipes/<class>.toml` under `$XDG_CONFIG_HOME/monkey/` or by passing `--recipe-dir DIR`, mirroring the existing classify.toml override mechanism.

Adds `ImageClass::from_label` (inverse of `as_str`) to parse `--class`, the recipe module with arg-coercion helpers and tests covering every embedded recipe end-to-end, and README docs for the new subcommand.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
fix(image): reject unknown recipe args/fields, decode once, byte-copy passthrough
All checks were successful
Check / fmt + clippy + build + tests (pull_request) Successful in 38s
Create release / Create release from merged PR (pull_request) Has been skipped
9b76fc9d99
Address review findings on the auto recipe runner:

Reject silent misconfiguration. `Step` and `Recipe` now use `#[serde(deny_unknown_fields)]` so a misspelled top-level key (e.g. `argz`) fails to parse, and an `Args` tracker records which keys each op reads then errors on any leftover arg key (e.g. `threshld` for `threshold`). This matters because the Layer 3 tuner will write these files programmatically; a typo silently no-op'ing would corrupt tuning results.

Decode the input once. On auto-detect the runner now opens the image a single time and reuses the decoded buffer for the pipeline, instead of `classify_path` opening it and `load` opening it again.

Byte-copy the passthrough. An empty recipe (e.g. `unknown`) now `fs::copy`s the input to the output verbatim rather than decoding and re-encoding, so alpha, metadata, and compression are preserved and the output is byte-identical, matching the documented "copy through untouched" behavior.

`arg_u32` also accepts whole-valued floats (e.g. `2.0`) so tuner-emitted floats do not trip the integer check.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
nrupard deleted branch feat/image-auto-detect-MK-5 2026-05-21 17:09:07 +02:00
Sign in to join this conversation.
No reviewers
No labels
No milestone
No project
No assignees
1 participant
Notifications
Due date
The due date is invalid or out of range. Please use the format "yyyy-mm-dd".

No due date set.

Dependencies

No dependencies set.

Reference
pandoras-box/monkey!26
No description provided.