Framezero
FreeNot checkedReverse-engineer what actually works on a niche's Instagram Reels, and turn it into a reusable script-writing skill.
About
Reverse-engineer what actually works on a niche's Instagram Reels, and turn it into a reusable script-writing skill.
README
Find out what actually works on a creator's Reels — then write in their voice.
Point it at a public handle. It pulls every reel with real play counts, scores each one
against that creator's own baseline, and tells you which subjects beat that baseline,
how the winners open, and whether the follower count and the view count even agree.
Then it transcribes the outliers locally and hands your agent a skill that writes like them.
Quickstart · Profile a creator · Topics & hooks · The findings · Voice · For AI assistants · How the scraping works
No login · No cookies · No paid scraping service · No transcription API
Runs on your machine for the cost of electricity.
🎯 The gap this fills
Everyone writing for social media has a creator they wish they sounded like.
The market splits in two and nothing bridges it. Some tools find a creator's best reels — they sort by views. Others explain one reel — hook, pacing, structure. The ones claiming to do both and "write in your competitor's voice" are, on inspection, generic models over a generic viral corpus. The output is not grounded in that specific creator's transcripts at all.
framezero does the grounding. Four things follow from that, and no other tool does any of them:
📈 Outlier score, not viewsEvery reel is scored against the median of its own neighbours in a ±90 day window. A 100K-view reel from when they had 20K followers is a far bigger signal than a 100K-view reel today. Sorting by raw views — all the paid tools do — mostly surfaces recent work. |
⚖️ Controls, not just winnersIt transcribes the worst performers alongside the best. Studying only winners is survivorship bias: you learn what all their videos do, not what the winning ones do differently. The delta is the whole point. No SaaS does this — it doubles their transcription bill. |
🎙️ Voice as numbers16 measured dials — who sentences address, how long they run, which phrases recur — each with a target band. "Sound like them" stops being an instruction to vibe and becomes a target you can fail and fix. |
🚫 And the point of all of it: mechanics, not scripts
Copying someone's scripts makes you a knock-off of an account that already has the audience. So the tool is built to separate what transfers from what does not — and to refuse to hand you the second column.
| Transfers | Doesn't |
|---|---|
| The shape of a hook | The exact hook words |
| Which subjects beat their baseline | Their face, their story, their followers |
| Structure, pacing, CTA placement | Their captions, verbatim |
| Whether their audience is even real | Their voice, pasted into your mouth |
Which is why voice is stored as bands rather than sentences, why a finding needs a second creator before it becomes a rule, and why every mined topic is held to a false-discovery correction before it is allowed to be called a finding at all. On one real account the uncorrected version confidently reported a subject at 10× baseline. It was noise. Four of 132 survived.
🕵️ Don't know whose work to study?
That is the question that comes before everything else, and guessing handles is how people waste their first hour.
./framezero neighbours # from catalogues already on disk
./framezero neighbours <handle> --probe # and check they have an audience
Creators tag each other, run collabs, and name each other in captions. All of
that is already in the index you paid for. neighbours ranks those handles by
how many of your creators point at them — because two unrelated accounts
naming the same person is a niche, while one account tagging somebody four
hundred times is a business partner.
--probe then samples each candidate and reports median plays, so you find out
which names have an audience before you commit to any of them. It has already
killed a candidate that looked ideal and turned out to run 150 plays a reel.
It will not find the ones nobody tags, and a tag is not a similarity — read the profile before you trust the name.
🔎 Profile any creator in a minute
Before you spend an hour transcribing anyone, find out who they are.
./framezero profile <handle>
One scrape, no whisper, about sixty seconds. That single command runs three
free stages and writes six files — profile.md, topics.md, hooks.md, their
JSON twins, and posts.csv, which opens straight in Excel or Sheets with hook,
topics and hook_shapes as their own columns.
Identity — name, bio, category, verified, follower and following counts, bio links, external URL Reach — median / mean / top-decile / best / worst plays, engagement as a share of plays, plays per follower Trajectory — median plays per quarter, drawn as bars | Monetisation — disclosed paid partnerships, who sponsored them, recurring tagged accounts, and the caption CTA they actually run Format habits — reel duration spread, aspect ratio, original audio vs licensed music, post types, top hashtags Neighbours — Instagram's own related accounts. The cheapest possible answer to "who else should I study?" |
Two gates before you spend an hour
Does the audience match the views? The first thing to ask about anyone you are about to learn from — and a ratio nothing else in the tool could judge.
| plays per follower | 0.02 — not credible |
| engagement | 1.70% of plays — weak |
**The numbers do not add up.** 1,000,000 followers against a recent median of
20,000 plays is 0.02 plays per follower, with engagement at 1.7% of plays. Both
signals are low together, which is the shape of a follower count that no longer
describes a live audience. Study the reels if you like — but do not treat the
follower number as evidence that any of this worked.
Two signals, and both are needed: low reach with healthy engagement is a big dormant list with a real core, low reach with low engagement is an audience that is not there. Compared against recent reels only, because followers is one number describing today and an all-time median would punish every account that has grown.
And the one that decides whether the winners are doing anything different:
## Is there anything to learn here?
**Yes — wide spread.** Their best reels run 3.5× their own median, so something
separates them and it is worth transcribing to find out.
- top decile: 484,420 (3.5× median)
- median: 138,946
- bottom decile: 53,647 (0.39× median)
If that multiple sits near 1, the account's winners are not doing anything different — they got luckier. The expensive pass would find nothing, and the dossier tells you so for the price of one scrape.
[!NOTE] Three things it will not pretend to know. Instagram returns one follower number, today — so the trajectory is median plays per quarter, a proxy, never presented as follower growth.
paid_partnershipis the disclosed flag only; sponsor tags and caption CTAs catch more, never all. And location appears only where the creator tagged it, which is usually nowhere.
🪝 What to make, and how to open it
Copying a creator's scripts makes you a knock-off of someone who already has the audience. The parts that actually transfer are narrower than that: which subjects beat their baseline, and the shape of how they open. Both are measured from data already on disk — no extra requests, no transcription.
Topics — what to make
./framezero topics <handle>
./framezero topics <handle> --define specs/real-estate.topics.txt
A creator averaging 10,000 plays who reliably hits 50,000 on one subject has
told you something you can act on tomorrow. topics.md opens with the brief:
1. **github** — 27 reels at 1.61× baseline, median 95,066 plays against
67,036 for the account. 59% of them beat their own neighbourhood.
**And what costs them:**
- **new cohort** — 13 reels at only 0.55× baseline, median 41,245 plays.
Three lenses — topics you declare, the creator's hashtags, and phrases mined from caption bodies — scored in outlier units against a ±90-day rolling median, so a subject cannot look good merely because they posted it while they were growing.
[!IMPORTANT] The statistics are the feature. Testing six hundred mined terms against one catalogue guarantees a few clear any fixed threshold by luck — on a real account, the naive version reported a subject at 10× baseline that did not exist. Every topic now gets a Mann-Whitney rank-sum test against the rest of the catalogue, and the whole family is held to a Benjamini-Hochberg false-discovery rate. Of 132 topics tested on that account, four survived. Anything that does not is reported as inconclusive, never as a finding.
Two smaller guards that matter as much: a bare lowercase word is nearly always an adjective — easy, complex, remove — so single words are kept only when the creator capitalises them mid-sentence, which is the free test for a product, brand or place name. And topics covering the same reels collapse into one row, so eleven phrasings of one boilerplate caption stop crowding out the real findings.
Hooks — how to open it
./framezero hooks <handle>
./framezero hooks <handle> --define specs/real-estate.hooks.txt
The hook is the single most transferable unit in a reel. Take the shape, never the sentence.
| | outlier | plays | opening line | shape |
|---|--------:|----------:|-------------------------------------------------|-------|
| W | 19.71× | 3,218,105 | You can now run <tool> for completely free | free, capability |
| W | 9.40× | 1,540,574 | Don't use <tool> unless you've installed these… | contrarian |
| C | 0.17× | 25,714 | A very nifty email hack that I'm about to show… | demo |
| C | 0.09× | 9,084 | <tool> just launched X and it's basically… | news |
Two lenses, because the good data and the plentiful data are not the same data. The spoken hook comes from the transcripts — only the ~30 reels in the study set, and that set is designed to be the two tails, so it is tested with Fisher's exact on winners against controls rather than pretending to be a random sample. The written lens reads the first line of every caption in the catalogue, hundreds of them, free, and carries the same rank-sum and correction as topics.
Read the table before the statistics. Thirty hooks you can see beat any test run on thirty rows, and the file says so.
One real account led 388 of its 396 captions with Comment "WORD" to get….
Measured naively, its "hook" was its funnel. That clause is now stripped before
matching and the share is reported.
And then — does it hold for anyone else?
./framezero signals <project> --mode informational
./framezero signals <project> --handles handle_a,handle_b
A subject that works for one creator is that creator's territory. The same REPLICATED / CONTESTED / SINGLE / DEAD verdicts the structural pass uses, applied to subjects and hook shapes:
| topic | verdict | creators | @creator_a | @creator_b |
|--------|------------|---------:|-----------:|-----------:|
| github | REPLICATED | 2 | 1.61× | 1.34× |
Two independent accounts, each surviving its own correction, pointing the same way. That is the strongest claim this tool makes about anything — and it is the only class that should ever become a rule.
[!TIP] Hook shapes replicate more meaningfully than subjects do. Every creator is scored against the same archetype list, so those names line up by construction. Two creators only share a topic name when they happen to use the same word for the same thing — which is exactly why
--definewith a shared spec is worth the ten minutes.
🤖 Made to be driven by an assistant
Nobody is going to use this raw. They are going to point Claude, Cursor or Codex at it — so the tool ships for that.
An MCP server, standard library, no install:
claude mcp add framezero -- python3 "$(pwd)/bin/mcp_server.py"
| tool | what it gives the assistant |
|---|---|
list_projects |
what already exists on disk |
profile_creator |
the full dossier, scraping if needed |
creator_topics |
which subjects beat their own baseline |
creator_hooks |
how they open, and whether it separates winners |
replicated_signals |
subjects and hooks that hold across creators |
findings |
which structural features REPLICATED across creators |
creator_report |
one creator's winner-vs-control deltas |
voice_profile |
the 16 dials and signature phrases |
check_script |
score a draft, before the user ever sees it |
transcripts |
the corpus, by cohort |
run_pipeline |
the slow full pass, flagged as slow |
Structured output everywhere. Every stage writes markdown and JSON —
profile.json, voice.json, ranked.json, index.json — plus posts.csv for
a spreadsheet. Markdown for the human, JSON for the agent, same numbers.
AGENTS.md is a full onboarding file: preflight, install per
platform, what to ask the user, which outputs to read in which order, the
mandatory draft-check loop, and the ground rules. CLAUDE.md, GEMINI.md and
.github/copilot-instructions.md point at it, so every assistant lands in the
same place.
⚡ Quickstart
1 · Install
# macOS
brew install ffmpeg whisper-cpp
# the model, once — ~1.6 GB
mkdir -p ~/.whisper/models
curl -L -o ~/.whisper/models/ggml-large-v3-turbo.bin \
https://huggingface.co/ggerganov/whisper.cpp/resolve/main/ggml-large-v3-turbo.bin
Python 3.9+, standard library only. No pip install. No API keys. No account.
Linux: apt install ffmpeg and build whisper.cpp from source — full commands in AGENTS.md.
2 · Describe your niche and whose work you want to learn from
./framezero new myproject \
--niche "AI, automation and workflow software" \
--vocabulary "ChatGPT,Claude,n8n,Make.com,Zapier,Cursor" \
--mode informational=creator_a,creator_b \
--mode tech-demo=creator_c \
--mode funny=creator_d,creator_e
Modes are yours to name. informational, teaching, tech-demo, funny, storytime, reviews — whatever divisions your niche actually has. Creators map to the mode you study them for, and the same creator can appear under more than one. Pooling a comedy account with a tutorial account compares two different crafts, so the pipeline keeps them apart.
[!TIP] Give every mode at least two creators. With one, nothing can replicate, and every finding comes back as a bet rather than a rule.
3 · Look at them before you spend the hour
./framezero profile creator_a # ~60s each. No whisper, no hour.
./framezero profile creator_b
./framezero signals myproject --handles creator_a,creator_b
Three questions answered before you commit to anyone:
- Is the audience real?
profile.mdreads plays-per-follower against engagement, over recent reels only. If the numbers do not add up, it says so. - Do their winners differ from their flops? If the top decile sits near the median, the expensive pass will find nothing.
- Does anything hold for both of them?
signalsgives subjects and hook shapes the REPLICATED / CONTESTED / SINGLE / DEAD treatment.
Drop anyone who fails the first two. That is the whole point of this step.
4 · Run it
./framezero run myproject # safe to repeat; every stage skips work already on disk
./framezero show myproject # progress, any time
$ ./framezero show myproject
project: myproject niche: AI, automation and workflow software
vocabulary: ChatGPT, Claude, Claude Code, Gemini, n8n, Make.com, Zapier …
informational:
- creator_a (227 reels, 33 transcribed)
- creator_b (395 reels, 48 transcribed)
tech-demo:
- creator_b (395 reels, 48 transcribed)
Narrow it with --mode funny, --only handle, --top 15 --bottom 15.
5 · Hand the outputs to your agent
data/_projects/<p>/<mode>.md ← START HERE — which STRUCTURE replicates
data/_projects/<p>/signals-<mode>.md ← which SUBJECTS and HOOK SHAPES replicate
data/<handle>/profile.md ← who they are, and is the audience real
data/<handle>/topics.md ← which subjects beat their own baseline
data/<handle>/hooks.md ← how the winners open — the transferable part
data/<handle>/report.md ← that creator's countable deltas (structure)
data/<handle>/voice.md ← how they SOUND — dials + signature phrases
data/<handle>/corpus.md ← the transcripts themselves (read LAST)
prompts/extract.md, prompts/emit.md ← how to turn all that into skills
The two _projects files come first for a reason: they are the only files in
the tree that have been checked against a second creator.
Your agent writes one skill per mode into out/skills/. There is a whole
file — AGENTS.md — written for it.
6 · Check every draft before you record it
./framezero check draft.txt --like creator_b --wpm 176
voice check — draft.txt vs @creator_b
runtime at 176.0 wpm: 55s their winners ran 23–57s ok
dial script target verdict
--------------------------------------------------------------------
second person /100w 6.17 4.26 – 7.77 ok
first person sing /100w 1.23 0.47 – 2.24 ok
words per sentence 13.5 12.9 – 20.5 ok
short sentences (<8w) % 8.33 2.52 – 31.4 ok
long sentences (>20w) % 8.33 9.11 – 52.0 LOW ↑ raise
contractions /100w 3.09 2.36 – 4.65 ok
numbers /100w 4.94 0.24 – 4.13 HIGH ↓ lower
--------------------------------------------------------------------
2 of 16 dials off. Worst first:
HIGH numbers /100w (20% outside)
LOW long sentences (>20w) % (9% outside)
[!IMPORTANT]
--wpmis your speaking rate, not the creator's. The default 210 is the studied creators' median and is faster than most people talk. Time yourself reading 200 words aloud:wpm = words ÷ minutes. Get this wrong and every script runs about 20% long.
🔬 What 616 reels actually showed
Run against two creators in the same niche — 221 and 395 reels, each split into winners and controls against their own contemporaneous baseline. Worth reading before you trust anything you have been told about short-form.
✅ A number in the first two sentences — REPLICATED60% of winners vs 21% of controls for one creator. 58% vs 25% for the other. Two different formats, two different audiences, near-identical split. The most reliable finding in the dataset. |
❌ Length is not a lever — DEADCorrelation between duration and performance: −0.058 across 221 reels and −0.006 across 395. Every quartile of one creator's ranking had a median duration of 47–49 seconds. And the two creators' tails point in opposite directions — one's winners are shorter than her controls, the other's are longer. That is what noise looks like. Every "keep it under N seconds" rule you have read is unsupported here. |
🎲 The named subject carries the reel — SINGLE (one creator's bet)One creator's winners named 1.67 already-famous entities in their opening two sentences; his controls named 0.58. The scripts are structurally identical — same format, same CTA, same delivery, similar length. A 3.2M-play reel and a 7.7K-play reel from the same creator, written the same way, differed mainly in whether the subject was a household-name tool or an unknown one. The matching negative: openers that withhold the subject and refer to it only as an unnamed category ran 8% of winners and 41% of controls. |
⚠️ Small samples lie confidentlyThe first pass here used 6 reels and produced a clean, plausible, completely false rule about length, with zero overlap between cohorts. Scaling to the full catalogue destroyed it — and re-baselining revealed that the reel that pass had called the best performer was actually running at 0.818×, below the creator's median. Six reels had it studying an underperformer. This is the entire argument for scraping the catalogue rather than eyeballing a handful. |
aggregate.py decides this for you. It pools every creator studied for a mode
and marks each feature:
| verdict | meaning | what to do with it |
|---|---|---|
| REPLICATED | same direction, real gap, 2+ creators | write it into the skill as a rule |
| SINGLE | one creator's habit | write it in as a bet, labelled as one |
| CONTESTED | creators disagree | leave it out |
| DEAD | no gap | leave it out, and stop repeating it |
One finding did not replicate, and the tool could only tell because it ran twice: interview framing (an off-camera voice asks, the creator answers) split 5-of-15 winners against 0-of-15 controls for one creator, and appeared nowhere at all in the other's catalogue. A real edge for her — not a law of the format. Anything measured on a single creator is a bet.
🎙️ Sounding like them
report.py measures what a reel is about. That is structure, and structure is
only half of why a script feels like a particular person.
The other half is voice: who the sentences are addressed to, how long they run,
which words recur, how one beat hands off to the next. voice.py measures it the
same way — mechanically, from that creator's own winning transcripts.
$ ./framezero voice creator_b
## Dials
| dial | target band | their range |
|--------------------------|----------------|--------------|
| second person /100w | 4.26 – 7.77 | 3.70 – 9.40 |
| first person sing /100w | 0.47 – 2.24 | 0.47 – 4.76 |
| words per sentence | 12.9 – 20.5 | 9.64 – 23.4 |
| contractions /100w | 2.36 – 4.65 | 1.01 – 5.05 |
| long words (8+ch) % | 7.57 – 12.1 | 4.76 – 13.7 |
| … 11 more | | |
## Signature phrases
Phrases they reach for and the other creators in this project do not.
| phrase | uses | lift |
|-----------------|------|-------|
| just comment | 12 | 15.0× |
| completely free | 6 | 7.5× |
| down below and | 5 | 6.3× |
Three things that make this work:
- A voice is a region, not a point. Bands are mean ± 1sd, clamped to what was actually observed. Land inside the band; do not chase the mean.
- Signature phrases are relative. A phrase counts only if this creator uses it and the others in your project do not — which is why voice profiling runs after every creator has been scraped, never inside the loop.
- Structure pools across creators. Voice must not. Averaging two voices
produces a third person who does not exist.
--like a,bwidens a target range; it is not a licence to blend two people in the prose.
🧩 The pipeline
flowchart LR
A["scrape.py<br/><small>index + real play counts</small>"] --> B["rank.py<br/><small>outlier score</small>"]
B --> C["fetch.py<br/><small>mp4 → 16kHz wav</small>"]
C --> D["listen.py<br/><small>whisper.cpp, seeded</small>"]
D --> E["corpus.py<br/><small>one markdown</small>"]
E --> F["report.py<br/><small>countable deltas</small>"]
F --> T["topics.py<br/><small>what to make</small>"]
T --> K["hooks.py<br/><small>how to open</small>"]
K --> P["profile.py<br/><small>account dossier</small>"]
P --> G["voice.py<br/><small>16 dials</small>"]
G --> H["aggregate.py<br/><small>structure replicates?</small>"]
H --> R["replicate.py<br/><small>subjects + hooks replicate?</small>"]
R --> I(["your agent<br/><small>writes the skill</small>"])
A -.->|no transcription needed| T
A -.->|already on disk| N["neighbours.py<br/><small>who else to study</small>"]
N -.-> A
topics.py, hooks.py and profile.py read the index the scrape already
wrote, so the whole right-hand answer — what to make, how to open it, is the
audience real — is available about a minute after you point it at a handle.
Every stage writes to disk and reads the previous stage's output, so any stage
reruns on its own. scrape.py resumes from whatever is already there.
python3 bin/scrape.py <handle> # post index + play counts
python3 bin/rank.py <handle> [--since D] # outlier scoring
python3 bin/fetch.py <handle> # download + 16kHz audio
python3 bin/listen.py <handle> --project P # local transcription
python3 bin/corpus.py <handle> # one markdown corpus
python3 bin/report.py <handle> --project P # countable deltas
python3 bin/topics.py <handle> [--define S] # subjects that beat baseline
python3 bin/hooks.py <handle> [--define S] # hook archetypes, both lenses
python3 bin/profile.py <handle> # account dossier + csv
python3 bin/replicate.py <project> [--mode M] # subjects + hooks that replicate
python3 bin/neighbours.py [handles] [--probe] # who else in the niche to study
python3 bin/voice.py profile <handle> # voice fingerprint
python3 bin/aggregate.py <project> <mode> # what replicates
report.py matters more than it looks. An agent reading transcripts will find
patterns whether or not they are there, so the countable features get measured
before the qualitative pass starts — each marked strong, weak or dead by the
size of the cohort split, with whole-catalogue correlations run separately to kill
findings that only look real at the tails. On its first run it caught two errors
in a careful hand analysis of the same data.
Flags worth knowing
| flag | stage | why |
|---|---|---|
--delay 30 |
scrape | seconds between pages; 2 is plenty on this path |
--top 15 --bottom 15 |
rank | size of the winner and control cohorts |
--window 90 |
rank | baseline window in days — shrink it for creators who grew fast |
--keep-mp4 |
fetch | keep the video, not just the audio |
--since 2025-06-01 |
rank | ignore everything before a pivot |
--wpm 176 |
check | your speaking rate |
--like a,b |
check | pool bands across handles |
If one creator changed niche and their older reels would poison the baseline, give that creator their own cutoff rather than the whole project:
"creators": { "somehandle": { "since": "2025-06-01" } }
Nothing is hardcoded to one niche
Three things used to be, and all three now come from the project config:
- The whisper seed. whisper.cpp emits all-lowercase, unpunctuated text without an initial prompt. framezero seeds one, built from your niche's vocabulary — so it fixes the casing and stops it writing "N8 N", "make dot com", and "cloud" when it means Claude. One flag, two wins.
- The famous-entity lexicon. Derived from your own scraped captions: proper nouns that recur broadly across the niche's biggest accounts. It filters sentence-initial capitals, drops words that also appear lowercase, and discards anything appearing in more than a third of posts — a term in every caption is that niche's boilerplate, not a household name.
- The modes. Yours to define.
🕸️ How it gets the data
Instagram gated the obvious route. Here is what actually works.
The old REST timeline (/api/v1/feed/user/) now answers 401 on the very first
request from a cold IP:
{"message":"Please wait a few minutes before you try again.",
"require_login":true,"igweb_rollout":true}
[!WARNING] That message is a lie. It is not a throttle and no cooldown clears it — it is the generic string Instagram returns for a retired or gated surface. Backing off and retrying is the trap; it costs hours and never succeeds. The same is true of the legacy
query_hashroute and the olderdoc_ids that instaloader and gallery-dl still ship.
What works anonymously is two GraphQL calls joined on code:
| call | gives you | missing |
|---|---|---|
PolarisProfilePostsQuery |
captions, timestamps, likes, comments, video_versions[] CDN URLs, DASH manifest |
view_count is always null logged-out |
| clips user connection | real play_count per reel |
no video URLs, no timestamps |
Duration is not returned at all any more, so framezero parses
mediaPresentationDuration out of the DASH manifest that ships with each post.
Same number, no extra request.
One REST call survives, and it is not load-bearing.
/api/v1/users/web_profile_info/ is the only source of follower count, bio,
category and related accounts. It is now being gated the same way — the same
"Please wait a few minutes" string, IP-wide, on handles you have never
touched. So nothing depends on it: scrape.py lifts the user id and basic
identity off the post timeline instead, the run completes either way, and the
dossier states which fields it could not fill rather than showing blanks.
Retry with ./framezero profile <handle> --refresh if it comes back.
The only header that matters is the CSRF pair. Fetch the profile page, keep
the csrftoken cookie, echo it back as X-CSRFToken. The cookie alone is
rejected with a 403. A browser User-Agent, X-ASBD-ID, Referer and Sec-Fetch-*
are all cargo cult on this endpoint — though X-IG-App-ID is required for the
one REST call that resolves the user id.
Two seconds between pages is plenty; there is no meaningful rate limit on this path. A 370-post profile takes about a minute.
doc_ids rotate every two to four weeks. When one stops working, framezero
scrapes the current value out of Instagram's own JS bundle rather than failing.
That is why this keeps working when the libraries above do not.
📦 What comes out
Your agent writes skills into your own agent config — for Claude Code that is
~/.claude/skills/<name>/, one directory per content mode:
informational-reel-script/ SKILL.md + swipe-file.md
teaching-reel-script/ SKILL.md + swipe-file.md
tech-demo-reel-script/ SKILL.md + swipe-file.md
reel-voice-layers/ SKILL.md
Split by mode, not by creator. A news reel, a how-to and a screen recording are three different crafts with different beat structures, and one skill trying to cover all three writes mush. The sibling descriptions have to disambiguate each other explicitly or the agent picks between them at random.
Swipe files quote real transcripts, so they stay local and out of git along with
everything else under data/.
Have your agent write them to out/skills/, then install:
python3 bin/install_skills.py --dry-run # see what would land where
python3 bin/install_skills.py
python3 bin/install_skills.py --uninstall
That is nearly a job for cp, with one exception that matters. Every skill ends
with a mandatory check loop written ./framezero check draft.txt, which is
correct in the repo and meaningless anywhere else — and nobody drafts a reel
while sitting in the repo. The command would fail, the agent would shrug, and
the one step that keeps a draft honest would quietly stop running. The installed
copy gets the absolute path baked in; the source keeps the relative one.
Before that, per creator and per project, on disk:
data/<handle>/profile.md who they are · is the audience real · is there spread
data/<handle>/topics.md which subjects beat their baseline — the brief
data/<handle>/hooks.md every winner's opening line + which shapes separate them
data/<handle>/posts.csv one row per post, with hook / topics / hook_shapes
data/<handle>/report.md countable winner-vs-control structural deltas
data/<handle>/voice.md 16 dials with target bands + signature phrases
data/_projects/<p>/<mode>.md structure that replicated
data/_projects/<p>/signals-<mode>.md subjects + hook shapes that replicated
Markdown for the human, JSON alongside it for the agent, same numbers.
🤝 Scope and etiquette
This reads public profile data while logged out — the same data any visitor sees. It does not log in, does not use anyone's cookies, and does not touch private accounts. It derives structural patterns for your own writing; it is not for republishing anyone's content.
data/, out/ and real projects/*.json are gitignored, so scraped material and
the handles you study never land in a commit.
Borrowed voice is scaffolding. Use it until you have enough of your own reels to measure — then point framezero at yourself.
MIT. Free forever. Fork it, break it, make it yours.
Built because the gap was real and nobody had filled it.
Installing Framezero
This server has no published package — it is built from source. Open the repository and follow its README.
▸ github.com/Ishan-sa/framezeroFAQ
Is Framezero MCP free?
Yes, Framezero MCP is free — one-click install via Unyly at no cost.
Does Framezero need an API key?
No, Framezero runs without API keys or environment variables.
Is Framezero hosted or self-hosted?
Self-hosted: the server runs locally on your machine via the install command above.
How do I install Framezero in Claude Desktop, Claude Code or Cursor?
Open Framezero on unyly.org, pick your client tab (Claude Desktop, Claude Code, Cursor) and press Install — the config is generated automatically, no JSON editing.
Related MCPs
GitHub
PRs, issues, code search, CI status
by GitHubFilesystem
Secure file operations with configurable access controls.
Memory
Knowledge graph-based persistent memory system.
Template MCP Server
A CLI tool to create a new Model Context Protocol server project with TypeScript support, dual transport options, and an extensible structure
by mcpdotdirectAmap Maps Mcp Server
MCP server for using the AMap Maps API
by duxiaohuiSupabase
Database, auth and storage
by SupabaseEverything
Reference / test server with prompts, resources, and tools.
Git
Tools to read, search, and manipulate Git repositories.
Sequential Thinking
Dynamic and reflective problem-solving through thought sequences.
Time
Time and timezone conversion capabilities.
Compare Framezero with
Not sure what to pick?
Find your stack in 60 seconds
Author?
Embed badge for your README
Browse similar
All development MCPs
