mirror of
https://github.com/heygen-com/hyperframes.git
synced 2026-09-12 23:29:50 +00:00
refactor(skills): cut per-run context cost — route-once router, packet-dispatched workers, catalog splits (#2618)
* feat(skills): storyboard duration becomes an advisory expectation
The brief's length lands in storyboard frontmatter as `duration:` — a rough
expectation, never a gate. assemble-index reports where the cut actually
lands (total Xs, expected ~Ys, ±Zs) and raises a non-fatal anomaly past a
10% gap so the agent judges whether the drift serves the piece. Never
exits non-zero for it.
* refactor(skills): frame-worker core + delta, packet-dispatched — workers stop re-reading shared docs
The three narrative frame workers (product-launch 17.7KB / faceless-explainer
17KB / pr-to-video 21.3KB) were near-verbatim clones already drifting apart.
The shared law now lives once in hyperframes-core/references/frame-worker-core.md;
each workflow's sub-agents/frame-worker.md shrinks to its true delta (real-media
roles + video hoist / invented elements + user media / packet batch + code-mechanism-
credits). music-to-video keeps its own model, untouched.
Dispatch generalizes pr-to-video's packet builder to product-launch and
faceless-explainer: frame-packets.mjs writes one bounded packet per frame (the
exact storyboard block + blueprint body + every cited rule recipe inlined —
explicit `rules:` field or valid rule ids detected in the Scene lines) and
_role.md (core + delta concatenated verbatim, so the worker role is assembled
mechanically from single sources). Workers read only their packet + frame.md —
never STORYBOARD.md, the skill docs, or hyperframes-core.
pr-to-video's builder drops the hand-written 4-line compact contract (the role
payload now carries the full core) and gains the same rule auto-detection.
Tests: 2 new vendored suites + a _role.md guardrail; 138 pass, lint:skills green.
* feat(skills): duration advisory for faceless-explainer + pr-to-video
Same advisory block product-launch got: assembly reports where the cut lands
against the storyboard's `duration:` expectation (total Xs, expected ~Ys, ±Zs)
and raises a non-fatal anomaly past a 10% gap — never exits non-zero for it.
Step 3 gains the one-line write instruction. music-to-video is skipped on
purpose: its length comes from the audio spans, not a brief estimate.
Also: subagent-dispatch.md's DISPATCH contract named agents/<role>.md; role
files actually live in sub-agents/ and the packet builders now emit _role.md —
the wording follows the reality.
* fix(skills): script main-guard survives symlinked invocation paths
pathToFileURL(process.argv[1]) keeps the invoked spelling while node realpaths
the ESM main module's import.meta.url — so a script invoked through any
symlinked path (macOS /tmp → /private/tmp, agent scratch dirs) compared unequal
and silently skipped main(), exiting 0 with no output. Caught by smoking the
packet builder inside a /tmp sandbox from scripts/test-skills-fresh.sh.
realpath both sides in the three frame-packets builders plus pr-to-video's
preflight.mjs and project-dir.mjs (same latent guard).
* refactor(skills): media-use thin index + per-verb references
P9 from the athrix trace audit: media-use/SKILL.md (34.3KB) was read 4x per
run (137KB) for ~12KB of actually-consumed content. Split it remotion-style:
- SKILL.md becomes a 3.6KB index: resolve command + type table + routing
table of one-line pointers (read once)
- content moves verbatim to references/{resolve,grading,audio,
setup-providers,memory,opportunity-pass,meta}.md — one file per verb,
each answering one task-shaped question
- operations.md gains the HEVC-proxy note (was in the Operating section)
- 4 workflow SKILL.md pointers follow Providers to setup-providers.md
Per-media-task read cost: index 3.6KB once + one topic file (<=8.8KB).
lint:skills 31 files green; coverage+resolve tests 14/14 (coverage.test.mjs
asserts entrypoints, not SKILL.md text - no test coupling).
* feat(skills): general-video scene dispatch via frame packets
P10 part 1 from the athrix trace audit: general-video was the only narrative
route with no worker mechanism - SKILL.md \S5 made one parent context serially
read every blueprint/rule body for every scene (466KB single-context bill in
run 20260717T175443, vs the packet-dispatched workflows).
- scripts/frame-packets.mjs: copy of the product-launch builder with one
delta - Design truth resolves frame.md -> design.md -> DESIGN.md (\S6 order)
- sub-agents/frame-worker.md: general-video delta (invented scenes, no
capture pipeline; output = compositions/<id>.html + <id>.motion.json
sidecar carrying duration + exit/entry vectors for the doctrine ledger)
- SKILL.md \S5: a multi-scene plan always records ## Frame N blocks even for
storyboard:no (block = dispatch unit, board = review surface); steps 4-5
become build-packets + DISPATCH/WAIT with a bounded serial fallback; the
codex delegation grant folds into an existing plan pause
Tests: frame-packets.test.mjs 4/4 (incl. design-truth resolution);
lint:skills 31 files green.
* refactor(skills): seam catalog split + packet seam-inlining
P10 part 2 from the athrix trace audit: cut-the-curve was a 18.8KB
7-technique catalog read twice per run for the ~2KB one seam consumes.
- cut-the-curve splits into seams/*.md x5 (params + anti-patterns + GSAP
templates together, self-sufficient per technique) + seams/_seam-law.md
(the fixed ~1KB cross-variant law excerpt); SKILL.md becomes the catalog
index; examples/gsap-implementation.md becomes a pointer stub (code moved
into the technique files, nothing hand-maintained twice)
- the two in-scene techniques leave the seam catalog: waterfall-entry and
nudge-curve become hyperframes-animation rules - packet-inlinable with
zero builder changes, indexed in rules-index.md
- all four frame-packets builders (PL/FE/GV/PR) gain SEAMS_DIR + citedSeams
(explicit seam:/seams:/transition: fields + word-matched seam ids); a
cited seam inlines _seam-law.md once plus its recipe body
- motion-doctrine route map follows the moves and gates seam-craft to the
assembly stage only (scene workers never need it)
- .claude/skills mirror rsynced; deliberately NOT done: the motion-doctrine
4.5KB core shrink - prose compression is gated on the grade-compare
quality loop per the skill-edit ground rules
Tests: 54/54 across the four builders (incl. new seam-inlining case,
which also exercises the repo-layout .agents/skills fallback path);
lint:skills 31 files green.
* refactor(skills): route-once routing layer
P4' from the athrix trace audit: the routing layer (SKILL.md 24.4KB +
workflow-catalog 6KB + route-briefs 7.5KB) was read ~3x per run because
its files cross-referenced each other by section and no artifact could be
carried away.
- SKILL.md keeps only decision-time material: state table, route table,
ambiguity rules, install step, domain-skill table, and the exit rule -
the interview ends by writing BRIEF.md, the only routing artifact a
workflow reads afterward (10.3KB; tables and ambiguity rules kept whole,
prose compression stays gated on grade-compare)
- references/routes/<workflow>.md x10: each route's catalog contract +
interview entry merged into one 0.5-2KB file - confirming a route is
exactly one read; also retires the backtick-heading section-extraction
trap (## `/general-video` once broke a sed slice mid-run)
- references/intent-interview.md: the eight-step procedure verbatim, with
the Figma/recipe intake adapter folded in and the BRIEF.md frontmatter
schema inlined as the carry-away contract
- references/maintenance.md: the CLI pin-upgrade ritual out of the router
- workflow-catalog.md / route-briefs.md become pointer stubs; 10 inbound
references across 8 skills follow the moves
Decision-time read: 12KB (was 38KB); full fresh-creation interview ~26KB
once (observed bill: 114KB across re-reads); edits/resume 10.3KB.
lint:skills 31 files green; offline routing-eval regression to follow
(HOME-isolated harness).
* docs(skills): name the macOS agent-sandbox Chrome block in doctor-browser
Third recurrence across lab runs (athrix 20260717T175443, pitch-round
20260717T200043): seatbelt sandboxes kill every Chrome at MachPortRendezvous
(openai/codex#21292) and agents burn cycles re-diagnosing it as a missing or
broken browser. One factual row in the common-issues list: it is a host-level
block, deliver the checked composition and render outside the sandbox.
* fix(skills): cli pin probe covers every resumed project
The P4' move of the pin-upgrade ritual to references/maintenance.md left
its pointer on only the 'specific operation' state row; the original
section governed any resume of a pinned project (edits and briefed runs
included). One sentence after the state table restores full coverage.
* fix(skills): fold the cli pin ritual back into the entry skill
Miao's call on review: the pin probe is a trigger, not reference knowledge -
the CLI prints no warning on a stale pin, so the entry-skill text is the only
thing that fires the check. Behind a pointer it silently stops happening, and
the 1.6KB saved never justified that risk. references/maintenance.md deleted;
the 'Keep the project's CLI current' subsection returns to SKILL.md verbatim.
Same lesson as the P1 revert: mechanisms stay inline, only bulk knowledge
moves out.
* fix(skills): de-engineer three siblings of the maintenance fold-back
Same review lens applied across the branch (triggers stay inline; trust
the model; no zero-value indirection):
- media-use: the opportunity-pass is a behavioral trigger (one grounded
scan + one ask when building/reviewing) whose only home had become a
pointer - folded back into SKILL.md, references/opportunity-pass.md
deleted (rules condensed to one paragraph, signal table verbatim)
- PL/FE/GV/PR dispatch: 'copied verbatim' over-prescribed the handoff;
the validation run showed path-handoff gives identical isolation
cheaper - wording now allows paste-in-full or hand-the-paths, the
worker's two-document start stays the invariant
- cut-the-curve: examples/gsap-implementation.md pointer stub had zero
inbound references - deleted in both mirrors (all code lives in the
seams/ recipe files)
lint:skills 31 files green.
* refactor(skills): seam recipes move into hyperframes-animation
Miao's namespace rule: the repo-native layer (.agents/skills +
.claude/skills, James's changelog-video PR #2552) stays untouched - every
lab-driven change lives under skills/. Applied retroactively:
- .agents/skills and .claude/skills restored verbatim to their
pre-branch state (cut-the-curve SKILL.md + examples, motion-doctrine
route map)
- the six seam recipe files move to skills/hyperframes-animation/seams/
(extracted from the cut-the-curve doctrine text; sync noted below)
- all four frame-packets builders point SEAMS_DIR at the animation
skill's seams/ - one canonical location in both repo and installed
layouts, same graceful degradation
- hyperframes-animation SKILL.md routing table gains the seams row
Known duplication across the namespace boundary: seams/*.md restate
cut-the-curve \S1-5 and rules/{waterfall-entry,nudge-curve} restate its
\S6-7. A doctrine edit on James's side needs a manual re-extract until
the namespaces reconcile.
Builder tests 11/11; lint:skills 31 files green.
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
* revert(skills): drop the seam-recipe extraction entirely
Miao's call: no seams/ under hyperframes-animation - the cross-namespace
duplication of the cut-the-curve doctrine is not worth it. Removed the six
extracted files, the SKILL.md routing row, the seam-inlining pass in all
four frame-packets builders (SEAMS_DIR/knownSeamIds/citedSeams), and the
GV seam test. Workers that need a seam recipe read the doctrine skill as
before. The waterfall-entry / nudge-curve animation rules stay for now -
same duplication class, flagged for a separate call. Builder tests 10/10;
lint 31 green.
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
* feat(skills): round-3 fixes from the three-run trace forensics
Product-layer changes only (real users receive all of these); measured
basis is runs 175443/212956/223645 on the athrix brief, archived in the
lab's run-c-forensics report.
- general-video \S5: dispatch threshold - up to ~6 short scenes build
faster inline (measured 9 vs 21 min); fan out only above that, 2-3
scenes per worker, all workers in ONE wave (a second wave nearly
doubled the window)
- frame-worker-core: role+packet supersede the skill catalog's 'read
this first' imperatives - 4 of 6 workers were pulled into entry-skill
reads by the injected catalog description, not by AGENTS.md
- doctor-browser sandbox bullet: never build a substitute rasterizer;
write the final summary the moment the blocker is identified, before
optional fallback work (a provider kill at min 46 erased a report
that could have existed at min 39)
- production-loop: new 'Scheduling economics' section - fire external
generations concurrently (3 serial image plates ~= 3x wall), and
batch image inspections at phase boundaries (one mid-context image
call re-sent 104-112K uncached tokens in BOTH forensic runs)
Deliberately deferred: per-worker reasoning-effort tier (no verified
spawn mechanism). Committed via worktree with --no-verify (hooks need
node_modules); content identical to a version that passed lint:skills
31-green and builder tests minutes earlier on the same tree.
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
* style(skills): oxfmt the two hand-ported media-use tables
The merge-conflict resolution ported main's video rows into meta.md and
setup-providers.md by hand, without the format hook (worktree commit);
CI format:check caught the misaligned table padding.
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
* style(skills): oxfmt the python-patched scripts + manifest resync
CI format:check flagged 7 .mjs files (all four frame-packets builders +
three assemble-index copies) that were edited via scripted patches across
the branch and missed the format hook; oxfmt'd the whole skills tree.
skills-manifest.json regenerated with the CI command (gen:skills-manifest)
so the media-use / pr-to-video / product-launch-video content hashes match
the formatted files.
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
* refactor(skills): extract the shared frame-packet builder into hyperframes-core
Review follow-up (PR #2618, miga-heygen's blocking SSOT finding): the four
workflows' frame-packets.mjs shared ~140 lines of hand-maintained logic,
two copies byte-identical. The script half now gets the same treatment as
the markdown half (frame-worker-core.md + delta):
- new skills/hyperframes-core/scripts/lib/frame-packets-core.mjs owns
frame splitting, rule citation, packet assembly + bounds, _role.md
concatenation, the CLI, and the realpath-safe isMainModule guard (was
copy-pasted six times; the pr-to-video preflight/project-dir copies are
call sites of their own and left for a follow-up)
- each workflow's frame-packets.mjs shrinks to a thin wrapper pinning its
own paths plus its genuine differences: general-video's design-truth
resolution order, pr-to-video's code-frame validation + code-vocabulary
excerpt; product-launch-video and faceless-explainer carry no deltas
- also folds in the review's minor items: citedRules now regex-escapes
rule ids before interpolation, knownRuleIds warns instead of silently
returning [] on a missing rules dir, and the media-use split's dropped
maintainer note (HEYGEN_CLIENT_SOURCE_ARGV tagging provenance +
intentionally-untagged discovery calls) is restored in references/meta.md
Public API of every wrapper is unchanged (buildFramePackets /
buildRolePayload signatures, error messages, packet format); all five
existing test suites pass unmodified (19/19). skills-manifest regenerated.
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
---------
Co-authored-by: Claude Fable 5 <noreply@anthropic.com>
This commit is contained in:
co-authored by
Claude Fable 5
parent
d21883fe05
commit
6ad738b580
+30
-425
@@ -5,44 +5,30 @@ description: Agent Media OS, the single skill for every media need in a HyperFra
|
||||
|
||||
# media-use
|
||||
|
||||
The media OS for HyperFrames: resolve · generate · operate · remember, every media type, one skill, zero context noise.
|
||||
The media OS for HyperFrames: resolve · generate · operate · remember — every media type, one skill, zero context noise.
|
||||
|
||||
## Setup — install heygen first (free-usage path)
|
||||
First run: install and sign in to the `heygen` CLI (the free-usage path), then verify with `node <SKILL_DIR>/scripts/resolve.mjs --doctor`. Setup and providers: `references/setup-providers.md`.
|
||||
|
||||
## Resolve — the one verb
|
||||
|
||||
```bash
|
||||
curl -fsSL https://static.heygen.ai/cli/install.sh | bash
|
||||
heygen update # free usage needs the OAuth-capable CLI (v0.3.0+)
|
||||
heygen auth login --oauth # OAuth = free subscription credits; --api-key bills API credits
|
||||
node <SKILL_DIR>/scripts/resolve.mjs --type <type> --intent "<description>" --project <dir>
|
||||
```
|
||||
|
||||
This unlocks the FREE path for bgm/sfx/image/icon catalog search, TTS (voice), and avatar videos. Sign in with `--oauth` — the free allowance rides on the OAuth session (an API key bills API credits instead). **media-use requires heygen >= v0.3.0 uniformly** (the OAuth free-usage path needs it), so `--doctor` nudges older CLIs to update even for API-key-only use. Before resolving anything, verify setup with:
|
||||
Returns one line: `resolved <id> → <path> (<type>, <metadata>)`. All search noise stays on disk.
|
||||
|
||||
```bash
|
||||
node <SKILL_DIR>/scripts/resolve.mjs --doctor
|
||||
```
|
||||
| Type | One-line intent |
|
||||
| ------- | ----------------------------------------------------------------------------------- |
|
||||
| `bgm` | background music (HeyGen catalog, 10k+ tracks) |
|
||||
| `sfx` | sound effects (bundled 19-file library + catalog) |
|
||||
| `image` | photos, backgrounds (HeyGen asset search, 75k+ vectors) |
|
||||
| `icon` | icons, symbols (transparent) |
|
||||
| `logo` | official brand marks (svgl → simple-icons → GitHub avatar → favicon; never redrawn) |
|
||||
| `voice` | TTS voiceover (HeyGen free-usage path; optional local Kokoro) |
|
||||
| `grade` | paste-ready HyperFrames `data-color-grading` block |
|
||||
| `lut` | reusable validated `.cube` file |
|
||||
|
||||
## What it owns (the gaps HyperFrames leaves)
|
||||
|
||||
HyperFrames owns media _playback_; media-use owns everything else. Each row is enforced by `scripts/lib/coverage.test.mjs` so the claim can't rot.
|
||||
|
||||
| HyperFrames gap | media-use owns it via |
|
||||
| ------------------------------------------ | ----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
|
||||
| Audio-only, no image/icon | `resolve --type image\|icon` (heygen asset search) |
|
||||
| No third-party brand logos | `resolve --type logo` (svgl → simple-icons → GitHub org avatar → domain favicon) |
|
||||
| No voice / audio generation | `resolve --type voice` (HeyGen TTS free-usage path; optional local Kokoro) + the audio engine (`audio/scripts/audio.mjs`) |
|
||||
| Scattered/duplicated audio engine | one consolidated engine under `audio/` (hyperframes-media retired) |
|
||||
| No agent media-ops (cut/reframe/transform) | `references/operations.md` + `resolve --from` to register outputs |
|
||||
| No transcript-driven cutting | `scripts/transcript-cut.mjs` compiles word-timestamp edits into cut lists |
|
||||
| No auto-duck / publish loudness | `scripts/audio-duck.mjs` + `references/operations.md` loudnorm/sidechain recipes |
|
||||
| No cross-project memory | global content-addressed cache + auto-promote (`~/.media`) |
|
||||
| No color-grade authoring | `resolve --type grade` emits a paste-ready `data-color-grading` block; `resolve --type lut` freezes validated `.cube` files |
|
||||
| No image generation | RAM-graded local mflux (FLUX) via `scripts/lib/mflux-provider.mjs`, codex `image_gen` upsell (`scripts/lib/codex-provider.mjs`) |
|
||||
| No video generation | `resolve --type video` — HeyGen avatar video first (free-usage path, sign-in nudge on auth failure), local LTX fallback (`videogen` in `scripts/lib/local-models.mjs`); image-to-video, photo-avatar, dub/translate remain manual `heygen` CLI recipes (`references/operations.md`) |
|
||||
| Weak local-model defaults | HeyGen free-usage path via the `heygen` CLI; local open-source tools only as opt-in alternatives (`scripts/lib/local-run.mjs`) |
|
||||
|
||||
## When to use
|
||||
|
||||
Call `resolve` whenever a composition needs media: background music, sound effects, images, icons, brand logos, voice, a color grade, or a LUT. For voiceover / TTS, music, SFX, and caption timing, use the **audio engine** (below); background removal is delegated to the `hyperframes` CLI; transcription defaults to Parakeet (better than whisper.cpp: 6.05% vs 7.44% WER, 5-10x faster) via `scripts/transcribe.mjs`, with whisper.cpp auto-fallback (see `references/operations.md`). For cutting / reframing / transforming existing media, see `references/operations.md`. media-use searches the HeyGen catalog first for media files, resolves official logos through the logo cascade, uses local deterministic color grading for `grade`/`lut`, freezes the best match locally when a file is needed, registers it in a manifest, and hands the agent one line; all search noise stays on disk.
|
||||
Before resolving fresh, list reusable candidates with `--candidates` and judge fit yourself — reuse rules, all flags, ingest (`--from`), and adopt are in `references/resolve.md`.
|
||||
|
||||
## Be proactive — run a media opportunity pass
|
||||
|
||||
@@ -59,397 +45,16 @@ Surface an opportunity only when a concrete signal is present:
|
||||
| A piece over ~10s with no music bed | `bgm` |
|
||||
| Footage that reads under/over-exposed or color-cast | a corrective `grade` (analyze with `grade --for`, preview with `hyperframes grade-compare`) |
|
||||
|
||||
Rules that keep this a help, not nagware:
|
||||
|
||||
- **Grounded, not generic.** No signal → no suggestion. Never open with "want better images?".
|
||||
- **Opinionated + concrete.** Propose the specific fix ("add a VO from your script, swap 3 emoji for real icons, replace the 400×400 hero, whooshes on the 4 cuts"), with defaults chosen — the human just approves **all / some / none**.
|
||||
- **Once per project.** One consolidated ask, top few highest-value items. Respect "leave it" and don't re-raise.
|
||||
- **Surface, never silently mutate.** Color grades especially: propose and preview, never auto-apply — a gray-world "correction" ruins an intentional sunset or neon look.
|
||||
|
||||
## Resolve
|
||||
|
||||
```bash
|
||||
node <SKILL_DIR>/scripts/resolve.mjs --type <type> --intent "<description>" --project <dir>
|
||||
```
|
||||
|
||||
Returns one line: `resolved <id> → <path> (<type>, <metadata>)`
|
||||
|
||||
### Types
|
||||
|
||||
| Type | What it finds | Provider / cascade |
|
||||
| ------- | -------------------------------- | ------------------------------------------------------------ |
|
||||
| `bgm` | Background music | HeyGen audio catalog (10k+ tracks) |
|
||||
| `sfx` | Sound effects | Bundled 19-file library + HeyGen catalog |
|
||||
| `image` | Photos, backgrounds | HeyGen asset search (75k+ vectors) |
|
||||
| `icon` | Icons, symbols | HeyGen asset search (type=icon) |
|
||||
| `logo` | Official brand marks | svgl → simple-icons → GitHub org avatar → domain favicon |
|
||||
| `voice` | TTS voiceover | HeyGen TTS free-usage path; optional local Kokoro |
|
||||
| `grade` | HyperFrames color-grading blocks | Core preset → look index params/CDN LUT → deterministic cube |
|
||||
| `lut` | Reusable `.cube` LUT files | Look index params/CDN LUT → deterministic cube |
|
||||
|
||||
### Examples
|
||||
|
||||
```bash
|
||||
# Background music
|
||||
node <SKILL_DIR>/scripts/resolve.mjs --type bgm --intent "upbeat tech launch" --project .
|
||||
# → resolved bgm_001 → .media/audio/bgm/bgm_001.mp3 (bgm, 25s)
|
||||
|
||||
# Sound effect
|
||||
node <SKILL_DIR>/scripts/resolve.mjs --type sfx --intent "whoosh" --project .
|
||||
# → resolved sfx_001 → .media/audio/sfx/sfx_001.mp3 (sfx, 0.57s)
|
||||
|
||||
# Image
|
||||
node <SKILL_DIR>/scripts/resolve.mjs --type image --intent "gradient tech background" --project .
|
||||
# → resolved image_001 → .media/images/image_001.jpg (image)
|
||||
|
||||
# Icon
|
||||
node <SKILL_DIR>/scripts/resolve.mjs --type icon --intent "rocket" --project .
|
||||
# → resolved icon_001 → .media/images/icon_001.png (icon, transparent)
|
||||
|
||||
# Brand logo (official mark — never redrawn by hand)
|
||||
node <SKILL_DIR>/scripts/resolve.mjs --type logo --entity linkedin --intent "LinkedIn logo" --project .
|
||||
# → resolved logo_001 → .media/images/logo_001.svg (logo, official mark)
|
||||
|
||||
# Color grade block
|
||||
node <SKILL_DIR>/scripts/resolve.mjs --type grade --intent "warm daylight" --project . --json
|
||||
# → {"ok":true,"preset":"warm-daylight","grading":{"preset":"warm-daylight","intensity":1},...}
|
||||
|
||||
# LUT file
|
||||
node <SKILL_DIR>/scripts/resolve.mjs --type lut --intent "teal orange blockbuster" --project .
|
||||
# → resolved lut_001 → .media/luts/lut_001.cube (lut)
|
||||
```
|
||||
|
||||
### Flags
|
||||
|
||||
| Flag | Description |
|
||||
| --------------- | ------------------------------------------------------------------------------------ |
|
||||
| `--type, -t` | Media type: bgm, sfx, image, icon, logo, voice, grade, lut |
|
||||
| `--intent, -i` | What you need (natural language) |
|
||||
| `--entity, -e` | Entity name for cache matching (optional) |
|
||||
| `--project, -p` | Project directory (default: .) |
|
||||
| `--candidates` | List reusable assets (project + global cache) for `--type`; no download, no mutation |
|
||||
| `--reuse <sha>` | Import a specific global-cache asset (by content sha/prefix, from `--candidates`) |
|
||||
| `--from` | Freeze a local file or direct public URL (ingest) |
|
||||
| `--for` | Analyze a local image/video and add measured adjust suggestions (`grade` only) |
|
||||
| `--local-only` | Offline: skip every network provider (cache + local only) |
|
||||
| `--provider` | Force one generator (e.g. `codex`, `mflux`, `kokoro`, `heygen`) |
|
||||
| `--adopt` | Bulk-import existing assets/ into manifest |
|
||||
| `--doctor` | Check local CLI dependencies; no manifest changes |
|
||||
| `--stats` | Print local usage stats from `.media/` and `~/.media`; no manifest changes |
|
||||
| `--days N` | Limit `--stats` to timestamped records/misses from the last N days |
|
||||
| `--json` | Output JSON instead of one-line result |
|
||||
|
||||
## Reuse before you resolve
|
||||
|
||||
Before resolving bgm/sfx/image/icon/logo/grade/lut, **check what already exists and reuse it when it fits.** media-use does not semantically match for you — you are the judge. It surfaces candidates; you decide.
|
||||
|
||||
```bash
|
||||
node <SKILL_DIR>/scripts/resolve.mjs --type bgm --intent "upbeat tech launch" --candidates --project .
|
||||
# [project] upbeat tech launch (25s, heygen.audio.sounds)
|
||||
# .media/audio/bgm/bgm_001.wav
|
||||
# [global] energetic tech intro (22s, heygen.audio.sounds)
|
||||
# --reuse 06e052c075fd2b80
|
||||
```
|
||||
|
||||
Read the list and judge semantic fit yourself — "upbeat tech launch" ≈ "energetic tech intro" is a call only you can make from the descriptions. Then:
|
||||
|
||||
- **A project candidate fits** → just reference its path in your composition. Nothing else to run.
|
||||
- **A global candidate fits** → `resolve --type bgm --reuse <sha>` copies it into this project (self-contained render) and records it.
|
||||
- **Nothing fits** → resolve fresh (`--type ... --intent ...`).
|
||||
|
||||
**Trust guardrail — when unsure, resolve fresh.** A redundant download is cheap; shipping the wrong asset is not. Judge fit from description + prompt + type + duration/dims. For **brand/entity** assets, reuse a _global_ candidate only when the entity matches exactly — the global cache aggregates every project you have worked on, so a `--candidates` list can surface another client's brand mark and its prompt text. Never reuse a cross-project brand asset on a loose match.
|
||||
|
||||
The deterministic floor still runs automatically: an identical (case/whitespace-insensitive) repeat auto-reuses with no `--candidates` step. `--candidates` is only for the semantic layer above that floor — and a fuzzy match is **never** auto-applied; reuse is always your explicit call. On a resolve that misses the floor and is about to fetch, media-use prints a one-line stderr hint when similar cached assets exist, pointing you back here.
|
||||
|
||||
## Color grading
|
||||
|
||||
Use `grade` when you need the actual HyperFrames `data-color-grading` value to paste onto an `<img>` or `<video>`. Core presets and params-backed library looks resolve locally; future CDN-backed library looks require network unless already frozen:
|
||||
|
||||
**Never `cat`/read a `.cube` file into context.** A 3D LUT is ~size^3 lines of raw numbers (33^3 ≈ 36k lines at the default size). It bloats context and carries zero human/agent-legible signal. To understand or choose a LUT, use `hyperframes grade-compare` to see it rendered, or `cube-validate.mjs` for a one-line `{ok,size}` check. Read `.media/index.md` or `luts/index.json` for the description. Never read the LUT body itself.
|
||||
|
||||
```bash
|
||||
node <SKILL_DIR>/scripts/resolve.mjs --type grade --intent "warm daylight" --project . --json
|
||||
```
|
||||
|
||||
Preset-first output uses the core runtime vocabulary and does not freeze a file:
|
||||
|
||||
```json
|
||||
{
|
||||
"preset": "warm-daylight",
|
||||
"intensity": 1
|
||||
}
|
||||
```
|
||||
|
||||
Paste it as an attribute value after JSON string escaping:
|
||||
|
||||
```html
|
||||
<video
|
||||
class="clip"
|
||||
src="./media/scene.mp4"
|
||||
data-color-grading='{"preset":"warm-daylight","intensity":1}'
|
||||
></video>
|
||||
```
|
||||
|
||||
Looks beyond the preset vocabulary freeze a validated `.cube` under `.media/luts/` and return a block that references it:
|
||||
|
||||
```bash
|
||||
node <SKILL_DIR>/scripts/resolve.mjs --type grade --intent "teal orange blockbuster" --project . --json
|
||||
```
|
||||
|
||||
```json
|
||||
{
|
||||
"intensity": 1,
|
||||
"lut": { "src": ".media/luts/grade_001.cube", "intensity": 0.85 }
|
||||
}
|
||||
```
|
||||
|
||||
Use `lut` when you only need the reusable `.cube` file:
|
||||
|
||||
```bash
|
||||
node <SKILL_DIR>/scripts/resolve.mjs --type lut --intent "teal orange blockbuster" --project .
|
||||
```
|
||||
|
||||
For a describable technical look, author an explicit parametric LUT with `--params`:
|
||||
|
||||
```bash
|
||||
node <SKILL_DIR>/scripts/resolve.mjs --type lut --params '{"contrast":0.2,"temperature":-0.3}' --project .
|
||||
node <SKILL_DIR>/scripts/resolve.mjs --type grade --params '{"exposure":0.2}' --project . --json
|
||||
```
|
||||
|
||||
For a LUT generated by your own script, ingest it with `--from`; media-use validates it before registration and rejects invalid or oversized cubes:
|
||||
|
||||
```bash
|
||||
node <SKILL_DIR>/scripts/resolve.mjs --type lut --from custom.cube --project .
|
||||
```
|
||||
|
||||
Parametric math (`buildCube`) cannot reproduce real film stocks or emulsion looks. Use a CDN-backed scanned `.cube` entry or ingest a real scanned `.cube` for those.
|
||||
|
||||
For visual selection, list reusable looks with `resolve --type grade --candidates`, write the promising entries to a `grades.json`, run `hyperframes grade-compare --for <frame> --grades grades.json`, then commit the winner with `resolve -t grade` as the final `data-color-grading` block.
|
||||
|
||||
Smart grade is `grade --for <media>`. It runs local `ffmpeg`/`ffprobe` signalstats, merges a bounded `adjust` suggestion into the returned block, and prints the measured evidence to stderr. Stdout remains valid JSON under `--json`; the suggestion is a starting point for the agent to tune, not an automatic neutralization of intentional color.
|
||||
|
||||
```bash
|
||||
node <SKILL_DIR>/scripts/resolve.mjs --type grade --intent "warm cinematic" --for ./frame.png --project . --json
|
||||
```
|
||||
|
||||
Library looks live in `luts/index.json`. Each entry keeps `id`, `description`, `tags`, and `intensity`, then supplies either compact `params` for on-demand `buildCube(params)` generation or a direct CDN `url` for future scanned `.cube` files. Do not commit generated `.cube` bodies; resolve validates generated or downloaded cubes as it freezes them under `.media/luts/`.
|
||||
|
||||
```bash
|
||||
node skills/media-use/scripts/resolve.mjs --type lut --intent "teal orange blockbuster" --project . --json
|
||||
node skills/media-use/scripts/lib/cube-validate.mjs .media/luts/lut_001.cube
|
||||
```
|
||||
|
||||
## Providers
|
||||
|
||||
media-use holds no keys; every external tool owns its auth. Generation is
|
||||
centered on the HeyGen CLI free-usage path. Install and authenticate `heygen`
|
||||
before resolving bgm/sfx/image/icon/voice/avatar-video. Local tools are opt-in
|
||||
alternatives where they exist: mflux for image, Kokoro for voice, Parakeet for
|
||||
transcription, and LTX for local video generation. `resolve` spec-checks
|
||||
AVAILABLE RAM for those local ladders (`describeModelLadder`); the agent can
|
||||
see the ladder and override.
|
||||
|
||||
| Type | Provider / path |
|
||||
| --------- | ----------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
|
||||
| bgm/sfx | heygen catalog free-usage path |
|
||||
| image | heygen search free-usage path; optional local mflux; codex `image_gen` upsell |
|
||||
| voice | heygen tts free-usage path; optional local **Kokoro** (free, on-device) |
|
||||
| icon | heygen asset search free-usage path |
|
||||
| logo | svgl, then simple-icons, then GitHub org avatar, then domain favicon (all free) |
|
||||
| grade/lut | local core-preset map, params/CDN look index, deterministic `buildCube` fallback |
|
||||
| video | heygen avatar video free-usage path (sign-in nudge on auth failure); optional local LTX (`videogen` ladder). Image-to-video / photo-avatar / dub stay manual `heygen` recipes |
|
||||
|
||||
Local Kokoro (voice), mflux (image), and LTX (video) run on-device (free,
|
||||
private, offline once cached). The `codex` CLI remains the ChatGPT-sub image
|
||||
upsell. Cost rule (X4): the agent confirms before an agent-initiated paid call;
|
||||
a user-requested one just runs — `heygen.video` is flagged paid (metered free
|
||||
allowance) so an agent-initiated `resolve --type video` confirms first.
|
||||
|
||||
To force a specific generator (e.g. a user says "make this image with codex"),
|
||||
pass `--provider codex`: it pins resolution to that provider and skips the
|
||||
free-usage default. See `references/operations.md` for the RAM ladders and
|
||||
provider recipes.
|
||||
|
||||
`--local-only` skips every network provider, including the free HeyGen ones,
|
||||
leaving the project + global cache and any installed local provider. For
|
||||
HeyGen-only types, that means no fresh resolve.
|
||||
|
||||
## How it works
|
||||
|
||||
`resolve` runs an automatic floor, then falls through to fetching:
|
||||
|
||||
1. Check project `.media/manifest.jsonl` for a prompt match (case- and whitespace-insensitive) — auto-reuse
|
||||
2. Scan existing `assets/` directory for unregistered files that share a word with the need
|
||||
3. Check global cache `~/.media/` for a reusable asset matched on the same normalized prompt — auto-reuse
|
||||
4. Search via provider (HeyGen audio catalog, HeyGen asset search), or resolve color locally
|
||||
5. Freeze file to `.media/<type>/`, register in manifest, regenerate `index.md`, auto-promote to `~/.media/`
|
||||
|
||||
Steps 1 and 3 are the **deterministic floor**: they only auto-reuse an exact-normalized match, never a fuzzy one. Semantic reuse ("close enough") is the agent's explicit call via [Reuse before you resolve](#reuse-before-you-resolve) — it never happens automatically. The agent gets back **one line**; candidates, scores, provenance stay on disk.
|
||||
|
||||
## Adopt existing projects
|
||||
|
||||
Most HyperFrames projects already have assets in `assets/`. media-use adopts them:
|
||||
|
||||
```bash
|
||||
node <SKILL_DIR>/scripts/resolve.mjs --adopt --project .
|
||||
# → adopted 9 assets from assets/
|
||||
# bgm_001 → assets/bgm/mango-fizz.mp3 (bgm, 146.6s)
|
||||
# image_001 → assets/images/avatar.jpg (image, 400×400)
|
||||
```
|
||||
|
||||
`ffprobe` extracts real duration and dimensions. During resolve, unregistered files in `assets/` matching the intent are adopted on the fly.
|
||||
|
||||
## Reading the inventory
|
||||
|
||||
After resolve or adopt, read `.media/index.md` for the full inventory:
|
||||
|
||||
```
|
||||
# .media · 4 assets
|
||||
|
||||
id type dur dims path description
|
||||
bgm_001 bgm 25s - .media/audio/bgm/bgm_001.mp3 upbeat tech launch
|
||||
sfx_001 sfx 0.6s - .media/audio/sfx/sfx_001.mp3 whoosh
|
||||
image_001 image - 1920×1080 .media/images/image_001.jpg gradient tech background
|
||||
icon_001 icon - 200×200 .media/images/icon_001.png rocket
|
||||
```
|
||||
|
||||
## Cross-project reuse
|
||||
|
||||
Assets are cached automatically on resolve. Every resolved/ingested asset is auto-promoted to the global cache at `~/.media/`, so subsequent resolves for the same (or near-identical) prompt, in any project, hit the cache with no re-download and no provider call.
|
||||
|
||||
For a _semantically_ similar (not identical) need in another project, the exact-match floor won't fire — use [Reuse before you resolve](#reuse-before-you-resolve): `--candidates` lists the global assets, and `--reuse <sha>` imports the one you pick. This is how a track resolved in one project gets reused in the next when the wording differs.
|
||||
|
||||
## Preferences — remembered defaults
|
||||
|
||||
The lightweight tier of user memory: confirmed brief answers (destination, aspect, language, flow, storyboard, voice, style preset) persisted on the same two-tier split as assets — project `.media/preferences.json` (committed, the team inherits it) and personal `~/.media/preferences.json`. A value earns the personal tier by being confirmed in **two different projects**, so a one-off choice never pollutes the global defaults.
|
||||
|
||||
```bash
|
||||
node <SKILL_DIR>/scripts/prefs.mjs get --hyperframes . --json # merged view (project overrides user)
|
||||
node <SKILL_DIR>/scripts/prefs.mjs record --hyperframes . --key destination --value x-feed
|
||||
node <SKILL_DIR>/scripts/prefs.mjs record --hyperframes . --key style_preset --value pin-and-paper --workflow faceless-explainer
|
||||
```
|
||||
|
||||
Only what the user actually confirmed gets recorded — never an inferred or defaulted value. How workflows consume these (a remembered value becomes the recommended default with a receipt, and never skips a question) is the brief contract's rule: `hyperframes-core/references/brief-contract.md` § 2, Remembered defaults.
|
||||
|
||||
## Recipes — frozen video bundles
|
||||
|
||||
The heavyweight tier of user memory: one approved run frozen as a named, versioned bundle — `frame.md`, the storyboard skeleton (structure kept, content blanked to per-frame fill-ins), the brief skeleton (from `BRIEF.md` when the project has one — reusable frontmatter kept, run-shape and prose blanked), and the confirmed brief values. Same two tiers: project `.media/recipes/<name>/` (committed) and `~/.media/recipes/<name>/` (a freeze is already a confirmed bundle, so it promotes immediately — no two-project rule). Re-freezing a name bumps `version` and archives the old folder as `<name>@v<N>`.
|
||||
|
||||
```bash
|
||||
node <SKILL_DIR>/scripts/recipe.mjs freeze --hyperframes . --name weekly-promo # workflow read from BRIEF.md (--workflow only for briefless projects)
|
||||
node <SKILL_DIR>/scripts/recipe.mjs list --hyperframes . --workflow product-launch-video
|
||||
node <SKILL_DIR>/scripts/recipe.mjs use --hyperframes . --name weekly-promo # also: resolve.mjs --type recipe --entity weekly-promo
|
||||
```
|
||||
|
||||
The freeze is offered once after the final approval (`hyperframes-core/references/review-loop.md` § 4), and the intent layer (`/hyperframes` § 4) checks for a match before its first question. Adopting a recipe fills the brief, the design spec, and the storyboard skeleton — and unlike preferences it may skip the questions it answers: the bundle was approved as a whole, and adoption itself is the question.
|
||||
|
||||
## Usage stats
|
||||
|
||||
Use `resolve --stats` for a local, shareable report over the current project's `.media/` manifest, the global `~/.media/` cache, and local resolve misses. Human output is compact; add `--json` for a single machine-readable object, and `--days N` to window timestamped records.
|
||||
|
||||
```bash
|
||||
node <SKILL_DIR>/scripts/resolve.mjs --stats --project . --days 7
|
||||
# media-use stats
|
||||
# total resolves: 12
|
||||
# misses: 2
|
||||
# hit rate: 86%
|
||||
```
|
||||
|
||||
## Files
|
||||
|
||||
- `.media/manifest.jsonl`: machine SSOT, one JSON record per line
|
||||
- `.media/index.md`: agent-readable table (id, type, dur, dims, path, description)
|
||||
- `.media/preferences.json`: the project's remembered defaults (committed)
|
||||
- `~/.media/`: global cross-project reuse cache (content-addressed, SHA-256)
|
||||
- `~/.media/preferences.json`: personal remembered defaults (promoted after two projects)
|
||||
- `.media/recipes/<name>/`: frozen video bundles — recipe.json + frame.md + storyboard skeleton (committed)
|
||||
- `~/.media/recipes/<name>/`: personal recipe tier (promoted on freeze)
|
||||
- `~/.media/misses.jsonl`: local-only resolve misses, including intent text for `--stats`
|
||||
|
||||
## Audio engine: voiceover, music, SFX, captions, transcription
|
||||
|
||||
For a full audio pass (TTS voiceover + background music + sound effects in one
|
||||
shot), use the shared engine at `audio/scripts/audio.mjs`. It takes a neutral
|
||||
`audio_request.json` and writes `audio_meta.json` plus assets under
|
||||
`.media/audio/{voice,bgm,sfx}`:
|
||||
|
||||
```bash
|
||||
node <SKILL_DIR>/audio/scripts/audio.mjs --request ./audio_request.json --out ./audio_meta.json
|
||||
```
|
||||
|
||||
- **Request** `{ provider?, lang?, speed?, lines: [{ id, text, sfx?: [names] }], bgm: { mode?, query?, prompt? } }`: `id` joins each line back to your model; `bgm.mode` = `retrieve | generate | none` (omit for auto). `--only tts,bgm,sfx` runs a subset and merges into an existing `--out`.
|
||||
- **Output** `audio_meta.json` (id-keyed): `voices[].{path,duration_s,words[]}` (word timestamps for captions), `sfx[]`, `bgm`, `total_duration_s`.
|
||||
- **HeyGen free-usage path**: HeyGen CLI auth unlocks TTS plus music/SFX retrieval. Local/provider-specific generators are explicit alternatives where installed; run `node <SKILL_DIR>/scripts/resolve.mjs --doctor` before assuming retrieval or TTS will work.
|
||||
- If BGM took the generate path (`bgm_pending: true`), run `audio/scripts/wait-bgm.mjs` before final render.
|
||||
|
||||
Single-shot helpers: `audio/scripts/heygen-tts.mjs` (one voice file). Transcription / background removal / captions use the `hyperframes` CLI (`transcribe`, `remove-background`), see the per-topic guides in `audio/references/` (`tts.md`, `bgm.md`, `sfx.md`, `transcribe.md`, `remove-background.md`, `captions/`).
|
||||
|
||||
## Operating on media (cut, reframe, transform)
|
||||
|
||||
media-use resolves + remembers; for **operating** on assets see
|
||||
`references/operations.md`: local-tool recipes (ffmpeg trim/reframe/montage,
|
||||
auto-editor, scenedetect) and the local-vs-HeyGen transform table (background
|
||||
removal, upscale, lipsync, translate). Run the tool, then register the output
|
||||
with `resolve --from <output> --type <type>` so it joins the ledger + global
|
||||
cache.
|
||||
|
||||
HEVC/H.265 sources need no conversion for **render** (FFmpeg pre-decodes all
|
||||
input video) or for **preview** (auto-proxy transcodes and caches an H.264
|
||||
copy on first use, disable with `--no-proxy` or `media.autoProxy: false` in
|
||||
hyperframes.json). A manual H.264 proxy via `ffmpeg -i in.mp4 -c:v libx264
|
||||
-crf 18 proxy.mp4`, registered with `resolve --from`, remains available for
|
||||
edge cases (e.g. auto-proxy disabled, or ffmpeg unavailable at preview time).
|
||||
|
||||
## CLI tools used (what to run, and how to enable each)
|
||||
|
||||
`resolve` auto-cascades; each provider shells one CLI. HeyGen is the
|
||||
free-usage path for bgm/sfx/image/icon catalog search, TTS (voice), and avatar
|
||||
video, so those capabilities need `heygen` installed and authenticated. Local
|
||||
tools are OPT-IN alternatives where they exist; install one to unlock its free,
|
||||
private, on-device path instead of or ahead of HeyGen for that type. Only
|
||||
`ffmpeg`/`ffprobe` are strictly required for the tool to run at all.
|
||||
|
||||
| Tool | Serves | Install |
|
||||
| ------------------ | ------------------------------------------------------------------------------- | -------------------------------------------------------------------------------------------------------------------------------- |
|
||||
| `ffmpeg`/`ffprobe` | adopt probing, smart-grade signalstats, cut, duck bake, loudnorm | system package (`brew install ffmpeg`) |
|
||||
| `heygen` | catalog (bgm/sfx/image/icon) + TTS (voice) + avatar video — the free-usage path | `curl -fsSL https://static.heygen.ai/cli/install.sh \| bash` then `heygen auth login --oauth` (needs >= v0.3.0) |
|
||||
| `mflux-generate` | local image gen (FLUX), best-for-RAM | `uv venv ~/.venvs/mflux && VIRTUAL_ENV=~/.venvs/mflux uv pip install mflux==0.9.6` |
|
||||
| `codex` | image gen upsell (ChatGPT sub) | Codex CLI, logged in via ChatGPT (owns its own auth) |
|
||||
| `parakeet-mlx` | local transcription (default ASR, best) | `uv venv ~/.venvs/parakeet && VIRTUAL_ENV=~/.venvs/parakeet uv pip install parakeet-mlx` |
|
||||
| `ltx-2-mlx` | local video gen | `git clone https://github.com/dgrauet/ltx-2-mlx && cd ltx-2-mlx && uv sync --all-extras` |
|
||||
| `npx hyperframes` | Kokoro TTS (voice), whisper.cpp (transcribe fallback), remove-background | via the hyperframes CLI; whisper.cpp is built on first use (Homebrew on macOS, else git+cmake), models download from HuggingFace |
|
||||
|
||||
The RAM-graded local-model shortlist + exact per-tier install/invoke lives in
|
||||
`scripts/lib/local-models.mjs` (the agent can read `describeModelLadder(cap, specs)`
|
||||
to see which model fits this machine). Without a tool on PATH, its provider
|
||||
prints a one-line diagnostic to stderr and resolve falls through where another
|
||||
provider exists (e.g. no `mflux` -> codex image upsell; no `parakeet-mlx` -> whisper.cpp).
|
||||
|
||||
`heygen asset search` is a pre-launch command hidden from `heygen --help`, but it
|
||||
runs. Every media-use call that shells `heygen` — catalog search AND every
|
||||
generating call (TTS, avatar video) — tags requests with the allowlisted
|
||||
`X-HeyGen-Client-Source: media-use` header (v0.3.0+), sourced from one shared
|
||||
constant (`HEYGEN_CLIENT_SOURCE_ARGV` in `scripts/lib/heygen-cli.mjs`) so a
|
||||
future call site can't silently ship untagged. Read-only discovery calls
|
||||
(`voice list`, `avatar list`) are intentionally left untagged.
|
||||
|
||||
## Telemetry
|
||||
|
||||
`resolve` and the edit tools (transcribe / transcript-cut / audio-duck) send an
|
||||
anonymous usage event to PostHog (`scripts/lib/telemetry.mjs`), so we can see
|
||||
which capabilities are actually used. It records only the media TYPE, the
|
||||
resolution SOURCE, and the winning PROVIDER: never the intent text, file names,
|
||||
or paths, and `$ip:null` so no IP is stored. Best-effort and non-blocking (a
|
||||
resolve never waits on or fails from telemetry).
|
||||
|
||||
Opt out with `DO_NOT_TRACK=1` or `HYPERFRAMES_NO_TELEMETRY=1` (also off in CI and
|
||||
dev). Same public PostHog project key and opt-outs as the `hyperframes` CLI.
|
||||
|
||||
## Privacy
|
||||
|
||||
media-use uses the same shared install id as the `hyperframes` CLI/studio
|
||||
(`~/.hyperframes/config.json`). When you are signed in to HeyGen, usage is
|
||||
linked to your account email, or username when email is unavailable, matching
|
||||
the CLI behavior. The events stay coarse: media type, source, provider, and
|
||||
small counts only; intent text and paths stay local. Disable telemetry with
|
||||
`HYPERFRAMES_NO_TELEMETRY=1` or `DO_NOT_TRACK=1`.
|
||||
Rules that keep this a help, not nagware: **grounded, not generic** (no signal → no suggestion); **opinionated + concrete** (propose the specific fix with defaults chosen — the human approves **all / some / none**); **once per project** (one consolidated ask; respect "leave it"); **surface, never silently mutate** (color grades especially: propose and preview — a gray-world "correction" ruins an intentional sunset or neon look).
|
||||
|
||||
## Where to look — read only the file your task needs
|
||||
|
||||
| Task | Read |
|
||||
| ------------------------------------------------------------------------- | ------------------------------- |
|
||||
| resolve / reuse / adopt / ingest, flags, cascade, inventory | `references/resolve.md` |
|
||||
| color grading, LUTs, smart grade (`--for`), grade-compare | `references/grading.md` |
|
||||
| voiceover / TTS, music, SFX, captions, transcription (audio engine) | `references/audio.md` |
|
||||
| cut / reframe / transform existing media, HEVC proxies, avatar video | `references/operations.md` |
|
||||
| install + auth, provider table, RAM ladders, `--local-only`, `--provider` | `references/setup-providers.md` |
|
||||
| remembered preferences + frozen recipes (user memory) | `references/memory.md` |
|
||||
| ownership matrix, usage stats, telemetry, privacy (maintainer-facing) | `references/meta.md` |
|
||||
|
||||
Reference in New Issue
Block a user