# Instagram Writer

> Instagram Carousel Writer

- Skill: `tylerprogramming/instagram-writer` (Agent Skill, multi-file: 7 files)
- Install (CLI): `npx skillmds@latest add tylerprogramming/instagram-writer`
- Raw SKILL.md: https://api.skillmd.com/api/skills/tylerprogramming/instagram-writer/raw
- Safety review: pending
- Works with: Claude Code, Claude.ai, OpenAI Codex
- Category: Coding & Dev Tools
- Author: tylerprogramming (https://skillmd.com/u/tylerprogramming)
- Updated: 2026-09-17
- Page: https://skillmd.com/skills/tylerprogramming/instagram-writer

---


# Instagram Carousel Writer

Creates 6-slide Instagram carousels in the @aiwithanushka style that drives saves, shares, and comment-bait CTA engagement.

## Design system (hardcoded in renderer)

- Background: warm cream `#F5F0E8` (default) or a custom image passed as 3rd arg to the renderer
- Primary text: near-black `#1C1C1C`, bold
- Accent: terra cotta `#C4713A` on key words
- Font: Arial Bold, clean and large
- Slide counter: top-left (1/6, 2/6...)
- Dotted grid: top-right decorative element
- Brand: `AI` (terra cotta) bottom-left, `@handle` (gray) bottom-right
- Dimensions: 1080x1350 (4:5 ratio)

## Slide structure

| # | Type | Purpose |
|---|------|---------|
| 1 | cover | Big hook headline - stops the scroll |
| 2 | pain | Relatable problem (question format) + bullets |
| 3 | solution | The answer - key noun in accent color |
| 4 | how | Framework / steps with bullets |
| 5 | results | Proof / outcomes with bullets |
| 6 | cta | Summary lines + giant "Comment [WORD]" |

---

## Step 1: Gather inputs

Ask the user for:
- **Topic** - what the carousel teaches (e.g. "Claude Code skills", "AI content automation")
- **CTA word** - one ALL-CAPS word for the comment CTA (e.g. SKILLS, GUIDE, SYSTEM, LIST, TOOLKIT)
- **Handle** - their Instagram handle (default: `@tylerai_dev`)
- **Renderer** - which rendering framework to use:

  > Which renderer do you want?
  > **1. PIL** (default) - fast, free, pixel-perfect typography. Best for text-heavy carousels.
  > **2. Kie.ai** - AI-generated visuals for every slide. Richer look, ~$0.54/carousel, slower.
  > **3. Hybrid** (recommended) - PIL for text slides, Kie.ai asset for cover logo/visuals. Best of both.

If the user provides a topic in their command, infer CTA word from the topic (e.g. "skills" topic → "SKILLS").

**Renderer notes:**
- PIL → use `instagram_writer.py`
- Kie.ai → use `instagram_kie.py`
- Hybrid → use `instagram_writer.py` (it auto-loads logo assets from `assets/logo-{name}.png` when `"logo"` is set in the cover slide)

---

## Two layouts

This skill renders two ways, chosen by the data rather than by `type`:

- **Rich** - the full treatment: mono rails, display headline, sticky notes,
  icon rows with inline emphasis, tables, terminal proof cards, quad cards.
  Triggered by any of `lines`, `table`, `quad`, `proof`, `note`, `closer`,
  `pill`, `rows`, `hero_path`. **Format: [SLIDES.md](SLIDES.md).**
- **Plain** - the original headline-and-bullets slide, below. Still the default
  for anything not carrying those keys, so old carousels are untouched.

Colours come from `~/social-studio/themes/<id>.json` (`THEME=electric` by
default). The styles these layouts copy, and why, are in
`~/content/BRAIN/instagram/carousel-styles.md`.

## Step 2: Generate slide content JSON

Create the JSON following this exact structure. Headlines must be SHORT lines (3-5 words max each) so the text is BIG and bold.

```json
{
  "topic": "<topic>",
  "handle": "@tylerai_dev",
  "brand_text": "AI",
  "slides": [
    {
      "type": "cover",
      "headline_lines": ["<2-3 words>", "<KEY WORD here>", "<2-3 words>"],
      "accent_words": ["<KEY WORD>"],
      "subtitle": "<One punchy line that hooks them into sliding>"
    },
    {
      "type": "pain",
      "headline_lines": ["Still doing this", "<PAIN WORD>?"],
      "accent_words": ["<PAIN WORD>"],
      "bullets": [
        "<Pain point 1 - short phrase>",
        "<Pain point 2 - short phrase>",
        "<Pain point 3 - short phrase>",
        "<Pain point 4 - short phrase>"
      ]
    },
    {
      "type": "solution",
      "headline_lines": ["The fix:", "<SOLUTION>", "is simpler"],
      "accent_words": ["<SOLUTION>"],
      "subtitle": "<Supporting line>",
      "bullets": []
    },
    {
      "type": "how",
      "headline_lines": ["The", "<FRAMEWORK>"],
      "accent_words": ["<FRAMEWORK>"],
      "bullets": [
        "<Step 1 - 4-7 words>",
        "<Step 2 - 4-7 words>",
        "<Step 3 - 4-7 words>",
        "<Step 4 - 4-7 words>"
      ]
    },
    {
      "type": "results",
      "headline_lines": ["Real", "<RESULTS>"],
      "accent_words": ["<RESULTS>"],
      "bullets": [
        "<Specific result 1>",
        "<Specific result 2>",
        "<Specific result 3>",
        "<Specific result 4>"
      ]
    },
    {
      "type": "cta",
      "summary_lines": [
        "<1-line takeaway from the carousel>",
        "<2nd supporting line>"
      ],
      "cta_action": "Comment",
      "cta_word": "<CTA_WORD>",
      "cta_subtext": "and I'll send you the full guide"
    }
  ]
}
```

### Content rules

- Headlines: 2-3 SHORT lines (3-5 words each) - the text must fill the slide vertically
- Accent words: 1-2 per slide, the most important noun or concept
- Bullets: max 4 per slide, short phrases (4-8 words)
- Pain slide: question format creates scroll-stopping relatability
- CTA word: single ALL-CAPS word, creates urgency to comment
- No em dashes - use commas or plain hyphens with spaces ( - )
- Write for saves first - the information must be worth saving

---

## Step 3: Save JSON and render

1. Create a 2-3 word kebab-case slug from the topic.

2. Set `OUTPUT_DIR=~/content/platform/instagram/<slug>/`

3. Save the JSON:
   ```bash
   mkdir -p ~/content/platform/instagram/<slug>/
   ```
   Write the JSON to `~/content/platform/instagram/<slug>/slides.json`

4. Run the renderer:
   ```bash
   python3 ~/.claude/skills/instagram-writer/instagram_writer.py \
     ~/content/platform/instagram/<slug>/slides.json \
     ~/content/platform/instagram/<slug>/
   ```

   To use a custom background image (e.g. a watercolor texture from Kie.ai):
   ```bash
   python3 ~/.claude/skills/instagram-writer/instagram_writer.py \
     ~/content/platform/instagram/<slug>/slides.json \
     ~/content/platform/instagram/<slug>/ \
     ~/path/to/background.png
   ```
   The image is cover-cropped to 1080x1350 with a subtle white overlay for text readability.

   Output:
   - `slide_01.png` through `slide_06.png` - individual slides
   - `carousel.pdf` - combined PDF for Blotato upload

---

## Step 4: Write the caption

**Short.** Forty words is the ceiling, and fewer is usually better.

```
<One line that matches slide 1 and promises the payoff>

Comment <CTA_WORD> and I'll send it.

#claudecode #aiagents #ai #<topic> #carousel
```

### Why short

The carousel is the content. The caption's only job is to get the comment,
because a comment-gated payoff is what produces the comment count. Everything
you would have explained in paragraph three is already on slide four, and
nobody reads past "... more" to find it.

Measured on the two carousels in the swipe file, both of which out-saved
anything of ours:

| | Caption | Comments | Saves |
|---|---|---|---|
| @ibraviz.ai | "Comment JARVIS for the setup!" - 6 words | 4,026 | 10.4K |
| @albert.olgaard | "Comment 'Famous' for the skills" - 5 words | - | 219 |

Ours have been running 180 to 197 words. Reach explains a lot of that gap and
caption length is not the only variable, so treat this as a strong prior rather
than a proven cause - but the direction is one-way, and a short caption costs
nothing to test.

### Rules

- **First line is the hook**, visible before "... more". Promise the payoff.
- **One comment CTA**, naming the keyword. That is the whole point of it.
- **Under 40 words** before the hashtags. If it needs a second paragraph, that
  paragraph belongs on a slide.
- **Five hashtags**, the set above.
- No em dashes.

### Hashtags

Five, in slots. Three fixed, two that change per post:

```
#claudecode #aiagents #ai #<topic> #carousel
```

| Slot | Value | Why |
|---|---|---|
| Tool | `#claudecode` | fixed |
| Category | `#aiagents` | fixed |
| Broad | `#ai` | fixed |
| **Topic** | `#mcp`, `#arcade`, `#jarvis`, `#obsidian` | **changes every post** |
| Format | `#carousel` | fixed |

The topic slot is the part copied from @ibraviz.ai, the only reference whose
tags were visible: `#claude #claudecode #ai #jarvis #reel`. Four of their five
describe the tool or the category; the fifth names **what the post is about**.
That is the one doing work a tool tag cannot - it reaches people searching the
subject rather than the software.

They tagged a carousel `#reel`, which we are not copying. Tag the format you
actually posted.

Honest note on `#aiagents`: it did not appear on any captured screenshot. It is
in the set because it is the category we want to be found in, not because it
was observed. Treat it as a deliberate bet, and if a post is not about agents,
swap it for something truer rather than leaving it in out of habit.

Save the caption to `~/content/platform/instagram/<slug>/caption.md`

---

## Step 5: Update status.md

After rendering (and again after scheduling), update `~/content/platform/instagram/status.md`:

| Slug | Topic | Created | Scheduled | Posted |
|------|-------|---------|-----------|--------|
| claude-code-skills | Claude Code skills | 2026-04-09 | Apr 10 12pm | - |

---

## Step 6: Present results

Show the user:
1. A summary of each slide's content (1 line each)
2. The full caption
3. File paths:
   - Slides: `~/content/platform/instagram/<slug>/slide_01.png` through `slide_06.png`
   - PDF: `~/content/platform/instagram/<slug>/carousel.pdf`
   - Caption: `~/content/platform/instagram/<slug>/caption.md`
4. Ask if they want to schedule via Blotato or adjust any slides

## Step 7: Save to carousel app Library

After generating carousel content, also save a JSON to the carousel maker app so it appears in the Library drawer:

```
~/carousel-maker/carousels/carousel_<timestamp>.json
```

JSON format:
```json
{
  "id": "carousel_<timestamp>",
  "title": "Carousel Title",
  "platform": "instagram",
  "slides": [
    {
      "id": "slide_0_<timestamp>",
      "type": "cover|content|cta",
      "slideNumber": 1,
      "headline": "Main Headline",
      "emphasisLine": "Accent line",
      "bodyText": "Body text.",
      "bgColor": "#F5F0EB",
      "textColor": "#1B1B1B",
      "accentColor": "#E07355"
    }
  ]
}
```

Slide types: `cover` (slide 1), `content` (slides 2-5, include `stepNumber`), `cta` (slide 6).

This keeps the carousel app Library and `~/content/platform/carousels/<slug>/` in sync. Always write to both locations.

