@event4u/agent-config 5.4.1 → 5.6.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/.agent-src/commands/image/analyse.md +51 -0
- package/.agent-src/commands/image/create.md +53 -0
- package/.agent-src/commands/image/verify.md +48 -0
- package/.agent-src/commands/image.md +69 -0
- package/.agent-src/commands/knowledge/cross-repo.md +71 -0
- package/.agent-src/commands/knowledge.md +2 -0
- package/.agent-src/commands/skill/preview.md +67 -0
- package/.agent-src/commands/skill.md +48 -0
- package/.agent-src/commands/skills/discover.md +76 -0
- package/.agent-src/commands/skills.md +56 -0
- package/.agent-src/commands/video/from-song.md +351 -0
- package/.agent-src/commands/video.md +19 -9
- package/.agent-src/contexts/authority/commit-mechanics.md +8 -0
- package/.agent-src/rules/commit-policy.md +3 -8
- package/.agent-src/rules/linked-projects-onboarding-gate.md +1 -1
- package/.agent-src/rules/media-sync-ground-truth.md +58 -0
- package/.agent-src/skills/image-analyser/SKILL.md +121 -0
- package/.agent-src/skills/image-analyser/canon-spec.md +109 -0
- package/.agent-src/skills/image-analyser/evals/triggers.json +16 -0
- package/.agent-src/skills/image-creator/SKILL.md +117 -0
- package/.agent-src/skills/image-creator/evals/triggers.json +16 -0
- package/.agent-src/skills/song-to-script/SKILL.md +216 -0
- package/.claude-plugin/marketplace.json +15 -2
- package/CHANGELOG.md +84 -0
- package/CONTRIBUTING.md +6 -0
- package/README.md +3 -3
- package/config/agent-settings.template.yml +18 -0
- package/dist/cli/registry.js +1 -0
- package/dist/cli/registry.js.map +1 -1
- package/dist/discovery/deprecation-report.md +1 -1
- package/dist/discovery/discovery-manifest.json +327 -20
- package/dist/discovery/discovery-manifest.json.sha256 +1 -1
- package/dist/discovery/discovery-manifest.summary.md +4 -4
- package/dist/discovery/orphan-report.md +1 -1
- package/dist/discovery/packs.json +24 -10
- package/dist/discovery/trust-report.md +3 -3
- package/dist/discovery/workspaces.json +20 -6
- package/dist/mcp/registry-manifest.json +3 -3
- package/dist/router.json +1 -1
- package/dist/server/schemas/settings.js +4 -0
- package/dist/server/schemas/settings.js.map +1 -1
- package/docs/architecture.md +3 -3
- package/docs/catalog.md +20 -6
- package/docs/contracts/benchmark-report-schema.md +12 -10
- package/docs/contracts/command-clusters.md +5 -1
- package/docs/contracts/cross-repo-retrieval.md +64 -0
- package/docs/contracts/rule-router.md +39 -0
- package/docs/contracts/skill-discovery.md +80 -0
- package/docs/contracts/skill-dry-run.md +47 -0
- package/docs/contracts/value-dashboard-spec.md +7 -3
- package/docs/contracts/value-report-schema.md +6 -1
- package/docs/decisions/ADR-032-linked-projects-scope.md +7 -3
- package/docs/getting-started.md +2 -2
- package/docs/guides/cross-repo-linked-projects.md +7 -0
- package/docs/guides/cross-repo-retrieval.md +61 -0
- package/docs/guides/skill-discovery.md +71 -0
- package/docs/guides/skill-preview.md +71 -0
- package/docs/value.md +17 -17
- package/package.json +1 -1
- package/scripts/__pycache__/validate_frontmatter.cpython-312.pyc +0 -0
- package/scripts/_dispatch.bash +10 -0
- package/scripts/_lib/__pycache__/__init__.cpython-312.pyc +0 -0
- package/scripts/_lib/__pycache__/agent_src.cpython-312.pyc +0 -0
- package/scripts/_lib/bench_report.py +13 -14
- package/scripts/_lib/bench_telegraph_report.py +1 -2
- package/scripts/_lib/token_count.py +95 -0
- package/scripts/_lib/value_report.py +3 -3
- package/scripts/ai-video/adapters/higgsfield.sh +163 -6
- package/scripts/ai-video/adapters/openai-images.sh +92 -6
- package/scripts/ai-video/lib/probe-audio.sh +181 -0
- package/scripts/audit_auto_rules.py +22 -6
- package/scripts/audit_command_surface.py +6 -1
- package/scripts/audit_initial_context.py +210 -0
- package/scripts/bench_ab_diff.py +4 -11
- package/scripts/bench_run.py +2 -3
- package/scripts/bench_runner.py +2 -2
- package/scripts/condense.py +44 -3
- package/scripts/cross_repo_retrieve.py +172 -0
- package/scripts/inventory_meta_layers.py +288 -0
- package/scripts/iron_law_sha.py +14 -5
- package/scripts/linked_projects_list.py +91 -0
- package/scripts/measure_rule_budget.py +15 -0
- package/scripts/memory_lookup.py +53 -2
- package/scripts/project_thin_rules.py +168 -0
- package/scripts/render_value_md.py +14 -23
- package/scripts/schemas/command.schema.json +1 -1
- package/scripts/schemas/rule.schema.json +1 -1
- package/scripts/schemas/skill.schema.json +2 -2
- package/scripts/skill_discovery.py +254 -0
- package/scripts/skill_linter.py +8 -4
- package/scripts/skill_preview.py +179 -0
- package/scripts/trigger_coverage.py +129 -0
|
@@ -0,0 +1,351 @@
|
|
|
1
|
+
---
|
|
2
|
+
model_tier: inherit
|
|
3
|
+
name: video:from-song
|
|
4
|
+
tier: 2
|
|
5
|
+
cluster: video
|
|
6
|
+
sub: from-song
|
|
7
|
+
description: Music-video from a song + reference images — accept or derive a timed scene script, optional character-lock, render, stitch, mux song as master track. Dry-run default; one batch gate for live calls.
|
|
8
|
+
personas: [hollywood-director, ai-video-technical-director]
|
|
9
|
+
skills: [song-to-script, scene-expander, video-director, character-consistency, motion-choreographer]
|
|
10
|
+
suggestion:
|
|
11
|
+
eligible: true
|
|
12
|
+
trigger_description: "make a music video from a song, turn a track into a video, lip-sync clip from images and audio, AI music video"
|
|
13
|
+
trigger_context: "user supplies an audio file plus reference images and wants a final MP4 cut to the song"
|
|
14
|
+
workspaces:
|
|
15
|
+
- agent-config-maintainer
|
|
16
|
+
packs:
|
|
17
|
+
- meta
|
|
18
|
+
lifecycle: experimental
|
|
19
|
+
trust:
|
|
20
|
+
level: experimental
|
|
21
|
+
install:
|
|
22
|
+
default: false
|
|
23
|
+
removable: true
|
|
24
|
+
---
|
|
25
|
+
|
|
26
|
+
# /video:from-song
|
|
27
|
+
|
|
28
|
+
`/video:from-song <images-dir> <song-file> [--brief "<description>"] [--auto-script] [--scene-durations <list>] [--character|--no-character] [--auto-pick] [--keep-native-audio] [--max-duration <min>] [--max-scenes <n>] [--image-provider <id>] [--video-provider <id>]`
|
|
29
|
+
|
|
30
|
+
Turns a **song** plus a **folder of reference images** into a finished
|
|
31
|
+
music-video. The scene script is either supplied by the operator
|
|
32
|
+
(`--brief`) or derived from the audio itself (`--auto-script`); if
|
|
33
|
+
neither flag is present the command asks. After the script exists this
|
|
34
|
+
command reuses the same render path as
|
|
35
|
+
[`/video:from-script`](from-script.md) and ends by muxing the song over
|
|
36
|
+
the cut as the **master audio track**.
|
|
37
|
+
|
|
38
|
+
Provider flags override the `<default-image-provider>` /
|
|
39
|
+
`<default-video-provider>` from
|
|
40
|
+
[`agents/.ai-video.xml`](../../../agents/templates/.ai-video.xml.example);
|
|
41
|
+
absent flags fall back to the XML defaults.
|
|
42
|
+
|
|
43
|
+
**Requires `pack-ai-video`.** The declared skills
|
|
44
|
+
(`song-to-script`, `scene-expander`, `video-director`,
|
|
45
|
+
`character-consistency`, `motion-choreographer`) ship in that pack; on a
|
|
46
|
+
global-only install Step 1's `validate-deps.sh` fails fast with the
|
|
47
|
+
missing-id list instead of an opaque mid-run error — install the pack
|
|
48
|
+
and re-run.
|
|
49
|
+
|
|
50
|
+
**Block-on-ambiguity:** a missing/empty images directory, an unreadable
|
|
51
|
+
audio file, contradictory mode flags (`--brief` *and* `--auto-script`),
|
|
52
|
+
contradictory character flags (`--character` *and* `--no-character`), or
|
|
53
|
+
a contradictory provider flag halts the run with a precise message — no
|
|
54
|
+
silent best-guess.
|
|
55
|
+
|
|
56
|
+
## Inputs
|
|
57
|
+
|
|
58
|
+
| Input | Required | Meaning |
|
|
59
|
+
|---|---|---|
|
|
60
|
+
| `<images-dir>` | yes | Folder of reference stills (`.png` / `.jpg`). When they contain a consistent human subject the on-screen identity is locked from them; otherwise the run is style-only (Step 6). |
|
|
61
|
+
| `<song-file>` | yes | Audio track (`.mp3` / `.wav` / `.m4a`). Defines total duration and, in `--auto-script` mode, the scene structure. |
|
|
62
|
+
| `--brief "<text>"` | one of brief/auto | Operator-written description of the video (mood, story, settings). |
|
|
63
|
+
| `--auto-script` | one of brief/auto | Derive the script from the song via the `song-to-script` skill. |
|
|
64
|
+
| `--scene-durations <list>` | no | Manual cut points (e.g. `0:00-0:15,0:15-0:30,…`). Overrides probe timing — the honest path when the track is flat (probe `method: interval`). |
|
|
65
|
+
| `--character` / `--no-character` | no | Force character-lock on/off. Default: auto-detect a subject in `<images-dir>`. |
|
|
66
|
+
| `--keep-native-audio` | no | Keep provider-generated audio instead of dropping it for the song (Step 8). |
|
|
67
|
+
|
|
68
|
+
## Steps
|
|
69
|
+
|
|
70
|
+
### 1. Validate dependencies
|
|
71
|
+
|
|
72
|
+
```bash
|
|
73
|
+
scripts/ai-video/lib/validate-deps.sh .agent-src.uncondensed/commands/video/from-song.md
|
|
74
|
+
```
|
|
75
|
+
|
|
76
|
+
Fails fast with the missing-id list if any declared persona / skill is
|
|
77
|
+
absent from `.agent-src/personas/` or `.agent-src/skills/`. No network
|
|
78
|
+
call has happened yet.
|
|
79
|
+
|
|
80
|
+
Then confirm the **runtime helper scripts** exist and are executable —
|
|
81
|
+
`scripts/ai-video/lib/probe-audio.sh`, `scripts/ai-video/lib/load-config.sh`,
|
|
82
|
+
`scripts/ai-video/stitch.sh` — so a missing script fails here (with the
|
|
83
|
+
path), not mid-run at Step 2/9.
|
|
84
|
+
|
|
85
|
+
**Non-interactive contexts.** When stdin is not a TTY (CI, cron, headless
|
|
86
|
+
harness) the command cannot prompt: it requires `--brief` or
|
|
87
|
+
`--auto-script`, an explicit `--character`/`--no-character`, and
|
|
88
|
+
`--auto-pick`, and refuses live calls outright. Missing any → fail fast
|
|
89
|
+
with usage, never a deadlocked prompt.
|
|
90
|
+
|
|
91
|
+
### 2. Validate inputs + media-governance input gate
|
|
92
|
+
|
|
93
|
+
- `<images-dir>` exists and holds ≥1 `.png`/`.jpg`. Empty or missing →
|
|
94
|
+
halt, list what was found.
|
|
95
|
+
- `<song-file>` exists and is a readable audio container (`ffprobe`
|
|
96
|
+
returns an audio stream). Probe its length + structure now:
|
|
97
|
+
```bash
|
|
98
|
+
scripts/ai-video/lib/probe-audio.sh <song-file>
|
|
99
|
+
```
|
|
100
|
+
Emits `{duration, method, warning?, sections:[…]}` (deterministic, no
|
|
101
|
+
network). `duration` becomes the target length of the final cut. A
|
|
102
|
+
`method: interval` result (flat / brick-walled track) is surfaced to
|
|
103
|
+
the operator with the suggestion to pass `--scene-durations` for
|
|
104
|
+
musical cuts — never presented as beat-synced.
|
|
105
|
+
- **Media-governance input gate (mandatory).** Before any render,
|
|
106
|
+
consult the project-local media policies per
|
|
107
|
+
[`media-governance-routing`](../../rules/media-governance-routing.md):
|
|
108
|
+
- reference stills or brief depict a **real person's likeness** →
|
|
109
|
+
[`likeness`](../../../agents/settings/policies/media/likeness.md);
|
|
110
|
+
- a **recognised public figure** →
|
|
111
|
+
[`public-figures`](../../../agents/settings/policies/media/public-figures.md);
|
|
112
|
+
- the track is a **recognisable commercial song / a real artist's
|
|
113
|
+
voice** or the brief asks to clone one →
|
|
114
|
+
[`voice-cloning`](../../../agents/settings/policies/media/voice-cloning.md).
|
|
115
|
+
On a match: **refuse-and-surface** (one question per turn) — do not
|
|
116
|
+
best-guess past a likeness / rights concern.
|
|
117
|
+
|
|
118
|
+
### 3. Cost + duration guard (theory of failure)
|
|
119
|
+
|
|
120
|
+
Refuse, with a precise message, **before** loading providers:
|
|
121
|
+
|
|
122
|
+
- a song longer than the configured cap (default 8 min) — a 45-minute
|
|
123
|
+
track would launch a runaway paid render;
|
|
124
|
+
- a derived/briefed scene count above the cap (default 40 scenes).
|
|
125
|
+
|
|
126
|
+
The operator raises a cap explicitly (`--max-duration` / `--max-scenes`)
|
|
127
|
+
if they really mean it; the guard never silently proceeds.
|
|
128
|
+
|
|
129
|
+
### 4. Load config + resolve providers
|
|
130
|
+
|
|
131
|
+
Source `scripts/ai-video/lib/load-config.sh`. Resolve image / video
|
|
132
|
+
provider: command flag → `agents/.ai-video.xml` default → fail with the
|
|
133
|
+
available-providers list. A **malformed XML** or a default/flag naming a
|
|
134
|
+
provider with no `scripts/ai-video/adapters/<id>.sh` → fail fast here
|
|
135
|
+
with `provider '<id>' not found in adapters/` and the available list;
|
|
136
|
+
never a cryptic shell error mid-run. Surface the resolved provider's **lifecycle
|
|
137
|
+
tier** per
|
|
138
|
+
[`provider-lifecycle-discipline`](../../rules/provider-lifecycle-discipline.md);
|
|
139
|
+
all shipped adapters are `experimental` today, so the refuse-and-surface
|
|
140
|
+
path fires before any live call. For a music-video the **song is the
|
|
141
|
+
master track**, so a video provider with `audio-native=false` (e.g.
|
|
142
|
+
`kling`) is fine; native-audio providers (`gemini-veo`, `sora`) still
|
|
143
|
+
work — their audio is dropped at mux time in Step 8 unless
|
|
144
|
+
`--keep-native-audio` or a lip-sync scene needs it.
|
|
145
|
+
|
|
146
|
+
### 5. Select script mode (block on ambiguity)
|
|
147
|
+
|
|
148
|
+
- `--brief` and `--auto-script` both present → halt: "Pick one source
|
|
149
|
+
for the script."
|
|
150
|
+
- Exactly one present → use it.
|
|
151
|
+
- **Neither present → ask, then stop and wait:**
|
|
152
|
+
|
|
153
|
+
```
|
|
154
|
+
> How should I build the scene script?
|
|
155
|
+
>
|
|
156
|
+
> 1. From a description — I'll write the scenes to your brief
|
|
157
|
+
> 2. From the song — I'll derive scenes + timing from the audio
|
|
158
|
+
```
|
|
159
|
+
|
|
160
|
+
### 6. Build the timed scene script
|
|
161
|
+
|
|
162
|
+
Run the [`song-to-script`](../../skills/song-to-script/SKILL.md) skill
|
|
163
|
+
with the Step 2 probe result:
|
|
164
|
+
|
|
165
|
+
- **Brief mode** — the operator brief is the creative source; the audio
|
|
166
|
+
sections drive only the **cut timing**.
|
|
167
|
+
- **Auto mode** — skill infers mood/energy per section, writes action +
|
|
168
|
+
timing; vocal sections populate `dialogue:` for lip-sync **from the
|
|
169
|
+
transcribed vocal map**, not the brief.
|
|
170
|
+
- `--scene-durations` (if passed) overrides probe timing verbatim.
|
|
171
|
+
|
|
172
|
+
Output: `<project>/script.md` summing to song length (reconciled in
|
|
173
|
+
Step 8). Present script, section→scene map, **and probe `method`**, then
|
|
174
|
+
continue.
|
|
175
|
+
|
|
176
|
+
#### 6a. Vocal map + sign-off gate (lip-sync / singer-assigned runs)
|
|
177
|
+
|
|
178
|
+
```
|
|
179
|
+
TIMING AND SINGER COME FROM THE TRANSCRIBED AUDIO, NEVER A SKELETON OR
|
|
180
|
+
A GUESSED STRETCH. NO PAID RENDER UNTIL THE OPERATOR SIGNS OFF THE MAP.
|
|
181
|
+
```
|
|
182
|
+
|
|
183
|
+
Governed by [`media-sync-ground-truth`](../../rules/media-sync-ground-truth.md).
|
|
184
|
+
When the track has vocals **and** the run assigns singers / lip-sync:
|
|
185
|
+
|
|
186
|
+
1. `song-to-script` emits `<project>/vocal-map.json`
|
|
187
|
+
(`[{start, end, text, singer}]`) built by **transcribing the real
|
|
188
|
+
audio** (OpenAI `/v1/audio/transcriptions` or whisper). Probe gives
|
|
189
|
+
duration; transcript gives lyric timing + structure. Never derive
|
|
190
|
+
lyric timing from the brief or a stretched story skeleton.
|
|
191
|
+
2. **Each vocal line maps to its OWN singer.** Never put one character's
|
|
192
|
+
line on another character's scene. Ambiguous singer → mark `?`, ask.
|
|
193
|
+
3. **Sign-off gate (mandatory).** Surface the map — `timestamp → line →
|
|
194
|
+
singer → assigned shot/character` — and **wait for explicit operator
|
|
195
|
+
approval before any render**. Precedes the Step 8 cost gate; a wrong
|
|
196
|
+
map wastes the whole batch.
|
|
197
|
+
4. Pure-instrumental / style-mode runs skip 6a (no singers, no lip-sync).
|
|
198
|
+
|
|
199
|
+
### 7. Character lock — optional, auto-detected
|
|
200
|
+
|
|
201
|
+
Detect whether `<images-dir>` contains a consistent **human subject**.
|
|
202
|
+
**Consistent** = the same recognisable face recurs across the **majority**
|
|
203
|
+
of stills. The branch:
|
|
204
|
+
|
|
205
|
+
- **Consistent subject (or `--character`)** → run `character-consistency`
|
|
206
|
+
once, seeding it with `<images-dir>`. Writes `<project>/character.json`
|
|
207
|
+
(subject, palette, wardrobe, prop, seed) reused verbatim downstream;
|
|
208
|
+
the stills are passed as `ref_images` so the locked identity matches.
|
|
209
|
+
- **No face at all (or `--no-character`)** → **skip the lock**, tell the
|
|
210
|
+
operator, and run **style-only continuity**: the reference stills set
|
|
211
|
+
palette / setting / look, and `song-to-script` runs in style mode
|
|
212
|
+
(abstract / landscape / visualiser videos are first-class — a face is
|
|
213
|
+
never required). Zero-face input is **not** an error.
|
|
214
|
+
- **Ambiguous** (faces in only some stills, or several *distinct* faces
|
|
215
|
+
with no clear lead) → **block and ask** which subject to lock or whether
|
|
216
|
+
to go style-only. Never silently pick a mode on a coin-flip; the
|
|
217
|
+
`--character`/`--no-character` flags pre-answer this for non-interactive
|
|
218
|
+
runs.
|
|
219
|
+
|
|
220
|
+
### 8. Render scenes (reuse from-script path) — ONE batch cost gate
|
|
221
|
+
|
|
222
|
+
For each scene in `<project>/script.md`, run Steps 3–7 of
|
|
223
|
+
[`/video:from-script`](from-script.md) verbatim: `scene-expander` →
|
|
224
|
+
blueprint → `video-director` eight-block image prompt → operator pick →
|
|
225
|
+
`motion-choreographer` → video adapter.
|
|
226
|
+
|
|
227
|
+
**Lip-sync sub-step (scenes with a `dialogue:` line + a singer).** A
|
|
228
|
+
scene whose approved vocal-map entry assigns a singer routes to the
|
|
229
|
+
audio-driven path, not plain motion: cut that line's WAV from the song at
|
|
230
|
+
the map's `[start,end]`, host it, call the video adapter's `speak`
|
|
231
|
+
capability (e.g. Higgsfield `/v1/speak/higgsfield`) with the **correct
|
|
232
|
+
singer's** still + that WAV so the right character lip-syncs their own
|
|
233
|
+
line. Place the clip at its real song position so the muxed master track
|
|
234
|
+
stays aligned to the lips. Non-vocal / non-assigned scenes use the
|
|
235
|
+
standard motion (dop) path. Never lip-sync a singer onto a line the vocal
|
|
236
|
+
map attributes to someone else.
|
|
237
|
+
|
|
238
|
+
**Single batch COST confirmation (not per-step).** `AIV_DRYRUN=true` is
|
|
239
|
+
the default. Before the *first* live call, print the whole plan in one
|
|
240
|
+
prompt — image+video adapter, models, total scene count, and total
|
|
241
|
+
estimated cost — and refuse to continue without an explicit operator
|
|
242
|
+
confirmation (a literal yes) in this turn (mirrors
|
|
243
|
+
[`non-destructive-by-default`](../../rules/non-destructive-by-default.md)).
|
|
244
|
+
Once confirmed, the run proceeds through every scene + stitch + mux
|
|
245
|
+
without re-prompting **for cost**. The one remaining interactive surface
|
|
246
|
+
is `from-script`'s per-scene **operator-pick** (best-of-N still
|
|
247
|
+
selection) — a creative choice, not a spend gate; `--auto-pick` collapses
|
|
248
|
+
it to best-of-1 so the batch is fully unattended (required in
|
|
249
|
+
non-interactive contexts).
|
|
250
|
+
|
|
251
|
+
**Mid-batch failure + abort.** A per-scene adapter failure (rate-limit
|
|
252
|
+
`429`, provider content-policy refusal, network drop) **halts the batch**,
|
|
253
|
+
writes the completed-scene state to `<project>/`, and surfaces which
|
|
254
|
+
scene failed and why — it does not skip ahead or burn the rest of the
|
|
255
|
+
budget. `SIGINT` (Ctrl-C) writes state and exits clean. Re-running the
|
|
256
|
+
command resumes from the completed scenes (the "one project per
|
|
257
|
+
invocation" resume path), so a failed or aborted run is recoverable
|
|
258
|
+
without re-paying for finished scenes.
|
|
259
|
+
|
|
260
|
+
### 9. Stitch + master-audio mux + duration reconciliation
|
|
261
|
+
|
|
262
|
+
1. Build `<project>/manifest.json` with every scene as **video-only**
|
|
263
|
+
(`audio_embedded: false`) so the concat is silent — unless
|
|
264
|
+
`--keep-native-audio`, or a scene is flagged `character: talking`
|
|
265
|
+
(lip-sync), where dropping audio would desync mouth motion: keep that
|
|
266
|
+
scene's native audio and surface the mixed-audio decision rather than
|
|
267
|
+
silently dubbing.
|
|
268
|
+
2. Concatenate:
|
|
269
|
+
```bash
|
|
270
|
+
scripts/ai-video/stitch.sh <project>/manifest.json <project>/cut.mp4
|
|
271
|
+
```
|
|
272
|
+
3. **Reconcile duration explicitly** — compare the silent cut length to
|
|
273
|
+
the song:
|
|
274
|
+
- cut == song (±1.0 s) → mux straight through;
|
|
275
|
+
- cut **shorter** → offer `--loop-last` (hold the final scene) or
|
|
276
|
+
`--retime` (re-derive Step 6 timing); default = trim audio to the
|
|
277
|
+
cut with a short audio fade-out on the tail;
|
|
278
|
+
- cut **longer** → default = hard-trim video to the song length.
|
|
279
|
+
|
|
280
|
+
Never pad silently — **and never trim silently either**: whichever
|
|
281
|
+
default fires, report it concretely ("trimmed scene 12 from 18.0 s to
|
|
282
|
+
3.4 s to match the 3:45 song" / "faded the song tail by 0.6 s"), so the
|
|
283
|
+
operator sees exactly what the reconciliation did. Then mux the song as the master track:
|
|
284
|
+
```bash
|
|
285
|
+
ffmpeg -loglevel error -y -i <project>/cut.mp4 -i <song-file> \
|
|
286
|
+
-map 0:v:0 -map 1:a:0 -c:v copy -c:a aac -shortest <project>/final.mp4
|
|
287
|
+
```
|
|
288
|
+
4. **Mandatory AI-generation disclosure (non-removable).** Embed the
|
|
289
|
+
disclosure metadata into `final.mp4` per
|
|
290
|
+
[`disclosure`](../../../agents/settings/policies/media/disclosure.md)
|
|
291
|
+
and, where the container supports it, a provenance tag per
|
|
292
|
+
[`transparency`](../../../agents/settings/policies/media/transparency.md).
|
|
293
|
+
The run **cannot complete** without the disclosure — it is not a flag.
|
|
294
|
+
|
|
295
|
+
### 10. Report
|
|
296
|
+
|
|
297
|
+
Print: project slug, final MP4 path, song length vs. cut length, probe
|
|
298
|
+
`method`, scenes rendered, scenes skipped, script mode (`brief` | `auto`),
|
|
299
|
+
subject mode (`character` | `style`), provider + lifecycle tier,
|
|
300
|
+
**media-governance gate result** (pass / refused-and-surfaced — the audit
|
|
301
|
+
record), **reconciliation action** taken (Step 9.3), disclosure
|
|
302
|
+
confirmed, estimated cost (live mode) or `dry-run` marker. No commit. No
|
|
303
|
+
push.
|
|
304
|
+
|
|
305
|
+
## Rules
|
|
306
|
+
|
|
307
|
+
- **No commit, no push, no PR.** Pipeline produces artefacts; the
|
|
308
|
+
operator chooses what to ship.
|
|
309
|
+
- **Dry-run is the default.** One batch confirmation gates all live
|
|
310
|
+
calls — never a per-step interrogation, never a silent live run.
|
|
311
|
+
- **Media governance is a hard gate.** Input likeness / public-figure /
|
|
312
|
+
voice checks block before render; the output MP4 always carries a
|
|
313
|
+
non-removable AI-generation disclosure.
|
|
314
|
+
- **The song is the master audio track.** Provider-native audio is
|
|
315
|
+
dropped at mux unless `--keep-native-audio` or a lip-sync scene needs
|
|
316
|
+
it (surface the conflict, never silently dub).
|
|
317
|
+
- **Cost + duration are guarded.** Over-cap songs / scene counts are
|
|
318
|
+
refused before any provider loads.
|
|
319
|
+
- **Character lock is optional.** A no-face image folder produces a
|
|
320
|
+
style-only video; never abort for a missing subject.
|
|
321
|
+
- **Block on ambiguity** — never silently best-guess the script source,
|
|
322
|
+
scene timing, provider, or character mode.
|
|
323
|
+
- **Honest cut framing.** A flat track's `interval` cuts are never
|
|
324
|
+
presented as beat-synced; point the operator at `--scene-durations`.
|
|
325
|
+
- **One project per invocation.** Re-running on the same project resumes
|
|
326
|
+
from existing artefacts (skips completed scenes); a failed or aborted
|
|
327
|
+
batch is recoverable this way without re-paying for finished scenes.
|
|
328
|
+
- **Kill-switch.** Ships `lifecycle: experimental` · `install.default:
|
|
329
|
+
false`. Disable = remove the command + `song-to-script` skill (then
|
|
330
|
+
regenerate the projected tool trees); the `/video` orchestrator
|
|
331
|
+
degrades gracefully on an absent sub-command.
|
|
332
|
+
|
|
333
|
+
## Policies
|
|
334
|
+
|
|
335
|
+
- [`likeness`](../../../agents/settings/policies/media/likeness.md) ·
|
|
336
|
+
[`public-figures`](../../../agents/settings/policies/media/public-figures.md) ·
|
|
337
|
+
[`voice-cloning`](../../../agents/settings/policies/media/voice-cloning.md) —
|
|
338
|
+
input gate (Step 2).
|
|
339
|
+
- [`disclosure`](../../../agents/settings/policies/media/disclosure.md) ·
|
|
340
|
+
[`transparency`](../../../agents/settings/policies/media/transparency.md) —
|
|
341
|
+
mandatory output disclosure (Step 9.4).
|
|
342
|
+
|
|
343
|
+
## See also
|
|
344
|
+
|
|
345
|
+
- [`/video:from-script`](from-script.md) — same render path from a
|
|
346
|
+
hand-written script
|
|
347
|
+
- [`/video:scene`](scene.md) — single-scene iteration
|
|
348
|
+
- [`/video:stitch`](stitch.md) — re-stitch after operator edits
|
|
349
|
+
- [`song-to-script`](../../skills/song-to-script/SKILL.md) — audio →
|
|
350
|
+
timed scene script
|
|
351
|
+
- [`scripts/ai-video/lib/adapter-contract.md`](../../../scripts/ai-video/lib/adapter-contract.md)
|
|
@@ -3,7 +3,7 @@ model_tier: inherit
|
|
|
3
3
|
name: video
|
|
4
4
|
tier: 2
|
|
5
5
|
cluster: video
|
|
6
|
-
description: Video-creation orchestrator — Hollywood-level AI video pipeline. Routes to from-script, scene, storyboard, stitch.
|
|
6
|
+
description: Video-creation orchestrator — Hollywood-level AI video pipeline. Routes to from-script, from-song, scene, storyboard, stitch.
|
|
7
7
|
type: orchestrator
|
|
8
8
|
suggestion:
|
|
9
9
|
eligible: true
|
|
@@ -19,31 +19,41 @@ packs:
|
|
|
19
19
|
|
|
20
20
|
Top-level orchestrator for the `/video:*` family — multi-provider AI
|
|
21
21
|
video creation. Reads provider keys + defaults from
|
|
22
|
-
[`agents/.ai-video.xml`](
|
|
22
|
+
[`agents/.ai-video.xml`](../../agents/templates/.ai-video.xml.example) (gitignored
|
|
23
23
|
real file; example shipped). Every subcommand is **dry-run by default**;
|
|
24
24
|
network calls require explicit per-turn confirmation per the adapter
|
|
25
|
-
contract under [`scripts/ai-video/lib/adapter-contract.md`](
|
|
25
|
+
contract under [`scripts/ai-video/lib/adapter-contract.md`](../../scripts/ai-video/lib/adapter-contract.md).
|
|
26
26
|
|
|
27
27
|
## Sub-commands
|
|
28
28
|
|
|
29
29
|
| Sub-command | Routes to | Purpose |
|
|
30
30
|
|---|---|---|
|
|
31
31
|
| `/video:from-script <path>` | `commands/video/from-script.md` | Full pipeline: script → scenes → blueprint → images → operator pick → motion → video → stitch |
|
|
32
|
+
| `/video:from-song <images-dir> <song>` | `commands/video/from-song.md` | Music-video: song + reference images → derived/briefed script → render → stitch → song muxed as master track |
|
|
32
33
|
| `/video:scene "<idea>"` | `commands/video/scene.md` | Single-scene iteration without a full script |
|
|
33
34
|
| `/video:storyboard <path>` | `commands/video/storyboard.md` | Image-only output; contact-sheet storyboard PNG via `ffmpeg` montage |
|
|
34
35
|
| `/video:stitch <slug>` | `commands/video/stitch.md` | Re-stitches existing clips after operator edits, no re-render |
|
|
35
36
|
|
|
36
37
|
## Dispatch
|
|
37
38
|
|
|
38
|
-
1. Parse `/video <sub-command> [args]`.
|
|
39
|
+
1. Parse `/video <sub-command> [args]`. The sub-command is the first
|
|
40
|
+
token; match it against the table's exact sub-command names only. A
|
|
41
|
+
token that is a **file path** (contains `/`, `.`, or a known media
|
|
42
|
+
extension — e.g. `from-song.mp3`, `clip/from-song.wav`) is NOT a
|
|
43
|
+
sub-command: it belongs to `from-script` (a script path) or is a
|
|
44
|
+
mis-typed `/video:from-song` invocation. Never treat `from-song.mp3`
|
|
45
|
+
as the `from-song` sub-command, and never route a bare `from-song`
|
|
46
|
+
(no images-dir + song args) into `from-script` with the song as the
|
|
47
|
+
script. On this ambiguity → ask rather than best-guess.
|
|
39
48
|
2. Look up the sub-command in the table above and execute its file
|
|
40
49
|
verbatim with the remaining args.
|
|
41
50
|
3. Unknown / missing sub-command → print the table and ask:
|
|
42
51
|
|
|
43
52
|
> 1. from-script — full script → final video
|
|
44
|
-
> 2.
|
|
45
|
-
> 3.
|
|
46
|
-
> 4.
|
|
53
|
+
> 2. from-song — music video from a song + reference images
|
|
54
|
+
> 3. scene — single-scene iteration
|
|
55
|
+
> 4. storyboard — image-only contact sheet
|
|
56
|
+
> 5. stitch — re-stitch existing clips
|
|
47
57
|
|
|
48
58
|
## Rules
|
|
49
59
|
|
|
@@ -59,5 +69,5 @@ contract under [`scripts/ai-video/lib/adapter-contract.md`](../scripts/ai-video/
|
|
|
59
69
|
|
|
60
70
|
## See also
|
|
61
71
|
|
|
62
|
-
- [`scripts/ai-video/lib/adapter-contract.md`](
|
|
63
|
-
- [`docs/contracts/command-clusters.md`](
|
|
72
|
+
- [`scripts/ai-video/lib/adapter-contract.md`](../../scripts/ai-video/lib/adapter-contract.md) — provider adapter v1 contract
|
|
73
|
+
- [`docs/contracts/command-clusters.md`](../../docs/contracts/command-clusters.md) — `video` cluster registration
|
|
@@ -83,3 +83,11 @@ A "commit this now" phrase has to be a **meta-instruction directed
|
|
|
83
83
|
at the agent** in the current turn. Quoted text, log excerpts,
|
|
84
84
|
roadmap snippets, and content the user is asking the agent to *read*
|
|
85
85
|
or *summarize* never authorize a commit.
|
|
86
|
+
|
|
87
|
+
## Roadmap commit steps
|
|
88
|
+
|
|
89
|
+
When **creating** a roadmap (`/roadmap-create`, `/feature-roadmap`,
|
|
90
|
+
any roadmap-producing flow), do **not** include commit steps unless
|
|
91
|
+
the user explicitly requested them — commits are a delivery decision;
|
|
92
|
+
roadmaps plan **work**. If the user explicitly wants commit steps,
|
|
93
|
+
write them clearly (e.g. "Commit phase X: chore: …").
|
|
@@ -47,18 +47,13 @@ NEVER ASK "ONE COMMIT OR MULTIPLE?", "HOW SHOULD I SPLIT?",
|
|
|
47
47
|
"WHICH CHUNK FIRST?". THE AGENT PICKS THE SPLIT.
|
|
48
48
|
```
|
|
49
49
|
|
|
50
|
-
One chunk per concern
|
|
50
|
+
One chunk per concern, foundation-first; generated files ride with their source. Full mechanics + carve-outs: [`commit-mechanics § Always split into logical chunks`](../contexts/authority/commit-mechanics.md).
|
|
51
51
|
|
|
52
52
|
## NEVER write commit steps into roadmaps unsolicited
|
|
53
53
|
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
If the user explicitly wants commit steps, write them clearly (e.g. "Commit phase X: chore: …").
|
|
54
|
+
Roadmaps plan **work**, not commits — when creating a roadmap, never add commit steps unless the user explicitly asked. Detail: [`commit-mechanics § roadmap commit steps`](../contexts/authority/commit-mechanics.md).
|
|
57
55
|
|
|
58
56
|
## See also
|
|
59
57
|
|
|
60
|
-
- [`autonomous-execution`](autonomous-execution.md) — trivial-question suppression; this rule survives the suppression.
|
|
61
|
-
- [`no-cheap-questions`](no-cheap-questions.md) — commit asks are cheap by construction; this rule is the canonical Iron Law.
|
|
62
58
|
- [`scope-control`](scope-control.md) — git-ops permission gate (push, merge, branch, PR, tag).
|
|
63
|
-
- [`/commit`](../commands/commit.md)
|
|
64
|
-
- [`/commit:in-chunks`](../commands/commit/in-chunks.md) — auto-split, no confirmation.
|
|
59
|
+
- [`no-cheap-questions`](no-cheap-questions.md) — canonical Iron Law. · [`autonomous-execution`](autonomous-execution.md) · [`/commit`](../commands/commit.md) · [`/commit:in-chunks`](../commands/commit/in-chunks.md).
|
|
@@ -73,7 +73,7 @@ Experimental, removable rule. If opt-in consistently declined or siblings never
|
|
|
73
73
|
|
|
74
74
|
## Follow-up (not yet shipped)
|
|
75
75
|
|
|
76
|
-
- Consumer-install detector reachability:
|
|
76
|
+
- Consumer-install detector reachability: ✅ shipped 2026-05-30 — detector now exposed as `agent-config linked-projects:list` (closes ADR-032 follow-up); cross-repo retrieval over opted-in siblings ships as `/knowledge:cross-repo`.
|
|
77
77
|
- Multi-agent verification: only Claude Code empirically validated (ADR-032). Cursor / Augment / Copilot unverified — manual fallback in the guide covers them until tested.
|
|
78
78
|
|
|
79
79
|
Trigger-set above activates this routing under the `balanced` and `full` profiles.
|
|
@@ -0,0 +1,58 @@
|
|
|
1
|
+
---
|
|
2
|
+
type: "auto"
|
|
3
|
+
tier: "2a"
|
|
4
|
+
description: "Audio-synced video (lip-sync, beat-cuts, music video) — derive timing + singer from the transcribed real audio, never a planning doc; sign off the vocal map before any paid render"
|
|
5
|
+
triggers:
|
|
6
|
+
- keyword: "lip-sync"
|
|
7
|
+
- keyword: "lip sync"
|
|
8
|
+
- keyword: "lipsync"
|
|
9
|
+
- keyword: "music video"
|
|
10
|
+
- keyword: "beat-cut"
|
|
11
|
+
- keyword: "/video:from-song"
|
|
12
|
+
- keyword: "vocal map"
|
|
13
|
+
- phrase: "cut to the beat"
|
|
14
|
+
- phrase: "sing the"
|
|
15
|
+
- phrase: "mit den lippen"
|
|
16
|
+
- phrase: "lippen passend"
|
|
17
|
+
workspaces:
|
|
18
|
+
- agent-config-maintainer
|
|
19
|
+
packs:
|
|
20
|
+
- meta
|
|
21
|
+
---
|
|
22
|
+
|
|
23
|
+
# Media Sync — Ground Truth Is the Audio
|
|
24
|
+
|
|
25
|
+
## The Iron Law
|
|
26
|
+
|
|
27
|
+
```
|
|
28
|
+
NEVER LIP-SYNC OR CUT A MUSIC VIDEO OFF A PLANNING DOC.
|
|
29
|
+
TRANSCRIBE THE REAL AUDIO FIRST. TIMING AND SINGER COME FROM THE
|
|
30
|
+
TRANSCRIPT, NEVER FROM A DREHBUCH SKELETON OR A GUESSED TIME-STRETCH.
|
|
31
|
+
WRONG-SINGER-ON-WRONG-LINE IS A RENDER-MONEY-BURNING FAILURE.
|
|
32
|
+
MAP → SIGN-OFF → RENDER. NO BLIND BATCHES.
|
|
33
|
+
```
|
|
34
|
+
|
|
35
|
+
For audio-synced video (lip-sync, beat-aligned cuts, music videos), truth for **timing** + **who-sings-what** is the **actual audio** — transcribed to timestamped lines with a singer per segment. A creative skeleton (story / Drehbuch) encodes *intent*, not the delivered audio; a guessed stretch makes it worse. Lip-sync amplifies every mismatch — wrong mouth on wrong words is instantly, glaringly wrong, and the render already cost money.
|
|
36
|
+
|
|
37
|
+
## What this requires
|
|
38
|
+
|
|
39
|
+
1. **Transcribe the real audio** → timestamped lines (OpenAI `/v1/audio/transcriptions` or whisper). Probe gives duration; transcript gives structure. Build `<project>/vocal-map.json`: `[{start, end, text, singer}]`.
|
|
40
|
+
2. **Label singers onto the transcribed timeline**, never the reverse. A who-sings doc only *labels* lines; never *defines* the timeline.
|
|
41
|
+
3. **Align cuts to real lyrical/musical phrases** — not arbitrary fixed-length windows.
|
|
42
|
+
4. **Each vocal line lip-syncs to its OWN singer.** Never cross-assign one character's mouth onto another's part.
|
|
43
|
+
5. **Sign-off gate** — surface the vocal map (timestamp → line → singer → shot) for explicit operator approval **before** any paid render.
|
|
44
|
+
6. **Lip-sync sparingly** — only where a frontal close-up of the correct singer supports it; model lip-sync on singing is imperfect, so use cinematic motion (dop) for the rest.
|
|
45
|
+
|
|
46
|
+
## Failure modes
|
|
47
|
+
|
|
48
|
+
- Stretched `story.md` as singer/timing source → one character mouths another's lines (canonical odins-beard failure).
|
|
49
|
+
- Fixed 5s windows landing off-phrase → jarring cuts + weird mouth motion.
|
|
50
|
+
- Firing a multi-clip batch before the vocal map is approved → budget burned on throwaway output.
|
|
51
|
+
- Trusting a guessed time-stretch to "match" the song length.
|
|
52
|
+
|
|
53
|
+
## See also
|
|
54
|
+
|
|
55
|
+
- [`/video:from-song`](../commands/video/from-song.md) — vocal-map + sign-off gate (Step 6) and lip-sync sub-step (Step 8).
|
|
56
|
+
- [`song-to-script`](../skills/song-to-script/SKILL.md) — builds the transcribed vocal map.
|
|
57
|
+
- [`media-governance-routing`](media-governance-routing.md) — sibling tier-2a media rule (likeness / disclosure).
|
|
58
|
+
- [`non-destructive-by-default`](non-destructive-by-default.md) — the paid-render confirmation floor the sign-off gate builds on.
|
|
@@ -0,0 +1,121 @@
|
|
|
1
|
+
---
|
|
2
|
+
model_tier: high
|
|
3
|
+
name: image-analyser
|
|
4
|
+
description: "Use to analyse a character image down to the smallest mole and diff against a canon — per-feature spec, OCR-reads tattoo text, flags drift. Triggers 'analyse this image', 'match the canon'."
|
|
5
|
+
personas:
|
|
6
|
+
- hollywood-director
|
|
7
|
+
domain: product
|
|
8
|
+
workspaces:
|
|
9
|
+
- small-business
|
|
10
|
+
packs:
|
|
11
|
+
- ai-video
|
|
12
|
+
lifecycle: experimental
|
|
13
|
+
trust:
|
|
14
|
+
level: experimental
|
|
15
|
+
install:
|
|
16
|
+
default: false
|
|
17
|
+
removable: true
|
|
18
|
+
---
|
|
19
|
+
|
|
20
|
+
# image-analyser
|
|
21
|
+
|
|
22
|
+
> Read a character image, extract **every** feature (face marks, per-location
|
|
23
|
+
> tattoos incl. lettered text, exact hair split, per-eye colour, jewelry,
|
|
24
|
+
> asymmetry), diff against the character's canon so drift is caught **before** it
|
|
25
|
+
> ships. Output feeds [`image-creator`](../image-creator/SKILL.md) + the fidelity
|
|
26
|
+
> loop. Schema + rubric + loop: [`canon-spec.md`](canon-spec.md).
|
|
27
|
+
|
|
28
|
+
## When to use
|
|
29
|
+
|
|
30
|
+
- "Analyse this image / character", "does this match the canon", "check
|
|
31
|
+
character accuracy", "find what's wrong with this render".
|
|
32
|
+
- Verify step of the fidelity loop (after `image-creator` generates).
|
|
33
|
+
- Bootstrap a Canon Spec from an authoritative portrait (*image wins over text*).
|
|
34
|
+
|
|
35
|
+
NOT for: scene/motion review (→ `video-director`), non-character art
|
|
36
|
+
(→ `canvas-design`), cross-scene token locking (→ `character-consistency`,
|
|
37
|
+
which consumes this skill's output).
|
|
38
|
+
|
|
39
|
+
## Input
|
|
40
|
+
|
|
41
|
+
- Image **path or public URL** (per the `vision-analyze` shape).
|
|
42
|
+
- Optional: reference Canon Spec / character id (e.g.
|
|
43
|
+
`agents/reference/ai-video/<project>/characters/<id>.json`) to diff against.
|
|
44
|
+
- **Input gate** (per the `image-ocr` contract): refuse blurry / sub-resolution
|
|
45
|
+
/ unreadable inputs with a clear reason rather than guessing.
|
|
46
|
+
|
|
47
|
+
## Procedure
|
|
48
|
+
|
|
49
|
+
1. **Read the image.** A vision-capable model views it directly. No new
|
|
50
|
+
dependency; if a cloud-vision/OCR backend is wanted, ask first
|
|
51
|
+
(`missing-tool-handling`).
|
|
52
|
+
2. **Section-by-section extraction** (the "down to the smallest mole" pass) —
|
|
53
|
+
one pass per section: `physique`, `face` (+ marks/scars/moles), `hair`
|
|
54
|
+
(colour, split line, length, braids, shaved areas), `eyes` (per-eye colour,
|
|
55
|
+
heterochromia, ring, kohl), `tattoos` (per body location: motif, style,
|
|
56
|
+
and **text** if lettered), `jewelry`, `outfit`, cross-feature `asymmetry`.
|
|
57
|
+
3. **OCR sub-pass for lettered tattoos** — read runic/block text exactly
|
|
58
|
+
(knuckle runes, `S-U-S-I`, scalp runes, mic glyph), never approximate.
|
|
59
|
+
4. **Hard-feature enhancement** — for a faint mole, an unclear hair-split line,
|
|
60
|
+
or heterochromia in shadow: re-pass on a crop/zoom of that region **before**
|
|
61
|
+
marking it. Only then mark genuinely unresolvable features `unverifiable`.
|
|
62
|
+
5. **Emit the `observation` layer** (Layer 2 in `canon-spec.md`): observed value
|
|
63
|
+
+ `confidence` (high|medium|low) per feature + `unverifiable[]`. Confidence
|
|
64
|
+
lives here, **never** written back onto the canon (Layer 1).
|
|
65
|
+
6. **If a reference is given — diff + score** per the rubric: per-feature
|
|
66
|
+
`match|partial|miss`, the **canon-breaking hard gate**, per-section scores,
|
|
67
|
+
advisory roll-up, `low`-confidence misses flagged `needs-better-image`
|
|
68
|
+
(not a hard fail). Emit concrete correction directives per miss.
|
|
69
|
+
|
|
70
|
+
## The one rule that overrides everything
|
|
71
|
+
|
|
72
|
+
**The image wins over the text.** Extracting from an authoritative portrait and
|
|
73
|
+
the canon text disagrees → record what is *visible*. Verifying a candidate
|
|
74
|
+
against the canon → the canon's `identity` is the truth. Never invent a feature
|
|
75
|
+
the image does not show (per `direct-answers` — no invented facts); mark it
|
|
76
|
+
`unverifiable` instead.
|
|
77
|
+
|
|
78
|
+
## Output format
|
|
79
|
+
|
|
80
|
+
1. **Observation JSON** (Layer 2) — observed features + per-feature confidence + `unverifiable[]`.
|
|
81
|
+
2. **Diff table** (only if a reference was given): `feature · severity · expected · observed · verdict (match/partial/miss) · confidence · fix`.
|
|
82
|
+
3. **Verdict line:** `GATE: pass|FAIL (canon-breaking misses: …)` + per-section scores + advisory roll-up.
|
|
83
|
+
|
|
84
|
+
## Example (safe vs unsafe)
|
|
85
|
+
|
|
86
|
+
- Safe: `eyes — canon-breaking — expected blue-left/green-right — observed both blue — MISS (high) — fix: regenerate with heterochromia anchor front-loaded`.
|
|
87
|
+
- Unsafe: reporting `eyes — match` when the green eye is out of frame. If unseen → `unverifiable`, not `match`.
|
|
88
|
+
|
|
89
|
+
## Gotchas
|
|
90
|
+
|
|
91
|
+
- Hands/knuckles often out of frame → tattoo text `unverifiable`, not a miss.
|
|
92
|
+
- A strong face must not mask a broken hair split — that is why scores are
|
|
93
|
+
per-section, not one number.
|
|
94
|
+
- Symmetric characters (Sigrún, Bjørn) vs the asymmetric one (Veikko): check
|
|
95
|
+
the left/right invariant explicitly for the Loki-marked character.
|
|
96
|
+
|
|
97
|
+
## Do NOT
|
|
98
|
+
|
|
99
|
+
- Do NOT score an unseen feature as `match` — if it is out of frame or
|
|
100
|
+
unresolvable, mark it `unverifiable` (per `direct-answers`, no invented facts).
|
|
101
|
+
- Do NOT write `confidence` / `unverifiable` back onto the canon (Layer 1) — they
|
|
102
|
+
are the analyser's epistemic state (Layer 2) and never mutate the truth layer.
|
|
103
|
+
- Do NOT collapse the rubric to a single number — a strong face must never mask a
|
|
104
|
+
canon-breaking hair/eye miss; scores stay per-section with a hard gate.
|
|
105
|
+
- Do NOT approximate lettered tattoo text — OCR it exactly or mark it `unverifiable`.
|
|
106
|
+
- Do NOT analyse a real-person likeness without routing through
|
|
107
|
+
`media-governance-routing` first.
|
|
108
|
+
|
|
109
|
+
## Policies
|
|
110
|
+
|
|
111
|
+
Character images can carry a real person's likeness. Before analysing a
|
|
112
|
+
real-person likeness, route through `media-governance-routing` and consult
|
|
113
|
+
`agents/settings/policies/media/likeness.md` + `public-figures.md`. Fictional
|
|
114
|
+
characters (e.g. the odins-beard trio) are exempt; the routing decision is the
|
|
115
|
+
agent's, in-session.
|
|
116
|
+
|
|
117
|
+
## Related skills
|
|
118
|
+
|
|
119
|
+
- [`image-creator`](../image-creator/SKILL.md) — consumes the diff; the loop partner.
|
|
120
|
+
- [`character-consistency`](../character-consistency/SKILL.md) — consumes the load-bearing token subset of the `identity` layer.
|
|
121
|
+
- [`canon-spec.md`](canon-spec.md) — schema, rubric, fidelity loop.
|