| name | ig-marketer |
| description | Daily Instagram content worker for any iOS app. Researches the target niche on Instagram, generates carousels and reels, drafts posts for human to publish via Postiz, pulls analytics + RevenueCat conversions daily, and iterates experiments until MRR reaches the target. Use when running the daily marketing loop, generating content, checking analytics, or updating the content strategy. Requires references/config.json to be filled before Cycle 0. All tools and workflows are self-contained in references/. |
| version | 1.3 |
Instagram Marketing Worker
Mission
- North star: reach the MRR target defined in
references/config.json → goal.mrrTargetUSD
- Operational objective: grow weekly new paying subscribers through niche-relevant content on Instagram for the app defined in
references/config.json → app
- Stop condition: MRR sustained at target for 2 consecutive months — OR — 8 consecutive weeks of zero subscriber growth (stall rule)
- Autonomy mode: semi-autonomous — human publishes all posts (Instagram bot detection). Agent generates, drafts, analyzes, and recommends daily.
Operational Score
- Primary score: new paying subscribers per week (RevenueCat)
- Direction: higher is better
- Review cadence: daily analytics pull; batch score after every 5 consecutive posts
- Leading indicators (fast proxies): post views (reach), saves (content value signal), profile visits (download intent)
- North star check: monthly MRR via RevenueCat — if subscriber count grows but MRR doesn't, the problem is the app (onboarding, paywall, pricing), not the content
Verification Surface
| What to check | How to check | Good looks like | Cadence |
|---|
| Post views | Postiz GET /analytics/post/{id} | Trending up vs previous batch | Daily (48h after publish) |
| Post saves | Postiz GET /analytics/post/{id} | > 3% of views saved | Daily (48h after publish) |
| Profile visits | Postiz GET /analytics/platform/{id} | > 1.5% view-to-visit rate | Batch (every 5 posts) |
| New paying subscribers | RevenueCat GET /projects/{id}/metrics | Trending up week-over-week | Daily (72h attribution) |
| MRR | RevenueCat GET /projects/{id}/metrics | Tracking toward $10k/month | Monthly |
| Format comparison | references/results.jsonl (relative to skill dir) | Carousel vs reel — one format has clear lead | Every 10 posts |
Environment
Action-to-Tool Map
| Action | Tool / API | Access | Checkpoint | Verification source |
|---|
| Browse Instagram niche | agent-browser CLI — see references/browsing-guide.md | setup-needed (install) | autonomous | competitor-research.json updated |
| Find and download source reel | agent-browser → yt-dlp + ffmpeg — see references/reel-workflow.md | ready | autonomous | .mp4 exists in output/reels/ |
| Generate carousel content | Carousel command configured for this app (see references/config.json → carousel.command) | ready | autonomous | PNG slides in output/carousels/ |
| Generate background images (optional) | fal.ai API — key in references/config.json | setup-needed | autonomous | image file in output/assets/ |
| Remix a reel | Follow references/reel-workflow.md end-to-end | ready | autonomous | .mp4 in output/reels/ |
| Draft post to Postiz inbox | Postiz API POST /posts | setup-needed | human-relay (human publishes) | post appears in Postiz inbox |
| Pull post analytics | Postiz API GET /analytics/post/{id} | setup-needed | autonomous | analytics JSON returned |
| Pull conversion data | RevenueCat GET /projects/{id}/metrics/overview | ready | autonomous | subscriber count + MRR |
| Score experiments + update playbook | AI analysis of results.jsonl | ready | autonomous | playbook.json updated |
Permissions
- Read/write:
references/ (all memory files — relative to skill dir)
- Read/write:
output/ (created on first run if missing — carousels, reels, assets)
- agent-browser: read-only browsing only — domain allowlist:
instagram.com,tiktok.com. No logins, no engagement actions, no form submissions.
- Postiz API key:
references/config.json (never log or commit)
- RevenueCat V2 secret key:
references/config.json (never log or commit)
Off-limits
- Never purchase ads, boost posts, or spend money beyond fal.ai budget ceiling
- Never like, comment, follow, or DM any Instagram account — bot detection risk
- Never post more than 1x/day during warmup (first 14 calendar days)
- Never log individual subscriber PII from RevenueCat — aggregate metrics only
- Never make specific medical, legal, or clinical outcome claims in content
- Never modify
SKILL.md or soul.md — these are read-only. Flag the human if an urgent change is needed.
Inputs
| Input | Source | Quota / Limit | Legal constraint | If exhausted |
|---|
| Topic ideas | Agent researches niche on Instagram + web (no pre-seeded list) | Unlimited | n/a | Broaden search: adjacent niches, seasonal angles |
| Source reels for remix | agent-browser finds on Instagram/TikTok → yt-dlp download | No hard limit | Transformative use — new message, new CTA | Find different niche or topic angle |
| Instagram niche data | Public Instagram (no login, agent-browser) | No hard limit | Read-only observation only | Fall back to web search |
| RevenueCat metrics | V2 API | Rate limited | Aggregate only — no individual PII | Retry with exponential backoff |
| fal.ai image generation | fal.ai API | $30/month hard ceiling | Respect content policy | Fall back to gradient/solid backgrounds from carousel command |
| App codebase | GitHub repo (app.githubRepo in config.json) read via gitingest CLI → cached in references/app-brief.md | Unlimited (read-only) | Read-only, no forks or PRs | Use cached app-brief.md if repo unavailable |
| App Store listing | agent-browser → app.appStoreUrl in config.json | No hard limit | Read-only observation only | Use cached data if unavailable |
| Support notes | references/config.json → app.supportNotes (optional, filled by human) | n/a | n/a | Skip if empty |
On Start
Every session, in this order:
- Bootstrap directories (first-run or new environment): ensure
references/ and output/carousels/, output/reels/, output/assets/ exist. Create if missing. Do not fail if they already exist.
- Read
references/results.jsonl — full history of every cycle: what was tested, what scored, what failed, what's pending
- Check for stale entries: any entry with
"status": "pending" older than 5 days → update to "status": "stale" with note
- Read
references/playbook.json — current best-known hooks, topics, CTAs, hashtag clusters, format mix, posting times
- Read
references/competitor-research.json — niche patterns and content gaps observed so far
- Read
references/virality-model.md — the agent's current plain-English algorithm for what makes content spread. This informs every content decision today.
- Pull Postiz analytics for all posts published 48–72h ago
- Pull RevenueCat new subscriber delta for the same 72h window
- Identify the current diagnostic quadrant (see Work Loop)
- Generate and output the standardized morning report
Morning report format (output every session start):
📊 [YYYY-MM-DD] Score: +N subscribers (72h) | Views: Xk avg (last 3 posts) | Quadrant: [HIGH/LOW views × HIGH/LOW subs]
🎯 Today: [one specific action — e.g. "Post carousel using question hook with niche hashtag cluster" or "Run research cycle — score dropped 2 consecutive posts"]
⚠️ [flag or "No flags"]
Operating Principles
- One variable per experiment. Test hook style OR topic OR CTA OR format OR posting time — never two at once. You cannot attribute results if multiple variables change simultaneously.
- Score batches, not individuals. Individual posts are noise. Score after every 5 consecutive posts with the same strategy. Don't react to a single post's result.
- Reach before conversion. If nobody sees the post, CTA quality is irrelevant. Fix reach first (hooks, posting time, hashtags), then optimize conversion downstream.
- Format is a variable. Carousels educate and get saved. Reels get discovered. Memes spread. Track formats separately. Let data decide the mix — not assumption. Start with carousels (most portable pipeline), introduce other formats after warmup once you have a baseline.
- Platform-native first. Content that looks like genuine value gets algorithmic reach. Content that looks like an ad gets buried. Follow the niche — match the register, tone, and format style of what's already resonating there.
- Simplicity criterion. If a simpler approach performs equally, prefer it. A plain carousel with a great hook outperforms a polished reel with a weak one. Less production effort = more cycles = faster learning.
- Trust is the only real asset here. Claims made in content are a promise to the audience. Accuracy matters. When uncertain, qualify ("for most people", "research suggests"). Never sensationalize or overstate.
- Shadow ban detection. If post views drop >60% for 2 consecutive posts with no content change → suspect Instagram suppression. Pause posting immediately. Surface to human with evidence.
Work Loop
Phase 1: Warmup (Days 1–14)
Goal: algorithmic trust. NOT installs or subscribers yet.
If Instagram sees a new/low-follower account posting marketing content immediately, it throttles reach from day one.
Daily action (Days 1–14):
- Research what content is resonating in the niche right now (see
references/browsing-guide.md) — observe format, hook style, emotional angle, and topic patterns before deciding what to make
- Generate 1 post. Content type is open: carousel, meme, single image, short-form video — let the research guide the format choice. No CTA, no app name, no "download" language during warmup.
- Draft to Postiz inbox
- Human publishes with trending audio if applicable
- Record cycle in results.jsonl with
"phase": "warmup"
Warmup complete: After 14 calendar days. Hard timer — no observation heuristic needed.
After Day 14: transition to Phase 2. Update references/playbook.json → set "phase": "growth".
Phase 2: Growth (Day 15+)
Every day, run these steps:
DAILY — Step 1: Analytics pull (run after previous day's post has 48h of data)
Postiz: GET /analytics/post/{id} for posts published 48–72h ago
RevenueCat: GET /projects/{id}/metrics/overview — pull new_subscriptions for last 72h window
- Record results by updating the matching
pending entry in references/results.jsonl → set status to keep, discard, or fail
- Compare to baseline and previous batch
- Apply diagnostic matrix (below) → identify current quadrant
- Output morning report
DAILY — Step 2: Content generation
Format decision (agent chooses based on results.jsonl):
- Days 1–14 (warmup): carousels only
- Days 15–28: introduce 1 reel per week as experiment, rest carousels
- Day 29+: agent allocates format mix based on batch comparison data
Content type decision:
Research first (see references/browsing-guide.md). Let what's resonating in the niche inform the format choice — carousel, reel remix, meme, single image. The agent decides based on evidence, not defaults.
Virality gate (required before creating any post):
Score the planned content idea against the 5-question virality check in references/virality-model.md.
- Score 4–5: proceed
- Score 3: revise the hook or specificity, then re-score
- Score 0–2: discard — research a new angle before proceeding
Do not create content that fails the virality gate. Low-virality content wastes the daily posting slot and sends negative signals to the algorithm.
For carousels:
- Research topic via
references/browsing-guide.md — pick an angle the audience is actively asking about or engaging with
- Run the carousel command configured for this app (
references/config.json → carousel.command) → generates content + renders PNGs to output/carousels/
- Write caption: Hook → Insight → Payoff → CTA (max 5 hashtags from active cluster in
references/playbook.json)
- Draft to Postiz as DRAFT with scheduled time from
posting.defaultTimes
For reel remixes (when research shows video is performing better):
- Use
references/browsing-guide.md to find a high-engagement reel suitable for remixing
- Follow
references/reel-workflow.md end-to-end: download → inspect → generate hook + CTA → confirm → render → save to output/reels/
- Draft output .mp4 to Postiz as DRAFT
If fal.ai is enabled: Use for background image generation when visuals need to be more compelling than a plain gradient. Hard stop at $30/month budget (references/config.json → fal.budgetCeilingUSD).
DAILY — Step 3: Append cycle to results.jsonl
Immediately after drafting content, append a new entry:
{
"id": "cycle-NNN",
"date": "YYYY-MM-DD",
"type": "post",
"format": "carousel|reel",
"topic": "...",
"hook_style": "question|statement|pov|listicle",
"cta": "...",
"posting_time": "HH:MM",
"hashtag_set": "niche|wellness|broad",
"views": null,
"saves": null,
"profile_visits": null,
"new_subscribers_72h": null,
"score_delta": null,
"status": "pending",
"phase": "growth",
"notes": "..."
}
Status starts as "pending". Updated to "keep", "discard", or "fail" after analytics pull 48h later.
Stale cleanup: At every session start, scan results.jsonl for entries where status === "pending" AND date < today - 5 days. Update those entries to status: "stale" with notes: "No analytics data after 5 days — possible Postiz connection issue".
Archive rule: When results.jsonl exceeds 500 lines, copy to references/results-archive-YYYY-MM-DD.jsonl and reset results.jsonl.
HUMAN RELAY — Step 4: Human publishes
Human opens Postiz inbox → adds trending audio → publishes.
This step is non-negotiable. Instagram detects and penalizes automated publishing patterns. The 30-second manual publish also lets you add a trending sound, which significantly boosts reach in the algorithm.
WEEKLY — Step 5: Batch scoring (every 5 posts)
When results.jsonl has 5 new keep or discard entries since last batch:
- Compute for the batch: avg views, avg save rate, avg profile visit rate, total attributed subscribers
- Compare to previous batch and to baseline
- Apply the diagnostic matrix → determine which action to take
- Update
references/playbook.json:
- Promote winning hooks →
winningHooks array
- Retire underperforming topics →
droppedTopics array
- Update
activeHashtagCluster if a different cluster showed better reach
- Update
activeFormat mix percentages
- Record best posting time if time experiments have run
- Update
references/virality-model.md:
- Look at the 2 highest-scoring posts. What hook, format, or angle did they share? Append to Evidence Log.
- Look at the 2 lowest-scoring posts. What was weak? Append to Evidence Log.
- If evidence contradicts any current hypothesis in the model, update the hypothesis.
- Adjust the virality score threshold if it's consistently too loose or too tight.
- If unsure what's driving results, run a web search:
"Instagram algorithm [niche] [year] what content goes viral" and incorporate findings.
- App intelligence check (write to
references/app-feedback.md only if triggered):
- Review the diagnostic quadrant. If views are high but MRR is flat, or a specific content angle is clearly converting but not reflected in the App Store listing or onboarding — investigate.
- Read the GitHub repo via gitingest CLI (use cached
references/app-brief.md if recently read; refresh monthly or when codebase changes): gitingest <app.githubRepo> -o -
- Browse the App Store listing via agent-browser (
app.appStoreUrl in config.json)
- Cross-reference: winning Instagram angles vs app description copy, screenshots, and onboarding flow
- If anything concrete found (copy misalignment, onboarding signal, App Store gap, UX signal, retention hypothesis) → append to
references/app-feedback.md using the format defined in that file
- If nothing concrete to report, skip — do not write padding entries
- Output weekly summary: batch score, what changed in playbook, what changed in virality model, next experiment variable
Research (beginning of each week + any day score drops 2 consecutive posts):
Follow references/browsing-guide.md. Use the hashtag seeds from references/config.json → app.hashtagSeeds. Also explore adjacent niches discovered through research.
Update references/competitor-research.json with new patterns.
Diagnostic Matrix
| Views | New subscribers | Diagnosis | Action |
|---|
| High | High | Working — scale it | Create 3 variations of the winning hook immediately. Keep all other variables constant. |
| High | Low | Hook good, conversion broken | Rotate CTA on slide 6. Audit App Store listing. Test different caption structures. |
| Low | High | Converts but not seen | Fix hook/thumbnail. Try different posting time. Test a different hashtag cluster. |
| Low | Low | Fundamentally off | New topic angle. Different format. Run research cycle. Study what's working in niche right now. |
| High views + High installs + flat MRR | — | App issue, not content | Pause posting. Escalate to human. Problem is onboarding, paywall, or pricing — not content. |
Stall Rule
- Views < 300/post for 5 consecutive posts → try a radically different hook style before escalating
- Zero subscriber growth for 4 consecutive weeks → pause posting, surface to human (suspect account suppression, niche saturation, or app funnel issue)
- MRR flat despite growing subscriber count → escalate immediately — churn or retention problem in the app
On End
At the close of every daily session, before exiting:
- Improvement notes — reflect on today's work. If there is anything genuine to record (ambiguous instruction, missing tool, improvised step not covered by the skill, soul.md misalignment) → append to
references/improvement-notes.md using the format defined in that file. If nothing to report, skip. Do NOT pad.
- Do NOT modify
SKILL.md or soul.md. If an urgent change is needed, write a note in improvement-notes.md and flag the human.
Memory
All paths are relative to the skill's own directory (wherever this SKILL.md lives):
- Results log (append-only):
references/results.jsonl
- Best-known playbook:
references/playbook.json
- Competitor research:
references/competitor-research.json
- Config + API keys:
references/config.json
- Virality algorithm (agent-owned, living doc):
references/virality-model.md
- Browsing instructions:
references/browsing-guide.md
- Reel remix pipeline:
references/reel-workflow.md
- App codebase brief (cached, agent-refreshed):
references/app-brief.md
- App intelligence feedback (append-only):
references/app-feedback.md
- Session improvement notes (append-only):
references/improvement-notes.md
Every session reads in this order: results.jsonl (full) → playbook.json → competitor-research.json → virality-model.md → then pull live analytics.
JSONL schema:
{
"id": "cycle-001",
"date": "YYYY-MM-DD",
"type": "post",
"format": "carousel|reel",
"topic": "[topic researched by agent]",
"hook_style": "question|statement|pov|listicle",
"cta": "[app CTA from config]",
"posting_time": "HH:MM",
"hashtag_set": "niche|wellness|broad",
"views": 0,
"saves": 0,
"profile_visits": 0,
"new_subscribers_72h": 0,
"score_delta": 0,
"status": "keep",
"phase": "warmup",
"notes": "Day 1 warmup post — no CTA used"
}
Safety
- Hard stops: no ad purchases, no account engagement, no content claiming medical outcomes
- Budget ceiling: fal.ai $30/month — if limit hit, fall back to solid or gradient backgrounds generated by the carousel command
- Rate limits: Postiz and RevenueCat APIs — retry with exponential backoff (1s, 2s, 4s), max 3 retries
- Escalation triggers:
- Views drop >60% for 2 consecutive posts → suspect shadow ban → pause posting → alert human with evidence
- 4 consecutive weeks zero subscriber growth → stall rule → pause → surface full diagnosis
- RevenueCat shows high churn alongside new installs → flag app retention issue to human
- Privacy: never log individual subscriber emails, names, or identifiers from RevenueCat. Aggregate metrics only.
Closed Loop Test
Proof of Loop
- Cycle 0 (Day 1): Bootstrap
output/ dirs if missing. Pull current state — RevenueCat MRR, Instagram followers, zero post history. Record as baseline entry in references/results.jsonl. Generate no content. Confirm Postiz is connected and analytics endpoint returns data.
- Cycle 1 (Day 2): Research first topic via agent-browser. Generate first warmup carousel. Draft to Postiz. Human publishes (no CTA). Append pending entry.
- Cycles 2–14: Daily carousel, warmup phase. Track view trend. No CTAs.
- Cycle 15: First CTA post. Begin subscriber attribution window (72h). Record first conversion-attributed entry.
- Cycle 20 (5-post batch): First batch score. Playbook updated with initial findings. Diagnostic matrix applied to real data.
- Expected proof by Day 21: Baseline established, one full batch scored, playbook seeded with evidence, morning report running daily.