Commit Graph

323 Commits

Author SHA1 Message Date
Morpheus 6580987931 fix: harden tool governance and subprocess safety
- persist budget warnings and approved paid-tool decisions
- support binary dependency declarations
- include stderr/stdout details for failed subprocesses
- escape lavfi movie paths used by ffmpeg scene detection

Verification:
- python3 tests/tools/test_cost_tracker_governance.py
- python3 tests/tools/test_scene_detect_lavfi_escape.py
- python3 tests/tools/test_base_tool_dependencies.py
- python3 -m py_compile ...
2026-07-03 20:07:00 +08:00
0xDevNinja 9613a3acfd fix(math_animate): block all reflection dunders, not an enumerated set
The prior dunder denylist was still bypassable via print.__self__ (the builtins
module) -> .open(...), reachable with no import and no bare open/__builtins__/
getattr name. Enumerating dangerous dunders is whack-a-mole, so block ALL
dunder attribute access generically and allow only the tiny set legitimate
scenes need (super().__init__, occasional Type.__name__). This closes the
print.__self__ / .__class__ / .__globals__ introspection-escape class at once.

Static analysis still has a ceiling — a real subprocess sandbox is the complete
fix — but the default path no longer executes the reported secret-read payloads.

Adds regression tests for print.__self__ and for super().__init__ staying allowed.

Refs #219
2026-07-03 13:04:33 +05:30
0xDevNinja f265afde5d fix(math_animate): harden scan against no-import builtins/reflection bypass
The scan only flagged dangerous builtins as direct call targets (ast.Name func)
and dunders as attribute access, so it missed indirection like
`__builtins__['open']('.env').read()` and `getattr(o, '__class__')` — the
default path still executed secret-reading code.

Block dangerous identifiers wherever they appear as a bare name (open, eval,
exec, compile, __import__, __builtins__, getattr/setattr/delattr, globals/
locals/vars) rather than only as a call target, and extend the blocked dunder
set (__class__, __dict__, __getattribute__, __reduce__, ...). This closes the
reported no-import bypass while genuine math scenes still pass.

Still defense-in-depth, not a full sandbox; the allow_unsafe_code opt-out and
explicit code-execution contract remain. A subprocess-level sandbox is the
right follow-up for complete isolation.

