Image Search
SkillSearchFind and download real images from the web — people, logos, brand/event stills, B-roll — to add as overlay image cards or project assets. Load when the prompt asks to source or insert images (e.g. 'add a photo of X', 'find images of the IPO', 'pull a shot of the factory').
Available today. Use it from your connected AI after setup.
No other account needed.
Connect ahel once, and every AI you use reads what you have installed.
Then ask your AI: use the Image Search skill
What this skill tells your AI
The instructions your AI receives, as published by thesampadilla/montaj in skills/image-search/SKILL.md and read by ahel’s review.
Sourcing real imagery is a two-step pipeline: search_images finds candidate URLs, fetch_image downloads the one you pick to a workspace path. From there the image becomes an overlay image card (load skill overlay) or a project asset.
Use this when the editing prompt asks for outside imagery — a person ("a photo of Elon Musk"), an event ("the IPO"), a logo, a brand still, or B-roll the footage doesn't contain. Never fabricate an image path or hotlink a remote URL into the project — always run step fetch_image to a real local file first (the preview player and render engine read local files).
Step 1 — search_images
Run step search_images with the following args. Returns candidate results; no download is performed.
| Arg | Default | Notes |
|---|---|---|
query | — | Search string. Be specific: "Elon Musk portrait 2025" beats "elon". |
provider | commons | commons · sportsdb · web (see below) |
limit | 10 | Max results, capped at 30 |
Output: { "results": [ { title, url, width, height, mime, license, artist, source, thumbnail? } ] }
url is always an HTTPS original (so the downstream fetch_image step accepts it).
Providers
commons(Wikimedia Commons, keyless) — license-clean, well-labeled. First choice for historical figures, landmarks, public-domain/CC imagery, and anything not time-sensitive.sportsdb(TheSportsDB, keyless) — team badges / escudos. Use for sports crests.web(open-web Google Images via SerpApi, needs a key) — broadest coverage. Use for current events, specific living people, brand/product shots, and anything Commons won't have. License is reported"unknown"— web results are not license-filtered; editorial use is the caller's judgment.
Pick the narrowest provider that will have the subject. Reach for web only when commons won't cover it (recent news, a specific private individual, a current product).
If the key is missing the step fails — tell the human to set up their SerpApi key via the native interface.
Step 2 — fetch_image
Run step fetch_image with the following args. Downloads one HTTPS URL to a workspace path. Private/internal IPs are blocked; non-image and oversized responses are rejected.
| Arg | Default | Notes |
|---|---|---|
url | — | HTTPS URL from a search result's url field |
out | — | Destination path. Use <project>/assets/<name>.jpg |
max-bytes | 25 MiB | Size cap |
Output: { "path": "/abs/path/to/file.jpg" }. Some hosts return 403 to non-browser fetches — if one fails, run step fetch_image with the next candidate instead of fighting it.
To register a fetched image into Hub Media (R2-backed, survives in the library), call
hub.ingest_media({ projectId, items: [{ workspacePath: "<absolute fetch_image out path>" }] }). Do not hand-rollcreate_media+ presigned PUT.
Picking the right image
Search returns more than you need. Before committing:
- Right subject — read the
titleand dimensions. For a named person or specific event, confirm it's actually them/it, not a lookalike or a generic stock shot. - High enough resolution — prefer ≥1000px on the long edge for full-frame cards. Tiny thumbnails upscale badly on 4K output.
- Clean frame — verify visually. After fetching, look at the file (read it as an image, or run step
analyze_mediawith a "is there burned-in text or a watermark?" prompt). Reject images with burned-in captions, news-chyron bars, watermarks, logos stamped across them, or collages. Plain, uncluttered shots composite far better behind text overlays. This matters most forwebresults, which are unfiltered. - Fetch 1–2 backups per subject when the first pick is uncertain — hosts 403, or the image turns out cluttered.
Where the image goes
- As an overlay image card — the usual choice for a B-roll insert synced to a beat. Author/point a
photo_card-style JSX overlay at it and pass the local path viaprops. Load skilloverlayand load skillwrite-overlay. - As a project asset — add to
project.assets[]({ id, type: "image", src, name }) so it's tracked and reusable.
Always use the local fetched path (absolute), never the remote URL.
Worked example
1. Run step `search_images` with {query:"Elon Musk portrait 2025", provider:"web", limit:6}
2. Eyeball results → pick a clean ≥1500px original
3. Run step `fetch_image` with {url:"https://…/elon.jpg", out:"<project>/assets/elon_musk.jpg"}
4. Read the downloaded file → confirm subject + no watermark/chyron
5. Add an image-card overlay (props.src = the fetched path) → load skill `overlay`
Signals
- GitHub stars
- 25
- Forks
- 11
- Last commit
- Sep 2026
Advanced
- Catalog kind
- skill
- Gateway key
image-search- Source
- github.com/thesampadilla/montaj