mcpbeat

Wonda CLI Skill for Claude by degausai

degausai/wonda-cli

Using the Wonda CLI to generate images, videos, music, and audio from the terminal — plus LinkedIn, Reddit, and X/Twitter research and automation

54k tokens
context cost
the whole folder, loaded on every use
1
files
instructions only
0
copies elsewhere
how many repositories repackaged it
140
stars on the repo
on the repository, not the skill itself

Install

one command, takes just this skill from the repository
npx skills add https://github.com/degausai/wonda --skill wonda-cli

The instruction itself

20 sections, as written by the author

Wonda CLI

Wonda CLI is a content creation toolkit for terminal-based agents. Use it to generate images, videos, music, and audio; edit and compose media; publish to social platforms; and research/automate across LinkedIn, Reddit, and X/Twitter.

Install

If wonda is not found on PATH, install it first. The recommended installs are the signed desktop installers (CLI + tray icon + always-on relay, zero extra steps): macOS brew install --cask degausai/tap/wonda-app (or the wonda-macos.pkg from releases), Windows winget/wonda-windows-setup.exe. The CLI-only channels below work everywhere and can add the desktop app later with wonda app install:

# npm
npm i -g @degausai/wonda

# Homebrew
brew tap degausai/tap && brew install wonda

Setup

  • Auth: wonda auth login (opens browser, recommended) or set WONDA_API_KEY env var
  • Verify: wonda auth check

OAuth connector auth

Claude web and Cowork connectors use Wonda's OAuth 2.1 flow instead of a CLI

API key field. The connector signs in through Wonda in the browser, grants the

requested account access, and receives OAuth tokens bound to the Wonda API

resource. The server swaps those tokens to the account's internal API key only

inside Wonda, so agents and connector hosts never see the sk_... key. For the

CLI and local stdio MCP path, keep using wonda auth login or

WONDA_API_KEY.

Claude Cowork local relay

Claude Cowork (the desktop app) runs local MCP servers on the host, so it can

load the .mcpb bundle or a local stdio wonda-mcp config directly, WAB

writes included (verified 2026-07-07). Claude web cannot. The Wonda local

relay is the alternative path: it lets the REMOTE connector (web or Cowork)

run actions on the user's own Mac and residential IP without any local MCP

config:

  • Open https://wonda.sh/download while signed in and install the notarized

Mac package.

  • Pair the relay with wonda relay pair or the first-run browser handoff. This

uses the existing cli-auth flow with a relay-scoped wrelay_...

credential stored in the macOS Keychain. Do not ask the user to paste an API

key or device code.

  • Open https://wonda.sh/setup, connect LinkedIn, X, and Reddit through the

headful local WAB, then approve the Wonda connector once in Claude.

The engine policy is auto | my_machine | cloud. auto uses the local relay

when it is online and cloud otherwise. my_machine must not silently fall back:

if the relay is offline, ask whether to switch to cloud.

Organizations & spend context

Wondercat orgs are shared wallets with their own seats and billing.

Members can spend from the org wallet (instead of their personal credits)

by switching context:

  • wonda organizations list (aliases: wonda orgs list, wonda org list) — see every org you belong to with your role and seat plan in each.
  • wonda use --org <slug> — sticky org context for this machine. Sets

X-Wonda-Org on every request; holds, charges, and wonda balance

route through the org wallet.

  • wonda use --personal — back to personal.
  • wonda usage — spend-only usage summary (total + per-model + per-project

breakdown) for a period (--month 2026-05, or --from/--to; defaults

to the current month, UTC). --project <name> restricts the report to one

project. In org context it reports org-wide usage including a per-member

breakdown — admin/owner role required. Admins can also download a full

Excel report from the org page on the web.

Projects (spend tagging)

Projects attribute spend to a named workstream for monitoring. Agents

should check the active project at task start (wonda use prints it) and

set one per task when the operator monitors spend by project:

  • wonda use --project <name> — sticky: every subsequent charge carries

the project (in wonda usage, the API, and the org Excel report).

wonda use --no-project stops tagging; switching org/personal context

clears the project automatically (projects are per-scope).

  • --project <name> on any command — one-off override for that invocation.
  • wonda project list|create|delete — manage the registry in the active

scope. Org projects are created by org admins/owners only; personal

projects are self-service. Tagging against a name that doesn't exist

fails with unknown_project (no silent new buckets, so typos can't

split the monitoring data).

wonda topup always tops up your personal wallet, regardless of

context. Topping up the org wallet (and configuring auto top-up) is

admin-only and happens on the web at /organizations/<slug>. If a

member runs out of org credits, the error tells them to ask an admin or

switch back to personal — they cannot top up the org wallet from CLI.

Roles inside an org are separate from the seat plan:

  • Owner: the original creator. Cannot be demoted or kicked. Can transfer ownership to another member from the org page (rare).
  • Admin: can invite (single or bulk via paste), kick, change roles, change seats, top up, configure auto top-up, change monthly limits.
  • User: can only spend within the org wallet (subject to a per-member monthly limit if the admin set one).

A paid org seat (WONDA / WONDA_PREMIUM) grants the same paid feature access (skills, etc.) as a personal paid plan, but only while in org context. wonda use --personal falls back to the user's personal account plan.

Access tiers

Wonda is paid-only: every product surface (generation, media, publishing, scraping, analysis, skills, cloud twin) requires a paid plan. New accounts get no credits and no product access until they subscribe.

| Tier | Access |

| ----------------------------------------------- | --------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |

| Anonymous (temporary account, no login) | No product access. The CLI mints a temporary account on first run, but it reaches only the local commands below plus the auth/billing endpoints. Run wonda auth login, then subscribe. |

| Free (logged in, no paid plan) | No product access. Subscribe at https://wonda.sh/account to use the product. |

| WONDA ($19.99/mo, "Pro") | Everything except cloud twin: generation (image/generate, video/generate, ...), media upload/download, publishing, scraping, analytics, video analysis, skills (wonda skill install/list/get), transitions, clipping, email, reddit/linkedin account creation, styles, brand. |

| WONDA_PREMIUM ($49.99/mo, "Premium") | Everything in WONDA, plus cloud twin (wonda twin: provisioning, scheduled runs, streamed login) with antidetect / shadowban protection, no caps, and US account creation. |

