CLI

Drive Media Moana from your terminal — folders, uploads, presets, AI jobs, and automations, all scriptable


moana is the official command-line interface for Media Moana. It exposes every action you can take in the web app — uploading media, managing folders, running AI jobs, wiring up automations — as a scriptable command you can call from any shell, CI pipeline, or cron job.

If you can do it in the UI, you can do it from the terminal.


Install

npm install -g @moana/cli

This installs a single binary, moana, available globally on your $PATH.

To verify:

moana --version
moana --help

Authenticate

The CLI authenticates against your Media Moana account using a browser-based OAuth flow. Run:

moana login

What happens:

  1. The CLI starts a temporary callback server on localhost:3456.
  2. Your default browser opens to the Media Moana login page.
  3. After you sign in, an API key is issued and posted back to the CLI.
  4. The key is saved to ~/.moana/config.yml. You're done.

You only need to run login once per machine. The token persists across sessions.


Commands at a glance

GroupWhat it manages
folderFolder hierarchy — create, list, move, delete
mediaMedia files — upload, list, get, rename, move, favorite, publish, trash, restore, purge, clone
presetProcessing presets (resize, compress, format conversion pipelines)
ai-presetsAI presets (model + prompt + schema bundles for chat and image generation)
modelsBrowse available chat and image AI models
jobsSubmit and monitor async AI / processing jobs
automationsCron and event-triggered pipelines

Run moana <group> --help for the full list of subcommands, or moana <group> <command> --help for option details.


Folders

Folders are paths like /products/2024/spring. The CLI works with absolute paths, not folder IDs, so commands stay readable.

# Create a nested folder (parents are created automatically)
moana folder create /products/2024/spring
 
# List the entire folder tree
moana folder list
 
# Rename or move
moana folder move /products/2024/spring /products/2024/summer
 
# Delete (trashes all media within — irreversible without restore)
moana folder delete /products/2024 --yes

folder list defaults to a visual tree. Use -o json|yaml|table to switch formats.


Media

Upload

Upload accepts files, folders, or wildcards. When you pass a folder, the local directory structure is preserved under the target.

# Single file into the default upload folder
moana media upload ./photo.jpg
 
# Whole folder into a target path (preserves nested structure)
moana media upload ./shoot-2024/ -f /products/2024
 
