@slatesvideo/cli 0.1.0 → 0.4.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/README.md ADDED
@@ -0,0 +1,77 @@
1
+ # @slatesvideo/cli
2
+
3
+ The `slates` command for the [Slates](https://slates.video) AI video studio. Drive Slates from your terminal, or let Claude Code shell out to it instead of loading 64 tool schemas into context.
4
+
5
+ ## Install
6
+
7
+ ```bash
8
+ npm i -g @slatesvideo/cli
9
+ ```
10
+
11
+ Requires Node.js 18+ and the Slates desktop app ([slates.video](https://slates.video)).
12
+
13
+ ## Commands
14
+
15
+ | Command | What it does |
16
+ |---|---|
17
+ | `slates login` | Authorize this machine via magic link (or `--token slates_sk_...`) |
18
+ | `slates logout` | Clear the stored cloud token |
19
+ | `slates status` | Show connection state, account, and credit balance |
20
+ | `slates mcp` | Detect installed MCP clients and print the exact config for each; `--write` merges it into Claude Desktop / Cursor configs (with a `.bak` backup) |
21
+ | `slates install-skills` | Install the bundled agent skills into `.claude/skills/<name>/SKILL.md`; `--global` targets `~/.claude/skills` |
22
+ | `slates run <op>` | Invoke any Slates operation by id; `--list` shows all 64 |
23
+
24
+ ## Skills
25
+
26
+ 15 agent skills ship embedded in `@slatesvideo/shared`: workflow recipes (one-prompt film, direct-response ad, storyboard from script, character turnaround, edit-and-iterate, vision feedback loop), per-model prompting guides (Kling V3, Veo 3.1, Seedance 2.0, Nano Banana 2, FLUX.2 Max, Seedream 5 Lite, lip sync, motion transfer), and cost discipline.
27
+
28
+ `slates install-skills` writes each one to `.claude/skills/<skill-name>/SKILL.md` in your current project, which is the layout Claude Code's skill discovery requires. Use `--global` to install for every project. Restart Claude Code afterward, then ask: "what slates skills do you have?" to verify.
29
+
30
+ ## Using `slates run` (agent-driven)
31
+
32
+ ```bash
33
+ # List every operation
34
+ slates run --list
35
+
36
+ # Create a project
37
+ slates run slates_create_project --name "neon samurai"
38
+
39
+ # Estimate before generating (the cost-discipline skill makes agents do this)
40
+ slates run slates_estimate_generation_cost --model kling-v3-standard-5s
41
+
42
+ # Generate an image into a project
43
+ slates run slates_generate_image --projectId <uuid> --prompt "..." --resolution 1k --aspectRatio 16:9
44
+
45
+ # Kick off a video in the background, then poll it
46
+ slates run slates_generate_video --projectId <uuid> --model veo-3.1-fast --prompt "..." --aspectRatio 16:9 --duration 8 --background true --confirm true
47
+ slates run slates_get_generation_status --generationId <uuid>
48
+
49
+ # Assemble + export
50
+ slates run slates_add_clip_to_timeline --projectId <uuid> --assetId <uuid>
51
+ slates run slates_export_video --projectId <uuid> --outputPath "C:\\Videos\\ad.mp4"
52
+
53
+ # Structured output for scripting
54
+ slates run slates_get_credit_balance --json
55
+ ```
56
+
57
+ > The timeline, export, background-generation, edit-image, and image-reference ops need a Slates desktop on agent API v2 — if an op reports a version error, update Slates (Settings → Check for Updates) and retry.
58
+
59
+ Notes for agent use:
60
+
61
+ - Repeated flags or comma lists become arrays: `--ids a,b,c`.
62
+ - `--json` emits `{text, data, images}`. Image entries carry `mimeType` and byte count only, not the binary. Use the MCP server (`@slatesvideo/mcp-server`) when the agent needs to see generated images inline.
63
+ - Generation ops gate on missing `aspectRatio`/`resolution` and on cost over $0.50 (`confirm=true` required), so a scripted run cannot silently overspend.
64
+
65
+ ## First-time setup
66
+
67
+ 1. Install and open the Slates desktop app.
68
+ 2. **Settings → Agent Control → enter your email → Send link.** Click the emailed link.
69
+ 3. `slates status` should now show your account. (Alternative: `slates login`.)
70
+
71
+ Credentials live in `~/.slates/agent-connection.json`. No env vars.
72
+
73
+ ## Links
74
+
75
+ - Website: [slates.video](https://slates.video)
76
+ - Source: [github.com/EricDisero/slates-mcp](https://github.com/EricDisero/slates-mcp)
77
+ - Issues: [github.com/EricDisero/slates-mcp/issues](https://github.com/EricDisero/slates-mcp/issues)
@@ -1,5 +1,5 @@
1
1
  interface InstallSkillsOptions {
2
- force: boolean;
2
+ global?: boolean;
3
3
  }
4
4
  export declare function runInstallSkills(opts: InstallSkillsOptions): void;
5
5
  export {};
@@ -1,36 +1,83 @@
1
- import { join, dirname } from 'node:path';
2
- import { fileURLToPath } from 'node:url';
3
- import { existsSync, readdirSync, readFileSync, writeFileSync, mkdirSync, } from 'node:fs';
4
- // Copy bundled skill markdown files into ./.claude/skills/ in the user's
5
- // current working directory. Mirrors how Higgsfield ships its CLI: skills
6
- // are markdown recipes that compose the operation surface. They auto-
7
- // register with Claude Code skill discovery once they're on disk.
1
+ import { join } from 'node:path';
2
+ import { homedir } from 'node:os';
3
+ import { existsSync, readdirSync, writeFileSync, mkdirSync, rmSync, statSync, } from 'node:fs';
4
+ import { SKILLS } from '@slatesvideo/shared';
5
+ // Install the bundled skill markdown into Claude Code's skill directories.
6
+ //
7
+ // Skill content is embedded in @slatesvideo/shared (generated from
8
+ // packages/shared/skills/*.md at build time), so the install works no matter
9
+ // how the CLI was delivered — global npm install, npx, or a bundled binary.
10
+ //
11
+ // Claude Code discovers skills as DIRECTORIES: .claude/skills/<name>/SKILL.md.
12
+ // A loose .md file dropped straight into .claude/skills/ is silently never
13
+ // loaded. So each bundled skill is written to its own <name>/SKILL.md folder,
14
+ // where <name> comes from the skill's frontmatter `name:` field (falling back
15
+ // to the embedded key, the source filename sans .md). Discovery runs at
16
+ // session start — a restart of Claude Code is required before new skills
17
+ // appear.
18
+ function frontmatterName(markdown, fallback) {
19
+ if (!markdown.startsWith('---'))
20
+ return fallback;
21
+ const end = markdown.indexOf('\n---', 3);
22
+ if (end === -1)
23
+ return fallback;
24
+ const block = markdown.slice(3, end);
25
+ const m = block.match(/^name:\s*(.+?)\s*$/m);
26
+ return m ? m[1].trim() : fallback;
27
+ }
8
28
  export function runInstallSkills(opts) {
9
- const here = dirname(fileURLToPath(import.meta.url));
10
- // dist/commands walk up to package root, then look for /skills.
11
- const pkgRoot = join(here, '..', '..');
12
- const skillsRoot = join(pkgRoot, 'skills');
13
- if (!existsSync(skillsRoot)) {
14
- console.error(`Bundled skills not found at ${skillsRoot}`);
29
+ const skillEntries = Object.entries(SKILLS);
30
+ if (skillEntries.length === 0) {
31
+ console.error('No bundled skills found in @slatesvideo/shared — broken build?');
15
32
  process.exit(1);
16
33
  }
17
- const target = join(process.cwd(), '.claude', 'skills');
34
+ const target = opts.global
35
+ ? join(homedir(), '.claude', 'skills')
36
+ : join(process.cwd(), '.claude', 'skills');
18
37
  if (!existsSync(target))
19
38
  mkdirSync(target, { recursive: true });
20
- const files = readdirSync(skillsRoot).filter((f) => f.endsWith('.md'));
21
- let copied = 0;
22
- let skipped = 0;
23
- for (const file of files) {
24
- const dest = join(target, file);
25
- if (existsSync(dest) && !opts.force) {
26
- console.log(`skip ${file} (already exists, use --force to overwrite)`);
27
- skipped++;
28
- continue;
39
+ // Migrate away from the old broken layout: earlier versions of this
40
+ // command copied loose slates-*.md files flat into the skills root, where
41
+ // Claude Code never discovers them. Remove them — the same content is
42
+ // about to be written in the correct <name>/SKILL.md layout. EXACT
43
+ // filename match only (the embedded key + .md): a slates-* glob would
44
+ // also delete a user's own files (e.g. slates-notes.md).
45
+ const legacyFilenames = new Set(skillEntries.map(([key]) => `${key}.md`));
46
+ const stale = readdirSync(target).filter((f) => {
47
+ if (!legacyFilenames.has(f))
48
+ return false;
49
+ try {
50
+ return statSync(join(target, f)).isFile();
51
+ }
52
+ catch {
53
+ return false;
54
+ }
55
+ });
56
+ for (const f of stale)
57
+ rmSync(join(target, f));
58
+ if (stale.length > 0) {
59
+ console.log(`Removed ${stale.length} stale flat .md file(s) left by a previous install — ` +
60
+ `the old flat layout was never picked up by Claude Code. Reinstalling in the correct layout now.`);
61
+ }
62
+ let fresh = 0;
63
+ let updated = 0;
64
+ for (const [key, content] of skillEntries) {
65
+ const name = frontmatterName(content, key);
66
+ const dir = join(target, name);
67
+ const isUpdate = existsSync(dir);
68
+ mkdirSync(dir, { recursive: true });
69
+ writeFileSync(join(dir, 'SKILL.md'), content);
70
+ if (isUpdate) {
71
+ updated++;
72
+ console.log(`update ${name}`);
73
+ }
74
+ else {
75
+ fresh++;
76
+ console.log(`install ${name}`);
29
77
  }
30
- writeFileSync(dest, readFileSync(join(skillsRoot, file)));
31
- console.log(`write ${file}`);
32
- copied++;
33
78
  }
34
- console.log(`\nInstalled ${copied} skill(s), skipped ${skipped}, into ${target}`);
79
+ const total = fresh + updated;
80
+ console.log(`\nInstalled ${total} skill(s) (${fresh} new, ${updated} updated) into ${target}`);
81
+ console.log(`Restart Claude Code, then ask: 'what slates skills do you have?' to verify.`);
35
82
  }
36
83
  //# sourceMappingURL=install-skills.js.map
@@ -31,6 +31,12 @@ export async function runLogin(opts) {
31
31
  process.exit(1);
32
32
  }
33
33
  console.log(`\nA sign-in link is on its way to ${trimmed}.`);
34
+ // Newer slates-api versions return a short user code (e.g. XK4-P2N) that
35
+ // the authorization page asks the user to verify — anti-phishing pairing.
36
+ // Older servers omit the field; show nothing in that case.
37
+ if (reqBody.userCode) {
38
+ console.log(`Confirm this code on the authorization page: ${reqBody.userCode}`);
39
+ }
34
40
  console.log('Click the link, then return here. Waiting (10 min max)...\n');
35
41
  const start = Date.now();
36
42
  const timeoutMs = 10 * 60 * 1000;
@@ -0,0 +1,6 @@
1
+ interface McpOptions {
2
+ write?: boolean;
3
+ }
4
+ export declare function runMcp(opts: McpOptions): void;
5
+ export {};
6
+ //# sourceMappingURL=mcp.d.ts.map
@@ -0,0 +1,146 @@
1
+ import { join, delimiter } from 'node:path';
2
+ import { homedir, platform } from 'node:os';
3
+ import { existsSync, readFileSync, writeFileSync, copyFileSync } from 'node:fs';
4
+ // `slates mcp` — zero-to-configured MCP in one command.
5
+ //
6
+ // Detects installed MCP clients (Claude Code, Claude Desktop, Cursor) and
7
+ // prints the exact config for each one found. With --write, safely merges
8
+ // the "slates" mcpServers entry into Claude Desktop's and Cursor's config
9
+ // files (backing up the original to <file>.bak first). No interactive
10
+ // prompts — flags only.
11
+ const SLATES_ENTRY = {
12
+ command: 'npx',
13
+ args: ['-y', '@slatesvideo/mcp-server'],
14
+ };
15
+ const MCP_JSON_SNIPPET = JSON.stringify({ mcpServers: { slates: SLATES_ENTRY } }, null, 2);
16
+ function claudeDesktopConfigPath() {
17
+ const os = platform();
18
+ if (os === 'win32') {
19
+ const appData = process.env.APPDATA ?? join(homedir(), 'AppData', 'Roaming');
20
+ return join(appData, 'Claude', 'claude_desktop_config.json');
21
+ }
22
+ if (os === 'darwin') {
23
+ return join(homedir(), 'Library', 'Application Support', 'Claude', 'claude_desktop_config.json');
24
+ }
25
+ return join(homedir(), '.config', 'Claude', 'claude_desktop_config.json');
26
+ }
27
+ function cursorConfigPath() {
28
+ return join(homedir(), '.cursor', 'mcp.json');
29
+ }
30
+ function claudeBinaryOnPath() {
31
+ const pathVar = process.env.PATH ?? '';
32
+ const exts = platform() === 'win32' ? ['.cmd', '.exe', '.bat', ''] : [''];
33
+ for (const dir of pathVar.split(delimiter)) {
34
+ if (!dir)
35
+ continue;
36
+ for (const ext of exts) {
37
+ try {
38
+ if (existsSync(join(dir, `claude${ext}`)))
39
+ return true;
40
+ }
41
+ catch {
42
+ // Unreadable PATH entry — skip.
43
+ }
44
+ }
45
+ }
46
+ return false;
47
+ }
48
+ // Merge the "slates" key into an existing mcpServers JSON config file.
49
+ // Touches ONLY mcpServers.slates; everything else in the file is preserved.
50
+ // The original is backed up to <file>.bak before writing.
51
+ function mergeIntoConfig(file, label) {
52
+ let config = {};
53
+ try {
54
+ const text = readFileSync(file, 'utf8');
55
+ config = text.trim().length > 0 ? JSON.parse(text) : {};
56
+ }
57
+ catch (err) {
58
+ console.error(` Could not parse ${label} config at ${file}: ${err instanceof Error ? err.message : String(err)}`);
59
+ console.error(' Not writing — fix the JSON (or merge the snippet above by hand).');
60
+ return false;
61
+ }
62
+ copyFileSync(file, `${file}.bak`);
63
+ const servers = config.mcpServers && typeof config.mcpServers === 'object'
64
+ ? config.mcpServers
65
+ : {};
66
+ servers.slates = SLATES_ENTRY;
67
+ config.mcpServers = servers;
68
+ writeFileSync(file, JSON.stringify(config, null, 2) + '\n');
69
+ console.log(` Wrote "slates" into ${file} (backup at ${file}.bak)`);
70
+ return true;
71
+ }
72
+ function printClaudeCodeSection() {
73
+ console.log('\n── Claude Code ──');
74
+ console.log(' Run this in your terminal:');
75
+ console.log('\n claude mcp add slates -- npx -y @slatesvideo/mcp-server\n');
76
+ }
77
+ function printClaudeDesktopSection(file, detected) {
78
+ console.log('\n── Claude Desktop ──');
79
+ console.log(` Config file: ${file}${detected ? '' : ' (not found — create it)'}`);
80
+ console.log(' Merge this into the file (or run `slates mcp --write`):\n');
81
+ console.log(indent(MCP_JSON_SNIPPET, 4));
82
+ }
83
+ function printCursorSection(file, detected) {
84
+ console.log('\n── Cursor ──');
85
+ console.log(` Config file: ${file}${detected ? '' : ' (not found — create it)'}`);
86
+ console.log(' Merge this into the file (or run `slates mcp --write`):\n');
87
+ console.log(indent(MCP_JSON_SNIPPET, 4));
88
+ }
89
+ function indent(text, spaces) {
90
+ const pad = ' '.repeat(spaces);
91
+ return text
92
+ .split('\n')
93
+ .map((l) => pad + l)
94
+ .join('\n');
95
+ }
96
+ export function runMcp(opts) {
97
+ const desktopFile = claudeDesktopConfigPath();
98
+ const cursorFile = cursorConfigPath();
99
+ const hasClaudeCode = claudeBinaryOnPath();
100
+ const hasClaudeDesktop = existsSync(desktopFile);
101
+ const hasCursor = existsSync(cursorFile);
102
+ const anyDetected = hasClaudeCode || hasClaudeDesktop || hasCursor;
103
+ if (anyDetected) {
104
+ const found = [];
105
+ if (hasClaudeCode)
106
+ found.push('Claude Code');
107
+ if (hasClaudeDesktop)
108
+ found.push('Claude Desktop');
109
+ if (hasCursor)
110
+ found.push('Cursor');
111
+ console.log(`Detected: ${found.join(', ')}`);
112
+ }
113
+ else {
114
+ console.log('No MCP client detected — showing setup for all three.');
115
+ }
116
+ if (hasClaudeCode || !anyDetected)
117
+ printClaudeCodeSection();
118
+ if (hasClaudeDesktop || !anyDetected)
119
+ printClaudeDesktopSection(desktopFile, hasClaudeDesktop);
120
+ if (hasCursor || !anyDetected)
121
+ printCursorSection(cursorFile, hasCursor);
122
+ if (opts.write) {
123
+ console.log('\n── Writing configs ──');
124
+ let wrote = 0;
125
+ if (hasClaudeDesktop) {
126
+ if (mergeIntoConfig(desktopFile, 'Claude Desktop'))
127
+ wrote++;
128
+ }
129
+ if (hasCursor) {
130
+ if (mergeIntoConfig(cursorFile, 'Cursor'))
131
+ wrote++;
132
+ }
133
+ if (!hasClaudeDesktop && !hasCursor) {
134
+ console.log(' Nothing to write — no Claude Desktop or Cursor config file found.');
135
+ console.log(' (--write only edits existing config files; Claude Code uses the one-liner above.)');
136
+ }
137
+ else if (wrote > 0) {
138
+ console.log(' Restart the client(s) to pick up the new server.');
139
+ }
140
+ }
141
+ console.log('\n── Next steps ──');
142
+ console.log(' 1. Connect your account: open Slates → Settings → Agent Control → Send link');
143
+ console.log(' (or run `slates login`)');
144
+ console.log(' 2. Install the agent skills: `slates install-skills`');
145
+ }
146
+ //# sourceMappingURL=mcp.js.map
@@ -87,7 +87,7 @@ export async function runOp(opts) {
87
87
  console.log(result.text);
88
88
  if (result.images && result.images.length > 0) {
89
89
  console.log(`\nReturned ${result.images.length} inline image(s).`);
90
- console.log('(use --json to get the full payload, or use the MCP server for vision-aware tools)');
90
+ console.log('(--json reports image metadata only, not the bytes use the MCP server for vision-aware tools)');
91
91
  }
92
92
  }
93
93
  function coerceForSchema(schema, raw) {
@@ -97,19 +97,81 @@ function coerceForSchema(schema, raw) {
97
97
  const shape = typeof zodObj._def.shape === 'function'
98
98
  ? zodObj._def.shape()
99
99
  : zodObj.shape ?? {};
100
+ // Unwrap ZodOptional / ZodDefault / ZodNullable / ZodEffects / ZodReadonly
101
+ // to find the leaf type. `z.number().optional()` reports typeName
102
+ // 'ZodOptional' with `_def.innerType` pointing at the ZodNumber.
103
+ const wrappers = new Set([
104
+ 'ZodOptional',
105
+ 'ZodDefault',
106
+ 'ZodNullable',
107
+ 'ZodReadonly',
108
+ 'ZodEffects',
109
+ 'ZodCatch',
110
+ 'ZodBranded',
111
+ ]);
112
+ const unwrap = (t) => {
113
+ let cur = t;
114
+ let depth = 0;
115
+ while (cur?._def?.typeName && wrappers.has(cur._def.typeName) && depth < 8) {
116
+ cur = cur._def.innerType ?? cur._def.schema;
117
+ depth++;
118
+ }
119
+ return cur;
120
+ };
121
+ // Does the declared type allow null anywhere in its wrapper chain?
122
+ // (e.g. z.string().uuid().nullable() — so `--folderId null` → null.)
123
+ const isNullable = (t) => {
124
+ let cur = t;
125
+ let depth = 0;
126
+ while (cur?._def?.typeName && depth < 8) {
127
+ if (cur._def.typeName === 'ZodNullable')
128
+ return true;
129
+ if (wrappers.has(cur._def.typeName)) {
130
+ cur = cur._def.innerType ?? cur._def.schema;
131
+ depth++;
132
+ continue;
133
+ }
134
+ break;
135
+ }
136
+ return false;
137
+ };
138
+ const coerceScalar = (fieldType, value) => {
139
+ if (fieldType === 'ZodNumber') {
140
+ const n = Number(value);
141
+ return Number.isFinite(n) ? n : value;
142
+ }
143
+ if (fieldType === 'ZodBoolean')
144
+ return value === 'true' || value === '1';
145
+ return value;
146
+ };
100
147
  const out = {};
101
148
  for (const [key, value] of Object.entries(raw)) {
102
- const fieldType = (shape[key]?._def?.typeName ?? '');
149
+ const declared = shape[key];
150
+ const leaf = unwrap(declared);
151
+ const fieldType = (leaf?._def?.typeName ?? '');
152
+ // `--folderId null` (or a bare `--folderId` → true is NOT null) → JS null
153
+ // for fields that actually allow null. Enables "move to project root",
154
+ // "clear character turnaround", etc. from the CLI.
155
+ if (value === 'null' && isNullable(declared)) {
156
+ out[key] = null;
157
+ continue;
158
+ }
159
+ // Array fields: a single `--ids X` produced a bare string; repeated
160
+ // `--ids X --ids Y` produced an array. Accept either, plus comma-split
161
+ // (`--ids a,b,c`). Coerce each element to the array's element type.
162
+ if (fieldType === 'ZodArray') {
163
+ const elemType = (leaf?._def?.type?._def?.typeName ?? '');
164
+ const arr = Array.isArray(value)
165
+ ? value
166
+ : typeof value === 'string'
167
+ ? value.split(',').map((s) => s.trim()).filter((s) => s.length > 0)
168
+ : [value];
169
+ out[key] = arr.map((v) => (typeof v === 'string' ? coerceScalar(elemType, v) : v));
170
+ continue;
171
+ }
103
172
  if (typeof value === 'string') {
104
- if (fieldType === 'ZodNumber') {
105
- const n = Number(value);
106
- out[key] = Number.isFinite(n) ? n : value;
107
- continue;
108
- }
109
- if (fieldType === 'ZodBoolean') {
110
- out[key] = value === 'true' || value === '1';
111
- continue;
112
- }
173
+ out[key] = coerceScalar(fieldType, value);
174
+ continue;
113
175
  }
114
176
  out[key] = value;
115
177
  }
package/dist/index.js CHANGED
@@ -1,36 +1,42 @@
1
1
  #!/usr/bin/env node
2
2
  import { Command } from 'commander';
3
+ import { readFileSync } from 'node:fs';
4
+ import { join, dirname } from 'node:path';
5
+ import { fileURLToPath } from 'node:url';
3
6
  import { readConnection, setCloudToken, clearCloudToken } from '@slatesvideo/shared';
4
7
  import { runLogin } from './commands/login.js';
5
8
  import { runLogout } from './commands/logout.js';
6
9
  import { runStatus } from './commands/status.js';
7
10
  import { runOp } from './commands/op.js';
8
11
  import { runInstallSkills } from './commands/install-skills.js';
12
+ import { runMcp } from './commands/mcp.js';
9
13
  import { ALL_OPERATIONS } from '@slatesvideo/shared';
10
14
  // Slates CLI. The CLI mirrors the MCP tool surface as commands so Claude
11
- // Code can shell out to them and skip the cost of loading 20+ tool
12
- // schemas into its context window. Skills (in packages/skills) tell the
13
- // agent how to compose them.
15
+ // Code can shell out to them instead of loading every tool schema into
16
+ // its context window. Bundled skills (embedded in @slatesvideo/shared,
17
+ // installed via `slates install-skills`) tell the agent how to compose
18
+ // the operations into recipes.
14
19
  //
15
20
  // First-time use:
16
- // 1. Open Slates desktop → Settings → Agent Control → toggle on.
17
- // 2. Run `slates login` sends a magic link to your account email.
18
- // 3. Click the link in your email.
19
- // 4. The CLI auto-detects the connection and writes the cloud token
20
- // into ~/.slates/agent-connection.json. The desktop app's local
21
- // port + token are already there from step 1.
21
+ // 1. Open Slates desktop → Settings → Agent Control → Send link.
22
+ // 2. Click the link in your email (or run `slates login`).
23
+ // 3. The connection is written to ~/.slates/agent-connection.json —
24
+ // cloud token + the desktop app's local port + token.
22
25
  //
23
26
  // Inside Claude Code:
24
- // `/slates run slates_create_project --name "neon samurai"`
25
- // `/slates run slates_generate_image --prompt "..." --resolution 2k`
27
+ // slates run slates_create_project --name "neon samurai"
28
+ // slates run slates_generate_image --prompt "..." --resolution 1k --aspectRatio 16:9
26
29
  //
27
- // Or import @slatesvideo/skills/*.md into .claude/skills/ for higher-
28
- // level recipes.
30
+ // Run `slates install-skills` to copy the bundled skills into
31
+ // .claude/skills/<name>/SKILL.md for higher-level recipes.
32
+ // Version comes from this package's own package.json (dist/index.js → ../package.json)
33
+ // so the CLI never drifts from the published version.
34
+ const pkg = JSON.parse(readFileSync(join(dirname(fileURLToPath(import.meta.url)), '..', 'package.json'), 'utf8'));
29
35
  const program = new Command();
30
36
  program
31
37
  .name('slates')
32
38
  .description('Slates CLI — drive AI Video Creation Studio from your terminal.')
33
- .version('0.1.0')
39
+ .version(pkg.version)
34
40
  .enablePositionalOptions();
35
41
  program
36
42
  .command('login')
@@ -47,16 +53,21 @@ program
47
53
  .command('status')
48
54
  .description('Show the current Slates connection status.')
49
55
  .action(() => runStatus());
56
+ program
57
+ .command('mcp')
58
+ .description('Detect installed MCP clients and print (or write) the Slates MCP config for each.')
59
+ .option('--write', 'Merge the "slates" entry into detected Claude Desktop / Cursor config files (backs up to .bak first)', false)
60
+ .action((opts) => runMcp(opts));
50
61
  program
51
62
  .command('install-skills')
52
- .description('Copy the bundled skills into your local .claude/skills directory.')
53
- .option('--force', 'Overwrite existing skill files', false)
63
+ .description('Install the bundled skills into .claude/skills/<name>/SKILL.md (Claude Code layout).')
64
+ .option('--global', 'Install into ~/.claude/skills instead of the current project', false)
54
65
  .action((opts) => runInstallSkills(opts));
55
- const runCmd = program
66
+ program
56
67
  .command('run')
57
68
  .description('Invoke a Slates operation by id (use `slates run --list` to see them).')
58
69
  .option('--list', 'List all available operations', false)
59
- .option('--json', 'Emit raw JSON response instead of formatted text', false)
70
+ .option('--json', 'Emit structured JSON ({text, data, images: [{mimeType, bytes}]}). Image binary is omitted — use the MCP server for inline image payloads.', false)
60
71
  .allowUnknownOption()
61
72
  .passThroughOptions()
62
73
  .argument('[opId]', 'Operation id, e.g. slates_create_project')
@@ -99,6 +110,12 @@ program
99
110
  clearCloudToken();
100
111
  console.log('Cloud token cleared.');
101
112
  });
113
+ // Bare `slates` with no args: print help and exit 0 (commander's default
114
+ // help-on-missing-command exits 1, which reads as an error to scripts).
115
+ if (process.argv.length <= 2) {
116
+ program.outputHelp();
117
+ process.exit(0);
118
+ }
102
119
  program.parseAsync(process.argv).catch((err) => {
103
120
  console.error(err instanceof Error ? err.message : String(err));
104
121
  process.exit(1);
package/package.json CHANGED
@@ -1,23 +1,54 @@
1
1
  {
2
2
  "name": "@slatesvideo/cli",
3
- "version": "0.1.0",
4
- "description": "Slates CLI drive Slates from your terminal or Claude Code via shell-out.",
5
- "license": "UNLICENSED",
3
+ "version": "0.4.0",
4
+ "description": "Slates CLI: drive the Slates AI video studio from your terminal or let Claude Code shell out to it. Includes the bundled agent skills and an MCP client configurator.",
5
+ "license": "MIT",
6
6
  "type": "module",
7
7
  "bin": {
8
- "slates": "./dist/index.js"
8
+ "slates": "dist/index.js"
9
9
  },
10
10
  "main": "./dist/index.js",
11
- "files": ["dist", "skills", "README.md"],
11
+ "files": [
12
+ "dist",
13
+ "!dist/**/*.map",
14
+ "README.md"
15
+ ],
12
16
  "scripts": {
13
17
  "build": "tsc",
14
18
  "start": "node dist/index.js",
15
- "typecheck": "tsc --noEmit"
19
+ "typecheck": "tsc --noEmit",
20
+ "prepublishOnly": "npm run build"
21
+ },
22
+ "repository": {
23
+ "type": "git",
24
+ "url": "git+https://github.com/EricDisero/slates-mcp.git",
25
+ "directory": "packages/cli"
26
+ },
27
+ "homepage": "https://slates.video",
28
+ "bugs": {
29
+ "url": "https://github.com/EricDisero/slates-mcp/issues"
30
+ },
31
+ "keywords": [
32
+ "slates",
33
+ "cli",
34
+ "mcp",
35
+ "model-context-protocol",
36
+ "ai-video",
37
+ "video-generation",
38
+ "image-generation",
39
+ "claude",
40
+ "claude-code",
41
+ "agent-skills",
42
+ "veo",
43
+ "kling",
44
+ "seedance"
45
+ ],
46
+ "engines": {
47
+ "node": ">=18"
16
48
  },
17
49
  "dependencies": {
18
- "@slatesvideo/shared": "0.1.0",
50
+ "@slatesvideo/shared": "0.4.0",
19
51
  "commander": "^12.1.0",
20
- "open": "^10.0.0",
21
52
  "zod": "^3.23.0"
22
53
  },
23
54
  "devDependencies": {
@@ -1 +0,0 @@
1
- {"version":3,"file":"install-skills.d.ts","sourceRoot":"","sources":["../../src/commands/install-skills.ts"],"names":[],"mappings":"AAUA,UAAU,oBAAoB;IAC5B,KAAK,EAAE,OAAO,CAAA;CACf;AAOD,wBAAgB,gBAAgB,CAAC,IAAI,EAAE,oBAAoB,GAAG,IAAI,CA8BjE"}
@@ -1 +0,0 @@
1
- {"version":3,"file":"install-skills.js","sourceRoot":"","sources":["../../src/commands/install-skills.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,IAAI,EAAE,OAAO,EAAE,MAAM,WAAW,CAAA;AACzC,OAAO,EAAE,aAAa,EAAE,MAAM,UAAU,CAAA;AACxC,OAAO,EACL,UAAU,EACV,WAAW,EACX,YAAY,EACZ,aAAa,EACb,SAAS,GACV,MAAM,SAAS,CAAA;AAMhB,yEAAyE;AACzE,0EAA0E;AAC1E,sEAAsE;AACtE,kEAAkE;AAElE,MAAM,UAAU,gBAAgB,CAAC,IAA0B;IACzD,MAAM,IAAI,GAAG,OAAO,CAAC,aAAa,CAAC,MAAM,CAAC,IAAI,CAAC,GAAG,CAAC,CAAC,CAAA;IACpD,kEAAkE;IAClE,MAAM,OAAO,GAAG,IAAI,CAAC,IAAI,EAAE,IAAI,EAAE,IAAI,CAAC,CAAA;IACtC,MAAM,UAAU,GAAG,IAAI,CAAC,OAAO,EAAE,QAAQ,CAAC,CAAA;IAE1C,IAAI,CAAC,UAAU,CAAC,UAAU,CAAC,EAAE,CAAC;QAC5B,OAAO,CAAC,KAAK,CAAC,+BAA+B,UAAU,EAAE,CAAC,CAAA;QAC1D,OAAO,CAAC,IAAI,CAAC,CAAC,CAAC,CAAA;IACjB,CAAC;IAED,MAAM,MAAM,GAAG,IAAI,CAAC,OAAO,CAAC,GAAG,EAAE,EAAE,SAAS,EAAE,QAAQ,CAAC,CAAA;IACvD,IAAI,CAAC,UAAU,CAAC,MAAM,CAAC;QAAE,SAAS,CAAC,MAAM,EAAE,EAAE,SAAS,EAAE,IAAI,EAAE,CAAC,CAAA;IAE/D,MAAM,KAAK,GAAG,WAAW,CAAC,UAAU,CAAC,CAAC,MAAM,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,QAAQ,CAAC,KAAK,CAAC,CAAC,CAAA;IACtE,IAAI,MAAM,GAAG,CAAC,CAAA;IACd,IAAI,OAAO,GAAG,CAAC,CAAA;IACf,KAAK,MAAM,IAAI,IAAI,KAAK,EAAE,CAAC;QACzB,MAAM,IAAI,GAAG,IAAI,CAAC,MAAM,EAAE,IAAI,CAAC,CAAA;QAC/B,IAAI,UAAU,CAAC,IAAI,CAAC,IAAI,CAAC,IAAI,CAAC,KAAK,EAAE,CAAC;YACpC,OAAO,CAAC,GAAG,CAAC,UAAU,IAAI,6CAA6C,CAAC,CAAA;YACxE,OAAO,EAAE,CAAA;YACT,SAAQ;QACV,CAAC;QACD,aAAa,CAAC,IAAI,EAAE,YAAY,CAAC,IAAI,CAAC,UAAU,EAAE,IAAI,CAAC,CAAC,CAAC,CAAA;QACzD,OAAO,CAAC,GAAG,CAAC,UAAU,IAAI,EAAE,CAAC,CAAA;QAC7B,MAAM,EAAE,CAAA;IACV,CAAC;IAED,OAAO,CAAC,GAAG,CAAC,eAAe,MAAM,sBAAsB,OAAO,UAAU,MAAM,EAAE,CAAC,CAAA;AACnF,CAAC"}
@@ -1 +0,0 @@
1
- {"version":3,"file":"login.d.ts","sourceRoot":"","sources":["../../src/commands/login.ts"],"names":[],"mappings":"AAKA,MAAM,WAAW,YAAY;IAC3B,KAAK,CAAC,EAAE,MAAM,CAAA;IACd,UAAU,CAAC,EAAE,MAAM,CAAA;IACnB,KAAK,CAAC,EAAE,MAAM,CAAA;CACf;AAED,wBAAsB,QAAQ,CAAC,IAAI,EAAE,YAAY,GAAG,OAAO,CAAC,IAAI,CAAC,CAiEhE"}
@@ -1 +0,0 @@
1
- {"version":3,"file":"login.js","sourceRoot":"","sources":["../../src/commands/login.ts"],"names":[],"mappings":"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"}
@@ -1 +0,0 @@
1
- {"version":3,"file":"logout.d.ts","sourceRoot":"","sources":["../../src/commands/logout.ts"],"names":[],"mappings":"AAEA,wBAAgB,SAAS,IAAI,IAAI,CAGhC"}
@@ -1 +0,0 @@
1
- {"version":3,"file":"logout.js","sourceRoot":"","sources":["../../src/commands/logout.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,eAAe,EAAE,MAAM,qBAAqB,CAAA;AAErD,MAAM,UAAU,SAAS;IACvB,eAAe,EAAE,CAAA;IACjB,OAAO,CAAC,GAAG,CAAC,sBAAsB,CAAC,CAAA;AACrC,CAAC"}
@@ -1 +0,0 @@
1
- {"version":3,"file":"op.d.ts","sourceRoot":"","sources":["../../src/commands/op.ts"],"names":[],"mappings":"AAEA,UAAU,YAAY;IACpB,IAAI,EAAE,MAAM,CAAA;IACZ,OAAO,EAAE,MAAM,EAAE,CAAA;IACjB,IAAI,EAAE,OAAO,CAAA;CACd;AAsDD,wBAAsB,KAAK,CAAC,IAAI,EAAE,YAAY,GAAG,OAAO,CAAC,IAAI,CAAC,CA+C7D"}
@@ -1 +0,0 @@
1
- {"version":3,"file":"op.js","sourceRoot":"","sources":["../../src/commands/op.ts"],"names":[],"mappings":"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"}
@@ -1 +0,0 @@
1
- {"version":3,"file":"status.d.ts","sourceRoot":"","sources":["../../src/commands/status.ts"],"names":[],"mappings":"AAGA,wBAAsB,SAAS,IAAI,OAAO,CAAC,IAAI,CAAC,CAmC/C"}
@@ -1 +0,0 @@
1
- {"version":3,"file":"status.js","sourceRoot":"","sources":["../../src/commands/status.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,cAAc,EAAE,iBAAiB,EAAE,mBAAmB,EAAE,MAAM,qBAAqB,CAAA;AAG5F,MAAM,CAAC,KAAK,UAAU,SAAS;IAC7B,MAAM,CAAC,GAAG,cAAc,EAAE,CAAA;IAC1B,OAAO,CAAC,GAAG,CAAC,kCAAkC,CAAC,CAAA;IAC/C,OAAO,CAAC,GAAG,CAAC,sBAAsB,CAAC,CAAC,KAAK,CAAC,KAAK,CAAC,CAAC,CAAC,SAAS,CAAC,CAAC,CAAC,8BAA8B,EAAE,CAAC,CAAA;IAC/F,OAAO,CAAC,GAAG,CACT,sBACE,CAAC,CAAC,OAAO,CAAC,OAAO;QACf,CAAC,CAAC,wBAAwB,CAAC,CAAC,OAAO,CAAC,IAAI,EAAE;QAC1C,CAAC,CAAC,mDACN,EAAE,CACH,CAAA;IAED,IAAI,CAAC,CAAC,KAAK,CAAC,KAAK,EAAE,CAAC;QAClB,IAAI,CAAC;YACH,MAAM,KAAK,GAAG,IAAI,iBAAiB,EAAE,CAAA;YACrC,MAAM,EAAE,GAAG,MAAM,KAAK,CAAC,GAAG,CAAiB,eAAe,CAAC,CAAA;YAC3D,OAAO,CAAC,GAAG,CAAC,wBAAwB,EAAE,CAAC,IAAI,CAAC,KAAK,EAAE,CAAC,CAAA;YACpD,OAAO,CAAC,GAAG,CAAC,sBAAsB,EAAE,CAAC,IAAI,CAAC,cAAc,EAAE,CAAC,CAAA;YAC3D,OAAO,CAAC,GAAG,CAAC,sBAAsB,EAAE,CAAC,IAAI,CAAC,IAAI,EAAE,CAAC,CAAA;YACjD,OAAO,CAAC,GAAG,CAAC,uBAAuB,EAAE,CAAC,IAAI,CAAC,sBAAsB,EAAE,CAAC,CAAA;YACpE,OAAO,CAAC,GAAG,CAAC,sBAAsB,EAAE,CAAC,MAAM,CAAC,IAAI,CAAC,IAAI,CAAC,EAAE,CAAC,CAAA;QAC3D,CAAC;QAAC,OAAO,GAAG,EAAE,CAAC;YACb,OAAO,CAAC,IAAI,CAAC,yBAAyB,GAAG,YAAY,KAAK,CAAC,CAAC,CAAC,GAAG,CAAC,OAAO,CAAC,CAAC,CAAC,MAAM,CAAC,GAAG,CAAC,EAAE,CAAC,CAAA;QAC3F,CAAC;IACH,CAAC;IAED,IAAI,CAAC,CAAC,OAAO,CAAC,OAAO,IAAI,CAAC,CAAC,OAAO,CAAC,IAAI,IAAI,CAAC,CAAC,OAAO,CAAC,KAAK,EAAE,CAAC;QAC3D,IAAI,CAAC;YACH,MAAM,OAAO,GAAG,IAAI,mBAAmB,EAAE,CAAA;YACzC,MAAM,CAAC,GAAG,MAAM,OAAO,CAAC,OAAO,EAAE,CAAA;YACjC,OAAO,CAAC,GAAG,CAAC,wBAAwB,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC,KAAK,CAAC,CAAC,CAAC,IAAI,EAAE,CAAC,CAAA;QAC5D,CAAC;QAAC,OAAO,GAAG,EAAE,CAAC;YACb,OAAO,CAAC,IAAI,CAAC,0BAA0B,GAAG,YAAY,KAAK,CAAC,CAAC,CAAC,GAAG,CAAC,OAAO,CAAC,CAAC,CAAC,GAAG,GAAG,CAAC,CAAA;QACrF,CAAC;IACH,CAAC;AACH,CAAC"}
@@ -1 +0,0 @@
1
- {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":""}
package/dist/index.js.map DELETED
@@ -1 +0,0 @@
1
- {"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"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"}
@@ -1 +0,0 @@
1
- {"version":3,"file":"prompt.d.ts","sourceRoot":"","sources":["../../src/util/prompt.ts"],"names":[],"mappings":"AAEA,wBAAgB,WAAW,CAAC,QAAQ,EAAE,MAAM,GAAG,OAAO,CAAC,MAAM,CAAC,CAQ7D"}
@@ -1 +0,0 @@
1
- {"version":3,"file":"prompt.js","sourceRoot":"","sources":["../../src/util/prompt.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,eAAe,EAAE,MAAM,eAAe,CAAA;AAE/C,MAAM,UAAU,WAAW,CAAC,QAAgB;IAC1C,OAAO,IAAI,OAAO,CAAC,CAAC,OAAO,EAAE,EAAE;QAC7B,MAAM,EAAE,GAAG,eAAe,CAAC,EAAE,KAAK,EAAE,OAAO,CAAC,KAAK,EAAE,MAAM,EAAE,OAAO,CAAC,MAAM,EAAE,CAAC,CAAA;QAC5E,EAAE,CAAC,QAAQ,CAAC,QAAQ,EAAE,CAAC,MAAM,EAAE,EAAE;YAC/B,EAAE,CAAC,KAAK,EAAE,CAAA;YACV,OAAO,CAAC,MAAM,CAAC,CAAA;QACjB,CAAC,CAAC,CAAA;IACJ,CAAC,CAAC,CAAA;AACJ,CAAC"}
@@ -1,53 +0,0 @@
1
- ---
2
- name: slates-character-turnaround
3
- description: Build a Slates character from a reference image — generate the turnaround sheet and expression sheet, bind both to the character's slots so the user sees the character card update live. Use when the user wants to "create a character", "build a character from this image", "generate a turnaround for X", or starts any storyboard-flow that needs consistent character references.
4
- ---
5
-
6
- # Character turnaround — Slates workflow
7
-
8
- Slates stores characters with two image slots: turnaround (full-body multi-angle) and expression sheet (face emotions). The whole storyboard generation pipeline pulls these via `@character` mentions for visual consistency. Building them well = consistent character across every frame.
9
-
10
- ## Workflow
11
-
12
- ### 1. Get the reference
13
- The user has either:
14
- - Pasted/uploaded an image of the character (real person, drawing, AI render).
15
- - Described the character in text only.
16
-
17
- If image: upload it as a reference (`slates_upload_reference_image`).
18
- If text only: skip step 2 and generate the turnaround from prompt-only (less consistent — warn the user).
19
-
20
- ### 2. Create the character record
21
- `slates_create_character` with:
22
- - `name` (ask if not given)
23
- - `style` — match the project's overall style (`realistic`, `anime`, `pixar`, `comic-book`).
24
- - `description` — 1-2 sentences, *visual* only ("tall, dark hair, scar over left eye"), not personality.
25
-
26
- ### 3. Generate the turnaround sheet
27
- - Use `slates_generate_image` with a prompt like:
28
- > "Character turnaround sheet: 5 angles (front, 3/4 left, profile left, 3/4 right, back). Neutral pose. Even studio lighting. White background. {character description}"
29
- - Pass the reference image URL/ID as a reference.
30
- - Resolution: **2k** (default). 4k only if the user specifies.
31
- - Estimate cost first.
32
-
33
- When the result returns inline:
34
- - Evaluate against the reference. Is it the same character?
35
- - If wrong angle count / inconsistent: refine prompt with explicit angle list, regenerate once.
36
- - When right: bind via `slates_set_character_turnaround_asset` (the user sees the character card update).
37
-
38
- ### 4. Generate the expression sheet
39
- - Prompt:
40
- > "Expression sheet: 6 expressions (neutral, happy, angry, sad, surprised, determined). Same character, same lighting as the turnaround. {character description}"
41
- - Pass BOTH the original reference AND the just-generated turnaround as references for max consistency.
42
- - Same model, same resolution.
43
- - On success bind via `slates_set_character_expression_asset`.
44
-
45
- ### 5. Hand back
46
- > "Character {name} ready. Turnaround + expressions bound. Use `@{name}` in any prompt to attach these references."
47
-
48
- ## Anti-patterns
49
-
50
- - **Don't** generate turnaround and expressions in one prompt. Slates expects them as two separate assets in two separate slots.
51
- - **Don't** skip binding. The slots are what the storyboard pipeline reads — an unbound asset doesn't help downstream.
52
- - **Don't** invent character details. Stick to what's in the reference image and the user's description.
53
- - **Don't** use 4k unless asked — wastes credits, no quality gain at sheet scale.
@@ -1,62 +0,0 @@
1
- ---
2
- name: slates-direct-response-ad
3
- description: Build a 30-second hyper-motion direct-response ad in Slates from a product image and brief. Composes upload → storyboard → frame gen → motion gen → timeline → export. Use when the user drops a product image and asks for "an ad", "a promo video", "a TikTok ad", "an Instagram ad", a launch video, or any short-form direct-response video built around a product.
4
- ---
5
-
6
- # Direct-response ad — Slates workflow
7
-
8
- You are building a 30-second hyper-motion direct-response ad. The user has handed you a product image (or product URL) and a short brief. Slates desktop is open on the second monitor; the user watches it populate as you work.
9
-
10
- **Hard rules**
11
-
12
- - Always estimate cost before generating. Use `slates_estimate_generation_cost` and surface the total.
13
- - All MCP/CLI generation routes through Slates Credits, period. BYOK is desktop-UI only by design — don't suggest "use your own keys" workarounds.
14
- - Default model: `nano-banana-2-2k`. For close-up product hero frames step up to `4k` only if the user asks.
15
- - Hyper-motion = punchy cuts, 4 frames in 30 seconds, ~7s each. Don't over-storyboard.
16
-
17
- ## Workflow
18
-
19
- ### 1. Set up the project
20
- - Create a project named for the product (`slates_create_project`).
21
- - If the user gave a product image as a file path, upload it (`slates_upload_reference_image`).
22
- - If they pasted base64 / a data URL, use the same op with `dataUrl`.
23
-
24
- ### 2. Generate the storyboard frames
25
- Build exactly 4 frames in this order:
26
-
27
- | # | Beat | Visual goal |
28
- |---|------|-------------|
29
- | 1 | Hook | Hyper-close-up of the product, dramatic light, motion blur edge |
30
- | 2 | Lifestyle | Real person using/wearing/holding the product, eye contact |
31
- | 3 | Problem→solution | The before/after moment that justifies the buy |
32
- | 4 | CTA | Clean product hero with mental room for an overlaid CTA in editing |
33
-
34
- For each frame:
35
- 1. Draft a tight 1-2 sentence prompt (visual only — no copy text in the image).
36
- 2. Reference the product upload's URL or asset ID for visual fidelity.
37
- 3. Call `slates_generate_image` with that prompt + reference. **You see the result inline — evaluate it.**
38
- 4. If it's wrong: refine prompt, regenerate. If it's right: bind it as a frame in the storyboard (`slates_add_frame`).
39
-
40
- ### 3. Build the storyboard
41
- - `slates_create_storyboard` named "30s ad — v1".
42
- - Default scene already exists. Add 3 more scenes ("Hook", "Lifestyle", "Problem-Solution", "CTA") via `slates_add_scene`, or just add all 4 frames to the default scene.
43
- - For each generated image, add a frame referencing the asset id (`slates_add_frame`).
44
-
45
- ### 4. Hand back to the user
46
- - Surface estimated total credits spent.
47
- - Tell the user the storyboard is ready and they can either:
48
- - **In Slates desktop:** click each frame to generate motion (the existing UI handles motion generation).
49
- - **Continue here:** ask you to keep going.
50
-
51
- If they say keep going, generate motion for each frame using the highest-confidence model the budget allows (Veo 3.1 Fast 8s by default). Then call the export op.
52
-
53
- ## Anti-patterns
54
-
55
- - **Don't** generate text overlays in the image. Slates renders captions/CTAs at the editor stage.
56
- - **Don't** burn credits on slot-machine prompting. If the first generation is off, refine the prompt; don't just regenerate.
57
- - **Don't** skip the cost estimate. Confirm with the user above $0.50.
58
- - **Don't** invent visual specifics about the product (colors, textures, angles) that aren't in the reference image. Reference-anchored prompts only.
59
-
60
- ## Voice
61
-
62
- The ad lives or dies on the hook frame. Tight, sensory, no fluff. Match the user's brand. Default tone is "scroll-stopping" not "informative."
@@ -1,46 +0,0 @@
1
- ---
2
- name: slates-edit-and-iterate
3
- description: Iterate on an existing Slates asset — re-evaluate, refine prompt, regenerate or edit. Use when the user has an existing generated image in Slates and wants to "tweak it", "change one thing", "make it warmer", "remove the second person", or any other surgical refinement instead of full regeneration.
4
- ---
5
-
6
- # Edit and iterate — Slates workflow
7
-
8
- The user already has a generated image in Slates and wants to refine it. The vision-feedback-loop skill defines the general pattern; this skill is the specific recipe for "I have asset X, here's what's wrong with it."
9
-
10
- ## Workflow
11
-
12
- ### 1. Pull the current asset back into context
13
- - The user references an asset by id, frame number, or "the latest one."
14
- - Resolve to an asset id (`slates_list_assets` if needed).
15
- - `slates_get_asset_image` with that id to load it inline. **You see the image.**
16
-
17
- ### 2. Identify the delta
18
- The user's request is one of:
19
- - **Surgical** — "remove the second figure", "make the sword red", "swap the background to a bamboo forest".
20
- - **Aesthetic** — "warmer light", "more dramatic", "softer focus".
21
- - **Compositional** — "wider shot", "lower angle", "centered subject".
22
- - **Wholesale** — "actually let's try a totally different look."
23
-
24
- ### 3. Pick the right tool
25
- | Delta type | Approach |
26
- |---|---|
27
- | Surgical | `slates_edit_image` with a focused edit prompt + the original as the source. |
28
- | Aesthetic / compositional | `slates_generate_image` with the original as a reference + a refined prompt. Don't re-roll from scratch. |
29
- | Wholesale | New prompt, no reference, fresh generation. Treat as a new brief. |
30
-
31
- ### 4. Generate, evaluate, decide
32
- - Estimate cost first.
33
- - After generation, the result is inline. Compare side-by-side with the original (`slates_get_asset_image` again).
34
- - If the delta is correct: bind to the same slot (frame, character turnaround, etc.) the original was bound to.
35
- - If the delta missed: one focused refinement, then regenerate. Cap at 3 tries.
36
-
37
- ### 5. Hand back
38
- - "Asset updated. Frame 3 now uses {new_asset_id}."
39
- - Always note what changed and what didn't, so the user can see the surgery worked: "Lighting shifted to warmer, composition unchanged."
40
-
41
- ## Anti-patterns
42
-
43
- - **Don't** delete the original asset until the user confirms the new one. Slates keeps both; the user picks.
44
- - **Don't** mix surgical and wholesale changes in one regeneration. The user said "make it warmer" — don't also reframe the shot.
45
- - **Don't** re-generate when `edit_image` would work. Edits preserve composition and identity; full regen rolls the dice.
46
- - **Don't** chain >3 iterations without checking in. If three tries didn't land, the brief is wrong, not the model.
@@ -1,49 +0,0 @@
1
- ---
2
- name: slates-storyboard-from-script
3
- description: Turn a script or treatment into a Slates storyboard with scenes and frames. Use when the user has a script, treatment, shot list, or scene-by-scene description and wants to materialize it as a Slates storyboard, optionally generating frame images per shot.
4
- ---
5
-
6
- # Storyboard from script — Slates workflow
7
-
8
- The user has a script, treatment, or shot list. You're turning it into a Slates storyboard with scene → frame structure, optionally generating images for each frame.
9
-
10
- ## Workflow
11
-
12
- ### 1. Parse the script
13
- Read the user's script. Decide:
14
-
15
- - **Scene count** — usually 1 scene per location/setting change. Don't fragment into one-frame scenes.
16
- - **Frames per scene** — match the shot list. Default is 3-6 frames per scene unless the script specifies more.
17
- - **Shot labels** — pull them from the script (e.g., "Wide", "Close-up", "Over-the-shoulder").
18
-
19
- If the user hasn't named the storyboard, suggest one based on the project tone.
20
-
21
- ### 2. Materialize the structure first (no generation yet)
22
- - `slates_create_storyboard` with the chosen name.
23
- - For each scene: `slates_add_scene` with a descriptive name and order.
24
- - For each frame: write a *visual-only* prompt (image, not action), the shot label, and any director notes. **Don't generate yet.**
25
-
26
- Surface the planned structure back to the user as a tight summary:
27
- > Storyboard "X" • 4 scenes • 12 frames total
28
- > Scene 1: Forest opening (3 frames)
29
- > Scene 2: Confrontation (4 frames)
30
- > ...
31
-
32
- Ask: **"Generate frame images now? (y/N)"**
33
-
34
- ### 3. Generate frames if requested
35
- For each frame:
36
- - Estimate cost (`slates_estimate_generation_cost`, `count = total frames`). Confirm with user if total > $0.50.
37
- - Generate sequentially, with character/environment/style references attached when present in the project (`slates_list_characters`, `slates_list_environments`).
38
- - Each result returns inline. Evaluate. If wrong, refine prompt + regenerate (charge once, not multiple).
39
- - Bind to the frame via `slates_add_frame`.
40
-
41
- ### 4. Hand back
42
- - Total frames generated, total credits spent, storyboard id.
43
- - Suggest next steps: motion generation (in Slates UI), or `slates_get_storyboard_with_frames` to review.
44
-
45
- ## Anti-patterns
46
-
47
- - **Don't** auto-generate without asking. Generation is the expensive step. Always confirm first.
48
- - **Don't** invent shot details the script doesn't mention. If the script says "they argue," ask what the shot looks like, don't fabricate "she clenches her fists in a wide shot."
49
- - **Don't** mix scene structure and frame generation in one pass — building the skeleton first lets the user catch errors before spending credits.
@@ -1,42 +0,0 @@
1
- ---
2
- name: slates-vision-feedback-loop
3
- description: Lower-level utility skill for any Slates workflow that needs to "generate, look at the result, refine, regenerate." Defines the standard inline-vision pattern. Other Slates skills compose this. Use when generating images and you need to confirm they match the brief before moving on, or when the user asks to "iterate" on an image.
4
- ---
5
-
6
- # Vision feedback loop — Slates utility skill
7
-
8
- Slates returns generated images inline as base64. You see the actual pixels. Use that — don't trust prompt-following blindly.
9
-
10
- ## The pattern
11
-
12
- 1. **Generate.** Call `slates_generate_image` with a prompt. The result is in your context as an image content block.
13
- 2. **Evaluate against the brief.** What did the user actually want? Are the elements right? Composition? Lighting? Subject identity?
14
- 3. **One of three outcomes:**
15
- - **Right** → save it (bind to a frame, character slot, etc.) and move on.
16
- - **Close, but adjustable** → refine the prompt with a specific delta ("wider shot", "warmer light", "remove the second figure"), regenerate **once**.
17
- - **Wrong direction** → ask the user before regenerating. Don't burn credits on prompt-thrashing.
18
-
19
- ## Refinement rules
20
-
21
- - **One specific delta per regeneration.** Don't change five things at once — you won't know what helped.
22
- - **Anchor with references.** If the result drifted from the user's intent, attach the *previous best* generation as a reference image alongside the original brief.
23
- - **Use `slates_get_asset_image`** to pull a previously-generated image back into context if you need to compare against a fresh generation.
24
- - **Use `slates_edit_image`** (when available) for surgical tweaks instead of full regeneration when 90% of the image is right.
25
-
26
- ## Cost discipline
27
-
28
- - Track total credits spent across the loop. Surface to the user every 3 iterations.
29
- - Stop after 3 failed iterations on the same prompt — escalate to the user with what you tried and what's not working. The slot machine never converges.
30
- - For high-cost generations (`> $0.50`), confirm before *every* attempt, not just the first.
31
-
32
- ## When to break the loop
33
-
34
- - The user said "good enough" or "ship it." Stop iterating.
35
- - You've burned >5 generations on one frame. Hand back and ask.
36
- - The user changes brief mid-loop. Treat it as a new brief, not a continuation.
37
-
38
- ## Voice when narrating to the user
39
-
40
- Tight, observational, no editorializing.
41
- - ✅ "Frame 2 has the wrong lighting direction — back-lit instead of side. Regenerating with side light."
42
- - ❌ "I notice that the lighting in frame 2 isn't quite what we were going for. I'll go ahead and try again with a different approach."