| Flagged (per-account PostHog kill-switches) | Included in the paid plan but still gateable by a per-account flag: wonda reddit signup (redditAccountCreationEnabled), wonda email (emailServerApiEnabled), public LinkedIn profile enrichment (linkedinProfileEnrichmentEnabled). |

| Local (no API call, no credits, no plan) | Run entirely on your machine, so they work without a plan: wonda brand extract <url> (no --save), wonda compose motion/wonda compose text, wonda wab record <url>, wonda edit ... ffmpeg primitive transforms on local files, and wonda doctor. The Chromium-backed ones need a one-time wonda wab install. |

If a command returns a 403 (paid_plan_required), subscribe at https://wonda.sh/account.

Voice cloning

Clone a voice from a 10s+ audio clip and use it in TTS. Hard limit: 20 cloned voices per account. Cost: $1.50 per clone.

# Clone from a local file (auto-uploads to media library first)
wonda voice create "Andu" --file ./sample.mp3 --description "My voice"

# Clone from existing wonda media
wonda voice create "Brand" --media-id <uuid>

# Optional source-audio preprocessing
wonda voice create "Clean" --file ./raw.wav --noise-reduction --normalize-volume

# List cloned voices (each row reports isExpired and expiresInDays)
wonda voice list

# One voice
wonda voice get <voice-id>

# Rename / re-describe (local only, no provider call)
wonda voice update <voice-id> --name "New Name" --description "..."

# Delete
wonda voice delete <voice-id>

Use a cloned voice in TTS by passing the providerVoiceId from voice get as voiceId to /audio/speech:

wonda audio speech "Hello world" \
  --model minimax-speech-2-8-hd \
  --params '{"voiceId":"<providerVoiceId>"}'

7-day expiry: cloned voices that haven't been used in TTS within 7 days are automatically expired. Running TTS with a cloned voice automatically refreshes its expiry. Idle voices that lapse must be re-cloned ($1.50 again).

Credentials vault

Persist logins created on external platforms (Instagram, TikTok, Twitter, etc.) so they can be reused on the next run. Passwords are AES-256-GCM encrypted with a server-side key and only decrypted on get.

# Create
wonda credentials create --website instagram.com --username myhandle \
  --email [email protected] --password-stdin <<< "hunter2" \
  --metadata '{"signup_source":"wonda-email"}'

# List (passwords omitted)
wonda credentials list --website instagram.com

# Get full record including decrypted password
wonda credentials get <id>

# Update any field (use --password-stdin to rotate; --username "" to clear)
wonda credentials update <id> --username newhandle

# Delete
wonda credentials delete <id>

# Fetch + record why you're using it in one call — POST, not GET, because
# it writes a 'used' event with the reason. Prefer this over `get` whenever
# you can articulate the reason.
wonda credentials use <id> --reason "instagram signup flow"

# See recent events (created / used / rotated / updated) for audit
wonda credentials events <id>

Fields: website (required — typed input like insta is canonicalized to instagram.com), username, email, password (required), metadata (arbitrary JSON). At least one of username / email must be present. Multiple records per (website, username) are allowed — dedupe on your side if you need to.

Event log: every credentials get/use, create, password rotate, and other updates are recorded as events on the credential (actor: cli | web | system). Use credentials events <id> or the web UI's history icon to audit. The event log is append-only and cascades on credential delete.

Global output flags

All commands support these output control flags:

  • --json — Force JSON output (auto-enabled when stdout is piped)
  • --quiet — Only output the primary identifier (job ID, media ID, etc.) — ideal for scripting
  • -o <path> — Download output to file (implies --wait)
  • --fields status,outputs — Select specific JSON fields
  • --jq '.outputs[0].media.url' — Filter JSON output with a jq expression

CLI announcements & deprecation warnings

On every command the CLI polls GET /api/v1/updates (anonymous, 1h cache in ~/.wonda/state.json) for active announcements: deprecation notices, incident heads-ups, upgrade prompts. Messages are printed to stderr only, so stdout/JSON stays clean for piping.

Per-request deprecation hints arrive as the standard Warning: 299 - "<message>" HTTP header and are surfaced to stderr by the CLI's HTTP client as [deprecated METHOD /path] <message>.

Silence both channels with WONDA_QUIET=1 (env var) or --quiet (flag). Disable just the network checks with WONDA_NO_UPDATE_CHECK=1.

WAB / Wonda Automation Browser (wonda wab)

The Wonda Automation Browser (WAB) is a premium stealth antidetect browser, hardened so platforms cannot fingerprint it as automation. wonda wab is the one command for the antidetect Chromium stack (an undetected Playwright fork). It has two faces:

  • Authenticated sessions. One persistent headful Chromium per persona that holds signed-in sessions for LinkedIn, X, Reddit, and friends. The CLI spawns it on demand, lets it idle out, and routes platform reads/writes through it whenever a command runs --via wab. Cookies live in the persona's Chromium profile, not in ~/.wonda/config.json.
  • Anonymous capture. wonda wab record <url> (and wonda brand extract) drive an ephemeral Chromium with a fresh fingerprint, no persona, no cookies. See the record block below.

The mental model: you have accounts (one identity per platform). Each platform command routes to that account's cookies via either the flat JSON store (--via cookies, fast, no Chromium) or the account's persona (--via wab, live antidetect Chromium). A persona is the Chromium envelope that can hold multiple accounts under one fingerprint. In almost every case the persona is auto-created on first --via wab use, named after the account, so you never type a persona name.

The local wonda.mcpb Desktop Extension uses this same local WAB path from Claude Desktop or Claude Code: platform cookies stay on-device, reads use local cookies, and writes use the local WAB. Claude web and Cowork need the remote MCP connector instead.

Native login is the default for a new persona. wonda wab login <persona> <platform> opens a headful WAB window and you log in there. The session is minted INSIDE the WAB, so it is independent (logging out of the same account in an unrelated Chrome cannot revoke it) and the cookies are born under the WAB's own fingerprint, so session and browser identity stay coherent. A brand-new persona auto-created on first --via wab use chains straight into this flow on a TTY. After an X login, Wonda detects the signed-in screen_name and records it as the persona's X account binding. Existing bindings are never silently changed; a different detected handle produces a warning. Pasting cookies from another browser (wonda linkedin auth set, wonda x auth set, ...) still works and is the explicit fallback, but a hand-pasted li_at on a novel WAB fingerprint is the highest-risk shape.

