syncast-cli
v0.3.13
Published
Syncast CLI — AI generation and agent integration for Syncast
Downloads
90
Readme
syncast-cli
Syncast CLI — AI image/video/audio generation and agent integration for Syncast.
Choose the workflow before generation
An external Agent must determine whether the user is working in a Syncast project or only wants independent assets to review outside a project. If the request is unclear, ask before generating.
- Project work: connect the intended page with
syncast project-agent, inspect it, and run generation through public project Actions. Usesyncast.imagine.submitwhen no existing channel was specified. Never fall back to the direct generation commands, including their--projectoptions. - Standalone assets: use
syncast imagine,video,audio,music, orsound-effectonly after the user explicitly chooses assets for external viewing or requests the standalone API.
Installation
npm install -g syncast-cli
# provides both `syncast` and `syncast-cli` commandsStandalone quick start
These examples are only for the explicitly selected standalone-asset route.
# 1. Log in (device authorization in browser)
syncast auth login
# 2. Verify
syncast auth status
# 3. Generate an image (defaults to Nano Banana 2)
syncast imagine --prompt "a cat on the moon"
# Generate with a local reference image
syncast imagine -p "turn this into a studio product photo" --reference-image ./reference.png
# Generate a custom-size image, e.g. 4x6 inch at 600 DPI
syncast imagine -p "passport photo" --model seedream-5-0 --resolution custom --width 2400 --height 3600
# Generate with Seedream 5.0 Pro image editing/fusion
syncast imagine -p "precise commercial product poster" --model seedream-5-0-pro --resolution 1K
# Call OpenAI's official GPT Image 2 route explicitly
syncast imagine -p "precise bilingual launch poster" --model oai-gpt-image-2 --aspect-ratio 16:9 --resolution 2K --quality auto
# 4. Generate a video (defaults to KittyVibe Seedance 2.0 Pro)
syncast video --prompt "ocean waves at sunset"
# 5. Generate a complete audio clip with SeedAudio
syncast audio --prompt "一段 60 秒悬疑刑侦广播剧,电话对白,低音量悬疑音乐,结尾有汽车刹车和高跟鞋脚步声"
# Use a reference voice
syncast audio -p "爷爷(70岁以上,沙哑慈祥,饰演者为 @Audio1)慢慢说道:“今天爷爷什么都买给你。”" --reference-audio ./grandpa.wav
# 6. Generate music (defaults to Suno v5.5)
syncast music --prompt "温暖克制的电影配乐,缓慢钢琴与弦乐,逐渐进入宽广副歌"
# Generate an instrumental track
syncast music --prompt "retro synthwave chase theme, 118 BPM, cinematic build" --instrumental
# 7. Generate a sound effect
syncast sound-effect --prompt "distant muffled thunder, low deep rumbling, intermittent thunderclaps, no voices, no music"Commands
| Command | Description |
|---------|-------------|
| syncast auth login | Device authorization login |
| syncast auth status | Check session |
| syncast auth logout | Clear local session |
| syncast imagine | Image generation |
| syncast video | Video generation |
| syncast audio / syncast seedaudio | Complete audio generation with SeedAudio |
| syncast music / syncast suno | Music generation with Suno v5.5 by default |
| syncast sound-effect / syncast sfx | Sound effect generation |
| syncast task status <id> | Task status / SSE stream |
| syncast task cancel <id> | Cancel task |
| syncast project-agent serve | Local bridge for external agents operating an opened frontend project |
| syncast project-agent run <action> | Forward a Syncast Agent Action into the connected project page |
| syncast project-agent notifications | List Agent Action notifications, including pending approvals |
| syncast project-agent approval respond <id> | Approve or deny an internal Agent action approval |
| syncast project-agent wait --ref <json> | Wait for a frontend Agent Action task ref |
| syncast library guide [type] | Print package fields, compatibility rules, and canonical examples without login |
| syncast library publish/import/export/share/status/approvals | Publish, package, share, import, and review reusable library resources |
| syncast sync / start | Local file sync (legacy) |
Project work
Connect and inspect the target project before any generation:
syncast project-agent serve
syncast project-agent pages
syncast project-agent run syncast.project.inspect --input '{"limit":10}'
syncast project-agent capabilities --action syncast.imagine.submit --disclosure full
syncast project-agent run syncast.imagine.submit \
--input '{"modelType":"nano-banana-2","prompt":"生成角色设定图","targetAssetName":"角色A首帧"}'syncast.imagine.submit automatically resolves or creates the Agent Imagine
channel and persists prompts, parameters, tasks, results, and Assets. Use
syncast.imagine.submitToChannel only when the user selected a real existing
Imagine channel. Document Imagine blocks and timeline generation Slots use
their dedicated project Actions.
The direct imagine --project/--folder/--reference-asset options remain
low-level compatibility features for API integrations. They do not reproduce
project interaction and are not the external-Agent route for project work.
Library resources
Library commands use the same resource model as the Syncast app. They support Agents, Skills, Prompt Templates, Imagine Optimize Presets, Project Specs, and Project Templates.
# Publish a local resource into your personal library
syncast library publish ./SKILL.md --type skill --target personal
# Inspect exact fields and copy a canonical package example (no login required)
syncast library guide agent
syncast library guide skill
syncast library guide project_template
# Submit a project template for public review
syncast library publish ./bundle.json --type project_template --target public
# Import or export a portable package
syncast library export <resourceId> --output ./exports/
syncast library import ./exports/my-agent.syncast-library.json --target personal
# Create a private share link, then let another user import it
syncast library share create <resourceId> --max-uses 3
syncast library share inspect <token>
syncast library share import <token> --target personal
# Check status
syncast library status list
syncast library status list --target team:<teamId> --item-id <itemId> --type project_template_bundle --status all
syncast library status list --target public
syncast library approvals list --team <teamId>
syncast library approvals approve <requestId> --team <teamId>Exports, share links, and public submissions include the stored resource data.
When prompt, instruction, or project-spec text is detected, CLI output includes a
disclosure block listing the relevant fields so callers can review what is
being shared or published.
syncast library guide [type] is the machine-readable source of truth for local resource package fields. In particular:
- Agent
skillsentries useskill_id,skill_type, and explicitpreloadfor new packages.preload: falsekeeps a Skill available for on-demand loading;trueinjects full instructions at startup. A missing legacy value is interpreted astrue. - Agent
allow_load_skillsis a compatibility field for access to unselected project custom Skills. Set it explicitly tofalsefor new packages unless the Agent intentionally needs the whole project custom-Skill catalog.falsestill permits every built-in Skill, selected custom Skills, their dependencies, andalways_applySkills; a missing legacy value remainstrue. - Custom Skill
dependsentries use onlyskill_idandskill_type; preload is not a dependency field. - Agent
child_agentsreference independent Agents bychild_agent_idand may add alias, routing, handoff, and project-spec strategy metadata. - Project-template bundles should include every referenced custom Skill and child Agent. Applying the bundle in a project performs dependency preflight and two-phase Agent import.
The canonical Agent shape begins like this; use syncast library guide agent for every field and a complete example:
{
"type": "agent",
"id": "story-planner",
"name": "Story Planner",
"instructions": "Read the project spec, then return a structured plan.",
"allow_load_skills": false,
"skills": [
{ "skill_id": "docs", "skill_type": "builtin", "preload": false },
{
"skill_id": "continuity-checker",
"skill_type": "custom",
"preload": true
}
]
}Project template bundles
Users who publish reusable project packs through the CLI use the library route:
syncast library publish ./bundle.json --type project_template --target personal
syncast library publish ./bundle.json --type project_template --target public --source-project-id <projectId>project_template is the product alias for the stored
project_template_bundle type. Personal and team targets store the package data
as a workspace library item; public targets submit the same data through
typedData.content for review. A project template bundle can include Agents,
Skills, Prompt Templates, Project Specs, and an optional project skeleton:
{
"type": "project_template",
"id": "short-drama-skeleton",
"name": "Short Drama Skeleton",
"agents": [{ "id": "writer" }],
"standardProjectTemplate": {
"schemaVersion": 1,
"docs": [
{
"id": "story-bible",
"title": "Story Bible",
"body": "# Story Bible\n\nProduction rules."
},
{
"id": "episode-outline",
"parentId": "story-bible",
"title": "Episode Outline",
"body": "Scene beats."
}
],
"resourceDirs": [
{ "path": "References/Characters" },
{ "path": "Shots/Act 1" }
]
}
}Use camel-case standardProjectTemplate in new packages. The app and backend
also accept legacy standard_project_template packages and preserve the
skeleton when importing, exporting, sharing, or submitting for public review. If
an old public submission was normalized before this field existed, republish or
upsert that package so reviewers and other clients can receive the skeleton.
Project Agent bridge
project-agent is separate from the normal cloud generation commands. It is a
thin transport into an already opened Syncast frontend project page. External
agents should still read .agents/skills/syncast-agent-actions to decide which
action to call and what JSON input to send.
Start the local bridge:
syncast project-agent serveThe command prints activation query parameters. Open or reload the Syncast project URL with those parameters once:
syncastAgentBridgeToken=...
syncastAgentBridgePort=23457Then verify the page is connected and call project-local actions:
syncast project-agent pages
syncast project-agent capabilities
syncast project-agent capabilities --action syncast.agent.delegate --disclosure full
syncast project-agent capabilities --action syncast.imagine.submit --disclosure full
syncast project-agent capabilities --action syncast.imagine.submitToChannel --disclosure full
syncast project-agent capabilities --action syncast.docs.imagineBlocks.history --disclosure full
syncast project-agent run syncast.project.inspect --input '{"limit":10}'
syncast project-agent run syncast.doc.graphql --input '{"query":"query { agents { agents { id name model allowLoadSkills skills { skillId skillType preload } childAgents { childAgentId alias displayName } } } }"}'
syncast project-agent run syncast.doc.graphql --input '{"query":"mutation EnsureDocs($inputs: [EnsureDocPageInput!]!) { ensureDocPages(inputs: $inputs) { success logicalKey docId created adopted contentWritten ready hasMeaningfulContent } }","variables":{"inputs":[{"logicalKey":"short-drama:episodes","title":"分集剧本","containerOnly":true},{"logicalKey":"short-drama:episode:01","title":"第一集","parentLogicalKey":"short-drama:episodes","initialMarkdown":"# 第一集\n\n## 场景一\n\n正文"}]}}'
syncast project-agent run syncast.agent.delegate --input '{"goal":"整理项目方案","executor":{"kind":"model","model":"gemini-3.8-flash"},"wait":false}'
syncast project-agent run syncast.agent.delegate --input '{"goal":"按专业配置整理项目方案","executor":{"kind":"agent","agentId":"project-agent-id"},"wait":false}'
syncast project-agent run syncast.imagine.submit --input '{"modelType":"nano-banana-2","prompt":"生成角色设定图","targetAssetName":"角色A"}'
syncast project-agent run syncast.imagine.submitToChannel --input '{"channelId":"imagine-channel-id","modelType":"nano-banana-2","prompt":"生成角色设定图","targetAssetName":"角色A"}'
syncast project-agent run syncast.docs.imagineBlocks.submit --input '{"docId":"doc-id","blockId":"block-id"}'
syncast project-agent run syncast.docs.imagineBlocks.history --input '{"docId":"doc-id","blockId":"block-id","disclosure":"full"}'
syncast project-agent wait --ref '{"kind":"agent_chat","projectId":"..."}' --return-resultProject document creation uses the generic syncast.doc.graphql bridge rather
than a second CLI-specific document command. New content pages must use one
ensureDocPages mutation with stable project-business logicalKey values and
meaningful initialMarkdown; use parentLogicalKey to build a tree in the
same batch. For an existing target, query its real id and pass
existingDocId. Do not guess identity from titles or silently create a
duplicate. success=true and ready=true are the persisted-content
postcondition, so a mechanical read-back is unnecessary. The full internal
GraphQL schema retains createDocPage only for App and historical blank-page
callers; external syncast.doc.graphql rejects that compatibility field.
The bridge is mandatory whenever the user is working in a Syncast project,
including a new or empty project. Project Imagine submission is a public
interaction action, not a duplicate direct-generation API:
syncast.imagine.submitToChannel reuses the frontend enqueue path and persists
prompt, parameters, task state, and results in the selected Imagine channel.
syncast.imagine.submit uses the same persistence path and is the default when
no existing channel was specified because it resolves or creates the Agent
Imagine channel automatically. The absence of an explicit channel-history
request is not permission to leave the project workflow. Direct generation
commands are only for a separately confirmed standalone-asset task.
Document Imagine cards keep an editable root plus independent frozen generation
versions. syncast.docs.imagineBlocks.submit { docId, blockId } always creates
another version, including while older versions are running or after results
already exist. submitBatch without blockIds keeps the top-bar “generate all
pending” behavior; explicit blockIds create another version for those blocks
in parallel. Each successful submission returns its own task ref.
Read the authoritative history before choosing a result:
syncast project-agent run syncast.docs.imagineBlocks.history \
--input '{"docId":"doc-id","blockId":"block-id","disclosure":"full"}'The response contains stable versions[].results[] refs. Copy one result object
unchanged into selectResult to change the current preview, or fixAsAsset to
land that exact result as a normal document Asset block:
syncast project-agent run syncast.docs.imagineBlocks.selectResult \
--input '{"docId":"doc-id","blockId":"block-id","result":{"channelId":"channel-id","messageId":"version-message-id","resultIndex":0,"assetId":"asset-id"}}'
syncast project-agent run syncast.docs.imagineBlocks.fixAsAsset \
--input '{"docId":"doc-id","blockId":"block-id","result":{"channelId":"channel-id","messageId":"version-message-id","resultIndex":0,"assetId":"asset-id"}}'Do not fix a result while another version is still running. A fixed Asset keeps its generation reference and can be restored later:
syncast project-agent run syncast.docs.imagineBlocks.restoreGeneration \
--input '{"docId":"doc-id","blockId":"block-id"}'Direct syncast imagine, ordinary channel submission, or manually patching Doc
block state cannot replace this contract.
executor.kind=model uses a direct model and exposes every project Agent as a
named option. executor.kind=agent uses one independent project Agent and
exposes only its bound named Agents. Both can create a fresh ad-hoc child; child
runs are leaves, and an ad-hoc child does not inherit parent Agent instructions.
Query the Agents GraphQL module before selecting executor.agentId.
The CLI option --agent-id identifies the external operator connected through
the bridge. It is not the same field as action input executor.agentId, which
selects an internal project Agent.
When reading then updating an Agent, always request and preserve allowLoadSkills plus every skills.preload value. All built-in Skills remain available on demand. allowLoadSkills: false excludes only unselected project custom Skills; selected custom Skills, their dependencies, and alwaysApply Skills remain available. Omitting either boolean turns it into the legacy missing value, which is interpreted as true. A running task keeps the Agent/Skill snapshot captured at submission, so edits affect the next task. Child Agent permissions never exceed the root task permission ceiling.
The bridge and this README are external integration guidance. Do not copy CLI,
Bridge, standalone API, syncast.* Action names, GraphQL mutations, transport,
or access instructions into project-internal Skills, Agent instructions,
project specs, prompt templates, or ordinary user documents unless the user
explicitly asks for an integration document. Internal content should describe
business rules, product-capability semantics, model ids, and creative
parameters. Validate every text-bearing field, including descriptions and
metadata, not only the body.
Delegate creative judgment such as ideation, script design, or an unknown structure. For complete user-provided text, use project GraphQL directly. For one or many exact edits in an existing document, use the structured action so the CLI does not need to guess the raw Patch DSL:
syncast project-agent run syncast.docs.replaceText \
--input '{"docId":"doc-id","replacements":[{"search":"exact old text","replacement":"replacement text"}]}'Every search must match exactly once; a missing or ambiguous match rejects the
whole batch. Use raw patchDoc for line, section, or whole-document edits only
after retrieving its complete string format from
syncast.doc.graphql.explain. Preserve all supplied content. Custom Skill creation must
query same-name Skills first, confirm alwaysApply, depends, and optional
Agent binding, then read the complete Skill back by its real id and validate
all document references plus instructions, description, and metadata.
The default output is stable JSON for agents. project-agent wait
--return-result returns a compact result by default: final text, terminal task
status, and artifact ids, with the final text at data.result.text. Add
--full-result only for debugging the complete message, thinking, parts, and
tool trace. For a readable terminal summary, add --format human.
CLI update guidance
Project Agent bridge responses may include a machine-readable cliUpdate
object with an update command and a bridge restart command:
{
"cliUpdate": {
"code": "cli_update_available",
"updateCommand": "npm install -g syncast-cli@latest",
"restartCommand": "syncast project-agent serve"
}
}Most CLI releases do not require any frontend change. The CLI checks npm for
syncast-cli@latest, so normal bug fixes and non-bridge features are announced
by the CLI itself after the package is published.
Only bump the frontend Project Agent recommended CLI version when the current
frontend depends on a newer project-agent bridge contract, activation
parameter, or action result shape. This keeps old CLI clients informed through
the opened frontend page without nagging users for unrelated CLI releases.
When a delegated internal Agent pauses on an approval request, list pending approval notifications and respond as the same external Agent identity:
syncast project-agent notifications --type agent_action.approval_requested --limit 5
syncast project-agent approval respond <approvalId> --approve
syncast project-agent approval respond <approvalId> --deny --feedback "User rejected this action."Approval notifications also include a respondAction object that can be used
directly with syncast project-agent run if the caller wants to stay fully
generic.
The bridge does not expose arbitrary browser JavaScript or UI automation. It
only forwards structured requests to window.__syncastAgent in the registered
project page.
Output format
Default: JSON (agent-friendly). Use --format human for readable text.
syncast imagine -p "hello" --format humanGeneration defaults
Syncast's default image model is nano-banana-2. Text-to-image, reference-image generation, and ordinary image editing should all be treated as the same image input capability family: use the image-input fields supported by the current schema instead of splitting "reference" and "edit" into separate model families. Use oai-gpt-image-2 when a task explicitly needs OpenAI/GPT Image 2, mask editing, official API behavior, or strict output controls.
The CLI deliberately does not keep a second model allowlist. Omitting --model uses the recommended defaults above; an explicit --model <backend-model-type> is normally passed to the server registry, so specialized models remain available without waiting for a CLI release. The retired Seedance aliases seedance2.0pro and seedance2.0fast are the exception: the CLI rewrites them to kittyvibe-seedance2.0pro and kittyvibe-seedance2.0fast, respectively. The same rewrite applies when model_type is supplied through --input or --input-file. Explicit models do not inherit the default command's aspect-ratio, resolution, or duration values.
For the standalone-asset route, direct syncast imagine supports schema
passthrough:
# Reuse a local image outside a project
syncast imagine -p "poster layout" --reference-image ./reference.png
# Read the same passthrough object from a file
syncast imagine -p "poster layout" --input-file ./input.json
If the source is already a Syncast project Asset, stay in the project workflow
and pass its stable Asset ID through syncast.imagine.submit. If a required
local file is not yet in the project, ask the user to import it there rather
than silently switching to standalone generation.
Syncast's default video model family is KittyVibe Seedance 2.0. Use kittyvibe-seedance2.0pro for normal text-to-video, image-to-video, and multi-reference/multimodal video; use kittyvibe-seedance2.0fast for fast/low-cost previews; use Global variants for complex action or high-motion scenes. Do not switch to other video models only because the user provides images or asks for references.
syncast video also accepts --input and --input-file, so model-specific video parameters such as content, images, first_frame, last_frame, or an upscale source can be supplied directly when an explicitly selected model needs them.
Syncast's direct complete-audio model is SeedAudio 1.0 (bytedance/seed-audio-1.0). Use syncast audio for voiceover, dubbing, audio drama, multi-character dialogue, narration with ambience/SFX/BGM, and reference-audio continuation or gap filling. Keep syncast sound-effect for short one-shot SFX and loopable ambience. The --duration value maps to target_duration_seconds (30-120 seconds) for prompt guidance and cost estimate; fal does not currently expose a hard duration parameter for this endpoint. The final prompt must stay within 2048 characters, including the automatic duration hint. Each audio reference must be 30s or shorter and 10MB or smaller; image references must be 10MB or smaller.
# Complete audio scene
syncast audio -p "一段约 60 秒的雨夜霓虹小巷影视级音频场景。雨声和远处车流声作为背景声床,低音量合成器音乐压在对白下方。"
# Up to 3 audio references, addressed as @Audio1, @Audio2, @Audio3 in the prompt
syncast audio -p "@Audio1 饰演林,@Audio2 饰演赵。生成一段约 45 秒的中文电梯对峙音频,背景有低沉通风声。" --duration 45 --reference-audio ./lin.wav --reference-audio ./zhao.wav
# Or one image reference, not mixed with audio references
syncast audio -p "使用参考图片作为视觉氛围和声音场景参考。生成清晨雪地火车站音频。" --reference-image ./station.png
# Passthrough advanced fields
syncast audio -p "A clean narration." --input '{"voice":"cedric_en_zh","output_format":"wav","sample_rate":44100}'Syncast's default music model is Suno v5.5 (zhenzhen-suno-v5.5). Use syncast music for songs, instrumentals, BGM, scores, hooks, lyrics, continuation, and cover workflows. Lyria remains available only as an explicitly selected alternative model through --model lyria-3-clip or --model lyria-3-pro.
# Natural-language music generation; mode defaults to description
syncast music -p "Mandarin indie-pop song, warm female vocal, restrained verse, expansive chorus, live drums and shimmering guitars"
# Instrumental BGM
syncast music -p "tense investigative documentary underscore, muted piano, low strings, subtle pulse" --instrumental
# Custom lyrics: prompt contains final lyrics, tags contain the music/style brief
syncast music --mode custom --lyrics-mode manual --title "夜航" --tags "Mandarin synth-pop, 112 BPM, female vocal, cinematic chorus" -p $'[Verse]\n城市在脚下退后\n[Chorus]\n我们沿着夜色远航'
# Continue or cover one local audio reference
syncast music --mode extend --continue-at 28 --reference-audio ./source.mp3 -p "Continue with the same key and vocal character, then build into a larger final chorus"
syncast music --mode cover --reference-audio ./source.mp3 --tags "acoustic folk, intimate male vocal" -p "Reinterpret the source as a sparse acoustic performance"Use syncast audio rather than syncast music when the result is primarily dialogue, dubbing, narration, radio drama, or a mixed sound scene. Use syncast sound-effect for isolated effects and ambience. For clean reusable long-form TTS or voice cloning/design, select the corresponding MiniMax model explicitly through syncast audio --model ... --input ....
The Agent skill is the operational guide for agents. When the CLI exposes machine-readable generation schema, agents should use it as the source of truth for supported media-input fields and examples.
Configuration
- File:
~/.syncast/config.json - Env:
SYNCAST_API_URLorAPI_URL(defaulthttp://localhost:8901)
Agent / Cursor skill
See .agents/skills/syncast-cli/SKILL.md for agent installation instructions.
The CLI package and Agent skills are updated separately. Before using
syncast project-agent, refresh the project skill from the published skill
repo if it is missing or stale:
npx skills add latentcat/syncast-skills --skill syncast-agent-actions -yExample prompt for agents:
Help me install Syncast CLI and log in, then generate a test sound effect.
Development
bun install
bun run build
node dist/cli.js --helpLicense
MIT
Workspace status and approval lists use a metadata-only endpoint (requires the matching backend update). Exact --item-id lookup avoids searching a truncated list. Reads share a 25-second overall deadline and retry a transport/gateway failure at most once; publications have a 90-second deadline and are never automatically replayed. If a publication response is lost, check its ID, version and status before retrying: a matching status alone does not prove that a particular attempted payload committed. Full resource reads and exports still fetch complete snapshots.
