Blog/General

find_or_generate_image: The Tool That Searches First and Slops Second

Published July 6, 2026

find_or_generate_image: The Tool That Searches First and Slops Second
Dewey Cardinal
Cover image by OKSLOP contributor Dewey Cardinal

If you're building an agent that needs images and you only wire up one OKSLOP tool, make it this one.

find_or_generate_image does the thing a careful person does without thinking: check whether a good image already exists before making a new one. Search the free library first. Generate only on a miss. One description in, one commercial-use, attribution-free URL out — plus a note telling you which path it took.

That order matters more than it sounds. It's why agent workflows stay fast and cheap, and it's why the library compounds instead of drowning in one-off generations nobody reuses.

The problem it solves

Point a naive agent at "add an image here" and it generates. Every time. Even when the commons already has fifty images that fit, it burns time and a generation credit making a fifty-first.

That's slow, it costs more, and it's wasteful in a way that's easy to miss: on-demand generation regenerates work that already exists. OKSLOP's whole model is generate-once-serve-forever — one image, pre-generated, served from a CDN to everyone. A tool that always generates fights that model. A tool that searches first honors it.

So find_or_generate_image inverts the default. Generation is the fallback, not the reflex.

The decision boundary

Here's exactly what happens on a call, straight from the implementation — no hand-waving:

  1. Search the library. It runs a semantic search for your query, sorted by relevance, pulling at least min_results candidates (minimum 5).
  2. Enough matches? Return the top one. If the number of results is at least min_results, you get the top result as a library URL — free, instant, commercial-use, no attribution. Done.
  3. Not enough, and generation allowed? Generate. If the library came up short and allow_generate is true (the default), it generates a custom image to spec in the chosen contributor's style and returns a deterministic embed URL.
  4. Not enough, and generation off? Say so. If allow_generate is false, it returns no image and tells you the library missed — no surprise spend.

The dial that controls all of this is min_results:

  • min_results: 1 (the default) — take any match. Cheapest, most library-biased. Good when "an image that fits" beats "the perfect image."
  • Higher values — pickier. The library has to return more candidates before the tool trusts it, so thin queries fall through to generation more often. Good when you'd rather generate to spec than settle for a loose match.

"Relevance" here is the search backend's own ranking plus that result-count threshold. There's no invented scoring API — just semantic search (Jina CLIP v2) and a bar you set.

The parameters

find_or_generate_image(
  query,           // required — describe the image in words
  orientation,     // "landscape" | "portrait" | "square" (optional)
  contributor,     // style used ONLY if it generates; default "nova-chen"
  min_results,     // library candidates needed to accept a match; default 1
  allow_generate   // generate on a miss? default true
)

Two of these have a subtlety worth calling out:

contributor is ignored on a library hit. It only kicks in when the tool has to generate. So set it to the style you'd want if it slops something new — you're not filtering the library by it. Browse styles at okslop.com/contributors.

allow_generate: false turns this into a pure library tool. Set it when you want zero generation cost and are fine with an occasional empty result. It's the safe mode for budget-sensitive batches.

A real call, both paths

When the library has it — the common case — you get a match:

**find_or_generate_image** for "cozy home office at golden hour"

Found in library (free, commercial-use, no attribution). 214 candidates
matched "cozy home office at golden hour".

Image URL: https://okslop.com/img/.../preview

- **Sunlit desk with laptop and ceramic mug** (1024×768) — https://okslop.com/img/.../preview [ID: ...]

When it doesn't — say you asked for something oddly specific — it crosses the boundary:

**find_or_generate_image** for "single origami crane on a slate desk, top-down"

No close library match — generated a custom image to spec in the "nova-chen"
style (status: queued). The URL works immediately (placeholder until ready)
and is deterministic + commercial-use safe.

Image URL: https://okslop.com/img/.../preview

Notice the note is doing real work. It tells you which path ran so an agent can log it, count it, or decide whether to try a broader query next. And the generated URL is live the instant you receive it — it serves a placeholder while the image renders, then swaps to the final image. No polling, no callback.

The cost model, in one line

A library match is cheap (think 1 credit; search itself is free). A custom generation costs more (a few credits). Because the tool prefers matches, you only pay generation credits when nothing fits — which, for most everyday queries, is rarely.

If you want to see the bill before a batch, estimate_cost prices a run of matches vs. generations, and plan_backfill proposes image slots for a piece of content. Both run locally — no API call, no spend — so an agent can budget before it commits.

When to reach for something else

find_or_generate_image returns one image and makes the call for you. Sometimes you want a different shape:

  • You want to choose from a shortlistsuggest_images returns several candidates with a one-line rationale each.
  • You need a repeatable, numbered comparison setcompare_image_options returns a stable shortlist with IDs and metadata.
  • You're filling many slots at oncebackfill_content_images runs find-or-generate across a whole list of {key, description} slots and returns a key → URL map.
  • You need the exact same image every time from a queryseeded_image is fully deterministic: same query + seed, same photo.

But for the plain case — "get me the right image for this spot, I don't care whether you found it or made it" — this is the one.

The recommendation, plainly

If you build agents that touch images, wire up find_or_generate_image and let it be the default. It's library-first, so it's fast and cheap. It's generate-on-miss, so it never leaves a slot empty when you don't want it to. And it's honest about which path it took, so you can trust what it did.

Search first, slop second. That's the whole idea, and it's the right one.


Install the OKSLOP MCP server or grab an API key at okslop.com/developers, then hand your agent a description and let the tool decide. It's available through the MCP server, the CLI, and the SDK.

Related: Running OKSLOP MCP in Claude Code · Migrating off the Unsplash API · What happened to Unsplash