wonda wab install                             # one-time: npm install + stealth-browser Chromium (shared by sessions, record, brand extract)
wonda wab update                              # refresh the runtime to the version this CLI pins (runtime versions ship inside CLI releases): staged download, verified, then atomically swapped in, so a failed download leaves the current driver tree untouched; refuses the runtime swap while personas run (wab stop them first; the relay picks the new runtime up on its next spawn, no restart), while an already-current tree's cheap manifest refresh proceeds without the gate: it reconciles drifted current files back to this build's embedded bytes (additive rewrites, safe under a running persona) and only prunes stale files when NO personas are running, deferring the prune (and keeping the mismatch visible) until the tree is quiet; --check reports installed vs pinned without changing anything, --force reinstalls even when current and re-downloads the shared Chromium build (corrupt-cache recovery; caveat: --force clears the cached Chromium before re-downloading, so a failed forced download leaves the shared cache without it until a retry succeeds). The driver tree also carries a manifest recording what produced it: the embedded driver asset identity compatibility is actually keyed on, plus the CLI build and platform as provenance. A tree whose recorded assets differ from this binary's embedded set (or that predates manifests) is refreshed automatically at the next browser spawn or wab update; two builds shipping byte-identical driver assets share one manifest without churn, so the recorded CLI version can lag behind the newest compatible binary. --check reports the manifest state (ok|absent|mismatch|unreadable) without touching anything; --json only changes the output format and still performs the update
wonda wab start [account]                     # spawn (offscreen by default; --visible to show)
wonda wab stop [account]                      # graceful shutdown
wonda wab show [account]                       # peek a background WAB on-screen to watch it (suspends the macOS focus guard); starts it offscreen first if needed
wonda wab hide [account]                       # send a surfaced WAB back offscreen, resume silent background operation
wonda wab screenshot [account]                 # capture the persona's current page as a PNG without surfacing the window; --json returns inline base64, --output writes a file, --tab/--full-page optional
wonda wab browse [url] --persona <persona>     # load a page and scroll it like a person: pause, scroll, pause, scroll; stops early once the scrolled element stops advancing, see below (plain text output, not JSON)
wonda wab menubar                              # Tray control, macOS menu bar or Windows notification area: the Wonda cat icon with a corner status badge. Green filled = running here and serving; orange half = standing by, which proves only that this machine is not the active device (whether another device or no device is serving is a separate three-way the badge cannot answer, and the menu's detail line only echoes the last relay-health check, a snapshot that can lag while this machine stays in standby); red triangle = running but cannot serve; grey hollow = not running here. The badge carries shape as well as color (filled/half/triangle/hollow) on both platforms; macOS falls back to a 🐱 text item with the same states as glyphs. Click for Restart Relay, a state-following Stop/Start toggle (`wonda relay disable`/`enable`, never `relay stop`), Open Log (macOS only; the Windows task runs the relay with no log file), and Show/Hide per running WAB; the tooltip carries the full status sentence. The bottom item "Quit Wonda" runs `wonda app quit` (stop relay + disable autostart + remove every open-at-login mechanism (macOS login item, Windows Startup entry) + remove the icon; quit stays quit until the app or `wonda app open` runs again). The Windows tray is a PowerShell/WinForms NotifyIcon consuming `relay health --json` (state) plus a periodic `wab status --json` (the persona Show/Hide list) and shelling wonda verbs, zero platform logic in the script. --stop removes only the icon and leaves the relay running
# macOS Dock menu: right-click a running WAB's Dock tile (the 🐱) for "Show on screen" / "Send to background" (same as wab show/hide). Each running persona has its own Dock tile and its menu controls only that persona. Opt out with WAB_DOCK_MENU=0.
# macOS: a background WAB no longer steals focus or flashes the menu bar / Dock when it opens a new tab; the Dock tile stays, it just never comes to the foreground until you `wab show` it.
wonda wab status                              # list personas + last activity + browser-context health (a running daemon whose Chromium died shows browser-dead with a restart hint instead of a misleading plain "running")
wonda wab login <account> <linkedin|x|reddit|instagram> # RECOMMENDED for a new persona: open headful window, user logs in, session minted in-WAB (independent + fingerprint-coherent)
wonda wab check <account> <linkedin|x|reddit|instagram> # non-interactive session-alive probe
wonda wab bind <persona> --x <acct> --reddit <acct> --linkedin <acct>  # multi-account power-user path: bind N accounts to ONE persona
wonda wab record <url>                        # anonymous one-shot capture (no account, no cookies), see below
wonda wab sync-cookies [account]              # force wab → disk cookie sync now (don't wait for the 10-min timer)
wonda wab logs [account] --tail 100           # tail driver.log (--audit for structured per-command log)
wonda wab errors --tail 20 --since 24h        # tail the cross-persona action-failure log
wonda wab top-failures --since 7d             # rank local WAB failures by platform/action/reason, joined with DOM recovery stats
wonda wab top-failures --platform x --json    # machine-readable local failure ranking
wonda wab bundle-failures list                # recent action failure bundles (one per failed run: screenshot, dom, visible-elements, cookies-summary REDACTED)
wonda wab bundle-failures show <id>           # print manifest + file tree for a bundle (id = unix-ms-ts prefix)
wonda wab bundle-failures ship <id>           # zip to ~/Downloads/wonda-failure-<id>.zip for sharing
wonda wab bundle-failures prune               # remove bundles older than 30d (or --max-per-persona, --all)
# Telemetry: on every wab action failure we report (action, platform, reason, error-string, has_bundle, cli_version) as a wab_action_failed PostHog event so maintainers can spot platform rotations across users. NO bundle contents, NO cookies, NO DOM, NO screenshots leave the user's machine. Opt out: WONDA_TELEMETRY_DISABLED=1. For server-side breakdowns, group `wab_action_failed` by `platform`, `action`, `reason`, and `has_bundle` in PostHog. Locally, `wonda wab top-failures` reads only `~/.wonda/wab/errors.jsonl` and persona-local `dom-recoveries.jsonl`, then shows count, last seen, recovered rate, bundle count, and a sample bundle id.
wonda wab migrate-legacy                      # copy a legacy WAB-driver profile into a persona slot
wonda wab restore <persona> [timestamp]       # restore from an hourly snapshot (--list to enumerate)
wonda wab backup disable                      # opt out of auto-push (on by default; existing cloud backups untouched)
wonda wab backup enable                       # opt back in (auto-push synced cookie JSON to wondercat after every disk sync)
wonda wab backup status                       # show config + remote inventory
wonda wab backup push [account]               # one-shot manual push for all platform bindings
wonda wab backup pull [account]               # guarded restore to ~/.wonda/<platform>-cookies/<account>.json; refuses non-empty local unless --force
wonda wab backup pull [account] --dry-run     # preview restores without writing
wonda wab backup list                         # inventory of cloud backups, including device/provenance metadata when available
wonda wab backup delete <plat> <persona> [acct] # remove one backup
wonda wab cookies list                        # explicit cookie backup inventory, metadata only
wonda wab cookies status [account]            # local cookie files plus cloud backup rows
wonda wab cookies port <plat> <persona> [acct] --from-device <id|label> # safely port one selected cloud row to this machine
wonda wab config set <persona> <key> <value>  # persist per-persona spawn defaults (idle-timeout, locale, visible, interactive, proxy_url, timezone, geo_lat/lon)
wonda wab config get <persona>                # print a persona's persisted config

