meme
Generate memes from the command line. The meme command wraps the free
memegen.link API — no API key needed.
Prime directive. For any meme request, use this skill end-to-end and
drive the meme CLI directly. Do not reimplement it (no hand-built URLs, no
ad-hoc python/curl), do not guess template ids, and keep to one bare
--print-url command. The Rules below are mandatory, not suggestions — follow
them every time, including the very first.
Prerequisite
The meme command must be installed. Check with meme --list. If it's missing,
install it:
uv tool install makememe
# or: pipx install makememe
Rules (always follow)
These apply everywhere the tool runs — interactive Claude Code and CI/CD:
- Always go through the
meme CLI. Never hand-build a memegen.link URL,
never write ad-hoc Python/scripts to construct or fetch one, and never
reimplement the escaping. The CLI handles path-segment escaping, line order,
errors, and output — reproducing it by hand gets these wrong.
- Discover template ids with
meme --list (or --list --json). Don't guess
ids from memory — guessed ids (buttons, twobuttons, …) 404. List first,
then use a verified id.
- Parse output with
--json, read it directly. When you need the path/URL
in a script, use meme ... --json and read the JSON fields. Do not pipe
it through python3 -c, sed, or awk to extract values — --json /
--print-url already give you exactly what you need.
- In CI/CD, install and call the CLI (
pip install makememe →
meme ... --print-url). Don't curl the API or build URLs inline in a
workflow step.
- Keep it smooth — one clean command, no files. Default to
--print-url;
do not download or save a file (-o, --open) unless the user explicitly
asks for one. Run meme as a single bare command — never pipe it into
grep/tail/awk or add redirects. A bare, consistent meme ... shape means
one permission approval covers every call and nothing is written to disk;
piping turns each call into a new command the user has to approve again.
Workflow
Choose the most apt template — match the joke's shape, not a default.
The single most important step. Don't reach for drake every time — it only
fits "rejecting A, preferring B." First work out the rhetorical structure
of the user's idea, then pick the template whose format matches it. The
catalog has ~200 templates; here is the high-value map by structure:
| The idea is… |
Template id |
Lines |
| Rejecting A, preferring B |
drake |
2 |
| Tempted away from the current thing by a shinier one |
db |
3 |
| Agonizing between two conflicting options |
ds |
3 |
| Swerving last-second to pick B over the obvious A |
exit |
3 |
| A multi-step plan whose last step backfires |
gru |
4 |
| Stating a hot take, daring you to argue |
cmm |
1 |
| Pretending all is fine amid disaster |
fine |
2 |
| A small, satisfying win / "nailed it" |
success |
2 |
| Galaxy-brain "can't have the problem if you avoid it" |
rollsafe |
2 |
| Escalating "increasingly enlightened" (often ironic) |
gb |
4 |
| Two things claimed different but actually identical |
same |
3 |
| Immediate regret right after a choice |
regret |
2 |
| Mocking a statement by repeating it sarcastically |
spongebob |
2 |
| An accusation vs. a smug, dismissive reply |
woman-cat |
2 |
| "One does not simply X" |
mordor |
2 |
| "Not sure if X… or just Y" (suspicion) |
fry |
2 |
| "False." + a blunt correction |
dwight |
2 |
| A forced smile hiding inner pain |
harold |
2 |
| Absurd gains from a dumb move |
stonks |
2 |
| "X, X everywhere" |
buzz |
2 |
| "I'm not saying it's X… but it's X" |
aag |
2 |
| Smug delight at chaos you caused |
disastergirl |
2 |
| Crude version vs. fancy/refined version of same thing |
pooh |
2 |
| An escalating back-and-forth argument |
chair |
6 |
| "Y U NO [do thing]" |
yuno |
2 |
If none of these fit the joke, browse the full catalog instead of forcing
a bad fit:
meme --list --json # ~200 templates; scan the titles for a better match
Always verify the chosen id with meme --list --json before using it —
guessing ids (e.g. buttons, twobuttons) leads to 404s. The map above is
accurate, but confirm anything you pull from memory.
Write the funniest version — reason before you render. Don't ship the
first phrasing that comes to mind. Briefly draft 2–3 caption options in your
head and pick the funniest, then render only that one. What makes it land:
- Specificity beats generic. "the
useEffect that runs twice" is funnier
than "a bug." Reach for the concrete, in-context detail.
- Punchy and short. Meme text is read in a second — trim filler words,
keep each line tight, favor a sharp last word.
- Match the template's voice. Lean into the format's built-in attitude
(smug
rollsafe, deadpan fine, escalating gru, mocking spongebob).
- Respect the structure. The funny comes from the contrast the template
sets up — make line A and line B actually play off each other.
- Use the user's name/specifics verbatim. If the user named a person,
team, tool, or thing ("make a meme about Raj and code reviews"), put that
exact name into the caption text — don't genericize it to "my coworker."
Names and inside-references are what make a meme land for its audience.
Get the URL (default). Pass the chosen template id with -t (as a flag,
not the leading word) then the caption lines in the template's natural order,
and use --print-url. This returns a public, permanent memegen.link URL — no
file is downloaded:
meme -t ds "ship it Friday" "wait till Monday" --print-url
Output (just the URL):
https://api.memegen.link/images/ds/ship_it_Friday/wait_till_Monday.png
Mind the line order for the template you picked — e.g. db reads
new temptation / you / current thing; exit reads straight road / exit
ramp / the car; fine is top speech / bottom "this is fine". If a render
looks off, it's usually line order or count — re-check against --list.
Using -t matters: every call starts with the same meme -t ... prefix, so
the user only has to approve the command once — not once per template.
Give the user the URL as a clickable link — they can open it in a browser
or paste it into Slack/GitHub (it renders inline with ). Don't
download a file unless they ask for one (see "Saving a local file" below).
Saving a local file
Only when the user explicitly wants a file (to attach it, edit it, or see it pop
open) — drop --print-url and instead:
meme -t drake "a" "b" --open # saves to a temp folder AND opens it in the viewer
meme -t drake "a" "b" -o ~/meme.png # save to a specific path
By default (without -o) a downloaded file goes to a temp folder
(<tmp>/makememe/) with a unique name, so it never clutters the user's working
directory.
Key flags
--print-url — return the public URL instead of downloading (the default
choice; prefer this).
--open — download and open the image in the user's default viewer.
-o path.png — save the download to a specific path.
--bg <image-url> — use a custom background image instead of a template;
pass caption lines as usual.
--ext png|jpg|webp|gif — output format.
--json — machine-readable output (use when you need to parse it in a script).
Tips
- Number of caption lines depends on the template (
--list shows each
template's lines count). Most use 2 (top/bottom).
- For an empty line, pass
"_" (memegen renders it blank).
- Text escaping (spaces,
?, /, %, emoji, etc.) is handled automatically —
just pass natural text in quotes.
- If a caption line starts with
- (e.g. "-26%"), insert -- before the
lines so it isn't read as a flag: meme regret --json -- "-26%" "WHY".
(Flags like --json/-o go before the --.)
- If a download fails, the JSON output includes the
url and error — inspect
the URL to debug the template id or line count.
Examples
Each picks the template that fits the joke's shape — not all drake:
meme -t drake "old way" "new way" --print-url # reject A, prefer B
meme -t ds "merge to main" "open another PR" --print-url # agonizing between two options
meme -t fine "prod is down" "this is fine" --print-url # disaster, pretending it's ok
meme -t gru "write the tests" "tests fail" "fix the code" "tests still fail" --print-url # plan backfires
meme -t same "staging" "prod" "they're the same picture" --print-url # claimed different, identical
meme -t cmm "tabs are better than spaces" --print-url # one-line hot take
meme -t mordor "one does not simply" "deploy on Friday" --print-url # "one does not simply X"
meme --bg https://example.com/cat.png "_" "DEPLOY ON FRIDAY" --print-url # custom background
meme -t success "fixed the bug" "on the first try" --open # only when the user wants a file
1---2name: meme3description: Generate meme images from a template and caption text using the `meme` CLI (a wrapper over the free memegen.link API). Use whenever the user asks to make/create/generate a meme, add a caption to a meme template, react with a meme, or wants a funny image with top/bottom text. This is the correct and only way to make a meme — always drive the `meme` CLI; never hand-build memegen URLs or use ad-hoc scripts. Handles popular templates (drake, distracted boyfriend, two buttons, etc.) and custom background images.4---56# meme78Generate memes from the command line. The `meme` command wraps the free9[memegen.link](https://api.memegen.link) API — no API key needed.1011> **Prime directive.** For *any* meme request, use this skill end-to-end and12> drive the `meme` CLI directly. Do not reimplement it (no hand-built URLs, no13> ad-hoc `python`/`curl`), do not guess template ids, and keep to one bare14> `--print-url` command. The Rules below are mandatory, not suggestions — follow15> them every time, including the very first.1617## Prerequisite1819The `meme` command must be installed. Check with `meme --list`. If it's missing,20install it:2122```bash23uv tool install makememe24# or: pipx install makememe25```2627## Rules (always follow)2829These apply everywhere the tool runs — interactive Claude Code **and** CI/CD:30311. **Always go through the `meme` CLI.** Never hand-build a `memegen.link` URL,32 never write ad-hoc Python/scripts to construct or fetch one, and never33 reimplement the escaping. The CLI handles path-segment escaping, line order,34 errors, and output — reproducing it by hand gets these wrong.352. **Discover template ids with `meme --list` (or `--list --json`).** Don't guess36 ids from memory — guessed ids (`buttons`, `twobuttons`, …) 404. List first,37 then use a verified id.383. **Parse output with `--json`, read it directly.** When you need the path/URL39 in a script, use `meme ... --json` and read the JSON fields. Do **not** pipe40 it through `python3 -c`, `sed`, or `awk` to extract values — `--json` /41 `--print-url` already give you exactly what you need.424. **In CI/CD, install and call the CLI** (`pip install makememe` →43 `meme ... --print-url`). Don't `curl` the API or build URLs inline in a44 workflow step.455. **Keep it smooth — one clean command, no files.** Default to `--print-url`;46 do **not** download or save a file (`-o`, `--open`) unless the user explicitly47 asks for one. Run `meme` as a single bare command — never pipe it into48 `grep`/`tail`/`awk` or add redirects. A bare, consistent `meme ...` shape means49 one permission approval covers every call and nothing is written to disk;50 piping turns each call into a new command the user has to approve again.5152## Workflow53541. **Choose the most apt template — match the joke's *shape*, not a default.**5556 The single most important step. Don't reach for `drake` every time — it only57 fits "rejecting A, preferring B." First work out the *rhetorical structure*58 of the user's idea, then pick the template whose format matches it. The59 catalog has ~200 templates; here is the high-value map by structure:6061 | The idea is… | Template id | Lines |62 |-------------------------------------------------------|---------------|-------|63 | Rejecting A, preferring B | `drake` | 2 |64 | Tempted away from the current thing by a shinier one | `db` | 3 |65 | Agonizing between two conflicting options | `ds` | 3 |66 | Swerving last-second to pick B over the obvious A | `exit` | 3 |67 | A multi-step plan whose last step backfires | `gru` | 4 |68 | Stating a hot take, daring you to argue | `cmm` | 1 |69 | Pretending all is fine amid disaster | `fine` | 2 |70 | A small, satisfying win / "nailed it" | `success` | 2 |71 | Galaxy-brain "can't have the problem if you avoid it" | `rollsafe` | 2 |72 | Escalating "increasingly enlightened" (often ironic) | `gb` | 4 |73 | Two things claimed different but actually identical | `same` | 3 |74 | Immediate regret right after a choice | `regret` | 2 |75 | Mocking a statement by repeating it sarcastically | `spongebob` | 2 |76 | An accusation vs. a smug, dismissive reply | `woman-cat` | 2 |77 | "One does not simply X" | `mordor` | 2 |78 | "Not sure if X… or just Y" (suspicion) | `fry` | 2 |79 | "False." + a blunt correction | `dwight` | 2 |80 | A forced smile hiding inner pain | `harold` | 2 |81 | Absurd gains from a dumb move | `stonks` | 2 |82 | "X, X everywhere" | `buzz` | 2 |83 | "I'm not saying it's X… but it's X" | `aag` | 2 |84 | Smug delight at chaos you caused | `disastergirl`| 2 |85 | Crude version vs. fancy/refined version of same thing | `pooh` | 2 |86 | An escalating back-and-forth argument | `chair` | 6 |87 | "Y U NO [do thing]" | `yuno` | 2 |8889 If none of these fit the joke, **browse the full catalog** instead of forcing90 a bad fit:9192 ```bash93 meme --list --json # ~200 templates; scan the titles for a better match94 ```9596 **Always verify the chosen id with `meme --list --json` before using it** —97 guessing ids (e.g. `buttons`, `twobuttons`) leads to 404s. The map above is98 accurate, but confirm anything you pull from memory.991002. **Write the funniest version — reason before you render.** Don't ship the101 first phrasing that comes to mind. Briefly draft 2–3 caption options in your102 head and pick the funniest, then render only that one. What makes it land:103104 - **Specificity beats generic.** "the `useEffect` that runs twice" is funnier105 than "a bug." Reach for the concrete, in-context detail.106 - **Punchy and short.** Meme text is read in a second — trim filler words,107 keep each line tight, favor a sharp last word.108 - **Match the template's voice.** Lean into the format's built-in attitude109 (smug `rollsafe`, deadpan `fine`, escalating `gru`, mocking `spongebob`).110 - **Respect the structure.** The funny comes from the *contrast* the template111 sets up — make line A and line B actually play off each other.112 - **Use the user's name/specifics verbatim.** If the user named a person,113 team, tool, or thing ("make a meme about *Raj* and code reviews"), put that114 exact name **into the caption text** — don't genericize it to "my coworker."115 Names and inside-references are what make a meme land for its audience.1161173. **Get the URL (default).** Pass the chosen template id with `-t` (as a flag,118 not the leading word) then the caption lines in the template's natural order,119 and use `--print-url`. This returns a public, permanent memegen.link URL — no120 file is downloaded:121122 ```bash123 meme -t ds "ship it Friday" "wait till Monday" --print-url124 ```125126 Output (just the URL):127128 ```129 https://api.memegen.link/images/ds/ship_it_Friday/wait_till_Monday.png130 ```131132 Mind the line order for the template you picked — e.g. `db` reads133 *new temptation / you / current thing*; `exit` reads *straight road / exit134 ramp / the car*; `fine` is *top speech / bottom "this is fine"*. If a render135 looks off, it's usually line order or count — re-check against `--list`.136137 Using `-t` matters: every call starts with the same `meme -t ...` prefix, so138 the user only has to approve the command **once** — not once per template.1391404. **Give the user the URL** as a clickable link — they can open it in a browser141 or paste it into Slack/GitHub (it renders inline with ``). Don't142 download a file unless they ask for one (see "Saving a local file" below).143144## Saving a local file145146Only when the user explicitly wants a file (to attach it, edit it, or see it pop147open) — drop `--print-url` and instead:148149```bash150meme -t drake "a" "b" --open # saves to a temp folder AND opens it in the viewer151meme -t drake "a" "b" -o ~/meme.png # save to a specific path152```153154By default (without `-o`) a downloaded file goes to a temp folder155(`<tmp>/makememe/`) with a unique name, so it never clutters the user's working156directory.157158## Key flags159160- `--print-url` — return the public URL instead of downloading (the default161 choice; prefer this).162- `--open` — download and open the image in the user's default viewer.163- `-o path.png` — save the download to a specific path.164- `--bg <image-url>` — use a custom background image instead of a template;165 pass caption lines as usual.166- `--ext png|jpg|webp|gif` — output format.167- `--json` — machine-readable output (use when you need to parse it in a script).168169## Tips170171- Number of caption lines depends on the template (`--list` shows each172 template's `lines` count). Most use 2 (top/bottom).173- For an empty line, pass `"_"` (memegen renders it blank).174- Text escaping (spaces, `?`, `/`, `%`, emoji, etc.) is handled automatically —175 just pass natural text in quotes.176- If a caption line starts with `-` (e.g. `"-26%"`), insert `--` before the177 lines so it isn't read as a flag: `meme regret --json -- "-26%" "WHY"`.178 (Flags like `--json`/`-o` go before the `--`.)179- If a download fails, the JSON output includes the `url` and `error` — inspect180 the URL to debug the template id or line count.181182## Examples183184Each picks the template that fits the joke's shape — not all drake:185186```bash187meme -t drake "old way" "new way" --print-url # reject A, prefer B188meme -t ds "merge to main" "open another PR" --print-url # agonizing between two options189meme -t fine "prod is down" "this is fine" --print-url # disaster, pretending it's ok190meme -t gru "write the tests" "tests fail" "fix the code" "tests still fail" --print-url # plan backfires191meme -t same "staging" "prod" "they're the same picture" --print-url # claimed different, identical192meme -t cmm "tabs are better than spaces" --print-url # one-line hot take193meme -t mordor "one does not simply" "deploy on Friday" --print-url # "one does not simply X"194meme --bg https://example.com/cat.png "_" "DEPLOY ON FRIDAY" --print-url # custom background195meme -t success "fixed the bug" "on the first try" --open # only when the user wants a file196```