260930 Split Cli Examples
ASecurity```text $ vid2 example ls name, title, duration, needs, whether a workspace exists $ vid2 example show opus-astra-paper manifest: summary, techniques, needs, steps, output, README path $ cd "$(vid2 example new opus-astra-paper)" copy sources into $VID2_HOME/examples/opus-astra-paper, print the path $ vid2 example new vid2-intro --dir ./intro copy into ./intro instead $ vid2 example path opus-astra-paper workspace path (no side effects); --source prints the package
- 2 stars
- 0 votes
- 0 copies
- 0 views
- Added September 29, 2026
Works with
Security analysis
92/100- Installs packages at runtime which could introduce malicious dependencies
Pro scans all 6 files and shows the line behind each finding
npx -y skills add lidge-ai/vid2-gen --skill 260930_split_cli_examples --agent claude-codeAre you the author of 260930 Split Cli Examples?
Add the live security badge to your README. It updates with every re-scan.
[](https://www.skillsdirectory.com/skills/lidge-ai-260930-split-cli-examples)# 030 wp4: examples on demand — `vid2 example` and the vid2-examples skill
## Target behaviour
```text
$ vid2 example ls name, title, duration, needs, whether a workspace exists
$ vid2 example show opus-astra-paper manifest: summary, techniques, needs, steps, output, README path
$ cd "$(vid2 example new opus-astra-paper)" copy sources into $VID2_HOME/examples/opus-astra-paper, print the path
$ vid2 example new vid2-intro --dir ./intro copy into ./intro instead
$ vid2 example path opus-astra-paper workspace path (no side effects); --source prints the packaged folder
```
`new` keeps `examples/workspace.mjs` semantics: repository sources overwrite their workspace copies; `media/`, `out/`,
`.work/` and `*.vid2cap/` in the workspace are kept. In text mode `new` and `path` print only the path so `cd "$(...)"` works.
## Files
| Path | Change |
|---|---|
| `examples/<name>/example.json` | NEW for opus-astra-paper, claude-codex-dawn, ima2-launch, vid2-intro, vid2-launch, generated-video |
| `src/examples/manifest.ts` | NEW: zod `strictObject` schema + `readManifest(dir)` |
| `src/examples/catalog.ts` | NEW: `examplesRoot()` = `packageRoot()/examples`; `listExamples()` = folders with a manifest, sorted |
| `src/examples/workspace.ts` | NEW: `WORKSPACE_ONLY`, `workspaceRoot()`, `workspaceFor(name)`, `syncWorkspace(name, dest?)` moved from `examples/workspace.mjs:13-30` |
| `src/examples/index.ts` | NEW barrel |
| `examples/workspace.mjs` | MODIFY: thin wrapper importing `../src/examples/index.ts` (precedent `scripts/skills-lint.mjs:5`); CLI flags unchanged |
| `src/cli/commands/example.ts` | NEW: parent spec `example` (group author) with subcommands ls, show, new, path |
| `src/cli/registry.ts` | MODIFY: register `example` |
| `src/cli/output.ts` | MODIFY: text mode prints `data.path` alone for `example new` / `example path` |
| `package.json` `files` | MODIFY: add `"examples"`, `"!examples/*/media"`, `"!examples/*/out"`, `"!examples/*/.work"`, `"!examples/*/*.vid2cap"`, `"!examples/opencodex-*"`, `"!**/.DS_Store"` |
| `examples/*/README.md`, `examples/README.md` | MODIFY: first line of each build block becomes `cd "$(vid2 example new <name>)"`; README index gains a column for `vid2 example show`; repository users keep `node examples/workspace.mjs` (mentioned once in examples/README.md) |
| `skills/vid2-examples/SKILL.md` | NEW skill (below) |
| `skills/vid2/SKILL.md` | MODIFY: route "make a video like X / start from an example" to vid2-examples |
| `skills-manifest.json` | regenerated by `npm run build` (`scripts/skills-manifest.mjs`) |
| `.claude-plugin/plugin.json` | MODIFY (in 040): add `./skills/vid2-examples` |
| `tests/e2e/examples.test.ts` | MODIFY: manifest/README consistency tests (below) |
| `tests/e2e/pack.test.ts` | MODIFY: tarball ships every manifest, no excluded paths, example bytes ≤ 600 KB; the packed install runs `vid2 example ls` and `vid2 example new` |
| `structure/INDEX.md`, `AGENTS.md` | MODIFY: owner row for `src/examples/` |
| `structure/skills.md` | MODIFY: list vid2-examples |
## Manifest (src/examples/manifest.ts)
```ts
export const ExampleManifest = z.strictObject({
name: z.string().regex(/^[a-z0-9-]+$/), // must equal the folder name
title: z.string().min(1),
summary: z.string().min(1), // one sentence: what the film is
durationS: z.number().positive().optional(),
size: z.string().regex(/^\d+x\d+$/).optional(), // "1920x1080"
techniques: z.array(z.string().min(1)).min(1), // "stage nodes", "springs", "web capture", ...
goodFor: z.array(z.string().min(1)).min(1), // requests this example answers: "paper cutout short", ...
needs: z.array(z.strictObject({ tool: z.string(), optional: z.boolean().optional(), note: z.string().optional() })),
edit: z.array(z.strictObject({ file: z.string(), what: z.string() })).min(1), // where to change content for a new film
steps: z.array(z.strictObject({ run: z.string().min(1), note: z.string().optional() })).min(1),
output: z.string().min(1), // final video path relative to the workspace
});
```
`steps[].run` are the README's build-block lines after the `cd` line, verbatim and in order, without trailing `# comments`.
Example (opus-astra-paper, from its README build block):
```json
{ "name": "opus-astra-paper", "title": "Opus & Astra — a paper-cutout short", "durationS": 26, "size": "1920x1080",
"summary": "A 26 s paper-cutout short built only from JS stage nodes, with a music-box cue.",
"techniques": ["stage nodes", "spring pops", "squash and stretch", "procedural paper texture", "bar-aligned scenes"],
"goodFor": ["paper cutout or craft-style short", "character animation without images", "cute mascot story"],
"needs": [{ "tool": "ffmpeg" }, { "tool": "music2-gen", "optional": true, "note": "for the cue; drop the audio block without it" }],
"edit": [{ "file": "build-timeline.mjs", "what": "characters, scenes and timings" }, { "file": "music/gen-song.mjs", "what": "the cue" }],
"steps": [{ "run": "node make-paper.mjs media/paper.png" }, { "run": "node music/gen-song.mjs music/opus-astra.song.json" },
{ "run": "music2 render music/opus-astra.song.json -o media/music.wav" }, { "run": "node build-timeline.mjs" },
{ "run": "vid2 validate timeline.json" }, { "run": "vid2 preview timeline.json --at 1s,5s,12s,22s --out out/preview" },
{ "run": "vid2 render timeline.json --profile proxy -o out/proxy.mp4" }, { "run": "vid2 render timeline.json -o out/opus-astra-paper.mp4" },
{ "run": "vid2 qa out/opus-astra-paper.mp4 --timeline timeline.json --expect-audio --out out/qa" }],
"output": "out/opus-astra-paper.mp4" }
```
## Command (src/cli/commands/example.ts)
| Sub | Args / options | data |
|---|---|---|
| `ls` | none | `{ examples: [{name,title,summary,durationS,needs,workspace,ready}] , templates: listTemplates() }` |
| `show <name>` | none | manifest + `source`, `readme`, `workspace`, `ready` |
| `new <name>` | `--dir <path>` | `{ name, path, source, files, steps }`; artifacts `[path]` |
| `path <name>` | `--source` | `{ name, path }` |
Unknown name → `E_INPUT unknown example`, `details.examples`, `fix: "run vid2 example ls"`.
## Skill (skills/vid2-examples/SKILL.md)
Frontmatter description names the triggers ("make a video like", "example", "paper cutout", "launch film", "puppet", "keynote",
"start from a template"). Body: (1) a table mapping request shapes to an example or `vid2 init` template, using each
manifest's `goodFor`; (2) the fast route: `vid2 example show <name>` → `cd "$(vid2 example new <name>)"` → run the steps up to
the proxy render → edit the manifest's `edit` files for the new content → proxy, QA, final; (3) fallbacks: no music2 → drop the
audio block or use `vid2 audio synth`; no ima2 → `--placeholders` or the offline twin; missing logos/fonts in
claude-codex-dawn → substitute files at the paths its README names; (4) reuse notes per technique pointing at the example file
that implements it (key collector and seeded `rnd()` in opus-astra-paper, puppet helpers in claude-codex-dawn/puppets.mjs,
bar-synced cuts in ima2-launch, typed command and rolling number in vid2-intro). Every `vid2 X Y` mention passes the 020 lint.
## Tests
`tests/e2e/examples.test.ts` additions: every folder under `examples/` except `hello.json` has a valid manifest whose `name`
equals the folder; every `steps[].run` appears, in order, in the README's bash fence; every `vid2 ...` step resolves through
`resolveCommand`; every example has a row in `examples/README.md` and in `skills/vid2-examples/SKILL.md`; `main(["example",
"new", name, "--dir", tmp])` copies the sources and skips a pre-seeded `media/keep.txt` (activation of the WORKSPACE_ONLY filter:
seed `tmp/media/keep.txt` and `tmp/out/x.mp4`, sync, assert both still exist and the README was copied).
`tests/e2e/pack.test.ts`: an ungated check runs `npm pack --dry-run --json --ignore-scripts` and asserts every
`examples/*/example.json` is listed, nothing under `media/`, `out/`, `.work/`, `*.vid2cap/` or `.DS_Store` is, and example
bytes ≤ 600 KB (activation: create `examples/opus-astra-paper/media/probe.bin` for the duration of the test and assert it is
absent from the list). The gated packed-install test adds `vid2 example ls --json` and `vid2 example new vid2-intro --dir <tmp>`.
## Verifiers
`node --test tests/e2e/examples.test.ts`, `VID2_PACK_TEST=1 node --test tests/e2e/pack.test.ts`, `npm run skills:check`,
`npm run build` (regenerates skills-manifest.json), `npm test`, `npm run privacy:scan`.
## Architect dispositions
D9 accepted, plus `goodFor` and `edit` so the skill can map requests to examples and say which file to change. D10 accepted.
D11 amended: `new` prints the workspace path (so `cd "$(vid2 example new x)"` replaces `node examples/workspace.mjs x`),
`--dir` instead of a positional directory; `path` prints the workspace path, `--source` the packaged folder. D12 accepted.
D13 accepted. Open assumption 3: packaged READMEs move to `vid2 example new`; examples/README.md keeps one line for repository
users. Assumption 5: `scripts/privacy-scan.mjs` already scans tracked files, which include `examples/` (re-checked in B).
## Reflection folds (Feynman: ALIGNED with gaps, 2026-09-30)
These rules supersede the sections above where they differ.
- R4 (gap 4). Success `command` strings are `"example ls"`, `"example show"`, `"example new"`, `"example path"`. `path --source`
returns the folder in `data.path`, so `output.ts` special-cases `example new` and `example path` on `data.path` alone.
- R5 (gap 5). examples.test.ts asserts each example README's build block starts with `cd "$(vid2 example new <name>)"`.
- R6 (gap 6). The pack exclusion test does not touch the checkout. It copies `package.json` and `examples/` into a temp directory,
seeds `examples/opus-astra-paper/{media/probe.bin,out/x.mp4,.work/y}` and `.DS_Store` there, runs
`npm pack --dry-run --json --ignore-scripts` in the temp directory and asserts the seeded files are absent and every manifest is
present. A second assertion on the real repository compares `git ls-files examples` (minus `examples/workspace.mjs` if
excluded, and `hello.json`) with the packed list. That guards tracked files that an `examples/*/.gitignore` would otherwise
drop, such as `ima2-launch/timeline.json`, `generated-video/timeline.json` and `vid2-launch/code-page/demo-timeline.json`. If
npm drops them, B adds explicit `files` entries for them.
- R7 (gap 7). Checked: `scripts/privacy-scan.mjs` `refs()` reads `git ls-tree -r -z HEAD` (or `rev-list --objects <range>`), so
every tracked file, including `examples/`, is scanned.
- R8 (gap 8). Links from example READMEs to repository docs (`../../structure/*.md`) become
`https://github.com/lidge-ai/vid2-gen/blob/main/structure/*.md`, because the package and the workspace do not contain
`structure/`.
## Audit folds (Goodall round 1, 2026-09-30) — supersede the sections above
- A4. `syncWorkspace(name, dest?, opts?: { sourceRoot?: string })`. The filter test builds a fixture source
(`<tmp>/src/demo/{README.md,example.json,media/a,out/b,.work/c,x.vid2cap/d,.DS_Store}`), syncs it and asserts only README.md
and example.json arrive; a second sync into a destination seeded with `media/keep` asserts it survives.
- A5 + A6 (replace R6). `package.json` `files` adds `"!examples/workspace.mjs"` too: the wrapper imports `src/`, which is not
packed. The pack comparison uses `git ls-files examples` minus `**/.gitignore` (npm never packs nested .gitignore files) and
minus `examples/workspace.mjs`; `examples/hello.json` stays on both sides. The seeded-exclusion check runs in a temp copy as R6
describes.
- A9. `src/skill/install.test.ts` (lines 14, 15, 32, 46, 50) and `src/skill/manifest.test.ts:15` hardcode 6 skills; both derive
the count from the `skills/` directories instead.
- A11. `steps[]` = every line of every bash fence in the README, in order, with `cd ...` lines and trailing `# comments`
removed; blank lines skipped. `generated-video/README.md` gains `cd "$(vid2 example new generated-video)"`. R5 checks the first
line of the first bash fence.
- A12. `example ls` rows are `{name, title, summary, durationS, needs, workspace, ready}`: `workspace` is the workspace path and
`ready` is true when that directory exists. `show` returns the same two fields.
- A15 (round 2 Medium blocker). vid2-launch no longer reads the repository: its build block becomes
`cd "$(vid2 example new vid2-launch)"`, `vid2 init feature-demo .work/feature-demo --force`, then
`vid2 capture web --serve .work/feature-demo/site --steps app.steps.json --size 1280x720 --scale 1.5 --out app`; the `REPO`
line and the `$REPO/templates/...` path go away in the block and in the table. `vid2 init` ships `templates/feature-demo/site/`
in the package, so the step works from an npm install. R5 then holds for all six READMEs.
## wp4 P re-verification (2026-09-30, after wp3 D at 9daefb2)
- `example` is built with `parentCommand` from `src/cli/tree.ts` (020 A1); its four subcommands are leaf `CommandSpec`s with
`group` on the parent (`author`), a `value` name for every string option and at least one example each, which
`src/cli/help.test.ts` test 1 already enforces for every registered path.
- Adding `example` also updates: `structure/cli-contract.md` parent list, `ROOT_EXAMPLES` in `src/cli/globals.ts` (re-add
`vid2 example ls`), README command table (`init`, `example` row) and the CHANGELOG Unreleased section.
- Skill-count tests: `src/skill/install.test.ts:14,15,46,50` (`installed.length`, `changedCount > 6`, link-mode `changedCount 6`)
and `src/skill/manifest.test.ts:15` derive the count from `readdirSync(SKILLS_ROOT)` directories.
- The existing workspace test (`tests/e2e/examples.test.ts` "workspace.mjs copies sources ...") keeps running against the thin
wrapper and still covers destination preservation; A4's fixture-source test is added next to it.
- No design decision changes, so no architect call; the plan is re-audited by the A reviewer.
Files in this skill
- 000_plan.md
- 010_repo_split.md
- 020_cli_help_tree.md
- 030_example_command_skill.md
- 040_release.md
Attribution
Comments
Loading comments…
Newsletter
Get the weekly list of safe new skills, and the ones we pulled.