Keep cron personas warm. A persona that continuously backs cookie-only read crons can use wonda wab config set <persona> idle-timeout off, followed by wonda wab start <persona>. The WAB then stays up and its existing 10-minute cookie sync keeps the flat files current. Use always-on only for cron-backing personas; wonda wab config unset <persona> idle-timeout restores the default 30-minute idle shutdown.

Local browser proxy (proxy_url). By default the local WAB dials direct (your own IP). Set wonda wab config set <persona> proxy_url managed to route the LOCAL browser through your account's minted twin proxy, so it shares the same egress as the cloud twin (useful for IP continuity or a VPN/office/CGNAT network). A literal socks5://…/https://… value is a manual override instead; unset clears it back to direct. The proxy is optional: if minting is disabled for the environment or unavailable, the browser falls back to a direct dial.

Lifecycle commands take an --account (e.g. wonda wab login <account> linkedin); the persona is auto-derived from the account name. wonda wab bind is the one place a persona is named explicitly: use it when one Chromium must host accounts that have different names per platform.

Scroll a page like a person (browse). wonda wab browse [url] --persona <persona> loads a page in the persona's WAB and scrolls it: a pause to look at the page, then scroll, pause, scroll, for --scrolls times (default 5). --scrolls accepts 1-200; a value outside that range is a hard error, not clamped, and it is rejected before a browser is launched. --first-wait (default 10s) is the pause before the first scroll; --wait (default 5s) is the pause between scrolls; both are jittered +/-30% because a precisely repeated interval is itself a fingerprint, and both are floored at 250ms so a very small value is not jittered down to zero — --first-wait 0 --wait 0 still pauses ~250ms per wait, not 0, so with --scrolls 200 that floor alone adds up to roughly 50s. It only scrolls — no clicking, no engagement — so it works on any site.

