Skip to content

feat(skills): style templates on the HyperFrames plan - #6842

Open
WaterrrForever wants to merge 34 commits into
mainfrom
miao/creator-templates
Open

WaterrrForever wants to merge 34 commits into
mainfrom
miao/creator-templates

Conversation

@WaterrrForever

@WaterrrForever WaterrrForever commented Oct 30, 2026 •

Copy link
Copy Markdown
Collaborator

What

Style templates for HyperFrames Pro. A person asks their agent for a video in one of five styles (Collage Explainer, Finance Explainer, Animated Science Explainer, 3D Brand Explainer, 3D True Crime). The agent pulls that style's template pack on demand and makes the episode on the person's topic. A signed-out person gets the sign-in step; a Free account gets the upgrade step and nothing is downloaded.

Why

A template's value is its files, so a gate in the prompt alone protects nothing. The gate sits at delivery: packs live in private storage and the server hands a short-lived link only to a Pro plan. Making the film then spends plan credits through media-use generate, priced and refused by the server.

Related work

Refs #6833 (the plan sign-in and credit rules this follows).

How

  • skills/style-remix/: one public skill, listed with the other published skills. SKILL.md lists the five templates when none is named and waits for a pick, checks the sign-in and plan, pulls, and holds the credit rules. references/remix.md is the order of work; each template's own steps stay in its private pack.
  • npx hyperframes templates pull <slug>: asks GET /v1/hyperframes/moments/<id>/bundle for a five-minute link, downloads, checks the pinned sha256, and moves the template into templates/<slug>/ whole. A pack already there is not downloaded again; 401, 402, 503 (one retry, never a public fallback) and 404 each end with a clear next step. Packs are pinned in templates.ts, so a new pack ships with a CLI release.
  • media-use generate: --type lipsync; --type cutout (a filmed shot out of its background, on the plan); --type avatar can speak a finished voice (--audio) or use the person's own look (--avatar). Prices for these on the plan, and a voice is only picked when the avatar reads a script. A cutout sends its retry key as the body's request_id (the route dedupes there, not on the header), and uploads carry their real media type, so WebM and MOV inputs work.
  • Smaller fixes found on the way: cloud offload uploads media named inside template tags and script strings; one ledger row per job; asset search skips a template's own pictures; HeyGen sound effects in resolve --type sfx; a font shorthand whose size nests parentheses.
  • Docs: cli.mdx gains templates pull; the media-use skill names the on-plan cutout and lipsync commands.

