# Genspark CLI (`gsk`)

**One CLI. Every AI capability.** Search, generate, analyze, communicate — all from your terminal.

`gsk` is the command-line interface for the [Genspark](https://www.genspark.ai) AI platform. It unifies **90+ AI tools** behind a single binary: web search, image/video/audio generation with 40+ models, document analysis, media transcription, cloud file management, email (Gmail & Outlook), calendar, GitHub, Slack, Notion, Microsoft Teams, OneDrive, SharePoint, AI phone calls, stock data, social media data (Twitter, Instagram, Reddit), and autonomous AI agents — all with clean JSON output for seamless integration with AI coding assistants, automation pipelines, and scripts.

### Capability Map

| Category | What You Get |
|----------|-------------|
| 🔍 **Search** | Web search, image search |
| 📄 **Documents** | Crawl pages, summarize PDFs/docs |
| 🎨 **Images** | 16 models: GPT Image, Gemini, Flux 2, Imagen 4, Recraft, Ideogram, Seedream ... |
| 🎬 **Videos** | 14 models: Kling V3, Veo 3.1, Sora 2, Hailuo, Wan, Runway, PixVerse, Seedance ... |
| 🎵 **Audio** | 14 models: Gemini TTS, ElevenLabs, MiniMax, Mureka, CassetteAI, Lyria 2 ... |
| 🧠 **Analysis** | Image/video/audio understanding, OCR, video style replication |
| 📝 **Transcribe** | Whisper, Gemini, ElevenLabs Scribe |
| ☁️ **AI Drive** | Cloud file storage, download, compress |
| 📧 **Email** | Gmail & Outlook: read, search, send, reply, forward, archive, labels, attachments |
| 📅 **Calendar** | Google & Outlook: list, create, delete events |
| 💬 **Collaboration** | Slack, Microsoft Teams, Notion — send messages, search, manage channels/pages |
| 📂 **Cloud Storage** | Google Drive, OneDrive, SharePoint, Google Sheets, Google Docs, Google Contacts |
| 🐙 **GitHub** | List repos, search/create/update issues |
| 📞 **Phone** | AI-powered phone calls to businesses |
| 📈 **Stocks** | Real-time stock prices |
| 📱 **Social Media** | Twitter/X, Instagram, Reddit — search posts/users, get comments, connections, and more (30 APIs) |
| 🤖 **Agents** | Podcasts, docs, slides, deep research, fact-checking, websites, batch media generation |
| 🔊 **Voice** | Voice cloning, voice changer |
| 🕸️ **Mesh** | Secure SSH between your devices over a private tailnet — `gsk mesh join` / `serve` / `ssh` / `scp` / `sftp` / `forward` |

## Table of Contents

- [Installation](#installation)
- [Quick Start](#quick-start)
- [Authentication](#authentication)
- [Commands](#commands)
  - [Search & Crawl](#search--crawl)
  - [Image Generation](#image-generation)
  - [Video Generation](#video-generation)
  - [Audio Generation](#audio-generation)
  - [Media Analysis & Transcription](#media-analysis--transcription)
  - [AI Drive (Cloud Storage)](#ai-drive-cloud-storage)
  - [AI Agents & Tasks](#ai-agents--tasks)
  - [Connectors (Unified)](#connectors-unified)
  - [Service-Level Tools](#service-level-tools)
  - [AI Phone Calls](#ai-phone-calls)
  - [Stock Prices](#stock-prices)
  - [Social Media](#social-media)
  - [File Transfer](#file-transfer)
  - [Mesh (Secure SSH)](#mesh--secure-ssh-between-your-devices)
- [Available Models](#available-models)
- [Configuration](#configuration)
- [Output Conventions](#output-conventions)
- [License](#license)

## Installation

```bash
npm install -g @genspark/cli
```

Requires Node.js >= 18.

## Quick Start

```bash
# Log in via browser
gsk login

# Search the web
gsk search "latest AI news"

# Generate an image
gsk img "A beautiful sunset over mountains" -o ./sunset.png

# Crawl a webpage
gsk crawl "https://example.com/article"
```

## Local developer projects, previews, and source deployments

```bash
gsk project create --kind web --name "Example" --yes
gsk project bind <project-id>
gsk project status
gsk preflight --kind web --operation preview
gsk preflight --kind web --operation hosted-deploy
gsk service-url --local --port 3000
gsk get_service_url --local --port 3000
gsk hosted deploy-local --source .
```

Create explicitly asks for confirmation; `--yes` confirms creation in automation.
It never retries creation after a network error. Check your project list and
bind the returned/existing project before trying to create another one.
Binding and status use the server's owner-authorized developer endpoint.

The nearest ancestor `.gsk/project.json` binds a checkout:

```json
{"version":1,"project_id":"example-id","kind":"web","base_url":"https://www.genspark.ai"}
```

Only these four fields are allowed. No command above writes credentials or
changes global project configuration. Project selection is **`--project-id` >
`GSK_PROJECT_ID` > nearest binding > legacy global config**. The active server
still comes from `--base-url`, `GSK_BASE_URL`, or global config; a binding for a
different server blocks cloud operations even with an explicit project ID.
Invalid bindings fail visibly. A different existing/inherited binding is never
silently overwritten: use another checkout or explicitly remove the old binding.
Concurrent writers use atomic create-if-absent publication.

Preview requires explicit `--local`, runs before schema fetching or update checks,
and needs no login. Ports must be decimal integers in 1–65535. A bounded TCP probe
of `127.0.0.1` returns `{status, local_only:true, url, reachable, probe, message}`;
TCP reachability does not imply HTTP/application health. There is no public tunnel
and no fallback from a failed remote URL request to localhost.

Preflight operations are `preview`, `hosted-deploy`, `github`, `cloudflare`,
`shopify`, and `android`. Checks are advisory and operation-specific: web preview
does not require Flutter, and platform hosting does not require local Wrangler
or Shopify authorization. Missing login, malformed binding, and unavailable
platform checks preserve local check results with actionable status. Local
provider login (`gh auth login`, `wrangler login`, `shopify auth login`) is
separate from platform connectors and `sandbox_auth_*` remote sandbox setup.

`hosted deploy-local` streams a private temporary ZIP snapshot, uploads it, then
submits its validated receipt to the existing `hosted_deploy` approval flow.
It does **not** approve the action, including with `--yes`. Review the returned
pending action/source digest in the project and approve explicitly. The CLI
does not run build scripts. Source must include the Wrangler configuration and
entry points required by the backend's hosted build pipeline.

Packaging rejects symlinks, non-regular files, traversal, unsafe paths, and
case/Unicode-normalization collisions. Exclusions apply at every depth:
`.env*`, `.git`, `node_modules`, `.wrangler`, `.gsk`, `.genspark-code`, local
credential/config directories and files (including `.ssh`, `.aws`, `.azure`,
`.config`, `.npmrc`, `.netrc`, `credentials.json`, private keys), plus the active
custom CLI config file if it is inside the source tree. Limits are
20,000 visited non-excluded entries, 250 MiB ZIP, and 500 MiB expanded source.
Source changes detected while packaging abort the upload.

The receipt is saved before submission to `.gsk/pending-source-<uuid>.json`.
This file is retained after submission as a recovery record, not proof of action
status. On a dropped response, inspect hosted actions in the project before
resubmitting. Upload and submission are never automatically retried. No remote
source is substituted when an upload/receipt/server capability fails.

### Developer API contract

All paths below are relative to `<base_url>/api/tool_cli`; calls use existing
`ApiClient` token auth (`X-Api-Key`), `X-GSK-CLI-Caps`, and selected `X-Project-ID`.

| Request | Response |
| --- | --- |
| `POST /developer/projects` JSON `{kind,name}` | `{project:{project_id,kind,name,url}}` |
| `GET /developer/projects/{id}` (owner-authorized) | `{project:{project_id,kind,name,url}}` |
| `GET /developer/preflight?kind=...&operation=...&project_id=...` (project ID omitted when unbound) | `{checks:[{name,status,code,message,action_url?}],project?:{project_id,kind,name,url}}` |
| `POST /hosted/source`, raw `application/zip`, required `X-Project-ID` | HTTP 201 `{local_source:receipt}` |
| Existing `executeTool('hosted_deploy', {local_source:receipt})` | Existing tool envelope/pending approval |

Check `status` is `ready`, `action_required`, `unknown`, or `not_applicable`.
Project/check response objects permit additional server fields but only the
documented project/check fields are consumed. Source receipts are passed unchanged:
`{version:1,owner_cogen_id,project_id,object_key,sha256,size_bytes,expanded_bytes,
file_count,created_at,expires_at}` (timestamps: integer Unix seconds). The CLI
checks project ID, digest, sizes/count, required receipt fields, and expiry before
submitting. Backend ownership/digest/expiry validation remains authoritative.

The CLI advertises `cli-local-source-v1`; its tools cache is isolated from older
capability views. The static `hosted` parent is seeded so existing grouped hosted
metadata and legacy flat commands coexist. No new hosted group metadata is needed
on old servers. Any future metadata that shadows a static command must be gated
to supporting capabilities, not sent to old binaries.

Backend source writes default off. HTTP 503 explains that supported writers must
be enabled only after all readers/executors converge; 404/405 reports an unsupported
server. Release requires verified backend endpoint support and reader rollout.
There is no client-side bypass or remote-source fallback.

### Local verification

```bash
npm test
# Optional published-client shared-HOME matrix against mocked HTTP transport:
GSK_COMPAT_CLI=/path/to/published/@genspark/cli/dist/index.js npm test
```

## Authentication

Log in with your Genspark account:

```bash
gsk login
```

This opens a browser for authentication and saves the API key plus the effective
API base URL to the selected config. The default is
`~/.genspark-tool-cli/config.json`; use `--config <path>` or `GSK_CONFIG` for a
separate profile.

Alternatively, provide an API key directly:

```bash
# Via environment variable
export GSK_API_KEY="gsk_..."

# Via CLI option
gsk search "query" --api-key "gsk_..."
```

To check your current identity:

```bash
gsk login-info
gsk me          # shorthand
```

To log out:

```bash
gsk logout
```

## Configuration

Config is loaded from three sources (highest priority first):

1. **CLI options** — `--api-key`, `--base-url`, etc.
2. **Environment variables** — `GSK_API_KEY`, `GSK_BASE_URL`, `GSK_PROJECT_ID`
3. **Config file** — `~/.genspark-tool-cli/config.json`

```json
{
  "api_key": "gsk_...",
  "base_url": "https://www.genspark.ai",
  "project_id": "project_abc123",
  "debug": false,
  "timeout": 300000
}
```

## Global Options

| Option | Env Var | Default | Description |
|--------|---------|---------|-------------|
| `--api-key <key>` | `GSK_API_KEY` | — | API key (required) |
| `--base-url <url>` | `GSK_BASE_URL` | `https://www.genspark.ai` | API base URL |
| `--project-id <id>` | `GSK_PROJECT_ID` | — | Project ID for access control |
| `--debug` | — | `false` | Enable debug output |
| `--timeout <ms>` | — | `300000` (5 min) | Request timeout |
| `--output <format>` | — | `json` | Output format: `json` or `text` |
| `--refresh` | — | — | Force refresh cached tool schemas |
| `-y, --yes` | — | — | Assume "yes" at confirmation prompts (see [Confirmation prompts](#confirmation-prompts)) |
| `--no-input` | — | — | Never prompt interactively; confirmation-required actions fail with exit code 2 on a gated action/value |
| `--config <path>` | `GSK_CONFIG` | `~/.genspark-tool-cli/config.json` | Config profile path |

## Confirmation prompts

When the server advertises interactive confirmation support, actions with
external side effects (email send, slack send, tweet post, ...) are
confirmed **client-side, before the single server call**:

```bash
$ gsk gmail send --to a@b.c --body "hi"
  to: a@b.c
  body: hi
About to execute gmail send. Proceed? [y/N] y
```

- The preview and prompt go to **stderr**; stdout still carries exactly one
  JSON envelope. The answer is read from **stdin**, so `echo y | gsk ...`
  works; EOF declines.
- Declining (`n`, anything else, or EOF) prints `Aborted, nothing was sent.`
  and exits with code 1 — **no server call is made**.
- `--yes` / `-y` skips the prompt (like `apt-get -y`). Interactive-only
  actions (`slack send`/`react`/`upload`/`invite` and `google_drive share`,
  Marketplace policy) reject `--yes` and always prompt.
- `--skip_confirmation true` / `--auto_skip_confirmation` are **deprecated**
  on this CLI: use `--yes`. They are no longer listed in `--help` (the
  server omits them from the schema for CLIs that send the
  `cli-yes-only-v1` capability, i.e. this version; earlier 1.9–1.11.x CLIs
  keep the legacy view and their `--skip_confirmation` flags keep
  working), but they still parse
  as hidden flags and `--args-file` keys on confirmation-gated actions, are
  forwarded verbatim, and the server honors them as before — so existing
  unattended scripts keep working, with one `[DEPRECATED] ... use --yes`
  line on stderr per run. On interactive-only actions they are ignored
  (server-stripped) and the prompt still runs. See
  [docs/confirmation.md](docs/confirmation.md#deprecated-skip-parameters).
- Every confirmation-gated command's `--help` (e.g. `gsk gmail send --help`)
  ends with a `Confirmation:` note naming `--yes` and `--no-input`; the
  two flags themselves are global (`gsk --help`).
- Actions that dispatch on an argument (genteam `members`/`pins`/
  `invite_link`/`dm`/`tasks` on `--op`, teams `api` on `--method`) prompt
  only for their write values; the read values the server declares (e.g.
  `--op list`, `--method GET`, spelled exactly — or `--method` omitted for
  teams `api`, whose server default is GET) run without a prompt and
  therefore also work with `--args-file -`. See
  [docs/confirmation.md](docs/confirmation.md#per-operation-actions).
- `--no-input` (or `--args-file -`, which consumes stdin) makes
  confirmation-required actions fail with exit code 2 without calling the
  server — for a gated action or value; server-declared read values such
  as `--op list` / `--method GET` run without a prompt. Pass `--yes` for
  scripted runs of the gated ones.
- If the server responds `pending_confirmation` anyway, the local schema
  cache is stale — run `gsk --refresh ls` and retry.

On older servers (or when the feature is disabled server-side) nothing
changes: no prompt, and the server's own confirmation flow applies.

## Commands

### list-tools (alias: `ls`)

List all available tools.

```bash
gsk list-tools
gsk ls
```

### login-info (alias: `me`)

Show your current account info — email, name, and membership plan.

```bash
gsk login-info
gsk me
```

### init-opencode

Generate an `opencode.json` config file for [OpenCode](https://opencode.ai), pre-configured to use Genspark's LLM proxy with your API key.

```bash
# Generate with the server-selected default model
gsk init-opencode

# Specify a different default model
gsk init-opencode --model claude-sonnet-4-6

# Write to a custom path
gsk init-opencode -o ./my-project/opencode.json
```

| Option | Default | Description |
|--------|---------|-------------|
| `--model <name>` | Server-selected | Default model for OpenCode |
| `-o, --out <path>` | `opencode.json` (cwd) | Output file path |

The generated models include per-model reasoning variants, selectable with OpenCode's variant selector:

| Models | Selectable levels |
|--------|-------------------|
| DeepSeek V4 Pro / Flash / Pro 0813 (text), including listed Baseten Pro | `none`, `low`, `high`, `max` |
| GLM-5.3 / GLM-5.3 Flash | `low`, `high`, `max` |
| Kimi K3 | `low`, `high`, `max` |
| GPT-5.2 / 5.4 (including mini/nano) / 5.5 | `none`, `low`, `medium`, `high`, `xhigh` |
| GPT-5.6 | `none`, `low`, `medium`, `high`, `xhigh`, `max` |
| GPT-6 Astra | `low`, `medium`, `high`, `xhigh`, `max` |
| Adaptive Claude | `low`, `medium`, `high`, `xhigh` |
| Legacy Claude / Grok 4.5 | `low`, `medium`, `high` |
| Gemini 3.1 Pro / 3.7 Flash / 3.8 Flash | `low`, `medium`, `high` |
| Gemini 3 Flash / 3.1 Flash Lite / 3.5 Flash / 3.6 Flash | `minimal`, `low`, `medium`, `high` |
| MiniMax M3 | `none` (off), `thinking` (always think); no selection keeps adaptive mode |

Model access gates still apply. Models without a verified end-to-end effort contract (including GLM-5.2, Grok 4.6 and DeepSeek vision-exp) do not gain speculative levels. MiniMax modes are not reasoning-depth levels. Gemini uses native `thinkingConfig.thinkingLevel`, not `reasoning_effort`.

The server owns this catalog; regenerating overwrites the output file, so preserve custom settings first. No CLI package update is needed for catalog changes. For rollout, deploy the LiteLLM effort-forwarding hook before the backend catalog/validation change, then regenerate configs; this avoids advertising levels while an older proxy still pins or drops them. This command does not deploy either service.

### init-pi

Generate config for [Pi](https://pi.dev) (`@earendil-works/pi-coding-agent`), pre-configured to use Genspark's LLM proxy with your API key. Pi reads two files under `~/.pi/agent/`, so the command writes both:

- `models.json` — the `genspark-llm-proxy` (OpenAI-compatible) and `genspark-gemini-proxy` providers, with the same catalog, context windows, output limits, credit cost, and reasoning ladder OpenCode receives.
- `settings.json` — `defaultProvider` / `defaultModel`.

```bash
# Write both files to ~/.pi/agent/
gsk init-pi

# Specify a different default model
gsk init-pi --model claude-opus-4-8

# Write to a custom directory
gsk init-pi -o ./pi-config
```

| Option | Default | Description |
|--------|---------|-------------|
| `--model <name>` | Server-selected | Default model for Pi |
| `-o, --out <dir>` | `~/.pi/agent` | Output directory for `models.json` + `settings.json` |

Unlike `init-opencode` (whose single file belongs entirely to GSK), both Pi files are shared: `models.json` also holds your own providers and `settings.json` every other Pi setting. `init-pi` **merges** — it upserts the two Genspark providers and the default model, leaving everything else intact. Re-running picks up new models without touching your config.

Pi exposes reasoning through its thinking-level picker: levels the model does not support are hidden. `MiniMax M3` exposes `off` and `high`; all other models follow the OpenCode table above (Pi's `off` ⇄ the provider's `none` effort). Cost is emitted as Genspark credits per 1M tokens, the same number OpenCode's fork displays; Pi labels that footer as USD, so treat it as an estimate — the billed figure arrives in-band on each call.

### init-skills

Sync GSK skill documents into the current project for AI agent discovery. Copies all skill docs and generates a `CONTEXT.md` entry point that AI agents (Claude Code, Gemini, Pi, etc.) can load automatically.

```bash
# Copy skills to .gsk/skills/ and generate CONTEXT.md
gsk init-skills

# Also generate .claude/ config for Claude Code
gsk init-skills --agent claude

# Generate config for all supported agents (Claude, Gemini, Pi)
gsk init-skills --agent all

# Custom output directory
gsk init-skills -o ./docs/gsk-skills
```

| Option | Default | Description |
|--------|---------|-------------|
| `-o, --out <dir>` | `.gsk/skills` (cwd) | Output directory for skills |
| `--agent <type>` | — | Generate agent config: `claude`, `gemini`, `pi`, or `all` |

`--agent pi` writes (`pi` auto-loads it) `AGENTS.md` referencing `CONTEXT.md`; `--agent claude` writes/appends `CLAUDE.md` and `--agent gemini` writes `gemini-extension.json`.

### init-genspark-code-skills

Fetch the genspark-code (code sandbox) skill documents into the current project for AI agent discovery. Covers the full developer-skill set a sandbox can install — web / Cloudflare / Flutter / Shopify / HTML5-game development, hosted deployment, and GitHub workflows. The bundle is served by the backend (`/api/tool_cli/genspark-code-skills`), so newly edited skill docs reach released CLIs without a package update.

```bash
# Copy skills to .genspark-code/skills/
gsk init-genspark-code-skills

# Custom output directory
gsk init-genspark-code-skills -o ./docs/genspark-code-skills
```

| Option | Default | Description |
|--------|---------|-------------|
| `-o, --out <dir>` | `.genspark-code/skills` (cwd) | Output directory for skills |

There is no `--agent` flag: an existing `CONTEXT.md` from `gsk init-skills` is left untouched. A built-in whose requirement the caller doesn't satisfy — the org-only `gsk-hosted-org-member` for a non-member — is omitted, so an agent never sees docs for a capability the server would refuse.

### Search & Crawl

### web_search (alias: `search`)

Search the web.

```bash
gsk search "latest AI news"
```

### crawler (alias: `crawl`)

Extract content from a web page or document.

```bash
gsk crawl "https://example.com/article"
```

### summarize_large_document (alias: `summarize`)

Analyze a document and answer questions about it.

```bash
gsk summarize "https://example.com/report.pdf" --question "What are the key findings?"
```

| Option | Description |
|--------|-------------|
| `<url>` | Document URL (**required**, positional) |
| `--question <text>` | Question about the document |

### image_search (alias: `img-search`)

Search for images on the web.

```bash
gsk img-search "modern architecture"
```

### Media Analysis & Transcription

### understand_images (alias: `analyze`)

Analyze images with AI vision model.

```bash
gsk analyze "Describe this image" -i "https://example.com/image.jpg"
gsk analyze "Extract all text" -i "https://img1.jpg" "https://img2.jpg"
gsk analyze "What's in this photo?" -i ./photo.jpg
```

| Option | Default | Description |
|--------|---------|-------------|
| `-i, --image_urls <url...>` | — | Image URL(s) or local file path(s) to analyze (**required**) |
| `-r, --instruction <text>` | — | Custom analysis instruction |

### Image Generation

### image_generation (alias: `img`)

Generate images using AI. Supports text-to-image and image-to-image.

```bash
# Text-to-image
gsk img "A beautiful sunset over mountains" -r "16:9" -o ./sunset.png
gsk img "Modern office at night" -s "4k" -r "1:1"

# Image-to-image (reference-based)
gsk img "A portrait in similar style" -i ./reference.png
```

| Option | Default | Description |
|--------|---------|-------------|
| `-r, --aspect_ratio <ratio>` | `1:1` | Aspect ratio (`1:1`, `16:9`, `9:16`) |
| `-s, --image_size <size>` | `auto` | Image size: `auto`, `2k`, `4k` |
| `-m, --model <name>` | — | Model to use (optional) |
| `-i, --image_urls <url...>` | — | Reference image URL(s) or local file(s) for image-to-image |
| `-o, --output-file <path>` | — | Download the generated file to a local path |

### Video Generation

### video_generation (alias: `video`)

Generate videos using AI.

```bash
gsk video "A cat playing with yarn" -m "kling/v1.6/standard" -d 5 -o ./cat.mp4
gsk video "Sunrise over a beach" -m "minimax/hailuo-02/standard" -r "16:9" -d 8

# Image-to-video
gsk video "Camera pan around the subject" -m "kling/v1.6/standard" -i ./photo.jpg
```

| Option | Default | Description |
|--------|---------|-------------|
| `-m, --model <name>` | — | Model (**required**). e.g., `kling/v1.6/standard`, `minimax/hailuo-02/standard` |
| `-r, --aspect_ratio <ratio>` | `16:9` | Aspect ratio |
| `-d, --duration <sec>` | `5` | Duration in seconds (2-15) |
| `-i, --image_urls <url...>` | — | Reference image URL(s) or local file(s) |
| `-a, --audio_url <url>` | — | Audio URL for soundtrack |
| `-o, --output-file <path>` | — | Download the generated file to a local path |

### Audio Generation

### audio_generation (alias: `audio`)

Generate audio: TTS, music, or sound effects. Each model takes its own `params`
object — run `gsk model-info <model>` first for the `params_schema`, the
available speakers and the prompting guide. A miss on `model-info` answers with
the closest catalog ids.

```bash
# Text-to-speech with Gemini 3.8 Flash TTS (also available: google/gemini-3.8-flash-lite-tts)
gsk model-info google/gemini-3.8-flash-tts
gsk audio "Speaker1: Hello, welcome to Genspark!" -m google/gemini-3.8-flash-tts \
  -p '{"speakers":[{"speaker":"Speaker1","voice_name":"Kore"}],"instructions":"Speak warmly."}' -o ./hello.mp3

# Song with lyrics
gsk audio "Upbeat synth-pop, female vocal" -m minimax/music-3.0 \
  -p '{"lyrics":"[Verse]\nCity lights are calling..."}' -o ./song.mp3

# Sound effect
gsk audio "Door creaking slowly open" -m elevenlabs/sound-effects -p '{"duration":4}' -o ./door.mp3
```

| Option | Default | Description |
|--------|---------|-------------|
| `-m, --model <name>` | `fal-ai/elevenlabs/tts/multilingual-v2` | Model id, e.g., `google/gemini-3.8-flash-tts`, `google/gemini-3.8-flash-lite-tts`, `elevenlabs/v4-tts`, `fal-ai/minimax/speech-2.8-hd` |
| `-p, --params <json>` | — | Model-specific parameters following the model's `params_schema` (speakers, speed/pitch/volume, duration, lyrics, ...) |
| `-d, --duration <sec>` | — | Duration in seconds for sound-effect/music models (prefer `params`) |
| `-l, --lyrics <text>` | — | Lyrics for song models (prefer `params`) |
| `-o, --output-file <path>` | — | Download the generated file to a local path |

### File Transfer

### upload

Upload a local file and get a URL for use in other commands.

```bash
gsk upload "./image.png"
gsk upload "./document.pdf"
```

### download

Download a file from a file wrapper URL.

```bash
# Get download URL only
gsk download "/api/files/s/abc123"

# Download and save to local file
gsk download "/api/files/s/abc123" -s "./downloaded.png"
```

| Option | Description |
|--------|-------------|
| `-s, --save <path>` | Download and save to local file path |

Without `--save` the response carries `download_url`, a 24-hour signed URL you can hand to `curl` or an external service. With `--save` the response lists only the saved file — `file_name`, `content_type`, `local_path`, `size_bytes` — and no `download_url`/`original_url`.

### analyze_media (alias: `media-analyze`)

Analyze various types of media content including images, audio, and video.

```bash
gsk media-analyze -i "https://example.com/image.jpg" -r "Describe the content"
gsk media-analyze -i "https://example.com/video.mp4" -r "Summarize the video"
```

| Option | Default | Description |
|--------|---------|-------------|
| `-i, --media_urls <urls>` | — | Media URL(s) to analyze (**required**) |
| `-r, --requirements <text>` | — | Analysis instructions |

### audio_transcribe (alias: `transcribe`)

Transcribe audio files to text.

```bash
gsk transcribe -i "https://example.com/audio.mp3"
gsk transcribe -i ./meeting.wav -m "whisper-large-v3"
```

| Option | Default | Description |
|--------|---------|-------------|
| `-i, --audio_urls <url...>` | — | Audio URL(s) or local file(s) to transcribe (**required**) |
| `-m, --model <name>` | — | Transcription model to use |

### AI Drive (Cloud Storage)

### aidrive (alias: `drive`)

AI-Drive file storage and management. Canonical workspaces are `my_drive`,
`shared_with_me`, and `shared_drive`. Run `ls` on a shared workspace first, then pass
the returned stable `source_id` to work inside one source. `shared_with_me` is
an ACL-filtered view and does not own bytes or quota.

```bash
# List files in root directory
gsk drive ls --workspace my_drive
gsk drive ls --workspace my_drive -p "/documents" -f file

# Discover and read a source shared with you
gsk drive ls --workspace shared_with_me
gsk drive ls --workspace shared_with_me --source "<source_id>"

# Create directory
gsk drive mkdir -p "/my-folder"

# Move file
gsk drive move -p "/old-path/file.txt" --target_path "/new-path/file.txt"

# Download an external video/audio/file into AI-Drive (the "download for me" actions)
gsk drive download_video --video_url "https://example.com/video.mp4" --target_folder "/videos"
gsk drive download_file --file_url "https://example.com/doc.pdf" --target_folder "/docs"

# Download an AI-Drive file to the local machine
gsk drive download "/docs/report.pdf" ./report.pdf

# Upload inline text content to AI-Drive
gsk drive upload --file_content "Hello World" --upload_path "/notes/hello.txt"

# Upload a local file directly to AI-Drive (streaming, supports 100MB+ files)
gsk drive upload --local_file ./report.pdf --upload_path /docs/report.pdf
gsk drive upload --local_file ./video.mp4 --upload_path /videos/demo.mp4

# Share a My Drive file with a GenTeam channel (posts its card; --post_card false opens it silently)
gsk drive share -p "/docs/report.pdf" --to "channel:<server_id>:<channel_id>" --permission edit
gsk drive unshare -p "/docs/report.pdf" --to "channel:<server_id>:<channel_id>"

# Share a Team Drive file with a channel: pick the drive with --source (from `ls --workspace shared_drive`),
# then name the entry by path relative to that source (or --id); you must manage sharing there
gsk drive share --workspace shared_drive --source "<source_id>" -p "/bug/clip.mov" --to "channel:<server_id>:<channel_id>"
gsk drive upload --local_file ./photo.png              # upload_path defaults to /photo.png
gsk drive upload --local_file ./doc.pdf --upload_path /docs/doc.pdf --override  # overwrite existing

# Get readable URL for a file
gsk drive get_readable_url -p "/documents/report.pdf"

```

| Option | Default | Description |
|--------|---------|-------------|
| `--workspace <name>` | `my_drive` | `my_drive`, `shared_with_me`, or `shared_drive` |
| `--source <id>` | — | Stable source ID returned by listing a shared workspace |
| `-p, --path <path>` | — | File or directory path in AI-Drive |
| `-f, --filter_type <type>` | `all` | Filter: `all`, `file`, `directory` |
| `--file_type <type>` | `all` | File type filter: `all`, `audio`, `video`, `image` |
| `--target_path <path>` | — | Target path for move operations |
| `--target_folder <path>` | — | Target folder for `download_video`, `download_audio`, or `download_file` |
| `--video_url <url>` | — | External video URL for `download_video` |
| `--audio_url <url>` | — | External audio/video URL for `download_audio` |
| `--file_url <url>` | — | External file URL for `download_file` |
| `--file_name <name>` | — | Custom filename for `download_file` |
| `--file_content <text>` | — | Inline text content to upload |
| `--local_file <path>` | — | Local file path to upload directly to AI-Drive (streaming, no size limit) |
| `--upload_path <path>` | — | Destination path for upload (defaults to `/<filename>` for `--local_file`) |
| `--override` | `false` | Overwrite an existing file at the destination path |

### AI Agents & Tasks

### The `gsk task` tree (create_task and friends)

Create and drive tasks executed by specialized AI agents. `gsk task create`
SUBMITS and returns in seconds with a `run_id` — poll `gsk task status
<run_id>` until it finishes (the terminal status carries the project's
`project_id`/`task_url`), read output with `gsk task info <project_id>`,
send a follow-up with `gsk task ask <project_id> -m "..."`, stop with
`gsk task stop <run_id>`. `--follow` follows the run live and exits with
the terminal result; `--wait true` restores the legacy blocking call.
(The pre-tree `gsk task <type>` form still parses — it is shimmed to
`gsk task create <type>`.)

```bash
# Create a podcast
gsk task create podcasts --task_name "AI Trends" --query "Create a podcast about AI trends" --instructions "Focus on practical applications"

# Create a document
gsk task create docs --task_name "Quantum Report" --query "Write a report on quantum computing" --instructions "Include recent breakthroughs"

# Create slides
gsk task create slides --task_name "Q4 Results" --query "Create a Q4 results presentation" --instructions "Use charts and data"

# Create a spreadsheet (returns file wrapper URL, use `gsk download` to save)
gsk task create sheets --task_name "Sales Report" --query "Create a quarterly sales report with formulas" --instructions "Use formulas and formatting"

# Deep research
gsk task create deep_research --task_name "Fusion Energy" --query "Research fusion energy advances" --instructions "Cover public and private sector"

# Fact-check a claim
gsk task create cross_check --task_name "Earth shape" --query "The Earth is flat" --instructions "Verify this claim with evidence"
```

| Option | Default | Description |
|--------|---------|-------------|
| `--task_name <name>` | — | Name for the task (**required**) |
| `--query <text>` | — | Query describing what to create (**required**) |
| `--instructions <text>` | — | Detailed instructions (**required**) |
| `--acp` | `false` | Start as ACP (Agent Client Protocol) stdio agent for multi-turn use with Genspark Claw |

**Supported task types:** `super_agent`, `podcasts`, `docs`, `slides`, `sheets`, `deep_research`, `website`, `video_generation`, `audio_generation`, `meeting_notes`, `cross_check`

#### ACP Mode

Use `--acp` to start a task agent as an [Agent Client Protocol](https://agentclientprotocol.com/) stdio server. This enables AI agent platforms like [Genspark Claw](https://openclaw.ai) to natively discover and interact with GSK agents, with multi-turn conversation support.

```bash
# Start an ACP agent for slides (used by acpx, not typically run manually)
gsk task create slides --acp

# Start an ACP agent for documents
gsk task create docs --acp
```

**acpx configuration** (`~/.acpx/config.json`):
```json
{
  "agents": {
    "gsk-slides": { "command": "gsk task create slides --acp" },
    "gsk-docs":   { "command": "gsk task create docs --acp" },
    "gsk-sheets": { "command": "gsk task create sheets --acp" }
  }
}
```

Then in Genspark Claw: `/acp spawn gsk-slides` to create and iterate on presentations via natural language.

### share_project (alias: `share-project`)

Make one of **your own** projects publicly viewable — anyone with the link can open it, no login — and return the viewer URL. Owner-only.

```bash
# Make a project public (returns the shareable viewer URL)
gsk share-project <project_id>

# Unshare (back to private)
gsk share-project <project_id> --permission private
```

| Option | Default | Description |
|--------|---------|-------------|
| `<project_id>` | — | The project id to share (**required**) |
| `--permission <value>` | `link` | `link` = public, `private` = unshare |

> Availability is gatekeeper-gated — the command appears only where it is enabled for your account.

### Stock Prices

### stock_price (alias: `stock`)

Retrieve stock price information and financial data.

```bash
gsk stock AAPL
gsk stock MSFT
```

### Connectors (unified)

One fixed flow discovers and invokes **any** connector — Gmail, Slack, Notion, HubSpot, custom MCP servers, and every connector added after this README was written:

```bash
gsk connector list                      # what is already connected?
gsk connector search <keyword>          # does a connector for X exist?
gsk connector tools <identifier>        # full JSON schema per tool
gsk connector call <identifier> -t <tool> -a '<json>'   # invoke it
```

`<identifier>` accepts a connector id (`gmail`, `slack`, `hubspot`), a display name (`"Google Drive"`), or an MCP slug. Prefer this over the per-service commands below — see `skills/gsk-connector/SKILL.md` for the full flow, error codes, and examples.

> **Requirements:** Connect services in [Genspark Account Settings → Integrations](https://www.genspark.ai/settings/integrations).

### Service-Level Tools

External service integrations are available as **service-level tools** — each service is a single command with an `action` parameter that dispatches to the underlying operation.

> **Deprecated but working:** these per-service commands still work and are documented below for reference, but new integrations only ship in the unified `gsk connector` flow above — prefer that for anything new.

> **Requirements:** Connect services in [Genspark Account Settings → Integrations](https://www.genspark.ai/settings/integrations).

#### gmail

Gmail operations: search, read, send, reply, forward, delete, archive, move, mark_as_read, add_label, remove_label, create_label, get_attachment, list_send_as.

```bash
gsk gmail search --query "from:boss subject:report"
gsk gmail read --id 19cbfecd7fb14d46
gsk gmail send --to user@example.com --subject "Hello" --body "<p>Hi!</p>"
gsk gmail forward --message_id 19cbfecd7fb14d46 --to colleague@example.com
gsk gmail archive --message_id 19cbfecd7fb14d46
```

#### outlook_email

Outlook Email operations: search, read, send, reply, reply_draft, forward, delete, archive, move, mark_as_read, add_category, remove_category, get_attachment, group_list, group_search, group_read, group_reply.

```bash
gsk outlook_email search --queryString "quarterly report"
gsk outlook_email read --messageId AAMkAG...
gsk outlook_email send --to user@example.com --subject "Update" --body "Hi!"
```

#### google_calendar

Google Calendar operations: list, create, delete.

```bash
gsk google_calendar list
gsk google_calendar create --summary "Team Sync" --start_time "2026-04-20T10:00:00Z" --end_time "2026-04-20T11:00:00Z"
```

#### outlook_calendar

Outlook Calendar operations: list, create, delete.

```bash
gsk outlook_calendar list
```

#### meeting

Meeting notes operations: list, search, get.

```bash
gsk meeting list
gsk meeting search --keyword "quarterly planning"
gsk meeting get --task_id "e02fd0f1-..."
```

#### google_drive

Google Drive file operations: list, search, read, upload.

```bash
gsk google_drive list --folder_url "https://drive.google.com/drive/folders/..."
gsk google_drive search --query "budget 2026"
gsk google_drive read --file_id 1hq9kH63sc...
```

#### google_sheets

Google Sheets operations: create, read, write, append, search, export.

```bash
gsk google_sheets search --query "sales report"
gsk google_sheets read --spreadsheet_id 1ABC... --range "Sheet1!A1:D10"
```

#### google_docs

Google Docs operations: create, read, append, search.

```bash
gsk google_docs search --query "meeting notes"
gsk google_docs read --document_id 1ABC...
```

#### google_contacts

Google Contacts operations: search, get, create, update.

```bash
gsk google_contacts search --query "John"
```

#### github

GitHub operations: list_repos, search_issues, create_issue, update_issue.

```bash
gsk github list_repos
gsk github search_issues --q "repo:owner/repo is:open label:bug"
gsk github create_issue --owner myorg --repo myrepo --title "Bug report" --body "Description..."
```

#### slack

Slack messaging operations: send, search, lookup.

```bash
gsk slack search --query "deployment update"
gsk slack lookup --lookup_type channels --search_query "engineering"
gsk slack send --recipient "#general" --message "Hello team!"
```

#### notion

Notion page operations: search, read, create.

```bash
gsk notion search --query "project roadmap"
gsk notion read --page_id 2ce8b6a5-...
```

#### microsoft_teams

Microsoft Teams operations: send, list_channels, list_chats, list_teams, search, search_users, create_chat.

```bash
gsk microsoft_teams list_teams
gsk microsoft_teams list_channels --team_id 6c0db3a9-...
gsk microsoft_teams search --query "release notes"
```

#### onedrive

OneDrive file operations: list, search, read.

```bash
gsk onedrive search --query "presentation"
gsk onedrive list --folder_path "/Documents"
```

#### sharepoint

SharePoint operations: list, search, read_content, read_file.

```bash
gsk sharepoint search --query "company wiki"
gsk sharepoint list --site_id abc123
```

#### outlook_contacts

Outlook Contacts operations: search.

```bash
gsk outlook_contacts search --query "John"
```

### Telephony

### telephony call

Make an AI phone call on your behalf. The AI validates prerequisites, resolves contact info, and initiates the call. Dialing is the default subcommand; companion subcommands (`status`, `hangup`, `log`, `detail`) inspect and control your calls, and `gsk telephony sms send` sends SMS.

The pre-migration form `gsk phone-call …` still works as a hidden deprecated alias; the flat `gsk sms` was retired — use `gsk telephony sms send`.

```bash
# Call a business by phone number
gsk telephony call "Pizza Hut" -c "+1-555-123-4567" -p "Check if they deliver to my area"

# Call a business by Google Maps place_id (the contact_info type is
# detected automatically from its shape — there is no flag to set)
gsk telephony call "Joe's Pizza" -c "ChIJxxxxxxxx" -p "Reserve a table for 4"

# Dry run: validate and resolve contact info without initiating the call
gsk telephony call "Pizza Hut" -c "+1-555-123-4567" -p "Check hours" --dry-run
```

| Option | Default | Description |
|--------|---------|-------------|
| `<recipient>` | — | Name of the person or business to call (**required**, positional) |
| `-c, --contact_info <value>` | — | Phone number, `calllog:` contact_ref, or Google Maps place_id — type detected automatically (**required**) |
| `-p, --purpose <value>` | — | Purpose of the call (**required**) |
| `--dry-run` | — | Only validate and resolve contact info (and `--from_number` when given), do not initiate the call |
| `--async` | — | Return right after dialing starts; poll with `gsk telephony call status`, stop with `gsk telephony call hangup` |
| `--from_number <value>` | — | Dial from this number (strict E.164, e.g. `+14155550123`) — one of your verified caller IDs or active purchased numbers |

### Social Media

Retrieve data from Twitter/X, Instagram, and Reddit. All social commands are grouped under `gsk social`.

#### social twitter

Search and retrieve data from Twitter/X. 12 actions available.

```bash
# Search tweets
gsk social twitter search_posts -q "artificial intelligence" --start_date 2026-03-01 --language en

# Search users
gsk social twitter search_users -q "openai" --limit 5

# Get tweets by a specific author
gsk social twitter get_posts_by_author -q "elonmusk" --start_date 2026-01-01

# Get tweets by IDs
gsk social twitter get_posts_by_ids --post_ids "123456789,987654321"

# Get user profile
gsk social twitter get_user -q "elonmusk"

# Get followers or following
gsk social twitter get_user_connections -q "elonmusk" --connection_type followers

# Get users by keywords (mentioned in tweets)
gsk social twitter get_users_by_keywords -q "machine learning" --start_date 2026-01-01

# Get comments on a tweet
gsk social twitter get_comments -p "123456789" --start_date 2026-03-01

# Get quotes of a tweet
gsk social twitter get_quotes -p "123456789"

# Get retweets of a tweet
gsk social twitter get_retweets -p "123456789"

# Get users who interacted with a tweet
gsk social twitter get_post_interacting_users -p "123456789" --interaction_type retweeters

# Count posts matching a query
gsk social twitter count_posts -q "AI" --start_date 2026-03-01 --end_date 2026-03-10
```

| Option | Default | Description |
|--------|---------|-------------|
| `<action>` | — | Action to perform (**required**, positional) |
| `-q, --query <text>` | — | Search query, username, or identifier |
| `-p, --post_id <id>` | — | Tweet/post ID |
| `--post_ids <ids>` | — | Comma-separated tweet IDs |
| `--connection_type <type>` | `followers` | `followers` or `following` |
| `--interaction_type <type>` | `retweeters` | `commenters`, `quoters`, or `retweeters` |
| `--start_date <YYYY-MM-DD>` | — | Start date filter |
| `--end_date <YYYY-MM-DD>` | — | End date filter |
| `--language <code>` | — | Language filter (e.g., `en`, `zh`) |
| `--limit <n>` | — | Max number of results |

**Actions:** `search_posts`, `search_users`, `get_posts_by_author`, `get_posts_by_ids`, `get_user`, `get_user_connections`, `get_users_by_keywords`, `get_comments`, `get_quotes`, `get_retweets`, `get_post_interacting_users`, `count_posts`

#### social instagram

Search and retrieve data from Instagram. 9 actions available.

```bash
# Search posts
gsk social instagram search_posts -q "travel photography" --start_date 2026-01-01

# Search users
gsk social instagram search_users -q "natgeo" --limit 5

# Get posts by a specific user
gsk social instagram get_posts_by_user -q "natgeo" --start_date 2026-03-01

# Get posts by IDs
gsk social instagram get_posts_by_ids --post_ids "abc123,def456"

# Get user profile
gsk social instagram get_user -q "natgeo"

# Get followers or following
gsk social instagram get_user_connections -q "natgeo" --connection_type following

# Get users by keywords
gsk social instagram get_users_by_keywords -q "landscape photographer"

# Get comments on a post
gsk social instagram get_comments -p "abc123" --start_date 2026-03-01

# Get users who liked or commented on a post
gsk social instagram get_post_interacting_users -p "abc123" --interaction_type likers
```

| Option | Default | Description |
|--------|---------|-------------|
| `<action>` | — | Action to perform (**required**, positional) |
| `-q, --query <text>` | — | Search query, username, or identifier |
| `-p, --post_id <id>` | — | Post ID |
| `--post_ids <ids>` | — | Comma-separated post IDs |
| `--connection_type <type>` | `followers` | `followers` or `following` |
| `--interaction_type <type>` | `likers` | `likers` or `commenters` |
| `--start_date <YYYY-MM-DD>` | — | Start date filter |
| `--end_date <YYYY-MM-DD>` | — | End date filter |
| `--limit <n>` | — | Max number of results |

**Actions:** `search_posts`, `search_users`, `get_posts_by_user`, `get_posts_by_ids`, `get_user`, `get_user_connections`, `get_users_by_keywords`, `get_comments`, `get_post_interacting_users`

#### social reddit

Search and retrieve data from Reddit. 9 actions available.

```bash
# Search posts (with sort and time filters)
gsk social reddit search_posts -q "rust programming" --sort top --time week -s "programming"

# Search comments
gsk social reddit search_comments -q "async await" -s "rust"

# Search users
gsk social reddit search_users -q "spez" --limit 5

# Search subreddits
gsk social reddit search_subreddits -q "machine learning" --limit 10

# Get a post with its comments
gsk social reddit get_post_with_comments -p "1abc2de"

# Get subreddit info with recent posts
gsk social reddit get_subreddit_with_posts -q "programming"

# Get subreddits by keywords
gsk social reddit get_subreddits_by_keywords -q "artificial intelligence"

# Get user profile
gsk social reddit get_user -q "spez"

# Get users by keywords (active in discussions)
gsk social reddit get_users_by_keywords -q "neural networks" -s "MachineLearning"
```

| Option | Default | Description |
|--------|---------|-------------|
| `<action>` | — | Action to perform (**required**, positional) |
| `-q, --query <text>` | — | Search query, username, or subreddit name |
| `-p, --post_id <id>` | — | Post ID |
| `-s, --subreddit <name>` | — | Subreddit name filter |
| `--sort <order>` | — | Sort: `relevance`, `hot`, `top`, `new`, `comments` |
| `--time <range>` | — | Time filter: `hour`, `day`, `week`, `month`, `year`, `all` |
| `--start_date <YYYY-MM-DD>` | — | Start date filter |
| `--end_date <YYYY-MM-DD>` | — | End date filter |
| `--limit <n>` | — | Max number of results |

**Actions:** `search_posts`, `search_comments`, `search_users`, `search_subreddits`, `get_post_with_comments`, `get_subreddit_with_posts`, `get_subreddits_by_keywords`, `get_user`, `get_users_by_keywords`

## Local File Handling

Most commands that accept URLs also accept local file paths. The CLI automatically uploads local files before passing them to the API:

```bash
# These are equivalent:
gsk analyze "Describe this" -i ./photo.jpg
gsk img "Enhance this" -i ./photo.png -o ./result.png
gsk video "Animate this" -i ./frame.jpg -o ./video.mp4
```

Use `-o` / `--output-file` to save generated results directly to a local file.

## Auto-Update

The CLI checks for updates every 4 hours and installs new versions in the background.

To disable auto-update:

```bash
# Via environment variable
export GSK_NO_AUTO_UPDATE=1

# Via config file
# Add "auto_update": false to ~/.genspark-tool-cli/config.json
```

## Output Conventions

| Stream | Content | Consumer |
|--------|---------|----------|
| **stdout** | JSON result | Programs / AI agents |
| **stderr** | Progress, debug, error messages | Human / logs |

This separation allows programs to parse clean JSON from stdout while humans can follow progress on stderr.

## Mesh — Secure SSH Between Your Devices

`gsk mesh` gives all the devices signed in to your Genspark account a private, end-to-end-encrypted network (a "tailnet", Tailscale-based) and SSH over it — no public IPs, no port-forwarding on your router, no separate login. Each device gets a stable `100.64.x.x` address; any device can reach any other.

It reuses your `gsk` login: once you `gsk login`, every `gsk mesh` command authenticates with the same token.

`gsk mesh` is a thin wrapper around the native `gsk-mesh` binary, fetched from the Genspark CDN on first use (~45 MB), verified by sha256, cached at `~/.genspark-tool-cli/bin/gsk-mesh`, and re-verified on every run (Apple-notarized on macOS, DigiCert-signed on Windows). Supported platforms: macOS (arm64/x64), Linux (x64/arm64), Windows (x64).

> **Scope:** the mesh only spans devices signed in to **your own account**. "Other devices" below always means your other devices — there is no cross-account access.

### Command reference

| Command | What it does |
|---|---|
| `gsk mesh join [--name <name>]` | Enroll **this** device in the mesh. Starts the local tailscaled daemon and reports the assigned tailnet IP. Run once per device. |
| `gsk mesh leave` | Sign this device out of the mesh, stop tailscaled, and remove its published SSH key. |
| `gsk mesh serve [--stop]` | Make this device **accept** incoming mesh SSH (runs an embedded SSH server — no OS-level `sshd` needed). Requires `join`. Keeps serving via a detached daemon; `--stop` tears it down. |
| `gsk mesh ssh <[user@]node> [-- <args>]` | SSH **into** another device. Anything after `--` is passed to `ssh` (a remote command, `-i`, etc.). |
| `gsk mesh scp <src...> <dst>` | Copy files to/from a node. Remote refs look like `[user@]node:path`. |
| `gsk mesh sftp <node>` | Interactive SFTP session to a node. |
| `gsk mesh forward -L <spec> <node>` | Hold an SSH port-forward open through the mesh (`-L` local, `-R` remote; repeatable). |
| `gsk mesh devices` | List the devices currently on your tailnet. |
| `gsk mesh status` | Health of the mesh + whether this device is serving. |
| `gsk mesh revoke <node-id>` | Expire another device by its id (from `gsk mesh devices`). |
| `gsk mesh whoami` | Show the resolved auth state (token source, base URL). |
| `gsk mesh upgrade [--force\|--prerelease]` | Update the native `gsk-mesh` binary. |

`node` is either a device name (resolved against `gsk mesh devices`) or a tailnet IP. Run `gsk mesh --help` (or `gsk mesh <cmd> --help`) for the authoritative, native help.

### 1. First-time setup (every device)

```bash
gsk login                       # once per machine; shared with all gsk commands
gsk mesh join --name laptop     # downloads gsk-mesh on first use, joins the mesh
# Joined mesh as laptop (100.64.0.5).
```

Do this on each device you want in the mesh (`--name` defaults to the hostname).

### 2. Make a device reachable (the "server" side)

To let your **other** devices SSH *into* this one — e.g. a home workstation, a build box, a cloud VM:

```bash
gsk mesh serve                  # embedded SSH server; no sshd to install/configure
# Serving mesh SSH. Reachable at 100.64.0.7:22.
gsk mesh serve --stop           # stop accepting connections
```

`serve` runs in the background and keeps serving after the command returns. Authorization is automatic: each serving device publishes its mesh SSH public key to your account, and peers pull the set — so a freshly-joined device can connect without any manual key exchange. (No `~/.ssh/authorized_keys` editing, no OpenSSH Server feature on Windows.)

### 3. Connect to other devices (the "client" side)

```bash
gsk mesh ssh laptop                              # interactive shell
gsk mesh ssh user@laptop                         # specify the remote login user
gsk mesh ssh laptop -- 'systemctl status nginx'  # run a remote command and exit
gsk mesh ssh laptop -i ~/.ssh/id_ed25519         # use a specific identity file

gsk mesh scp ./build.tar.gz laptop:~/releases/   # push a file
gsk mesh scp laptop:/var/log/app.log ./          # pull a file
gsk mesh sftp laptop                             # interactive file browsing

# Forward a remote service to your local machine (e.g. a DB on the workstation):
gsk mesh forward -L 5432:localhost:5432 workstation
# Now localhost:5432 tunnels to the workstation over the mesh.
```

`ssh`/`scp`/`sftp`/`forward` shell out to your system `ssh`/`scp` over the tunnel, so all OpenSSH features work as-is: agent forwarding, `~/.ssh/config`, PTY, signal handling. To use a **non-default port**, set it in `~/.ssh/config` (`Host laptop` / `Port 2222`) — trailing `-- ...` args land in the remote-command position, so they're not the place for ssh options like `-p`.

### 4. Manage & inspect

```bash
gsk mesh devices                # who's on the tailnet
gsk mesh status                 # mesh health + serve state
gsk mesh revoke <node-id>       # kick a lost/old device (id from `devices`)
gsk mesh leave                  # remove THIS device from the mesh
```

### 5. Keeping the binary current

```bash
gsk mesh upgrade                # check + pull the latest gsk-mesh release
gsk mesh upgrade --force        # reinstall even if already at the latest
gsk mesh upgrade --prerelease   # opt into the beta channel
```

The native binary versions independently of `@genspark/cli`, so new mesh features land without an `npm install -g @genspark/cli` cycle. Once a binary is installed, `gsk mesh` also checks for updates in the background on the same 4-hour cadence as the CLI's own auto-update (honoring `GSK_NO_AUTO_UPDATE` / `"auto_update": false`; the background check is skipped on Windows, where a running `.exe` can't be replaced in place — run `gsk mesh upgrade` explicitly there).

> `gsk mesh login` / `logout` are not separate flows — `gsk` and `gsk mesh` share one authentication. Use `gsk login` / `gsk logout`.

### End-to-end example: reach a home box from a laptop

```bash
# On the home workstation:
gsk login && gsk mesh join --name workstation && gsk mesh serve

# On the laptop (anywhere in the world):
gsk login && gsk mesh join --name laptop
gsk mesh ssh workstation -- 'uname -a && uptime'
gsk mesh forward -L 8080:localhost:80 workstation   # browse its local web app at localhost:8080
```

## Available Models

<details>
<summary>Image Generation Models — <code>gsk img -m &lt;model&gt;</code></summary>

| Model | Description |
|-------|-------------|
| `nano-banana-2` | Gemini 3.1 Flash Image - Fast and efficient with advanced reasoning. Multi-image fusion with up to 14 references. Supports 0.5K-4K resolution |
| `fal-ai/gpt-image-1.5` | GPT Image 1.5 - Supports text-to-image and image editing with multi-image input |
| `imagen4` | Latest high quality image generation model, upgrade from Imagen 3 |
| `recraft-v3` | Realistic image generation model |
| `fal-ai/bytedance/seedream/v5/lite` | Bytedance Seedream v5 Lite - Text-to-image and image editing with native 2K resolution and excellent text layout |
| `fal-ai/flux-2` | Flux 2 - Text-to-image and image editing with enhanced realism and crisp text generation. Supports up to 3 images for edit mode |
| `fal-ai/flux-2-pro` | Flux 2 Pro - Higher quality version of Flux 2 with professional-grade output |
| `fal-ai/z-image/turbo` | Z-Image Turbo - Optimized for speed. Good for quick iterations, bulk generation, and style transfer |
| `ideogram/V_3` | Ideogram V3 - Character reference specialist with superior facial feature preservation and character consistency |
| `qwen-image` | Chinese poster specialist with outstanding Chinese text rendering and cultural context mastery |
| `bbox-segment` | Extract subjects from images based on bounding box region |
| `fal-bria-rmbg` | Remove background from image |
| `fal-ai/recraft-clarity-upscale` | Upscale image |
| `fal-ai/image-editing/text-removal` | Remove text and watermarks from images while preserving background |
| `flux-pro/outpaint` | Expand image to a specific aspect ratio |

</details>

<details>
<summary>Video Generation Models — <code>gsk video -m &lt;model&gt;</code></summary>

| Model | Capabilities | Aspect Ratios | Duration | Notes |
|-------|-------------|---------------|----------|-------|
| `kling/v3` | Text/Image-to-video | 16:9, 9:16, 1:1 | 3-15s | Latest Kling V3 with audio. Pro/Standard quality modes |
| `gemini/veo3.1` | Text/Image-to-video | 16:9, 9:16 | 8s | Latest Veo with enhanced quality. Supports fast_mode and hd_mode (1080p) |
| `gemini/veo3.1/reference-to-video` | Reference-to-video | 16:9, 9:16 | 8s | Generate video using 1+ reference images. Supports fast_mode and hd_mode |
| `gemini/veo3.1/first-last-frame-to-video` | Frame transition | 16:9, 9:16 | 8s | Precise transitions from first to last frame. Requires exactly 2 images |
| `minimax/hailuo-2.3/standard` | Text/Image-to-video | 16:9, 9:16 | 6s, 10s | Fast (~4min), cost-effective. Supports first & last frame control |
| `wan/v2.6` | Text/Image/Video-to-video | 16:9, 9:16, 1:1, 4:3, 3:4 | 5s, 10s, 15s | 1080p with audio. Supports reference-to-video with 1-3 reference videos |
| `vidu/q3` | Text/Image-to-video | 16:9, 9:16, 4:3, 3:4, 1:1 | 1-16s | Enhanced quality with audio generation. Resolution: 720p, 1080p |
| `runway/gen4_turbo` | Image-to-video | 5:3, 3:5 | 5s, 10s | Fast, high quality. Requires reference image |
| `pixverse/v5` | Text/Image-to-video | 16:9, 9:16, 4:3, 1:1, 3:4 | 5s | Fast (~30s). Supports start/end frame transitions |
| `fal-ai/bytedance/seedance/v1.5/pro` | Text/Image-to-video | 21:9, 16:9, 4:3, 1:1, 3:4, 9:16 | 4-12s | Seedance v1.5 Pro with native audio support. Supports first & last frame control |
| `sora-2` | Text/Image/Video-to-video | 16:9, 9:16 | 4s, 8s, 12s | OpenAI Sora 2 for fast, creative videos. Supports video remixing |
| `sora-2-pro` | Text/Image-to-video | 16:9, 9:16 | 4s, 8s | Sora 2 Pro - Higher fidelity, cinematic quality. 720p and 1080p |
| `fal-ai/bytedance-upscaler/upscale/video` | Video upscaling | — | — | Upscale existing videos to 2K. Requires video_url parameter |
| `xai/grok-imagine-video` | Text/Image-to-video | 16:9, 4:3, 1:1, 3:4, 9:16, 21:9, 9:21 | 1-15s | xAI Grok Imagine Video. 720p HD output |

</details>

<details>
<summary>Audio Generation Models — <code>gsk audio -m &lt;model&gt;</code></summary>

**Text-to-Speech (TTS)**

| Model | Description |
|-------|-------------|
| `google/gemini-3.1-flash-tts-preview` | Gemini 3.1 Flash TTS. Expressive narration with inline audio tags (`[whispers]`, `[excited]`) and up to 2 speakers via `Speaker1: text, Speaker2: text` prefixes |
| `google/gemini-3.8-flash-tts` | Gemini 3.8 Flash TTS. Up to 2 speakers via `speakers` and `Speaker: text` turns; put voice/style directions in `instructions`. 1 credit per 20 characters |
| `google/gemini-3.8-flash-lite-tts` | Gemini 3.8 Flash-Lite TTS. Same speaker and instructions parameters as Flash TTS. 1 credit per 20 characters |
| `bytedance/seed-audio-1.0` | ByteDance Seed-Audio 1.0. Top speech quality plus narration and radio-drama scenes from a description; clones a voice from up to 3 reference clips |
| `alibaba/qwen-audio-3-tts` | Qwen Audio 3.0 TTS (Flash). Fast, low-cost multilingual TTS with 45 preset voices |
| `elevenlabs/v4-tts` | Advanced multilingual TTS (Eleven v4, 85 languages) with multi-speaker dialogue support and emotional tags like `[excited]`, `[whispers]`, `[laughs]`. `params.tier`: `standard` (default) or `turbo` (faster, half price) |
| `elevenlabs/v3-tts` | Legacy id — same Eleven v4 engine as `elevenlabs/v4-tts`; prefer the v4 id |
| `fal-ai/elevenlabs/tts/multilingual-v2` | High-quality multilingual TTS. Preferred for English |
| `fal-ai/minimax/speech-2.8-hd` | High-quality multilingual TTS. Preferred for Chinese, Cantonese, Japanese, Korean. One speaker per generation |

**Sound Effects**

| Model | Description |
|-------|-------------|
| `elevenlabs/sound-effects` | Sound effect generation. Duration: 0.1-22 seconds |

**Music Generation**

| Model | Description |
|-------|-------------|
| `elevenlabs/music` | ElevenLabs music generation with vocals/singing. Lyrics auto-generated (no custom lyrics). Duration: 10s-5min |
| `CassetteAI/music-generator` | Background music generation. Duration: 10-180 seconds |
| `mureka` | Mureka music, `params.mode` picks the product: `song` (default, vocals over `lyrics`, style prompt or reference track), `instrumental` (vocal-free from the prompt), `remix` (re-sing an existing `source_audio_file` mp3/m4a 10-350s with new `lyrics`) |
| `google/lyria-music` | Google Lyria 3 text-to-music (`sub_model`: `lyria-3-clip` 30s clip or `lyria-3-pro` full song). 44.1kHz stereo, vocals with lyrics in multiple languages |
| `minimax/music-3.0` | MiniMax Music 3.0 song generation with lyrics (`is_instrumental` for tracks without vocals). Supports (Verse), (Chorus), (Bridge) markers |

**Voice Cloning & Transformation**

| Model | Description |
|-------|-------------|
| `elevenlabs/voice-clone` | Clone a voice from audio samples. Returns voice ID for use in TTS generation |
| `elevenlabs/voice-changer` | Transform audio from one voice to another. Requires source audio and target voice ID |
| `fal-ai/minimax/voice-clone` | Clone a voice from a sample audio and generate speech from text prompts (gated feature) |

</details>

## License

MIT