Progress is measured on the element that was actually scrolled: the viewport-filling overflow container when the site has one (LinkedIn's feed lives in <main id="workspace">, where window.scrollY never moves at all), otherwise the document scroller. Scrolling stops early once that element stops advancing across 2 consecutive scrolls, reported as (reached bottom) in the printed summary, so a short page does not grind against the bottom. An infinite feed keeps going for the full --scrolls.

--persona falls back to your configured default account exactly like the other wonda wab commands, and an invalid persona name is rejected up front instead of silently creating an empty logged-out profile. With a url, browse navigates in its OWN isolated tab (like every other WAB write) and reports the page actually browsed (after any redirect). Omitting the url dispatches to the persona's shared default tab instead — the driver's initial page, the same tab id wonda wab show/hide reference — scrolling whatever that tab already shows. wonda wab login does NOT leave anything there: it opens and navigates its own separate <platform>-login tab, so a persona that was just logged in still has an untouched default tab (often still about:blank). wonda wab show/hide don't navigate the default tab either — they only toggle the window's on/off-screen visibility — so neither one "opens a page" there. What actually leaves a page on default is something that navigates it directly, e.g. wonda wab start --open <platform|url> (also what the MCP wab_open tool calls). This is NOT a way to continue a page from a previous wonda wab browse <url> run: that run navigated in its own isolated tab, which the no-url form never sees. If the default tab has no page open (about:blank) — the common case right after logging a new persona in, since login's tab is separate — the command fails and asks for a url rather than reporting a successful scroll of nothing.

browse prints a plain-text summary, not JSON, so the global --json / --fields / --jq flags do not apply to it.

wonda wab browse https://example.com --persona <persona> --scrolls 6
wonda wab browse --persona <persona>                      # scroll the shared default tab's current page, no navigation

Anonymous capture (record). wonda wab record <url> records a URL to webm in an ephemeral Chromium (fresh fingerprint each call, no persona, no cookies). Use it for cookie-banner-gated pages (Notion public shares, pdf.js renders, any site where bare Playwright trips a bot check) and marketing demo capture.

wonda wab record https://example.notion.site/page \
  --output recording.webm \
  --duration 5 \
  --viewport 960x1080 \
  --inject-js scripts/page-script.mjs   # optional: runs after load, before timer starts

# Transcode webm to mp4 at 30 fps (the stealth browser records webm/VP8)
ffmpeg -y -i recording.webm -t 5 -r 30 -an \
  -c:v libx264 -pix_fmt yuv420p -crf 18 recording.mp4

The --inject-js file is wrapped in an async IIFE so top-level await works. It runs AFTER domcontentloaded + networkidle + 400 ms paint settle, BEFORE the duration timer starts. Any await inside counts against the recording window. Use it for dark-theme injection, cookie-banner removal, scroll animations, anything that needs to happen in page context.

Node.js requirement: wonda needs Node >= v20 on PATH. Brew users get it via the node dependency; npm users have it by definition; install.sh users may need brew install node (or any Node distribution). If Node is missing, wonda wab install fetches a private copy into ~/.wonda/node/.

Cookie cloud backup. On by default (opt out per machine with wonda wab backup disable). The WAB driver pushes the synced cookie JSON for each bound platform to the wondercat backend after every wab → disk sync and graceful shutdown; auto-push no-ops when no api_key is configured. Encrypted at rest server-side (AES-256-GCM) when SOCIAL_COOKIES_KEY is set, else plaintext jsonb; the wire payload is always plaintext because the server holds the key. Cookie values are never printed by list/status/port commands.

Recovery is guarded. wonda wab backup pull <account> and wonda wab cookies port <platform> <persona> [account] refuse to overwrite a non-empty or newer local cookie file unless --force is passed. Forced writes create a hidden .before-pull-* backup first. Use --dry-run to inspect planned writes. When the backend exposes multiple device rows for the same platform/persona/account, use wonda wab cookies port ... --from-device <id|label> so the source row is explicit.

Current backend compatibility: legacy servers still expose one last-write-wins row per (account, platform, persona, account_label). Newer servers may include device_id, device_label, source, status, generation, and provenance; the CLI displays those fields when present and shows legacy rows as device legacy.

Source lives at cli/wondercat/wab/. The driver is launch.mjs and per-platform action scripts under actions/<platform>/.

WAB reads fail early when the selected browser profile has no live platform session cookie. For LinkedIn, X, Reddit, and Instagram, the error includes wonda wab login <persona> <platform> instead of surfacing an unexplained platform 401/403. This preflight is read-only; writes retain their existing error handling and native login itself is unaffected.

Per-command transport (--via). linkedin, x, and reddit commands take:

  • --via cookies|wab: cookies reads the flat per-account JSON store (fast, no Chromium); wab routes through the account's persona Chromium (cookies + TLS fingerprint inherit from a real browser session). An unsupported value errors loudly rather than silently downgrading.
  • --via public: paid public-data API where a command explicitly supports it. For LinkedIn this avoids logged-in cookies and WAB profile reads, and uses the public scrape task route for wonda linkedin profile and wonda linkedin enrich.
  • --account <name>: which on-disk identity to use (cookie filename / persona). Persona resolution is implicit: the first --via wab use auto-creates a persona named after the account and (on a TTY) chains straight into login.

Defaults differ for reads vs writes. Read commands (profile, posts, search, timeline, etc.) default to cookies (direct API), because that path is fast and detection-safe. Write / engagement commands (post, comment, like, follow, connect, message, mute, repost, delete) default to wab, because the cookie-API path triggers anti-abuse heuristics on LinkedIn / X / Reddit at any meaningful volume. Pass --via cookies to a write command if you explicitly want the legacy API path (where the command supports it).

Commands that require --via wab. A few commands have no cookie path and only run through the Wonda Automation Browser: wonda linkedin comment, wonda linkedin reply-comment, wonda linkedin mute, wonda linkedin follow, wonda linkedin edit-post, wonda linkedin edit-comment, wonda linkedin delete-comment, wonda linkedin post --media, wonda x delete, wonda x reply --attach, wonda x dm send, wonda x dm accept, and wonda x dm start. On these, the default already resolves to wab (one stderr line noting it); passing --via cookies explicitly errors. Reddit's writes (vote, comment, subscribe, save, unsave, delete, and subreddit submit) are likewise wab-only.

Where it runs (--engine). --via picks the transport (browser vs. cookies); --engine picks the location, and the two are orthogonal. Values: local (this machine's WAB), cloud (the account's cloud twin, reached through the twin-action API with the control-session warm-up hidden behind a blocking wait), or auto (the default). auto resolves to local when the identity lives on this machine and cloud when it only exists as a cloud twin (a persona with no local footprint, or one cached as home=cloud from wonda twin provision). So wonda linkedin posts <profile> --account <twin> --engine cloud --via wab returns recent posts through the cloud twin's browser with the same structured result as the local command. --via works the same on both engines: reads default to cookies, writes default to wab, and an explicit supported override is preserved. Wired for LinkedIn (posts, connect, like/unlike, comment, reply-comment, edit-comment, send-message, follow, mute, delete-post, edit-post), X (like/unlike, bookmark, retweet/unretweet, follow/unfollow, delete), Reddit (vote, subscribe, save/unsave, delete), and Instagram (comment); other verbs run local only. --engine is accepted at the platform level (so both linkedin --engine cloud posts and linkedin posts --engine cloud work) but honored only on the wired verbs; passing it to another read or an unwired write is a clear error, not a silent no-op. wonda twin run-action is deprecated in favor of <platform> <verb> --engine cloud (it still works so running agents are not broken). On cloud, like supports plain likes and reactions (--reaction, routed to the react action); only comment reactions (--comment) stay local for now. auto resolves to local when a persona has no local footprint and no cloud twin (so first-use auto-create still works), and to cloud when a cloud twin exists for it. An explicit --engine cloud always runs on the cloud twin and never falls back to a live local relay.

Per-account credentials. Cookies live in per-account JSON files on disk:

  • ~/.wonda/x-cookies/<account>.json
  • ~/.wonda/reddit-cookies/<account>.json
  • ~/.wonda/linkedin-cookies/<account>.json (auto-migrated from the legacy single-file format)

Each file is a session-owned local cache, not a portable credential. A platform account may have separate sessions on multiple computers and a cloud Twin. The file records the owning device/persona WAB session, and every injection, overwrite, cookie-only read, refresh, and backup restore checks that identity first. The CLI does not upload these cookies to or download them from the legacy shared hosted-token store. --force never bypasses a session mismatch.

Pass --account <name> to auth set to keep multiple logins side-by-side on the current device. The binding is recorded against the resolved account persona in account-bindings.json, even when --persona is omitted, and if the matching persona's Chromium is running, the rotated cookies get pushed into that live context. Never use auth set to copy cookies from another device or a Twin. Native wab login is safer. The driver also syncs cookies back to disk every 10 minutes (and on graceful shutdown), so rotated cookies (ct0 cycles, token_v2 server-side refresh, etc.) flow back to the cookies path without manual re-paste. Direct X cookie requests also absorb response cookie rotation into the same store and send the full stored cookie jar, preserving device-trust cookies across reads.

The cloud Twin is its own stable, always-on session. Ordinary provisioning does not seed LinkedIn from local cookie files; use wonda twin login <persona> --platform linkedin to log in inside the Twin. Cloud backups are recovery artifacts for their source session only. Inspect local and cloud ownership with wonda wab cookies status [persona]; it never prints cookie values. Recent LinkedIn posts have a direct structured cloud path: wonda linkedin posts <profile> --persona <persona> --engine cloud --via wab. Other reads that are not yet engine-wired can run inside the Twin with wonda twin run-now <persona> --command "<platform read command>"; retrieve the captured result with wonda twin output <twinRunId>, using the id returned by run-now. Neither path downloads Twin cookies locally.

Safely refresh LinkedIn's flat cookie file. Run wonda linkedin auth refresh --account <account> --persona <persona> before a cookie-only read batch. Fresh disk cookies are a fast local no-op. Stale or near-expiry cookies cause one WAB start (a no-op when already running), one WAB-to-disk sync, and a local/WAB-side LinkedIn session check. The refresh path never invokes the raw wonda linkedin auth check probe and never retries credentials. If the WAB session is dead, it exits nonzero with native re-login required; stop the batch and recover manually with wonda wab login <persona> linkedin.

wonda linkedin auth refresh --json returns {fresh, refreshed, ageSeconds, expiresAt, sessionAlive}. fresh describes the final disk state; refreshed is true only when WAB-to-disk sync ran; ageSeconds is the disk cookie age; expiresAt is the known expiry or null; and sessionAlive is the local/WAB-side login result. sessionAlive is null on a fresh local no-op because no WAB check was needed. --fresh-within changes both the maximum accepted disk age and the minimum remaining recorded li_at lifetime (15 minutes by default). Treat a nonzero exit as authoritative even with JSON output.

Cookie-backed LinkedIn reads accept opt-in --freshen alongside --via cookies. It runs the same local preflight only when the disk cookies are stale, then attempts the requested read once. The default remains unchanged: without --freshen, --via cookies stays fast and browser-free.

Safely refresh X's flat cookie file. wonda x auth refresh --account <account> --persona <persona> uses the same local-first lifecycle with X-specific freshness rules. Since auth_token has no locally readable expiry claim, freshness is the cookie store age only. A store newer than --fresh-within (15 minutes by default) is a browser-free no-op. A stale store starts the selected WAB if needed, syncs X cookies to disk, and checks the WAB-side session without invoking the raw x auth check probe. A dead session exits nonzero with the exact native login command.

wonda x auth refresh --json returns {fresh, refreshed, ageSeconds, sessionAlive}. Cookie-backed X reads accept opt-in --freshen; it runs the same refresh only when the selected disk store is stale, pins the read to the refreshed account, and never applies to WAB reads, writes, or auth commands.

Use wonda x auth status --account <name> for a pure-local view of cookie origin, latest capture provenance, generation, ownership, cookie names, and missing device-trust-cookie risk. It never contacts X and never prints cookie values. Use wonda x browser-bootstrap --account <name> to explicitly push the selected stored jar into running WAB personas bound to that account.

Action rate limits

Every platform command (linkedin, x, reddit, instagram), reads AND writes, runs through a per-profile rate-limit guard so a burst doesn't trip a platform's shadow-ban / anti-abuse heuristics. Accounting is per (platform, account) in a rolling 24h window, logged per profile under ~/.wonda/wab/personas/<persona>/ (so a cloud twin's caps persist across runs).

  • Reads are _paced_, never blocked: spacing is jittered to keep a profile under read_per_min (75/min default), holding across separate invocations.
  • Writes are checked against per-bucket daily caps. The LinkedIn defaults (other platforms track + count toward the total/day but have no per-type write cap by default):

| bucket | commands | safe | max |

| ------------------------ | ------------------------------------- | ----------- | --- |

| outreach | connect + send-message + inmail | 20 | 40 |

| post | post | 3 | 5 |

| comment | comment, reply-comment | 10 | 20 |

| react | like | 25 | 50 |

| visit | visit | 15 | 30 |

| search | search, search-posts | 25 | 50 |

| total (all non-read) | any of the above | warn at 90% | 100 |

salesnav search (Sales Navigator) is exempt: it carries no Commercial Use Limit, so it paces as an uncapped read instead of counting toward the search cap or the total/day.

Caps are SOFT by default: an over-safe / over-max action prints a shadow-ban-risk warning to stderr and proceeds. Pass --hard (or set mode: hard in config) to make over-cap writes abort (exit 1) instead.

wonda actions is a JSON data query (not a dashboard) for reading a profile's rolling-24h usage vs caps on demand; the caps/pacing/warnings run silently in the live hook regardless.

wonda actions                        # rolling-24h usage per profile vs caps, as JSON
wonda actions --persona <persona>        # one profile
wonda actions --platform linkedin    # filter to one platform
wonda linkedin quota                 # planning view: remaining LinkedIn allowance per bucket (used vs safe/max + remaining, incl. untouched buckets) BEFORE a big pull, instead of hitting the mid-output warnings
wonda actions sync                   # flush local action/health events to your Wonda account
wonda actions sync --persona <persona>   # flush one profile's ledgers
wonda linkedin post "…" --hard       # enforce caps as hard limits for this command

When an API key is configured, the local ledgers (actions log, WAB audit/error logs, cookie provenance) also sync to your Wonda account-health record automatically in the background on every command: best-effort, batched, and idempotent (a stable client event id per record means retries never double count), so offline use keeps working and sync catches up later. wonda actions sync forces a full flush and prints the server's insert/dedup counts; without an API key it is a silent no-op. Only event metadata travels, never cookie values or failure bundles. WONDA_TELEMETRY_DISABLED=1 turns the background sync off.

Override / disable / hard-mode via ~/.wonda/config.json under action_limits (caps are clamped to safety floors/ceilings so an override can loosen but not silently disable the guard):

{
  "action_limits": {
    "mode": "hard",
    "read_per_min": 75,
    "total_per_day": 100,
    "buckets": { "linkedin": { "outreach": { "safe": 15, "max": 30 } } }
  }
}

Config keys

wonda config get|set|list keys:

  • api-key: your wondercat API key.
  • base-url: API base (defaults to prod, set to https://staging.api.wondercat.ai for staging).
  • default-account: account used when a platform command doesn't pass --account.
  • wab-backup-enabled: true/false for cookie cloud backup (same as wonda wab backup enable/disable). On by default; only an explicit false disables it.

Transport is NOT a config key. Each command picks it per kind (reads default to cookies, writes / engagement default to wab), identically on every platform. Override it per command with --via cookies|wab (where the platform supports it).

How to think about content creation

You are a marketing director with access to a full production toolkit. Before touching any tool, think:

  • What product category? (beauty, food, tech, fashion, fitness, etc.)
  • What format performs for this category? (UGC memes for everyday products, cinematic for luxury, before/after for transformations, testimonial for services)
  • What's the hook? (relatable scenario, surprising twist, aspirational lifestyle, social proof)
  • What specific scene? (not "product on table" but "person discovering the product in a funny situation")

Decision flow

When asked to create content, follow this order:

Step 1: Gather context

wonda brand                                                    # Active brand: identity, colors, fonts, logos, products
wonda brand list                                               # All brands owned by this account/org
wonda brand show <brand-id>                                    # Specific brand
wonda brand extract https://stripe.com                         # Local-only: writes ./output/stripe.com/{DESIGN.md, tokens.json, assets/}
wonda brand extract https://stripe.com --save --make-active    # Local + persist + activate (the common path)
wonda brand extract https://stripe.com --save --name "Stripe"  # Persist with a custom name
wonda brand extract https://stripe.com --no-output --save      # Don't write to disk, persist only
wonda brand save                                               # Persist the most recent ./output/<domain>/ dir to the server
wonda brand save --from ./output/stripe.com --make-active
wonda brand pull <brand-id>                                    # Download a saved brand back to ./output/<domain>/
wonda brand activate <brand-id>                                # Set as the active brand
wonda brand upload-logo <brand-id> https://acme.com/logo.svg   # Attach a logo by URL (--variant wordmark|icon|dark|light)
wonda brand upload-font <brand-id> https://acme.com/Geist.woff2 --weight 700
wonda brand delete <brand-id>
wonda analytics instagram                                      # What content performs well
wonda scrape social --handle @competitor --platform instagram --wait  # Competitive research (if relevant)

# Cross-platform research (if relevant)
wonda x search "topic OR keyword"                              # Find conversations on X/Twitter
wonda x user-tweets @competitor                                # Competitor's recent tweets
wonda reddit search "topic" --sort top --time week             # Reddit discussions
wonda reddit feed marketing --sort hot                         # Subreddit trends
wonda linkedin search "topic" --type COMPANIES                 # LinkedIn company/people research
wonda linkedin profile competitor-vanity-name                  # LinkedIn profile intel

Step 2: Check content skills

Content skills are step-by-step guides for common content types. Each skill tells you exactly which models, prompts, and editing operations to use — and in what order. ALWAYS check skills before building from scratch.

Skills are server-hosted, per-account, and editable (the same model as wonda brand save) — you don't download a folder of .md files you own. Wonda ships a canonical set of default skills, served read-only as the fallback. Pull them live for a task; fork a default into your own copy when you want to tweak it; Wonda keeps full version history. skill list shows your effective skills (defaults overlaid with your own edits), and flags any fork whose default has since changed.

wonda skill list                                # Browse your effective skills (defaults + your own); forks with a changed default are flagged
wonda skill get <slug>                          # Pull a skill's full step-by-step guide live to stdout

<!-- SKILLS_TABLE_START -->

Default skill catalog (live source: wonda skill list, which also shows your own forks/edits and flags drift):

video

| Slug | What it does |

| ------------------- | --------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |

| product-demo-video | Premium ~15s multi-beat product demo, a dev hits a pain point, runs your tool, it does something real on screen, the payoff lands, then a branded CTA, built as one HTML composite captured per-frame and muxed with ffmpeg |

| product-video | Product/scene video from an image or from scratch |

| split-screen-demo | 5-second 16:9 LinkedIn loop, source doc to designed slides comparison ending on a CTA that crosses out the competitors |

| tiktok-ugc-pipeline | Reverse-engineer a viral reel, generate 5 variations, auto-post |

| ugc-dance-motion | Dance and motion transfer video from image + reference |

| ugc-hook-brainstorm | 25 graded scroll-stopping UGC hooks, hot casting, iPhone 16 aesthetic, psychological levers |

| ugc-reaction-batch | Batch produce TikTok-native UGC reaction videos |

| ugc-talking | Talking-head UGC ad, single clip, two-angle PIP, or long-form 20s+ |

image

| Slug | What it does |

| --------------------------------- | ---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |

| creative-static-ads | High-converting single-frame static ads, 6 conversion pillars, 8 format archetypes, 8 psychological hooks |

| linkedin-media-premium-generation | Render a single stop-the-scroll LinkedIn hero card (1920x1080) using a layered visual vocabulary: italic-serif headline, real product screenshot, paper grain, floating social-proof cards. Six layout patterns sharing the same DNA. Wonda CLI sourcing for real quotes from X / LinkedIn / Reddit. |

| premium-static-ads | Pixel-perfect HTML+Playwright static ads with brand extraction (wonda brand extract). Real fonts, exact tokens, reproducible templates |

| tiktok-slideshow-carousel | 3-5 slide TikTok carousel that looks organic but promotes your product, hook, bridge, reveal |

social-research

| Slug | What it does |

| ------------------------------------ | ------------------------------------------------------------------------------------------------------------------------- |

| analyze-reel | Analyze a viral reel or TikTok, viral breakdown + 5 adapted content ideas |

| linkedin-account-multithreading-map | Map current account coverage, relationship state, and platform-suggested introduction paths across an accepted roster |

| linkedin-buying-committee-radar | Monitor named accounts for new role matches, job changes, recent posts, and Sales Navigator alerts |

| linkedin-comment-first-opportunities | Find a few live LinkedIn conversations where the user can add a specific, useful public contribution |

| linkedin-competitor-engager-watch | Watch named LinkedIn people and turn only their new high-signal engagers into a qualified outreach list |

| linkedin-engager-intel | Pull every commenter + reactor on a LinkedIn post with profile URLs for warm outreach |

| linkedin-icp-angle-brief | Turn a LinkedIn profile into an explainable ICP decision and one evidence-backed outreach angle |

| linkedin-icp-qualify | Enrich LinkedIn engagers with their current employer (industry, headcount, HQ, description) so you can filter for ICP fit |

| linkedin-inbound-intent-triage | Turn new LinkedIn notifications, invitations, messages, and owned-post comments into an evidenced response queue |

| linkedin-social-listening | Turn narrow pain, migration, and buying-language searches into a ranked, evidenced LinkedIn shortlist |

| reddit-subreddit-intel | Scrape top posts, analyze virality patterns, generate post ideas |

| twitter-influencer-search | Find micro-influencers and amplifiers for product launches |

strategy

| Slug | What it does |

| -------------------- | -------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |

| linkedin-post-system | Turn a raw idea into a LinkedIn post that matches proven formats and the user's exact voice. Bootstraps the user's voice corpus via wonda linkedin profile/posts, maps the idea to one of 28 proven content formats, drafts 2 variants with anti-AI-slop guardrails. |

| marketing-brain | Strategy brain for hooks, visuals, ads, and competitive analysis |

utility

| Slug | What it does |

| ---------------------- | ---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |

| extract-apply-style | Extract a visual style from any image, then generate new subjects in that style |

| ffmpeg | Local deterministic media transforms, trim, replace audio, burn captions, social formatting, scene splitting, silence cut, frame extraction, analysis artifacts |

| image-edit | Edit existing images, img2img, background removal, crop, text overlay, vectorize |

| slide-generation | Generate branded slide decks from any content source, codebase, Notion notes, or Google Docs |

| software-ui-mockups | Render real software UIs, terminal/CLI TUIs, the Chrome browser window, the macOS desktop, pixel-accurately in HTML for demo videos, slides, screenshots and docs, from the program's real source of truth |

| tiktok-caption-presets | TikTok-style textOverlay and animatedCaptions presets applied via wonda edit --preset |

<!-- SKILLS_TABLE_END -->

Editing skills (optional). When a default doesn't quite fit, fork and edit it instead of working around it. Editing a default forks it into your account automatically:

wonda skill create my-ugc --from ugc-talking    # Fork a default into your own editable copy
wonda skill edit my-ugc --editor                # Record a new version (opens $EDITOR; or --file <md> / stdin)
wonda skill diff <slug>                          # See what changed in the default since you forked it (drift)
wonda skill refactor <slug> --editor             # Re-base your fork onto the updated default, clears the drift hint

If a skill matcheswonda skill get <slug>, read it, adapt to context, execute each step.

If no skill matches → build from scratch (Step 3).

Step 2.5: Decide whether finishing should be local

Not every media task should go back through Wonda editing. Use this routing rule:

  • Use wonda for AI generation, AI transcription/alignment, scraping, publishing, hosted transitions, and workflows that need media IDs or remote jobs.
  • Use local ffmpeg for deterministic transforms on files you already have or can download: trim, crop/scale/pad, concat (merging multiple clips), replace audio, extract audio/frame, reverse, normalize for delivery, burn captions, split scenes, cut silence, and build analysis artifacts. Always merge clips locally — server-side merge can hang for 30+ minutes once any input exceeds ~7MB.

When a task starts from a Wonda media ID but the actual edit is deterministic, move it to local files first:

wonda media download <mediaId> -o ./input.mp4

Before any local ffmpeg work:

which ffmpeg
which ffprobe
ffmpeg -version
ffprobe -v error -show_format -show_streams -of json ./input.mp4

Font rule for local caption/text work:

  • Prefer an explicit font file path over a family name.
  • Never assume a font exists. Check first with fc-match, fc-list, /System/Library/Fonts, /Library/Fonts, ~/Library/Fonts, or /usr/share/fonts.
  • If the task is mainly local finishing/captions/formatting/splitting/artifact extraction, check the ffmpeg skill before inventing commands.

Other skills for the same job

different authors, same section of the catalogue
Canvas Design
by anthropics
vendor ×13

Create beautiful visual art in .png and .pdf documents using design philosophy. You should use this skill when the user asks to create a poster, piece of art, design, or other static piece. Create original visual designs, never copying existing artists' work to avoid copyright violations.

1388k tokens
Algorithmic Art
by anthropics
vendor ×10

Creating algorithmic art using p5.js with seeded randomness and interactive parameter exploration. Use this when users request creating art using code, generative art, algorithmic art, flow fields, or particle systems. Create original algorithmic art rather than copying existing artists' work to avoid copyright violations.

15k tokens scripts
Image Enhancer
by frostant
×6

Improves the quality of images, especially screenshots, by enhancing resolution, sharpness, and clarity. Perfect for preparing images for presentations, documentation, or social media posts.

635 tokens
Video Downloader
by CommandCodeAI
×4

Downloads videos from YouTube and other platforms for offline viewing, editing, or archival. Handles various formats and quality options.

671 tokens
Histolab
by christophacham
×3

Lightweight WSI tile extraction and preprocessing. Use for basic slide processing tissue detection, tile extraction, stain normalization for H&E images. Best for simple pipelines, dataset preparation, quick tile-based analysis. For advanced spatial proteomics, multiplexed imaging, or deep learning pipelines use pathml.

18k tokens
Omero Integration
by christophacham
×3

Microscopy data management platform. Access images via Python, retrieve datasets, analyze pixels, manage ROIs/annotations, batch processing, for high-content screening and microscopy workflows.

32k tokens
Pydicom
by christophacham
×3

Python library for working with DICOM (Digital Imaging and Communications in Medicine) files. Use this skill when reading, writing, or modifying medical imaging data in DICOM format, extracting pixel data from medical images (CT, MRI, X-ray, ultrasound), anonymizing DICOM files, working with DICOM metadata and tags, converting DICOM images to other formats, handling compressed DICOM data, or processing medical imaging datasets. Applies to tasks involving medical image analysis, PACS systems, radiology workflows, and healthcare imaging applications.

13k tokens scripts
Transformers
by christophacham
×3

This skill should be used when working with pre-trained transformer models for natural language processing, computer vision, audio, or multimodal tasks. Use for text generation, classification, question answering, translation, summarization, image classification, object detection, speech recognition, and fine-tuning models on custom datasets.

13k tokens

How to use it

Copy the folder

Take degausai/wonda-cli from the repository into ~/.claude/skills for personal use, or into .claude/skills inside a project.

Check the name does not clash

The agent identifies a skill by the name field in its header. Two skills with the same name cannot sit side by side — one of them will be ignored.

Install what it needs

The instructions reference npm, brew. Without those the skill loads but fails at the first command.