# Wildcards with concurrency tuning and a MIME filter
moana media upload ./raw/*.{jpg,png} \
  -f /inbox \
  --concurrency 8 \
  --mime-type jpeg png
OptionPurpose
-f, --folder <path>Target folder. Defaults to /upload-{timestamp} if omitted.
-c, --concurrency <n>Parallel uploads (default 3). Tune up for large batches and fast networks.
-m, --mime-type <types...>Skip files whose MIME type isn't in the list. Case-insensitive, accepts both image/jpeg and jpeg.

The CLI hashes each file, dedupes against your library, stages uploads, and reports a per-file table with timing breakdowns at the end.

List, get, rename

# List with pagination and filtering
moana media list --type all --page 0 --per-page 20
moana media list --type favorite
moana media list --type folder --value <folder-id>
moana media list --type search --value "sunset beach"
 
# Inspect one
moana media get <media-id>
 
# Rename
moana media rename <media-id> -n "New Name.jpg"

--type accepts all, folder, trash, favorite, published, or search. The --value flag carries the query (folder ID for folder, text for search).

Organize and curate

All bulk commands take one or more media IDs and accept -o json|yaml|table.

# Move into a folder
moana media move <id1> <id2> -f /products/featured
 
# Favorite / unfavorite
moana media favorite <id1> <id2>
moana media favorite <id1> --off
 
# Publish to a public URL / unpublish
moana media publish <id1>
moana media publish <id1> --off
 
# Clone (creates new media with new IDs)
moana media clone <id1> <id2>

Delete, restore, purge

The CLI distinguishes between soft delete (move to trash, recoverable) and purge (permanent, irreversible).

# Move to trash
moana media delete <id1> <id2>
 
# Bring back from trash
moana media restore <id1>
 
# Permanent delete (asks for confirmation)
moana media purge <id1> <id2>
moana media purge <id1> --yes              # skip confirmation
 
# Empty the trash entirely
moana media purge --empty-trash --yes

Processing presets

Processing presets are deterministic image pipelines — resize, compress, format-convert, and so on. They're the same presets used by the web app's batch flows and by automations.

# List
moana preset list                   # all
moana preset list -f user           # only your custom presets
moana preset list -f builtin        # only built-in presets
 
# Inspect a preset's pipeline
moana preset get builtin-social-instagram-square -o yaml
 
# Create from inline JSON
moana preset create \
  -n "Web Optimize" \
  -p '[{"operation":"resize","params":{"width":1600}},{"operation":"webp","params":{"quality":82}}]'
 
# Or from a file (the -p flag accepts JSON strings or file paths)
moana preset create -n "Web Optimize" -p ./pipelines/web-optimize.json
 
# Update / clone / delete
moana preset update <slug> -n "Web Optimize v2" -p ./pipelines/web-optimize-v2.json
moana preset clone builtin-social-instagram-square
moana preset delete <slug> --yes
 
# Bulk
moana preset batch-delete <slug-1> <slug-2>
moana preset import ./presets-export.json

A pipeline is just an array of { operation, params } objects — see any built-in preset with preset get … -o yaml for a working template.


AI presets

AI presets bundle a model + prompt + parameters + optional JSON schema into a reusable handle. They power both chat and image-generation flows.

# List, filter, inspect
moana ai-presets list -m chat
moana ai-presets list -m ai_image -f user
moana ai-presets get my-product-describer -o yaml
 
# Create a chat preset with a structured-output schema
moana ai-presets create \
  -t "Product Describer" \
  --mode chat \
  -m google/gemini-2.5-flash \
  -p @./prompts/product-describer.md \
  --schema ./schemas/product.json \
  --tags "ecommerce,seo" \
  --description "Generates SEO-friendly product copy from a single image"
 
# Create an image preset
moana ai-presets create \
  -t "Studio Product Shot" \
  --mode ai_image \
  -m openai/gpt-image-1 \
  --params '{"size":"1024x1024","quality":"high"}'
 
# Update, clone, delete
moana ai-presets update my-product-describer -t "Product Describer v2"
moana ai-presets clone builtin-tagger
moana ai-presets delete my-product-describer --yes
 
# Import a JSON export from another workspace
moana ai-presets import ./ai-presets-export.json

Loading prompts and JSON from files

Two conventions worth remembering:

  • -p, --prompt accepts either a literal string or a file path prefixed with @ (e.g. @./prompt.md).
  • --schema, --params, --variables accept either a JSON string or a path to a .json file. The CLI auto-detects which.

This makes it easy to keep prompts and schemas under source control and reference them by path.


AI models

Browse the catalogue of models available to your account.

# Chat models (default mode)
moana models list
 
# Image-generation models, with full pricing details
moana models list -m ai_image
 
# Pipe to jq for ad-hoc filtering
moana models list -m chat -o json | jq '.[] | select(.support_structured_output)'

The table view shows series, ID, modality, context length, supported parameters, and per-million-token (or per-image) pricing.


Jobs

Jobs are the async execution layer behind every AI run. Use them when you want to script work that the UI would normally fire off in the background.

There are four job types:

TypeWhat it does
ai-generateText-to-image generation. Outputs N new media items.
ai-editAI edit on existing media (background removal, upscale, style transfer, etc.)
parseRun a chat AI preset over media — typically for tagging, captioning, or metadata extraction.
processRun a deterministic processing preset (resize, compress, convert) at scale.

Estimate before submitting

Every job has an estimable credit cost. Always estimate before running large batches.

moana jobs estimate \
  --type ai-edit \
  --media-ids id1,id2,id3 \
  --preset-id builtin-remove-background

Submit

# Generate 4 images from a prompt
moana jobs submit \
  --type ai-generate \
  --preset-id my-product-shot \
  --count 4 \
  --target-folder-id <folder-id>
 
# Process a folder of media through a preset, replacing originals
moana jobs submit \
  --type process \
  --media-ids id1,id2,id3 \
  --preset-id builtin-preset-util-web-optimize \
  --mode REPLACE_MEDIA
 
# Override a preset on the fly with an inline model and prompt
moana jobs submit \
  --type parse \
  --media-ids id1,id2 \
  --model google/gemini-2.5-flash \
  --prompt @./prompts/tagger.md

--mode controls whether output media replace originals (REPLACE_MEDIA) or land as new files (NEW_MEDIA).

Track and recover

# List jobs (paginated, filterable)
moana jobs list --status PROCESSING
moana jobs list --type ai-generate --trigger-type cron
moana jobs list --automation-id <slug>
 
# Drill into one job (per-item results)
moana jobs get <job-id> -o yaml
 
# Cancel a running job
moana jobs cancel <job-id>
 
# Resume a failed job — only the unfinished items re-run, linked via rootJobId
moana jobs resume <job-id>
 
# Clean up
moana jobs delete <job-id> --yes
moana jobs batch-delete <id1> <id2> <id3> --yes

jobs resume is the right tool when a batch fails halfway through. It creates a new attempt that picks up only the items that didn't settle, so you don't pay twice for already-finished work.


Automations

Automations chain triggers (cron, upload events, generic events) to actions (run a processing preset, run an AI preset, …). Once enabled, they fire on their own.

Because the trigger and action shapes are nested JSON, automations create and update take a single --data payload — either inline JSON or a file path.

# List, inspect
moana automations list
moana automations list -f user
moana automations get builtin-web-optimize -o yaml
 
# Create from a file
moana automations create -d ./automations/auto-tag.json
 
# Toggle on / off
moana automations enable my-auto-tag
moana automations disable my-auto-tag
 
# Manually fire a cron automation right now (creates a job)
moana automations trigger my-nightly-rebuild
 
# Clone (always disabled by default — review before enabling)
moana automations clone builtin-web-optimize
 
# Delete
moana automations delete my-auto-tag --yes
moana automations batch-delete slug-1 slug-2 --yes

A minimal automation looks like this:

{
  "name": "Auto-tag on upload",
  "enabled": true,
  "trigger": {
    "type": "event",
    "eventType": "media.upload"
  },
  "action": {
    "type": "chat_ai_preset",
    "presetId": "my-product-describer"
  }
}

For the full schema and trigger/action catalogue, see the Automations guide.


Output formats

Every command that returns data accepts -o json|yaml|table. Most reads default to table; most writes default to json. Folder list also supports tree.

moana media list -o json
moana preset get my-preset -o yaml
moana folder list -o tree

JSON output is colorized for terminals and machine-readable when piped, so you can chain commands with tools like jq:

# Trash every media item over 50 MB in /raw
moana media list --type folder --value <raw-folder-id> -o json |
  jq -r '.data[] | select(.basicInfo.size > 50000000) | .mediaId' |
  xargs moana media delete

Configuration

State lives at ~/.moana/config.yml:

env: prod
token: mk_live_…

You can edit it by hand, but moana login is usually the easier path.


Conventions cheat-sheet

ConventionWhere it applies
--yes / -ySkip confirmation on destructive commands
-o, --output <fmt>json (default for reads of one item), yaml, table (default for lists), tree (folder list only)
-p, --prompt @filePrompt option reads file contents when prefixed with @
--schema, --params, --variables, -p (presets)Accept inline JSON or a file path — auto-detected
--tags "a,b,c"Comma-separated lists
--media-ids id1,id2Job options take comma-separated IDs
Multiple positional IDsMost batch commands take space-separated IDs as positional args

What's next

  • Run moana --help to explore the full command tree.
  • Pair the CLI with Automations to remove the human from repeatable workflows.
  • Use the same actions over HTTP — see the API Reference for the underlying endpoints.

Last updated: July 7, 2026