← AstriaCONTENT HISTORY

Update to Astria

Snapshot Oct 5, 2026 · 18:34 UTC · version 1.5.6

Collection source: downloaded plugin package. These snapshots do not have a confirmed matching collection source. Differences in file lists alone do not establish changes to the package.

WHAT CHANGED · RULE-BASED ANALYSIS

Instructions updated for astria-api

Added instruction text: “### Image review comments”. 18 additional added or edited lines are in the evidence.

Observed in instructions or declared skills. Runtime behavior has not been tested.

Skill instructions

Before

No removed lines (ordering may have changed)

After

### Image review comments Request image comments with the repeatable `--expand` option: astria prompts list -w 17 --expand prompt.comments --limit 100 astria prompts get 555 -w 17 --tune 123 --expand prompt.comments astria prompts get 55...

Compare saved observations

Download comparison JSON
Full technical diff · 1 changed fields

changed /skill_md_contents

BEFORE
"---\nname: astria-api\ndescription: Use when making API calls to Astria for tunes, prompts, packs, image/video generation (Gemini/Seedream), inspecting or variating videos, handing an external agent session into Astria, or estimating generation and pack pricing. The reference for the `astria` CLI.\nallowed-tools: Bash(astria:*)\n---\n\n# Astria CLI Reference\n\nAll Astria operations go through the bundled **`astria`** command-line tool. It\nhandles authentication, the API base URL, and workspace scoping for you — never\nbuild raw `curl` calls and never read API tokens from environment variables.\n\nOutput is JSON on stdout, so you can parse ids and image URLs directly.\n\n## Authentication\n\n`astria` resolves credentials automatically:\n1. Environment variables, if present (the Astria web app injects these).\n2. `~/.astria/config.json`, written by `astria login`.\n\nIf a command fails with *\"not authenticated\"*, tell the user to run:\n\n```bash\nastria login          # prompts for an API key (astria.ai/users/edit/api)\n```\n\nCheck the active account any time with `astria whoami`.\n\n## Profiles\n\nProfiles work like the AWS CLI — keep separate credentials, base URL and\nworkspace per profile (e.g. production vs a local dev server):\n\n```bash\nastria --profile localhost login --base-url http://localhost:3000\nastria --profile localhost generate --text \"...\"\nASTRIA_PROFILE=localhost astria tunes list       # env-var form\n```\n\n`--profile <name>` (before the subcommand) or the `ASTRIA_PROFILE` env var\nselects it. Each profile is its own file — `~/.astria/config.<name>.json`; the\ndefault profile stays at `~/.astria/config.json`.\n\n## Tune reference syntax\n\nThe core concept. A **tune** is a fine-tuned model trained on user images —\n\"tune\" and \"reference\" mean the same thing. Reference a tune inside prompt text\nwith `<model_type:id:1> name`:\n\n- `model_type` and `id` come from the tune JSON (`astria tunes get <id>`)\n- `name` is the tune's class name and MUST appear right after the `<...>` token\n- the trailing `:1` is a fixed part of the token syntax — it is NOT a weight or strength. Always write `:1`; never vary it and never suggest changing it.\n- Combine freely: `<faceid:123:1> woman wearing <faceid:456:1> dress, white studio background`\n\n`<faceid:123:1> woman` is correct; `John` (a bare name the model never trained on) is wrong.\n\n## Workspace scoping\n\nAdd `-w/--workspace` to any command:\n- `-w <id>` — target a specific workspace\n- `-w all` — query across every workspace\n- omit it — uses `WORKSPACE_ID`/config default, or personal scope\n\n## Models\n\n`--model` accepts a model name or a raw tune id. **Don't hardcode model\nnames — discover the current catalog at runtime:**\n\n```bash\nastria models              # image + video models — name, title, tune id, resolutions\nastria models --refresh    # force-refresh (otherwise cached for a day)\n```\n\nThe catalog is fetched from the Astria server, so it stays current as models\nare added or retired and the tune ids never go stale. The output marks the\n`default` model (used when `--model` is omitted) and lists each model's\nsupported `--resolution` values — a model with no resolutions listed doesn't\naccept `--resolution`. It also lists the `video_models` catalog and the\n`default_video_model` used by `astria video`.\n\n`astria generate` / `astria video` `--help` print the current model,\nresolution and video-model names inline — they read the same cached catalog.\n\n---\n\n## Tunes / references\n\n```bash\nastria tunes list                              # all tunes\nastria tunes list --title \"brown dress\"        # by title / product name / SKU\nastria tunes list --name shoes --name sandals  # by class name (repeatable)\nastria tunes list --gallery --model-type faceid --limit 200   # public gallery\nastria tunes get 123\nastria tunes create --title \"Brown dress\" --name dress \\\n  --description \"satin brown dress\" \\\n  --image-url https://example.com/a.jpg --image-url https://example.com/b.jpg\nastria tunes create --title \"Studio shot\" --name woman --image ./face1.jpg --image ./face2.jpg\nastria tunes update 123 --name ring --title \"Gold ring\"\n```\n\n`tunes create` takes `--image-url` (remote) and/or `--image` (local file),\nboth repeatable. `--name` is the subject class (man, woman, dress, shoes,\nsandals, pose, …). `--model-type` defaults to `faceid`.\n\n## Prompts\n\n```bash\nastria prompts list                            # recent prompts\nastria prompts list --pack-id 88               # a pack's template prompts\nastria prompts list --tune-id 123              # prompts for one tune\nastria prompts list --liked --is-video         # liked video prompts\nastria prompts list --today --limit 100        # prompts created today\nastria prompts list --text \"white background\" --limit 100 --offset 0\nastria prompts get 555 --model nano-banana-pro       # one prompt (needs its tune/model)\nastria prompts update 555 --model nano-banana-pro --pack-id 88   # assign a prompt to a pack\nastria prompts update 555 --model nano-banana-pro --base-pack-id 88   # bind as a pack one-off (board frame)\n```\n\n- `prompts list` filters: `--pack-id`, `--base-pack-id`, `--tune-id`,\n  `--user-id`, `--orig-prompt-id`, `--text`, and the flags `--liked`,\n  `--today`, `--is-video`, `--is-api`.\n\n## Generate images\n\n```bash\nastria generate --text \"<faceid:123:1> woman, clean white studio background\"\nastria generate --model nano-banana-pro --text \"...\" --num-images 4 --aspect-ratio 3:4 --resolution 2K\nastria generate --model seedream --text \"product photo of headphones on marble\" --num-images 2\nastria generate --text \"cinematic portrait\" --film-grain\nastria generate --text \"recreate this in 4K\" --input-image https://example.com/photo.jpg\nastria generate --text \"<faceid:123:1> woman, white bg\" --pack-id 88 --wait   # author a pack template prompt\nastria generate --text \"...\" --base-pack-id 88       # one-off bound to pack 88 — lands in its board frame\n```\n\n- `--input-image` accepts a URL or a local file path (used for image editing/upscaling).\n- `--film-grain` sends film grain as a separate prompt attribute and leaves\n  `--text` unchanged. `--film_grain` is an alias; `--no-film-grain` explicitly\n  disables it.\n- `--pack-id` authors the prompt as a pack **template** prompt; `--base-pack-id`\n  records pack provenance only (a one-off). On the board, `--base-pack-id`\n  generations appear as free rows inside that pack's frame.\n- A `--pack-id` template prompt must **reference a fine-tuned tune** — embed a\n  `<faceid:ID:1>` (or `<lora:ID:1>` …) token in `--text`. A plain foundation-model\n  prompt with no reference is rejected (HTTP 422, \"Prompt is not using a fine-tuned\n  model\"). `--base-pack-id` one-offs have no such requirement.\n- `--wait` polls until the images are ready and prints the finished prompt JSON.\n  Without it, the command returns immediately — images render asynchronously.\n- `aspect_ratio` values: `1:1 16:9 9:16 21:9 9:21 3:2 2:3 5:4 4:5 4:3`.\n- `--seed` sets the generation seed. Astria dedups prompts by `(text, seed)`\n  within a tune, so the same prompt text reused on different input images\n  collapses onto one prompt — pass a distinct `--seed` per call to keep them\n  separate without altering the prompt text.\n\n## Generate video\n\nVideo runs through the same prompt: the image stage renders the first frame\nfrom `--text`, then the video model animates it from `--video-prompt`.\n\n```bash\n# Existing reference: use the same token + tune-name syntax as image generation.\n# Put Seedance 2 references in --video-prompt so their images condition the video.\nastria video --video-model seedance2_fast_720p \\\n  --video-prompt \"<faceid:1234:1> woman walks down a runway as the camera tracks her\" \\\n  --duration 5 --aspect-ratio 16:9 --wait\n\n# New references: create them from local files or URLs and use them immediately.\nastria video --video-model seedance2_fast_720p \\\n  --video-prompt \"woman wearing a dress walks down a runway\" \\\n  --reference woman=./model.jpg --reference dress=https://example.com/dress.jpg \\\n  --duration 5 --aspect-ratio 16:9 --wait\n\n# Ordered raw references: attach the images directly without creating tunes.\nastria video --video-model seedance2_fast_720p \\\n  --video-prompt \"transition through these looks in order\" \\\n  --image-reference ./look-1.jpg --image-reference ./look-2.jpg \\\n  --duration 15 --aspect-ratio 16:9 --wait\n\nastria video --text \"zwx man <faceid:123:1> in a dance arena\" \\\n  --video-model kling30_motion_control_pro --video-prompt \"match the dance moves\" \\\n  --duration 10 --input-video ./reference.mp4\n```\n\n- Seedance 2 references use `<faceid:TUNE_ID:1> TUNE_NAME`, exactly like image\n  prompts. The tune's class name must immediately follow the token. A bare\n  `<faceid:1234:1>` token is incomplete.\n- Put existing reference mentions in `--video-prompt`; Seedance 2 resolves the\n  referenced tunes' images and sends them as video reference images.\n- `--reference NAME=PATH_OR_URL` creates an instant `faceid` reference and\n  prepends `<faceid:NEW_ID:1> NAME` to both `--text` (when present) and\n  `--video-prompt`. Repeat it for multiple references. `--images` is an alias.\n- `--image-reference PATH_OR_URL` attaches a raw image directly to the video\n  prompt without creating a tune. Repeat it in storyboard order. Use either\n  all local files or all URLs in one request so that ordering remains exact.\n- `--first-frame` / `--last-frame` / `--input-video` accept a URL or local file.\n- Motion-control models (`*_motion_control*`, `wan_animate_*`, `dreamactor_m2`,\n  `happyhorse_motion_control`) require `--input-video`.\n\n### `video_model` values and cost\n\nCosts are per 5-second base (per 10s for motion-control / fixed-duration\nmodels) and scale linearly with duration. `_audio` models include a soundtrack.\n\n| video_model                     | cost (¢)    | duration options |\n|----------------------------------|------------:|------------------|\n| seedance_480p                    |          10 | 2–12             |\n| seedance_v15_720p                |          14 | 4–12             |\n| seedance_v15_audio_720p          |          29 | 4–12             |\n| cinematic_video                  |          84 | 5, 10, 15        |\n| wan25_720p                       |          53 | 5, 10            |\n| wan26_720p / wan26_1080p         |       53/79 | 5, 10, 15        |\n| wan27_720p / wan27_1080p         |       55/83 | 5, 10, 15        |\n| wan_animate_720p                 |          44 | 10               |\n| ltx23_720p / ltx23_1080p         |       17/22 | 5, 10, 15, 20    |\n| happyhorse_720p / _1080p         |      77/132 | 3–10             |\n| happyhorse_motion_control        |         154 | 10               |\n| dreamactor_m2                    |          29 | 10               |\n| seedance2_fast_480p / _720p      |      60/140 | 4–15             |\n| seedance2_480p / _720p / _1080p  | 120/280/450 | 4–15             |\n| veo31_fast_720p / _1080p         |          85 | 4, 6, 8          |\n| veo31_fast_4k                    |         264 | 8                |\n| veo31_lite_720p / _1080p         |       44/71 | 4, 6, 8          |\n| kling30_standard / _pro          |      92/123 | 3–15             |\n| kling30_4k                       |         263 | 3–15             |\n| kling30_motion_control / _pro    |     277/370 | 10               |\n\nVideo output is delivered in the prompt's `images[]` with `content_type=video/mp4`.\n\n## Inspect video\n\nTurn a local video or public HTTPS video URL into timestamped text-to-video\nprompt text. Local files are direct-uploaded to Astria automatically; do not\nupload them separately or build raw API requests.\n\n```bash\nastria inspect-video ./clip.mp4\nastria inspect-video https://example.com/clip.mp4\nastria inspect-video ./clip.mp4 --tune-id 123 --tune-id 456\n```\n\nThe output uses one `SS-SS - description` line per cut for videos up to 30\nseconds. `--tune-id` is repeatable: use it when the resulting generation will\ncarry those references, so inspection removes their appearance details and\ninserts the exact Astria reference tokens. There is intentionally no custom\nprompt option; use the returned `description` as the video prompt.\n\n## Variate video\n\nUse `astria variate` when the user wants to preserve a source video's timing,\nperformance, camera, transitions, and audio while changing its content. The\ncommand runs the Variate mini-app workflow end to end: source inspection,\nreplacement-reference creation, structured prompt writing, and fixed-model\nSeedance 2.5 generation.\n\n```bash\n# Edit from a written brief\nastria variate ./source.mp4 \\\n  --brief 'Change the text on the final card to say \"Astria\"' --wait\n\n# Mix existing references with new local or remote images\nastria variate ./source.mp4 \\\n  --tune-id 123 \\\n  --reference ./dress.jpg \\\n  --reference woman=https://example.com/model.jpg \\\n  --brief 'Replace the presenter and wardrobe' --wait\n\n# Reuse an existing source description and avoid another inspection charge\nastria variate https://example.com/source.mp4 \\\n  --description-file ./source-description.txt \\\n  --brief 'Use a warmer end-card treatment'\n```\n\n- `SOURCE` is a local MP4/MOV or public HTTPS URL.\n- Repeat `--tune-id ID` for existing replacement references.\n- Repeat `--reference [NAME=]PATH_OR_URL` to create replacement references.\n  Without `NAME=`, the CLI detects the image class. With it, detection is\n  skipped. References preserve command order within the existing/new groups.\n- At least one reference or a non-empty `--brief` is required.\n- `--description` / `--description-file` bypass source inspection.\n- The command intentionally fixes `video_model=seedance25_720p`, enables\n  generated audio, and omits duration/aspect ratio so the source drives them.\n- Local source and reference files are direct-uploaded in one parallel batch.\n- The JSON result contains `description`, `references`, `video_prompt`, and\n  `prompt`; add `--wait` to receive the settled generation in `prompt`.\n\n## Download\n\n`astria download` saves a prompt's rendered assets (images, or `video/mp4`) to a\nlocal directory. It works from a **prompt id alone** — no tune id needed — and\nfetches each prompt fresh from the API, so newly rendered assets are included.\n\n```bash\nastria download 555 556 557                       # ids as arguments\nastria download 555 --out ./shoot                  # custom target directory\nastria download --prompts-file ids.txt             # one id per line (or whitespace)\nastria prompts list --pack-id 88 | \\\n  python3 -c 'import sys,json; [print(p[\"id\"]) for p in json.load(sys.stdin)]' | \\\n  astria download                                  # ids piped on stdin\n```\n\n- Prompt ids come from positional args, `--prompts-file`, and/or stdin; they are\n  deduped with original order preserved.\n- `--out` defaults to `./astria-downloads` and is created if missing.\n- Each asset is saved as `prompt-<id>-<NN><ext>` — `<NN>` is a zero-padded\n  index, `<ext>` is derived from the URL (`.jpg`/`.png`/`.webp`/`.mp4`/…).\n- Downloads run in parallel (~6 at a time).\n- A prompt that 404s, errors, or has no images yet is reported in the JSON\n  output (`error` field) and does not abort the run.\n- The JSON summary lists per prompt `{id, images, saved[], error?}` plus\n  `totals {prompts, downloaded, failed}`.\n\n## Packs\n\nPacks are surfaced in the Astria GUI as **Templates** — \"pack\" and \"template\" are interchangeable terms for the same object.\n\n```bash\nastria packs list\nastria packs get spring-lookbook\nastria packs create --title \"Spring Lookbook\"\nastria prompts update 555 --model nano-banana-pro --pack-id 88   # add a prompt to the pack\n```\n\n## Pricing\n\n`cost_mc` is an integer number of **millicents** (one thousandth of a US cent):\n\n- 1,000 `cost_mc` = $0.01\n- 100,000 `cost_mc` = $1.00\n- Convert to dollars with `cost_mc / 100_000`.\n\nA prompt's `cost_mc` already includes its `num_images`; never multiply by\n`num_images` again. Sum `cost_mc` across prompt records to price a prompt batch.\nFor example, prompts priced at 12,500 and 25,000 `cost_mc` total 37,500\nmillicents, or **$0.375**.\n\nUse `astria packs get <slug|id>` before running a pack:\n\n- `template_prompts[].cost_mc` is each stored template prompt's baseline. Sum\n  all entries for the full stored baseline, or selected entries for a\n  `--prompt-ids` subset.\n- `costs.<class>.cost_mc` estimates a fresh reference tune of that class plus\n  that class's prompt group. For multi-class packs it is not necessarily the\n  cost of the entire pack.\n\nThese are estimates, not personalized quotes. Generated prompts recalculate\ncost after prompt overrides; creator discounts, the payer's ecommerce pricing,\nworkspace rules, and Cartesian tune variants can change the result.\n\nAfter `astria packs run`, use `order.total_cost_mc` as the authoritative amount\ncharged when an order is returned. If no order is returned, the generated\nprompts' `cost_mc` values describe their individual base costs.\n\n### Run a pack\n\n`astria packs run <slug|id>` fires a pack's template prompts —\n`POST /p/:slug/tunes`. This is the canonical \"run a template\": the pack\ngenerates its whole prompt set, either against **tunes you already have** or\nagainst a **fresh tune trained from photos**. The positional accepts either the\npack **slug** or its numeric **id** — `astria packs run zara-pants …` and\n`astria packs run 3893 …` are equivalent.\n\n```bash\n# multi packs — run against existing tunes (tune_ids), with overrides\nastria packs run spring-lookbook --tune-id 123 --tune-id 456 \\\n  --brief \"golden hour, Lisbon\" --aspect-ratio 3:4 --inpaint-faces\n\n# only a subset of the pack's template prompts\nastria packs run spring-lookbook --tune-id 123 --prompt-ids 501,502\n\n# regular packs — train a fresh tune from photos, then generate\nastria packs run my-pack --title Jane --name woman \\\n  --image ./a.jpg --image ./b.jpg          # or --image-url https://…\n```\n\n- **Who the pack runs on** — pass either `--tune-id ID` (repeatable, or a\n  comma-separated list) to reuse existing tunes, **or** a training set\n  (`--title` + `--name` + `--image`/`--image-url`) to train a new tune first.\n  **Multi packs require at least one `--tune-id`** (the server routes tune_ids\n  to its multi handler; omitting them on a multi pack is a 422).\n- `--prompt-ids 501,502` runs only that subset of the pack's template prompts;\n  omit it to run them all.\n- `--brief` is an art-direction brief applied to the generated prompts.\n- **Overrides** ride along as `prompt_attributes`: `--num-images`,\n  `--aspect-ratio`, `--resolution`, `--inpaint-faces/--no-inpaint-faces`, and\n  `--attr KEY=VALUE` (repeatable) for any other prompt attribute, e.g.\n  `--attr super_resolution=true`.\n- The positional is the pack **slug or numeric id** — both resolve to the same\n  `/p/:slug/tunes` endpoint. On a multi pack the JSON response includes the new\n  `order` and its `prompt_ids` — feed those to `astria prompts wait` and\n  `astria download` to fetch the images.\n\n#### Worked example — a multi pack, step by step\n\n`zara-boot-test` (id `4001`) is a **multi pack** that composes two references —\na `dress` and a `shoes` (Footwear) — into one shoot. Create a reference per\ngarment, then run the pack against both by id. Scope every step to a workspace\nwith `-w` (find yours with `astria workspaces list`).\n\n```bash\n# 1. Create a reference for the dress (Gemini branch — instant, no training wait)\nastria tunes create -w 679 --name dress --title \"Zara dress\" --image ./dress.jpg\n# → { \"id\": 5234832, \"branch\": \"gemini-2\", \"trained_at\": \"...\" }\n\n# 2. Create a SEPARATE reference for the boots.\n#    Use a class the pack's slot recognizes: 'boots' (like 'shoes'/'sandals')\n#    resolves to the Footwear cube, so it fills the pack's shoes slot.\nastria tunes create -w 679 --name boots --title \"Zara boots\" --image ./boot.jpg\n# → { \"id\": 5234834, \"branch\": \"gemini-2\", \"trained_at\": \"...\" }\n\n# 3. Run the pack against both references — one --tune-id each.\n#    'zara-boot-test' or its id '4001' are interchangeable here.\nastria packs run zara-boot-test -w 679 \\\n  --tune-id 5234832 --tune-id 5234834 --num-images 1 --aspect-ratio 3:4\n# → { \"status\": 201, \"order\": { \"id\": 37345, \"tune_ids\": [5234834, 5234832] },\n#     \"prompt_ids\": [45042524, 45042523] }\n\n# 4. Fetch the results (the order hands back the prompt ids)\nastria prompts wait -w 679 45042524 45042523              # block until rendered (or user_error)\nastria download 45042524 45042523 --out ./zara-boot-shoot\n```\n\nThe pack swaps each reference into the matching template slot by lookbook cube,\nso the generated prompts come back with both tokens recorded, e.g.\n`a model wearing <faceid:5234832:1> dress and <faceid:5234834:1> boots, …`\n(and the shoes-only template gets just the boots token). The overrides land as\nprompt attributes (`aspect_ratio: 3:4`, `num_images: 1`).\n\nGemini-branch references (step 1–2) are ready instantly; a pack built on trained\ntunes queues its prompts and renders them once the tunes finish training. Pass\none `--tune-id` per reference slot the pack defines — a multi pack needs at\nleast one, and rejects the run (422) if you send none.\n\n## Board (infinite canvas)\n\nThe board (`/boards/:id` in the GUI) organizes work as **frames** (a pack-bound working context), **order rows** (one Order = a line of prompts sharing one reference set) and **reference cards** (tunes with lookbook roles: Pose, Face, Accessories, Jacket, Top, Bags & Belts, Footwear, Bottom, Background). There is no board API and no `board` verb — you act on the regular domain objects with the verbs above, and the canvas updates live (new rows land via the `order.created` broadcast, cells re-render as prompts finish).\n\n```bash\nastria packs run 88 --tune-id 123 --tune-id 456 \\\n    --prompt-ids 501,502 --brief \"golden hour, Lisbon\"  # new row: clone the pack's templates with swapped refs\nastria prompts wait 7001 7002 && astria download 7001 7002   # wait for the row's cells, fetch images\nastria generate --text \"...\" --base-pack-id 88       # one-off into pack 88's frame (free row, not a template)\n# variant with edited text (stacks as a version on its cell; order_id from `astria prompts get`):\nastria api POST /prompts/7001/duplicate --query view=board --data '{\"prompt\":{\"text\":\"...\",\"order_id\":901}}'\n# promote a prompt into the pack template / demote a template back out (confirm with the user first):\nastria api PATCH /prompts/7001 --query view=board --data '{\"prompt\":{\"pack_id\":88,\"base_pack_id\":null,\"orig_prompt_id\":null}}'\nastria api PATCH /prompts/7001 --query view=board --data '{\"prompt\":{\"pack_id\":null,\"base_pack_id\":88}}'\n```\n\nFor an ordered raw-image video, pass the selected images directly with repeated\n`astria video --image-reference PATH_OR_URL` options. Do not create temporary\ntunes for those images.\n\n## Workspaces & landing pages\n\n```bash\nastria workspaces list\nastria workspaces create --title \"Acme Store\"   # new workspace → returns its id/slug\nastria landing get -w 42                        # workspace JSON incl. landing_page_html\nastria landing set -w 42 --html-file ./edited.html\n```\n\n## Hand work into Astria’s embedded agent\n\nWhen the user asks to continue the current ChatGPT, Codex, Claude, or Cursor\nsession in Astria, write a concise UTF-8 `HANDOFF.md` containing the objective,\ncompleted work, important decisions, artifact paths, unresolved issues, and the\nrecommended next action. Do not include credentials or hidden reasoning.\n\nAttach only files needed to continue. Include a custom skill only when it was\nactually used or is needed for the remaining work; never export credential\nfiles or an entire agent configuration directory.\n\n```bash\nastria agent handoff -w 42 \\\n  --handoff ./HANDOFF.md \\\n  --attach ./deliverables \\\n  --skill ~/.claude/skills/relevant-skill \\\n  --source claude-code \\\n  --open\n```\n\n`--attach` and `--skill` are repeatable. A skill path must be a directory with\n`SKILL.md`. The command uploads the versioned bundle, creates a dedicated chat\nsession, prints its HTTPS deep link, and opens it with `--open`. Imported skills\nare reviewable session-scoped references; Astria does not silently install them\ninto the shared workspace skill directory.\n\n## Raw API escape hatch\n\nFor anything without a dedicated verb:\n\n```bash\nastria api GET /prompts --query limit=5 --query offset=0\nastria api POST /tunes --form 'tune[title]=Hat' --form 'tune[images][]=@./hat.jpg'\n```\n\n## Pagination\n\nList commands accept `--limit N` and `--offset Y`. Default sort is id\ndescending, so `--offset` walks backwards through history.\n\n## Errors\n\nA non-zero exit prints `astria: <METHOD> <PATH> → HTTP <code>: <message>` on\nstderr. Surface the message to the user and suggest a fix. HTTP 422 means a\nvalidation error (missing/invalid fields).\n"
AFTER
"---\nname: astria-api\ndescription: Use when making API calls to Astria for tunes, prompts, packs, image/video generation (Gemini/Seedream), inspecting or variating videos, handing an external agent session into Astria, or estimating generation and pack pricing. The reference for the `astria` CLI.\nallowed-tools: Bash(astria:*)\n---\n\n# Astria CLI Reference\n\nAll Astria operations go through the bundled **`astria`** command-line tool. It\nhandles authentication, the API base URL, and workspace scoping for you — never\nbuild raw `curl` calls and never read API tokens from environment variables.\n\nOutput is JSON on stdout, so you can parse ids and image URLs directly.\n\n## Authentication\n\n`astria` resolves credentials automatically:\n1. Environment variables, if present (the Astria web app injects these).\n2. `~/.astria/config.json`, written by `astria login`.\n\nIf a command fails with *\"not authenticated\"*, tell the user to run:\n\n```bash\nastria login          # prompts for an API key (astria.ai/users/edit/api)\n```\n\nCheck the active account any time with `astria whoami`.\n\n## Profiles\n\nProfiles work like the AWS CLI — keep separate credentials, base URL and\nworkspace per profile (e.g. production vs a local dev server):\n\n```bash\nastria --profile localhost login --base-url http://localhost:3000\nastria --profile localhost generate --text \"...\"\nASTRIA_PROFILE=localhost astria tunes list       # env-var form\n```\n\n`--profile <name>` (before the subcommand) or the `ASTRIA_PROFILE` env var\nselects it. Each profile is its own file — `~/.astria/config.<name>.json`; the\ndefault profile stays at `~/.astria/config.json`.\n\n## Tune reference syntax\n\nThe core concept. A **tune** is a fine-tuned model trained on user images —\n\"tune\" and \"reference\" mean the same thing. Reference a tune inside prompt text\nwith `<model_type:id:1> name`:\n\n- `model_type` and `id` come from the tune JSON (`astria tunes get <id>`)\n- `name` is the tune's class name and MUST appear right after the `<...>` token\n- the trailing `:1` is a fixed part of the token syntax — it is NOT a weight or strength. Always write `:1`; never vary it and never suggest changing it.\n- Combine freely: `<faceid:123:1> woman wearing <faceid:456:1> dress, white studio background`\n\n`<faceid:123:1> woman` is correct; `John` (a bare name the model never trained on) is wrong.\n\n## Workspace scoping\n\nAdd `-w/--workspace` to any command:\n- `-w <id>` — target a specific workspace\n- `-w all` — query across every workspace\n- omit it — uses `WORKSPACE_ID`/config default, or personal scope\n\n## Models\n\n`--model` accepts a model name or a raw tune id. **Don't hardcode model\nnames — discover the current catalog at runtime:**\n\n```bash\nastria models              # image + video models — name, title, tune id, resolutions\nastria models --refresh    # force-refresh (otherwise cached for a day)\n```\n\nThe catalog is fetched from the Astria server, so it stays current as models\nare added or retired and the tune ids never go stale. The output marks the\n`default` model (used when `--model` is omitted) and lists each model's\nsupported `--resolution` values — a model with no resolutions listed doesn't\naccept `--resolution`. It also lists the `video_models` catalog and the\n`default_video_model` used by `astria video`.\n\n`astria generate` / `astria video` `--help` print the current model,\nresolution and video-model names inline — they read the same cached catalog.\n\n---\n\n## Tunes / references\n\n```bash\nastria tunes list                              # all tunes\nastria tunes list --title \"brown dress\"        # by title / product name / SKU\nastria tunes list --name shoes --name sandals  # by class name (repeatable)\nastria tunes list --gallery --model-type faceid --limit 200   # public gallery\nastria tunes get 123\nastria tunes create --title \"Brown dress\" --name dress \\\n  --description \"satin brown dress\" \\\n  --image-url https://example.com/a.jpg --image-url https://example.com/b.jpg\nastria tunes create --title \"Studio shot\" --name woman --image ./face1.jpg --image ./face2.jpg\nastria tunes update 123 --name ring --title \"Gold ring\"\n```\n\n`tunes create` takes `--image-url` (remote) and/or `--image` (local file),\nboth repeatable. `--name` is the subject class (man, woman, dress, shoes,\nsandals, pose, …). `--model-type` defaults to `faceid`.\n\n## Prompts\n\n```bash\nastria prompts list                            # recent prompts\nastria prompts list --pack-id 88               # a pack's template prompts\nastria prompts list --tune-id 123              # prompts for one tune\nastria prompts list --liked --is-video         # liked video prompts\nastria prompts list --today --limit 100        # prompts created today\nastria prompts list --text \"white background\" --limit 100 --offset 0\nastria prompts get 555 --model nano-banana-pro       # one prompt (needs its tune/model)\nastria prompts update 555 --model nano-banana-pro --pack-id 88   # assign a prompt to a pack\nastria prompts update 555 --model nano-banana-pro --base-pack-id 88   # bind as a pack one-off (board frame)\n```\n\n- `prompts list` filters: `--pack-id`, `--base-pack-id`, `--tune-id`,\n  `--user-id`, `--orig-prompt-id`, `--text`, and the flags `--liked`,\n  `--today`, `--is-video`, `--is-api`.\n\n### Image review comments\n\nRequest image comments with the repeatable `--expand` option:\n\n```bash\nastria prompts list -w 17 --expand prompt.comments --limit 100\nastria prompts get 555 -w 17 --tune 123 --expand prompt.comments\nastria prompts get 555 -w 17 --tune 123 --expand comments --expand prompt.debug_images\nastria api GET /prompts -w 17 --query 'expand[]=prompt.comments'\nastria api GET /tunes/123/prompts/555 -w 17 --query 'expand[]=comments'\n```\n\n`comments` is an alias for `prompt.comments`. The API also accepts the scalar\nquery `expand=prompt.comments`, or repeated `expand[]` values to combine\nexpansions. Without this expansion, responses omit the `comments` field.\n\nEach prompt returns a flat `comments` array, oldest first, containing both open\nand resolved comments on its available images. Each entry includes `id`,\n`body`, `author`, `author_avatar_url`, `created_at`, `resolved_at`, `resolved_by`,\n`workspace_id`, `prompt_id`, `attachment_id`, `blob_id`, `image_url`, `filename`,\nand `image_review_id`. Use `blob_id` or `attachment_id` to associate a comment\nwith an image, and `resolved_at` to determine whether it is resolved.\n\nComments are limited to workspaces the authenticated account belongs to. Use\n`prompts list --expand prompt.comments` to retrieve comments for a page in one\nrequest instead of fetching each image separately.\n\n## Generate images\n\n```bash\nastria generate --text \"<faceid:123:1> woman, clean white studio background\"\nastria generate --model nano-banana-pro --text \"...\" --num-images 4 --aspect-ratio 3:4 --resolution 2K\nastria generate --model seedream --text \"product photo of headphones on marble\" --num-images 2\nastria generate --text \"cinematic portrait\" --film-grain\nastria generate --text \"recreate this in 4K\" --input-image https://example.com/photo.jpg\nastria generate --text \"<faceid:123:1> woman, white bg\" --pack-id 88 --wait   # author a pack template prompt\nastria generate --text \"...\" --base-pack-id 88       # one-off bound to pack 88 — lands in its board frame\n```\n\n- `--input-image` accepts a URL or a local file path (used for image editing/upscaling).\n- `--film-grain` sends film grain as a separate prompt attribute and leaves\n  `--text` unchanged. `--film_grain` is an alias; `--no-film-grain` explicitly\n  disables it.\n- `--pack-id` authors the prompt as a pack **template** prompt; `--base-pack-id`\n  records pack provenance only (a one-off). On the board, `--base-pack-id`\n  generations appear as free rows inside that pack's frame.\n- A `--pack-id` template prompt must **reference a fine-tuned tune** — embed a\n  `<faceid:ID:1>` (or `<lora:ID:1>` …) token in `--text`. A plain foundation-model\n  prompt with no reference is rejected (HTTP 422, \"Prompt is not using a fine-tuned\n  model\"). `--base-pack-id` one-offs have no such requirement.\n- `--wait` polls until the images are ready and prints the finished prompt JSON.\n  Without it, the command returns immediately — images render asynchronously.\n- `aspect_ratio` values: `1:1 16:9 9:16 21:9 9:21 3:2 2:3 5:4 4:5 4:3`.\n- `--seed` sets the generation seed. Astria dedups prompts by `(text, seed)`\n  within a tune, so the same prompt text reused on different input images\n  collapses onto one prompt — pass a distinct `--seed` per call to keep them\n  separate without altering the prompt text.\n\n## Generate video\n\nVideo runs through the same prompt: the image stage renders the first frame\nfrom `--text`, then the video model animates it from `--video-prompt`.\n\n```bash\n# Existing reference: use the same token + tune-name syntax as image generation.\n# Put Seedance 2 references in --video-prompt so their images condition the video.\nastria video --video-model seedance2_fast_720p \\\n  --video-prompt \"<faceid:1234:1> woman walks down a runway as the camera tracks her\" \\\n  --duration 5 --aspect-ratio 16:9 --wait\n\n# New references: create them from local files or URLs and use them immediately.\nastria video --video-model seedance2_fast_720p \\\n  --video-prompt \"woman wearing a dress walks down a runway\" \\\n  --reference woman=./model.jpg --reference dress=https://example.com/dress.jpg \\\n  --duration 5 --aspect-ratio 16:9 --wait\n\n# Ordered raw references: attach the images directly without creating tunes.\nastria video --video-model seedance2_fast_720p \\\n  --video-prompt \"transition through these looks in order\" \\\n  --image-reference ./look-1.jpg --image-reference ./look-2.jpg \\\n  --duration 15 --aspect-ratio 16:9 --wait\n\nastria video --text \"zwx man <faceid:123:1> in a dance arena\" \\\n  --video-model kling30_motion_control_pro --video-prompt \"match the dance moves\" \\\n  --duration 10 --input-video ./reference.mp4\n```\n\n- Seedance 2 references use `<faceid:TUNE_ID:1> TUNE_NAME`, exactly like image\n  prompts. The tune's class name must immediately follow the token. A bare\n  `<faceid:1234:1>` token is incomplete.\n- Put existing reference mentions in `--video-prompt`; Seedance 2 resolves the\n  referenced tunes' images and sends them as video reference images.\n- `--reference NAME=PATH_OR_URL` creates an instant `faceid` reference and\n  prepends `<faceid:NEW_ID:1> NAME` to both `--text` (when present) and\n  `--video-prompt`. Repeat it for multiple references. `--images` is an alias.\n- `--image-reference PATH_OR_URL` attaches a raw image directly to the video\n  prompt without creating a tune. Repeat it in storyboard order. Use either\n  all local files or all URLs in one request so that ordering remains exact.\n- `--first-frame` / `--last-frame` / `--input-video` accept a URL or local file.\n- Motion-control models (`*_motion_control*`, `wan_animate_*`, `dreamactor_m2`,\n  `happyhorse_motion_control`) require `--input-video`.\n\n### `video_model` values and cost\n\nCosts are per 5-second base (per 10s for motion-control / fixed-duration\nmodels) and scale linearly with duration. `_audio` models include a soundtrack.\n\n| video_model                     | cost (¢)    | duration options |\n|----------------------------------|------------:|------------------|\n| seedance_480p                    |          10 | 2–12             |\n| seedance_v15_720p                |          14 | 4–12             |\n| seedance_v15_audio_720p          |          29 | 4–12             |\n| cinematic_video                  |          84 | 5, 10, 15        |\n| wan25_720p                       |          53 | 5, 10            |\n| wan26_720p / wan26_1080p         |       53/79 | 5, 10, 15        |\n| wan27_720p / wan27_1080p         |       55/83 | 5, 10, 15        |\n| wan_animate_720p                 |          44 | 10               |\n| ltx23_720p / ltx23_1080p         |       17/22 | 5, 10, 15, 20    |\n| happyhorse_720p / _1080p         |      77/132 | 3–10             |\n| happyhorse_motion_control        |         154 | 10               |\n| dreamactor_m2                    |          29 | 10               |\n| seedance2_fast_480p / _720p      |      60/140 | 4–15             |\n| seedance2_480p / _720p / _1080p  | 120/280/450 | 4–15             |\n| veo31_fast_720p / _1080p         |          85 | 4, 6, 8          |\n| veo31_fast_4k                    |         264 | 8                |\n| veo31_lite_720p / _1080p         |       44/71 | 4, 6, 8          |\n| kling30_standard / _pro          |      92/123 | 3–15             |\n| kling30_4k                       |         263 | 3–15             |\n| kling30_motion_control / _pro    |     277/370 | 10               |\n\nVideo output is delivered in the prompt's `images[]` with `content_type=video/mp4`.\n\n## Inspect video\n\nTurn a local video or public HTTPS video URL into timestamped text-to-video\nprompt text. Local files are direct-uploaded to Astria automatically; do not\nupload them separately or build raw API requests.\n\n```bash\nastria inspect-video ./clip.mp4\nastria inspect-video https://example.com/clip.mp4\nastria inspect-video ./clip.mp4 --tune-id 123 --tune-id 456\n```\n\nThe output uses one `SS-SS - description` line per cut for videos up to 30\nseconds. `--tune-id` is repeatable: use it when the resulting generation will\ncarry those references, so inspection removes their appearance details and\ninserts the exact Astria reference tokens. There is intentionally no custom\nprompt option; use the returned `description` as the video prompt.\n\n## Variate video\n\nUse `astria variate` when the user wants to preserve a source video's timing,\nperformance, camera, transitions, and audio while changing its content. The\ncommand runs the Variate mini-app workflow end to end: source inspection,\nreplacement-reference creation, structured prompt writing, and fixed-model\nSeedance 2.5 generation.\n\n```bash\n# Edit from a written brief\nastria variate ./source.mp4 \\\n  --brief 'Change the text on the final card to say \"Astria\"' --wait\n\n# Mix existing references with new local or remote images\nastria variate ./source.mp4 \\\n  --tune-id 123 \\\n  --reference ./dress.jpg \\\n  --reference woman=https://example.com/model.jpg \\\n  --brief 'Replace the presenter and wardrobe' --wait\n\n# Reuse an existing source description and avoid another inspection charge\nastria variate https://example.com/source.mp4 \\\n  --description-file ./source-description.txt \\\n  --brief 'Use a warmer end-card treatment'\n```\n\n- `SOURCE` is a local MP4/MOV or public HTTPS URL.\n- Repeat `--tune-id ID` for existing replacement references.\n- Repeat `--reference [NAME=]PATH_OR_URL` to create replacement references.\n  Without `NAME=`, the CLI detects the image class. With it, detection is\n  skipped. References preserve command order within the existing/new groups.\n- At least one reference or a non-empty `--brief` is required.\n- `--description` / `--description-file` bypass source inspection.\n- The command intentionally fixes `video_model=seedance25_720p`, enables\n  generated audio, and omits duration/aspect ratio so the source drives them.\n- Local source and reference files are direct-uploaded in one parallel batch.\n- The JSON result contains `description`, `references`, `video_prompt`, and\n  `prompt`; add `--wait` to receive the settled generation in `prompt`.\n\n## Download\n\n`astria download` saves a prompt's rendered assets (images, or `video/mp4`) to a\nlocal directory. It works from a **prompt id alone** — no tune id needed — and\nfetches each prompt fresh from the API, so newly rendered assets are included.\n\n```bash\nastria download 555 556 557                       # ids as arguments\nastria download 555 --out ./shoot                  # custom target directory\nastria download --prompts-file ids.txt             # one id per line (or whitespace)\nastria prompts list --pack-id 88 | \\\n  python3 -c 'import sys,json; [print(p[\"id\"]) for p in json.load(sys.stdin)]' | \\\n  astria download                                  # ids piped on stdin\n```\n\n- Prompt ids come from positional args, `--prompts-file`, and/or stdin; they are\n  deduped with original order preserved.\n- `--out` defaults to `./astria-downloads` and is created if missing.\n- Each asset is saved as `prompt-<id>-<NN><ext>` — `<NN>` is a zero-padded\n  index, `<ext>` is derived from the URL (`.jpg`/`.png`/`.webp`/`.mp4`/…).\n- Downloads run in parallel (~6 at a time).\n- A prompt that 404s, errors, or has no images yet is reported in the JSON\n  output (`error` field) and does not abort the run.\n- The JSON summary lists per prompt `{id, images, saved[], error?}` plus\n  `totals {prompts, downloaded, failed}`.\n\n## Packs\n\nPacks are surfaced in the Astria GUI as **Templates** — \"pack\" and \"template\" are interchangeable terms for the same object.\n\n```bash\nastria packs list\nastria packs get spring-lookbook\nastria packs create --title \"Spring Lookbook\"\nastria prompts update 555 --model nano-banana-pro --pack-id 88   # add a prompt to the pack\n```\n\n## Pricing\n\n`cost_mc` is an integer number of **millicents** (one thousandth of a US cent):\n\n- 1,000 `cost_mc` = $0.01\n- 100,000 `cost_mc` = $1.00\n- Convert to dollars with `cost_mc / 100_000`.\n\nA prompt's `cost_mc` already includes its `num_images`; never multiply by\n`num_images` again. Sum `cost_mc` across prompt records to price a prompt batch.\nFor example, prompts priced at 12,500 and 25,000 `cost_mc` total 37,500\nmillicents, or **$0.375**.\n\nUse `astria packs get <slug|id>` before running a pack:\n\n- `template_prompts[].cost_mc` is each stored template prompt's baseline. Sum\n  all entries for the full stored baseline, or selected entries for a\n  `--prompt-ids` subset.\n- `costs.<class>.cost_mc` estimates a fresh reference tune of that class plus\n  that class's prompt group. For multi-class packs it is not necessarily the\n  cost of the entire pack.\n\nThese are estimates, not personalized quotes. Generated prompts recalculate\ncost after prompt overrides; creator discounts, the payer's ecommerce pricing,\nworkspace rules, and Cartesian tune variants can change the result.\n\nAfter `astria packs run`, use `order.total_cost_mc` as the authoritative amount\ncharged when an order is returned. If no order is returned, the generated\nprompts' `cost_mc` values describe their individual base costs.\n\n### Run a pack\n\n`astria packs run <slug|id>` fires a pack's template prompts —\n`POST /p/:slug/tunes`. This is the canonical \"run a template\": the pack\ngenerates its whole prompt set, either against **tunes you already have** or\nagainst a **fresh tune trained from photos**. The positional accepts either the\npack **slug** or its numeric **id** — `astria packs run zara-pants …` and\n`astria packs run 3893 …` are equivalent.\n\n```bash\n# multi packs — run against existing tunes (tune_ids), with overrides\nastria packs run spring-lookbook --tune-id 123 --tune-id 456 \\\n  --brief \"golden hour, Lisbon\" --aspect-ratio 3:4 --inpaint-faces\n\n# only a subset of the pack's template prompts\nastria packs run spring-lookbook --tune-id 123 --prompt-ids 501,502\n\n# regular packs — train a fresh tune from photos, then generate\nastria packs run my-pack --title Jane --name woman \\\n  --image ./a.jpg --image ./b.jpg          # or --image-url https://…\n```\n\n- **Who the pack runs on** — pass either `--tune-id ID` (repeatable, or a\n  comma-separated list) to reuse existing tunes, **or** a training set\n  (`--title` + `--name` + `--image`/`--image-url`) to train a new tune first.\n  **Multi packs require at least one `--tune-id`** (the server routes tune_ids\n  to its multi handler; omitting them on a multi pack is a 422).\n- `--prompt-ids 501,502` runs only that subset of the pack's template prompts;\n  omit it to run them all.\n- `--brief` is an art-direction brief applied to the generated prompts.\n- **Overrides** ride along as `prompt_attributes`: `--num-images`,\n  `--aspect-ratio`, `--resolution`, `--inpaint-faces/--no-inpaint-faces`, and\n  `--attr KEY=VALUE` (repeatable) for any other prompt attribute, e.g.\n  `--attr super_resolution=true`.\n- The positional is the pack **slug or numeric id** — both resolve to the same\n  `/p/:slug/tunes` endpoint. On a multi pack the JSON response includes the new\n  `order` and its `prompt_ids` — feed those to `astria prompts wait` and\n  `astria download` to fetch the images.\n\n#### Worked example — a multi pack, step by step\n\n`zara-boot-test` (id `4001`) is a **multi pack** that composes two references —\na `dress` and a `shoes` (Footwear) — into one shoot. Create a reference per\ngarment, then run the pack against both by id. Scope every step to a workspace\nwith `-w` (find yours with `astria workspaces list`).\n\n```bash\n# 1. Create a reference for the dress (Gemini branch — instant, no training wait)\nastria tunes create -w 679 --name dress --title \"Zara dress\" --image ./dress.jpg\n# → { \"id\": 5234832, \"branch\": \"gemini-2\", \"trained_at\": \"...\" }\n\n# 2. Create a SEPARATE reference for the boots.\n#    Use a class the pack's slot recognizes: 'boots' (like 'shoes'/'sandals')\n#    resolves to the Footwear cube, so it fills the pack's shoes slot.\nastria tunes create -w 679 --name boots --title \"Zara boots\" --image ./boot.jpg\n# → { \"id\": 5234834, \"branch\": \"gemini-2\", \"trained_at\": \"...\" }\n\n# 3. Run the pack against both references — one --tune-id each.\n#    'zara-boot-test' or its id '4001' are interchangeable here.\nastria packs run zara-boot-test -w 679 \\\n  --tune-id 5234832 --tune-id 5234834 --num-images 1 --aspect-ratio 3:4\n# → { \"status\": 201, \"order\": { \"id\": 37345, \"tune_ids\": [5234834, 5234832] },\n#     \"prompt_ids\": [45042524, 45042523] }\n\n# 4. Fetch the results (the order hands back the prompt ids)\nastria prompts wait -w 679 45042524 45042523              # block until rendered (or user_error)\nastria download 45042524 45042523 --out ./zara-boot-shoot\n```\n\nThe pack swaps each reference into the matching template slot by lookbook cube,\nso the generated prompts come back with both tokens recorded, e.g.\n`a model wearing <faceid:5234832:1> dress and <faceid:5234834:1> boots, …`\n(and the shoes-only template gets just the boots token). The overrides land as\nprompt attributes (`aspect_ratio: 3:4`, `num_images: 1`).\n\nGemini-branch references (step 1–2) are ready instantly; a pack built on trained\ntunes queues its prompts and renders them once the tunes finish training. Pass\none `--tune-id` per reference slot the pack defines — a multi pack needs at\nleast one, and rejects the run (422) if you send none.\n\n## Board (infinite canvas)\n\nThe board (`/boards/:id` in the GUI) organizes work as **frames** (a pack-bound working context), **order rows** (one Order = a line of prompts sharing one reference set) and **reference cards** (tunes with lookbook roles: Pose, Face, Accessories, Jacket, Top, Bags & Belts, Footwear, Bottom, Background). There is no board API and no `board` verb — you act on the regular domain objects with the verbs above, and the canvas updates live (new rows land via the `order.created` broadcast, cells re-render as prompts finish).\n\n```bash\nastria packs run 88 --tune-id 123 --tune-id 456 \\\n    --prompt-ids 501,502 --brief \"golden hour, Lisbon\"  # new row: clone the pack's templates with swapped refs\nastria prompts wait 7001 7002 && astria download 7001 7002   # wait for the row's cells, fetch images\nastria generate --text \"...\" --base-pack-id 88       # one-off into pack 88's frame (free row, not a template)\n# variant with edited text (stacks as a version on its cell; order_id from `astria prompts get`):\nastria api POST /prompts/7001/duplicate --query view=board --data '{\"prompt\":{\"text\":\"...\",\"order_id\":901}}'\n# promote a prompt into the pack template / demote a template back out (confirm with the user first):\nastria api PATCH /prompts/7001 --query view=board --data '{\"prompt\":{\"pack_id\":88,\"base_pack_id\":null,\"orig_prompt_id\":null}}'\nastria api PATCH /prompts/7001 --query view=board --data '{\"prompt\":{\"pack_id\":null,\"base_pack_id\":88}}'\n```\n\nFor an ordered raw-image video, pass the selected images directly with repeated\n`astria video --image-reference PATH_OR_URL` options. Do not create temporary\ntunes for those images.\n\n## Workspaces & landing pages\n\n```bash\nastria workspaces list\nastria workspaces create --title \"Acme Store\"   # new workspace → returns its id/slug\nastria landing get -w 42                        # workspace JSON incl. landing_page_html\nastria landing set -w 42 --html-file ./edited.html\n```\n\n## Hand work into Astria’s embedded agent\n\nWhen the user asks to continue the current ChatGPT, Codex, Claude, or Cursor\nsession in Astria, write a concise UTF-8 `HANDOFF.md` containing the objective,\ncompleted work, important decisions, artifact paths, unresolved issues, and the\nrecommended next action. Do not include credentials or hidden reasoning.\n\nAttach only files needed to continue. Include a custom skill only when it was\nactually used or is needed for the remaining work; never export credential\nfiles or an entire agent configuration directory.\n\n```bash\nastria agent handoff -w 42 \\\n  --handoff ./HANDOFF.md \\\n  --attach ./deliverables \\\n  --skill ~/.claude/skills/relevant-skill \\\n  --source claude-code \\\n  --open\n```\n\n`--attach` and `--skill` are repeatable. A skill path must be a directory with\n`SKILL.md`. The command uploads the versioned bundle, creates a dedicated chat\nsession, prints its HTTPS deep link, and opens it with `--open`. Imported skills\nare reviewable session-scoped references; Astria does not silently install them\ninto the shared workspace skill directory.\n\n## Raw API escape hatch\n\nFor anything without a dedicated verb:\n\n```bash\nastria api GET /prompts --query limit=5 --query offset=0\nastria api POST /tunes --form 'tune[title]=Hat' --form 'tune[images][]=@./hat.jpg'\n```\n\n## Pagination\n\nList commands accept `--limit N` and `--offset Y`. Default sort is id\ndescending, so `--offset` walks backwards through history.\n\n## Errors\n\nA non-zero exit prints `astria: <METHOD> <PATH> → HTTP <code>: <message>` on\nstderr. Surface the message to the user and suggest a fix. HTTP 422 means a\nvalidation error (missing/invalid fields).\n"

