Skip to content

feat(skills,studio,media-use): the intent layer, review loop, and user memory — BRIEF.md, companion mode, recipes; /website-to-video folds into /product-launch-video#2133

Merged
WaterrrForever merged 29 commits into
mainfrom
feat/skills-review-loop
Jul 15, 2026
Merged

feat(skills,studio,media-use): the intent layer, review loop, and user memory — BRIEF.md, companion mode, recipes; /website-to-video folds into /product-launch-video#2133
WaterrrForever merged 29 commits into
mainfrom
feat/skills-review-loop

Conversation

@WaterrrForever

@WaterrrForever WaterrrForever commented Jul 10, 2026

Copy link
Copy Markdown
Collaborator

What

The intent layer — every creation run starts with one front-door conversation in the /hyperframes router: it reads remembered defaults and recipes first, triages the input, picks the route, asks that route's own questions, closes with two run-shape questions — storyboard? and automation or companion? — and offers a capability menu before handing a locked brief to the workflow. The confirmed brief becomes BRIEF.md at the project root; workflows ask no brief question of their own. The old collaborative/autonomous first question is gone — the execution mode derives (automation+storyboard: yes → collaborative, automation+storyboard: no → autonomous, companion → general-video), and companion mode turns general-video into a co-creation session with every HyperFrames capability on the table.

The review loop — collaborative runs of the narrative workflows review in three passes of rising fidelity: text plan → wireframe sketch board → animated build, each gated on the user, with a per-frame comment channel on the Studio board that batches into a sidecar file the agent picks up on its next reply. Autonomous runs are untouched: no board, no sketch pass, one preview-or-render question before render.

One website route/website-to-video is removed (skill count 20 → 19). /product-launch-video owns every website input, and its own pipeline is untouched: a "show the site as-is" ask is brief intent, not a pipeline branch — the intent layer asks sell it or show it?, writes the answer into BRIEF.md ("feature the site's own captured screens as the video's assets"), and the workflow's normal steps carry it, since captured screens already flow into asset_candidates.

User memory — two tiers on media-use's existing storage split. Preferences: confirmed brief answers (destination, aspect, language, flow, storyboard, voice, style preset) become next run's recommended defaults with receipts naming their source. Recipes: one approved run frozen as a named, versioned bundle (design spec + storyboard skeleton + brief skeleton + confirmed values); the next "make another weekly-promo" fills the brief, skips the design step, and drafts from the skeletons — while every review gate still runs.