Test plan

  • Unit tests added/updated: templates.test.ts (402, 401, 503 retry, hash mismatch, unsafe archive path), generate.test.ts (cutout of real WebM and MOV files: their upload type and a stable request_id), v3.test.ts (a server that dedupes on the body's request_id only: a lost answer keeps it, a failed job moves it), offload.test.ts, adopt.test.mjs, registry.test.mjs, the font shorthand test. src/heygen, src/commands/media-use, templates.test.ts and offload.test.ts: 125 passed. Fails without the fix: the cutout test sees audio/mpeg for WebM and MOV.
  • Manual: each of the five packs pulled from production with a Pro account (1–4 s); a signed-out request gets the sign-in step and pulls nothing; an agent in a clean project made a one-minute film with each template end to end.
  • Documentation updated: docs/packages/cli.mdx, skills/media-use, and the skill lists in README, AGENTS.md, CLAUDE.md and docs/guides/skills.mdx.
  • Comments follow CONTRIBUTING.md "Comments".
  • A Free account getting the 402 on production: needs a Free test account.

Size

About 1,100 added lines across 44 files: the templates command and its tests (~280), the new skill (~110), the media-use generate types and pricing (~250), and the small fixes with their tests.

🤖 Generated with Claude Code

WaterrrForever and others added 10 commits October 30, 2026 21:43
…t of retries

An out-of-credits refusal named what the step needs, and an agent read
that as the shortfall. It now says the number is the step's total.

After its last try, an agent told the person what was spent and what
another try would cost. The HeyGen reference now says not to.
An avatar's credits came from its old API price, about five times what
the plan charges, so --max-credits refused calls that fit and a top-up
asked for too much. They now use the Avatar IV photo row plus the
general avatar video row, 950 credits a minute.
The general avatar row is only checked at admission and billed on
seconds left after Avatar IV, so adding it to every second made a 15 s
script plan at 238 instead of 200 and a 220 limit refuse a call that fits.
A Pro account asks for a video in a creator's format and the agent pulls that
template on demand. The packs sit in the private bucket behind the plan-gated
bundle route, so a Free account gets a 402 and the upgrade step. A pull costs
no credits; making the film spends them as Reverse does.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
SKILL.md holds the catalog, the Pro openings, the pull and the credit
rules. references/remix.md is how to make the episode, from Desktop's
creator-remix with only what the app alone has swapped for the CLI.
The packs now hold only the template, so their hashes change.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
SKILL.md holds the catalog, the Pro openings, the pull and the credit
rules. references/remix.md is how to make the episode, from Desktop's
creator-remix with only what the app alone has swapped for the CLI.
The packs now hold only the template, so their hashes change.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
The person's own HeyGen avatar is recommended, not required: without
one, 小Lin's presenter is made with HeyGen Video 1 from their photo.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Base automatically changed from miao/reverse-wording to main October 31, 2026 01:03
@mintlify

mintlify Bot commented Oct 31, 2026 •

Copy link
Copy Markdown

Preview deployment for your docs. Learn more about Mintlify Previews.

Project Status Preview Updated
hyperframes 🟢 Ready View Preview Nov 2, 2026, 6:11 PM

💡 Tip: Enable Automations to automatically generate PRs for you.

@github-actions

github-actions Bot commented Oct 31, 2026 •

Copy link
Copy Markdown
Contributor

Edit accuracy: accurate 267 (base branch 267), smooth 104 of those

The gate passes.
Smoothness is reported in the artifact, not gated. A case fails only if it fails 2 of 3 runs.

Quarantined, measured but not gated (8)

Unstable (1)

  • seqplainkeys-none-pct-r0-nested-z100: tracking 0.05, pressJump 0, drop 0, reload 0, render 0.02, renderKey -, undo true, teleport true / tracking 0.05, pressJump 0, drop 0, reload 0, render 0.02, renderKey -, undo true, teleport true / tracking 0.05, pressJump 0, drop 0, reload 0, render 0.02, renderKey -, undo true, teleport true

WaterrrForever and others added 4 commits November 2, 2026 00:52
References in a composition's <template> were never rewritten, because the DOM
query stops at the tag and template.content does not serialize, so the file stayed
in the zip. A stem matched as a plain word and a same-named file elsewhere counted
as a mention too. A 5-minute presented film went from 196 MB to 71 MB.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Video 1 takes audio as a reference and re-paces it, so a shot's lips follow its
own track and drift up to a second from the voice. generate --type lipsync redoes
the mouth to the exact voice. generate --type avatar takes --audio, and --avatar
for the person's own look, so the lips land on the voice from one job.

Also moves the plan rows to the 2026-10-30 price book, estimates a voice's credits
so --max-credits can hold it, logs jobs from a folder with no project, and describes
the resolve flags.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
The person's own avatar, then Avatar IV from their photo, then Video 1 with
lipsync. With no clone or recording, a stock voice named in the credits. Pins the
five rebuilt packs. The archive test keeps its ../ under GNU tar with -P.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Keeps the 2026-10-30 price rows over main's older ones and regenerates the skills
manifest.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
try {
const archive = join(work, "template.tar.gz");
const out = join(work, "template");
writeFileSync(archive, data);
WaterrrForever and others added 7 commits November 2, 2026 02:06
A wav gives the avatar price test an exact length on every platform. The
sfx tests now expect HeyGen first. Comment share is back under the base.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
`font: calc(var(--size) * 1px)/1 "X"` cut at the first closing parenthesis, so a
bad family name failed the render.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
…ictures

A job done at once logs one row, transcribe logs to the project, and resolve no
longer offers a component's file for a search. --reuse and --provider get help text.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
… real slug

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
WaterrrForever and others added 2 commits November 2, 2026 16:40
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
…oryboard rule

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
WaterrrForever and others added 5 commits November 2, 2026 18:41
…e stock-presenter ban

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
…ates to names that say the look

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
…phics

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
…ackground on the plan

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
WaterrrForever and others added 4 commits November 2, 2026 21:34
…riety rule

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
…eal films

Animated Science gets a worlds-and-boards budget, 3D True Crime a main board and a
brief corner note, 3D Brand caps by measured rate, Finance and Collage set pieces and
more than one look.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
…, not the heygen CLI ones

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
# Conflicts:
#	packages/cli/src/heygen/generate.ts
#	skills-manifest.json
#	skills/media-use/references/heygen.md
@WaterrrForever WaterrrForever changed the title feat(skills): creator templates on the HyperFrames plan feat(skills): style templates on the HyperFrames plan Nov 2, 2026

@jrusso1020 jrusso1020 left a comment

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Reviewed at 0e30f4c78caab000f78af85de3ae0155c4a160e0.

The template pull authenticates before downloading, checks pinned size and SHA-256 before extraction, and stages beside the destination before an atomic rename (packages/cli/src/commands/templates.ts:55–123). The generation retry key derives from source bytes rather than newly assigned asset IDs (packages/cli/src/heygen/generate.ts:624–626).

Important — cutout retries do not use the server's deduplication mechanism (packages/cli/src/heygen/generate.ts:243–246,627). The new /v3/background-removals body omits request_id. That endpoint uses body request_id, and explicitly does not honor the HTTP Idempotency-Key header: see EF movio/api_service/app/controller/background_removal_dto.py:39–48 and background_removal.py:69, plus service background_removal.py:381–389. I checked those files against current EF master. Two identical actual generate/runJob calls, each advanced through its 30-minute pending timeout with mocked upload/HTTP, retain the same header key but have no body request_id. A server-contract model therefore creates two jobs; supplying the same body request_id deduplicates. This is a mocked contract reproduction, not an observed production duplicate. Paid-up HF Pro/Max cutout is currently free, but API credentials can potentially incur another charge (the service has a separate billed path; no billing was executed), and either caller creates another job.

Fix: send the effective retry key as cutout's body request_id, including the failed-job suffix selected by runJob, rather than only as a header. Preserve the same value after a lost response/pending timeout and a fresh value after a confirmed terminal failure. Add a retry regression whose server stub ignores the header and deduplicates exclusively by request_id.

Important — WebM and MOV inputs are declared as audio (packages/cli/src/heygen/generate.ts:386). uploaded() declares .mp4 as video/mp4 and everything else as audio/mpeg. Both new video operations accept an input --video without restricting it to MP4; WebM/MOV reach upload finalization as audio/mpeg and are rejected by the server media-category helper under the checked contract. Actual generate calls captured that declaration. Real FFmpeg MP4/WebM/MOV fixtures, sniffed with file(1), were passed to the AST-extracted current EF _resolve_real_file_type: MP4 succeeds; WebM and MOV fail with “Stored file type … does not match … audio/mpeg.” Correct declared-MIME controls all succeed.

Fix: reuse getMimeType from @hyperframes/core/studio-api (already used by the CLI static server), or explicitly map/validate supported video and audio types before upload (WebM video/webm, MOV video/quicktime, and each accepted audio format). Add real-file MIME controls for cutout/lipsync and avatar audio.

Nit — public discovery: skills/style-remix/SKILL.md:5 still sets metadata.internal=true. The existing skills installer lists the eight public skills and omits style-remix; an explicitly named --skill style-remix does find it. If this is the public launch described in the body, remove the flag and update the catalog/count surfaces. Otherwise describe it as an internal opt-in for now.

Plan-gate / hands-on evidence: no HyperFrames account is configured here. The built CLI's signed-out templates pull 3d-true-crime prints the login step and creates no project directory. No live Free/Pro pull was possible. The CLI's mocked 402 path passes with upgrade guidance and no template files. I inspected current EF moment_routes/moment_access: the server checks the payer's paid-up plan before storage lookup/signing when purchase enforcement is enabled; all five M9001–M9005 packs are outside the free list. Extracted actual functions with mocked policy/plan/storage cover 25 cases: enabled+unpaid→402 with no storage/signing, unavailable+unpaid→503, paid→link. Pre-existing policy: explicitly disabled purchase enforcement allows Free callers; this is a conditional server gate, not an unconditional Pro-only rule. I did not verify production policy configuration or a real expired subscription.

Validation: 181 CLI tests, 21 media-use JS tests and 7 font tests pass; full build and lint pass. Independently reran both adversarial witnesses and MIME controls. Template tests also cover hash mismatch, unsafe parent paths, an existing destination and cleanup after refusal. Malicious symlink/hardlink archives, redirect handling and filesystem-failure injection were not exercised; private pack contents were not available for inspection. No paid generation, live upload, plan purchase/change, full episode or cloud render performed. The linked design/eval page was inaccessible to the web tool; its films were not evaluated.

Audited: template command/tests, shared media generation/pricing/upload/ledger boundaries, transcription and SFX changes, offload references and retention, asset adoption, font shorthand, skill/docs/catalog integration. Server gate and upload/background-removal contracts checked separately against EF source.
Trusting: unchanged auth/payment/provider internals and private pack content; generated manifest structure checked, author-reported production pulls and five end-to-end films not reproduced.

Need: yes · Size: broad but reviewable; media fixes are independently testable · Reuse: getMimeType and endpoint request_id contract · Simpler: adapt the shared paid-job wrapper to cutout's existing deduplication field · Structure: fine
Risk: medium — adds paid media routes and private pack delivery.

Verdict: REQUEST CHANGES
Reasoning: Template refusal and staging pass the exercised paths, but cutout retry identity and non-MP4 upload typing need fixes before approval.

— hf-review

@miguel-heygen miguel-heygen left a comment

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Independent review at 0e30f4c78caab000f78af85de3ae0155c4a160e0; the PR is still a draft.

The template path verifies pinned bytes/SHA256 before unpacking and publishes from a temporary sibling with finally cleanup (packages/cli/src/commands/templates.ts:84–119). The credit-limit check refuses an unpriced operation before generation (packages/cli/src/heygen/pricing.ts:134–150).

Blockers: +1 to @jrusso1020's existing findings; no duplicate inline comments. I independently traced the cutout body at packages/cli/src/heygen/generate.ts:243–246 through runJob: the effective retry key reaches only the HTTP header, while the server DTO/controller use body request_id for deduplication and explicitly ignore that header. A resumed command can therefore start another cutout job. The upload helper at generate.ts:386 also labels every non-MP4 input audio/mpeg, including MOV/WebM and avatar WAV/M4A. These need contract-level tests, beyond the mocked successful upload response.

Additional CI qualification: current Fallow job 125441922255 exits 1. Its report identifies generate.ts:472, commands/media-use/generate.ts:149, and cloud/offload.ts:534,896; resolve or explicitly disposition that gate. The current hosted CLI shards pass 3,982 + 3,343 cases, with 23 + 89 skips; their checkout is synthetic merge 1179aec83fe751f9e1f175a32bfedaca0ce2bd84, merging this head into captured base 7d3c2252. Lint and skill lint/mirror pass. The 167 check records include historical failures and a pending WIP check, so this is not an all-green claim.

Audited: all 36 changed-file diffs; downloader, generation/retry/upload, pricing/refusal, skill instructions, and relevant consumer paths. Limits: no paid calls or new local test run; existing local server-source contracts are not serving-deployment proof. No valid own Free account was established, so live Free→402/no download and live Pro pulls remain unverified. The design/evaluation link requires sign-in; no private pack contents or film-quality claim. The existing internal-skill/public-discovery concern remains as Rames noted.

Verdict: REQUEST CHANGES
Reasoning: The two independently confirmed job-contract bugs remain at this exact head; passing mocked tests do not discharge them.

— Magi (cutroom-dev)

…al type; style-remix is public

The background-removal route dedupes on the body's request_id and ignores the Idempotency-Key
header, so a retry after a lost answer started a second job: runJob now also sends the key in the
body for such a route. Uploads typed every non-MP4 file as audio, so WebM and MOV inputs were
refused: they now take their type from the extension. Fails without the fix: the new cutout test
in generate.test.ts sees audio/mpeg for WebM and MOV.

style-remix drops metadata.internal and is listed with the other published skills.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
@WaterrrForever

Copy link
Copy Markdown
Collaborator Author

Thanks. Fixed in 83d176e:

  • Cutout retries: runJob takes a bodyKey; the cutout route sets it to request_id, so the key actually sent (including the suffix after a confirmed failure) goes in the body as well as the header. v3.test.ts has a server stub that ignores the header and dedupes only on request_id: a lost answer (408) keeps the same value, a failed job moves to -1.
  • Upload type: uploads now use getMimeType from @hyperframes/studio-server, so WebM is video/webm, MOV video/quicktime, M4A audio/mp4. generate.test.ts makes real WebM and MOV files with ffmpeg and cuts each out twice; without the fix it sees audio/mpeg.
  • Public discovery: metadata.internal is gone, and style-remix is in the README, AGENTS.md, CLAUDE.md, the skills guide and the fresh-install check (9 published skills).
  • Fallow: the two added suppressions are gone (the template-scene pass is now a small wrapper around the unchanged rewrite), and the voice decision moved into voiceFor.

On the server gate: agreed it's conditional on purchase enforcement, which is on in production.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
@WaterrrForever

Copy link
Copy Markdown
Collaborator Author

@miguel-heygen (Magi): thanks. All three are fixed at the current head (a6e07a6), as answered to Rames above:

  • Cutout request_id: the key actually sent (with the suffix after a confirmed failure) now goes in the body. v3.test.ts runs it against a stub that ignores the header and dedupes only on body request_id: a lost answer keeps the value, a failed job moves it.
  • Upload type: getMimeType from @hyperframes/studio-server, so MOV, WebM, WAV and M4A are declared as what they are. generate.test.ts cuts out real ffmpeg-made WebM and MOV files and checks the declared type; without the fix it sees audio/mpeg.
  • Fallow: the unused export, the CRAP finding and both added suppressions are gone; fallow audit reports no issues in the changed files.
  • Public discovery: style-remix is no longer internal and is listed with the published skills.

@jrusso1020 jrusso1020 left a comment

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Reviewed at a6e07a60f7b0a4296a46987dbbc09b5bff5f6d38, delta from 0e30f4c78caab000f78af85de3ae0155c4a160e0.

Both earlier Important findings are fixed:

  • Cutout selects bodyKey: "request_id"; runJob inserts the effective liveKey, including its failed-job suffix, into the body as well as the header (packages/cli/src/heygen/generate.ts:251,642; v3.ts:231–235). The lost-response/body-only-dedup regression and real generation timeout witness preserve one job; a confirmed failed job gets a fresh key.
  • uploaded() uses the shared getMimeType mapping (generate.ts:382–389), covering MOV/WebM video and WAV/M4A audio. The real-file WebM/MOV regression executes successfully. This also fixes the shared upload boundary used by lipsync and avatar audio.

Public discovery is fixed: the existing skills installer now lists 9 skills, including style-remix, without an explicit name. The catalog, fresh-install list and manifest include it. The offload function extraction preserves the template-scene rewrite fallback and passes the offload suite.

Validation: bun run --cwd packages/cli test src/commands/templates.test.ts src/heygen src/commands/media-use src/cloud/offload.test.ts src/utils/skillsManifest.test.ts reports 183 passed. Removing both fixes makes the two targeted regressions fail; restoring them makes both pass. The prior actual-generate pending-timeout reproduction now yields one body-keyed job, and fresh adversarial controls cover lost response, timeout, successful replay, terminal failure and shared MIME consumers. Root bun run build and bun run lint pass. Hosted Fallow audit succeeds on this exact head (run 41498870011). No new Important finding in the delta or fresh adversarial pass.

Nit: README.md:85 and CLAUDE.md:7 retain “all 8” while the public catalog has nine; update those remaining counts.

Limits: this re-review exercises mocked service responses and local FFmpeg, not live paid generation, billing, a Free/Pro production pull or a full film. Concurrent independent cutout invocations were not exercised; the retry claim is limited to the tested sequential recovery paths. The original server-gate qualification remains: unpaid callers are refused before signing when purchase enforcement is enabled; the disabled-policy branch permits access. The author reports enforcement is enabled in production; I did not independently verify deployment configuration. Private pack contents/eval films remain outside this review.

Audited: all 16 delta files, retry/upload consumers, offload extraction and public catalog/manifest. Trusting: unchanged PR surfaces covered in my prior review and unchanged server/auth/payment internals.

Need: yes · Size: bounded delta · Reuse: shared MIME table and existing retry-key selection · Simpler: existing wrapper carries the endpoint-specific body key · Structure: fine
Risk: medium — private pack delivery and paid media contracts; fixes close the exercised retry and upload failures.

Verdict: APPROVE
Reasoning: Both prior Important job-contract findings and public discovery are resolved at this head; no new blocking defect found in the reviewed delta.

— hf-review

This branch was successfully deployed

1 active (outdated) deployment
staging - docs — 83d176e1 Deployed Nov 2, 2026 by mintlify[bot]
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

4 participants