SKILL.md line diff

--- before
+++ after
@@ -120,6 +120,33 @@
   `--user-id`, `--orig-prompt-id`, `--text`, and the flags `--liked`,
   `--today`, `--is-video`, `--is-api`.
 
+### Image review comments
+
+Request image comments with the repeatable `--expand` option:
+
+```bash
+astria prompts list -w 17 --expand prompt.comments --limit 100
+astria prompts get 555 -w 17 --tune 123 --expand prompt.comments
+astria prompts get 555 -w 17 --tune 123 --expand comments --expand prompt.debug_images
+astria api GET /prompts -w 17 --query 'expand[]=prompt.comments'
+astria api GET /tunes/123/prompts/555 -w 17 --query 'expand[]=comments'
+```
+
+`comments` is an alias for `prompt.comments`. The API also accepts the scalar
+query `expand=prompt.comments`, or repeated `expand[]` values to combine
+expansions. Without this expansion, responses omit the `comments` field.
+
+Each prompt returns a flat `comments` array, oldest first, containing both open
+and resolved comments on its available images. Each entry includes `id`,
+`body`, `author`, `author_avatar_url`, `created_at`, `resolved_at`, `resolved_by`,
+`workspace_id`, `prompt_id`, `attachment_id`, `blob_id`, `image_url`, `filename`,
+and `image_review_id`. Use `blob_id` or `attachment_id` to associate a comment
+with an image, and `resolved_at` to determine whether it is resolved.
+
+Comments are limited to workspaces the authenticated account belongs to. Use
+`prompts list --expand prompt.comments` to retrieve comments for a page in one
+request instead of fetching each image separately.
+
 ## Generate images
 
 ```bash
Full snapshot data
{
  "description": "Use when making API calls to Astria for tunes, prompts, packs, image/video generation (Gemini/Seedream), inspecting or variating videos, handing an external agent session into Astria, or estimating generation and pack pricing. The reference for the `astria` CLI.",
  "included_files": [],
  "name": "astria-api",
  "skill_md_contents": "---\nname: astria-api\ndescription: Use when making API calls to Astria for tunes, prompts, packs, image/video generation (Gemini/Seedream), inspecting or variating videos, handing an external agent session into Astria, or estimating generation and pack pricing. The reference for the `astria` CLI.\nallowed-tools: Bash(astria:*)\n---\n\n# Astria CLI Reference\n\nAll Astria operations go through the bundled **`astria`** command-line tool. It\nhandles authentication, the API base URL, and workspace scoping for you — never\nbuild raw `curl` calls and never read API tokens from environment variables.\n\nOutput is JSON on stdout, so you can parse ids and image URLs directly.\n\n## Authentication\n\n`astria` resolves credentials automatically:\n1. Environment variables, if present (the Astria web app injects these).\n2. `~/.astria/config.json`, written by `astria login`.\n\nIf a command fails with *\"not authenticated\"*, tell the user to run:\n\n```bash\nastria login          # prompts for an API key (astria.ai/users/edit/api)\n```\n\nCheck the active account any time with `astria whoami`.\n\n## Profiles\n\nProfiles work like the AWS CLI — keep separate credentials, base URL and\nworkspace per profile (e.g. production vs a local dev server):\n\n```bash\nastria --profile localhost login --base-url http://localhost:3000\nastria --profile localhost generate --text \"...\"\nASTRIA_PROFILE=localhost astria tunes list       # env-var form\n```\n\n`--profile <name>` (before the subcommand) or the `ASTRIA_PROFILE` env var\nselects it. Each profile is its own file — `~/.astria/config.<name>.json`; the\ndefault profile stays at `~/.astria/config.json`.\n\n## Tune reference syntax\n\nThe core concept. A **tune** is a fine-tuned model trained on user images —\n\"tune\" and \"reference\" mean the same thing. Reference a tune inside prompt text\nwith `<model_type:id:1> name`:\n\n- `model_type` and `id` come from the tune JSON (`astria tunes get <id>`)\n- `name` is the tune's class name and MUST appear right after the `<...>` token\n- the trailing `:1` is a fixed part of the token syntax — it is NOT a weight or strength. Always write `:1`; never vary it and never suggest changing it.\n- Combine freely: `<faceid:123:1> woman wearing <faceid:456:1> dress, white studio background`\n\n`<faceid:123:1> woman` is correct; `John` (a bare name the model never trained on) is wrong.\n\n## Workspace scoping\n\nAdd `-w/--workspace` to any command:\n- `-w <id>` — target a specific workspace\n- `-w all` — query across every workspace\n- omit it — uses `WORKSPACE_ID`/config default, or personal scope\n\n## Models\n\n`--model` accepts a model name or a raw tune id. **Don't hardcode model\nnames — discover the current catalog at runtime:**\n\n```bash\nastria models              # image + video models — name, title, tune id, resolutions\nastria models --refresh    # force-refresh (otherwise cached for a day)\n```\n\nThe catalog is fetched from the Astria server, so it stays current as models\nare added or retired and the tune ids never go stale. The output marks the\n`default` model (used when `--model` is omitted) and lists each model's\nsupported `--resolution` values — a model with no resolutions listed doesn't\naccept `--resolution`. It also lists the `video_models` catalog and the\n`default_video_model` used by `astria video`.\n\n`astria generate` / `astria video` `--help` print the current model,\nresolution and video-model names inline — they read the same cached catalog.\n\n---\n\n## Tunes / references\n\n```bash\nastria tunes list                              # all tunes\nastria tunes list --title \"brown dress\"        # by title / product name / SKU\nastria tunes list --name shoes --name sandals  # by class name (repeatable)\nastria tunes list --gallery --model-type faceid --limit 200   # public gallery\nastria tunes get 123\nastria tunes create --title \"Brown dress\" --name dress \\\n  --description \"satin brown dress\" \\\n  --image-url https://example.com/a.jpg --image-url https://example.com/b.jpg\nastria tunes create --title \"Studio shot\" --name woman --image ./face1.jpg --image ./face2.jpg\nastria tunes update 123 --name ring --title \"Gold ring\"\n```\n\n`tunes create` takes `--image-url` (remote) and/or `--image` (local file),\nboth repeatable. `--name` is the subject class (man, woman, dress, shoes,\nsandals, pose, …). `--model-type` defaults to `faceid`.\n\n## Prompts\n\n```bash\nastria prompts list                            # recent prompts\nastria prompts list --pack-id 88               # a pack's template prompts\nastria prompts list --tune-id 123              # prompts for one tune\nastria prompts list --liked --is-video         # liked video prompts\nastria prompts list --today --limit 100        # prompts created today\nastria prompts list --text \"white background\" --limit 100 --offset 0\nastria prompts get 555 --model nano-banana-pro       # one prompt (needs its tune/model)\nastria prompts update 555 --model nano-banana-pro --pack-id 88   # assign a prompt to a pack\nastria prompts update 555 --model nano-banana-pro --base-pack-id 88   # bind as a pack one-off (board frame)\n```\n\n- `prompts list` filters: `--pack-id`, `--base-pack-id`, `--tune-id`,\n  `--user-id`, `--orig-prompt-id`, `--text`, and the flags `--liked`,\n  `--today`, `--is-video`, `--is-api`.\n\n### Image review comments\n\nRequest image comments with the repeatable `--expand` option:\n\n```bash\nastria prompts list -w 17 --expand prompt.comments --limit 100\nastria prompts get 555 -w 17 --tune 123 --expand prompt.comments\nastria prompts get 555 -w 17 --tune 123 --expand comments --expand prompt.debug_images\nastria api GET /prompts -w 17 --query 'expand[]=prompt.comments'\nastria api GET /tunes/123/prompts/555 -w 17 --query 'expand[]=comments'\n```\n\n`comments` is an alias for `prompt.comments`. The API also accepts the scalar\nquery `expand=prompt.comments`, or repeated `expand[]` values to combine\nexpansions. Without this expansion, responses omit the `comments` field.\n\nEach prompt returns a flat `comments` array, oldest first, containing both open\nand resolved comments on its available images. Each entry includes `id`,\n`body`, `author`, `author_avatar_url`, `created_at`, `resolved_at`, `resolved_by`,\n`workspace_id`, `prompt_id`, `attachment_id`, `blob_id`, `image_url`, `filename`,\nand `image_review_id`. Use `blob_id` or `attachment_id` to associate a comment\nwith an image, and `resolved_at` to determine whether it is resolved.\n\nComments are limited to workspaces the authenticated account belongs to. Use\n`prompts list --expand prompt.comments` to retrieve comments for a page in one\nrequest instead of fetching each image separately.\n\n## Generate images\n\n```bash\nastria generate --text \"<faceid:123:1> woman, clean white studio background\"\nastria generate --model nano-banana-pro --text \"...\" --num-images 4 --aspect-ratio 3:4 --resolution 2K\nastria generate --model seedream --text \"product photo of headphones on marble\" --num-images 2\nastria generate --text \"cinematic portrait\" --film-grain\nastria generate --text \"recreate this in 4K\" --input-image https://example.com/photo.jpg\nastria generate --text \"<faceid:123:1> woman, white bg\" --pack-id 88 --wait   # author a pack template prompt\nastria generate --text \"...\" --base-pack-id 88       # one-off bound to pack 88 — lands in its board frame\n```\n\n- `--input-image` accepts a URL or a local file path (used for image editing/upscaling).\n- `--film-grain` sends film grain as a separate prompt attribute and leaves\n  `--text` unchanged. `--film_grain` is an alias; `--no-film-grain` explicitly\n  disables it.\n- `--pack-id` authors the prompt as a pack **template** prompt; `--base-pack-id`\n  records pack provenance only (a one-off). On the board, `--base-pack-id`\n  generations appear as free rows inside that pack's frame.\n- A `--pack-id` template prompt must **reference a fine-tuned tune** — embed a\n  `<faceid:ID:1>` (or `<lora:ID:1>` …) token in `--text`. A plain foundation-model\n  prompt with no reference is rejected (HTTP 422, \"Prompt is not using a fine-tuned\n  model\"). `--base-pack-id` one-offs have no such requirement.\n- `--wait` polls until the images are ready and prints the finished prompt JSON.\n  Without it, the command returns immediately — images render asynchronously.\n- `aspect_ratio` values: `1:1 16:9 9:16 21:9 9:21 3:2 2:3 5:4 4:5 4:3`.\n- `--seed` sets the generation seed. Astria dedups prompts by `(text, seed)`\n  within a tune, so the same prompt text reused on different input images\n  collapses onto one prompt — pass a distinct `--seed` per call to keep them\n  separate without altering the prompt text.\n\n## Generate video\n\nVideo runs through the same prompt: the image stage renders the first frame\nfrom `--text`, then the video model animates it from `--video-prompt`.\n\n```bash\n# Existing reference: use the same token + tune-name syntax as image generation.\n# Put Seedance 2 references in --video-prompt so their images condition the video.\nastria video --video-model seedance2_fast_720p \\\n  --video-prompt \"<faceid:1234:1> woman walks down a runway as the camera tracks her\" \\\n  --duration 5 --aspect-ratio 16:9 --wait\n\n# New references: create them from local files or URLs and use them immediately.\nastria video --video-model seedance2_fast_720p \\\n  --video-prompt \"woman wearing a dress walks down a runway\" \\\n  --reference woman=./model.jpg --reference dress=https://example.com/dress.jpg \\\n  --duration 5 --aspect-ratio 16:9 --wait\n\n# Ordered raw references: attach the images directly without creating tunes.\nastria video --video-model seedance2_fast_720p \\\n  --video-prompt \"transition through these looks in order\" \\\n  --image-reference ./look-1.jpg --image-reference ./look-2.jpg \\\n  --duration 15 --aspect-ratio 16:9 --wait\n\nastria video --text \"zwx man <faceid:123:1> in a dance arena\" \\\n  --video-model kling30_motion_control_pro --video-prompt \"match the dance moves\" \\\n  --duration 10 --input-video ./reference.mp4\n```\n\n- Seedance 2 references use `<faceid:TUNE_ID:1> TUNE_NAME`, exactly like image\n  prompts. The tune's class name must immediately follow the token. A bare\n  `<faceid:1234:1>` token is incomplete.\n- Put existing reference mentions in `--video-prompt`; Seedance 2 resolves the\n  referenced tunes' images and sends them as video reference images.\n- `--reference NAME=PATH_OR_URL` creates an instant `faceid` reference and\n  prepends `<faceid:NEW_ID:1> NAME` to both `--text` (when present) and\n  `--video-prompt`. Repeat it for multiple references. `--images` is an alias.\n- `--image-reference PATH_OR_URL` attaches a raw image directly to the video\n  prompt without creating a tune. Repeat it in storyboard order. Use either\n  all local files or all URLs in one request so that ordering remains exact.\n- `--first-frame` / `--last-frame` / `--input-video` accept a URL or local file.\n- Motion-control models (`*_motion_control*`, `wan_animate_*`, `dreamactor_m2`,\n  `happyhorse_motion_control`) require `--input-video`.\n\n### `video_model` values and cost\n\nCosts are per 5-second base (per 10s for motion-control / fixed-duration\nmodels) and scale linearly with duration. `_audio` models include a soundtrack.\n\n| video_model                     | cost (¢)    | duration options |\n|----------------------------------|------------:|------------------|\n| seedance_480p                    |          10 | 2–12             |\n| seedance_v15_720p                |          14 | 4–12             |\n| seedance_v15_audio_720p          |          29 | 4–12             |\n| cinematic_video                  |          84 | 5, 10, 15        |\n| wan25_720p                       |          53 | 5, 10            |\n| wan26_720p / wan26_1080p         |       53/79 | 5, 10, 15        |\n| wan27_720p / wan27_1080p         |       55/83 | 5, 10, 15        |\n| wan_animate_720p                 |          44 | 10               |\n| ltx23_720p / ltx23_1080p         |       17/22 | 5, 10, 15, 20    |\n| happyhorse_720p / _1080p         |      77/132 | 3–10             |\n| happyhorse_motion_control        |         154 | 10               |\n| dreamactor_m2                    |          29 | 10               |\n| seedance2_fast_480p / _720p      |      60/140 | 4–15             |\n| seedance2_480p / _720p / _1080p  | 120/280/450 | 4–15             |\n| veo31_fast_720p / _1080p         |          85 | 4, 6, 8          |\n| veo31_fast_4k                    |         264 | 8                |\n| veo31_lite_720p / _1080p         |       44/71 | 4, 6, 8          |\n| kling30_standard / _pro          |      92/123 | 3–15             |\n| kling30_4k                       |         263 | 3–15             |\n| kling30_motion_control / _pro    |     277/370 | 10               |\n\nVideo output is delivered in the prompt's `images[]` with `content_type=video/mp4`.\n\n## Inspect video\n\nTurn a local video or public HTTPS video URL into timestamped text-to-video\nprompt text. Local files are direct-uploaded to Astria automatically; do not\nupload them separately or build raw API requests.\n\n```bash\nastria inspect-video ./clip.mp4\nastria inspect-video https://example.com/clip.mp4\nastria inspect-video ./clip.mp4 --tune-id 123 --tune-id 456\n```\n\nThe output uses one `SS-SS - description` line per cut for videos up to 30\nseconds. `--tune-id` is repeatable: use it when the resulting generation will\ncarry those references, so inspection removes their appearance details and\ninserts the exact Astria reference tokens. There is intentionally no custom\nprompt option; use the returned `description` as the video prompt.\n\n## Variate video\n\nUse `astria variate` when the user wants to preserve a source video's timing,\nperformance, camera, transitions, and audio while changing its content. The\ncommand runs the Variate mini-app workflow end to end: source inspection,\nreplacement-reference creation, structured prompt writing, and fixed-model\nSeedance 2.5 generation.\n\n```bash\n# Edit from a written brief\nastria variate ./source.mp4 \\\n  --brief 'Change the text on the final card to say \"Astria\"' --wait\n\n# Mix existing references with new local or remote images\nastria variate ./source.mp4 \\\n  --tune-id 123 \\\n  --reference ./dress.jpg \\\n  --reference woman=https://example.com/model.jpg \\\n  --brief 'Replace the presenter and wardrobe' --wait\n\n# Reuse an existing source description and avoid another inspection charge\nastria variate https://example.com/source.mp4 \\\n  --description-file ./source-description.txt \\\n  --brief 'Use a warmer end-card treatment'\n```\n\n- `SOURCE` is a local MP4/MOV or public HTTPS URL.\n- Repeat `--tune-id ID` for existing replacement references.\n- Repeat `--reference [NAME=]PATH_OR_URL` to create replacement references.\n  Without `NAME=`, the CLI detects the image class. With it, detection is\n  skipped. References preserve command order within the existing/new groups.\n- At least one reference or a non-empty `--brief` is required.\n- `--description` / `--description-file` bypass source inspection.\n- The command intentionally fixes `video_model=seedance25_720p`, enables\n  generated audio, and omits duration/aspect ratio so the source drives them.\n- Local source and reference files are direct-uploaded in one parallel batch.\n- The JSON result contains `description`, `references`, `video_prompt`, and\n  `prompt`; add `--wait` to receive the settled generation in `prompt`.\n\n## Download\n\n`astria download` saves a prompt's rendered assets (images, or `video/mp4`) to a\nlocal directory. It works from a **prompt id alone** — no tune id needed — and\nfetches each prompt fresh from the API, so newly rendered assets are included.\n\n```bash\nastria download 555 556 557                       # ids as arguments\nastria download 555 --out ./shoot                  # custom target directory\nastria download --prompts-file ids.txt             # one id per line (or whitespace)\nastria prompts list --pack-id 88 | \\\n  python3 -c 'import sys,json; [print(p[\"id\"]) for p in json.load(sys.stdin)]' | \\\n  astria download                                  # ids piped on stdin\n```\n\n- Prompt ids come from positional args, `--prompts-file`, and/or stdin; they are\n  deduped with original order preserved.\n- `--out` defaults to `./astria-downloads` and is created if missing.\n- Each asset is saved as `prompt-<id>-<NN><ext>` — `<NN>` is a zero-padded\n  index, `<ext>` is derived from the URL (`.jpg`/`.png`/`.webp`/`.mp4`/…).\n- Downloads run in parallel (~6 at a time).\n- A prompt that 404s, errors, or has no images yet is reported in the JSON\n  output (`error` field) and does not abort the run.\n- The JSON summary lists per prompt `{id, images, saved[], error?}` plus\n  `totals {prompts, downloaded, failed}`.\n\n## Packs\n\nPacks are surfaced in the Astria GUI as **Templates** — \"pack\" and \"template\" are interchangeable terms for the same object.\n\n```bash\nastria packs list\nastria packs get spring-lookbook\nastria packs create --title \"Spring Lookbook\"\nastria prompts update 555 --model nano-banana-pro --pack-id 88   # add a prompt to the pack\n```\n\n## Pricing\n\n`cost_mc` is an integer number of **millicents** (one thousandth of a US cent):\n\n- 1,000 `cost_mc` = $0.01\n- 100,000 `cost_mc` = $1.00\n- Convert to dollars with `cost_mc / 100_000`.\n\nA prompt's `cost_mc` already includes its `num_images`; never multiply by\n`num_images` again. Sum `cost_mc` across prompt records to price a prompt batch.\nFor example, prompts priced at 12,500 and 25,000 `cost_mc` total 37,500\nmillicents, or **$0.375**.\n\nUse `astria packs get <slug|id>` before running a pack:\n\n- `template_prompts[].cost_mc` is each stored template prompt's baseline. Sum\n  all entries for the full stored baseline, or selected entries for a\n  `--prompt-ids` subset.\n- `costs.<class>.cost_mc` estimates a fresh reference tune of that class plus\n  that class's prompt group. For multi-class packs it is not necessarily the\n  cost of the entire pack.\n\nThese are estimates, not personalized quotes. Generated prompts recalculate\ncost after prompt overrides; creator discounts, the payer's ecommerce pricing,\nworkspace rules, and Cartesian tune variants can change the result.\n\nAfter `astria packs run`, use `order.total_cost_mc` as the authoritative amount\ncharged when an order is returned. If no order is returned, the generated\nprompts' `cost_mc` values describe their individual base costs.\n\n### Run a pack\n\n`astria packs run <slug|id>` fires a pack's template prompts —\n`POST /p/:slug/tunes`. This is the canonical \"run a template\": the pack\ngenerates its whole prompt set, either against **tunes you already have** or\nagainst a **fresh tune trained from photos**. The positional accepts either the\npack **slug** or its numeric **id** — `astria packs run zara-pants …` and\n`astria packs run 3893 …` are equivalent.\n\n```bash\n# multi packs — run against existing tunes (tune_ids), with overrides\nastria packs run spring-lookbook --tune-id 123 --tune-id 456 \\\n  --brief \"golden hour, Lisbon\" --aspect-ratio 3:4 --inpaint-faces\n\n# only a subset of the pack's template prompts\nastria packs run spring-lookbook --tune-id 123 --prompt-ids 501,502\n\n# regular packs — train a fresh tune from photos, then generate\nastria packs run my-pack --title Jane --name woman \\\n  --image ./a.jpg --image ./b.jpg          # or --image-url https://…\n```\n\n- **Who the pack runs on** — pass either `--tune-id ID` (repeatable, or a\n  comma-separated list) to reuse existing tunes, **or** a training set\n  (`--title` + `--name` + `--image`/`--image-url`) to train a new tune first.\n  **Multi packs require at least one `--tune-id`** (the server routes tune_ids\n  to its multi handler; omitting them on a multi pack is a 422).\n- `--prompt-ids 501,502` runs only that subset of the pack's template prompts;\n  omit it to run them all.\n- `--brief` is an art-direction brief applied to the generated prompts.\n- **Overrides** ride along as `prompt_attributes`: `--num-images`,\n  `--aspect-ratio`, `--resolution`, `--inpaint-faces/--no-inpaint-faces`, and\n  `--attr KEY=VALUE` (repeatable) for any other prompt attribute, e.g.\n  `--attr super_resolution=true`.\n- The positional is the pack **slug or numeric id** — both resolve to the same\n  `/p/:slug/tunes` endpoint. On a multi pack the JSON response includes the new\n  `order` and its `prompt_ids` — feed those to `astria prompts wait` and\n  `astria download` to fetch the images.\n\n#### Worked example — a multi pack, step by step\n\n`zara-boot-test` (id `4001`) is a **multi pack** that composes two references —\na `dress` and a `shoes` (Footwear) — into one shoot. Create a reference per\ngarment, then run the pack against both by id. Scope every step to a workspace\nwith `-w` (find yours with `astria workspaces list`).\n\n```bash\n# 1. Create a reference for the dress (Gemini branch — instant, no training wait)\nastria tunes create -w 679 --name dress --title \"Zara dress\" --image ./dress.jpg\n# → { \"id\": 5234832, \"branch\": \"gemini-2\", \"trained_at\": \"...\" }\n\n# 2. Create a SEPARATE reference for the boots.\n#    Use a class the pack's slot recognizes: 'boots' (like 'shoes'/'sandals')\n#    resolves to the Footwear cube, so it fills the pack's shoes slot.\nastria tunes create -w 679 --name boots --title \"Zara boots\" --image ./boot.jpg\n# → { \"id\": 5234834, \"branch\": \"gemini-2\", \"trained_at\": \"...\" }\n\n# 3. Run the pack against both references — one --tune-id each.\n#    'zara-boot-test' or its id '4001' are interchangeable here.\nastria packs run zara-boot-test -w 679 \\\n  --tune-id 5234832 --tune-id 5234834 --num-images 1 --aspect-ratio 3:4\n# → { \"status\": 201, \"order\": { \"id\": 37345, \"tune_ids\": [5234834, 5234832] },\n#     \"prompt_ids\": [45042524, 45042523] }\n\n# 4. Fetch the results (the order hands back the prompt ids)\nastria prompts wait -w 679 45042524 45042523              # block until rendered (or user_error)\nastria download 45042524 45042523 --out ./zara-boot-shoot\n```\n\nThe pack swaps each reference into the matching template slot by lookbook cube,\nso the generated prompts come back with both tokens recorded, e.g.\n`a model wearing <faceid:5234832:1> dress and <faceid:5234834:1> boots, …`\n(and the shoes-only template gets just the boots token). The overrides land as\nprompt attributes (`aspect_ratio: 3:4`, `num_images: 1`).\n\nGemini-branch references (step 1–2) are ready instantly; a pack built on trained\ntunes queues its prompts and renders them once the tunes finish training. Pass\none `--tune-id` per reference slot the pack defines — a multi pack needs at\nleast one, and rejects the run (422) if you send none.\n\n## Board (infinite canvas)\n\nThe board (`/boards/:id` in the GUI) organizes work as **frames** (a pack-bound working context), **order rows** (one Order = a line of prompts sharing one reference set) and **reference cards** (tunes with lookbook roles: Pose, Face, Accessories, Jacket, Top, Bags & Belts, Footwear, Bottom, Background). There is no board API and no `board` verb — you act on the regular domain objects with the verbs above, and the canvas updates live (new rows land via the `order.created` broadcast, cells re-render as prompts finish).\n\n```bash\nastria packs run 88 --tune-id 123 --tune-id 456 \\\n    --prompt-ids 501,502 --brief \"golden hour, Lisbon\"  # new row: clone the pack's templates with swapped refs\nastria prompts wait 7001 7002 && astria download 7001 7002   # wait for the row's cells, fetch images\nastria generate --text \"...\" --base-pack-id 88       # one-off into pack 88's frame (free row, not a template)\n# variant with edited text (stacks as a version on its cell; order_id from `astria prompts get`):\nastria api POST /prompts/7001/duplicate --query view=board --data '{\"prompt\":{\"text\":\"...\",\"order_id\":901}}'\n# promote a prompt into the pack template / demote a template back out (confirm with the user first):\nastria api PATCH /prompts/7001 --query view=board --data '{\"prompt\":{\"pack_id\":88,\"base_pack_id\":null,\"orig_prompt_id\":null}}'\nastria api PATCH /prompts/7001 --query view=board --data '{\"prompt\":{\"pack_id\":null,\"base_pack_id\":88}}'\n```\n\nFor an ordered raw-image video, pass the selected images directly with repeated\n`astria video --image-reference PATH_OR_URL` options. Do not create temporary\ntunes for those images.\n\n## Workspaces & landing pages\n\n```bash\nastria workspaces list\nastria workspaces create --title \"Acme Store\"   # new workspace → returns its id/slug\nastria landing get -w 42                        # workspace JSON incl. landing_page_html\nastria landing set -w 42 --html-file ./edited.html\n```\n\n## Hand work into Astria’s embedded agent\n\nWhen the user asks to continue the current ChatGPT, Codex, Claude, or Cursor\nsession in Astria, write a concise UTF-8 `HANDOFF.md` containing the objective,\ncompleted work, important decisions, artifact paths, unresolved issues, and the\nrecommended next action. Do not include credentials or hidden reasoning.\n\nAttach only files needed to continue. Include a custom skill only when it was\nactually used or is needed for the remaining work; never export credential\nfiles or an entire agent configuration directory.\n\n```bash\nastria agent handoff -w 42 \\\n  --handoff ./HANDOFF.md \\\n  --attach ./deliverables \\\n  --skill ~/.claude/skills/relevant-skill \\\n  --source claude-code \\\n  --open\n```\n\n`--attach` and `--skill` are repeatable. A skill path must be a directory with\n`SKILL.md`. The command uploads the versioned bundle, creates a dedicated chat\nsession, prints its HTTPS deep link, and opens it with `--open`. Imported skills\nare reviewable session-scoped references; Astria does not silently install them\ninto the shared workspace skill directory.\n\n## Raw API escape hatch\n\nFor anything without a dedicated verb:\n\n```bash\nastria api GET /prompts --query limit=5 --query offset=0\nastria api POST /tunes --form 'tune[title]=Hat' --form 'tune[images][]=@./hat.jpg'\n```\n\n## Pagination\n\nList commands accept `--limit N` and `--offset Y`. Default sort is id\ndescending, so `--offset` walks backwards through history.\n\n## Errors\n\nA non-zero exit prints `astria: <METHOD> <PATH> → HTTP <code>: <message>` on\nstderr. Surface the message to the user and suggest a fix. HTTP 422 means a\nvalidation error (missing/invalid fields).\n"
}

SHA-256 of public snapshot: 441cae4af34a5e5fe868181339d39f7753e807f2da115af235a6008ad87dcdb0