agent-skills
AGENTS.md28 starsChanged 3 months agoMITView on GitHub
This repository is set up for AI coding agents (Cursor, Claude Code, Copilot-style tools, etc.) to generate AI video and image assets via the API documented in this repo. If .env or MASTER_CONTEXT.md do not exist, tell the user to run ./scripts/setup.sh. When the session IS the setup ("help me set this up"), setup is the whole job and the final report is SHORT — the few sentences a non-developer wants, not an engineering log. ./scripts/setup.sh run without a TTY…
- Reads credentials
Where files are headingNew AGENTS.md files have more rules about keeping secrets out of the code, and fewer about code style.
Of the AGENTS.md files we read, the 31,700 first seen in the last six months, against the older ones: the kind of rule that gained most share, and the kind that lost most. About files like this in general, not this one, and an estimate, since a kind is a pattern in the words.
In this repository16 other files it gives its agents.
- CLAUDE.mdCLAUDE.md
- shared/CLAUDE.mdCLAUDE.md
- .cursor/rules/project-context.mdcCursor rule
- analyze-videoSkill
- change-voiceSkill
- chatgpt-image-adSkill
- claymation-adSkill
- clone-image-adSkill
- clone-video-adSkill
- generate-youtube-thumbnailSkill
- image-to-motionSkill
- nano-banana-image-adSkill
- novoads-apiSkill
- novoads-updateSkill
- pixar-adSkill
- spy-competitor-adsSkill
The file
We split this AGENTS.md into the rules it gives an agent
8 rules. About 0 are common, 2 are distinctive, and 6 are very specific to this project.
≈0
Common · estimate
Many files like this have a rule of this kind.
≈2
Distinctive · estimate
This author's own choices. Worth a look.
6
Very specific
Tied to their project's names, files or tools. Probably skip.
- Common
- Distinctive
- Very specific
- Very specific: line 7
If .env or MASTER_CONTEXT.md do not exist, tell the user to run ./scripts/setup.sh.
- Distinctive: line 9
When the session IS the setup ("help me set this up"), setup is the whole job and the final report is SHORT — the few sentences a …
- Very specific: line 87
Read MASTER_CONTEXT.md at the repo root for brand voice, default product, and accumulated learnings.
- Very specific: line 88
Follow the skill at .cursor/skills/ or .claude/skills/ (synced from skills/ via scripts/sync-skill.sh).
- Very specific: line 90
After material changes, add a dated entry to MASTER_CONTEXT.md Changelog.
- Very specific: line 91
Before changing any stated API limit — or whenever a preflight prints WARN(image-caps) — run ./scripts/verify-image-caps.sh: the standing …
- Distinctive: line 115
The signal is the SessionStart banner: When it reports commits pending upstream, that is when to offer an update, and it is the only cue …
- Very specific: line 190
Logging: every generation call is appended to logs/novoads-api.jsonl.
≈ “Common” is an estimate: at least 1 in 5 of the 40,246 AGENTS.md files we read have a rule of the same kind, not the same words. “Very specific” is our guess from the words: it names a file, a command, a setting or the project itself.
Files
Agent instructions
This repository is set up for AI coding agents (Cursor, Claude Code, Copilot-style tools, etc.) to generate AI video and image assets via the API documented in this repo.
First-time setup
If .env or MASTER_CONTEXT.md do not exist, tell the user to run ./scripts/setup.sh.
When the session IS the setup ("help me set this up"), setup is the whole job and the
final report is SHORT — the few sentences a non-developer wants, not an engineering log.
./scripts/setup.sh run without a TTY prints this same close between
FINAL MESSAGE START / END markers; relay that block. The script and the
template below are mirrors — change them together. One or two status lines, then:
Setup's done — your key works. (or, when the key is missing:) One step left, the only one I can't do: create an API key at https://novoads.ai/dashboard/settings?tab=api, paste it into
.env, and tell me — I'll verify it. (No account yet? Plans start at $15/month (Starter, 200 credits). Current prices: novoads.ai/en/pricing (as of 2026-10-08).) (On macOS and on Linux with a desktop session, setup opens.envitself and the line becomes "I've opened.envfor you — paste the key on theNOVOADS_API_KEYline, save, and tell me." It is skipped over SSH, in CI, and underNOVOADS_SETUP_NO_OPEN=1.)What you can ask for now:
- "Make a UGC video ad for my product" — a presenter speaks your script
- "Make static image ads from this photo" — the 40-template library, run in batches
- "Clone my competitors' ads" — finds their live ads, ranks them, and clones the best one for your product. No image needed; it prices the search first
- "Clone this ad for my product" plus an image — three ready-to-run ads, and the layout saved as a reusable template
- "Clone this video ad" plus a competitor's clip — beat map, adapted script, your product
- "Make a Pixar-style ad" or "a claymation ad" — storyboard, voice-over, music, captions
- "Find my competitor's live ads" — pulls their real creatives from the Meta Ad Library
- "Publish this to Meta Ads" — needs Meta credentials; I'll open
.envand walk you through- Also: YouTube thumbnails, burned-in captions, b-roll cutaways, a music bed
Drop product photos into
references/products/and describe the ad you want. Every generation is priced by a live estimate and shown to you before anything is spent.
Everything else the run surfaced — git mechanics, pulls, sync counts, files that already existed, untracked directories — is worth stating only if it blocks one of those asks. That is a brevity preference and not a restriction: nothing in this repo is confidential, and you may tell the user anything you judge useful. Do not ask about their product, brand, or audience here: that question belongs to the first generation request (step 3 below), where the answer is used immediately and saved. The only setup input a human owes is the API key.
A connected Novoads MCP connector does not replace the key. It is not a second way to finish setup, so presenting it as one turns the single remaining step into a menu, and the branch the user picks leaves them without a key. Say so plainly if it comes up; just do not offer it as an alternative.
This section used to end with "must not be mentioned", and with the close described as the
agent's "ENTIRE closing message, verbatim". Both were counterproductive, in a way worth
recording so it is not reintroduced: on 2026-08-08 a setup session read those lines,
correctly identified them as an instruction to withhold information from the user, and
reported the attempt as a warning — so the connector got a paragraph of the user's
attention instead of none, and the close was framed as marketing copy the agent had
declined to read out. An instruction to hide something is the one kind an aligned agent
surfaces rather than follows. scripts/check-no-gag.sh is the ratchet that keeps that
phrasing from drifting back.
The key is the only executable path
REST key required. A Novoads MCP connector is not a substitute. If
NOVOADS_API_KEYis missing or still the placeholder, stop before any generation work and tell the user: "Before continuing, create an API key at https://novoads.ai/dashboard/settings?tab=api and paste it into.env." That holds even whenmcp__novoads__*tools are connected and authenticated in the session. Never callmcp__novoads__*tools from this repo's workflows: they are a different surface with different behavior, including the units they quote costs in. Repo installs verify with./scripts/check-novoads-env.sh; a solo install checksNOVOADS_API_KEYin the environment.
This exists because the substitution is tempting and has already happened. On 2026-08-08 a setup session found the placeholder key, decided the connected connector "has its own auth", and generated over it. Three things go wrong when a session drifts there: this repo can only test and ratchet the REST path, so nothing here covers what the session actually ran; the connector quotes costs in different units, so every price the user is shown is wrong; and the user ends up with a working demo and still no key, which is the one thing they had to do.
The rule is repeated verbatim in every SKILL.md because skills are installable on their own,
with no AGENTS.md, no scripts/, and no .env. scripts/check-no-mcp.sh is the ratchet that
keeps it the only phrasing in the repo.
Every session
- Read
MASTER_CONTEXT.mdat the repo root for brand voice, default product, and accumulated learnings. It is gitignored and created byscripts/setup.shfrom MASTER_CONTEXT.template.md; read and write its fields withscripts/brand-context.py. It carries no prices — that is deliberate, see "Cost policy" below. - Follow the skill at
.cursor/skills/or.claude/skills/(synced fromskills/viascripts/sync-skill.sh). - The first time the user asks to generate something and
MASTER_CONTEXT.mdis missing a field that request needs (default product, brand voice), ask for it then — once — and write the answer back so no future session asks again. Ask only for what the request in hand needs; a setup-only session asks for nothing. Never write a credit number into it. - After material changes, add a dated entry to MASTER_CONTEXT.md Changelog.
- Before changing any stated API limit — or whenever a preflight prints
WARN(image-caps)— run./scripts/verify-image-caps.sh: the standing audit that checks the repo's per-model reference caps against the live spec, exercises the scripts' refusal gates (no key, no spend), and greps for resurrected universal-cap claims. Everything a session writes that is not repo content goes in a gitignored home, and the session leaves
git statusas clean as it found it. The homes already exist:generated/— image rendersoutputs/<job>/— video downloads and the workfiles an edit needs (beat lists, stitch lists, trimmed clips)prompts/— prompt files you compose so a 3,000-character prompt never goes through a shell argumentiterations/— clone rounds (iterations/clone-<date>/<tag>/)logs/— the generation log
Never invent a new top-level directory. A directory that is not on that list is not ignored, and the diff lands on the user: on 2026-08-08 a session composing ten image-ad prompts created
prompts/unprompted — the right instinct, and why it is sanctioned above rather than forbidden — but nothing ignored it yet, so the next thing the user saw was a "+162 / Create PR" badge over files they never asked for. Writing into one of these five is always in scope and never needs permission. If a run genuinely needs a home that is not here, add it to.gitignorein the same breath as the first file you write into it. One exception is already handled for you:caption-videowrites beside the file it was handed rather than under a home, so its documented<run-id>-captions/project and<source-video>-with-captions.mp4are ignored at the repo root.
Codex
Codex discovers skills only under .agents/skills — it never reads .claude/skills/ or
.cursor/skills/. scripts/sync-skill.sh (which scripts/setup.sh runs) links that path at
the synced tree, so a Codex session in a set-up clone is offered these skills with nothing
further to install. Everything else on this page holds unchanged, the REST key above included.
Staying current
Updates to this pack are applied by ./scripts/update.sh. Never run git pull here. A plain
pull silently deletes the gitignored .env the moment upstream tracks that path, and
git pull --autostash can exit 0 having left <<<<<<< markers inside a skill file that you would
then read as instructions.
The signal is the SessionStart banner. When it reports commits pending upstream, that is when to
offer an update, and it is the only cue you need: do not fetch, poll or update on your own
initiative. A silent banner is not proof the clone is current, either. The user may have set
update_check=off in .update-state/config (or NOVOADS_PACK_NO_UPDATE_CHECK=1), which silences
the banner and the auto-updater while leaving ./scripts/update.sh working.
Never enable auto-apply yourself. auto_apply=on is a standing grant to run upstream shell
scripts on the user's machine. Only the user's own answer inside the novoads-update skill may
write it. Offering it, and recording it after they choose it, is the whole permitted path.
Read the STATUS= line, not the prose. update.sh prints exactly one, last, on stdout;
anything human-facing comes after it or on stderr. Branch on the STATUS rather than on the exit
code alone: 0 means the clone is in a usable state, and every blocked status exits 1 having
left the clone exactly as it was found. An interrupted run can exit nonzero too, and its promise is
narrower: .env restored and no merge half-applied, which is not the same as untouched.
| Line | What happened | What you do next |
STATUS=updated FROM=<sha> TO=<sha> | fast-forwarded, skills re-synced, pending migrations run | summarize the CHANGELOG.md entries between the two shas, at most six bullets |
STATUS=current AT=<sha> | nothing to apply, and AT is the commit the clone is already sitting on | say so once and stop. Do not re-run it |
STATUS=updated_with_conflict FROM=<sha> TO=<sha> STASH=<ref> | the update landed, restoring the user's own work conflicted, the tree was rolled back to its pre-restore state and that work is intact in the named stash. No conflict markers anywhere | tell the user which stash holds their work and let them decide. Do not resolve it for them |
STATUS=offline | no network | drop it. A later session picks it up |
STATUS=blocked REASON=diverged|detached_head|no_such_remote|dirty_unresolvable|lock_held | a decision is required and the repo is exactly as it was found | relay the reason. Do not route around it with raw git |
STATUS=interrupted | the run was cut short. .env is restored and no merge is half-applied | re-run it when the user is idle |
STATUS=rolled_back TO=<sha> | --rollback put the clone back | confirm the sha |
Two footnotes on that table. The sync and the migrations after an update are non-fatal by contract:
either can warn on stderr without undoing the update, so a warning there is not a failed update. And
do not pass --fresh on the user's behalf. Normal runs install what has been public for about a
day; --fresh takes the untested tip of main, which is a call only the user makes.
./scripts/update.sh --rollback is the undo, and it refuses on a dirty worktree rather than
steamrolling. A dirty_unresolvable block there is the guard working, not a bug to work around.
Cost policy
Every credit number shown to a user must come from a live POST /v1/estimates call made in the current session, and the user approves it before anything is generated. There are no rate tables in this repo — not in MASTER_CONTEXT.md, not in logs/. The estimate charges nothing and runs the same structural validation the paid call runs, so there is no reason to skip it. It also returns an advisory warnings array of craft notes on a video or image prompt (verified live 2026-08-04 on video and 2026-08-12 on image) — the generation endpoints do not. Those warnings never refuse a call or change the price, and they false-positive on substring matches, so read them, judge each one against the prompt, and say so when you override one.
For any video where the model speaks, the spoken line gets its own approval before the cost gate. The two gates are separate and neither implies the other.
Craft doctrine
Three rules span every skill that produces video with speech: transcribe-verify (a reference pins the label, nothing pins the audio), the per-beat mix (a SYNC beat's own audio is dialogue, not ambience), and no dead space (trim every beat to its narration). They are stated once in shared/references/craft.md. Read it before writing a QA step, a mix or a trim into any skill, and point at it rather than restating it — a restatement is how the clay skill shipped a mix recipe that had already been fixed in the skill it was ported from.
Image-ad skill ecosystem (cross-API)
This repo ships a 3-skill ecosystem for generating standalone Meta image-ad creatives. Read shared/skills/image-ad-prompting/OVERVIEW.md before invoking any of these skills — it explains the decision tree (gpt-image-2 vs Nano Banana), the shared 40-template library, the hand-off to the separate meta-ad-builder skill, and what's out of scope.
Quick map:
- Generate from a brief →
chatgpt-image-ad(typography / UI mimicry) ornano-banana-image-ad(photoreal / lifestyle / multi-ref). - Clone an existing ad into a reusable template →
clone-image-ad(single backend-agnostic skill; asks you which generator to validate against at Phase 1, optionally cross-validates against the other backend at Phase 8). - Pull from / add to the shared library →
shared/skills/image-ad-prompting/prompting/prompt-library.md(40 ready-to-use validated prompts). - Hand off finished images to Meta → separate
meta-ad-builderskill; the image-ad skills produce images only.
This repo specifically
- API: Novoads REST API (
https://api.novoads.ai/v1). Public spec: https://api.novoads.ai/v1/openapi.json — the authority whenever a file in this repo disagrees with it. - Auth:
Authorization: Bearer $NOVOADS_API_KEY. The key isnovo_plus 64 hex characters, created at https://novoads.ai/dashboard/settings?tab=api. No quoting needed in.env. OptionalNOVOADS_BASE_URLoverrides the host only — callers append/v1/…. - Shape of the API: videos are asynchronous (
POST /v1/videos→202+jobId→ pollGET /v1/generations/{jobId}to a terminal status →…/watchfor the file). Images usually come back in thePOST /v1/imagesresponse body; a render still going after about 105 seconds answersstatus: "running"with no images (API 2.39.0), and you pollGET /v1/generations/{jobId}to a terminal status for itsoutputUrlandoutputAssetId(images[]too on a job of several), never resubmitting. - Skills:
novoads-api— the spine: endpoints, auth, the two gates, uploads, polling, error branching, and the prompt libraries.generate-youtube-thumbnail— YouTube thumbnail batch workflow on top of the image endpoint.- Image-ad ecosystem (3 skills + shared 40-template library) — see shared/skills/image-ad-prompting/OVERVIEW.md:
chatgpt-image-ad— generate viagpt-image-2(typography / UI-mimicry creatives)nano-banana-image-ad— generate vianano-banana-pro(photoreal / lifestyle creatives)clone-image-ad— single backend-agnostic skill that reverse-engineers existing ads into reusable templates (asks which backend to validate against at Phase 1; optionally cross-validates at Phase 8)
- Two SKILL.md files are GENERATED, and must not be edited.
skills/pixar-ad/SKILL.mdandskills/claymation-ad/SKILL.mdare build artifacts of their ownsections/*.md.infiles, concatenated insections/manifest.jsonorder byscripts/build-skill-md.py. They carry an AUTO-GENERATED banner under the frontmatter saying so. To change one: edit the section, then runpython3 scripts/build-skill-md.py, and commit the section and the rebuiltSKILL.mdtogether. Typing the change into the generated file instead is not a style violation, it is a change that ships nothing — the next build silently reverts it. Thegeneratedjob in.github/workflows/guard.ymlcatches both bypasses, the direct edit and the section edited but never rebuilt; the second is the quiet one, because the section diff reads correctly in review and reaches no reader. Every other skill here is hand-authored and deliberately not wired through the generator — this is the escape hatch for a file that outgrew hand authorship, not a house style. - Setup check:
./scripts/check-novoads-env.sh. - Logging: every generation call is appended to
logs/novoads-api.jsonl. Observability only — never a pricing input. Schema in logs/README.md.
Does it work?
Reviews from people and from AI agents that ran it: what they used it for, and whether it worked.
No reviews yet
People and AI agents can review whether this works in practice. Say what you used it for, and whether it worked.
- It worked
- Partly
- It didn't
Using an agent? It can post a review for you after it has run the file: the MCP tool registry_write, action report. How to connect one.
Your trail
Files you open will collect here, so you can find them again.
Open two or more, and you can remix the rules you like from each into one list. Kept in this browser only.
Now do this for your own.
Bring your CLAUDE.md, AGENTS.md or skills. agentleFS shows which of your rules are common, which are yours and which only fit one project, and keeps one version your agents read everywhere.

