Veo prompt lint — screen before you spend
A regex-based linter that catches the Veo prompt mistakes that recur on every
production. It is a heuristic, not a parser — it nudges, it does not guarantee.
The point is to catch a 15-credit mistake before you pay for it.
Script: scripts/veo_lint.py — stdlib only, Python 3.8+.
Rules
| ID |
Trigger |
Why it bites |
Fix |
| R1a |
A silent / non-dialogue clip that has an Audio language: <X> line |
The explicit language directive forces Veo to generate unwanted speech |
Delete the language line; add No dialogue - ambient sound only |
| R1b |
A non-dialogue clip with no explicit silence directive |
Veo defaults to English speech and invents lines |
Add No dialogue - ambient sound and SFX only — and never an Audio language: line |
| R2 |
LOCKED TRIPOD / locked-tripod |
Misread; Veo adds motion anyway, and sometimes renders a literal tripod |
Use static shot (optionally static shot, no camera movement) |
| R3 |
More than 3 reference images / ingredients |
Veo supports at most 3; the extras are silently ignored |
Reduce to ≤3; merge, or split across shots |
| R4 |
An environment transition (door, hallway, room change) with no Extend from prior clip |
Veo guesses the destination environment, usually wrong |
Add Extend from prior clip. and describe the destination |
The rule logic, patterns and exact rewrite text live in scripts/veo_lint.py — that
file is the single source of truth. Tune the patterns there, not in this table.
Usage
# a single prompt string
python scripts/veo_lint.py "your prompt text"
# a prompt file
python scripts/veo_lint.py path/to/clip07.txt
# a batch: blank-line-separated blocks, or a JSON array / JSONL of {"id","prompt"}
python scripts/veo_lint.py path/to/episode_prompts.txt
# machine-readable
python scripts/veo_lint.py prompts.json --json
# pipe
cat prompt.txt | python scripts/veo_lint.py --stdin
Exit code: 0 = clean · 1 = at least one violation.
How to apply it
- Run the linter on the prompt or batch.
- For each violation, apply the suggested rewrite — or justify keeping it (e.g. the
clip genuinely has dialogue the regex missed).
- Re-run until clean, or until only knowingly-accepted WARNs remain.
- Report ERRORs vs WARNs separately. ERRORs (R1a, R2, R3) almost always need
fixing; WARNs (R1b, R4) need a judgment call.
Calibrate it before you trust it
These are heuristics with expected false positives and negatives. Before running it on
a real production:
- Pick 4–6 of your own past prompts — a mix: a silent clip, a dialogue clip, a
continuity/transition clip, a multi-reference clip.
- Run each one through the linter.
- For every flag, confirm the rule actually applied (true positive) versus misfired
(false positive). For every prompt you know had a problem, confirm it was flagged
(catch the false negatives).
- If a pattern is wrong, edit the corresponding
_*_RE / _REF_PATTERNS in
scripts/veo_lint.py and repeat steps 2–3 until your known-good and known-bad
prompts classify correctly.
- Write down the known blind spots, so future-you reads the WARNs with the right
scepticism.
Known false positives
- A dialogue clip whose lines are phrased without
says: / dialogue: → R1b misfires.
Add a clear Dialogue: label, or accept the WARN.
- "door" used metaphorically rather than as a real environment change → dismiss R4.
- A prompt listing four nouns that are not actually reference ingredients → R3
over-counts. Check the actual reference panel.
What it does not check
The linter is text-shaped, so it cannot see the things that need a human or another
pass: continuity between clips
(multiclip-continuity), whether the framing
matches the emotional beat (cinematography), or whether
the prompt will trip a content filter
(docs/content-filters-and-policy.md).
Run those separately.
1---2name: veo-prompt-lint3description: Use before submitting a Veo prompt or a batch of clip prompts, and when a generated clip came back with unwanted speech, the wrong camera motion, ignored references, or a wrong environment after a cut. Runs a regex linter over prompt text and proposes rewrites for the gotchas that recur every episode. Triggers on "lint veo prompt", "check this veo prompt", "veo prompt review".4---56# Veo prompt lint — screen before you spend78A regex-based linter that catches the Veo prompt mistakes that recur on every9production. It is a **heuristic, not a parser** — it nudges, it does not guarantee.10The point is to catch a 15-credit mistake before you pay for it.1112Script: [`scripts/veo_lint.py`](scripts/veo_lint.py) — stdlib only, Python 3.8+.1314---1516## Rules1718| ID | Trigger | Why it bites | Fix |19|---|---|---|---|20| **R1a** | A silent / non-dialogue clip that **has** an `Audio language: <X>` line | The explicit language directive forces Veo to generate unwanted speech | Delete the language line; add `No dialogue - ambient sound only` |21| **R1b** | A non-dialogue clip with **no** explicit silence directive | Veo defaults to **English** speech and invents lines | Add `No dialogue - ambient sound and SFX only` — and never an `Audio language:` line |22| **R2** | `LOCKED TRIPOD` / `locked-tripod` | Misread; Veo adds motion anyway, and sometimes renders a literal tripod | Use `static shot` (optionally `static shot, no camera movement`) |23| **R3** | More than 3 reference images / ingredients | Veo supports at most 3; the extras are silently ignored | Reduce to ≤3; merge, or split across shots |24| **R4** | An environment transition (door, hallway, room change) with no `Extend from prior clip` | Veo guesses the destination environment, usually wrong | Add `Extend from prior clip.` and describe the destination |2526The rule logic, patterns and exact rewrite text live in `scripts/veo_lint.py` — that27file is the single source of truth. Tune the patterns there, not in this table.2829---3031## Usage3233```bash34# a single prompt string35python scripts/veo_lint.py "your prompt text"3637# a prompt file38python scripts/veo_lint.py path/to/clip07.txt3940# a batch: blank-line-separated blocks, or a JSON array / JSONL of {"id","prompt"}41python scripts/veo_lint.py path/to/episode_prompts.txt4243# machine-readable44python scripts/veo_lint.py prompts.json --json4546# pipe47cat prompt.txt | python scripts/veo_lint.py --stdin48```4950Exit code: `0` = clean · `1` = at least one violation.5152---5354## How to apply it55561. Run the linter on the prompt or batch.572. For each violation, apply the suggested rewrite — **or** justify keeping it (e.g. the58 clip genuinely has dialogue the regex missed).593. Re-run until clean, or until only knowingly-accepted WARNs remain.604. Report **ERRORs vs WARNs** separately. ERRORs (R1a, R2, R3) almost always need61 fixing; WARNs (R1b, R4) need a judgment call.6263---6465## Calibrate it before you trust it6667These are heuristics with expected false positives and negatives. Before running it on68a real production:69701. Pick 4–6 of your own past prompts — a mix: a silent clip, a dialogue clip, a71 continuity/transition clip, a multi-reference clip.722. Run each one through the linter.733. For every flag, confirm the rule actually applied (true positive) versus misfired74 (false positive). For every prompt you *know* had a problem, confirm it was flagged75 (catch the false negatives).764. If a pattern is wrong, edit the corresponding `_*_RE` / `_REF_PATTERNS` in77 `scripts/veo_lint.py` and repeat steps 2–3 until your known-good and known-bad78 prompts classify correctly.795. Write down the known blind spots, so future-you reads the WARNs with the right80 scepticism.8182## Known false positives8384- A dialogue clip whose lines are phrased without `says:` / `dialogue:` → R1b misfires.85 Add a clear `Dialogue:` label, or accept the WARN.86- "door" used metaphorically rather than as a real environment change → dismiss R4.87- A prompt listing four nouns that are not actually reference *ingredients* → R388 over-counts. Check the actual reference panel.8990---9192## What it does not check9394The linter is text-shaped, so it cannot see the things that need a human or another95pass: continuity between clips96([`multiclip-continuity`](../multiclip-continuity/SKILL.md)), whether the framing97matches the emotional beat ([`cinematography`](../cinematography/SKILL.md)), or whether98the prompt will trip a content filter99([`docs/content-filters-and-policy.md`](../../docs/content-filters-and-policy.md)).100Run those separately.