cli/lib/eval/refs.ts. It is one of the 13 hard invariants in AGENTS.md (#3). Generic briefs — “my coffee shop’s new pastry,” “a no-name workout app” — pass through without refs.
This page covers the rule, the classifier, the override, and the example flows.
Why the gate exists
Three reasons. Identity fidelity. AI image and video models cannot fabricate a specific real human from text alone. “A photo of Elon Musk” produces a plausible-looking middle-aged tech man — often with the wrong nose, wrong hair pattern, wrong eye color. The video then drifts further. A real reference photo of Musk solves this in one shot — the model has a target to lock to. Legal posture. Generating videos of named real people, real brand products, or copyrighted IP without a reference is a risk surface. The gate forces a deliberate decision: either you have rights to use the reference (you took the photo, you own the brand, the IP is in the public domain), or you are explicitly accepting the risk via--no-ref-consent with a logged reason.
Cost. The most expensive failure mode in 10 shipped postmortems was “the model generated five drift-y variants of a famous face before the agent noticed and pulled a real ref.” Ten seconds of reading + ten seconds of attaching a ref saves ~$2-10 of regen burn per project.
What triggers the gate
The classifier groups triggers into three buckets, in priority order:person > brand-product > ip. The lexicons in cli/lib/eval/refs.ts are deliberately short — “catch the obvious 80%,” not “complete name database.” False negatives are preferred over false positives.
person — named real humans
Match list excerpts (regex anchored on word boundaries, case-insensitive):
- Tech: Elon Musk, Mark Zuckerberg, Steve Jobs, Bill Gates, Jeff Bezos, Satya Nadella, Sundar Pichai, Sam Altman, Jensen Huang.
- Politics: Donald Trump, Joe Biden, Barack Obama, Vladimir Putin.
- Entertainment / sport: Taylor Swift, Beyoncé, Kanye West, Lionel Messi, Cristiano Ronaldo, LeBron James, Kim Kardashian, MrBeast, Dwayne Johnson.
character.name = "Elon Musk") triggers. A generic role label (character.name = "the barista") does not trigger — the classifier filters against a GENERIC_ARCHETYPE_TOKENS set: barista, founder, ceo, engineer, teacher, student, courier, doctor, nurse, athlete, musician, chef, it-remote, designer, developer.
brand-product — recognizable products and packaging
Match list excerpts:
- Drinks: Coca-Cola, Coke, Pepsi, Sprite, Dr Pepper, Red Bull, Monster Energy.
- Coffee / fast food: Starbucks, Dunkin’, McDonald’s, Burger King, KFC, Taco Bell, Chipotle.
- Tech products: iPhone (with optional model number / Pro / Plus / Max), iPad, MacBook, AirPods, Apple Watch, Galaxy S / Note, Pixel, PlayStation, PS4 / PS5, Xbox (Series S/X, One), Nintendo Switch, Steam Deck.
- Fashion / cosmetics: Nike, Adidas, Gucci, Louis Vuitton, Chanel, Rolex, Old Spice, Axe body spray/wash.
- Cars: Tesla Model / Cybertruck, Ferrari, Lamborghini, Porsche, BMW M-series.
ip — recognizable characters and franchises
Match list excerpts: Mickey Mouse, Donald Duck, Elsa (from Frozen), Pikachu, Pokémon, Darth Vader, Baby Yoda, Grogu, Luke Skywalker, Spider-Man, Iron Man, Batman, Superman, Wonder Woman, Deadpool, Goku, Naruto, Sailor Moon, Ronald McDonald, Colonel Sanders.
Italian Brainrot characters (Tralalero Tralala, Tung Tung Sahur, Ballerina Cappuccina, …) are not in the IP lexicon because the ralphy-assets companion repo ships canonical references for them — the agent pulls from the pool rather than generating from text. See /concepts/asset-catalog.
What does NOT trigger the gate
The classifier errs toward false negatives. Generic nouns and unrecognizable proper nouns pass without refs.- “My coffee shop’s new pastry” — generic.
- “A no-name workout app” — generic.
- “The founder narrates” — generic archetype (
founderis in the archetype set). - “Megan Park, the founder” — passes (
Megan Parkis not in the famous-names lexicon). - “A black sports car” — generic (no brand named).
- “A red running shoe” — generic.
- “A talking eggplant” — generic, even though anthropomorphic.
The classifier in detail
needsReference(input) from cli/lib/eval/refs.ts:
name, description, brand, character.name, character.role, character.description, every scene’s keyframe_prompt_brief, motion_prompt, voEn, voRu, notes — into one searchable blob, then scans each lexicon in priority order (person → brand-product → ip). On the first hit, it returns required: true with the bucket and the matched span.
checkReferenceGate(scenario, attachedRefs) adds the satisfaction check: if required: true and attachedRefs.length > 0, the result has satisfied: true. The CLI floor only checks presence — granular per-kind matching (does this person ref actually depict Elon Musk?) is left to the agent in chat.
The CLI floor
ralphy ref check <project-id> runs the offline classifier against the project’s scenario and prints the gate result:
ralphy generate ... calls checkReferenceGate before spending an API token. If required: true && satisfied: false, the generation refuses with a non-zero exit code and prints the same JSON. The agent reads the refusal and stops.
The override
When the user explicitly accepts the risk, the override is--no-ref-consent "<reason>":
- Bypasses the gate for this single generate call only. The next call (without the flag) refuses again.
- Appends an entry to
workspace/projects/<id>/logs/user-prompts.jsonlwithstage: "no-ref-consent"andtext: "<reason>". The audit trail is permanent. - Does not affect the offline classifier or the manifest — the project’s scenario still has the named entity in it.
Attaching a reference
Refs are folders underworkspace/.ralph/refs/<id>/. Each ref has a ref.json (the metadata), the source media, and any derived artifacts (frames, transcript, vision tags, blueprint).
ralphy generate call sees attachedRefs.length > 0 and the gate is satisfied. The agent then passes the ref’s master image via --ref on the actual i2v call, so the model has a target to lock to.
Example flows
Flow 1 — generic brief, no gate
Flow 2 — named human, gate fires
Flow 3 — brand product, override with logged reason
Where the agent decides nuance
The offline classifier is the floor. The agent during intake can do more:- Detect fringe names the lexicon misses (regional politicians, small creators) and ask for a ref.
- Detect implied brands (e.g. “the red can with the white wave” is probably Coca-Cola — the lexicon does not match this, but a good agent does).
- Suggest using a companion-repo asset instead of generating from text when the user names an Italian Brainrot character.
Related
cli/lib/eval/refs.ts— the classifier source- AGENTS.md hard invariant #3 — the canonical rule
- Brands and personas — generic archetype personas pass the gate
- Asset catalog — for IP characters that ship as canonical refs
- Generation log —
--no-ref-consententries land inuser-prompts.jsonl