Changes — skills (the intent layer)

  • hyperframes/references/intent.md (new) — the sequence: memory before questions (a mandatory prefs.mjs get + recipe check), input triage, route pick, the route's must-haves, the two run-shape questions, the nice-to-have capability offer, and the handoff. Edit requests never trigger it; a briefed project (BRIEF.md on disk) is read, not re-asked; a pre-BRIEF project resumes from its storyboard frontmatter — never re-interrogated.

  • hyperframes/references/route-briefs.md (new) — per-route question sets, adaptive to the input: the three narrative workflows' fields (pr-to-video's PR-size → length table moves here whole), general-video's former Discovery, website-to-video and music-to-video with declared deferred asks (message/arc after capture; brand/genre at plan time), and the footage/deck routes where the run-shape questions don't apply (their in-flow picks — caption identity, render strategy — are announced up front, asked where the probe data lives).

  • hyperframes/references/capability-menu.md (new) — one table, two readers: the intent layer shows the user a route-filtered slice (capture, beat analysis, blueprints, presets, media generation, figma, registry blocks…); companion-mode general-video uses it as the execution map, with skills update <workflow> before borrowing a lazily-installed workflow's script. Its design ask is a three-state question — they have a spec (frame.md / design.md → brand truth) / the look matters (open 2–3 preset frame-showcase.html files in the browser and pick by eye; the choice records as the style_preset preference) / don't care or nothing fits (workflow decides, or the design picker as a declared deferred ask). On capture routes the showcases come with the honest line: the pick is the layout bones — the site's brand colors remix on top.

  • One owner per rule — the router keeps recognition and pointers; the conversation lives in intent.md; field semantics stay canonical in brief-contract.md; per-route practice lives in route-briefs.md. Duplicated guidance (exploratory intake, mode derivation, aspect table, recipe protocol) was collapsed to its single owner.

  • hyperframes-core/references/brief-format.md (new) — the BRIEF.md artifact: frontmatter = the confirmed deterministic fields (keys align with the registry and the preference store), body = prose sections (Intent / Assets / Customizations / Notes) that stay project-local. Written by each workflow's Setup as its first action after hyperframes init; the storyboard's mode: wins on resume; recipes carry its skeleton.

  • brief-contract.md — § 1 opens with the mode derivation; § 2's registry gains flow and storyboard; § 3's two-round template is replaced by the intent layer's invariants, including the deferred-asks rule (declared, never sprung).

  • All ten workflow SKILL.mds open with the same three-branch rule (BRIEF.md → read; existing project → resume; fresh creation → intent layer) — the narrative three lose their Round 1/Round 2 templates and recipe checks (Step 0 is Setup only: init, BRIEF.md, preference recording, auth preflight); general-video gains a Setup and a Companion section and its board keys off storyboard: yes.

  • hyperframes-core/references/production-loop.md (new) — the stages from an approved plan to a delivered video (blocks & assets, audio, frames, duration sync, assembly, transitions, captions, verify, deliver) written as dependencies, not numbered steps: independent stages schedule freely, chains don't. It never addresses the user — every user-facing pause stays in review-loop.md, and the file only marks the two attach points (plan approval in, final look out). The narrative workflows implement these stages with their own scripts; a freeform build follows the file directly.

  • general-video rewritten freeform — the fixed Step 1/2/3 pipeline is gone. The skill now reads: Setup → the route is yours (three postures: automation brief / companion / edit; resemble a genre → skim that workflow's SKILL.md as a worked example, borrow the shape and the taste, never the machinery) → the laws (admission rule: a law names the action it guards and the bad render without it — scope, identity-before-HTML with the HARD-GATE, end-state-before-tween, run-shape contract, composition contract, media through media-use) → the reading map → companion as conversation (the menu doubles as the trigger list; offer at the moment, one at a time, do-then-show; the conversation is the gate when there's no board; decisions write back to BRIEF.md, which § Lifecycle now keeps as the run's living truth).

  • capability-menu.md v2 — every row's last column normalized to home → entry → what you get; five capabilities added (generative video: HeyGen avatar / image-to-video / dub, publish-to-stable-link, real map scenes, transcript-driven footage cuts, designed overlays on user footage with a whole-ask-vs-one-scene rule); a § Genre lenses section maps piece-resemblance → which narrative workflow's story-design / visual-design / motion-language / cut-catalog to borrow.

Changes — skills (the review loop)

  • hyperframes-core/references/review-loop.md (new) — the single source for the three passes: the plan proposed on a live board (§ 1), wireframe sketches marked built with one layout question (§ 2 — real words on plain blocks, run no CLI; a confirmed board is itself a valid deliverable when the user asked for a storyboard, not a video), the build dressing confirmed layouts (§ 3, worker or inline), the final look plus a once-only recipe-freeze offer whose confirmation teaches the recall phrase (§ 4).
  • The three narrative workflows' Steps 3/4/6 collapse to references plus their sketch stand-ins (captured-asset blocks for product-launch-video, plain code panels for pr-to-video); the confirmed-sketch handoff stays in each frame-worker prompt. general-video plans on a board for multi-scene narrative pieces — its sketch pass is layout-before-animation with the user watching.
  • The router treats "I want a storyboard" as the intent layer's run-shape answer rather than a route, closes exploratory intake by recommending a route plus how the run will review, and recognizes a named recipe or "like last time".
  • The comments channel (silent submit, one reply picks it up, check the file before the words) lands in brief-contract.md § 1; the sidecar schema and the built status rung in storyboard-format.md.

Changes — routing (/website-to-video removed)

  • The skill and its machinery (step references, w2h-verify.mjs, bundled SFX) are deleted; hyperframes skills update removes it from installed machines automatically. /product-launch-video is byte-identical to before except two clauses that pointed at the deleted route.
  • Rewired: the router's cheat-sheet and disambiguation (any URL → one route), route-briefs' PLV entry (sell or show? + what to show), every sibling skill's route-elsewhere pointers, all five catalog surfaces + skill counts, the four plugin manifests, nine docs pages (the /guides/website-to-video guide page keeps its URL, retargeted), and hyperframes capture's generated agent prompt.

Changes — studio + server (the surfaces)

  • Per-frame comments — a comment box on every board tile, batch Submit comments (N) writing .hyperframes/frame-comments.json (a resubmit wins per frame; unconsumed comments on other frames are kept); submitted-but-unconsumed comments stay visible — toolbar banner + per-tile echo — until the agent consumes the file.
  • The board keeps itself current — new GET /projects/:id/signature (cheap: the CLI adapter's watcher-invalidated cache), the storyboard payload carries the signature it was derived from, and the view polls at 2 s (hidden tabs skipped), refetching in place with no loading flash. Posters bake the signature into their URL so tiles fill in as sketches land; the empty state upgrades itself when STORYBOARD.md appears, and its handoff prompt points the agent at the review loop.
  • preview lands where review is — the storyboard view while any frame is built or the board is pure planning; the timeline once assembled.

Changes — media-use (the memory engine)

  • scripts/lib/prefs-store.mjs + scripts/prefs.mjs — project .media/preferences.json (committed, the team inherits it) + personal ~/.media/preferences.json; a value earns the personal tier by being confirmed in two different projects (a user-side sightings ledger accumulates the cross-project evidence), so a one-off choice never pollutes the global defaults. Keys: destination, aspect, language, flow, storyboard, voice, style_preset (per workflow).
  • scripts/lib/recipe-store.mjs + scripts/recipe.mjs — named versioned folders, not content hashes (a recipe is an evolving bundle): freeze skeletonizes the storyboard (structure kept — durations, transitions, srcs, Video direction; statuses reset; content blanked to per-frame fill-ins naming each beat's role) and, when the project has a BRIEF.md, the brief (reusable frontmatter kept; run-shape keys and prose blanked — a recipe never locks the run's shape); list merges tiers, use imports and copies the frame spec in, handing back both skeleton paths (recipes frozen before BRIEF.md existed degrade gracefully). resolve --type recipe --entity <name> delegates like grade/lut.

The trust model

  • Only confirmed answers enter memory — an inferred value, or a default nobody chose (the pipeline's TTS voice), is not an answer; a "go" that accepts the recommended defaults is. The first record announces itself once.
  • Preferences change the default, never the question — every ask-marked field still gets asked, and what the request says this time beats what was picked last time. A wrong guess costs nothing. A remembered flow/storyboard reorders the recommendations; the two run-shape questions are never skipped.
  • Recipes may skip the questions they answer — the bundle was approved as a whole, and adoption itself is the question. Gates are never skipped: a recipe fills in answers, not approvals.

…d, status-aware preview landing

Per-frame comment boxes on the storyboard board batch into
.hyperframes/frame-comments.json (a resubmit wins per frame; unconsumed
comments on other frames are kept). Submitted-but-unconsumed comments
stay visible — a toolbar banner plus a per-tile echo — until the agent
consumes the file; the banner also says what to do next (reply anything
in the agent chat).

The board keeps itself current: GET /projects/:id/signature exposes the
watcher-cached project signature, the storyboard payload carries the
signature it was derived from, and the view polls at 2s (hidden tabs
skipped, re-checked on visibility), refetching in place with no loading
flash. Posters bake the signature into their URL so tiles fill in as
sketches land and a poster that failed mid-write retries on the next
version; the empty state upgrades itself when STORYBOARD.md appears,
and its handoff prompt now points the agent at the review loop and uses
the parser's real status vocabulary (outline, not planned).

preview lands the browser on the storyboard view while the board is the
review surface — any frame built, or pure planning (srcs declared, none
on disk yet) — and on the timeline once the video is assembled.
…cess

hyperframes-core/references/review-loop.md is the single source for the
three-pass collaborative review: the plan proposed on a live board
(§ 1), wireframe sketches marked built with one layout question (§ 2 —
real words on plain blocks, run no CLI; a confirmed board is itself a
valid deliverable when the user asked for a storyboard, not a video),
the build dressing confirmed layouts (§ 3, worker or inline), and the
final look (§ 4). Autonomous runs skip every gate and keep one question
before render.

The three narrative workflows' Steps 3/4/6 collapse to references plus
their sketch stand-ins (captured-asset blocks for product-launch-video,
plain code panels for pr-to-video); the confirmed-sketch handoff stays
in each frame-worker prompt. general-video plans on a board for
multi-scene narrative pieces in collaborative mode — its sketch pass is
layout-before-animation with the user watching. The router treats
"I want a storyboard" as a process request rather than a route, and
closes exploratory intake by recommending a route plus how the run will
review.

The supporting contracts land next door: the comments channel (silent
submit, one reply picks it up, check the file before the words) in
brief-contract § 1; the sidecar schema and the built status rung in
storyboard-format; the mode question asked first and alone in the three
workflows' Step 0.
Two tiers of memory on media-use's existing two-tier storage split.

Preferences (lightweight): confirmed brief answers — destination, aspect,
language, mode, voice, style preset — recorded to the project's
.media/preferences.json (committed, the team inherits it) and promoted
to the personal ~/.media/preferences.json once the same value is
confirmed in two different projects (a sightings ledger accumulates the
cross-project evidence user-side, since project files can't see each
other). prefs.mjs get/record; merge reads project-over-user; a changed
value restarts its provenance.

Recipes (heavyweight): one approved run frozen as a named, versioned
bundle — frame.md, the storyboard skeleton (structure kept: durations,
transitions, srcs, Video direction; statuses reset to outline; content
blanked to per-frame fill-ins naming the beat's role), and the confirmed
brief values. Named folders, not content hashes: re-freezing bumps
version and archives <name>@v<N>; a freeze is already confirmed, so it
promotes to the user tier immediately. recipe.mjs freeze/list/use, plus
resolve --type recipe --entity <name> delegating like grade/lut.

16 new node --test cases; the media-use lib suite is 168/168.
brief-contract § 2 gains Remembered defaults: read the merged
preferences before Round 2 and let a remembered value become the
recommended option with a receipt naming its source project. Memory
changes the default, never the question — every ask-marked field still
gets asked, and what the request says this time beats what was picked
last time. Record only what the user actually confirmed (a defaulted
voice nobody chose is not an answer; a "go" that accepts the
recommended defaults is). The first record announces itself once;
after that the receipts carry the reminder. In autonomous mode a
remembered value becomes the decided value, receipt included.

The three narrative workflows read the remembered defaults before
Round 2, record the confirmed answers at the Step 0 gate, record the
chosen preset at the Step 2 gate (pr-to-video excepted — its preset is
fixed), and fall back to the remembered voice when the request names
none. general-video's discovery reads the same defaults.

Recipes wire in at both ends: Step 0 checks for a matching recipe
before the mode question — one question, plural-aware, and adopting
one fills the brief, skips the design step, and drafts the storyboard
from the frozen skeleton while every review gate still runs. The
review loop's final look (§ 4) offers the freeze once after approval,
and the confirmation teaches the recall phrase — the name is something
the system reminds the user of, never something they must remember.
The router recognizes a named recipe or "like last time" as a route.

@miga-heygen miga-heygen left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

Review — feat(skills,studio,media-use): the review loop and user memory

Big feature, well-structured. Six interleaved pieces that compose into the three-pass review flow + user memory. I'll take them in the order they build on each other.

1. Project signature polling (studio-server + studio)

resolveProjectSignature extracted from preview.ts into projectSignature.ts and reused by preview, projects, and storyboard routes — good SSOT improvement, was inline before.

New /projects/:id/signature endpoint is a cheap poll target. useProjectSignaturePoll polls every 2s, skips hidden tabs, avoids concurrent requests, and no-ops when the baseline is undefined (initial load not yet done). Well-tested: signature mismatch fires, match stays quiet, hidden tabs skip, re-arms after caller refresh, cleanup on unmount.

The storyboard response now carries signature in both the absent and present branches — tested in storyboard.test.ts. The board uses it as posterVersion on FramePoster (cache-bust on the thumbnail URL via a ?sig= param).

2. Preview landing on storyboard view

studioLandingSearch determines the landing view from frame statuses: any built → board (sketch review in progress), all outline with declared srcs but no files → board (planning), otherwise timeline. Exported and tested. The deep-link URL puts ?view=storyboard before the hash — documented in preview-render.md.

3. Frame comments (studio + shared contract)

Clean separation between pure logic (frameComments.ts — all the data transforms, fully tested) and React state (useFrameComments.ts — the hook that wires drafts, submit, and pending-refresh to the file manager context).

The buildCommentsFile merge logic is right: a resubmit before the agent consumes the previous batch keeps unconsumed entries for frames the new batch doesn't mention, overwrites the ones it does, sorts by frame index. The passForFrames derivation (furthest status on the board determines the pass) is simple and correct.

The comment box per tile (StoryboardFrameTile.tsx) and the batch submit bar (CommentsSubmitBar in StoryboardLoaded.tsx) are clean UI additions. The useEffect on data.signature in StoryboardLoaded re-checks the comments file when the board refreshes — catches the moment the agent deletes it after consuming.

The contract is defined in storyboard-format.md § Frame comments and cross-referenced from brief-contract.md § 1 ("the comments channel"). Good.

4. Preferences — two-tier remembered defaults (media-use)

prefs-store.mjs: atomic writes (tmp + rename), tolerant reads (corrupt = empty), two-tier with a clean promotion rule (PROMOTE_AT = 2 distinct projects). style_preset keyed per workflow via preferenceKeyFor. User-tier sightings ledger keeps cross-project evidence in the only place that can see it (the user file). Best-effort user-tier writes — a read-only home directory never fails a brief.

Test coverage is solid: record + merge, no one-project promotion, two-project promotion, idempotency, changed-value provenance reset, project-overrides-user, per-workflow keys, unknown key rejection, corrupt file handling.

The consumption contract (brief-contract § 2, "Remembered defaults") is clear: a remembered value changes the recommended default with a receipt — never skips a question, and explicit request content always wins. Each workflow's Step 0 references this section.

5. Recipes — frozen video bundles (media-use)

recipe-store.mjs: skeletonizeStoryboard is the interesting piece — parses markdown, keeps structure (durations, transitions, src paths, Video direction block, style frontmatter), blanks content (message, audience, narration, per-frame prose → one <fill in> placeholder per frame naming the beat's role), resets all statuses to outline. Well-tested against a realistic storyboard fixture.

freezeRecipe: merges preferences into recipe.json, copies frame.md, generates the skeleton, appends a manifest record, promotes to user-tier immediately (a freeze is already confirmed). Re-freezing bumps version and archives the old folder as <name>@v<N>. useRecipe: imports from user tier if the project doesn't have it, copies frame.md over, returns brief values + skeleton path. listRecipes: two-tier merged (project wins), skips @v archives.

Also wired into resolve.mjs as --type recipe — consistent with the existing resolve pattern for other asset types.

6. Skill updates (faceless-explainer, pr-to-video, product-launch-video, general-video, hyperframes)

The same changes replicated across all storyboard-planning workflows:

  • Recipe check before Round 1
  • Round 1 sent alone (explicit "wait before Round 2" wording)
  • Remembered defaults before Round 2 questions
  • Sketch pass at Step 4 with workflow-specific stand-ins
  • Worker context includes confirmed-sketch flag + keep-layout rule in frame-worker.md
  • Gates include sketch board confirmation (collaborative)
  • Voice fallback to remembered voice before pipeline default
  • Review loop reference at plan presentation and final look

This is intentional replication — each workflow SKILL.md is a standalone document loaded independently. The shared process lives in review-loop.md; each skill wires its steps to specific sections. Correct pattern for the skills architecture.

SSOT check

  • resolveProjectSignature unified — previously inline in preview.ts, now shared across three routes. Good.
  • Frame comments contract: defined once in storyboard-format.md, implemented in frameComments.ts, cross-referenced from brief-contract.md. Single source.
  • Preferences consumption rule: defined once in brief-contract.md § 2, referenced by every workflow. Single source.
  • Review loop process: defined once in review-loop.md, wired into each workflow at the appropriate steps. Single source.
  • Skill replication: intentional — standalone docs, not shared code.

CI note

Skills: manifest in sync is failing — the manifest hash/count may need a refresh after the skill file changes.

Verdict

LGTM. Clean architecture, good test coverage, well-separated concerns. The CI manifest check needs a fix before merge. Looking forward to the additional tests Miao mentioned.

Review by Miga

@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.

HF-specialist review — COMMENT (external author; stamp = James's call)

Audited (in addition to Miga's general coverage): the new shared-contract file (review-loop.md) end-to-end and its integration with brief-contract.md + storyboard-format.md; the Studio-side signature-polling design (useProjectSignaturePoll.ts + server-side projectSignature.ts); the frame-comments file protocol (frameComments.ts); the preferences store's two-tier promotion logic (prefs-store.mjs); and skeletonizeStoryboard's structure-keep/content-blank behavior (recipe-store.mjs).

Trusting: Miga's coverage on the 6-piece composition (project-signature polling, preview landing, frame comments, prefs two-tier, recipes, skill updates). Not duplicating; adds below focus on the HF architectural angle.

Design fit — shared-contract pattern

review-loop.md (+41 lines, new) follows the exact shape established by brief-contract.md and story-spine.md (HF#2058): shared rules file + workflow SKILLs bind to it via markdown pointers + explicit cross-references between siblings. Same "invariants centralized, executable script local" split. Load-bearing cross-refs from review-loop.md §§ 1-4 back into brief-contract.md § 1 (interaction mode / comments channel) and storyboard-format.md (frame statuses, comments file) are all present and land correctly on the referenced targets. Fits cleanly.

brief-contract.md gets two additions — "The comments channel" (§ 1) and "Remembered defaults" (§ 2) — that widen its scope from interaction to interaction + memory. Reasonable expansion; the file already handled ordering + gates + fields, so preferences memory as a field-level attribute belongs here.

Studio storyboard board — signature polling design

useProjectSignaturePoll.ts:29-67: 2s interval, skips when document.hidden, skips when previous request inFlight, visibility change triggers immediate re-check, no baseline (signatureRef.current === undefined) → no compare (safe), any fetch failure → skip tick (fails open). Solid shape. Comparison baseline is the signature the caller's data was loaded with, so refetch naturally re-arms.

Server-side projectSignature.ts computes a stable content-aware hash: text files ≤ 2MB use content, everything else uses mtime + size. Cache keyed by (mtime + size + relative-path) fingerprint avoids re-reading unchanged files — good. Excluded dirs list at projectSignature.ts:18-30 covers the standard cases (.git, node_modules, outputs, renders, .next, .cache, dist, build, coverage, .hyperframes, .vite).

Concern (nit-level, not blocking): STUDIO_SIGNATURE_MANIFEST_PATHS at projectSignature.ts:32-35 is a hand-maintained allowlist of .hyperframes/* files that DO count toward the signature (studio-manual-edits.json, studio-motion.json). The .hyperframes/ dir itself is otherwise excluded. This means a future Studio subsystem writing to .hyperframes/newthing.json will silently NOT trigger poll refreshes until someone remembers to add it here. Two mitigations to consider (either fine, both fine): (a) invert to a denylist that skips .hyperframes/frame-comments.json (outbound feedback, doesn't need to trigger self-refresh) and includes everything else under .hyperframes/; or (b) add a test that pins this list against the actual Studio-server write surface so a mismatch fails CI.

Concern (nit-level): collectProjectSignatureFiles at projectSignature.ts:65-99 recurses without a depth or file-count cap. Excluded-dirs handles the common problem cases, but a non-standard build directory (someone's .next renamed to custom-build) would churn the 2s poll traversing files. The cache short-circuits on unchanged fingerprints so steady state is cheap, but the first-hit or after-a-refactor cost is uncapped. Consider a soft cap or a file-count guard. Not blocking.

Frame comments file — the review's structured feedback channel

frameComments.ts:104-115 buildCommentsFile correctly handles the "resubmit before agent consumed" case: keeps entries for frames the new batch doesn't mention, overwrites the ones it does. Right invariant — a partial resubmit doesn't lose feedback on other frames.

parseCommentsFile:79-97 is lenient — malformed JSON, missing fields, or non-array comments returns null → treated as "no file". Aligned with the storyboard parser's lenient pattern (storyboard-format.md "The parser is lenient"). Good consistency across the read-side contract.

The cross-repo contract comment at frameComments.ts:6-10 explicitly pins the file shape to skills/hyperframes-core/references/storyboard-format.md § Frame comments. Nice discipline — keeps the shape from drifting between the Studio writer and the SKILL.md documented contract. A regression test that reads both the TS interface and the SKILL.md section and asserts field parity would tighten this further; not blocking.

skeletonizeStoryboard — structure/content split

recipe-store.mjs:123-141. What's kept: frame count, headings, duration, transition_in, src, style-ish frontmatter (format, arc). What's blanked: frontmatter content keys (message, audience, mode), per-frame content keys (voiceover / vo / voice_over / narration / scene / description / summary / caption / asset_candidates), every frame's status → outline, per-frame prose → placeholder <fill in: this video's content for the "..." beat — keep the layout role, replace the words.>.

Verified correct: mode correctly drops (interaction mode is per-run content, not reusable structure) per brief-contract.md § 1. arc correctly kept (reusable narrative structure) per story-spine.md. Case-insensitive detection via .toLowerCase() in skeletonFrameLine:96-101 matches how storyboard-format.md defines these keys.

Consistency observation: FRAME_CONTENT_KEYS at recipe-store.mjs:37-49 includes asset_candidates which isn't documented in storyboard-format.md's per-frame table. If that's an emerging convention worth documenting, add it to the storyboard-format table so both sides stay in lockstep. Not blocking — the skeletonizer treating unknown-but-content-shaped keys as content is the safer default.

Concern (nit-level): recipe archive accumulation. freezeRecipe:174-181 renames the old folder to <name>@v<N> before writing the new one, and scanRecipesDir:229-238 filters out @v entries from listings. No garbage collection — long-lived projects that re-freeze the same name repeatedly accumulate @v1, @v2, @v3, ... indefinitely. Not a bug, but worth a follow-up (either a hard cap like keep-last-3 or an explicit recipe.mjs gc command).

Preferences store — two-tier promotion

prefs-store.mjs:130-146 recordUserSighting: accumulates project sightings under sightings[fullKey][value] (per-value), promotes to preferences[fullKey] when seenIn.length >= PROMOTE_AT (2). Atomic writes via writePrefsFile:70-76 (tmp + rename) — good. Best-effort user-tier write in recordPreference:167-173 so a read-only home directory never fails a brief.

Concern (subtle, nit-level): sightings[fullKey][value] is keyed on basename(resolve(projectDir)) at prefs-store.mjs:161. Two distinct repos with the same basename (git clone in two different parents, e.g. ~/work/foo and ~/personal/foo) both writing the same value would deduplicate to ONE sighting via the dedupe([...]) on line 134, delaying promotion. Conversely, two separate projects with different basenames but the same identity (a directory rename) would double-count. The unaffected common case is the one that matters here (most people don't clone the same repo twice), so this is a low-frequency concern. Fix if it comes up: salt with a project-hash slice.

The keepProvenance logic in recordProjectTier:113-124 is nice: a changed value starts provenance over (old confirmations vouched for the old value), so a mid-flight preference change doesn't inherit stale trust. Right shape.

Manifest CI failure

Skills: manifest in sync fails at the "Verify skills-manifest.json matches skills/" step. Confirmed via the failing job log + the diff shape: hyperframes-core shows +1 file (14 → 15 — the new review-loop.md) and multiple hash rows updated for touched skills. This is a regen-only fixbun scripts/gen-skills-manifest.ts (or whatever the local generator command is) will produce a manifest that matches. Miga's read is correct.

Verdict

COMMENT — the review-loop / preferences / recipes design fits HF's shared-contract pattern cleanly (same shape as brief-contract.md + story-spine.md); the Studio signature polling is thoughtful (visibility-aware, in-flight-guarded, fails-open); skeletonizeStoryboard's structure/content split is coherent with brief-contract.md § 2's memory semantics; frame-comments file protocol matches its SKILL.md documented contract. Concerns found are all nit-level (allowlist maintenance risk on signature manifest paths, no file-count cap in signature traversal, no GC on @v archives, project-basename collision in sightings ledger). Manifest CI failure is regen-only. Stamp = @jrusso1020's call (external author WaterrrForever; requester Miao is allowlisted but not a trusted-stamper, per delegation rule).

Given Miao is explicitly holding on merge for more tests to land, none of these nits need to block the eventual merge — noting them for the next follow-up.

— Rames Jusso

@WaterrrForever WaterrrForever changed the title feat(skills,studio,media-use): the review loop and user memory — sketch-first review, per-frame board comments, remembered defaults, recipes feat(skills,studio,media-use): the intent layer, the review loop, and user memory — BRIEF.md, companion mode, sketch-first review, remembered defaults, recipes Jul 13, 2026
@mintlify

mintlify Bot commented Jul 13, 2026

Copy link
Copy Markdown

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

Project Status Preview Updated (UTC)
hyperframes 🟢 Ready View Preview Jul 13, 2026, 4:05 PM

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

@WaterrrForever WaterrrForever changed the title feat(skills,studio,media-use): the intent layer, the review loop, and user memory — BRIEF.md, companion mode, sketch-first review, remembered defaults, recipes feat(skills,studio,media-use): the intent layer, review loop, and user memory — BRIEF.md, companion mode, recipes; /website-to-video folds into /product-launch-video Jul 13, 2026
# Conflicts:
#	.claude-plugin/plugin.json
#	.codex-plugin/plugin.json
#	.cursor-plugin/plugin.json
#	README.md
#	skills-manifest.json
#	skills/hyperframes-cli/SKILL.md
#	skills/product-launch-video/SKILL.md
… records require workflow scope

Two holes found by a live companion-run freeze: the agent-supplied --workflow
contradicted the run's actual workflow (recipe.json said faceless-explainer,
brief-skeleton said general-video), and the style_preset lookup missed because
the preference had been recorded under the bare key.

- freezeRecipe resolves the workflow from BRIEF.md frontmatter; the flag is a
  fallback for briefless projects and a contradicting flag is ignored (noted).
- recordPreference refuses a bare style_preset — the scoped key is the only
  writable shape; freeze tolerates legacy bare records via read fallback.
- review-loop § 4 / media-use SKILL / brief-format wording follow the machinery.

@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.

Re-review — COMMENT (external author; stamp = James's call)

Delta from my prior review at 451699db260b: 250 new commits, 559 ahead / 7 behind, 143 files touched (+3764/-5121). Not a merge-only re-ping — this is the substantial redesign Miao described on 2026-07-13 (intent layer at /hyperframes, companion/automation modes, pitch round for unformed requests, product-launch absorbs website-to-video as the tour angle). Not duplicating Miga's substance walkthrough — additive on design-fit + status of my prior-round nits.

Strengths on the intent-layer redesign

  • State-table-first at /hyperframes § 1 — six state rows evaluated top-to-bottom (Remotion port / project operation / edit / BRIEF.md exists / hyperframes.json or STORYBOARD.md exists / fresh creation). Fresh creation is the only path that triggers the intent layer. Edits, project ops, briefed projects, and Remotion ports skip cleanly. That's the correct discipline — the intent layer is expensive (5+ mandatory reference reads), and it should only run when there's genuinely no state to resume from. references/workflow-catalog.md as the canonical route contract before lazy-installed workflow skills are present is a nice pre-install gate.
  • Two run-shape questions kept orthogonal at § 4.6flow × storyboard, four combos valid, "never merge them into one menu" spelled out explicitly (companion-with-storyboard is a real user choice, not an "outcome-of-a-3-way-branch" artifact). This is exactly the invariant that gets silently violated when a diagram summarizes outcomes as three branches; codifying it in prose before any workflow's Step 0 sees the state is the right shape.
  • BRIEF.md as durable output (contract at hyperframes-core/references/brief-format.md) — replaces ad-hoc in-conversation briefs with a file the workflow reads. Handoff at § 4.8 is right: workflow's Setup writes BRIEF.md as its first action after hyperframes init (not before — init refuses non-empty dirs), then never asks brief questions again. Load-bearing invariant.
  • Pitch round for unformed requests (references/pitch-round.md) — "sample five concepts along five genuinely different paths, at least two from the distribution's tail" is a strong sampling discipline. The "concept names its capabilities in the plain language of capability-menu.md" idea keeps the pitch grounded in what the system can actually do vs abstract vision.
  • Recipe-adoption gates — "make the offer earn the yes" with specific "what adopting saves" — the discipline for what a recipe answers vs what still gets asked is now explicit at § 4.1.

Design concerns worth eyeballing

  1. Cognitive load on the router. § 4's mandatory-reads table lists 5 references to consult on the routing path (workflow-catalog.md, route-briefs.md, pitch-round.md, capability-menu.md, brief-contract.md). Plus the domain-skill table at § 6. That's a lot of reference-material load for a single agent turn — the LLM opens 5 files, reads route-specific sections, applies the state-table + route-table + ambiguity-resolution, all before asking any question. Sanity-check that the intent-layer walkthrough completes in a reasonable turn budget on a real fresh request; if not, consider consolidating the mandatory reads into a single "intent-router.md" reference (or making some conditional/deferred).

  2. Pitch round's five-diverse-concepts discipline is aspirational without a pinning example. "At least two from the distribution's tail" is easy for a reviewer to endorse and hard for an LLM to actually execute — most LLMs settle on 3-4 similar concepts around the modal case. Consider adding one worked example inside pitch-round.md showing what "genuinely different paths" looks like for a specific input (e.g. a launch video for X → 5 concepts spanning: literal-demo / metaphor / customer-testimonial / behind-the-scenes / animation-first). A calibration example is worth several paragraphs of "should sample diversely."

  3. "Route absorbs website-to-video as the tour angle" (/product-launch-video). This is a meaningful scope shift. The old routing distinguished "launch/promo → product-launch-video" from "general site tour → website-to-video". The new state at § 3 folds site tours into product-launch-video with the note that "a tour is brief intent, not a pipeline branch." That's cleaner architecturally, but the routing entry at row 8 says "Market or showcase a website, product site, app, or company from a URL or site-specific brief" which is broad. Miga's substance walkthrough will catch whether the product-launch-video SKILL.md now handles both intents without regressions on the pure-tour case.

Status of my prior-round nits

Comparing to the 4 nits I flagged at head 451699db:

  • Recipe @v archive GC (was: "no garbage collection; <name>@v1, @v2, @v3 accumulate forever"): essentially addressed. freezeRecipe at recipe-store.mjs:225-227 does rmSync(archive, {recursive:true, force:true}); renameSync(dir, archive) — the OLD @v<N-1> archive is deleted before renaming the current dir. Effectively keep-last-1 per recipe name, one archive at a time. Not the full GC I proposed but the invariant is bounded. Fine.
  • STUDIO_SIGNATURE_MANIFEST_PATHS hand-maintained allowlist (was: "future Studio subsystems writing new .hyperframes/* files will silently miss the poll"): still open. projectSignature.ts:32 still uses the hand-maintained include-list.
  • Uncapped file collection in collectProjectSignatureFiles (was: "no depth or count cap"): still open. SIGNATURE_EXCLUDED_DIRS at :18 unchanged; still traverses recursively without a soft cap.
  • Prefs basename collision (was: "two repos with same basename collapse in the sightings ledger"): still open. prefs-store.mjs:165 still uses basename(resolve(projectDir)).

All 3 remaining are nits I flagged as non-blocking previously; they remain non-blocking here. Just noting the status so a follow-up can pick them up cleanly.

Verdict

COMMENT — intent-layer redesign is well-shaped, the state-table + two-orthogonal-questions + BRIEF.md-as-durable-output patterns are load-bearing invariants worth having in-source. Cognitive-load + pitch-round-diversity concerns are worth pin-testing in real runs but don't block. Prior-round nits mostly still open (1 of 4 resolved). CI green on b831ed8fc238. Stamp = @jrusso1020's call (external author WaterrrForever; requester Miao is allowlisted but not a trusted-stamper, per delegation rule).

— Rames Jusso

@miga-heygen miga-heygen left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

Review — #2133 feat(skills,studio,media-use): intent layer, review loop, user memory

Verdict: LGTM — 143 files, 3554/5123 lines. Reviewed in three parallel passes (skills layer, studio/server, media-use memory). Strong SSOT discipline throughout. No blocking issues.


Skills layer — SSOT verified clean

Every major new concept has a single canonical owner:

Concept Canonical Owner
BRIEF.md artifact shape brief-format.md
Mode derivation brief-contract.md §1
Review loop checkpoints review-loop.md
Production loop stages production-loop.md
Intent layer procedure /hyperframes SKILL.md §4
Per-route questions route-briefs.md
Workflow contracts workflow-catalog.md
Preferences media-use SKILL.md (impl) + brief-contract.md §2 (consumption)
Recipes media-use SKILL.md (storage) + review-loop.md §4 (offer)

No duplicated decisions. Cross-reference graph verified — every "see X section N" points to a file and section that exists and says what's claimed.

Skill count (20→19): verified consistent across CLAUDE.md, README.md, skills-manifest.json (19 entries), all plugin manifests.

Three-branch rule: verified consistent across all five main creation workflows (PLV, faceless, pr-to-video, general-video, music-to-video). Lighter workflows have appropriate variants.

website-to-video removal: complete. All 13 files deleted, all routing/disambiguation/catalog surfaces cleaned, zero remaining w2v/w2h references.

Stale concepts: Round 1/Round 2 templates fully removed. "Collaborative or autonomous?" question properly replaced by flow × storyboard mode derivation.

Non-blocking (skills)

  1. Docs files not in the diff — 4 docs pages (introduction.mdx, showcase.mdx, hyperframes-vs-remotion.mdx, docs.json) still reference "website-to-video" as a concept name. They link to the retained /guides/website-to-video guide page (which was retargeted), so the links aren't broken — but introduction.mdx naming it as a skill could confuse readers. Follow-up cleanup.

  2. inspectcheck renamehyperframes-core/SKILL.md's validation checklist (outside the diff's hunk range) may still read npx hyperframes inspect while the references were updated to check. Worth verifying.


Studio / server — clean React, one minor URL nit

Signature polling (useProjectSignaturePoll): well-designed. disposed flag handles unmount, inFlight prevents concurrent fetches, document.hidden skips background tabs, ref-based comparison avoids stale closures. The two-level cache in createProjectSignature (fingerprint → content hash) keeps the 2s poll cheap.

Frame comments (useFrameComments, frameComments.ts): clean data model. File is versioned, parser is tolerant, merge semantics (resubmit preserves unconsumed comments for other frames) are correct. buildCommentsFile tested for merge behavior.

useStoryboard background refresh: hasDataRef / lastProjectRef pattern elegantly avoids loading-spinner flash on background refresh. cancelled flag handles concurrent fetches.

Type safety: no any types, no unsafe as assertions. parseCommentsFile uses runtime type guards. fetchProjectSignature casts + validates.

Non-blocking (studio)

  1. studioDeepLink URL construction${url}/${studioLandingSearch(...)}#project/... inserts an extra / before the hash when studioLandingSearch returns "". Produces http://host:port/ + #project/name instead of http://host:port + #project/name. Most SPAs handle both, but it's an unnecessary behavioral change.

  2. Redundant onChange during slow refetch — if the storyboard reload is slow (>2s), the next poll tick sees the stale signatureRef and fires onChange again. useStoryboard's cancelled flag handles this gracefully (no data corruption), but it triggers 2-3 redundant fetches per change event. Tracking "last fired signature" in a ref would prevent it.

  3. useFrameComments hook untested — the pure functions are tested in frameComments.test.ts, but the hook's state machine (draft tracking, submit flow, error recovery, refreshPending on focus) has no dedicated test.


Media-use memory engine — well-designed for CLI context

Preference store: two-tier model (project + personal) is clean. PROMOTE_AT = 2 threshold is a named constant. Atomic writes (tmp + rename). Tolerant reads (corrupt/missing → empty). Input validation at the store level (unknown keys rejected, empty values rejected, style_preset without workflow rejected).

Recipe store: slugifyRecipeName thoroughly prevents path traversal (strips everything except [a-z0-9-]). Versioned re-freeze with archive (@vN suffix). BRIEF.md is the workflow source of truth (flag is fallback). Skeletonization correctly keeps structure and blanks content.

Trust model: enforced at the store level, not just docs. Best-effort user tier (try/catch, never breaks project-tier write).

Non-blocking (media-use)

  1. Stale sightings in promotion ledgerrecordUserSighting accumulates project associations but never retracts them when a project's value changes. If project A confirms destination = "x-feed", then later changes to "youtube", the sightings for "x-feed" still include project A. A retracted value could re-promote from phantom evidence on a future confirmation cycle. The project tier correctly restarts provenance — this is only about the personal-tier sightings ledger. Worth documenting the design choice or adding retraction logic.

  2. Three independent "content key" setsFRONTMATTER_CONTENT_KEYS, BRIEF_CONTENT_KEYS, and FRAME_CONTENT_KEYS in recipe-store.mjs are hardcoded independently. If the storyboard format adds a new content key, it needs to be added to the right set with no shared constant or test to catch a miss. Acceptable for v1 — tech debt if the format evolves.


Summary

Domain Blocking Non-blocking
Skills layer 0 2 (docs refs, inspect→check)
Studio/server 0 3 (URL nit, redundant onChange, hook test gap)
Media-use memory 0 2 (stale sightings, content key sets)

Strong SSOT discipline across a massive PR. No blocking issues. Ship it.

@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.

Approving on @jrusso1020's call.

@WaterrrForever WaterrrForever merged commit b9be0b2 into main Jul 15, 2026
51 checks passed
@WaterrrForever WaterrrForever deleted the feat/skills-review-loop branch July 15, 2026 13:19
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.

3 participants