Refs #219
2026-07-03 13:04:33 +05:30
0xDevNinja b69ce5f9a2 fix(math_animate): gate caller-supplied scene_code execution (#219)
math_animate writes caller-supplied Python to scene.py and runs Manim on it —
arbitrary local code execution with no boundary surfaced in the tool contract.
In an agent-driven system the scene_code may be LLM-generated or influenced by
untrusted prompt content, so import-time code or construct() could read
secrets/SSH material, open network connections, or spawn subprocesses.

Add a static AST safety scan that rejects dangerous imports (os, subprocess,
socket, requests, ctypes, ...), dangerous builtins (eval/exec/compile/open/
__import__), and sandbox-escape dunders (__globals__, __subclasses__, ...)
before Manim runs. Genuine math scenes (manim, numpy, math, ...) pass
untouched. This is defense-in-depth, not a sandbox: a determined attacker can
evade a static denylist, so it is paired with an explicit allow_unsafe_code
opt-out and a tool contract (schema + side_effects) that names the boundary.

Closes #219
2026-07-03 13:04:33 +05:30
0xDevNinja 6426662083 fix(audio_mixer): asplit speech stream so ducking graph is CI-portable
The prior fix removed the dangling pad but still reused the speech filter
output for two consumers (sidechain key + final mix). FFmpeg auto-splits a
reused *input* label on some builds (macOS) but the Linux ffmpeg on CI rejects
it, so both full_mix ducking tests failed there.

Build a single [speech_all] stream and asplit it into [speech_key] (sidechain
key) and [speech_out] (final mix) so every filter label is produced once and
consumed once. Verified the generated graph for the single- and multi-narration
cases: no label is consumed more than once.

Refs #265
2026-07-03 12:58:29 +05:30
Calesthio 0c202b507a
Merge pull request #226 from 0xDevNinja/feat/publish-tier-export-bundle
feat(publish): add export_bundle, the first PUBLISH-tier tool
2026-07-02 15:06:03 -07:00
Calesthio 7f88e5904e
Merge pull request #251 from 0xDevNinja/fix/issue-217-remotion-debuggable
fix(video_compose): surface Remotion failures + add render timeout passthrough (#217)
2026-07-02 14:49:31 -07:00
calesthio 80657bb820 Fix Backlot CI test client dependency 2026-07-02 12:28:55 -07:00
calesthio 280400d479 Ship Backlot living storyboard release hardening 2026-07-02 12:19:06 -07:00
calesthio 1d60f0da14 backlot: fix all five dogfood findings (F-01..F-05)
- F-01: cost bar crit (red) state past 90% of budget
- F-02: normalize() hardens fetched board state against sparse payloads
- F-03: /thumb 404s for videos with no extractable poster frame instead
  of serving raw video bytes
- F-04: checkpoint artifact path refs only resolve inside the project dir
- F-05 (board half): stall detection — in_progress stage with no disk
  activity >10min renders red 'stalled?' + header badge flips to STALLED?;
  verified against the real wedged why-cities-glow project
- eval harness from dogfood session committed (visual regression +
  interaction smoke, capture watcher, server/gate test suites) +
  regression tests for each finding; 46 backlot tests green, visual eval
  green (restage-before-capture note logged)
2026-07-02 08:22:03 -07:00
calesthio 811480d39b backlot: README showcase + screenshot pipeline, unlisted-stage placement fix
- README 'Watch It Happen' section with four staged screenshots (fictional
  demo productions, generated placeholder art — no private project content)
  + governance section notes enforced approval gates
- scripts/backlot_screenshot_stage.py: stages 4 demo projects in 4 pipeline
  states against OPENMONTAGE_PROJECTS_DIR and captures the shots with
  Playwright — reproducible README imagery
- lib/paths.py: OPENMONTAGE_PROJECTS_DIR env override (checkpoints, events,
  and the board all follow one root); backlot/state.py now imports it
  (was still defining its own copy — the exact drift the review warned of)
- undeclared-stage checkpoints (e.g. a legacy 'idea' run under a cinematic
  manifest) now slot into their canonical rail position instead of dangling
  after publish, drawn dashed + italic with an 'unlisted' note
2026-07-02 07:20:17 -07:00
0xDevNinja f08a77979c fix(schema): allow empty files[] in source_media_review artifact
review_source_media deliberately returns files:[] with a 'no source media —
fully generated production' summary when no user media is supplied or none can
be reviewed, but the schema declared files.minItems:1, so that intended
artifact failed its own validation. Relax files.minItems to 0 to match the
code's deliberate empty-media state (planning_implications still carries an
entry, so its minItems:1 remains satisfied).

Adds a regression test validating the no-source-media artifact.

Closes #269
2026-07-02 16:52:00 +05:30
0xDevNinja 364182cc39 fix(variation_checker): measure longest run for consecutive same-size shots
Check 2 flagged 'N consecutive same-size shots' from a count of every equal
adjacent pair across the whole plan, not the length of any real run. So three
separate 2-shot groups (wide,wide,cu,cu,med,med) tripped a false '3
consecutive' violation, while a genuine run of 3 (only 2 pairs) was never
flagged. Track the current run length, reset on change, and compare the longest
run >= 3.

Adds regression tests: non-consecutive pairs pass, a true run of 3 is flagged,
unspecified shots don't form a run.

Closes #268
2026-07-02 16:52:00 +05:30
0xDevNinja febc9244d3 fix(audio_mixer): drop dangling speech_dup pad in full_mix ducking
full_mix with ducking enabled (the default) failed for a single narration
track + one music bed — the most common shape — because the ducking branch
appended an acopy[speech_dup] filter whose output pad was never consumed,
leaving the filtergraph with a dangling output that ffmpeg rejects.

For a single speech track speech_out is '[a0]' (starts with '[a'), so the
guarded append fired; the compensating pop() only removes the empty-string
case from the multi-speech branch, so the dead pad survived exactly in the
single-narration case. The speech stream is already re-derived for the final
mix via [speech_out], and ffmpeg auto-splits the reused input label, so the
duplicate is unnecessary. Multi-speech and SFX paths are unaffected.

Adds regression tests for single- and multi-narration full_mix with ducking.

Closes #265
2026-07-02 16:41:58 +05:30
mojahurtowniapl f95505c3ca Clamp Pixabay per_page to API-required 3-200 range
Pixabay rejects per_page outside 3-200 with HTTP 400. The stock_sources
adapter already clamped, but the PixabayVideo and PixabayImage tools
passed the value through raw, so callers using per_page < 3 got a 400.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
2026-07-02 09:31:11 +02:00
calesthio cf3edafff0 backlot phase 3 review fixes: SSE filtering, thumb race, replay robustness
- ChangeHub subscriptions filtered per project: unrelated-project bursts
  can no longer flood a board's queue and starve its own change signal
- thumbnail temp files unique per request (concurrent-miss race on the
  shared .tmp path corrupted the cache)
- watcher change-mapping is pure string work (no per-path resolve() in
  thousand-file change batches); 'C:'-style project ids rejected
- replay: tz-naive timestamps treated as UTC; final render/script no
  longer leak at t0 on storyboard-less projects; single tick chain on
  rapid pause/play; drag-safe scrubber (label tracks input, board renders
  on release); render-video playback survives SSE re-renders
- state: scene id 0 joins correctly, nested depth>0 events don't corrupt
  generating state, out-of-project asset paths honestly unserveable,
  negative durations clamped, tolerant manifest stage parse
- UI: decisions alt filter precedence fixed, activity counts parallel
  same-tool runs, el() html sink removed, NaN-safe formatters
2026-07-02 00:05:13 -07:00
calesthio 64e44612d9 backlot phase 3: in-browser replay, live-run fixes, simulation driver
- replay mode: scrub a completed run from checkpoint history + event
  timestamps — stage rail rewinds, script/storyboard/renders appear at
  their real moments, generating shimmer replays; ~20s full-run playback
- stage history_entries exposed in BoardState (powers replay + versions)
- entrance choreography plays on first paint only (not on SSE refreshes)
- live-run fixes found by driving a simulated production against the
  board: null rendered by native append, activity ticker showing closed
  starts as running, scene-id label handling for 'scene-N' ids
- scripts/backlot_simulate_run.py: drives a fake production through the
  REAL contract (init_project, in_progress heartbeats, gated
  awaiting_human -> approved, per-scene events, growing manifest) —
  live-board verification + demo driver
- backlot/README.md
2026-07-01 23:57:06 -07:00
calesthio 4b4d7b1e99 backlot phase 2: board UI (library, live board, filmstrip, script modal, drawers)
- vanilla ESM frontend on the mockup design system (no build step):
  library contact-sheet with mini rails + live badges; project board with
  slate header, cost meter, clickable stage rail, stage drawers (artifact
  view, review findings, gate-skipped chip, versions), screenplay card +
  full-script modal, decisions + activity rails, storyboard filmstrip
  (duration-width cards, shimmer/spec/missing/text-card states, takes,
  narration + waveform playback), render player with versions, degraded
  found-media view
- /thumb endpoint: cached downscaled JPEGs (Pillow) + ffmpeg poster-frame
  extraction for videos — the library was loading 73 full-res PNGs
- library summaries cached, invalidated by the watcher
- asset path resolution tolerates project-relative, repo-relative and
  absolute manifest paths (real-world variance found in why-do-we-dream)
- ?static=1 disables SSE (screenshots/static export)
- verified in browser against signal-from-tomorrow, why-do-we-dream,
  done-beats-perfect and the 73-project library
2026-07-01 23:47:45 -07:00
0xDevNinja 8c9af320b6 fix(video_compose): forward remotion_timeout_ms through high-level render path
The timeout handling only took effect on a direct _remotion_render() call. The
high-level execute(operation='render') path goes through _render(), which builds
a fresh remotion_inputs dict (edit_decisions, output_path, profile) and dropped
remotion_timeout_ms — so callers of the documented operation='render' path never
got the timeout passed to the Remotion CLI. Forward it there.

Adds a test exercising _render() (not just _remotion_render()) to cover the
high-level forwarding path.

Refs #217
2026-07-02 11:59:53 +05:30
0xDevNinja fbbe32a676 fix(video_compose): surface Remotion failures and add render timeout passthrough
The high-level Remotion render path hid the useful failure reason. run_command
runs with check=True + capture_output, so a non-zero exit raised
CalledProcessError whose str() is only 'returned non-zero exit status 1' — the
actual Remotion diagnostics in stderr were dropped. Catch CalledProcessError
and surface the stderr/stdout tail, and TimeoutExpired with an actionable hint.

Also add a creator-facing remotion_timeout_ms input, passed through as
Remotion's --timeout (headless-browser setup + delayRender). Slow browser
startup on restricted networks previously failed opaquely at the default 30s
with no way to raise it. The subprocess timeout is widened to match so
run_command does not kill Remotion before its own timeout fires.

Closes #217
2026-07-02 11:59:53 +05:30
calesthio c80ecbcb2d backlot phase 1: board server (state derivation, watcher, SSE, media, CLI)
- backlot/state.py: BoardState from disk — stage rail with gate audit
  (gate_skipped detection from history/), scene_plan x script x
  asset_manifest storyboard join, takes, generating-state from events,
  media discovery incl. atelier root-render heuristic, degradation ladder,
  library summaries
- backlot/server.py: FastAPI on 4750 — /api/projects, /api/project/{id}/state,
  SSE change feeds (project + library) fed by a watchfiles watcher,
  /media with range support and traversal protection, UI mounts
- backlot/__main__.py: 'python -m backlot open [project]' idempotent
  launcher (spawns detached server, opens browser); 'serve' foreground
- verified against real projects: 73 listed, full state for
  signal-from-tomorrow, 206 range responses, SSE change push on
  filesystem write
2026-07-01 23:26:30 -07:00
calesthio 514d0faf37 backlot phase 0 review fixes: fail-closed gates, atomic checkpoint writes, event attribution hardening
- gate = manifest OR caller (stricter wins); unknown pipeline_type now
  raises instead of silently disabling enforcement; corrupt manifest logs
  and falls back; misleading diagnostic fixed
- write_checkpoint backfills pipeline_type from project.json marker so
  omitting the kwarg can't bypass gates
- checkpoint writes are atomic (temp + os.replace); history archiving is
  copy-based and best-effort (Windows open-file safe)
- manifest loads cached (load_pipeline_readonly); stage gate lookup moved
  to pipeline_loader.get_stage_human_approval_default; PROJECTS_DIR unified
  in lib/paths.py
- events: containment + root-normalization for explicit project dirs, no
  ghost-project mkdir, 0.0 cost preserved, nested-call depth tag,
  wrapper simplified
- documentary-montage edit-director gate footer (was missed); AGENT_GUIDE
  no longer claims edit/compose always auto-proceed
2026-07-01 23:24:11 -07:00
calesthio 722491d732 backlot phase 0: artifact contract + gate hardening
- init_project() writes project.json marker + canonical workspace layout
- write_checkpoint enforces approval gates: completed on a gated stage
  requires human_approved=True (GATE VIOLATION otherwise)
- superseded checkpoints archived to projects/<id>/history/ (stage
  versioning, gate audit trail, replay)
- BaseTool auto-instruments execute() -> projects/<id>/events.jsonl
  (start/finish/error, scene_id, cost) for the Backlot live board
- assets stage now gates (human_approval_default: true) in all manifests
- checkpoint-protocol + AGENT_GUIDE: manifest gate value is binding,
  awaiting_human + end-turn protocol, per-gate approval, canonical
  checkpoint location fixed to projects/<id>/
- gate reminder footer on all gating stage director skills
- /backlot command files for Claude Code, Codex, Cursor, Copilot
2026-07-01 23:08:51 -07:00
Calesthio dc1cbca657
Merge pull request #256 from MoonCaves/fix-gpt-image-default
replace retired openai image models with gpt-image-2 (dall-e 3 is shut down too)
2026-07-01 23:02:07 -07:00
Remotely Human fabc0e7088 Replace retired OpenAI image models with gpt-image-2 (DALL-E shut down 2026-05-12)
- openai_image: enum narrowed to ["gpt-image-2"]; DALL-E code path, sizes
  (1024x1792/1792x1024) and qualities (standard/hd) removed; estimate_cost
  updated to real GPT Image 2 pricing ($0.006/$0.053/$0.211 at 1024x1024)
- image_gen (deprecated but callable): default dall-e-3 -> gpt-image-2; drop
  response_format="b64_json", which GPT image models reject; update pricing
- docs/skills sweep: scrub retired-model references from README (en/zh),
  .env.example, docs/PROVIDERS.md (incl. pricing table + deprecation note),
  docs/ARCHITECTURE.md, AGENT_GUIDE.md, skills/creative/*, 14 pipeline
  director skills, and tests/qa/QA_PLAN.md

Source: https://developers.openai.com/api/docs/deprecations

proofread by fable 5 + codex
2026-07-02 11:36:31 +08:00
MoonCaves 07739952a8 fix openai_image default (gpt-image-1 is retired, 400s now) 2026-07-02 02:07:29 +08:00
calesthio b3ff734b5a Add first-class Sora video provider 2026-07-01 10:51:48 -07:00
Yiyabo b4bed5735a dashscope: fix multi-image download and complete idempotency keys
Address PR #240 review feedback from @calesthio:

1. dashscope_image: save EVERY returned image URL, not just the first.
   The tool advertised multiple_outputs and accepted n>1 but only read
   content[0], silently dropping paid outputs. Now collects all image
   URLs across choices/content and downloads each to a distinct indexed
   path (foo.png -> foo_1.png, foo_2.png, ...). images_generated now
   reflects the actual count downloaded.

   Per Qwen Cloud docs, a multi-output task is SUCCEEDED if at least one
   image is generated; choices with finish_reason != "stop" are skipped
   to avoid downloading partial/failed results.

2. Complete idempotency_key_fields so different requests no longer
   collide and reuse stale artifacts:
   - image: + negative_prompt, seed, prompt_extend, watermark
   - tts:   + instructions
   - asr:   + enable_words, language_hints

Adds 19 regression tests (114 total, all pass, no API keys needed):
- TestDashscopeImageMultiOutput: URL extraction across choices / within
  one choice / failed-choice skipping, path resolution for
  single/multi/no-extension, end-to-end multi-image download with a
  mocked 3-URL DashScope response verifying all 3 files land on disk,
  single-image legacy path behavior
- TestDashscopeIdempotencyKeys: field presence + key-differs-on-value
  for every newly added field across all three tools
2026-07-02 00:37:51 +08:00
Calesthio 169124d0fd
Merge pull request #246 from calesthio/feat/ink-theater
feat: Ink Theater — hand-drawn doodle animation engine + mocap puppet + cross-agent commands
2026-07-01 06:36:11 -07:00
calesthio 7837bfee4a ink-theater: clear code-review findings — license-clean mocap + font, fix stale clip refs
Licensing (finding 1):
- Mocap library is now 100% CMU-sourced (free for any use). Replaced the 3
  Meta/FAIR clips with CMU equivalents: wave=141_16, shuffle=77_29 (creep);
  dropped the un-CMU "dab", added twist=141_12. Deleted the 4 committed FAIR
  BVHs (dab/jumping/wave_hello/zombie).
- Ship Patrick Hand's SIL OFL license (assets/OFL.txt) beside the bundled font
  — OFL permits embedding/redistribution; this is the required attribution.
- Add THIRD_PARTY_NOTICES.md (Patrick Hand OFL + CMU) and rewrite mocap/NOTE.md
  to drop the "verify before commercial use" caveat (no longer applicable).

Stale clip names (finding 2):
- Update the /ink-art command files (.claude/.github/.cursor/.codex),
  character-design-director, and the creative skills to the current catalog
  (wave/twist/…), and point to add-motion.mjs.
- ink-puppet.js: console.warn on an unknown clip name instead of silent dead-time.

Examples (finding 3):
- Remove broken standalone reel.html/momentum.html (they referenced a missing
  ink-theater.js and momentum shipped the subset font the fix warns against).
- Keep mocap-figure/ as the canonical self-contained, lintable example; refresh
  its bundled clips.js/ink-puppet.js; add examples/README.md with the lint path.
2026-07-01 04:03:19 -07:00
Calesthio 19ebce4b6b
Merge pull request #225 from xucailiang/fix/makefile-virtualenv-setup
Use virtualenv-aware Python commands in Makefile
2026-07-01 03:02:07 -07:00
calesthio a80bb6e7e1 feat: /animated-drawing character-source chooser (ask first; generate/upload/stock/doodle-ify)
Adds an explicit 'choose a character source' step so the agent never silently
reuses a bundled character (the 'same mascot every video' problem). Options:
user uploads a drawing; user uploads a photo -> doodle-ify (img2img) -> rig;
generate a fresh doodle (FLUX/Imagen, recommended default); or stock
(pixabay/pexels, hit-or-miss). Bundled chars are demo-only.
2026-07-01 02:52:44 -07:00
Justin caf1c96fe1 Merge branch 'main' of https://github.com/calesthio/OpenMontage into fix/makefile-virtualenv-setup 2026-07-01 13:50:04 +08:00
Justin fc91ee760d Use virtualenv-aware Python commands in Makefile 2026-07-01 13:48:26 +08:00
calesthio 0b9cde8458 feat: complete Ink Theater motion system — action library + self-extending converter + balloon primitive + audit doc fixes
Ships Phases 1-3 so the feature isn't left hanging:
- Phase 1: 12-action mocap library (walk/run/jump/climb/march/kick/sit/wave/dab/
  shuffle/dance_spin/dance_glide) from CMU + fair1, with mocap/catalog.json.
  Fixes the '4 repeated moves' repetition problem.
- Phase 2: bvh2clip.mjs is skeleton-agnostic (fair1/CMU/Mixamo joint aliases) +
  frame cap + --name; add-motion.mjs fetches/converts/rebundles any BVH by CMU
  id / URL / path — self-extending, no code changes.
- Phase 3: skill guidance to read catalog.json + choreograph variedly (never
  loop a clip), add-motion, and the balloon primitive.
- Engine: InkTheater.balloon() speech-balloon primitive (both audit videos
  hand-built it).
- Audit fixes: /animated-drawing skill gains a motion->retarget mapping table
  (2 motions crashed on the wrong config) + a 'Compositing into HyperFrames'
  section (transparent output, GIF-freezes->VP9-alpha, the linter video
  contract) + character-variety guidance (animate the user's/a generated
  drawing, not a bundled char) + pipeline-exempt notes.
Example refreshed to the new library + full Patrick Hand TTF.
2026-06-30 21:13:38 -07:00
Calesthio 1188e1bee9
Merge pull request #199 from An-idd/fix/video-compose-vertical-resolution
fix(video_compose): honor target resolution in FFmpeg compose (vertical/9:16)
2026-06-30 20:45:49 -07:00
Calesthio 1242f8459e
Merge pull request #227 from kapil971390/fix/character-reviewer-success-contract
fix(reviewer): success=False when CharacterAnimationReviewer finds QA issues
2026-06-30 20:40:30 -07:00
Calesthio 7b8d59186d
Merge pull request #223 from 0xDevNinja/feat/issue-168-music-library-preflight
feat(audio): add music_library tool so user tracks surface at preflight
2026-06-30 20:40:14 -07:00
calesthio 2a7f130bee fix: correct the font gotcha — subset trap, not SVG-vs-HTML; bundle Patrick Hand TTF
Audit finding from video production: handwriting rendered as serif everywhere
because the woff2 we downloaded was a Google-Fonts css2 subset MISSING basic-latin
(ASCII) glyphs — not because 'SVG text can't use webfonts' (the old README claim
was a misdiagnosis; prior demos were silently serif). Fix: embed the FULL font.
Bundles ink-theater/assets/patrickhand.ttf and corrects README + skill guidance
(HTML overlay divs + full TTF).
2026-06-30 20:40:12 -07:00
calesthio ccbce8bb1e feat: discoverability + cross-agent slash commands for Ink Theater / Animated Drawing
Makes the doodle-animation capability findable instead of hidden.

Routing (OpenMontage-internal):
- AGENT_GUIDE: Style Playbooks gets an ink-sketch row + a 'hand-drawn doodle'
  routing note (it's a style + engine on the animation / character-animation
  pipelines, NOT a new pipeline).
- animation/idea-director + character-animation/character-design-director point
  to the Ink Theater / Ink Puppet skills for hand-drawn character briefs.

Cross-agent slash commands (/ink-art, /animated-drawing) for Claude Code,
Copilot, Cursor, and Codex — thin pointers to the canonical skills so they stay
in sync. /ink-art = create a vector doodle from scratch (Ink Theater + Ink
Puppet mocap); /animated-drawing = animate a SUPPLIED drawing via Meta
AnimatedDrawings (raster). New skills/creative/animated-drawing.md documents the
Path A setup/run/limits. Codex prompts are user-home only — .codex/prompts/README
explains the copy/symlink step.

  .claude/commands/*.md            (Claude Code)
  .github/prompts/*.prompt.md      (Copilot)
  .cursor/commands/*.md            (Cursor)
  .codex/prompts/*.md + README     (Codex; copy to ~/.codex/prompts)
2026-06-30 20:13:48 -07:00
calesthio 389534af4a feat: Ink Puppet — real mocap (BVH) retargeted onto a hand-drawn figure
The agent-seamless character system: motion comes from a LIBRARY of real
motion-capture clips, never hand-tuned per video. Two parts:

- mocap/bvh2clip.mjs: offline BVH(3D) -> compact 2D clip converter (FK +
  projection + skeleton-rest scaling), run once per motion; bundled via clips.js.
- ink-puppet.js: runtime that draws a stick figure limb-by-limb (draw-on reveal)
  and plays named clips via a declarative choreograph() API. Deterministic /
  seek-safe (pose = pure fn of segment local time).

Example (examples/mocap-figure): the pencil figure draws itself, then waves /
dabs / jumps / walks from real mocap. Keeps vector white-ink + draw-on reveal
that Meta AnimatedDrawings (raster, humanoid-only, no reveal) cannot do.
Provenance/licensing: mocap/NOTE.md (prefer free CMU mocap for production).
2026-06-30 19:49:57 -07:00
calesthio 0aa986e61b feat: Ink Theater — deterministic hand-drawn moving-art engine + creative skill
Reusable engine (ink-theater/ink-theater.js, global InkTheater) for hand-drawn
ink-on-white animated 'moving art', authored for HyperFrames (atelier). Five
seek-safe primitives: variable-width brush strokes (inkPath/inkRibbon),
timeline-driven boil, closed-form damped-spring eases, FABRIK 2D IK + riggable
mascot, and a parametric contraption grammar (crank/gauge/hopper/slot/lever/box).

Adds skills/creative/ink-theater.md (metaphor method + mined archetypes + color
grammar) and README with the HyperFrames font gotcha (webfonts apply to HTML
divs, not SVG <text>). Two reference builds under ink-theater/examples/.

Grounded in deep-research on vector/physics/metaphor foundations (FABRIK,
bounded-biharmonic/ARAP, closed-form springs, LLM metaphor+layout planning).
2026-06-30 17:03:20 -07:00
kapil971390 5782f704b3
fix(character-reviewer): align success contract with visual_qa pattern
Per maintainer feedback on PR #227:
- Revert success=not issues back to success=True — tool execution
  succeeded even when QA finds issues; verdict lives in status/issues
- Update test to assert the real contract: success=True + status='revise'
  + issues non-empty, matching how compose-director actually gates
- Consistent with visual_qa.py: success=True, verdict in validation_passed
2026-06-30 22:23:52 +05:30
Yiyabo 05494030be dashscope: add provider documentation to docs/PROVIDERS.md 2026-06-30 15:24:06 +08:00
Yiyabo 7473d0d1bb dashscope: add contract tests (95 tests, no API calls needed) 2026-06-30 14:35:34 +08:00
Yiyabo f5cbe1011f dashscope: add Layer 3 skill documentation 2026-06-30 14:35:34 +08:00
Yiyabo 75c641ac44 dashscope: add ASR provider with word-level timestamps (qwen3-asr-flash-filetrans) 2026-06-30 14:35:34 +08:00
Yiyabo b836416ac2 dashscope: add TTS provider (qwen3-tts-flash) 2026-06-30 14:35:34 +08:00
Yiyabo 4528a0f6eb dashscope: add image generation provider (qwen-image-2.0-pro) 2026-06-30 14:35:34 +08:00
Yiyabo c8f30c2cf3 dashscope: add DASHSCOPE_API_KEY to .env.example 2026-06-30 14:35:33 +08:00