# Tanit commands (LLM brief)

## Built-in CLI commands

### `resize`

Resize / transform an image (libvips, Sharp-like options)

- Allows extra positional arguments.

**Options:**

- `input` (TEXT, optional, positional) — Input path, glob (*, ?, **), or http(s):// URL
- `output` (TEXT, optional, positional) — Output file/dir, or omit when there is exactly one input; writes under cwd (sanitized name)
- `--src` (TEXT, optional) — Input (repeat for multiple); use with --dst; Explorer passes several files
- `--dst` (TEXT, optional) — Same as positional output; directory if multiple inputs
- `--max-width` (INT, optional) — Target / max width (0 = no limit)
- `--max-height` (INT, optional) — Target / max height (0 = no limit)
- `--format` (TEXT, optional) — Output format (default: from extension)
- `--fit` (TEXT, optional, default `inside`) — inside|cover|contain|fill|outside (see Sharp resize.fit)
- `--position` (TEXT, optional, default `centre`) — For cover: centre|attention|entropy|...
- `--kernel` (TEXT, optional, default `lanczos3`) — nearest|cubic|mitchell|lanczos2|lanczos3
- `--quality` (INT, optional, default `85`) — JPEG/WebP/AVIF quality 1-100
- `--png-compression` (INT, optional, default `6`) — PNG DEFLATE 0-9
- `--background` (TEXT, optional) — Letterbox colour #rrggbb (contain)
- `--rotate` (INT, optional, default `0`) — Rotate 0|90|180|270 after EXIF autorotate
- `--flip` (optional, flag) — Vertical flip
- `--flop` (optional, flag) — Horizontal flop
- `--no-autorotate` (optional, flag) — Disable EXIF orientation
- `--no-strip` (optional, flag) — Keep metadata on output
- `--allow-enlargement` (optional, flag) — Allow upscaling (inside/contain/outside)
- `--no-cache` (optional, flag) — Disable output cache (default: cache on)
- `--cache-dir` (TEXT, optional) — Cache root (default: <cwd>/cache/images)
- `--url-timeout` (INT, optional, default `5`) — HTTP(S) fetch timeout (seconds, 0 = libcurl default)
- `--url-max-redirects` (INT, optional, default `20`) — Max redirects when fetching URL inputs

### `transform`

AI image editing (Gemini / Google)

- Allows extra positional arguments.

**Options:**

- `input` (TEXT, optional, positional) — Input image, or use --src for a batch (Explorer multi-select uses --src)
- `--src` (TEXT, optional) — Input path (repeat for multiple files; one job queue / one window with --job-ui on Windows)
- `output` (TEXT, optional, positional) — Output path (omit = auto from input + prompt)
- `--prompt` (TEXT, optional) — Editing prompt (required if --preset-id is not set, unless preset supplies prompt)
- `--preset-id` (TEXT, optional) — Preset id from settings: explorer_presets (op=transform), or chat_web quick action as chat-<id>
- `--provider` (TEXT, optional) — AI provider (google, replicate, pixlwiz); omit = from app Chat image_provider (aborts if unset)
- `--model` (TEXT, optional) — Model id; omit = from app Chat image_model (aborts if unset)
- `--api-key` (TEXT, optional) — API key (optional; default from app provider settings)
- `--aspect-ratio` (TEXT, optional) — Output aspect ratio (1:1,16:9,4:3,...)
- `--image-size` (TEXT, optional) — Output size (512,1K,2K,4K)
- `--reference` (TEXT, optional) — Reference image path (logo / brand sheet / style swatch). Repeatable: -r logo.png -r palette.jpg
- `--json` (optional, flag) — Print machine-readable outputs JSON on stdout.
- `--job-ui` (optional, flag) — List-style job window (pause / cancel) — Windows

### `create`

AI text-to-image (Gemini / Google, no input file)

- Allows extra positional arguments.

**Options:**

- `output` (TEXT, optional, positional) — Output path (omit = create_<slug>.png in cwd)
- `--prompt` (TEXT, required) — Generation prompt
- `--provider` (TEXT, optional) — AI provider (google, replicate, pixlwiz); omit = from app Chat image_provider (aborts if unset)
- `--model` (TEXT, optional) — Model id; omit = from app Chat image_model (aborts if unset)
- `--api-key` (TEXT, optional) — API key (optional; default from app provider settings)
- `--aspect-ratio` (TEXT, optional) — Output aspect ratio (1:1,16:9,4:3,...)
- `--image-size` (TEXT, optional) — Output size (512,1K,2K,4K)
- `--reference` (TEXT, optional) — Reference image path (style / brand). Repeat as needed.
- `--json` (optional, flag) — Print machine-readable outputs JSON on stdout.

### `find`

Find images by name/folder or by semantic prompt via LLM.

- Allows extra positional arguments.

**Options:**

- `input` (TEXT, required, positional) — Input file(s), folder(s) or glob(s); repeatable
- `--prompt` (TEXT, required) — Search query (required)
- `--llm` (optional, flag) — Query mode: match prompt vs filename + .md/.json/EXIF (or generate them); default = LLM judge per file, or --local-text
- `--local-text` (optional, flag) — With --llm: no find:judge Gemini; case-insensitive substring/word match on text only
- `--case-sensitive` (optional, flag) — Name mode: case-sensitive match
- `--no-folders` (optional, flag) — Name mode: don't match parent folder names
- `--no-recursive` (optional, flag) — Don't recurse into directory inputs
- `--bypass-cache` (optional, flag) — LLM: ignore existing .md/.json/EXIF, force re-generate
- `--no-generate` (optional, flag) — LLM: skip images without cached meta (don't call meta_extract)
- `--no-md` (optional, flag) — LLM: don't read sidecar .md
- `--no-json` (optional, flag) — LLM: don't read sidecar .json
- `--no-exif` (optional, flag) — LLM: don't read libvips EXIF tags
- `--max` (INT, optional, default `0`) — Max results (0 = unlimited)
- `--dry-run` (optional, flag) — Resolve candidates + cache, no LLM calls / no writes
- `--json` (optional, flag) — Print JSON array {path,score,source,reason} on stdout
- `--provider` (TEXT, optional) — AI provider for --llm meta/judge; omit = app Chat image_recognition_provider (aborts if unset when --llm)
- `--model` (TEXT, optional) — Model for --llm; omit = app image_recognition_model (aborts if unset when --llm)
- `--api-key` (TEXT, optional) — API key (optional; default from app provider settings)
- `--judge-prompt` (TEXT, optional) — Override the LLM judge prompt
- `--meta-prompt` (TEXT, optional) — Override the cataloguer prompt used when generating cache
- `--no-resize` (optional, flag) — Generation: skip in-memory resize before sending to model
- `--resize-width` (INT, optional, default `512`) — Generation: resize-width for the model input
- `--reference` (TEXT, optional) — LLM: reference image(s), examples of what you're looking for; sent as multimodal parts in every judge call. Repeatable: -r logo.png -r palette.jpg

### `search`

Unified search. Subcommands: search (files), index, detail, action.

- Allows extra positional arguments.

**Subcommands:**

- `search` — Search files with the unified search facade (exact first; semantic later).
- `index` — Index files for semantic search (cron-friendly).
- `detail` — Expand a search hit through the owning source adapter.
- `action` — Run a search-scoped action such as replace (implementation pending).

#### `search search`

Search files with the unified search facade (exact first; semantic later).

- Allows extra positional arguments.

**Options:**

- `input` (TEXT, optional, positional) — File(s), folder(s), or glob(s)
- `--log-level` (TEXT:{trace,debug,info,warn,warning,error,err,critical,off,none}, optional) — Log level for this search command: trace, debug, info, warn, error, critical, off
- `--mode` (TEXT:{auto,name,grep,semantic,metadata,fingerprint}, optional) — auto | name | grep | semantic | metadata | fingerprint (repeatable or comma-separated)
- `--content` (TEXT:{any,text,code,image,document,office,pdf,catalog}, optional) — any | text | code | image | document | office | pdf | catalog (repeatable or comma-separated)
- `--backend` (TEXT:{auto,any,exact,image-meta,vector,fingerprint,catalog}, optional) — auto | exact | image-meta | vector | fingerprint | catalog (repeatable or comma-separated)
- `--sort` (TEXT:{auto,none,score,path,relevance}, optional, default `auto`) — Result order for merged/fan-out search: auto | none | score | path
- `--query` (TEXT, optional) — Search pattern (filename substring, regex, semantic query, or grep needle)
- `--type` (TEXT, optional) — any | image, or rg-style type shorthand: cpp, ts, py, md, ...
- `--indexer` (TEXT:{own,os}, optional, default `own`) — own (default) | os - exact-search indexer
- `--grep` (optional, flag) — Alias for --mode grep
- `--names-only` (optional, flag) — With grep: report only the filepath, not individual match lines
- `--regex` (optional, flag) — Treat --query as ECMAScript regex
- `--case-sensitive` (optional, flag) — Case-sensitive match
- `--whole-word` (optional, flag) — Require word-boundary match
- `--no-recursive` (optional, flag) — Do not recurse into directory inputs
- `--include-hidden` (optional, flag) — Include dot-files and dot-directories
- `--follow-symlinks` (optional, flag) — Follow symbolic links
- `--no-skip-binary` (optional, flag) — Scan binary files
- `--context` (INT:NONNEGATIVE, optional, default `0`) — Symmetric context lines
- `--context-before` (INT:NONNEGATIVE, optional, default `0`) — Context lines before
- `--context-after` (INT:NONNEGATIVE, optional, default `0`) — Context lines after
- `--multiline` (optional, flag) — Enable multiline regex
- `--output-mode` (TEXT:{content,files_with_matches,count}, optional, default `content`) — content (default) | files_with_matches | count
- `--head-limit` (INT, optional, default `0`) — Cap output to first N entries
- `--offset` (INT, optional, default `0`) — Skip first N entries
- `--max` (INT, optional, default `0`) — Max total results
- `--max-per-file` (INT, optional, default `0`) — Max grep matches per file
- `--max-file-size` (INT, optional, default `0`) — Skip grep files larger than N bytes
- `--include` (TEXT, optional) — Only scan filename glob; repeatable
- `--exclude` (TEXT, optional) — Skip filename glob; repeatable
- `--exclude-dir` (TEXT, optional) — Directory names to prune; repeatable
- `--dry-run` (optional, flag) — Resolve candidates and print counts; no matching
- `--json` (optional, flag) — Print JSON
- `--stream` (optional, flag) — Stream NDJSON events (start/task/hit/done) incrementally; cancelable, web-friendly
- `--md` (optional, flag) — Print Markdown result tables/details
- `--markdown` (TEXT:{auto,plain,render}, optional, default `auto`) — With --md: auto (render on TTY), plain (raw Markdown), or render (always run terminal markdown)
- `--markdown-color` (TEXT:{auto,never,always}, optional, default `auto`) — With rendered --md: auto, never, or always
- `--index-policy` (TEXT:{same-dir,specific-dir,disabled}, optional, default `same-dir`) — same-dir | specific-dir | disabled
- `--index` (TEXT, optional) — Vector store/index dir(s); repeatable or glob. Multiple stores => search merges across them
- `--model` (TEXT, optional) — Embedding model hint/path
- `--threads` (INT:POSITIVE, optional, default `4`) — Embedding CPU threads
- `--gpu-layers` (INT, optional, default `0`) — Embedding GPU layers: 0 CPU, -1 all GPU
- `--reindex` (optional, flag) — Force re-ingest before searching
- `--no-index-create` (optional, flag) — Fail if an index is needed but missing
- `--extract` (TEXT, optional, default `auto`) — auto | text | office | pdf
- `--adapter` (TEXT, optional) — Source adapter hint, e.g. image-sidecar | ocr-local | llm-meta | office-officecli
- `--fingerprint` (TEXT:{off,cheap}, optional, default `off`) — off | cheap
- `--chunk-size` (INT, optional, default `500`) — Semantic ingest chunk size
- `--chunk-overlap` (INT, optional, default `100`) — Semantic ingest chunk overlap
- `--meta-prompt` (TEXT, optional) — For --adapter llm-meta: image_understand prompt; empty = built-in search metadata prompt
- `--resize-width` (INT, optional, default `768`) — For --adapter llm-meta: pre-resize longest edge before external image understanding
- `--no-resize` (optional, flag) — For --adapter llm-meta: disable image_understand pre-resize
- `--include-detail` (TEXT:{auto,row,page,section,object,metadata}, optional) — Expand search hits with adapter detail: auto | row | page | section | object | metadata
- `--detail-max` (INT:NONNEGATIVE, optional, default `0`) — With --include-detail: expand at most N hits (0 = all returned hits)

#### `search index`

Index files for semantic search (cron-friendly).

- Allows extra positional arguments.

**Options:**

- `input` (TEXT, optional, positional) — File(s), folder(s), or glob(s)
- `--log-level` (TEXT:{trace,debug,info,warn,warning,error,err,critical,off,none}, optional) — Log level for this search command: trace, debug, info, warn, error, critical, off
- `--mode` (TEXT:{auto,name,grep,semantic,metadata,fingerprint}, optional) — auto | name | grep | semantic | metadata | fingerprint (repeatable or comma-separated)
- `--content` (TEXT:{any,text,code,image,document,office,pdf,catalog}, optional) — any | text | code | image | document | office | pdf | catalog (repeatable or comma-separated)
- `--backend` (TEXT:{auto,any,exact,image-meta,vector,fingerprint,catalog}, optional) — auto | exact | image-meta | vector | fingerprint | catalog (repeatable or comma-separated)
- `--sort` (TEXT:{auto,none,score,path,relevance}, optional, default `auto`) — Result order for merged/fan-out search: auto | none | score | path
- `--index-policy` (TEXT:{same-dir,specific-dir,disabled}, optional, default `same-dir`) — same-dir | specific-dir | disabled
- `--index` (TEXT, optional) — Vector store/index dir(s); repeatable or glob. Multiple stores => search merges across them
- `--model` (TEXT, optional) — Embedding model hint/path
- `--threads` (INT:POSITIVE, optional, default `4`) — Embedding CPU threads
- `--gpu-layers` (INT, optional, default `0`) — Embedding GPU layers: 0 CPU, -1 all GPU
- `--reindex` (optional, flag) — Force re-ingest before searching
- `--no-index-create` (optional, flag) — Fail if an index is needed but missing
- `--extract` (TEXT, optional, default `auto`) — auto | text | office | pdf
- `--adapter` (TEXT, optional) — Source adapter hint, e.g. image-sidecar | ocr-local | llm-meta | office-officecli
- `--fingerprint` (TEXT:{off,cheap}, optional, default `off`) — off | cheap
- `--chunk-size` (INT, optional, default `500`) — Semantic ingest chunk size
- `--chunk-overlap` (INT, optional, default `100`) — Semantic ingest chunk overlap
- `--meta-prompt` (TEXT, optional) — For --adapter llm-meta: image_understand prompt; empty = built-in search metadata prompt
- `--resize-width` (INT, optional, default `768`) — For --adapter llm-meta: pre-resize longest edge before external image understanding
- `--no-resize` (optional, flag) — For --adapter llm-meta: disable image_understand pre-resize
- `--json` (optional, flag) — Print unified JSON envelope
- `--md` (optional, flag) — Print Markdown result tables
- `--markdown` (TEXT:{auto,plain,render}, optional, default `auto`) — With --md: auto (render on TTY), plain (raw Markdown), or render
- `--markdown-color` (TEXT:{auto,never,always}, optional, default `auto`) — With rendered --md: auto, never, or always

#### `search detail`

Expand a search hit through the owning source adapter.

- Allows extra positional arguments.

**Options:**

- `--log-level` (TEXT:{trace,debug,info,warn,warning,error,err,critical,off,none}, optional) — Log level for this search command: trace, debug, info, warn, error, critical, off
- `--adapter` (TEXT, optional) — Owning source adapter ID, e.g. office-officecli
- `--path` (TEXT, required) — Source file path
- `--selector` (TEXT, optional) — Adapter-owned selector, e.g. officecli query selector
- `--office-path` (TEXT, optional) — Office native/XML path, e.g. /Sheet1/row[6]
- `--include-detail` (TEXT:{auto,row,page,section,object,metadata}, optional) — auto | row | page | section | object | metadata
- `--meta-prompt` (TEXT, optional) — For --adapter llm-meta: image_understand prompt; empty = built-in search metadata prompt
- `--resize-width` (INT, optional, default `768`) — For --adapter llm-meta: pre-resize longest edge before external image understanding
- `--no-resize` (optional, flag) — For --adapter llm-meta: disable image_understand pre-resize
- `--context-before` (INT:NONNEGATIVE, optional, default `0`) — Nearby units before
- `--context-after` (INT:NONNEGATIVE, optional, default `0`) — Nearby units after
- `--json` (optional, flag) — Print JSON
- `--md` (optional, flag) — Print Markdown detail
- `--markdown` (TEXT:{auto,plain,render}, optional, default `auto`) — With --md: auto (render on TTY), plain (raw Markdown), or render
- `--markdown-color` (TEXT:{auto,never,always}, optional, default `auto`) — With rendered --md: auto, never, or always

#### `search action`

Run a search-scoped action such as replace (implementation pending).

- Allows extra positional arguments.

**Options:**

- `input` (TEXT, optional, positional) — File(s), folder(s), or glob(s)
- `--log-level` (TEXT:{trace,debug,info,warn,warning,error,err,critical,off,none}, optional) — Log level for this search command: trace, debug, info, warn, error, critical, off
- `--mode` (TEXT:{auto,name,grep,semantic,metadata,fingerprint}, optional) — auto | name | grep | semantic | metadata | fingerprint (repeatable or comma-separated)
- `--content` (TEXT:{any,text,code,image,document,office,pdf,catalog}, optional) — any | text | code | image | document | office | pdf | catalog (repeatable or comma-separated)
- `--backend` (TEXT:{auto,any,exact,image-meta,vector,fingerprint,catalog}, optional) — auto | exact | image-meta | vector | fingerprint | catalog (repeatable or comma-separated)
- `--sort` (TEXT:{auto,none,score,path,relevance}, optional, default `auto`) — Result order for merged/fan-out search: auto | none | score | path
- `--query` (TEXT, optional) — Search pattern (filename substring, regex, semantic query, or grep needle)
- `--type` (TEXT, optional) — any | image, or rg-style type shorthand: cpp, ts, py, md, ...
- `--indexer` (TEXT:{own,os}, optional, default `own`) — own (default) | os - exact-search indexer
- `--grep` (optional, flag) — Alias for --mode grep
- `--names-only` (optional, flag) — With grep: report only the filepath, not individual match lines
- `--regex` (optional, flag) — Treat --query as ECMAScript regex
- `--case-sensitive` (optional, flag) — Case-sensitive match
- `--whole-word` (optional, flag) — Require word-boundary match
- `--no-recursive` (optional, flag) — Do not recurse into directory inputs
- `--include-hidden` (optional, flag) — Include dot-files and dot-directories
- `--follow-symlinks` (optional, flag) — Follow symbolic links
- `--no-skip-binary` (optional, flag) — Scan binary files
- `--context` (INT:NONNEGATIVE, optional, default `0`) — Symmetric context lines
- `--context-before` (INT:NONNEGATIVE, optional, default `0`) — Context lines before
- `--context-after` (INT:NONNEGATIVE, optional, default `0`) — Context lines after
- `--multiline` (optional, flag) — Enable multiline regex
- `--output-mode` (TEXT:{content,files_with_matches,count}, optional, default `content`) — content (default) | files_with_matches | count
- `--head-limit` (INT, optional, default `0`) — Cap output to first N entries
- `--offset` (INT, optional, default `0`) — Skip first N entries
- `--max` (INT, optional, default `0`) — Max total results
- `--max-per-file` (INT, optional, default `0`) — Max grep matches per file
- `--max-file-size` (INT, optional, default `0`) — Skip grep files larger than N bytes
- `--include` (TEXT, optional) — Only scan filename glob; repeatable
- `--exclude` (TEXT, optional) — Skip filename glob; repeatable
- `--exclude-dir` (TEXT, optional) — Directory names to prune; repeatable
- `--dry-run` (optional, flag) — Resolve candidates and print counts; no matching
- `--json` (optional, flag) — Print JSON
- `--stream` (optional, flag) — Stream NDJSON events (start/task/hit/done) incrementally; cancelable, web-friendly
- `--md` (optional, flag) — Print Markdown result tables/details
- `--markdown` (TEXT:{auto,plain,render}, optional, default `auto`) — With --md: auto (render on TTY), plain (raw Markdown), or render (always run terminal markdown)
- `--markdown-color` (TEXT:{auto,never,always}, optional, default `auto`) — With rendered --md: auto, never, or always
- `--action` (TEXT, optional, default `replace`) — replace
- `--replacement` (TEXT, optional) — Replacement text or prompt
- `--reference-image` (TEXT, optional) — Reference image for image actions; repeatable

### `settings`

Import / export the app settings profile (UTF-8 JSON). Use `settings path` to locate the file.

- Allows extra positional arguments.

**Subcommands:**

- `path` — Print the canonical on-disk settings.json path for this OS (no file I/O) and exit.
- `import` — Replace the live profile store with the given UTF-8 JSON file (full document replace). Windows: accepts PME1 or JSON (same as in-app). Other OS: JSON object only. All OSes: --archive restores a profile ZIP.
- `export` — Write the current profile settings to a UTF-8 JSON file (default: settings.json in cwd). Windows: `--encrypted` writes PME1 instead of JSON. All OSes: `--archive` writes a profile ZIP.

#### `settings path`

Print the canonical on-disk settings.json path for this OS (no file I/O) and exit.

- Allows extra positional arguments.

#### `settings import`

Replace the live profile store with the given UTF-8 JSON file (full document replace). Windows: accepts PME1 or JSON (same as in-app). Other OS: JSON object only. All OSes: --archive restores a profile ZIP.

- Allows extra positional arguments.

**Options:**

- `path` (TEXT, required, positional) — Source file (relative paths are from cwd)
- `--archive` (optional, flag) — Read a profile ZIP exported by `settings export --archive`. Skips web* folders and never imports .settings-key.dat.

#### `settings export`

Write the current profile settings to a UTF-8 JSON file (default: settings.json in cwd). Windows: `--encrypted` writes PME1 instead of JSON. All OSes: `--archive` writes a profile ZIP.

- Allows extra positional arguments.

**Options:**

- `path` (TEXT, optional, default `settings.json`, positional) — Output file (relative paths are from cwd)
- `--encrypted` (optional, flag) — Write PME1 binary (DPAPI-bound key on this profile) instead of UTF-8 JSON.
- `--archive` (optional, flag) — Write a ZIP of the app profile. Skips web* WebView folders; Windows settings.json is portable JSON; .settings-key.dat is omitted.

### `provider`

Provider utilities (model catalog, etc.)

- Allows extra positional arguments.

**Subcommands:**

- `models` — Provider model catalog operations

#### `provider models`

Provider model catalog operations

- Allows extra positional arguments.

**Subcommands:**

- `list` — List provider models and return full JSON payload

#### `provider models list`

List provider models and return full JSON payload

- Allows extra positional arguments.

**Options:**

- `--provider` (TEXT, optional, default `replicate`) — Provider id (replicate|openrouter)
- `--api-key` (TEXT, optional) — API key (Replicate: required. OpenRouter: optional for public /v1/models; from app if set for openrouter)
- `--base-url` (TEXT, optional) — Replicate: catalog URL (default official collection). OpenRouter: API root (default https://openrouter.ai/api/v1)
- `--limit` (INT, optional) — Replicate /v1/models: optional page size (ignored for openrouter)
- `--cursor` (TEXT, optional) — Replicate: optional pagination cursor (ignored for openrouter)
- `--sort-by` (TEXT, optional) — Replicate: optional sort field (ignored for openrouter)
- `--sort-direction` (TEXT, optional) — Replicate: optional sort direction (asc|desc) (ignored for openrouter)

### `llm`

LLM: tools-list / tools-call / info (saved chat + image defaults) / agent (path tools)

- Allows extra positional arguments.

**Subcommands:**

- `info` — Show Chat router/model and image provider/model from app settings, effective defaults for path tools, and which CLI flags override per command (find/transform/meta/duplicates, …)
- `tools-list` — Print the JSON-Schema tool catalog (one entry per tanit op)
- `tools-call` — Invoke a tool by name with a JSON arguments envelope
- `agent` — Run a single chat-agent turn: LLM picks tools (image_resize / compress / transform / meta / find), runs them on the supplied paths, and writes outputs to disk. Use --no-tools for a plain one-shot text reply (no path tools). Use --disable-tools=a,b to omit specific path tools from the catalog. Provider is router-aware (OpenAI-compatible client).
- `codex` — Run one turn via the Codex CLI (`codex exec --json`). Requires `codex login`. Build flag: FEATURE_AGENT_CODEX.
- `claude` — Run one turn via Claude Code (`claude -p --output-format stream-json`). Build flag: FEATURE_AGENT_CLAUDE.
- `cursor` — Run one turn via Cursor Agent (`agent -p --output-format stream-json`). Build flag: FEATURE_AGENT_CURSOR.

#### `llm info`

Show Chat router/model and image provider/model from app settings, effective defaults for path tools, and which CLI flags override per command (find/transform/meta/duplicates, …)

- Allows extra positional arguments.

**Subcommands:**

- `providers` — List enabled LLM providers from the provider registry and app settings.
- `models` — List models for a given provider. local / llama: text/planner GGUF models. vlm: local VLM models (multimodal / vision / OCR) with mmproj paths. whisper: local whisper.cpp ggml models. pixlwiz / openrouter / replicate: fetches live catalog (disk-cached; replicate 3 d, others 24 h). Other names: shows configured default_model from app settings.
- `tools` — List all built-in path-mode agent tools (name + description). These are the tools available to the chat agent in every session.
- `skills` — List discovered agent skills from roaming and workspace roots with availability/active state.
- `policy` — Dump the full GPO policy catalog (keys, categories, types, defaults, ADMX strings). Single source consumed by scripts/generate-admx.mjs.

**Options:**

- `--json` (optional, flag) — Print machine-readable JSON on stdout
- `--compress-md` (optional, flag) — Print raw compact Markdown for router/planner context: tools, skills, XBlox blocks. Ignored with --json.
- `--preset` (TEXT, optional) — Chat settings preset name or id. If omitted, uses preset `Default`, or the lone saved preset.
- `--markdown` (TEXT:{auto,plain,render}, optional, default `render`) — Human stdout: render (default — always pretty-print), auto (only on TTY), or plain (raw UTF-8). Ignored with --json.
- `--color` (TEXT:{auto,never,always}, optional, default `auto`) — When markdown rendering is used: auto (color on TTY unless NO_COLOR/TERM=dumb), never, or always.
- `--no-mcp-probe` (optional, flag) — Do not run live MCP profile probes (stdio/HTTP handshakes). JSON/text output still lists settings; the `mcp` object notes that the probe was skipped.
- `--mcp-probe` (optional, flag) — Run live MCP profile probes (stdio/HTTP handshakes).

#### `llm info providers`

List enabled LLM providers from the provider registry and app settings.

- Allows extra positional arguments.

**Options:**

- `--json` (optional, flag) — Output JSON array
- `--all` (optional, flag) — Include providers disabled by FEATURE_PROVIDER_* or Group Policy (for GPO generation).

#### `llm info models`

List models for a given provider. local / llama: text/planner GGUF models. vlm: local VLM models (multimodal / vision / OCR) with mmproj paths. whisper: local whisper.cpp ggml models. pixlwiz / openrouter / replicate: fetches live catalog (disk-cached; replicate 3 d, others 24 h). Other names: shows configured default_model from app settings.

- Allows extra positional arguments.

**Options:**

- `--provider` (TEXT, required) — Provider to query: local | llama | vlm | whisper | pixlwiz | openrouter | replicate | <name from `llm info providers`>
- `--no-cache` (optional, flag) — Bypass the disk cache and force a live HTTP fetch (pixlwiz / openrouter).
- `--json` (optional, flag) — Output JSON

#### `llm info tools`

List all built-in path-mode agent tools (name + description). These are the tools available to the chat agent in every session.

- Allows extra positional arguments.

**Options:**

- `--json` (optional, flag) — Output JSON array {name, description}
- `--all` (optional, flag) — Show the full built-in registry, ignoring user/GPO filtering (for GPO template generation).

#### `llm info skills`

List discovered agent skills from roaming and workspace roots with availability/active state.

- Allows extra positional arguments.

**Options:**

- `--json` (optional, flag) — Output JSON

#### `llm info policy`

Dump the full GPO policy catalog (keys, categories, types, defaults, ADMX strings). Single source consumed by scripts/generate-admx.mjs.

- Allows extra positional arguments.

**Options:**

- `--json` (optional, flag) — Output JSON

#### `llm tools-list`

Print the JSON-Schema tool catalog (one entry per tanit op)

- Allows extra positional arguments.

**Options:**

- `--path` (optional, flag) — List path-mode chat agent tools (default catalog for llm agent). Omit for in-buffer REST/MCP tools.

#### `llm tools-call`

Invoke a tool by name with a JSON arguments envelope

- Allows extra positional arguments.

**Options:**

- `--name` (TEXT, required) — Tool name (image_resize|image_compress|image_transform|image_create|image_meta|image_find|file_read)
- `--args` (TEXT, optional) — Path to JSON arguments file ('-' or '@-' for stdin; omit = empty {}).
- `--image-file` (TEXT, optional) — Convenience: read this file, base64-encode it, and inject as arguments.image.b64.

#### `llm agent`

Run a single chat-agent turn: LLM picks tools (image_resize / compress / transform / meta / find), runs them on the supplied paths, and writes outputs to disk. Use --no-tools for a plain one-shot text reply (no path tools). Use --disable-tools=a,b to omit specific path tools from the catalog. Provider is router-aware (OpenAI-compatible client).

- Allows extra positional arguments.

**Options:**

- `--prompt` (TEXT, optional) — User prompt (required unless piped via stdin or --mic is used, e.g. 'compress these as MozJPEG quality 70'). Supports ${VAR} variable substitution (CWD, SRC_FILE, YYYY, …) and file references: `@path`, `file:path`, or an absolute path to a UTF-8 text file.
- `--logging-dir` (TEXT, optional) — Directory for pm-image.log and per-run agent JSON artifacts. Relative paths are resolved from cwd. Same as the global --logging-dir.
- `--system-prompt` (TEXT, optional) — Override the full system prompt. Use `null`/`none` to send no system message, `@path` or `file:path` to read a UTF-8 file (relative or absolute), or literal text.
- `--planner-prompt` (TEXT, optional) — Override the planner system prompt. Same grammar as --system-prompt (literal text, `@path`, `file:path`, or `null`/`none`). The loaded text is run through `${...}` template substitution; `${builtin}` resolves to the baked-in planner instructions so you can extend rather than fully replace. A `planner-prompt.md` file in the exe folder or the config dir is used automatically when no CLI override is given.
- `--include` (TEXT, optional) — One or more file paths to put in the agent's selection context. Repeatable. When omitted, --cwd is used as the folder context.
- `--embed` (TEXT, optional) — One or more text file paths to inline into the user prompt under 'Embedded Content'. Uses the same text read policy as file_read. Repeatable; works even with --system-prompt null.
- `--preset` (TEXT, optional) — Chat settings preset name or id. Loads saved router/model/max-iter/planner defaults; explicit CLI flags override it.
- `--runner` (TEXT, optional) — Agent backend: native (default) | claude-code | codex | cursor. Also reads PM_LLM_AGENT_RUNNER when unset.
- `--save-preset` (TEXT, optional) — Save the resolved chat/tool/MCP/skill settings as a preset name. With --preset, clones/updates from that base; without --prompt, saves and exits.
- `--router` (TEXT, optional) — LLM router (llama|openrouter|openai|deepseek|gemini|ollama|fireworks|xai|huggingface). Default: from Chat Provider Settings in app.
- `--model` (TEXT, optional) — Model id (router-specific, e.g. openai/gpt-4o-mini). Default: from Chat Provider Settings in app.
- `--ai-consent-review` (optional, flag) — Run the SecurityAgent as an advisory reviewer before CLI consent prompts. The review is shown on stderr; human approval is still required.
- `--ai-consent-router` (TEXT, optional) — Router for the advisory SecurityAgent reviewer. Implies --ai-consent-review. Default: Chat security router, then planner router, then text router.
- `--ai-consent-model` (TEXT, optional) — Model/script for the advisory SecurityAgent reviewer. Implies --ai-consent-review. Default: Chat security model, then planner model, then text model.
- `--consent-ui` (TEXT, optional, default `win32`) — Consent surface for security-gated tools: cli | win32 | owner | auto-deny | auto. cli = stdio prompt (stderr/stdin); win32 = native modal dialog; auto-deny = deny immediately (headless); owner = route to owning surface (not yet wired -> auto). Default auto: cli when stdin is attached, else win32 on an interactive desktop, else auto-deny.
- `--consent-owner` (TEXT, optional) — Target descriptor (ipc id) for --consent-ui owner routing. Reserved; owner delegation is not wired yet.
- `--ocr-provider` (TEXT, optional) — Override the OCR tool provider for this run (e.g. llama, onnx, replicate). Wins over Chat → OCR settings and the active preset.
- `--ocr-model` (TEXT, optional) — Override the OCR tool model id for this run (e.g. paddleocr-vl-1-5). Wins over Chat → OCR settings and the active preset.
- `--recognition-provider` (TEXT, optional) — Override the image recognition (image_understand) provider for this run.
- `--recognition-model` (TEXT, optional) — Override the image recognition model id for this run.
- `--image-provider` (TEXT, optional) — Override the image creation (image_create) provider for this run.
- `--image-model` (TEXT, optional) — Override the image creation model id for this run.
- `--video-provider` (TEXT, optional) — Override the video creation (create_video) provider for this run.
- `--video-model` (TEXT, optional) — Override the video creation model id for this run.
- `--api-key` (TEXT, optional) — API key (optional; default from app chat / API Keys in settings.json)
- `--base-url` (TEXT, optional) — Override the router's default base URL (OpenAI-compatible endpoints). Default: from app API Providers settings.
- `--timeout-ms` (INT, optional) — HTTP timeout per LLM round (ms). Default: from Chat Provider Settings (or 60000).
- `--max-iter` (INT, optional) — Maximum tool-call iterations before forcing a final response. Default: from Chat Provider Settings (or 8).
- `--no-tools` (optional, flag) — Do not register path tools (no list_images, image_resize, image_compress, …) — one LLM text turn only
- `--no-mcp` (optional, flag) — Suppress MCP-backed tools for this turn, overriding the chat preset (path/run tools still register).
- `--no-skills` (optional, flag) — Skip agent skill discovery/injection for this turn, overriding the chat preset.
- `--no-planner` (optional, flag) — Force the planner pre-pass off for this turn, overriding --planner and any chat-preset default.
- `--planner` (optional, flag) — Run a compact planner pass first to select a budgeted subset of tool schemas, then execute the normal agent.
- `--planner-budget` (INT, optional, default `8`) — Maximum tool schemas the planner may pre-expand before falling back to the full catalog.
- `--no-parallel-tools` (optional, flag) — Disable concurrent tool dispatch and fall back to serial execution. Parallel dispatch (P6) is on by default; use this flag to opt out.
- `--parallel-tools` (optional, flag) — Dispatch all tool calls in a single LLM response concurrently (std::async). On by default — this flag is accepted for compatibility but is a no-op unless --no-parallel-tools was previously applied.
- `--multi-turn` (optional, flag) — Enable session memory across turns (default: on).
- `--single-turn` (optional, flag) — Disable session memory and run as one-shot only.
- `--session-id` (TEXT, optional) — Optional session id used when --multi-turn is enabled (allows continuity across CLI invocations).
- `--load-snapshot` (TEXT, optional) — P12: Load a named snapshot before the agent run. Merges the snapshot's memory_state / recent_events into the session context so the agent starts with that knowledge baseline. Name is sanitized to a filename; file lives under <config>/snapshots/<name>.json.
- `--save-snapshot` (TEXT, optional) — P12: Save the current session state to a named snapshot after the agent run. Requires --multi-turn (needs an active session). The snapshot captures memory_state + recent_events so the workflow can be restored later via --load-snapshot.
- `--memory-features` (TEXT, optional) — Override structured-memory feature mask. Accepts a decimal/0xHEX literal or comma-separated flag names with optional +/- deltas. Special tokens: all, default, none. Examples: --memory-features=0x7FF | --memory-features=CaptureWriteArtifacts,InjectItems | --memory-features=default,-ReplayTranscript. Overrides PM_LLM_STRUCTURED_MEMORY_FEATURES. See pm::llm::StructuredMemoryFeature.
- `--no-replay` (optional, flag) — Clear the ReplayTranscript bit from the structured-memory mask (skip raw chat-history injection; rely on session items/rules only).
- `--scheduler` (optional, flag) — After the first turn completes, start the agent scheduler in this process so schedule_every / schedule_in / schedule_at tasks created by the agent actually fire. Blocks until Ctrl+C, --scheduler-timeout expires, or --scheduler-exit-when-idle and no tasks remain.
- `--scheduler-timeout` (INT, optional, default `0`) — When --scheduler is set, auto-exit after N seconds (0 = run until Ctrl+C / idle).
- `--scheduler-exit-when-idle` (optional, flag) — When --scheduler is set, exit cleanly once every scheduled task is disabled (one-shots done, every-tasks hit max_runs / cancelled).
- `--disable-tools` (TEXT, optional) — Comma- or semicolon-separated enabled tools to omit. Built-ins: list_images, file_glob, file_read, file_search, image_resize, image_transform, image_create, create_video, image_understand, image_from_camera, ocr_text, write_file, speak, audio_transcribe, ask_user, schedule_at, schedule_in, schedule_every, schedule_cancel, schedule_list, memory_read, memory_write, memory_append_event, run, run_sequence, info_lookup, service_page_create, service_page_update, service_page_list, service_page_get, service_files_list, service_files_get, service_files_upload, service_search, create_command, app_inspect_dump, app_inspect_find, app_screenshot, app_click, app_drag, app_open, app_type, app_hotkey, app_close, app_batch. MCP tools use mcp_<server>__<tool>; run `llm agent --help` for a live list. Ineffective with --no-tools
- `--enable-tools` (TEXT, optional) — Comma- or semicolon-separated tool names to allow (whitelist). Only these tools will be offered to the model; all others are hidden. Overrides --disable-tools. Built-ins: list_images, file_glob, file_read, file_search, image_resize, image_transform, image_create, create_video, image_understand, image_from_camera, ocr_text, write_file, speak, audio_transcribe, ask_user, schedule_at, schedule_in, schedule_every, schedule_cancel, schedule_list, memory_read, memory_write, memory_append_event, run, run_sequence, info_lookup, service_page_create, service_page_update, service_page_list, service_page_get, service_files_list, service_files_get, service_files_upload, service_search, create_command, app_inspect_dump, app_inspect_find, app_screenshot, app_click, app_drag, app_open, app_type, app_hotkey, app_close, app_batch. Ineffective with --no-tools.
- `--context-reduction` (TEXT:{off,none,tool-results,tools,all}, optional) — Pre-API context reduction (attention reduction layer). Shrinks the wire payload sent to the model each round; the transcript keeps full fidelity. off (default), tool-results (reduce large tool-result messages only), or all (also reduce older assistant/user context — never the system message or the live user turn). JSON/code tool envelopes take the structural path; free text takes the deterministic attention pipeline.
- `--context-reduction-ratio` (FLOAT:FLOAT in [0 - 1], optional, default `0.5`) — Target output/input byte ratio for reduced messages (0..1). Only used when --context-reduction names a non-off mode.
- `--context-reduction-min-bytes` (INT, optional, default `2048`) — Minimum message size (bytes) before the pre-API filter reduces it. Only used when --context-reduction names a non-off mode.
- `--context-reduction-objective` (TEXT, optional) — Relevance objective for text reduction (empty = use the user prompt). Only used when --context-reduction names a non-off mode.
- `--json` (optional, flag) — Emit the full transcript as JSON on stdout (instead of plain-text events)
- `--dry-run` (optional, flag) — Resolve provider + tools + selection; print context as Markdown to stdout. With --planner, runs only the planner LLM pass to preview selected schemas.
- `--log` (TEXT, optional, default `agent.json`) — Write a JSON run log (provider, per-event tool calls with full envelopes, transcript) to this file (truncates). Default: <logging-dir>/agent.json.
- `--dst` (TEXT, optional) — Write the agent response to this file path (truncates on each turn). Without --json: writes result.final_text (raw markdown, no ANSI). With --json: writes the full result JSON object. Supports ${VAR} variable substitution (CWD, SRC_FILE, YYYY, MM, DD, …) resolved against --cwd / --include paths. Relative paths are resolved from --cwd. Parent directories are created automatically.
- `--type` (TEXT:{completion,responses,realtime}, optional, default `responses`) — LLM API type: completion (POST /chat/completions) or responses (POST /responses — OpenAI Responses API; supported by OpenAI, OpenRouter, and LiteLLM proxy), or realtime (experimental WebSocket /realtime PoC; text-only; best with router=openai). Default: responses.
- `--realtime` (optional, flag) — Start a live speech-to-speech voice session over the WebSocket /v1/realtime endpoint (mic + speaker; the full agent is exposed as the run_pm_agent tool). No --prompt is required; if given it seeds the conversation. Runs until Ctrl+C or `--realtime-stop`. Best with router=openai / a realtime model. (With --save-preset, falls back to the text PoC `--type realtime` path.)
- `--realtime-stop` (optional, flag) — Signal a running `--realtime` live voice session (this or another process) to stop cooperatively, then exit. Uses the cross-process session file.
- `--realtime-status` (optional, flag) — Print whether a live `--realtime` voice session is running (add --json for machine-readable output), then exit.
- `--realtime-idle-ms` (INT, optional, default `120000`) — Self-stop a live `--realtime` session after this many ms of genuine idle time — no speech, no reply, and no delegated run_pm_agent in flight (a running agent task always keeps the session alive). Stops headless sessions from lingering. 0 = never auto-stop. Default: 120000 (2 min).
- `--streaming` (TEXT:{auto,on,off}, optional, default `on`) — Streaming mode: on (default), auto (catalog-gated), off. Implemented now for --type responses; completion remains non-streaming.
- `--markdown` (TEXT:{auto,plain,render}, optional, default `auto`) — Human stdout: auto (render when stdout is a TTY), plain (raw model UTF-8), or render (always run the terminal markdown pass). Ignored with --json.
- `--color` (TEXT:{auto,never,always}, optional, default `auto`) — When markdown rendering is used: auto (color on TTY unless NO_COLOR/TERM=dumb), never, or always.
- `--mic` (optional, flag) — Use the microphone as prompt input (continuous STT → LLM → TTS loop). Replaces --prompt for user input; --prompt may still be given as context. Requires --stt-api-key or ELEVENLABS_API_KEY. Press Ctrl+C to stop.
- `--stt-api-key` (TEXT, optional) — ElevenLabs API key for real-time STT (and TTS when --voice-id is set). Falls back to ELEVENLABS_API_KEY environment variable.
- `--voice-id` (TEXT, optional) — ElevenLabs voice ID to speak LLM responses aloud (empty = text-only). Browse voices at elevenlabs.io/app/voice-library.
- `--no-tts` (optional, flag) — Mic mode: disable TTS playback entirely (keep listening continuously after each response).
- `--tts-model-id` (TEXT, optional, default `eleven_v3`) — ElevenLabs TTS model used with --voice-id (default: eleven_v3).
- `--input` (TEXT, optional) — Microphone device name (case-insensitive substring; use `audio info` to list). Omit to use the system default input device.
- `--input-source` (TEXT:{mic,desktop,mix}, optional, default `mic`) — Input source for the realtime session: mic (default), desktop (system loopback), or mix (mic + desktop summed). Use `audio info` to list available devices.
- `--desktop` (TEXT, optional) — Loopback device name substring for --input-source desktop or mix (case-insensitive; empty = default render device). Sets --input-source desktop when --input-source is not explicitly provided.
- `--mic-gain` (FLOAT:NONNEGATIVE, optional, default `1`) — Mic input level multiplier (linear; 0 = mute, 1 = unity, 2 = double). Applied before mixing when --input-source mix is set.
- `--desktop-gain` (FLOAT:NONNEGATIVE, optional, default `1`) — Desktop/loopback input level multiplier (linear; 0 = mute, 1 = unity). Applied before mixing when --input-source desktop or mix is set.
- `--silence-ms` (INT, optional, default `1500`) — Silence duration in ms after which speech is auto-committed to the LLM (0 = disabled; default 1500).
- `--stt-provider` (TEXT, optional) — Override the STT provider for this run (whisper for local built-in, elevenlabs, …). Default: from Chat → Voice & Audio settings. Use 'whisper' to select the built-in local whisper.cpp (no API key needed).
- `--stt-model` (TEXT, optional) — Override the STT model id / alias for this run (e.g. base.en, small.en for whisper; scribe_v2_realtime for ElevenLabs). Default: from settings.
- `--tts-provider` (TEXT, optional) — Override the TTS provider for this run (e.g. elevenlabs). Default: from settings.
- `--tts-model` (TEXT, optional) — Override the TTS model id for this run (e.g. eleven_flash_v2_5). Also applies as --tts-model-id when --voice-id is used.
- `--tts-voice-id` (TEXT, optional) — Override the TTS voice id for this run. Alias for --voice-id; wins if both are set.

#### `llm codex`

Run one turn via the Codex CLI (`codex exec --json`). Requires `codex login`. Build flag: FEATURE_AGENT_CODEX.

- Allows extra positional arguments.

**Options:**

- `--prompt` (TEXT, optional) — User prompt (required). Supports the same path grammar as `llm agent --prompt`.
- `--include` (TEXT, optional) — File paths to inject as Pixlwiz selection context. Repeatable.
- `--embed` (TEXT, optional) — Text files whose contents are appended to the prompt (same as `llm agent --embed`). Repeatable. Max 1 MiB per file.
- `--cwd` (TEXT, optional) — Working directory / workspace root for the external agent.
- `--model` (TEXT, optional) — External CLI model override.
- `--resume` (TEXT, optional) — Resume a prior external session (Codex thread id; Claude/Cursor session id).
- `--timeout-ms` (INT, optional) — Max wait for the external CLI process (default 600000).
- `--executable` (TEXT, optional) — Override CLI executable name/path (default: codex | claude | agent).
- `--json` (optional, flag) — Print structured JSON result on stdout.
- `--ephemeral` (optional, flag) — Do not persist the external session to disk (Codex --ephemeral).
- `--sandbox` (TEXT:{read-only,workspace-write,danger-full-access}, optional) — Codex sandbox: read-only | workspace-write | danger-full-access (default read-only).
- `--ask-for-approval` (TEXT:{untrusted,on-request,never}, optional) — Ignored for Codex (use -s/--sandbox). Kept for CLI parity with other agents.
- `--skip-git-repo-check` (optional, flag) — Allow Codex outside a git repository (default on).

#### `llm claude`

Run one turn via Claude Code (`claude -p --output-format stream-json`). Build flag: FEATURE_AGENT_CLAUDE.

- Allows extra positional arguments.

**Options:**

- `--prompt` (TEXT, optional) — User prompt (required). Supports the same path grammar as `llm agent --prompt`.
- `--include` (TEXT, optional) — File paths to inject as Pixlwiz selection context. Repeatable.
- `--embed` (TEXT, optional) — Text files whose contents are appended to the prompt (same as `llm agent --embed`). Repeatable. Max 1 MiB per file.
- `--cwd` (TEXT, optional) — Working directory / workspace root for the external agent.
- `--model` (TEXT, optional) — External CLI model override.
- `--resume` (TEXT, optional) — Resume a prior external session (Codex thread id; Claude/Cursor session id).
- `--timeout-ms` (INT, optional) — Max wait for the external CLI process (default 600000).
- `--executable` (TEXT, optional) — Override CLI executable name/path (default: codex | claude | agent).
- `--json` (optional, flag) — Print structured JSON result on stdout.
- `--ephemeral` (optional, flag) — Do not persist the external session to disk (Codex --ephemeral).

#### `llm cursor`

Run one turn via Cursor Agent (`agent -p --output-format stream-json`). Build flag: FEATURE_AGENT_CURSOR.

- Allows extra positional arguments.

**Options:**

- `--prompt` (TEXT, optional) — User prompt (required). Supports the same path grammar as `llm agent --prompt`.
- `--include` (TEXT, optional) — File paths to inject as Pixlwiz selection context. Repeatable.
- `--embed` (TEXT, optional) — Text files whose contents are appended to the prompt (same as `llm agent --embed`). Repeatable. Max 1 MiB per file.
- `--cwd` (TEXT, optional) — Working directory / workspace root for the external agent.
- `--model` (TEXT, optional) — External CLI model override.
- `--resume` (TEXT, optional) — Resume a prior external session (Codex thread id; Claude/Cursor session id).
- `--timeout-ms` (INT, optional) — Max wait for the external CLI process (default 600000).
- `--executable` (TEXT, optional) — Override CLI executable name/path (default: codex | claude | agent).
- `--json` (optional, flag) — Print structured JSON result on stdout.
- `--ephemeral` (optional, flag) — Do not persist the external session to disk (Codex --ephemeral).
- `--trust` (optional, flag) — Trust workspace without prompting (Cursor --trust; headless only).
- `--mode` (TEXT, optional) — Cursor mode: plan | ask (empty = default agent).

### `register-explorer`

Register Windows Explorer menus: resize / convert / meta + Workbench + Viewer + Chat + Presets

- Allows extra positional arguments.

**Options:**

- `--group` (TEXT, optional, default `PM Media`)
- `--unregister` (optional, flag)
- `--dry` (optional, flag)
- `--no-refresh-shell` (optional, flag)
- `--elevated-write-only` (optional, flag) — Internal: elevated register-explorer writes only.
- `--media-bin` (TEXT, optional) — Path to tanit.exe (default: this executable)
- `--widths` (TEXT, optional, default `1980,1200`)

### `register-startmenu`

Register current-user Start Menu shortcuts for a zip/unpacked install.

- Allows extra positional arguments.

**Options:**

- `--folder` (TEXT, optional, default `PolyMech`)
- `--unregister` (optional, flag)
- `--dry` (optional, flag)
- `--media-bin` (TEXT, optional) — Path to tanit.exe (default: this executable)
- `--install-root` (TEXT, optional) — Install/zip root for docs and Uninstall.exe lookup (default: parent of win-x64, or exe directory).

### `installer`

Zip/unpacked install helper: seed profile data, register Explorer integration, and register Start Menu shortcuts.

- Allows extra positional arguments.

**Options:**

- `--uninstall` (optional, flag) — Unregister Explorer and Start Menu integration. Profile data is kept.
- `--dry` (optional, flag)
- `--json` (optional, flag) — Emit ManifestResult JSON on stdout.
- `--no-seed` (optional, flag) — Skip copying missing dist/data files into the roaming profile.
- `--no-explorer` (optional, flag) — Skip register-explorer / unregister.
- `--no-startmenu` (optional, flag) — Skip register-startmenu / unregister.
- `--no-url-schemes` (optional, flag) — Skip registering / unregistering the tanit:// URL scheme handler.
- `--root` (TEXT, optional) — Install/zip root. Default: parent of win-x64, or exe directory.
- `--bundle` (TEXT, optional) — Path to a JSON bundle manifest (${VAR}-aware; resolved after --root/--config). Executed after seed/register steps. ${INSTALL_ROOT} resolves to --root.
- `--verbs` (TEXT, optional) — Comma-separated verb allow globs (e.g. copy,vfs_*). Empty = all registered verbs.
- `--journal-dir` (TEXT, optional) — Directory for run-journal sidecars (resume support; ${VAR}-aware).
- `--resume` (optional, flag) — Resume from an existing journal (default).
- `--fresh` (optional, flag) — Ignore any existing journal and start fresh.
- `--server-url` (TEXT, optional) — Service base URL override for vfs_pull / vfs_push verbs.
- `--config` (TEXT, optional) — JSON variable overrides applied before manifest resolution. Flat object or { "variables": { … } }. Installer keys include DEFAULT_VFS_SERVER (CMS host for vfs:// sources). Values are deep-resolved (${OTHER}/sub, ${ENV:NAME}, ${KNOWNFOLDER:…}).

### `service`

Call the configured Tanit web service API. Run `login` first.

- Allows extra positional arguments.

**Subcommands:**

- `info` — Print resolved CMS, LLM, license, and Zitadel service URLs.
- `search` — GET /api/search?q=... - full-text search across pages, posts, pictures, VFS files, and places. Default uses login token (includes your private content); --public searches global/public content only.
- `spending` — AI gateway spend APIs on the CMS server (GET /api/ai-gateway/spend/me).
- `balance` — GET /api/ai-gateway/balance/me - purchased credits minus synced spend.
- `ai-gateway-health` — GET /api/ai-gateway/health - gateway configured/alive state.
- `upload` — Deprecated alias for `service images upload`.
- `images` — Image APIs: upload image files through /api/images and receive image metadata.
- `settings` — Settings sync APIs: upload/import unencrypted settings JSON via the home VFS mount.
- `files` — VFS file APIs: upload arbitrary files and return Tanit filebrowser URLs.
- `pages` — Page APIs: list, fetch, and create Tanit pages.
- `pictures` — Picture APIs: list and fetch /api/pictures records.
- `posts` — Post APIs: list, fetch, and create posts.
- `categories` — Category APIs: list, fetch, create, update, and remove Tanit categories.

#### `service info`

Print resolved CMS, LLM, license, and Zitadel service URLs.

- Allows extra positional arguments.

**Options:**

- `--server-url` (TEXT, optional) — Service base URL (default: env SERVER_URL, else VITE_SERVER_IMAGE_API_URL, else CLIENT_URL). No trailing slash.
- `--json` (optional, flag) — Print machine-readable JSON instead of pretty output.

#### `service search`

GET /api/search?q=... - full-text search across pages, posts, pictures, VFS files, and places. Default uses login token (includes your private content); --public searches global/public content only.

- Allows extra positional arguments.

**Options:**

- `query` (TEXT, required, positional) — Search query.
- `--type` (TEXT, optional) — Content type: all, pages, posts, pictures, files, places (default: all).
- `--limit` (INT, optional, default `20`) — Max results (default: 20, server cap: 50).
- `--sizes` (TEXT, optional) — Comma-separated responsive image widths.
- `--formats` (TEXT, optional) — Comma-separated responsive image formats.
- `--visibility-filter` (TEXT, optional) — Filter authenticated results: invisible or private.
- `--public` (optional, flag) — Anonymous/global search without bearer token (public content only).
- `--server-url` (TEXT, optional) — Service base URL (default: env SERVER_URL, else VITE_SERVER_IMAGE_API_URL, else CLIENT_URL). No trailing slash.
- `--json` (optional, flag) — Print raw server JSON instead of pretty output.

#### `service spending`

AI gateway spend APIs on the CMS server (GET /api/ai-gateway/spend/me).

- Allows extra positional arguments.

**Subcommands:**

- `logs` — GET /api/ai-gateway/spend/me/logs - paginated request-level spend logs.

**Options:**

- `--server-url` (TEXT, optional) — Service base URL (default: env SERVER_URL, else VITE_SERVER_IMAGE_API_URL, else CLIENT_URL). No trailing slash.
- `--json` (optional, flag) — Print machine-readable JSON instead of pretty output.

#### `service spending logs`

GET /api/ai-gateway/spend/me/logs - paginated request-level spend logs.

- Allows extra positional arguments.

**Options:**

- `--days-back` (INT, optional) — Lookback window when start/end dates are omitted (default: 7).
- `--start-date` (TEXT, optional) — Range start (YYYY-MM-DD).
- `--end-date` (TEXT, optional) — Range end (YYYY-MM-DD).
- `--page` (INT, optional) — Page number (default: 1).
- `--page-size` (INT, optional) — Page size (default: 25, max: 100).
- `--sort-by` (TEXT, optional) — Sort column (default: startTime).
- `--sort-order` (TEXT, optional) — asc or desc (default: desc).
- `--all-pages` (optional, flag) — Fetch and merge every page in range (CMS path; direct LiteLLM fallback when empty).
- `--server-url` (TEXT, optional) — Service base URL (default: env SERVER_URL, else VITE_SERVER_IMAGE_API_URL, else CLIENT_URL). No trailing slash.
- `--json` (optional, flag) — Print machine-readable JSON instead of pretty output.

#### `service balance`

GET /api/ai-gateway/balance/me - purchased credits minus synced spend.

- Allows extra positional arguments.

**Options:**

- `--server-url` (TEXT, optional) — Service base URL (default: env SERVER_URL, else VITE_SERVER_IMAGE_API_URL, else CLIENT_URL). No trailing slash.
- `--json` (optional, flag) — Print machine-readable JSON instead of pretty output.

#### `service ai-gateway-health`

GET /api/ai-gateway/health - gateway configured/alive state.

- Allows extra positional arguments.

**Options:**

- `--server-url` (TEXT, optional) — Service base URL (default: env SERVER_URL, else VITE_SERVER_IMAGE_API_URL, else CLIENT_URL). No trailing slash.
- `--json` (optional, flag) — Print machine-readable JSON instead of pretty output.

#### `service upload`

Deprecated alias for `service images upload`.

- Allows extra positional arguments.

**Options:**

- `files` (TEXT, required, positional) — Local image path(s); repeat or list several
- `--server-url` (TEXT, optional) — Service base URL (default: env SERVER_URL, else VITE_SERVER_IMAGE_API_URL, else CLIENT_URL). No trailing slash.
- `--dump-raw-http` (optional, flag) — Each stdout JSON line also includes http_status and raw_body (exact /api/images response string).

#### `service images`

Image APIs: upload image files through /api/images and receive image metadata.

- Allows extra positional arguments.

**Subcommands:**

- `upload` — POST /api/images?forward=vfs&original=true - multipart field "file" (same as uploadUtils.uploadImage).

#### `service images upload`

POST /api/images?forward=vfs&original=true - multipart field "file" (same as uploadUtils.uploadImage).

- Allows extra positional arguments.

**Options:**

- `files` (TEXT, required, positional) — Local image path(s); repeat or list several
- `--server-url` (TEXT, optional) — Service base URL (default: env SERVER_URL, else VITE_SERVER_IMAGE_API_URL, else CLIENT_URL). No trailing slash.
- `--dump-raw-http` (optional, flag) — Each stdout JSON line also includes http_status and raw_body (exact /api/images response string).

#### `service settings`

Settings sync APIs: upload/import unencrypted settings JSON via the home VFS mount.

- Allows extra positional arguments.

**Subcommands:**

- `upload` — Upload portable unencrypted settings.json to VFS for cross-machine sync.
- `import` — Import portable unencrypted settings.json from VFS into the local profile.
- `remove` — Remove the remote settings sync directory from VFS.

#### `service settings upload`

Upload portable unencrypted settings.json to VFS for cross-machine sync.

- Allows extra positional arguments.

**Options:**

- `--remote-dir` (TEXT, optional) — Remote VFS directory under home mount (default: settings).
- `--commands` (optional, flag) — Also upload commands.json when present.
- `--mcp` (optional, flag) — Also upload MCP config files/folder when present.
- `--server-url` (TEXT, optional) — Service base URL (default: env SERVER_URL, else VITE_SERVER_IMAGE_API_URL, else CLIENT_URL). No trailing slash.
- `--json` (optional, flag) — Print machine-readable JSON instead of pretty output.

#### `service settings import`

Import portable unencrypted settings.json from VFS into the local profile.

- Allows extra positional arguments.

**Options:**

- `--remote-dir` (TEXT, optional) — Remote VFS directory under home mount (default: settings).
- `--download-dir` (TEXT, optional) — Temporary/local directory for downloaded files before importing settings.json (default: cwd).
- `--commands` (optional, flag) — Also import commands.json when present remotely.
- `--mcp` (optional, flag) — Also import MCP config files/folder when present remotely.
- `--server-url` (TEXT, optional) — Service base URL (default: env SERVER_URL, else VITE_SERVER_IMAGE_API_URL, else CLIENT_URL). No trailing slash.
- `--json` (optional, flag) — Print machine-readable JSON instead of pretty output.

#### `service settings remove`

Remove the remote settings sync directory from VFS.

- Allows extra positional arguments.

**Options:**

- `--remote-dir` (TEXT, optional) — Remote VFS directory under home mount (default: settings).
- `--server-url` (TEXT, optional) — Service base URL (default: env SERVER_URL, else VITE_SERVER_IMAGE_API_URL, else CLIENT_URL). No trailing slash.
- `--json` (optional, flag) — Print machine-readable JSON instead of pretty output.

#### `service files`

VFS file APIs: upload arbitrary files and return Tanit filebrowser URLs.

- Allows extra positional arguments.

**Subcommands:**

- `upload` — POST /api/vfs/upload/{mount}/{path} for any file type (multipart field "file").
- `list` — GET /api/vfs/ls/{mount}/{path} - list files in a VFS directory.
- `pull` — Stream-download VFS file(s) to a local directory (HTTP Range resume, retries). Skips files that already exist locally unless --overwrite. Uses GET /api/vfs/get by default (public mounts such as models).
- `read` — GET /api/vfs/read/{mount}/{path} - read raw file content for download/buffer use.
- `get` — Alias for `files read`: GET /api/vfs/read/{mount}/{path}. Binary and large files require --download or --download-as.
- `remove` — DELETE /api/vfs/delete/{mount}/{path} - remove one or more VFS files/folders.

#### `service files upload`

POST /api/vfs/upload/{mount}/{path} for any file type (multipart field "file").

- Allows extra positional arguments.

**Options:**

- `files` (TEXT, required, positional) — Local file path(s), globs, or brace groups (e.g. dir/**/*.{png,jpg}); repeat or list several
- `--mount` (TEXT, optional) — VFS mount name (default: home). Resulting user URL is /app/filebrowser/<mount>?file=...
- `--remote-dir` (TEXT, optional) — Remote VFS directory. Each matched file is placed under this path; glob matches preserve relative subfolders. Default: VFS root.
- `--remote-path` (TEXT, optional) — Exact remote VFS path for one matched file (overrides --remote-dir; one positional spec only).
- `--server-url` (TEXT, optional) — Service base URL (default: env SERVER_URL, else VITE_SERVER_IMAGE_API_URL, else CLIENT_URL). No trailing slash.
- `--dump-raw-http` (optional, flag) — Each stdout JSON line also includes http_status and raw_body from /api/vfs/upload.

#### `service files list`

GET /api/vfs/ls/{mount}/{path} - list files in a VFS directory.

- Allows extra positional arguments.

**Options:**

- `path` (TEXT, optional, positional) — Directory path inside the mount. Default: root.
- `--mount` (TEXT, optional) — VFS mount name (default: home).
- `--server-url` (TEXT, optional) — Service base URL (default: env SERVER_URL, else VITE_SERVER_IMAGE_API_URL, else CLIENT_URL). No trailing slash.
- `--json` (optional, flag) — Print raw server JSON instead of pretty output.

#### `service files pull`

Stream-download VFS file(s) to a local directory (HTTP Range resume, retries). Skips files that already exist locally unless --overwrite. Uses GET /api/vfs/get by default (public mounts such as models).

- Allows extra positional arguments.

**Options:**

- `path` (TEXT, required, positional) — Remote file or directory path inside the mount.
- `--mount` (TEXT, optional) — VFS mount name (default: home).
- `--local-dir` (TEXT, optional) — Local destination root (default: MODELS_DIR when --mount models, else cwd).
- `--pattern` (TEXT, optional) — Glob filter when pulling a directory (e.g. widget-test.md, **/*.gguf).
- `--no-resume` (optional, flag) — Disable HTTP Range resume.
- `--overwrite` (optional, flag) — Re-download even when the local file already exists (default: skip existing).
- `--retries` (INT, optional) — Per-file retry count (default: 3).
- `--read-endpoint` (optional, flag) — Use GET /api/vfs/read instead of /api/vfs/get.
- `--progress` (optional, flag) — Log download progress ([service-pull]).
- `--server-url` (TEXT, optional) — Service base URL (default: env SERVER_URL, else VITE_SERVER_IMAGE_API_URL, else CLIENT_URL). No trailing slash.
- `--json` (optional, flag) — Print machine-readable JSON instead of pretty output.

#### `service files read`

GET /api/vfs/read/{mount}/{path} - read raw file content for download/buffer use.

- Allows extra positional arguments.

**Options:**

- `path` (TEXT, required, positional) — File path inside the mount.
- `--mount` (TEXT, optional) — VFS mount name (default: home).
- `--out` (TEXT, optional) — Write raw bytes to this file and print JSON metadata. Default: write raw bytes to stdout.
- `--download` (TEXT, optional) — Save to current directory using this name; omit name to use the remote path basename. Refused for binary/large files when no destination is given.
- `--download-as` (TEXT, optional) — Save to this exact local path (creates parent directories automatically).
- `--server-url` (TEXT, optional) — Service base URL (default: env SERVER_URL, else VITE_SERVER_IMAGE_API_URL, else CLIENT_URL). No trailing slash.
- `--overwrite` (optional, flag) — Re-download even when the local destination already exists (default: skip existing).
- `--json` (optional, flag) — With --download/--download-as/--out, print JSON metadata instead of pretty output. Without a destination, stdout remains raw text bytes.

#### `service files get`

Alias for `files read`: GET /api/vfs/read/{mount}/{path}. Binary and large files require --download or --download-as.

- Allows extra positional arguments.

**Options:**

- `path` (TEXT, required, positional) — File path inside the mount.
- `--mount` (TEXT, optional) — VFS mount name (default: home).
- `--download` (TEXT, optional) — Save to current directory using this name; omit name to use the remote path basename.
- `--download-as` (TEXT, optional) — Save to this exact local path (creates parent directories automatically).
- `--out` (TEXT, optional) — Alias for --download-as: write raw bytes to this file and print metadata.
- `--server-url` (TEXT, optional) — Service base URL (default: env SERVER_URL, else VITE_SERVER_IMAGE_API_URL, else CLIENT_URL). No trailing slash.
- `--overwrite` (optional, flag) — Re-download even when the local destination already exists (default: skip existing).
- `--json` (optional, flag) — With --download/--download-as/--out, print JSON metadata instead of pretty output. Without a destination, stdout remains raw text bytes.

#### `service files remove`

DELETE /api/vfs/delete/{mount}/{path} - remove one or more VFS files/folders.

- Allows extra positional arguments.

**Options:**

- `paths` (TEXT, required, positional) — VFS path(s) inside the mount.
- `--mount` (TEXT, optional) — VFS mount name (default: home).
- `--server-url` (TEXT, optional) — Service base URL (default: env SERVER_URL, else VITE_SERVER_IMAGE_API_URL, else CLIENT_URL). No trailing slash.
- `--json` (optional, flag) — Print machine-readable JSON instead of pretty output.

#### `service pages`

Page APIs: list, fetch, and create Tanit pages.

- Allows extra positional arguments.

**Subcommands:**

- `create` — POST /api/pages with markdown wrapped as a markdown-text widget.
- `update` — PATCH /api/pages/{id}; with --slug, resolves /api/user-page/{owner}/{slug} first.
- `list` — GET /api/pages?userId=... - list pages for a user.
- `get` — GET /api/user-page/{identifier}/{slug}; if slug is omitted, fetch by page id.
- `remove` — DELETE /api/pages/{id}; with --slug, resolves /api/user-page/{owner}/{slug} first.

#### `service pages create`

POST /api/pages with markdown wrapped as a markdown-text widget.

- Allows extra positional arguments.

**Options:**

- `markdown` (TEXT, required, positional) — Local markdown file(s), globs, or brace groups (e.g. docs/**/*.md); repeatable
- `--title` (TEXT, optional) — Page title (default: markdown filename).
- `--slug` (TEXT, optional) — Page URL slug (default: generated from title).
- `--description` (TEXT, optional) — Optional page description.
- `--tags` (TEXT, optional) — Comma-separated page tags.
- `--owner` (TEXT, optional) — Owner user UUID for API create (default: app_user_id from zitadel-oauth.json). Output URL prefers cached app_username when available.
- `--parent` (TEXT, optional) — Optional parent page UUID or slug.
- `--category-id` (TEXT, optional) — Optional category slug, display name, or UUID; repeatable.
- `--private` (TEXT, optional) — Create with is_public=false. Optional value: true/false.
- `--hidden` (TEXT, optional) — Create with visible=false. Optional value: true/false.
- `--server-url` (TEXT, optional) — Service base URL (default: env SERVER_URL, else VITE_SERVER_IMAGE_API_URL, else CLIENT_URL). No trailing slash.
- `--dump-raw-http` (optional, flag) — Stdout JSON also includes http_raw_steps and raw /api/pages response.

#### `service pages update`

PATCH /api/pages/{id}; with --slug, resolves /api/user-page/{owner}/{slug} first.

- Allows extra positional arguments.

**Options:**

- `markdown` (TEXT, required, positional) — Local markdown file(s), globs, or brace groups; repeatable. Batch update uses slug/id from front matter.
- `--id` (TEXT, optional) — Page UUID to update.
- `--slug` (TEXT, optional) — Existing page slug to update when --id is omitted.
- `--owner` (TEXT, optional) — Owner user UUID or username for --slug lookup (default: app_user_id from zitadel-oauth.json).
- `--title` (TEXT, optional) — Optional replacement page title.
- `--new-slug` (TEXT, optional) — Optional replacement page slug.
- `--description` (TEXT, optional) — Optional replacement meta description.
- `--tags` (TEXT, optional) — Comma-separated replacement page tags.
- `--parent` (TEXT, optional) — Optional replacement parent page UUID or slug.
- `--category-id` (TEXT, optional) — Optional replacement category slug, display name, or UUID; repeatable.
- `--private` (TEXT, optional) — Set is_public=false. Optional value: true/false.
- `--hidden` (TEXT, optional) — Set visible=false. Optional value: true/false.
- `--server-url` (TEXT, optional) — Service base URL (default: env SERVER_URL, else VITE_SERVER_IMAGE_API_URL, else CLIENT_URL). No trailing slash.
- `--dump-raw-http` (optional, flag) — Stdout JSON also includes http_raw_steps and raw /api/pages response.

#### `service pages list`

GET /api/pages?userId=... - list pages for a user.

- Allows extra positional arguments.

**Options:**

- `--user-id` (TEXT, optional) — Owner user UUID (default: app_user_id from zitadel-oauth.json, then Tanit default).
- `--server-url` (TEXT, optional) — Service base URL (default: env SERVER_URL, else VITE_SERVER_IMAGE_API_URL, else CLIENT_URL). No trailing slash.
- `--json` (optional, flag) — Print raw server JSON instead of pretty output.

#### `service pages get`

GET /api/user-page/{identifier}/{slug}; if slug is omitted, fetch by page id.

- Allows extra positional arguments.

**Options:**

- `identifier` (TEXT, required, positional) — Owner/username for route lookup, or page id when slug is omitted.
- `slug` (TEXT, optional, positional) — Page slug. Omit to fetch by page id.
- `--lang` (TEXT, optional) — Optional page language query parameter.
- `--download` (optional, flag) — Export page content to disk. Writes markdown-text content as .md when present, otherwise full page JSON.
- `--out` (TEXT, optional) — Destination file or directory for --download. Default: slug/title/id with .md or .json.
- `--server-url` (TEXT, optional) — Service base URL (default: env SERVER_URL, else VITE_SERVER_IMAGE_API_URL, else CLIENT_URL). No trailing slash.
- `--json` (optional, flag) — Print raw server JSON instead of pretty output.

#### `service pages remove`

DELETE /api/pages/{id}; with --slug, resolves /api/user-page/{owner}/{slug} first.

- Allows extra positional arguments.

**Options:**

- `ids` (TEXT, optional, positional) — Page UUID(s).
- `--slug` (TEXT, optional) — Existing page slug to remove.
- `--owner` (TEXT, optional) — Owner user UUID or username for --slug lookup (default: app_user_id from zitadel-oauth.json).
- `--server-url` (TEXT, optional) — Service base URL (default: env SERVER_URL, else VITE_SERVER_IMAGE_API_URL, else CLIENT_URL). No trailing slash.
- `--json` (optional, flag) — Print machine-readable JSON instead of pretty output.

#### `service pictures`

Picture APIs: list and fetch /api/pictures records.

- Allows extra positional arguments.

**Subcommands:**

- `list` — GET /api/pictures?userId=...&page=...&limit=... - list pictures for a user.
- `get` — GET /api/pictures/{id} - fetch a picture record.
- `remove` — DELETE /api/pictures/{id} - remove one or more picture records.

#### `service pictures list`

GET /api/pictures?userId=...&page=...&limit=... - list pictures for a user.

- Allows extra positional arguments.

**Options:**

- `--user-id` (TEXT, optional) — Owner user UUID (default: app_user_id from zitadel-oauth.json, then Tanit default).
- `--page` (INT, optional, default `0`) — Page index (default: 0).
- `--limit` (INT, optional, default `9999`) — Page size (default: 9999).
- `--server-url` (TEXT, optional) — Service base URL (default: env SERVER_URL, else VITE_SERVER_IMAGE_API_URL, else CLIENT_URL). No trailing slash.
- `--json` (optional, flag) — Print raw server JSON instead of pretty output.

#### `service pictures get`

GET /api/pictures/{id} - fetch a picture record.

- Allows extra positional arguments.

**Options:**

- `id` (TEXT, required, positional) — Picture UUID.
- `--download` (optional, flag) — Download the picture asset referenced by image_url/url instead of printing the detail summary.
- `--out` (TEXT, optional) — Destination file or directory for --download. Default: filename from URL in the current directory.
- `--server-url` (TEXT, optional) — Service base URL (default: env SERVER_URL, else VITE_SERVER_IMAGE_API_URL, else CLIENT_URL). No trailing slash.
- `--json` (optional, flag) — Print raw server JSON instead of pretty output.

#### `service pictures remove`

DELETE /api/pictures/{id} - remove one or more picture records.

- Allows extra positional arguments.

**Options:**

- `ids` (TEXT, required, positional) — Picture UUID(s).
- `--server-url` (TEXT, optional) — Service base URL (default: env SERVER_URL, else VITE_SERVER_IMAGE_API_URL, else CLIENT_URL). No trailing slash.
- `--json` (optional, flag) — Print machine-readable JSON instead of pretty output.

#### `service posts`

Post APIs: list, fetch, and create posts.

- Allows extra positional arguments.

**Subcommands:**

- `list` — GET /api/posts?page=...&limit=...&userId=... - list posts for a user.
- `get` — GET /api/posts/{id} - fetch post details.
- `remove` — DELETE /api/posts/{id} - remove one or more posts.
- `create` — POST /api/posts then multipart /api/images per file, then POST /api/pictures (same as web publish flow). Default post title is the first file's filename; each picture title is that file's filename. Description optional.

#### `service posts list`

GET /api/posts?page=...&limit=...&userId=... - list posts for a user.

- Allows extra positional arguments.

**Options:**

- `--user-id` (TEXT, optional) — Owner user UUID (default: app_user_id from zitadel-oauth.json, then Tanit default).
- `--page` (INT, optional, default `0`) — Page index (default: 0).
- `--limit` (INT, optional, default `9999`) — Page size (default: 9999).
- `--server-url` (TEXT, optional) — Service base URL (default: env SERVER_URL, else VITE_SERVER_IMAGE_API_URL, else CLIENT_URL). No trailing slash.
- `--json` (optional, flag) — Print raw server JSON instead of pretty output.

#### `service posts get`

GET /api/posts/{id} - fetch post details.

- Allows extra positional arguments.

**Options:**

- `id` (TEXT, required, positional) — Post UUID.
- `--sizes` (TEXT, optional) — Optional responsive image sizes query.
- `--formats` (TEXT, optional) — Optional responsive image formats query.
- `--lang` (TEXT, optional) — Optional language query parameter.
- `--download` (optional, flag) — Download media assets referenced by the post detail response instead of printing the detail summary.
- `--out` (TEXT, optional) — Destination file/directory for --download. Multiple post media files are written into this directory.
- `--server-url` (TEXT, optional) — Service base URL (default: env SERVER_URL, else VITE_SERVER_IMAGE_API_URL, else CLIENT_URL). No trailing slash.
- `--json` (optional, flag) — Print raw server JSON instead of pretty output.

#### `service posts remove`

DELETE /api/posts/{id} - remove one or more posts.

- Allows extra positional arguments.

**Options:**

- `ids` (TEXT, required, positional) — Post UUID(s).
- `--server-url` (TEXT, optional) — Service base URL (default: env SERVER_URL, else VITE_SERVER_IMAGE_API_URL, else CLIENT_URL). No trailing slash.
- `--json` (optional, flag) — Print machine-readable JSON instead of pretty output.

#### `service posts create`

POST /api/posts then multipart /api/images per file, then POST /api/pictures (same as web publish flow). Default post title is the first file's filename; each picture title is that file's filename. Description optional.

- Allows extra positional arguments.

**Options:**

- `files` (TEXT, required, positional) — Local image path(s)
- `--title` (TEXT, optional) — Post title (default: filename of the first image, e.g. photo.png).
- `--description` (TEXT, optional) — Optional post description.
- `--visibility` (TEXT:{public,listed,private}, optional, default `public`) — Post visibility: public | listed | private (JSON settings.visibility; default public).
- `--server-url` (TEXT, optional) — Service base URL (default: env SERVER_URL, else VITE_SERVER_IMAGE_API_URL, else CLIENT_URL). No trailing slash.
- `--dump-raw-http` (optional, flag) — Stdout JSON also includes http_raw_steps: label, http_status, body_raw for each API call.
- `--job-ui` (optional, flag) — Windows: list-style job window + Tanit post dialog (Explorer `Share to Tanit...` verb).

#### `service categories`

Category APIs: list, fetch, create, update, and remove Tanit categories.

- Allows extra positional arguments.

**Subcommands:**

- `list` — GET /api/categories - list categories (optionally scoped to a parent slug).
- `get` — GET /api/categories/{id} - fetch a category with its parents and children.
- `items` — GET /api/categories/{slug}/items - list pages in a category with resolved variables.
- `create` — POST /api/categories - create a category.
- `update` — PATCH /api/categories/{id} - update category fields.
- `remove` — DELETE /api/categories/{id} - remove one or more categories.

**Options:**

- `--type` (TEXT, optional, default `pages`) — Category meta.type filter/field (default: pages). Applies to list, get, items, create, update, and remove.

#### `service categories list`

GET /api/categories - list categories (optionally scoped to a parent slug).

- Allows extra positional arguments.

**Options:**

- `--parent-slug` (TEXT, optional) — Only list children of this parent category slug.
- `--include-children` (optional, flag) — Return only top-level categories with nested children.
- `--lang` (TEXT, optional) — Optional language for translated names.
- `--server-url` (TEXT, optional) — Service base URL (default: env SERVER_URL, else VITE_SERVER_IMAGE_API_URL, else CLIENT_URL). No trailing slash.
- `--json` (optional, flag) — Print raw server JSON instead of pretty output.

#### `service categories get`

GET /api/categories/{id} - fetch a category with its parents and children.

- Allows extra positional arguments.

**Options:**

- `id` (TEXT, required, positional) — Category UUID.
- `--server-url` (TEXT, optional) — Service base URL (default: env SERVER_URL, else VITE_SERVER_IMAGE_API_URL, else CLIENT_URL). No trailing slash.
- `--json` (optional, flag) — Print raw server JSON instead of pretty output.

#### `service categories items`

GET /api/categories/{slug}/items - list pages in a category with resolved variables.

- Allows extra positional arguments.

**Options:**

- `slug` (TEXT, required, positional) — Category slug.
- `--limit` (INT, optional) — Max items (default: server default 50).
- `--no-descendants` (optional, flag) — Exclude items from child categories.
- `--server-url` (TEXT, optional) — Service base URL (default: env SERVER_URL, else VITE_SERVER_IMAGE_API_URL, else CLIENT_URL). No trailing slash.
- `--json` (optional, flag) — Print raw server JSON instead of pretty output.

#### `service categories create`

POST /api/categories - create a category.

- Allows extra positional arguments.

**Options:**

- `name` (TEXT, required, positional) — Category name.
- `--slug` (TEXT, optional) — Category slug (default: from name).
- `--description` (TEXT, optional) — Optional description.
- `--visibility` (TEXT, optional) — public | unlisted | private (default: public).
- `--parent` (TEXT, optional) — Optional parent category UUID (creates a relation).
- `--relation-type` (TEXT, optional) — Relation type for --parent (default: generalization).
- `--server-url` (TEXT, optional) — Service base URL (default: env SERVER_URL, else VITE_SERVER_IMAGE_API_URL, else CLIENT_URL). No trailing slash.
- `--dump-raw-http` (optional, flag) — Stdout JSON also includes http_status and raw_body.
- `--json` (optional, flag) — (No-op; create always prints JSON.)

#### `service categories update`

PATCH /api/categories/{id} - update category fields.

- Allows extra positional arguments.

**Options:**

- `id` (TEXT, required, positional) — Category UUID.
- `--name` (TEXT, optional) — Replacement name.
- `--slug` (TEXT, optional) — Replacement slug.
- `--description` (TEXT, optional) — Replacement description.
- `--visibility` (TEXT, optional) — Replacement visibility: public | unlisted | private.
- `--server-url` (TEXT, optional) — Service base URL (default: env SERVER_URL, else VITE_SERVER_IMAGE_API_URL, else CLIENT_URL). No trailing slash.
- `--dump-raw-http` (optional, flag) — Stdout JSON also includes http_status and raw_body.

#### `service categories remove`

DELETE /api/categories/{id} - remove one or more categories.

- Allows extra positional arguments.

**Options:**

- `ids` (TEXT, required, positional) — Category UUID(s).
- `--server-url` (TEXT, optional) — Service base URL (default: env SERVER_URL, else VITE_SERVER_IMAGE_API_URL, else CLIENT_URL). No trailing slash.
- `--json` (optional, flag) — Print machine-readable JSON instead of pretty output.

### `batch`

Manage batch sessions (save / load / resume / list / discard).

- Allows extra positional arguments.

**Subcommands:**

- `list` — List saved sessions from sessions.json.
- `discard` — Remove a saved session by id.
- `resume` — Resume a saved session by id (auto-detects op and re-runs pending items).

#### `batch list`

List saved sessions from sessions.json.

- Allows extra positional arguments.

#### `batch discard`

Remove a saved session by id.

- Allows extra positional arguments.

**Options:**

- `session-id` (TEXT, required, positional) — Session id to remove

#### `batch resume`

Resume a saved session by id (auto-detects op and re-runs pending items).

- Allows extra positional arguments.

**Options:**

- `session-id` (TEXT, required, positional) — Session id to resume

### `login`

Sign in via OIDC browser flow (PKCE), or use --probe / --decode-jwt.

- Allows extra positional arguments.

**Options:**

- `--probe` (optional, flag) — Fetch OIDC discovery + JWKS only; verbose stderr logs; no browser.
- `--no-browser` (optional, flag) — Print authorize URL and code_verifier to stderr instead of opening a browser.
- `--decode-jwt` (TEXT, optional) — Decode a JWT access token and explain `sub` vs app user id (optional value; if omitted, uses ZITADEL_TEST_ACCESS_TOKEN from the environment).
- `--issuer` (TEXT, optional) — Override ZITADEL_ISSUER / VITE_ZITADEL_AUTHORITY.
- `--client-id` (TEXT, optional) — Override ZITADEL_OIDC_CLIENT_ID / VITE_ZITADEL_CLIENT_ID.
- `--oauth-port` (INT:INT in [1024 - 65535], optional) — First loopback port for http://127.0.0.1:<port>/callback (default 8844). Register that exact redirect URI on the ZITADEL application; if the port is busy, the next free port up to +50 is tried (each must be registered, or use a free port).

### `audio`

Audio utilities: list devices, record, play, synthesise, and change voices.

- Allows extra positional arguments.

**Subcommands:**

- `info` — List audio devices: capture inputs by default; use --playback for MMDevice render endpoints.
- `record` — Record from a capture device (PCM s16le mono 16 kHz). Stops after --duration-ms, Ctrl+C, console close, or `audio record stop`. Plain recording: --dst. Transcript only: --text-out, or --provider/--model to print to stdout. Both is also fine.
- `play` — Play an audio file through the default output device. Supports MP3, WAV, FLAC via miniaudio. Playback is asynchronous by default; use --wait to block until finished.
- `voice-change` — Transform speech into an ElevenLabs voice while preserving timing, emotion, and delivery.
- `tts` — Synthesise speech from text using a TTS provider and write audio to a file.

#### `audio info`

List audio devices: capture inputs by default; use --playback for MMDevice render endpoints.

- Allows extra positional arguments.

**Options:**

- `--json` (optional, flag) — Machine-readable JSON array on stdout.
- `--models` (optional, flag) — List discovered local whisper.cpp ggml models instead of capture devices.
- `--playback` (optional, flag) — List MMDevice playback (render) endpoints instead of capture devices. Shows active speakers, monitors, and Bluetooth audio outputs.
- `--all` (optional, flag) — List all playback endpoints including UNPLUGGED (paired Bluetooth speakers/headphones that are not currently connected). Implies --playback.

#### `audio record`

Record from a capture device (PCM s16le mono 16 kHz). Stops after --duration-ms, Ctrl+C, console close, or `audio record stop`. Plain recording: --dst. Transcript only: --text-out, or --provider/--model to print to stdout. Both is also fine.

- Allows extra positional arguments.

**Subcommands:**

- `stop` — Signal a running `audio record` session in another terminal to stop cooperatively.
- `status` — Show the active `audio record` session (device, format, provider/model, elapsed time, dst, text-out, live STT buffer).

**Options:**

- `--dst` (TEXT, optional) — Destination WAV file. Optional when --text-out is set (scratch WAV is used internally). Relative paths are resolved from the current working directory.
- `--input` (TEXT, optional) — Capture device name (case-insensitive substring; use `audio info` to list names). Omit to use the system default input device. Ignored when --input-source desktop is set.
- `--input-source` (TEXT:{mic,desktop,mix}, optional, default `mic`) — Input source: mic (default), desktop (system loopback), or mix (mic + desktop).
- `--desktop` (TEXT, optional) — Loopback device name substring for --input-source desktop/mix (empty = default render device). Sets --input-source desktop when --input-source is not explicitly given.
- `--mic-gain` (FLOAT:NONNEGATIVE, optional, default `1`) — Mic level multiplier (linear; 0 = mute, 1 = unity). Used with --input-source mix.
- `--desktop-gain` (FLOAT:NONNEGATIVE, optional, default `1`) — Desktop/loopback level multiplier (linear; 0 = mute, 1 = unity). Used with --input-source desktop or mix.
- `--output` (TEXT, optional) — Playback device name for TTS output during STT→TTS loop (case-insensitive substring). Omit to use the system default output device.
- `--connect` (TEXT, optional) — Connect a paired Bluetooth audio device by address or fuzzy name before recording. If --input is omitted, this value is also used as the capture device selector.
- `--connect-timeout-ms` (INT:POSITIVE, optional, default `30000`) — Maximum ms to wait for --connect device to become ready (default 30000 = 30 s). Increase for AV receivers or devices that take a long time to boot from standby.
- `--connect-delay-ms` (INT:NONNEGATIVE, optional, default `0`) — Extra delay (ms) after --connect succeeds, before recording starts. Useful when the BT device needs time to switch inputs or unmute (default 0).
- `--duration` (INT:NONNEGATIVE, optional, default `0`) — Stop recording after this many milliseconds (0 = run until Ctrl+C).
- `--seconds` (INT:NONNEGATIVE, optional, default `0`) — Stop recording after this many seconds (0 = run until Ctrl+C).
- `--stt` (optional, flag) — Enable speech-to-text alongside recording (live ElevenLabs or batch Whisper). Implied by --text-out, --provider, or --model. Without STT flags, --dst records WAV only.
- `--provider` (TEXT:{elevenlabs,tanit,whisper}, optional) — STT provider. Implies transcription when no --dst/--text-out is set. Currently supported: elevenlabs (Scribe v2 Realtime), pixlwiz (Whisper batch), whisper (local whisper.cpp, offline). Defaults to chat.stt_provider from app settings.
- `--model` (TEXT, optional) — STT model override. For --provider whisper this may be a ggml model path, for example ${MODELS_DIR}/ggml-base.en.bin. Defaults to Chat Provider voice model settings.
- `--backend` (TEXT:{cpu,gpu}, optional, default `cpu`) — Local whisper.cpp only: inference backend policy, cpu or gpu. Default: cpu.
- `--gpu-device` (INT:NONNEGATIVE, optional, default `0`) — Local whisper.cpp only: GPU device index, only meaningful with --backend gpu.
- `--flash-attn` (TEXT:{auto,on,off}, optional, default `auto`) — Local whisper.cpp only: flash attention policy, auto/on/off. Default: auto.
- `--threads` (INT:NONNEGATIVE, optional, default `0`) — Local whisper.cpp only: CPU thread count (0 = auto, capped by the wrapper).
- `--language` (TEXT, optional, default `auto`) — Local whisper.cpp only: language code such as en or de, or auto. Default: auto.
- `--api-key` (TEXT, optional) — API key for the selected STT provider (--provider elevenlabs → xi-api-key). Also used as the TTS key when --voice-id is set. Falls back to the provider entry in App Settings when omitted.
- `--from-wav` (TEXT:FILE, optional) — Transcribe an existing WAV file instead of capturing from the mic (batch providers only: whisper local / pixlwiz). Implies --stt. Prints the transcript and exits; combine with --text-out to also write a file.
- `--voice-id` (TEXT, optional) — ElevenLabs voice ID for real-time TTS playback. When set, each committed transcript is synthesised and played through the speakers. Requires --stt/--text-out and --provider elevenlabs. Browse voices at elevenlabs.io/app/voice-library.
- `--model-id` (TEXT, optional, default `eleven_v3`) — ElevenLabs TTS model used with --voice-id (default: eleven_v3).
- `--silence-ms` (INT, optional, default `1500`) — Auto-commit STT utterance after this many milliseconds of silence (0 = disabled; requires --stt or --text-out; default: 1500).
- `--text-out` (TEXT, optional) — Write the full STT transcript to this file (UTF-8 text). Enables STT automatically. --dst is optional. Relative paths are resolved from the current working directory.
- `--json` (optional, flag) — Emit STT result as JSON on stdout and in --text-out.

#### `audio record stop`

Signal a running `audio record` session in another terminal to stop cooperatively.

- Allows extra positional arguments.

#### `audio record status`

Show the active `audio record` session (device, format, provider/model, elapsed time, dst, text-out, live STT buffer).

- Allows extra positional arguments.

**Options:**

- `--json` (optional, flag) — Machine-readable JSON on stdout.

#### `audio play`

Play an audio file through the default output device. Supports MP3, WAV, FLAC via miniaudio. Playback is asynchronous by default; use --wait to block until finished.

- Allows extra positional arguments.

**Options:**

- `path` (TEXT, required, positional) — Path to the audio file. Relative paths are resolved from the current working directory.
- `--wait` (optional, flag) — Block until playback finishes (normally async). Ctrl+C aborts playback.
- `--output` (TEXT, optional) — Playback device name (case-insensitive substring; use `audio info` to list names). Omit to use the system default output device.
- `--connect` (TEXT, optional) — Connect a paired Bluetooth audio device by address or fuzzy name before playback. When --output is omitted, playback uses the newly connected default endpoint.
- `--connect-timeout-ms` (INT:POSITIVE, optional, default `30000`) — Maximum ms to wait for --connect device to become ready (default 30000 = 30 s).
- `--connect-delay-ms` (INT:NONNEGATIVE, optional, default `0`) — Extra delay (ms) after --connect succeeds, before playback starts. Useful for AV receivers that need time to switch inputs or unmute (default 0).

#### `audio voice-change`

Transform speech into an ElevenLabs voice while preserving timing, emotion, and delivery.

- Allows extra positional arguments.

**Options:**

- `source` (TEXT:FILE, required, positional) — Source audio file. Encoded audio is accepted by default; use --input-format pcm_s16le_16 for raw 16 kHz mono signed 16-bit little-endian PCM.
- `--dst` (TEXT, required) — Destination audio file. .mp3, .wav, and .opus select a matching default --format.
- `--voice-id` (TEXT, optional) — Target ElevenLabs voice ID. Defaults to the configured TTS voice.
- `--model-id` (TEXT, optional, default `eleven_multilingual_sts_v2`) — Speech-to-speech model ID.
- `--format` (TEXT, optional) — ElevenLabs output format, for example mp3_44100_128, wav_44100, or opus_48000_128. Defaults from --dst extension.
- `--input-format` (TEXT:{other,pcm_s16le_16}, optional, default `other`) — Input encoding hint: other (encoded audio) or pcm_s16le_16 (raw PCM).
- `--api-key` (TEXT, optional) — ElevenLabs API key. Falls back to the configured ElevenLabs provider, then ELEVENLABS_API_KEY.
- `--base-url` (TEXT, optional) — ElevenLabs API origin for regional residency, without /v1 (default: https://api.elevenlabs.io).
- `--voice-settings` (TEXT, optional) — Advanced JSON object overriding target voice settings. Individual flags below override matching JSON fields.
- `--stability` (FLOAT:FLOAT in [0 - 1], optional) — Voice stability from 0 to 1. Lower is more expressive; higher is more consistent.
- `--similarity-boost` (FLOAT:FLOAT in [0 - 1], optional) — Target-voice similarity from 0 to 1.
- `--style` (FLOAT:FLOAT in [0 - 1], optional) — Style exaggeration from 0 to 1.
- `--speaker-boost` (optional, flag) — Enable ElevenLabs speaker boost for stronger target-voice similarity.
- `--no-speaker-boost` (optional, flag) — Explicitly disable ElevenLabs speaker boost.
- `--seed` (INT:INT in [0 - 4294967295], optional) — Best-effort deterministic seed (0..4294967295).
- `--optimize-streaming-latency` (INT:INT in [0 - 4], optional, default `0`) — ElevenLabs latency optimisation level (0..4).
- `--remove-background-noise` (optional, flag) — Remove background noise from the source using ElevenLabs Audio Isolation.
- `--zero-retention` (optional, flag) — Send enable_logging=false. ElevenLabs restricts zero-retention mode to eligible enterprise accounts.
- `--json` (optional, flag) — Emit machine-readable result metadata on stdout.

#### `audio tts`

Synthesise speech from text using a TTS provider and write audio to a file.

- Allows extra positional arguments.

**Options:**

- `--text` (TEXT, required) — Text to synthesise, or path to a plain-text file (.txt, .md, …). When the value is an existing readable file it is loaded (binary files rejected). Use quotes for inline multi-word input.
- `--dst` (TEXT, optional) — Destination file (.mp3 / .wav / .opus). Extension determines the default output format when --format is omitted. Omit to play through speakers without saving.
- `--no-play` (optional, flag) — Do not play audio through speakers; only save to --dst.
- `--output` (TEXT, optional) — Playback device name (case-insensitive substring; use `audio info` to list names). Omit to use the system default output device.
- `--connect` (TEXT, optional) — Connect a paired Bluetooth audio device by address or fuzzy name before TTS playback. Synthesis is overlapped with the device wake-up so total latency is minimised. Ignored with --no-play.
- `--connect-timeout-ms` (INT:POSITIVE, optional, default `30000`) — Maximum ms to wait for --connect device to become ready (default 30000 = 30 s).
- `--connect-delay-ms` (INT:NONNEGATIVE, optional, default `0`) — Extra delay (ms) after --connect succeeds, before TTS playback starts. Useful for AV receivers that need time to switch inputs or unmute (default 0).
- `--no-stream` (optional, flag) — Opt out of the streaming playback path (curl → ring → device). When omitted and --dst is not set, the playback path uses streaming for lowest first-audio latency (mirrors the agent's `do_speak`). Ignored when --dst is set (the file write requires the full buffer).
- `--provider` (TEXT:{elevenlabs,tanit,vibevoice}, optional) — TTS provider: elevenlabs (direct API), pixlwiz (proxy /audio/speech), or vibevoice (local ggml — requires FEATURE_VIBEVOICE build). Defaults to chat.tts_provider from app settings, then elevenlabs.
- `--tokenizer` (TEXT, optional) — Path to tokenizer.gguf — required when --provider vibevoice.
- `--ref-audio` (TEXT, optional) — Reference WAV for voice cloning (vibevoice 1.5B only). Pass a ~5 s 24 kHz mono WAV of the target speaker. When set, --voice-id must be empty and the 1.5B model must be loaded.
- `--api-key` (TEXT, optional) — API key for the TTS provider. Falls back to ELEVENLABS_API_KEY env var.
- `--voice-id` (TEXT, optional, default `tLK6fPv15M0oKv4V3ACR`) — Voice ID. For elevenlabs: ElevenLabs voice UUID. For pixlwiz: ElevenLabs voice UUID override (empty = proxy default). Defaults to chat.tts_model from app settings when omitted.
- `--model-id` (TEXT, optional, default `eleven_v3`) — Model ID. For elevenlabs: eleven_v3, eleven_turbo_v2, etc. For pixlwiz: proxy alias (pixlwiz-speech, pixlwiz-speech-turbo). Defaults to chat.tts_model from app settings when omitted.
- `--format` (TEXT, optional) — Output format override. ElevenLabs: mp3_44100_128, pcm_44100, opus_48000_32. Tanit proxy: mp3, opus, aac, flac. Defaults to mp3_44100_128 for .mp3, pcm_44100 for .wav.
- `--no-voice-settings` (optional, flag) — Do not send explicit ElevenLabs voice_settings (use voice defaults).
- `--no-chunk` (optional, flag) — Disable sentence chunking + request stitching for long ElevenLabs inputs.
- `--chunk-target-chars` (INT:INT in [100 - 800], optional, default `400`) — Greedy-merge sentences up to this many chars per ElevenLabs request (default 400; range 100–800).
- `--chunk-max-chars` (INT:INT in [200 - 2000], optional, default `800`) — Hard-split a single sentence beyond this length (default 800; range 200–2000).
- `--stability` (FLOAT:FLOAT in [0 - 1], optional, default `0.9`) — ElevenLabs voice_settings.stability (0–1, default 0.9). Higher reduces drift on long inputs.
- `--similarity-boost` (FLOAT:FLOAT in [0 - 1], optional, default `0.75`) — ElevenLabs voice_settings.similarity_boost (0–1, default 0.75).
- `--style` (FLOAT:FLOAT in [0 - 1], optional, default `0`) — ElevenLabs voice_settings.style (0–1, default 0). Non-zero style can cause inconsistent speed and added sounds.

### `video`

Video capture: enumerate devices, capture still frames, and record video.

- Allows extra positional arguments.

**Subcommands:**

- `info` — List capture sources usable by `video image` / `video record` / `video detect`: webcam devices plus (Win32) display monitors and application windows with their `screen:` --input specs. Use --modes to also enumerate each device's supported resolutions and frame rates; --screens to show only monitors and windows.
- `image` — Capture a single still frame from a webcam and save it as an image file.
- `stream` — Prototype window/screen streaming host for a mobile WebRTC remote. This slice starts the built-in HTTP bootstrap/signaling server; media and data-channel transport are wired next.
- `record` — Record video from a webcam OR a screen/window. Windows .mp4 uses H.264 + optional AAC audio (mic/desktop/mix). .avi uses MJPEG. macOS .mp4/.mov uses native H.264. Use --input "screen:N[:wintitle=GLOB]" for monitor/window capture. Stops after --duration-ms, on Ctrl+C, or via `video record stop`.
- `detect` — Real-time YOLO-format object detection from a webcam. Outputs NDJSON frames to stdout; prints a summary on exit. Requires FEATURE_VIDEO_DETECTION (FEATURE_VIDEO + FEATURE_ONNX).

#### `video info`

List capture sources usable by `video image` / `video record` / `video detect`: webcam devices plus (Win32) display monitors and application windows with their `screen:` --input specs. Use --modes to also enumerate each device's supported resolutions and frame rates; --screens to show only monitors and windows.

- Allows extra positional arguments.

**Options:**

- `--json` (optional, flag) — Machine-readable JSON on stdout.
- `--modes` (optional, flag) — Enumerate supported capture modes (resolution, fps, format) for each device.
- `--screens` (optional, flag) — List ONLY display monitors and visible application windows (capture devices are also shown without this flag). Use the printed spec as --input for both `video record` and `video detect` (e.g. screen:0:wintitle=Notepad*).
- `--input` (TEXT, optional) — Filter to a specific device (case-insensitive substring match on name). With --modes, enumerate modes for this device only.

#### `video image`

Capture a single still frame from a webcam and save it as an image file.

- Allows extra positional arguments.

**Options:**

- `--dst` (TEXT, required) — Destination image file (.jpg / .jpeg / .png / .bmp). Relative paths are resolved from the current working directory.
- `--input` (TEXT, optional) — Capture source: webcam name (case-insensitive substring) OR a screen spec "screen:N" / "screen:0:wintitle=GLOB" to grab a monitor or app window (Win32). Omit to use the first/default device. Run `video info` to list devices, screens, and applications.
- `--mode` (INT, optional, default `-1`) — Mode index from `video info --modes` (0-based). Overrides --width/--height when set.
- `--width` (INT, optional, default `0`) — Preferred capture width in pixels (0 = device default).
- `--height` (INT, optional, default `0`) — Preferred capture height in pixels (0 = device default).

#### `video stream`

Prototype window/screen streaming host for a mobile WebRTC remote. This slice starts the built-in HTTP bootstrap/signaling server; media and data-channel transport are wired next.

- Allows extra positional arguments.

**Options:**

- `--server` (optional, flag) — Start the built-in LAN bootstrap/signaling server.
- `--input` (TEXT, optional) — Capture source spec for the eventual stream, e.g. "screen:0" or "screen:0:hwnd=...". Defaults to screen:0.
- `--bind` (TEXT, optional, default `0.0.0.0`) — Bind address for the built-in server (default: 0.0.0.0). Use 127.0.0.1 for loopback-only.
- `--port` (INT:INT bounded to [0 - 65535], optional, default `0`) — TCP port for the built-in server (0 = choose a free port).
- `--fps` (INT:INT bounded to [1 - 240], optional, default `30`) — Target capture/stream frame rate (default: 30).
- `--bitrate-kbps` (INT:POSITIVE, optional, default `8000`) — Target video bitrate for the eventual encoder (default: 8000).
- `--mjpeg-quality` (INT:INT bounded to [1 - 100], optional, default `85`) — Temporary HTTP MJPEG preview JPEG quality, 1-100 (default: 85).
- `--encoder` (TEXT:{auto,mf,nvenc,software}, optional, default `auto`) — Encoder preference for the eventual media path: auto, mf, nvenc, software.
- `--no-cursor` (optional, default `1`, flag) — Disable cursor capture for the eventual stream.
- `--token` (TEXT, optional) — Pairing token for the mobile client (default: generated per run).
- `--open` (optional, flag) — Open the local remote-client URL in the default browser after startup.
- `--duration-ms` (INT:NONNEGATIVE, optional, default `0`) — Stop the server after this many milliseconds (0 = run until Ctrl+C).
- `--json` (optional, flag) — Print server status JSON when the server is ready.

#### `video record`

Record video from a webcam OR a screen/window. Windows .mp4 uses H.264 + optional AAC audio (mic/desktop/mix). .avi uses MJPEG. macOS .mp4/.mov uses native H.264. Use --input "screen:N[:wintitle=GLOB]" for monitor/window capture. Stops after --duration-ms, on Ctrl+C, or via `video record stop`.

- Allows extra positional arguments.

**Subcommands:**

- `stop` — Signal a running `video record` session in another terminal to stop cooperatively.
- `status` — Show the active `video record` session (device, mode, codec, elapsed time, frames, dst).

**Options:**

- `--dst` (TEXT, optional) — Destination file (.avi MJPEG, or .mp4/.mov H.264 on macOS). Relative paths are resolved from the current working directory.
- `--input` (TEXT, optional) — Capture source: webcam name (case-insensitive substring) OR a screen spec "screen:N" / "screen:0:wintitle=GLOB" to record a monitor or app window (Win32, same grammar as `video detect`). Omit to use the first/default device. Run `video info` to list devices, screens, and applications.
- `--mode` (INT, optional, default `-1`) — Mode index from `video info --modes` (0-based). Overrides --width/--height/--fps when set.
- `--width` (INT, optional, default `0`) — Preferred capture width in pixels (0 = device default).
- `--height` (INT, optional, default `0`) — Preferred capture height in pixels (0 = device default).
- `--fps` (INT:POSITIVE, optional, default `30`) — Frame rate for capture and AVI header (default: 30).
- `--capture-engine` (TEXT:{auto,fast,compat}, optional, default `auto`) — Screen/window backend: auto prefers fast Windows Graphics Capture, fast requires it, compat uses the frame-pump recorder.
- `--encoder` (TEXT:{auto,nvenc,mediaFoundation}, optional, default `auto`) — Fast Windows H.264 encoder: auto tries the optional NVENC plugin then Media Foundation; nvenc requires NVIDIA; mediaFoundation forces Windows.
- `--bitrate-kbps` (INT:INT bounded to [0 - 100000], optional, default `0`) — Fast Windows H.264 bitrate in Kbps (0 = automatic from size and fps).
- `--no-cursor` (optional, default `1`, flag) — Exclude the pointer from screen/window capture.
- `--size-mode` (TEXT:{native,pad,fit,fill}, optional, default `native`) — Fast fixed-canvas layout: native, pad, fit, or fill.
- `--zoom` (FLOAT:FLOAT bounded to [1 - 32], optional, default `1`) — Initial fast-recorder viewport zoom multiplier.
- `--follow` (TEXT:{none,anchor,cursor}, optional, default `none`) — Fast-recorder viewport tracking: none, anchor, or cursor.
- `--follow-speed` (FLOAT:FLOAT bounded to [0.01 - 1], optional, default `0.2`) — Cursor-follow interpolation factor.
- `--follow-deadzone` (INT:INT bounded to [0 - 1000], optional, default `3`) — Cursor-follow deadzone in source pixels.
- `--transition-ms` (INT:INT bounded to [0 - 10000], optional, default `300`) — Zoom transition duration.
- `--interactive-zoom` (optional, flag) — Change zoom with Shift+mouse-wheel while recording.
- `--zoom-step` (FLOAT:FLOAT bounded to [0.01 - 2], optional, default `0.15`) — Interactive zoom increment per wheel notch.
- `--zoom-min` (FLOAT:FLOAT bounded to [1 - 32], optional, default `1`)
- `--zoom-max` (FLOAT:FLOAT bounded to [1 - 32], optional, default `4`)
- `--pass-zoom-input` (optional, default `1`, flag) — Let Shift+wheel also reach the application under the cursor.
- `--no-zoom-status` (optional, default `1`, flag) — Hide the interactive recording zoom HUD.
- `--hud-capture` (TEXT:{auto,exclude,visible}, optional, default `auto`) — HUD/frame capture policy: auto, exclude, or visible. visible allows OBS and other screen recorders to capture overlays.
- `--pause-key` (TEXT, optional) — Global shortcut that toggles recording pause/resume, e.g. F9 or Ctrl+Shift+P. Empty disables it.
- `--duration-ms` (INT:NONNEGATIVE, optional, default `0`) — Stop recording after this many milliseconds (0 = run until Ctrl+C).
- `--quality` (INT:INT bounded to [1 - 100], optional, default `85`) — JPEG quality for MJPEG frames (1-100; default: 85).
- `--audio-source` (TEXT:{none,mic,desktop,mix}, optional, default `none`) — Mux audio into MP4: none (default), mic, desktop (system loopback), or mix.
- `--audio-device` (TEXT, optional) — Mic device name substring for --audio-source mic/mix. Omit to use the system default input device.
- `--desktop` (TEXT, optional) — Loopback device name substring for --audio-source desktop/mix (empty = default render device). Implies desktop when --audio-source is omitted.
- `--mic-gain` (FLOAT:NONNEGATIVE, optional, default `1`) — Mic level multiplier (linear; 0 = mute, 1 = unity). Used with mix.
- `--desktop-gain` (FLOAT:NONNEGATIVE, optional, default `1`) — Desktop/loopback level multiplier (linear). Used with desktop or mix.

#### `video record stop`

Signal a running `video record` session in another terminal to stop cooperatively.

- Allows extra positional arguments.

#### `video record status`

Show the active `video record` session (device, mode, codec, elapsed time, frames, dst).

- Allows extra positional arguments.

**Options:**

- `--json` (optional, flag) — Machine-readable JSON on stdout.

#### `video detect`

Real-time YOLO-format object detection from a webcam. Outputs NDJSON frames to stdout; prints a summary on exit. Requires FEATURE_VIDEO_DETECTION (FEATURE_VIDEO + FEATURE_ONNX).

- Allows extra positional arguments.

**Options:**

- `--model` (TEXT, required) — YOLO ONNX model (e.g. yolov8n.onnx).
- `--input` (TEXT, optional) — Capture source: camera device name (case-insensitive substring; default = first device), a monitor "screen:N", or a window "screen:0:wintitle=GLOB". GLOB is a full-title match (*, ?), so wrap with stars: screen:0:wintitle=*Chrome*. See `video info --screens` for available screens/windows.
- `--width` (INT, optional, default `0`) — Preferred capture width  (0 = device default).
- `--height` (INT, optional, default `0`) — Preferred capture height (0 = device default).
- `--fps` (INT:POSITIVE, optional, default `30`) — Preferred capture frame rate (default 30).
- `--conf` (FLOAT:FLOAT in [0 - 1], optional, default `0.25`) — Confidence threshold (default 0.25).
- `--nms` (FLOAT:FLOAT in [0 - 1], optional, default `0.45`) — NMS IoU threshold (default 0.45).
- `--input-size` (INT:INT in [32 - 4096], optional, default `640`) — Model input size in pixels (default 640).
- `--every-n` (INT:POSITIVE, optional, default `1`) — Run YOLO every N captured frames — drop intermediate frames (default 1).
- `--threads` (INT:INT in [1 - 256], optional, default `4`) — ONNX intra-op thread count (default 4).
- `--duration-ms` (INT:NONNEGATIVE, optional, default `0`) — Stop after N milliseconds (0 = run until Ctrl+C).
- `--task` (TEXT:{auto,detect,classify,cls,obb,pose,segment,seg}, optional) — YOLO head to decode: auto|detect|classify|obb|pose|segment. auto (default) infers detect/classify/segment from the model; obb/pose must be requested explicitly. segment emits a mask polygon (contour) per box (no OpenCV).
- `--top-k` (INT:POSITIVE, optional, default `5`) — classify task: number of top predictions to emit per frame (default 5).
- `--classes` (TEXT, optional) — Comma-separated class label list matching model output class indices (e.g. 'person,bicycle,car,...'). Overridden by --labels-yaml.
- `--labels-yaml` (TEXT:FILE, optional) — Path to a YOLO data.yaml; reads the 'names:' block as class labels. Takes precedence over --classes.
- `--save-frames` (TEXT, optional) — Directory to save every captured frame as JPEG (useful for building a training dataset).
- `--filter-classes` (TEXT, optional) — Only emit NDJSON lines for frames that contain at least one box whose label matches (case-insensitive substring). Frames with no matching detections are silently skipped. Can be specified multiple times or as a comma-separated list (e.g. --filter-classes cat --filter-classes car).
- `--quiet` (optional, flag) — Suppress the per-frame NDJSON stream on stdout (the final summary line still prints). Handy for --visualize-only runs. Combine with --no-summary for total silence, or redirect stdout (1>$null).
- `--no-summary` (optional, flag) — Also suppress the end-of-run summary line on stdout.
- `--max-objects` (INT:NONNEGATIVE, optional) — Keep only the top-N detections per frame (0 = unlimited). Selection is sticky across frames (follows the same object by position) so a single box doesn't hop between similar objects. Applies after --filter-classes, to both the NDJSON output and the overlay. E.g. --max-objects 1 = single object.
- `--max-by` (TEXT:{conf,area}, optional) — Priority when picking which object(s) to keep for --max-objects: 'conf' (default, highest confidence) or 'area' (largest extent — the biggest / closest object).
- `--smooth-alpha` (FLOAT:FLOAT in [0 - 1], optional) — EMA smoothing factor for overlay bounding boxes (0=maximum smooth, 1=raw/no smoothing, default 0.35). Only affects visualization.
- `--smooth-age` (INT:NONNEGATIVE, optional) — Frames a detection persists in the overlay after it disappears (prevents flashing, default 4). Set 0 to disable persistence.
- `--visualize` (optional, flag) — Open an on-screen visualization window with bounding boxes. Mode is auto-selected: transparent overlay for screen: inputs, preview window for webcam. Override with --visualize-mode.
- `--visualize-mode` (TEXT:{auto,overlay,preview}, optional) — Visualization mode: auto (default), overlay (transparent topmost window over source rect), or preview (windowed frame + boxes).
- `--no-stats` (optional, default `1`, flag) — Hide the stats bar (frame / infer_ms / fps / box count) from the visualization window.
- `--no-labels` (optional, default `1`, flag) — Hide class label + confidence text above each bounding box.
- `--fill-alpha` (INT:INT in [0 - 255], optional) — Box fill opacity 0–255 (0 = border-only, default 40).
- `--smooth-min-hits` (INT:NONNEGATIVE, optional) — Frames a track must be seen before it is shown (confirmation / "min age"; default 0 = show immediately). Suppresses one-frame false positives in the overlay.
- `--track-ids` (optional, flag) — Assign a stable track id per object and show it (#id) with a per-track color in the overlay.
- `--track-two-stage` (optional, flag) — ByteTrack-style association: match high-confidence detections first, then recover lost tracks with leftover low-confidence ones (fewer id switches through occlusion).
- `--track-conf-high` (FLOAT:FLOAT in [0 - 1], optional) — High/low confidence split for --track-two-stage (default 0.50).
- `--no-track-center` (optional, default `1`, flag) — Center-distance fallback: match by nearest predicted center when IoU=0 (recovers fast movers). On by default.
- `--track-center-dist` (FLOAT:NONNEGATIVE, optional) — Center-distance gate as a multiple of the box mean side (w+h)/2 (default 1.2). Larger = match farther jumps.
- `--track-vel-blend` (FLOAT:FLOAT in [0 - 1], optional) — Velocity EMA factor for prediction during dropouts (higher = steadier but laggier, default 0.7).
- `--kpt-min-score` (FLOAT:FLOAT in [0 - 1], optional) — Min pose keypoint score to update a joint; weaker joints freeze at their last good position (default 0.30). Reduces off-body joint snapping.
- `--provider` (TEXT:{auto,cpu,cuda}, optional, default `auto`) — ONNX execution provider: auto (default, try CUDA then CPU), cpu, or cuda (hard-require NVIDIA CUDA EP). Requires FEATURE_ONNX_CUDA=ON for CUDA.
- `--gpu-stats` (optional, flag) — Include best-effort NVIDIA VRAM telemetry in the final summary (requires nvidia-smi; ignored if unavailable).

### `bluetooth`

Bluetooth and audio-endpoint management: list, pair, and connect devices.

- Allows extra positional arguments.

**Subcommands:**

- `list` — List paired/connected Bluetooth devices (and optionally audio endpoints). Implicitly routes audio to a connected Bluetooth audio device.
- `endpoints` — List MMDevice audio endpoints (playback by default).
- `connect` — Connect a Bluetooth audio device (pairs if needed) and route audio to it.
- `disconnect` — Disconnect a Bluetooth audio device (best-effort).
- `pair` — Pair a Bluetooth device.
- `unpair` — Remove (unpair) a Bluetooth device.
- `set-default` — Set an audio endpoint as the default device for all roles.

**Options:**

- `--json` (optional, flag) — Machine-readable JSON output.

#### `bluetooth list`

List paired/connected Bluetooth devices (and optionally audio endpoints). Implicitly routes audio to a connected Bluetooth audio device.

- Allows extra positional arguments.

**Options:**

- `--json` (optional, flag) — Machine-readable JSON output.
- `--nearby` (optional, flag) — Also issue an inquiry for nearby discoverable devices (slow).
- `--endpoints` (optional, flag) — Also list playback audio endpoints.
- `--no-switch` (optional, flag) — Do not implicitly change the default playback endpoint.

#### `bluetooth endpoints`

List MMDevice audio endpoints (playback by default).

- Allows extra positional arguments.

**Options:**

- `--json` (optional, flag) — Machine-readable JSON output.
- `--capture` (optional, flag) — List recording (capture) endpoints instead of playback.

#### `bluetooth connect`

Connect a Bluetooth audio device (pairs if needed) and route audio to it.

- Allows extra positional arguments.

**Options:**

- `--json` (optional, flag) — Machine-readable JSON output.
- `--id` (TEXT, required, positional) — Device address (AA:BB:CC:DD:EE:FF) or name substring.
- `--no-switch` (optional, flag) — Connect only; do not change the default playback endpoint.
- `--timeout-ms` (INT, optional, default `6000`) — How long to wait for the audio endpoint to appear (default 6000).

#### `bluetooth disconnect`

Disconnect a Bluetooth audio device (best-effort).

- Allows extra positional arguments.

**Options:**

- `--json` (optional, flag) — Machine-readable JSON output.
- `--id` (TEXT, required, positional) — Device address or name substring.

#### `bluetooth pair`

Pair a Bluetooth device.

- Allows extra positional arguments.

**Options:**

- `--json` (optional, flag) — Machine-readable JSON output.
- `--id` (TEXT, required, positional) — Device address or name substring.

#### `bluetooth unpair`

Remove (unpair) a Bluetooth device.

- Allows extra positional arguments.

**Options:**

- `--json` (optional, flag) — Machine-readable JSON output.
- `--id` (TEXT, required, positional) — Device address or name substring.

#### `bluetooth set-default`

Set an audio endpoint as the default device for all roles.

- Allows extra positional arguments.

**Options:**

- `--json` (optional, flag) — Machine-readable JSON output.
- `--id` (TEXT, required, positional) — MMDevice endpoint id (from `bluetooth endpoints`).

### `xblox`

Run XBlox block-tree command flows.

- Allows extra positional arguments.

**Subcommands:**

- `info` — Print XBlox block/command metadata for builders and LLM composition.
- `selftest` — Run native runtime self-tests (scope frames, exit policy, muParser var factory) and print a JSON report.
- `run` — Run a blocks-file JSON document emitted by the XBlox web app.
- `session` — Inspect and control live xblox sessions (looping runs and bare hosts).

**Options:**

- `--log-level` (TEXT:{trace,debug,info,warn,warning,error,err,critical,off,none}, optional) — Alias for the global --log-level option when using `xblox --log-level ... run`.

#### `xblox info`

Print XBlox block/command metadata for builders and LLM composition.

- Allows extra positional arguments.

**Subcommands:**

- `schema` — Resolve a provider options schema via the block_params_ui resolver. Exits 0 when the schema has properties, 1 when null/unregistered.
- `options` — Resolve a block-param options list (array of {value,label}) via block_params_ui resolver. Exits 0 when options are returned, 1 when the path is unknown.

**Options:**

- `--json` (optional, flag) — Print full JSON metadata: block groups, descriptions, params, defaults, and supported commands.
- `--commands` (TEXT, optional) — Optional commands.json override for custom command metadata.

#### `xblox info schema`

Resolve a provider options schema via the block_params_ui resolver. Exits 0 when the schema has properties, 1 when null/unregistered.

- Allows extra positional arguments.

**Options:**

- `--schema-path` (TEXT, optional) — Resolver routing key, e.g. providers.whisper or providers.replicate.image.
- `--provider` (TEXT, optional) — Provider name shorthand; used as providers.<name> when --schema-path is omitted.
- `--model` (TEXT, optional) — Model slug forwarded to the resolver (e.g. base.en or stability-ai/sdxl).

#### `xblox info options`

Resolve a block-param options list (array of {value,label}) via block_params_ui resolver. Exits 0 when options are returned, 1 when the path is unknown.

- Allows extra positional arguments.

**Options:**

- `--path` (TEXT, required) — Options path, e.g. providers.replicate.collections or providers.replicate.models.official.

#### `xblox selftest`

Run native runtime self-tests (scope frames, exit policy, muParser var factory) and print a JSON report.

- Allows extra positional arguments.

#### `xblox run`

Run a blocks-file JSON document emitted by the XBlox web app.

- Allows extra positional arguments.

**Options:**

- `--src` (TEXT, required) — Path to a blocks-file JSON document: { version: 1, context?: {}, roots: [...] }.
- `--commands` (TEXT, optional) — Optional commands.json override for resolving host.runCustomCommand({ id }).
- `--json` (optional, flag) — Print a JSON execution report.
- `--dry-run` (optional, flag) — Stage CLI/external commands but do not spawn child processes.
- `--simulate` (optional, flag) — Simulate execution: resolve inputs and run pure dataflow/control blocks, but suppress side-effecting blocks (fs writes, shell, network, capture, external commands), emitting predicted 'simulated' events instead.
- `--md` (optional, flag) — Print the document as brief pseudo-code markdown (context bullets + script tree) and exit without running it.
- `--md-numbered` (optional, flag) — Use numeric bullets (1. / 2.) instead of dashes in --md output.
- `--md-filter` (TEXT, optional) — Block kinds excluded from --md output, with their subtrees (repeatable or comma-separated). Default: stdout. Pass 'none' to include everything.
- `--mermaid` (optional, flag) — Render the script section as a fenced mermaid flowchart instead of the bullet tree. Context variables stay as markdown bullets above the diagram. Requires --md.
- `--mermaid-type` (TEXT:{flow,sequence}, optional) — Diagram type: flow (default; flowchart with decision diamonds) or sequence (registry groups as participants, control flow as alt/loop fragments).
- `--mermaid-direction` (TEXT:{TD,LR,BT,RL}, optional) — Flowchart direction: TD (default, vertical), LR, BT, or RL.
- `--mermaid-color` (TEXT:{edges,groups,both,none}, optional) — Colouring: edges (yes/no/loop/case link tints), groups (node strokes per registry group + flow diamonds), both (default), or none.
- `--expand-parameters` (optional, flag) — Include set block parameters in mermaid node labels (default: compact labels — group/kind, set <name>, conditions on diamonds).
- `--no-wait` (optional, flag) — Skip sleeping for wait blocks.
- `--max-loop-iterations` (INT:INT in [0 - 1000000], optional, default `10000`) — Maximum iterations per for/while loop block.
- `--loop` (optional, flag) — Re-run the whole document until cancelled (Ctrl+C). Overrides the document's stored loop setting.
- `--no-loop` (optional, flag) — Force a single pass even if the document enables looping.
- `--loop-interval-ms` (INT:INT in [0 - 86400000], optional) — Gap in milliseconds between loop passes (0 = as fast as possible, yielding each pass). Clamped to [0, 86400000] (1 day).
- `--loop-reset` (optional, flag) — Reset scope/state each loop pass (clean restart). Default persists state across passes (variables carry over).
- `--loop-limit` (INT:INT in [0 - 9223372036854775807], optional) — Stop after exactly N document-level loop passes (0 = unlimited). Counted at the runtime level before each inter-pass yield.
- `--quiet` (optional, flag) — Suppress stdout block output (message is still resolved and the event is still emitted). Useful for benchmarking and CI runs.
- `--profile` (optional, flag) — Print a per-category timing breakdown to stderr after the run (jq VM, converters, emit, set-ctx).
- `--arg` (TEXT, optional) — Extra argument appended to cliCommand/external argv command invocations; repeatable.

#### `xblox session`

Inspect and control live xblox sessions (looping runs and bare hosts).

- Allows extra positional arguments.

**Subcommands:**

- `list` — List live sessions (stale entries are reaped on scan).
- `start` — Host a bare session and block until stopped (Ctrl+C or `session stop`).
- `stop` — Signal a session (or --all) to stop.
- `ping` — Send a ping to a session (or --all); prints the pong reply.
- `pong` — Send a pong to a session (or --all); prints the ping reply.
- `info` — Show a session's details (xblox file, cwd, pid, uptime) and live vars.
- `get` — Read a variable from a session's published scope.
- `set` — Set a variable on a session (applied at the next loop pass).
- `vars` — List a session's published variables.
- `send` — Send a directed message to a session's inbox.
- `broadcast` — Send a message to every live session's inbox.
- `recv` — Drain (or --peek) a session's message inbox.

#### `xblox session list`

List live sessions (stale entries are reaped on scan).

- Allows extra positional arguments.

**Options:**

- `--json` (optional, flag) — Emit JSON.

#### `xblox session start`

Host a bare session and block until stopped (Ctrl+C or `session stop`).

- Allows extra positional arguments.

**Options:**

- `--key` (TEXT, optional) — Session name/key (default: auto host-<ms>).
- `--label` (TEXT, optional) — Human-friendly label.
- `--json` (optional, flag) — Emit JSON.

#### `xblox session stop`

Signal a session (or --all) to stop.

- Allows extra positional arguments.

**Options:**

- `--key` (TEXT, optional) — Target session key, stem, or unambiguous prefix.
- `--all` (optional, flag) — Target every live session.
- `--json` (optional, flag) — Emit JSON replies.

#### `xblox session ping`

Send a ping to a session (or --all); prints the pong reply.

- Allows extra positional arguments.

**Options:**

- `--key` (TEXT, optional) — Target session key, stem, or unambiguous prefix.
- `--all` (optional, flag) — Target every live session.
- `--json` (optional, flag) — Emit JSON replies.

#### `xblox session pong`

Send a pong to a session (or --all); prints the ping reply.

- Allows extra positional arguments.

**Options:**

- `--key` (TEXT, optional) — Target session key, stem, or unambiguous prefix.
- `--all` (optional, flag) — Target every live session.
- `--json` (optional, flag) — Emit JSON replies.

#### `xblox session info`

Show a session's details (xblox file, cwd, pid, uptime) and live vars.

- Allows extra positional arguments.

**Options:**

- `--key` (TEXT, optional) — Target session key, stem, or unambiguous prefix.
- `--json` (optional, flag) — Emit JSON.

#### `xblox session get`

Read a variable from a session's published scope.

- Allows extra positional arguments.

**Options:**

- `--key` (TEXT, optional) — Target session key, stem, or unambiguous prefix.
- `--name` (TEXT, required) — Variable name.
- `--json` (optional, flag) — Emit JSON reply.

#### `xblox session set`

Set a variable on a session (applied at the next loop pass).

- Allows extra positional arguments.

**Options:**

- `--key` (TEXT, optional) — Target session key, stem, or unambiguous prefix.
- `--name` (TEXT, required) — Variable name.
- `--value` (TEXT, optional) — Value (parsed as JSON when possible, else a string).
- `--json` (optional, flag) — Emit JSON reply.

#### `xblox session vars`

List a session's published variables.

- Allows extra positional arguments.

**Options:**

- `--key` (TEXT, optional) — Target session key, stem, or unambiguous prefix.
- `--json` (optional, flag) — Emit compact JSON.

#### `xblox session send`

Send a directed message to a session's inbox.

- Allows extra positional arguments.

**Options:**

- `--key` (TEXT, optional) — Target session key, stem, or unambiguous prefix.
- `--message` (TEXT, optional) — Message text.
- `--from` (TEXT, optional) — Sender identity (default: cli).
- `--json` (optional, flag) — Emit JSON reply.

#### `xblox session broadcast`

Send a message to every live session's inbox.

- Allows extra positional arguments.

**Options:**

- `--message` (TEXT, optional) — Message text.
- `--from` (TEXT, optional) — Sender identity (default: cli).

#### `xblox session recv`

Drain (or --peek) a session's message inbox.

- Allows extra positional arguments.

**Options:**

- `--key` (TEXT, optional) — Target session key, stem, or unambiguous prefix.
- `--peek` (optional, flag) — Read without consuming.
- `--json` (optional, flag) — Emit JSON.

### `test`

Developer probes: low-level core and UI tests.

- Allows extra positional arguments.

**Subcommands:**

- `core` — Low-level JSON probes for sanitizer, filesystem guard, and compression tests.
- `screenshot` — Start the main window, wait, capture it to a PNG, then exit.

#### `test core`

Low-level JSON probes for sanitizer, filesystem guard, and compression tests.

- Allows extra positional arguments.

**Subcommands:**

- `string` — Apply a registered text sanitizer profile to --input.
- `path` — Run string path cleanup helpers against --input.
- `id` — Run UUID/id/group/permission cleanup helpers against --input.
- `fs-guard` — Run LLM filesystem guard policy against --path.
- `url-schemes` — URL scheme parsing and variable expansion probes (vfs/url_schemes.cpp reference impl).
- `compress` — Run the local context compressor (JSON/text structural + entropy masking) over --input / --input-file.
- `reduce` — Attention reduction POC: segment -> score/drop/protect stages -> blend -> budget-select -> render. JSON/code route to the structural compressor. Model score stages (embed/kompress) activate with --emb / --onnx+--vocab.
- `tokenize` — ModernBERT byte-level BPE parity probe: dump [CLS]+subtokens+[SEP] ids and word_ids for --input using a vocab-only GGUF (--vocab). Compare against the HF reference fixture.
- `kompress` — Run the Kompress ONNX text scorer over --input/--input-file: keep important words. Uses --onnx + --vocab when set; otherwise shipped exe/../models/kompress, then ${MODELS_DIR}/kompress.

**Options:**

- `--json` (optional, flag) — Print machine-readable JSON.

#### `test core string`

Apply a registered text sanitizer profile to --input.

- Allows extra positional arguments.

**Options:**

- `--profile` (TEXT:{common,html,markdown,skill,strip-bom,repair-utf8,ascii,html-comments,html-dangerous}, optional, default `common`) — common, html, markdown, skill, strip-bom, repair-utf8, ascii, html-comments, html-dangerous
- `--input` (TEXT, optional) — Input text
- `--input-file` (TEXT, optional) — UTF-8/binary input file to sanitize

#### `test core path`

Run string path cleanup helpers against --input.

- Allows extra positional arguments.

**Options:**

- `--input` (TEXT, required) — Input path

#### `test core id`

Run UUID/id/group/permission cleanup helpers against --input.

- Allows extra positional arguments.

**Options:**

- `--kind` (TEXT:{uuid,id,group,permission,permissions}, required) — uuid, id, group, permission, permissions
- `--input` (TEXT, required) — Input value

#### `test core fs-guard`

Run LLM filesystem guard policy against --path.

- Allows extra positional arguments.

**Options:**

- `--mode` (TEXT:{read,sensitive,write}, optional, default `read`) — read, sensitive, or write
- `--path` (TEXT, required) — Path to check

#### `test core url-schemes`

URL scheme parsing and variable expansion probes (vfs/url_schemes.cpp reference impl).

- Allows extra positional arguments.

**Subcommands:**

- `parse` — Validate and parse a tanit:// URI: scheme, verb, path safety, VFS decomposition, token format.
- `variables` — Expand ${VAR} templates using the URI-safe restricted VariableMap (no ENV:, no session context).

#### `test core url-schemes parse`

Validate and parse a tanit:// URI: scheme, verb, path safety, VFS decomposition, token format.

- Allows extra positional arguments.

**Options:**

- `--uri` (TEXT, required) — tanit:// URI to parse and validate

#### `test core url-schemes variables`

Expand ${VAR} templates using the URI-safe restricted VariableMap (no ENV:, no session context).

- Allows extra positional arguments.

**Options:**

- `--input` (TEXT, required) — Template string to expand

#### `test core compress`

Run the local context compressor (JSON/text structural + entropy masking) over --input / --input-file.

- Allows extra positional arguments.

**Options:**

- `--input` (TEXT, optional) — Input text/JSON
- `--input-file` (TEXT, optional) — Input file to compress
- `--type` (TEXT:{auto,json,text,code,log,markdown,diff}, optional, default `auto`) — auto, json, text, code, log, markdown, diff
- `--ratio` (FLOAT:FLOAT in [0 - 1], optional, default `0.3`) — Truncation target as a fraction of span length (0-1, default 0.3)
- `--no-truncate` (optional, flag) — Lossless reduction only (whitespace collapse + line dedup; no head/tail truncation)
- `--no-entropy` (optional, flag) — Disable high-entropy identifier preservation

#### `test core reduce`

Attention reduction POC: segment -> score/drop/protect stages -> blend -> budget-select -> render. JSON/code route to the structural compressor. Model score stages (embed/kompress) activate with --emb / --onnx+--vocab.

- Allows extra positional arguments.

**Options:**

- `--input` (TEXT, optional) — Input text
- `--input-file` (TEXT, optional) — Input file
- `--objective` (TEXT, optional) — Query/objective for relevance scoring (lexical; embed when --emb given)
- `--unit` (TEXT:{auto,line,paragraph,whole}, optional, default `auto`) — auto, line, paragraph, whole
- `--type` (TEXT:{auto,json,text,code,log,markdown,diff}, optional, default `auto`) — auto, json, text, code, log, markdown, diff (json/code -> structural)
- `--stages` (TEXT, optional) — Comma list, e.g. protect,lexical,entropy,blend,topk (overrides --preset)
- `--preset` (TEXT:{logs,docs,prose,tool,memory}, optional) — logs, docs, prose, tool, memory
- `--budget` (TEXT, optional, default `ratio=0.5`) — ratio=0.5 | tokens=200 | threshold=0.5
- `--drop-markers` (optional, flag) — Emit ...[dropped N]... markers between kept units
- `--emb` (TEXT, optional) — Embedding GGUF for the embed stage (requires --objective)
- `--onnx` (TEXT, optional) — Kompress ONNX (empty → shipped exe/../models/kompress, then ${MODELS_DIR})
- `--vocab` (TEXT, optional) — ModernBERT vocab GGUF (empty → shipped, then ${MODELS_DIR})

#### `test core tokenize`

ModernBERT byte-level BPE parity probe: dump [CLS]+subtokens+[SEP] ids and word_ids for --input using a vocab-only GGUF (--vocab). Compare against the HF reference fixture.

- Allows extra positional arguments.

**Options:**

- `--vocab` (TEXT, required) — Path to vocab-only ModernBERT GGUF
- `--input` (TEXT, required) — Text to tokenize (split on ASCII whitespace)
- `--max-len` (INT:INT in [2 - 8192], optional, default `512`) — Max sequence length incl. [CLS]/[SEP] (default 512)

#### `test core kompress`

Run the Kompress ONNX text scorer over --input/--input-file: keep important words. Uses --onnx + --vocab when set; otherwise shipped exe/../models/kompress, then ${MODELS_DIR}/kompress.

- Allows extra positional arguments.

**Options:**

- `--onnx` (TEXT, optional) — kompress-int8-wo.onnx (default: shipped, then ${MODELS_DIR})
- `--vocab` (TEXT, optional) — modernbert-vocab.gguf (default: shipped, then ${MODELS_DIR})
- `--input` (TEXT, optional) — Text to compress
- `--input-file` (TEXT, optional) — File alternative to --input
- `--ratio` (FLOAT:FLOAT in [-1 - 1], optional, default `-1`) — Keep ratio per chunk (0-1). <=0 (default): score-threshold mode.
- `--chunk` (INT:INT in [1 - 4096], optional, default `350`) — Words per chunk (default 350)
- `--scores` (optional, flag) — Also dump per-word max scores
- `--via-compressor` (optional, flag) — Register the scorer and route through universal_compressor (Text)

#### `test screenshot`

Start the main window, wait, capture it to a PNG, then exit.

- Allows extra positional arguments.

**Options:**

- `--output` (TEXT, required) — PNG output path
- `--wait-ms` (INT, optional, default `2000`) — Milliseconds to wait after UI init before capture (default: 2000)

### `status`

Show Tanit credits and license status.

- Allows extra positional arguments.

**Options:**

- `--json` (optional, flag) — Print machine-readable JSON on stdout.
- `--log` (optional, flag) — Show recent Tanit spend log entries.
- `--log-days` (INT:INT in [1 - 365], optional) — Number of days to look back for --log (default 7).

### `commands`

List registered pm-image CLI commands for UI/custom-command pickers and scripts.

- Allows extra positional arguments.

**Options:**

- `--json` (optional, flag) — Print command metadata as JSON.

### `daemon`

Global shortcut daemon: hotkeys, UI presets, app commands, STT, and voice session.

- Allows extra positional arguments.

**Subcommands:**

- `run` — Run the foreground hotkey daemon (default action).
- `tray` — Run the user-session tray daemon with global hotkeys and a notification-area menu.
- `register` — Windows: register the daemon for logon by writing HKLM Run (requires elevation). Seeds config if missing.
- `unregister` — Windows: remove the daemon HKLM Run entry (requires elevation).
- `stop` — Windows: stop the running daemon for this user session.
- `path` — Print the effective daemon.json path and exit.

**Options:**

- `--config` (TEXT, optional) — Daemon JSON config path. Default: the app roaming profile daemon.json next to settings.json.
- `--elevated-write-only` (optional, flag) — Internal: elevated register writes autorun only; caller starts the daemon.

#### `daemon run`

Run the foreground hotkey daemon (default action).

- Allows extra positional arguments.

**Options:**

- `--tray` (optional, flag) — Run with a notification-area tray icon.

#### `daemon tray`

Run the user-session tray daemon with global hotkeys and a notification-area menu.

- Allows extra positional arguments.

#### `daemon register`

Windows: register the daemon for logon by writing HKLM Run (requires elevation). Seeds config if missing.

- Allows extra positional arguments.

#### `daemon unregister`

Windows: remove the daemon HKLM Run entry (requires elevation).

- Allows extra positional arguments.

#### `daemon stop`

Windows: stop the running daemon for this user session.

- Allows extra positional arguments.

#### `daemon path`

Print the effective daemon.json path and exit.

- Allows extra positional arguments.

### `assistant`

AI assistant: toolbar, global shortcuts, realtime voice, and UIA spy.
With no subcommand: starts the assistant toolbar/global shortcut host.

- Allows extra positional arguments.

**Subcommands:**

- `app-inspect` — Inspect desktop applications for computer-use.
- `app-use` — Perform replayable computer-use actions: open apps, click, type, and send hotkeys.
- `pick` — Interactively pick a window/element on any monitor with a live highlight.
Move the mouse over the target and left-click (ESC cancels). Prints a JSON
descriptor with a canonical capture `selector` (usable as `video detect/out
--input screen:...`), plus HWND, UIA (AutomationId/Name/ControlType), process
exe + command line, and the precise rectangle (coords fallback).
- `spy` — Foreground UIAutomation focus spy: polls the focused element and logs all available UIA properties + text content (ValuePattern, TextPattern). Target apps: Notepad, LibreOffice, Chrome. Press Ctrl+C to stop.

Targets with special handling in src/win/assistant/:
  notepad.exe  — class RichEditD2DPT; ValuePattern + TextPattern both work.
  soffice.bin  — class SALFRAME; TextPattern in Writer, clipboard in Calc/Impress.
  chrome.exe   — framework 'Chrome'; address bar via ValuePattern, content via TextPattern.
  msedge.exe   — same as Chrome.
  code.exe     — VSCode Electron; Monaco a11y bridge exposes TextPattern.

**Options:**

- `--ui` (optional, default `1`, flag) — Show the assistant toolbar window (topmost pill, left-edge snap by default).
Default: on when no subcommand is given.
- `--realtime` (optional, flag) — Toggle a live voice session (start if idle, stop if running) and exit.
- `--stop` (optional, flag) — Signal a detached assistant toolbar (started via `pm-image assistant` or `app togglelauncher`) to close cooperatively.

#### `assistant app-inspect`

Inspect desktop applications for computer-use.

- Allows extra positional arguments.

**Subcommands:**

- `dump` — Dump visible windows and useful UIA elements with screen coordinates.
- `screenshot` — Save a screen crop as JPEG. Use --rect=x,y,w,h or --element from a matching dump.

#### `assistant app-inspect dump`

Dump visible windows and useful UIA elements with screen coordinates.

- Allows extra positional arguments.

**Options:**

- `--json` (optional, flag) — Pretty-print JSON output.
- `--md` (optional, flag) — Print a compact Markdown tree for humans and LLMs.
- `--probe-cells` (optional, flag) — Probe visible virtualized cells with ElementFromPoint (slower; auto-enabled for spreadsheet-looking --md targets).
- `--foreground` (optional, flag) — Inspect only the foreground window.
- `--pid` (INT, optional) — Inspect windows for a process id.
- `--process` (TEXT, optional) — Case-insensitive process-name substring filter, e.g. notepad.exe.
- `--title` (TEXT, optional) — Case-insensitive title substring filter.
- `--controls` (TEXT, optional) — Markdown control filter, e.g. button,menuitem,edit,input,text.
- `--limit` (INT:INT in [1 - 10000], optional, default `500`) — Maximum useful elements per window.
- `--text-max-chars` (INT:INT in [20 - 200000], optional, default `4096`) — Maximum characters per Markdown text/value field.

#### `assistant app-inspect screenshot`

Save a screen crop as JPEG. Use --rect=x,y,w,h or --element from a matching dump.

- Allows extra positional arguments.

**Options:**

- `--json` (optional, flag) — Pretty-print JSON output.
- `--foreground` (optional, flag) — Resolve --element in the foreground window.
- `--pid` (INT, optional) — Resolve --element for a process id.
- `--process` (TEXT, optional) — Resolve window/element by process-name substring.
- `--title` (TEXT, optional) — Resolve --element by title substring.
- `--element` (INT, optional) — Element index from app-inspect dump.
- `--rect` (TEXT, optional) — Screen rectangle x,y,w,h.
- `--output` (TEXT, required) — Destination .jpg path.
- `--quality` (INT:INT in [1 - 100], optional, default `85`) — JPEG quality 1..100.
- `--no-activate` (optional, flag) — Skip bringing the target window to foreground before capture. Default: when a window is resolved by --title/--process/--pid/--foreground, it is activated first so the capture matches what the user sees.

#### `assistant app-use`

Perform replayable computer-use actions: open apps, click, type, and send hotkeys.

- Allows extra positional arguments.

**Subcommands:**

- `open-app` — Launch an app with optional args/cwd and place its first visible window.
- `mouse-move` — Move the cursor to a screen coordinate. Use --api-width/--api-height for scaled LLM coordinates.
- `click` — Click a screen coordinate. Supports --button, --count, scaled API coords, and --virtual HWND messages.
- `type` — Type UTF-8 text into the currently focused control via Unicode SendInput.
- `hotkey` — Send a hotkey sequence such as ctrl+s, alt+f, or f5.
- `key-press` — Press a single key, hold for --hold-ms, release. Use this when key DURATION matters (virtual pianos, rhythm games, held-modifier window managers). For chords / shortcuts, prefer `hotkey` (atomic) and for melodies use `batch` with key-press steps.
- `cursor-position` — Report cursor position and virtual-screen dimensions; optionally include scaled API coordinates.
- `batch` — Run a JSON app-use action sequence in one process, with per-step delays and wait-element polling.
- `close-app` — Close a window gracefully (WM_CLOSE) and wait for the process to exit. Pass --force to TerminateProcess if it doesn't exit within --wait-ms.

#### `assistant app-use open-app`

Launch an app with optional args/cwd and place its first visible window.

- Allows extra positional arguments.

**Options:**

- `--json` (optional, flag) — Pretty-print JSON output.
- `--exe` (TEXT, required) — Executable path or name.
- `--args` (TEXT, optional) — Raw command-line args passed after --exe.
- `--cwd` (TEXT, optional) — Working directory.
- `--x` (INT, optional) — Window left coordinate.
- `--y` (INT, optional) — Window top coordinate.
- `--width` (INT, optional) — Window width.
- `--height` (INT, optional) — Window height.
- `--wait-ms` (INT:INT in [0 - 60000], optional, default `1000`) — Milliseconds to wait for first visible window.

#### `assistant app-use mouse-move`

Move the cursor to a screen coordinate. Use --api-width/--api-height for scaled LLM coordinates.

- Allows extra positional arguments.

**Options:**

- `--json` (optional, flag) — Pretty-print JSON output.
- `--x` (INT, required) — X coordinate.
- `--y` (INT, required) — Y coordinate.
- `--api-width` (INT, optional) — Coordinate-space width from an LLM computer-use API.
- `--api-height` (INT, optional) — Coordinate-space height from an LLM computer-use API.

#### `assistant app-use click`

Click a screen coordinate. Supports --button, --count, scaled API coords, and --virtual HWND messages.

- Allows extra positional arguments.

**Options:**

- `--json` (optional, flag) — Pretty-print JSON output.
- `--virtual` (optional, flag) — Do not move the physical cursor; post mouse messages.
- `--x` (INT, required) — Screen x coordinate.
- `--y` (INT, required) — Screen y coordinate.
- `--button` (TEXT, optional, default `left`) — Mouse button: left, right, or middle.
- `--count` (INT:INT in [1 - 10], optional, default `1`) — Click count (2 = double click).
- `--api-width` (INT, optional) — Coordinate-space width from an LLM computer-use API.
- `--api-height` (INT, optional) — Coordinate-space height from an LLM computer-use API.

#### `assistant app-use type`

Type UTF-8 text into the currently focused control via Unicode SendInput.

- Allows extra positional arguments.

**Options:**

- `--json` (optional, flag) — Pretty-print JSON output.
- `--text` (TEXT, required) — Text to type.

#### `assistant app-use hotkey`

Send a hotkey sequence such as ctrl+s, alt+f, or f5.

- Allows extra positional arguments.

**Options:**

- `--json` (optional, flag) — Pretty-print JSON output.
- `--keys` (TEXT, required) — Keys separated by +, comma, or spaces.

#### `assistant app-use key-press`

Press a single key, hold for --hold-ms, release. Use this when key DURATION matters (virtual pianos, rhythm games, held-modifier window managers). For chords / shortcuts, prefer `hotkey` (atomic) and for melodies use `batch` with key-press steps.

- Allows extra positional arguments.

**Options:**

- `--json` (optional, flag) — Pretty-print JSON output.
- `--key` (TEXT, required) — Single key name (a-z, 0-9, f1..f12, enter, space, left, up, ...).
- `--hold-ms` (INT:INT in [0 - 30000], optional, default `50`) — How long to hold the key down (ms). FreePiano / similar apps treat this as note sustain.
- `--modifiers` (TEXT, optional) — Optional modifiers held during the press, separated by +/,/space (e.g. "ctrl" or "ctrl+shift").

#### `assistant app-use cursor-position`

Report cursor position and virtual-screen dimensions; optionally include scaled API coordinates.

- Allows extra positional arguments.

**Options:**

- `--json` (optional, flag) — Pretty-print JSON output.
- `--api-width` (INT, optional) — Coordinate-space width from an LLM computer-use API.
- `--api-height` (INT, optional) — Coordinate-space height from an LLM computer-use API.

#### `assistant app-use batch`

Run a JSON app-use action sequence in one process, with per-step delays and wait-element polling.

- Allows extra positional arguments.

**Options:**

- `--json` (optional, flag) — Pretty-print JSON output.
- `--continue-on-error` (optional, flag) — Continue running later steps after a step fails.
- `--file` (TEXT, required) — Batch JSON file: an array or {"steps":[...]} document.
- `--default-delay-ms` (INT:INT in [0 - 60000], optional, default `50`) — Default delay after each step (ms).
- `--speed` (FLOAT:FLOAT in [0.05 - 20], optional, default `1`) — Replay speed multiplier: 1.0=normal, 0.5=half speed (delays×2), 2.0=double speed. Also settable as top-level JSON key "speed" in the batch file.

#### `assistant app-use close-app`

Close a window gracefully (WM_CLOSE) and wait for the process to exit. Pass --force to TerminateProcess if it doesn't exit within --wait-ms.

- Allows extra positional arguments.

**Options:**

- `--json` (optional, flag) — Pretty-print JSON output.
- `--pid` (INT, optional) — Target process id.
- `--hwnd` (INT, optional) — Target window handle (decimal).
- `--title` (TEXT, optional) — Find window by title substring.
- `--force` (optional, flag) — TerminateProcess if graceful close times out.
- `--wait-ms` (INT:INT in [0 - 30000], optional, default `2000`) — Wait for process exit (default 2000 ms).

#### `assistant pick`

Interactively pick a window/element on any monitor with a live highlight.
Move the mouse over the target and left-click (ESC cancels). Prints a JSON
descriptor with a canonical capture `selector` (usable as `video detect/out
--input screen:...`), plus HWND, UIA (AutomationId/Name/ControlType), process
exe + command line, and the precise rectangle (coords fallback).

- Allows extra positional arguments.

**Options:**

- `--json` (optional, flag) — Pretty-print JSON output.
- `--target` (TEXT:{auto,follow,element,window,monitor}, optional, default `auto`) — Which selector to make canonical: auto|follow|element|window|monitor.
auto   = follow when a sub-window element is picked, else window.
follow = hwnd=<root>:rrect=dx,dy,w,h — sub-rect that tracks window moves.
element= fixed screen rect (does not track moves).
window = whole window (hwnd=).  monitor = whole monitor.
- `--no-highlight` (optional, flag) — Do not draw the translucent highlight that follows the cursor.
- `--no-uia` (optional, flag) — Skip UIA ElementFromPoint (no AutomationId/Name/precise element rect).
- `--visible-only` (optional, flag) — Disable descent into hidden child windows (WinSpy fShowHidden). Default off: hidden descent is needed to land on Chrome render widgets.
- `--no-cmdline` (optional, flag) — Skip reading the target process command line (args).

#### `assistant spy`

Foreground UIAutomation focus spy: polls the focused element and logs all available UIA properties + text content (ValuePattern, TextPattern). Target apps: Notepad, LibreOffice, Chrome. Press Ctrl+C to stop.

Targets with special handling in src/win/assistant/:
  notepad.exe  — class RichEditD2DPT; ValuePattern + TextPattern both work.
  soffice.bin  — class SALFRAME; TextPattern in Writer, clipboard in Calc/Impress.
  chrome.exe   — framework 'Chrome'; address bar via ValuePattern, content via TextPattern.
  msedge.exe   — same as Chrome.
  code.exe     — VSCode Electron; Monaco a11y bridge exposes TextPattern.

- Allows extra positional arguments.

**Options:**

- `--interval-ms` (INT:INT in [50 - 60000], optional, default `500`) — Poll interval in milliseconds (default 500; minimum 50).
- `--no-value` (optional, flag) — Skip IUIAutomationValuePattern (edit fields, cells, address bars).
- `--no-selection` (optional, flag) — Skip IUIAutomationTextPattern selection ranges.
- `--no-text` (optional, flag) — Skip IUIAutomationTextPattern document range (full buffer).
- `--all` (optional, flag) — Log every poll tick even when nothing changed (very verbose).
- `--text-max-chars` (INT, optional, default `4096`) — Maximum characters to extract from the TextPattern document range (default 4096; -1 = no cap — caution: can be very large).
- `--stt` (optional, flag) — Enable live STT dictation: microphone → ElevenLabs Scribe v2 Realtime →
write-back to the currently focused UI element via SendInput (KEYEVENTF_UNICODE).
Ctrl+C stops both spy and STT. In --stt mode, spy output shows focus changes only.
- `--stt-live` (optional, default `1`, flag) — Stream audio to the STT server as each chunk is captured (default: on).
With --no-stt-live, PCM is buffered per utterance and sent in one shot on VAD commit
(no partial transcript feedback; may improve accuracy for short phrases).
- `--stt-provider` (TEXT, optional) — STT provider name (default: chat settings stt_provider, e.g. "elevenlabs").
- `--stt-api-key` (TEXT, optional) — API key for the STT provider (default: from app provider settings).
- `--stt-silence-ms` (INT:INT in [300 - 10000], optional, default `1200`) — VAD silence threshold in ms before auto-committing an utterance (default 1200).

### `info`

Generate reference docs for Tanit: CLI commands, XBlox blocks, app verbs, and agent tools. Default: plain markdown (end-user docs). --skill: agent-skill with YAML frontmatter. --json: structured JSON for scripting.

- Allows extra positional arguments.

**Subcommands:**

- `commands` — Generate a CLI + custom command reference. Plain md: commands.md in cwd. --skill: <profile>/skills/commands/SKILL.md. --json: commands.json.
- `xblox` — Generate an XBlox block-flow reference. Plain md: xblox.md in cwd. --skill: <profile>/skills/xblox/SKILL.md. --json: xblox.json.
- `app-commands` — Generate a Tanit app/UI command verb reference (togglechat, takescreenshot, etc.) grouped by category. Plain md: app-commands.md in cwd. --skill: <profile>/skills/app-commands/SKILL.md.
- `tools` — Generate an LLM agent path-tool reference with parameters and descriptions. Plain md: tools.md in cwd. --skill: <profile>/skills/tools/SKILL.md. --json: tools.json.

#### `info commands`

Generate a CLI + custom command reference. Plain md: commands.md in cwd. --skill: <profile>/skills/commands/SKILL.md. --json: commands.json.

- Allows extra positional arguments.

**Options:**

- `--dst` (TEXT, optional) — Output path. Plain md: <name>.md in cwd (default). --skill: <profile>/skills/<name>/SKILL.md (default). --json: <name>.json in cwd (default).
- `--stdout` (optional, flag) — Print to stdout instead of writing --dst.
- `--skill` (optional, flag) — Wrap output with YAML frontmatter and a generated-by marker for use as an agent skill file. Default (without --skill): plain markdown for end-user docs.
- `--json` (optional, flag) — Emit structured JSON instead of markdown. Useful for scripting; pipe into jq or import into other tools. Takes priority over --skill when both are set.

#### `info xblox`

Generate an XBlox block-flow reference. Plain md: xblox.md in cwd. --skill: <profile>/skills/xblox/SKILL.md. --json: xblox.json.

- Allows extra positional arguments.

**Options:**

- `--dst` (TEXT, optional) — Output path. Plain md: <name>.md in cwd (default). --skill: <profile>/skills/<name>/SKILL.md (default). --json: <name>.json in cwd (default).
- `--stdout` (optional, flag) — Print to stdout instead of writing --dst.
- `--skill` (optional, flag) — Wrap output with YAML frontmatter and a generated-by marker for use as an agent skill file. Default (without --skill): plain markdown for end-user docs.
- `--json` (optional, flag) — Emit structured JSON instead of markdown. Useful for scripting; pipe into jq or import into other tools. Takes priority over --skill when both are set.

#### `info app-commands`

Generate a Tanit app/UI command verb reference (togglechat, takescreenshot, etc.) grouped by category. Plain md: app-commands.md in cwd. --skill: <profile>/skills/app-commands/SKILL.md.

- Allows extra positional arguments.

**Options:**

- `--dst` (TEXT, optional) — Output path. Plain md: <name>.md in cwd (default). --skill: <profile>/skills/<name>/SKILL.md (default). --json: <name>.json in cwd (default).
- `--stdout` (optional, flag) — Print to stdout instead of writing --dst.
- `--skill` (optional, flag) — Wrap output with YAML frontmatter and a generated-by marker for use as an agent skill file. Default (without --skill): plain markdown for end-user docs.
- `--json` (optional, flag) — Emit structured JSON instead of markdown. Useful for scripting; pipe into jq or import into other tools. Takes priority over --skill when both are set.

#### `info tools`

Generate an LLM agent path-tool reference with parameters and descriptions. Plain md: tools.md in cwd. --skill: <profile>/skills/tools/SKILL.md. --json: tools.json.

- Allows extra positional arguments.

**Options:**

- `--dst` (TEXT, optional) — Output path. Plain md: <name>.md in cwd (default). --skill: <profile>/skills/<name>/SKILL.md (default). --json: <name>.json in cwd (default).
- `--stdout` (optional, flag) — Print to stdout instead of writing --dst.
- `--skill` (optional, flag) — Wrap output with YAML frontmatter and a generated-by marker for use as an agent skill file. Default (without --skill): plain markdown for end-user docs.
- `--json` (optional, flag) — Emit structured JSON instead of markdown. Useful for scripting; pipe into jq or import into other tools. Takes priority over --skill when both are set.

### `llama`

GGUF embedding: embed texts, rank candidates by cosine similarity, or benchmark.

- Allows extra positional arguments.

**Subcommands:**

- `embed` — Embed one or more texts and print JSON with dim, ok, and optionally the full vector.
- `match` — Rank candidates by cosine similarity to a query, output JSON.
- `benchmark` — Run built-in string-utils parity cases and report pass/fail.
- `vlm` — Multimodal VLM inference: encode an image and generate text (OCR, captions, ...).

#### `llama embed`

Embed one or more texts and print JSON with dim, ok, and optionally the full vector.

- Allows extra positional arguments.

**Options:**

- `--model` (TEXT, required) — Path to GGUF embedding model (e.g. ${MODELS_DIR}/all-MiniLM-L6-v2.Q5_K_M.gguf).
- `--threads` (INT:INT in [1 - 256], optional, default `4`) — CPU threads for inference (default 4).
- `--ctx` (INT:INT in [32 - 8192], optional, default `512`) — Context length for the embedding model (default 512).
- `--text` (TEXT, required) — Text to embed (repeat for multiple).
- `--full-vec` (optional, flag) — Include the full float32 embedding array in the JSON output.

#### `llama match`

Rank candidates by cosine similarity to a query, output JSON.

- Allows extra positional arguments.

**Options:**

- `--model` (TEXT, required) — Path to GGUF embedding model (e.g. ${MODELS_DIR}/all-MiniLM-L6-v2.Q5_K_M.gguf).
- `--threads` (INT:INT in [1 - 256], optional, default `4`) — CPU threads for inference (default 4).
- `--ctx` (INT:INT in [32 - 8192], optional, default `512`) — Context length for the embedding model (default 512).
- `--query` (TEXT, required) — Query text.
- `--candidate` (TEXT, required) — Candidate text(s) to rank (repeat for each).
- `--top` (INT, optional, default `0`) — Return only the top N results (0 = all).

#### `llama benchmark`

Run built-in string-utils parity cases and report pass/fail.

- Allows extra positional arguments.

**Options:**

- `--model` (TEXT, required) — Path to GGUF embedding model (e.g. ${MODELS_DIR}/all-MiniLM-L6-v2.Q5_K_M.gguf).
- `--threads` (INT:INT in [1 - 256], optional, default `4`) — CPU threads for inference (default 4).
- `--ctx` (INT:INT in [32 - 8192], optional, default `512`) — Context length for the embedding model (default 512).
- `--json` (optional, flag) — Append full JSON result block after the human-readable summary.

#### `llama vlm`

Multimodal VLM inference: encode an image and generate text (OCR, captions, ...).

- Allows extra positional arguments.

**Options:**

- `--model` (TEXT, required) — Path to the language-model GGUF (e.g. PaddleOCR-VL-1.5.gguf).
- `--mmproj` (TEXT, required) — Path to the vision projector GGUF (e.g. PaddleOCR-VL-1.5-mmproj.gguf).
- `--image` (TEXT, required) — Path to the input image (JPEG / PNG).
- `--prompt` (TEXT, optional, default `OCR:`) — Text prompt appended after the image tokens (default: "OCR:").
- `--threads` (INT:INT in [1 - 256], optional, default `4`) — CPU threads for inference (default 4).
- `--ctx` (INT:INT in [512 - 65536], optional, default `8192`) — KV context length (default 8192).
- `--n-predict` (INT:INT in [1 - 16384], optional, default `2048`) — Maximum tokens to generate (default 2048).
- `--ngl` (INT:INT in [-1 - 1000], optional, default `-1`) — Number of model layers to offload to GPU (-1 = all, 0 = CPU-only; default -1).
- `--frame` (TEXT, optional) — Additional image path(s) for multi-frame / video inference. Repeat for each frame: --image frame0.png --frame frame1.png --frame frame2.png. All frames are passed to the model simultaneously; --image is always frame 0.

### `onnx`

ONNX Runtime inference: inspect models, run inference, classify images, detect text.

- Allows extra positional arguments.

**Subcommands:**

- `info` — Print model input/output names, element types, and shapes as JSON.
- `run` — Run inference with zero inputs (or --image) and print output shapes as JSON.
- `classify` — Classify an image using a float32[1,3,H,W] model (SqueezeNet, MobileNetV2, …).
- `ocr` — Detect text regions in an image using PP-OCRv4-det (or compatible DB detector).
- `detect` — YOLO-format UI-element/object detection (OmniParser icon_detect, YOLOv8, …).
- `layout` — PP-DocLayoutV3 document layout analysis — detects regions (table, text, title, …) with bounding boxes and reading order.
- `train` — Fine-tune a YOLO model on a custom dataset and export to ONNX. Requires Python + ultralytics (`pip install ultralytics`). Trains with `model.train()` and exports via `model.export(format='onnx')`, then copies best.onnx to --output.

#### `onnx info`

Print model input/output names, element types, and shapes as JSON.

- Allows extra positional arguments.

**Options:**

- `--model` (TEXT, required) — Path to ONNX model file (.onnx).
- `--threads` (INT:INT in [1 - 256], optional, default `4`) — Intra-op CPU thread count (default 4).
- `--provider` (TEXT:{cpu,cuda}, optional, default `cpu`) — Execution provider: cpu (default) or cuda (NVIDIA GPU via CUDA EP). Requires FEATURE_ONNX_CUDA=ON build, GPU ORT package in third_party/, and CUDA runtime installed.

#### `onnx run`

Run inference with zero inputs (or --image) and print output shapes as JSON.

- Allows extra positional arguments.

**Options:**

- `--model` (TEXT, required) — Path to ONNX model file (.onnx).
- `--threads` (INT:INT in [1 - 256], optional, default `4`) — Intra-op CPU thread count (default 4).
- `--provider` (TEXT:{cpu,cuda}, optional, default `cpu`) — Execution provider: cpu (default) or cuda (NVIDIA GPU via CUDA EP). Requires FEATURE_ONNX_CUDA=ON build, GPU ORT package in third_party/, and CUDA runtime installed.
- `--image` (TEXT:FILE, optional) — Image file to preprocess and feed as the first input tensor.
- `--full-vec` (optional, flag) — Include full float32 output values in JSON (may be large).

#### `onnx classify`

Classify an image using a float32[1,3,H,W] model (SqueezeNet, MobileNetV2, …).

- Allows extra positional arguments.

**Options:**

- `--model` (TEXT, required) — Path to ONNX model file (.onnx).
- `--threads` (INT:INT in [1 - 256], optional, default `4`) — Intra-op CPU thread count (default 4).
- `--provider` (TEXT:{cpu,cuda}, optional, default `cpu`) — Execution provider: cpu (default) or cuda (NVIDIA GPU via CUDA EP). Requires FEATURE_ONNX_CUDA=ON build, GPU ORT package in third_party/, and CUDA runtime installed.
- `--image` (TEXT:FILE, required) — Input image path.
- `--labels` (TEXT:FILE, optional) — Text file with one class label per line (e.g. ImageNet synset).
- `--top` (INT:INT in [1 - 10000], optional, default `5`) — Number of top predictions to return (default 5).

#### `onnx ocr`

Detect text regions in an image using PP-OCRv4-det (or compatible DB detector).

- Allows extra positional arguments.

**Options:**

- `--det-model` (TEXT:FILE, required) — Detection model path (PP-OCRv4 det ONNX).
- `--image` (TEXT:FILE, required) — Input image path.
- `--threads` (INT:INT in [1 - 256], optional, default `4`) — Intra-op CPU thread count (default 4).
- `--threshold` (FLOAT:FLOAT in [0 - 1], optional, default `0.3`) — Probability map threshold for text regions (default 0.3).
- `--max-size` (INT:INT in [32 - 4096], optional, default `960`) — Longest image edge after resize before detection (default 960).
- `--rec-model` (TEXT:FILE, optional) — Recognition model path (PP-OCRv4 rec ONNX). When provided, runs the full det+rec pipeline.
- `--dict` (TEXT:FILE, optional) — Character dictionary file (one char per line, e.g. en_dict.txt).
- `--rec-threshold` (FLOAT:FLOAT in [0 - 1], optional, default `0.5`) — Minimum recognition confidence to include a word (default 0.5).

#### `onnx detect`

YOLO-format UI-element/object detection (OmniParser icon_detect, YOLOv8, …).

- Allows extra positional arguments.

**Options:**

- `--model` (TEXT, required) — Path to ONNX model file (.onnx).
- `--threads` (INT:INT in [1 - 256], optional, default `4`) — Intra-op CPU thread count (default 4).
- `--provider` (TEXT:{cpu,cuda}, optional, default `cpu`) — Execution provider: cpu (default) or cuda (NVIDIA GPU via CUDA EP). Requires FEATURE_ONNX_CUDA=ON build, GPU ORT package in third_party/, and CUDA runtime installed.
- `--image` (TEXT:FILE, required) — Input image path.
- `--conf` (FLOAT:FLOAT in [0 - 1], optional, default `0.25`) — Minimum confidence threshold (default 0.25).
- `--nms` (FLOAT:FLOAT in [0 - 1], optional, default `0.45`) — NMS IoU overlap threshold (default 0.45).
- `--classes` (TEXT, optional) — Comma-separated class names (e.g. icon,text). Default: class_0, class_1, …. Overridden by --labels-yaml.
- `--labels-yaml` (TEXT:FILE, optional) — Path to YOLO data.yaml; reads the 'names:' block as class labels. Takes precedence over --classes.
- `--input-size` (INT:INT in [32 - 4096], optional, default `0`) — Force model input size in pixels (default: from model metadata).
- `--output-image` (TEXT, optional) — Write detection overlay (coloured boxes) to this image path. Format inferred from extension (.png, .jpg, …).

#### `onnx layout`

PP-DocLayoutV3 document layout analysis — detects regions (table, text, title, …) with bounding boxes and reading order.

- Allows extra positional arguments.

**Options:**

- `--model` (TEXT, optional) — Path to ONNX model file (.onnx). Empty = auto-discover where supported.
- `--threads` (INT:INT in [1 - 256], optional, default `4`) — Intra-op CPU thread count (default 4).
- `--provider` (TEXT:{cpu,cuda}, optional, default `cpu`) — Execution provider: cpu (default) or cuda (NVIDIA GPU via CUDA EP). Requires FEATURE_ONNX_CUDA=ON build, GPU ORT package in third_party/, and CUDA runtime installed.
- `--image` (TEXT, required) — Input image (JPEG, PNG, …).
- `--conf` (FLOAT:FLOAT in [0 - 1], optional, default `0.5`) — Minimum detection confidence (default 0.5).
- `--output-image` (TEXT, optional) — Write layout overlay (coloured region boxes) to this image.

#### `onnx train`

Fine-tune a YOLO model on a custom dataset and export to ONNX. Requires Python + ultralytics (`pip install ultralytics`). Trains with `model.train()` and exports via `model.export(format='onnx')`, then copies best.onnx to --output.

- Allows extra positional arguments.

**Options:**

- `--data` (TEXT:FILE, required) — Path to YOLO data.yaml (required).
- `--base-model` (TEXT, optional, default `yolov8n.pt`) — Starting checkpoint: any .pt or .yaml accepted by ultralytics (default: yolov8n.pt).
- `--output` (TEXT, optional, default `dist/models/trained.onnx`) — Destination path for the exported ONNX model (default: dist/models/trained.onnx).
- `--epochs` (INT:INT in [1 - 10000], optional, default `50`) — Number of training epochs (default 50).
- `--imgsz` (INT:INT in [32 - 4096], optional, default `640`) — Training image size in pixels (default 640).
- `--batch` (INT:INT in [-1 - 4096], optional, default `16`) — Batch size (-1 = auto-batch; default 16).
- `--python` (TEXT, optional) — Python interpreter path (default: auto-detect 'python' / 'python3').

### `hg`

Hugging Face GGUF models: list catalog, inspect metadata, probe quants, download one variant.

- Allows extra positional arguments.

**Subcommands:**

- `list` — List built-in GGUF catalog aliases.
- `org` — List models published by a Hugging Face organization or user.
- `variants` — List GGUF quantization variants for a catalog alias or repo id.
- `meta` — Fetch Hugging Face model card JSON for a catalog alias or repo id.
- `probe` — Resolve variant files and sizes without downloading.
- `sidecar` — Rebuild model.local.json sidecar from a downloaded variant directory.
- `download` — Download one GGUF variant with upstream filenames + tanit-manifest.json + model.local.json.

**Options:**

- `--token` (TEXT, optional) — HF API token (default: settings variable HF_TOKEN, else HF_TOKEN env).

#### `hg list`

List built-in GGUF catalog aliases.

- Allows extra positional arguments.

#### `hg org`

List models published by a Hugging Face organization or user.

- Allows extra positional arguments.

**Options:**

- `org` (TEXT, required, positional) — Org slug or URL (e.g. sentence-transformers or https://huggingface.co/sentence-transformers).
- `--limit` (INT:INT in [1 - 500], optional, default `100`) — Max models to return (default 100).

#### `hg variants`

List GGUF quantization variants for a catalog alias or repo id.

- Allows extra positional arguments.

**Options:**

- `model` (TEXT, required, positional) — Catalog alias, org/repo id, or HF model URL.

#### `hg meta`

Fetch Hugging Face model card JSON for a catalog alias or repo id.

- Allows extra positional arguments.

**Options:**

- `model` (TEXT, required, positional) — Catalog alias, org/repo id, or HF model URL.

#### `hg probe`

Resolve variant files and sizes without downloading.

- Allows extra positional arguments.

**Options:**

- `model` (TEXT, required, positional) — Catalog alias, org/repo id, or HF model URL.

#### `hg sidecar`

Rebuild model.local.json sidecar from a downloaded variant directory.

- Allows extra positional arguments.

**Options:**

- `path` (TEXT, required, positional) — Variant directory containing .gguf files.

#### `hg download`

Download one GGUF variant with upstream filenames + tanit-manifest.json + model.local.json.

- Allows extra positional arguments.

**Options:**

- `model` (TEXT, required, positional) — Catalog alias, org/repo id, or HF model URL.
- `--output` (TEXT, optional) — Output root (default: ${MODELS_DIR} / settings_store models).
- `--overwrite` (optional, flag) — Re-download even when files exist.
- `--remanifest-only` (optional, flag) — Rebuild tanit-manifest.json and model.local.json without downloading.
- `--quiet` (optional, flag) — Suppress stderr progress lines.

### `run-ipc`

Discover and control live pm-image instances over the command IPC bus.

- Allows extra positional arguments.

**Subcommands:**

- `list` — List pm-image IPC descriptors, including orphaned descriptors that fail liveness validation.
- `info` — Show composed details for an IPC descriptor, including child registries.
- `tree` — Render the IPC registry as a plain tree, or a navigable FTXUI tree with --interactive.
- `prune` — Remove orphaned run-ipc instance and agent descriptor JSON files.
- `ping` — Send a ping to a live instance and print the pong reply.
- `status` — Query the status (descriptor + process info) of a live instance.
- `run-ids` — List active command-runner run IDs on a live instance.
- `cancel` — Cancel a command-runner run on a live instance by its run ID.
- `send` — Send an arbitrary action frame to a live instance and print the reply.
- `host` — Spawn a bare IPC server host (registers in instances dir, serves until stopped). Primarily for testing and scripted orchestration.
- `agents` — List ongoing agents (regular + realtime) from the cross-process registry, with cwd, command line, model, session, and sampled memory/CPU. With no target, reads the shared registry directly; with a target, queries that instance.
- `app-cmds` — List app commands accepted by a live UI instance over `run-ipc app-cmd`.
- `app-cmd` — Send an app command to a live UI instance (e.g. replay, takescreenshot, togglequeue). Command names are matched case/separator-insensitively via app_commands.cpp registry.

**Options:**

- `--json` (optional, flag) — Output results as JSON (default: human-readable table).

#### `run-ipc list`

List pm-image IPC descriptors, including orphaned descriptors that fail liveness validation.

- Allows extra positional arguments.

**Options:**

- `--json` (optional, flag) — Output results as JSON.

#### `run-ipc info`

Show composed details for an IPC descriptor, including child registries.

- Allows extra positional arguments.

**Options:**

- `--json` (optional, flag) — Output the composed info envelope as JSON.
- `target` (TEXT, required, positional) — Instance id ("pid:<n>") or bare pid.

#### `run-ipc tree`

Render the IPC registry as a plain tree, or a navigable FTXUI tree with --interactive.

- Allows extra positional arguments.

**Options:**

- `--json` (optional, flag) — Output the tree source rows as JSON.
- `--interactive` (optional, flag) — Open the navigable FTXUI tree view (requires an interactive terminal).

#### `run-ipc prune`

Remove orphaned run-ipc instance and agent descriptor JSON files.

- Allows extra positional arguments.

**Options:**

- `--json` (optional, flag) — Output prune results as JSON.

#### `run-ipc ping`

Send a ping to a live instance and print the pong reply.

- Allows extra positional arguments.

**Options:**

- `--json` (optional, flag) — Output the raw reply as JSON.
- `target` (TEXT, required, positional) — Instance id ("pid:<n>") or bare pid.

#### `run-ipc status`

Query the status (descriptor + process info) of a live instance.

- Allows extra positional arguments.

**Options:**

- `--json` (optional, flag) — Output the raw reply as JSON.
- `target` (TEXT, required, positional) — Instance id or bare pid.

#### `run-ipc run-ids`

List active command-runner run IDs on a live instance.

- Allows extra positional arguments.

**Options:**

- `--json` (optional, flag) — Output the raw reply as JSON.
- `target` (TEXT, required, positional) — Instance id or bare pid.

#### `run-ipc cancel`

Cancel a command-runner run on a live instance by its run ID.

- Allows extra positional arguments.

**Options:**

- `--json` (optional, flag) — Output the raw reply as JSON.
- `target` (TEXT, required, positional) — Instance id or bare pid.
- `run_id` (UINT, required, positional) — Numeric run ID to cancel (from run-ids).

#### `run-ipc send`

Send an arbitrary action frame to a live instance and print the reply.

- Allows extra positional arguments.

**Options:**

- `target` (TEXT, required, positional) — Instance id or bare pid.
- `action` (TEXT, required, positional) — Action name (e.g. ping, status, run_ids, cancel, app_cmd, stop, …).
- `--json` (TEXT, optional) — Extra JSON object to merge into the request (e.g. '{"run_id":42}').
- `--timeout-ms` (INT, optional, default `3000`) — Socket timeout in milliseconds (default: 3000).

#### `run-ipc host`

Spawn a bare IPC server host (registers in instances dir, serves until stopped). Primarily for testing and scripted orchestration.

- Allows extra positional arguments.

**Options:**

- `--json` (optional, flag) — Output the host descriptor as JSON.
- `--cwd` (TEXT, optional) — Working directory to advertise (default: current directory).
- `--register-agent` (optional, flag) — Also publish a live entry in the agent registry (test fixture for `run-ipc agents`).

#### `run-ipc agents`

List ongoing agents (regular + realtime) from the cross-process registry, with cwd, command line, model, session, and sampled memory/CPU. With no target, reads the shared registry directly; with a target, queries that instance.

- Allows extra positional arguments.

**Options:**

- `--json` (optional, flag) — Output results as JSON.
- `target` (TEXT, optional, positional) — Optional instance id or bare pid to query over the bus (default: local registry).

#### `run-ipc app-cmds`

List app commands accepted by a live UI instance over `run-ipc app-cmd`.

- Allows extra positional arguments.

**Options:**

- `--json` (optional, flag) — Output the raw reply as JSON.
- `target` (TEXT, required, positional) — Instance id or bare pid.
- `--timeout-ms` (INT, optional, default `3000`) — Socket timeout in milliseconds (default: 3000).

#### `run-ipc app-cmd`

Send an app command to a live UI instance (e.g. replay, takescreenshot, togglequeue). Command names are matched case/separator-insensitively via app_commands.cpp registry.

- Allows extra positional arguments.

**Options:**

- `target` (TEXT, required, positional) — Instance id or bare pid.
- `command` (TEXT, required, positional) — App command name (e.g. replay, takescreenshot, browse, togglequeue, …).
- `--json` (TEXT, optional) — Extra JSON args for the command (e.g. '{"path":"session.json"}' for replay).
- `--timeout-ms` (INT, optional, default `3000`) — Socket timeout in milliseconds (default: 3000).

### `media`

Experimental media type tools: probe files and inspect libmagic MIME/extension metadata.

- Allows extra positional arguments.

**Subcommands:**

- `probe` — Probe file MIME type, likely extensions, and Tanit media kind.
- `types` — List MIME types and extensions from file(1) Magdir annotations; supports wildcards like application/*.
- `search` — Search raw file(1) Magdir source lines with wildcards; useful when a type has no !:ext annotation.

#### `media probe`

Probe file MIME type, likely extensions, and Tanit media kind.

- Allows extra positional arguments.

**Options:**

- `path` (TEXT, required, positional) — File path(s) to probe
- `--magic-db` (TEXT, optional) — Explicit magic.mgc database path.
- `--json` (optional, flag) — Print JSON.

#### `media types`

List MIME types and extensions from file(1) Magdir annotations; supports wildcards like application/*.

- Allows extra positional arguments.

**Options:**

- `pattern` (TEXT, optional, default `*`, positional) — MIME/kind/extension wildcard pattern.
- `--kind` (TEXT, optional) — Filter by kind: image, video, document, code, script, binary, ...
- `--ext` (TEXT, optional) — Filter by extension, e.g. .pdf or jpg.
- `--source-dir` (TEXT, optional) — Explicit packages/file/magic/Magdir directory.
- `--json` (optional, flag) — Print JSON.

#### `media search`

Search raw file(1) Magdir source lines with wildcards; useful when a type has no !:ext annotation.

- Allows extra positional arguments.

**Options:**

- `pattern` (TEXT, required, positional) — Wildcard pattern to match against source lines or filenames.
- `--source-dir` (TEXT, optional) — Explicit packages/file/magic/Magdir directory.
- `--json` (optional, flag) — Print JSON.

### `mcp`

MCP utilities: run a foreground agent-tool server, or inspect/call external MCP servers.

- Allows extra positional arguments.

**Subcommands:**

- `client` — Inspect and call external MCP servers configured in mcp.json.

**Options:**

- `--preset` (TEXT, optional) — Chat settings preset name or id. If omitted, uses preset `Default`, or the lone saved preset.
- `--bind` (TEXT, optional, default `0.0.0.0`) — Interface/address for MCP HTTP. Default: 0.0.0.0 on Windows, 127.0.0.1 elsewhere.
- `--port` (INT:INT in [1 - 65535], optional, default `4444`) — First TCP port to try for MCP HTTP (default 4444; next free port if busy)
- `--disable-tools` (TEXT, optional) — Comma- or semicolon-separated enabled tools to omit. Built-ins: list_images, file_glob, file_read, file_search, image_resize, image_transform, image_create, create_video, image_understand, image_from_camera, ocr_text, write_file, speak, audio_transcribe, ask_user, schedule_at, schedule_in, schedule_every, schedule_cancel, schedule_list, memory_read, memory_write, memory_append_event, run, run_sequence, info_lookup, service_page_create, service_page_update, service_page_list, service_page_get, service_files_list, service_files_get, service_files_upload, service_search, create_command, app_inspect_dump, app_inspect_find, app_screenshot, app_click, app_drag, app_open, app_type, app_hotkey, app_close, app_batch. MCP tools use mcp_<server>__<tool>; run `llm agent --help` for a live list. Ineffective with --no-tools
- `--json` (optional, flag) — JSON output (server descriptor, or mcp client subcommand result).

#### `mcp client`

Inspect and call external MCP servers configured in mcp.json.

- Allows extra positional arguments.

**Subcommands:**

- `list` — List MCP server names, transport, and enabled state from mcp.json.
- `tools` — List tools on an MCP server (name and description).
- `schema` — Show a tool's inputSchema from tools/list.
- `call` — Call a tool on an MCP server (fresh session per invocation).

**Options:**

- `--no-probe` (optional, flag) — Use cached tools/list only; skip live MCP handshakes.
- `--probe` (optional, flag) — Allow live MCP handshakes when cache is missing or stale (default).

#### `mcp client list`

List MCP server names, transport, and enabled state from mcp.json.

- Allows extra positional arguments.

#### `mcp client tools`

List tools on an MCP server (name and description).

- Allows extra positional arguments.

**Options:**

- `--server` (TEXT, required) — MCP server name from mcp.json.

#### `mcp client schema`

Show a tool's inputSchema from tools/list.

- Allows extra positional arguments.

**Options:**

- `--server` (TEXT, required) — MCP server name from mcp.json.
- `--tool` (TEXT, required) — Remote tool name.

#### `mcp client call`

Call a tool on an MCP server (fresh session per invocation).

- Allows extra positional arguments.

**Options:**

- `--server` (TEXT, required) — MCP server name from mcp.json.
- `--tool` (TEXT, required) — Remote tool name.
- `--args` (TEXT, optional, default `{}`) — JSON object of tool arguments.
- `--timeout-ms` (INT, optional, default `0`) — MCP request timeout in milliseconds.

---

## XBlox composition metadata

Use `tanit-cli xblox info --json` for machine-readable block definitions, grouped palette metadata, default block JSON, param schemas, registered CLI commands, and custom command payloads.

### AI

#### `agent` — Agent

Run an LLM agent turn in-process (tool loop included) and store the answer in PREVIOUS.

Params:
- `prompt` (value, required)
- `systemPrompt` (value, default `""`)
- `system` (value, default `""`)
- `plannerPrompt` (value, default `""`)
- `include` (value, default `[]`)
- `embed` (value, default `[]`)
- `preset` (value, default `""`)
- `model` (value, default `""`)
- `router` (value, default `""`)
- `type` (value, default `"completion"`)
- `streaming` (value, default `"auto"`)
- `apiKey` (value, default `""`)
- `baseUrl` (value, default `""`)
- `tools` (value, default `true`)
- `mcp` (value, default `true`)
- `skills` (value, default `true`)
- `planner` (value, default `true`)
- `plannerBudget` (value, default `0`)
- `disableTools` (value, default `[]`)
- `enableTools` (value, default `[]`)
- `parallelTools` (value, default `true`)
- `maxSteps` (value, default `0`)
- `timeoutMs` (value, default `0`)
- `aiConsentReview` (value, default `false`)
- `aiConsentRouter` (value, default `""`)
- `aiConsentModel` (value, default `""`)
- `ocrProvider` (value, default `""`)
- `ocrModel` (value, default `""`)
- `recognitionProvider` (value, default `""`)
- `recognitionModel` (value, default `""`)
- `imageProvider` (value, default `""`)
- `imageModel` (value, default `""`)
- `videoProvider` (value, default `""`)
- `videoModel` (value, default `""`)
- `sttProvider` (value, default `""`)
- `sttModel` (value, default `""`)
- `ttsProvider` (value, default `""`)
- `ttsModel` (value, default `""`)
- `ttsVoiceId` (value, default `""`)
- `cwd` (value, default `""`)
- `streamLog` (value, default `false`)
- `json` (value, default `false`)
- `contextReduction` (value, default `"off"`)
- `contextReductionRatio` (value, default `0.5`)
- `contextReductionMinBytes` (value, default `2048`)
- `contextReductionObjective` (value, default `""`)
- `usage` (value)
- `transcript` (value)
- `storeAs` (value, default `"answer"`)

Default block: `{"embed":[],"include":[],"kind":"agent","prompt":"","storeAs":"answer","tools":true}`

#### `llm` — LLM

Run an LLM agent turn in-process (tool loop included) and store the answer in PREVIOUS.

Params:
- `prompt` (value, required)
- `systemPrompt` (value, default `""`)
- `system` (value, default `""`)
- `plannerPrompt` (value, default `""`)
- `include` (value, default `[]`)
- `embed` (value, default `[]`)
- `preset` (value, default `""`)
- `model` (value, default `""`)
- `router` (value, default `""`)
- `type` (value, default `"completion"`)
- `streaming` (value, default `"auto"`)
- `apiKey` (value, default `""`)
- `baseUrl` (value, default `""`)
- `tools` (value, default `true`)
- `mcp` (value, default `true`)
- `skills` (value, default `true`)
- `planner` (value, default `true`)
- `plannerBudget` (value, default `0`)
- `disableTools` (value, default `[]`)
- `enableTools` (value, default `[]`)
- `parallelTools` (value, default `true`)
- `maxSteps` (value, default `0`)
- `timeoutMs` (value, default `0`)
- `aiConsentReview` (value, default `false`)
- `aiConsentRouter` (value, default `""`)
- `aiConsentModel` (value, default `""`)
- `ocrProvider` (value, default `""`)
- `ocrModel` (value, default `""`)
- `recognitionProvider` (value, default `""`)
- `recognitionModel` (value, default `""`)
- `imageProvider` (value, default `""`)
- `imageModel` (value, default `""`)
- `videoProvider` (value, default `""`)
- `videoModel` (value, default `""`)
- `sttProvider` (value, default `""`)
- `sttModel` (value, default `""`)
- `ttsProvider` (value, default `""`)
- `ttsModel` (value, default `""`)
- `ttsVoiceId` (value, default `""`)
- `cwd` (value, default `""`)
- `streamLog` (value, default `false`)
- `json` (value, default `false`)
- `contextReduction` (value, default `"off"`)
- `contextReductionRatio` (value, default `0.5`)
- `contextReductionMinBytes` (value, default `2048`)
- `contextReductionObjective` (value, default `""`)
- `usage` (value)
- `transcript` (value)
- `storeAs` (value, default `"answer"`)

Default block: `{"embed":[],"include":[],"kind":"llm","prompt":"","storeAs":"answer","tools":true}`

#### `llmAgent` — LLM Agent

Run an LLM agent turn in-process (tool loop included) and store the answer in PREVIOUS.

Params:
- `prompt` (value, required)
- `systemPrompt` (value, default `""`)
- `system` (value, default `""`)
- `plannerPrompt` (value, default `""`)
- `include` (value, default `[]`)
- `embed` (value, default `[]`)
- `preset` (value, default `""`)
- `model` (value, default `""`)
- `router` (value, default `""`)
- `type` (value, default `"completion"`)
- `streaming` (value, default `"auto"`)
- `apiKey` (value, default `""`)
- `baseUrl` (value, default `""`)
- `tools` (value, default `true`)
- `mcp` (value, default `true`)
- `skills` (value, default `true`)
- `planner` (value, default `true`)
- `plannerBudget` (value, default `0`)
- `disableTools` (value, default `[]`)
- `enableTools` (value, default `[]`)
- `parallelTools` (value, default `true`)
- `maxSteps` (value, default `0`)
- `timeoutMs` (value, default `0`)
- `aiConsentReview` (value, default `false`)
- `aiConsentRouter` (value, default `""`)
- `aiConsentModel` (value, default `""`)
- `ocrProvider` (value, default `""`)
- `ocrModel` (value, default `""`)
- `recognitionProvider` (value, default `""`)
- `recognitionModel` (value, default `""`)
- `imageProvider` (value, default `""`)
- `imageModel` (value, default `""`)
- `videoProvider` (value, default `""`)
- `videoModel` (value, default `""`)
- `sttProvider` (value, default `""`)
- `sttModel` (value, default `""`)
- `ttsProvider` (value, default `""`)
- `ttsModel` (value, default `""`)
- `ttsVoiceId` (value, default `""`)
- `cwd` (value, default `""`)
- `streamLog` (value, default `false`)
- `json` (value, default `false`)
- `contextReduction` (value, default `"off"`)
- `contextReductionRatio` (value, default `0.5`)
- `contextReductionMinBytes` (value, default `2048`)
- `contextReductionObjective` (value, default `""`)
- `usage` (value)
- `transcript` (value)
- `storeAs` (value, default `"answer"`)

Default block: `{"embed":[],"include":[],"kind":"llmAgent","prompt":"","storeAs":"answer","tools":true}`

#### `modelControl` — Model Control

List or unload loaded local model instances for this xBlox process.

Params:
- `action` (value, default `"List"`)
- `key` (value, default `""`)
- `storeAs` (value, default `"models"`)

Default block: `{"action":"List","key":"","kind":"modelControl","storeAs":"models"}`

### App

#### `appActivate` — App Activate

Bring a target window to the foreground.

Params:
- `title` (value, default `""`)
- `process` (value, default `""`)
- `pid` (value)
- `hwnd` (value)
- `foreground` (value, default `false`)
- `storeAs` (value, default `""`)

Default block: `{"kind":"appActivate","title":"Notepad"}`

#### `appBatch` — App Batch

Run a sequence of app_batch actions in one block.

Params:
- `steps` (value, required)
- `defaultDelayMs` (value, default `50`)
- `defaultWaitTimeoutMs` (value, default `5000`)
- `defaultWaitIntervalMs` (value, default `100`)
- `continueOnError` (value, default `false`)
- `storeAs` (value, default `""`)

Default block: `{"defaultDelayMs":50,"kind":"appBatch","steps":[{"action":"activate","title":"Notepad"},{"action":"type","text":"Hello"}]}`

#### `appClick` — App Click

Click at (x,y) or (xw,yw) on a target window.

Params:
- `title` (value, default `""`)
- `process` (value, default `""`)
- `x` (value)
- `y` (value)
- `xw` (value)
- `yw` (value)
- `button` (value, default `"left"`)
- `count` (value, default `1`)
- `virtual` (value, default `false`)
- `storeAs` (value, default `""`)

Default block: `{"button":"left","count":1,"kind":"appClick","title":"Notepad","xw":100,"yw":100}`

#### `appClose` — App Close

Send WM_CLOSE (or TerminateProcess with force=true).

Params:
- `title` (value, default `""`)
- `process` (value, default `""`)
- `pid` (value)
- `hwnd` (value)
- `foreground` (value, default `false`)
- `force` (value, default `false`)
- `storeAs` (value, default `""`)

Default block: `{"force":false,"kind":"appClose","title":"Notepad"}`

#### `appDrag` — App Drag

Drag linear / polyline / arc with smooth pacing.

Params:
- `title` (value, default `""`)
- `process` (value, default `""`)
- `x` (value)
- `y` (value)
- `xw` (value)
- `yw` (value)
- `toX` (value)
- `toY` (value)
- `toXw` (value)
- `toYw` (value)
- `dx` (value)
- `dy` (value)
- `path` (value)
- `arc` (value)
- `button` (value, default `"left"`)
- `durationMs` (value, default `250`)
- `storeAs` (value, default `""`)

Default block: `{"durationMs":250,"kind":"appDrag","title":"Notepad","toXw":300,"toYw":200,"xw":100,"yw":100}`

#### `appHotkey` — App Hotkey

Send a key combination (e.g. ctrl+shift+t).

Params:
- `keys` (value, required, default `"ctrl+s"`)
- `title` (value, default `""`)
- `process` (value, default `""`)
- `foreground` (value, default `false`)
- `storeAs` (value, default `""`)

Default block: `{"keys":"ctrl+s","kind":"appHotkey","title":"Notepad"}`

#### `appInspectDump` — App Inspect Dump

Dump UI Automation tree of matching windows.

Params:
- `input` (value, default `""`)
- `title` (value, default `""`)
- `process` (value, default `""`)
- `foreground` (value, default `false`)
- `format` (value, default `"md"`)
- `limit` (value, default `0`)
- `filterToSelection` (value, default `false`)
- `controls` (value, default `"all"`)
- `textMaxChars` (value, default `1200`)
- `probeCells` (value, default `false`)
- `storeAs` (value, default `""`)

Default block: `{"format":"md","input":"","kind":"appInspectDump","title":"Notepad"}`

#### `appInspectFind` — App Inspect Find

Filter UIA elements by name/value/automationId/className.

Params:
- `title` (value, default `""`)
- `process` (value, default `""`)
- `foreground` (value, default `false`)
- `name` (value, default `""`)
- `value` (value, default `""`)
- `automationId` (value, default `""`)
- `className` (value, default `""`)
- `nth` (value, default `-1`)
- `storeAs` (value, default `""`)

Default block: `{"kind":"appInspectFind","name":"File","title":"Notepad"}`

#### `appKey` — App Key

Press one key with optional modifiers and hold duration.

Params:
- `key` (value, required, default `"a"`)
- `modifiers` (value)
- `holdMs` (value, default `0`)
- `title` (value, default `""`)
- `process` (value, default `""`)
- `foreground` (value, default `false`)
- `storeAs` (value, default `""`)

Default block: `{"holdMs":100,"key":"a","kind":"appKey"}`

#### `appMouseMove` — App Mouse Move

Smoothly move the cursor (auto-paced) or teleport.

Params:
- `title` (value, default `""`)
- `process` (value, default `""`)
- `x` (value)
- `y` (value)
- `xw` (value)
- `yw` (value)
- `smooth` (value, default `true`)
- `durationMs` (value, default `-1`)
- `storeAs` (value, default `""`)

Default block: `{"kind":"appMouseMove","smooth":true,"title":"Notepad","xw":200,"yw":200}`

#### `appOpen` — App Open

Launch an executable and (optionally) wait for its window.

Params:
- `exe` (value, required, default `"notepad.exe"`)
- `args` (value, default `""`)
- `cwd` (value, default `""`)
- `x` (value)
- `y` (value)
- `width` (value)
- `height` (value)
- `waitMs` (value, default `3000`)
- `storeAs` (value, default `""`)

Default block: `{"exe":"notepad.exe","kind":"appOpen","waitMs":3000}`

#### `appScreenshot` — App Screenshot

Capture a window / element / explicit rect to a JPEG file.

Params:
- `outputPath` (value, required, default `"out/shot.jpg"`)
- `title` (value, default `""`)
- `process` (value, default `""`)
- `foreground` (value, default `false`)
- `rect` (value, default `""`)
- `elementIndex` (value)
- `quality` (value, default `85`)
- `activate` (value, default `true`)
- `storeAs` (value, default `""`)

Default block: `{"kind":"appScreenshot","outputPath":"out/shot.jpg","quality":85,"title":"Notepad"}`

#### `appScroll` — App Scroll

Wheel scroll (vertical or horizontal) at an optional point.

Params:
- `title` (value, default `""`)
- `process` (value, default `""`)
- `clicks` (value, required, default `-3`)
- `axis` (value, default `"vertical"`)
- `x` (value)
- `y` (value)
- `xw` (value)
- `yw` (value)
- `storeAs` (value, default `""`)

Default block: `{"clicks":-3,"kind":"appScroll","title":"Notepad"}`

#### `appType` — App Type

Type a string into the activated window.

Params:
- `text` (value, required, default `"Hello"`)
- `title` (value, default `""`)
- `process` (value, default `""`)
- `foreground` (value, default `false`)
- `storeAs` (value, default `""`)

Default block: `{"kind":"appType","text":"Hello","title":"Notepad"}`

#### `clipboardCopy` — Clipboard Copy

Send Ctrl+C to the focused or targeted element, then return the clipboard content (text or file paths). No target selector = operates on the currently focused element.

Params:
- `title` (value, default `""`)
- `process` (value, default `""`)
- `pid` (value)
- `hwnd` (value)
- `foreground` (value, default `false`)
- `type` (value, default `"text"`)
- `trigger` (value, default `true`)
- `delayMs` (value, default `80`)
- `storeAs` (value, default `""`)

Default block: `{"delayMs":80,"kind":"clipboardCopy","trigger":true,"type":"text"}`

#### `clipboardPaste` — Clipboard Paste

Write text or file paths to the clipboard, then send Ctrl+V to the focused or targeted element. No target selector = operates on the currently focused element.

Params:
- `title` (value, default `""`)
- `process` (value, default `""`)
- `pid` (value)
- `hwnd` (value)
- `foreground` (value, default `false`)
- `type` (value, default `"text"`)
- `text` (value, default `""`)
- `files` (value, default `[]`)
- `trigger` (value, default `true`)
- `storeAs` (value, default `""`)

Default block: `{"files":[],"kind":"clipboardPaste","text":"","trigger":true,"type":"text"}`

#### `picker` — Picker

Interactive window / element picker with live highlight overlay (Spy++ style). Click any window or web element to commit; press ESC to cancel. Stores a screen spec string (e.g. 'screen:0:hwnd=...:wintitle=Chrome*:rrect=x,y,w,h') in PREVIOUS / storeAs — wire directly into imageScreenshot, videoDetect, etc.

Params:
- `highlight` (value, default `true`)
- `resolveUia` (value, default `true`)
- `showHidden` (value, default `true`)
- `timeoutMs` (value, default `60000`)
- `storeAs` (value, default `""`)

Default block: `{"highlight":true,"kind":"picker","resolveUia":true,"showHidden":true,"timeoutMs":60000}`

### Audio

#### `audioListDevices` — List Audio Devices

List microphone and desktop/loopback capture devices.

Params:
- `storeAs` (value, default `"audioDevices"`)

Default block: `{"kind":"audioListDevices","storeAs":"audioDevices"}`

#### `audioModelControl` — Unload Model

List or unload loaded local model instances for this xBlox process.

Params:
- `action` (value, default `"List"`)
- `key` (value, default `"vibevoice:tts"`)
- `storeAs` (value, default `"modelKey"`)

Default block: `{"action":"Unload","key":"vibevoice:tts","kind":"audioModelControl","storeAs":"modelKey"}`

#### `audioPlay` — Play Audio

Play an audio file (MP3, WAV, or FLAC). Uses PREVIOUS as the file path when path is empty.

Params:
- `path` (value, default `""`)
- `outputDevice` (value, default `""`)
- `storeAs` (value, default `""`)

Default block: `{"kind":"audioPlay","outputDevice":"","path":"","storeAs":""}`

#### `audioRecord` — Record Audio

Record mic, desktop, or mixed audio to a WAV file. Stores the output path in PREVIOUS / storeAs.

Params:
- `inputSource` (value, default `"mic"`)
- `device` (value, default `""`)
- `desktopDevice` (value, default `""`)
- `micGain` (value, default `1`)
- `desktopGain` (value, default `1`)
- `durationMs` (value, required, default `3000`)
- `outputPath` (value, default `""`)
- `storeAs` (value, default `"audioPath"`)

Default block: `{"desktopDevice":"","desktopGain":1,"device":"","durationMs":3000,"inputSource":"mic","kind":"audioRecord","micGain":1,"outputPath":"","storeAs":"audioPath"}`

#### `audioRecordStart` — Start Recording

Start a mic/desktop/mix recording session and store its session id.

Params:
- `inputSource` (value, default `"mic"`)
- `device` (value, default `""`)
- `desktopDevice` (value, default `""`)
- `micGain` (value, default `1`)
- `desktopGain` (value, default `1`)
- `session` (value, default `""`)
- `storeAs` (value, default `"recordSession"`)

Default block: `{"desktopDevice":"","desktopGain":1,"device":"","inputSource":"mic","kind":"audioRecordStart","micGain":1,"session":"","storeAs":"recordSession"}`

#### `audioRecordStop` — Stop Recording

Stop a microphone recording session and write it to a WAV file.

Params:
- `session` (value, required, default `""`)
- `outputPath` (value, default `""`)
- `storeAs` (value, default `"audioPath"`)

Default block: `{"kind":"audioRecordStop","outputPath":"","session":"","storeAs":"audioPath"}`

#### `audioSpeak` — Text to Speech

Convert text to speech via the configured TTS provider and play it through the speakers. Supports Tanit, ElevenLabs, and local VibeVoice builds. Uses PREVIOUS string as text when text is empty. Markdown/plain-text pre-parsers run on file paths and on inline/PREVIOUS content (e.g. fsRead → audioSpeak). Stores output file path in PREVIOUS / storeAs when outputPath is set, otherwise stores the input text.

Params:
- `text` (value, default `""`)
- `provider` (value, default `""`)
- `model` (value, default `""`)
- `voice` (value, default `""`)
- `tokenizer` (value, default `""`)
- `refAudio` (value, default `""`)
- `instance` (value, default `""`)
- `outputDevice` (value, default `""`)
- `outputPath` (value, default `""`)
- `sendVoiceSettings` (value, default `true`)
- `chunkSentences` (value, default `true`)
- `chunkTargetChars` (value, default `400`)
- `chunkMaxChars` (value, default `800`)
- `stability` (value, default `0.9`)
- `similarityBoost` (value, default `0.75`)
- `style` (value, default `0`)
- `storeAs` (value, default `""`)

Default block: `{"chunkMaxChars":800,"chunkSentences":true,"chunkTargetChars":400,"instance":"","kind":"audioSpeak","model":"","outputDevice":"","outputPath":"","provider":"","refAudio":"","sendVoiceSettings":true,"similarityBoost":0.75,"stability":0.9,"storeAs":"","style":0,"text":"","tokenizer":"","voice":""}`

#### `audioTranscribe` — Speech to Text

Transcribe an audio file, or record from the microphone and transcribe speech to text. When 'input' is set, the file is transcribed directly (no microphone, no duration limit). When empty, records from the microphone for up to maxDurationMs ms with optional VAD silence-gate. Prefers local Whisper when selected/available, with Tanit as a provider-backed fallback. Stores the transcript string in PREVIOUS / storeAs, or a structured STT payload when json is on.

Params:
- `input` (value, default `""`)
- `maxDurationMs` (value, default `30000`)
- `silenceMs` (value, default `1500`)
- `device` (value, default `""`)
- `provider` (value, default `""`)
- `model` (value, default `""`)
- `apiKey` (value, default `""`)
- `providerOptions` (value, default `{}`)
- `json` (value, default `false`)
- `result` (value)
- `outputPath` (value, default `""`)
- `storeAs` (value, default `"transcript"`)

Default block: `{"device":"","input":"","json":false,"kind":"audioTranscribe","maxDurationMs":30000,"model":"","outputPath":"","provider":"","providerOptions":{},"silenceMs":1500,"storeAs":"transcript"}`

### Bluetooth

#### `bluetoothConnect` — Bluetooth Connect

Connect a Bluetooth audio device (pairs if needed) and implicitly route audio to it. Uses PREVIOUS as the device id/name when 'id' is empty. Stores {ok,target,routed_to} in PREVIOUS / storeAs.

Params:
- `id` (value, default `""`)
- `autoRoute` (value, default `true`)
- `timeoutMs` (value, default `6000`)
- `delayMs` (value, default `0`)
- `storeAs` (value, default `"bluetooth"`)

Default block: `{"autoRoute":true,"delayMs":0,"id":"","kind":"bluetoothConnect","storeAs":"bluetooth","timeoutMs":6000}`

#### `bluetoothDisconnect` — Bluetooth Disconnect

Disconnect a Bluetooth audio device (best-effort). Uses PREVIOUS when 'id' is empty.

Params:
- `id` (value, default `""`)
- `storeAs` (value, default `"bluetooth"`)

Default block: `{"id":"","kind":"bluetoothDisconnect","storeAs":"bluetooth"}`

#### `bluetoothEndpoints` — Audio Endpoints

List MMDevice audio endpoints (playback by default). Stores an array of {id,name,default,is_bluetooth,state,active,...} in PREVIOUS / storeAs. Set includeDisconnected to also list Bluetooth devices that are paired but not yet connected.

Params:
- `capture` (value, default `false`)
- `includeDisconnected` (value, default `false`)
- `storeAs` (value, default `"audioEndpoints"`)

Default block: `{"capture":false,"includeDisconnected":false,"kind":"bluetoothEndpoints","storeAs":"audioEndpoints"}`

#### `bluetoothListDevices` — Bluetooth Devices

List paired / connected Bluetooth devices. Stores an array of {id,name,address,paired,connected,is_audio_device,...} in PREVIOUS / storeAs. Set autoRoute to implicitly switch the default playback endpoint to a connected audio device.

Params:
- `nearby` (value, default `false`)
- `autoRoute` (value, default `false`)
- `storeAs` (value, default `"bluetoothDevices"`)

Default block: `{"autoRoute":false,"kind":"bluetoothListDevices","nearby":false,"storeAs":"bluetoothDevices"}`

#### `bluetoothPair` — Bluetooth Pair

Pair a Bluetooth device (just-works / SSP). Uses PREVIOUS when 'id' is empty.

Params:
- `id` (value, default `""`)
- `storeAs` (value, default `"bluetooth"`)

Default block: `{"id":"","kind":"bluetoothPair","storeAs":"bluetooth"}`

#### `bluetoothSetDefault` — Set Default Endpoint

Set an MMDevice audio endpoint as the default device for all roles. Pass the endpoint id from bluetoothEndpoints (or PREVIOUS).

Params:
- `id` (value, default `""`)
- `storeAs` (value, default `"bluetooth"`)

Default block: `{"id":"","kind":"bluetoothSetDefault","storeAs":"bluetooth"}`

#### `bluetoothUnpair` — Bluetooth Unpair

Remove (unpair) a Bluetooth device. Uses PREVIOUS when 'id' is empty.

Params:
- `id` (value, default `""`)
- `storeAs` (value, default `"bluetooth"`)

Default block: `{"id":"","kind":"bluetoothUnpair","storeAs":"bluetooth"}`

### Commands

#### `command` — Command

Run a custom command payload.

Params:
- `command` (value)

Default block: `{"command":{},"kind":"command"}`

### Context

#### `getVariable` — Get Variable

Read a value from root scope.

Params:
- `name` (value, required)
- `target` (value, default `"PREVIOUS"`)

Default block: `{"kind":"getVariable","name":"","target":"PREVIOUS"}`

#### `log` — Log

Log a message, expression, variable, or the whole scope.

Params:
- `level` (value, default `"info"`)
- `message` (value, default `"PREVIOUS"`)
- `input` (value, default `"PREVIOUS"`)
- `filter` (value, default `"."`)
- `format` (value, default `"auto"`)

Default block: `{"kind":"log","level":"info","message":"PREVIOUS"}`

#### `saveState` — Save State

Persist current scope values back into this XBlox document's context.

Params:
- `scope` (value, default `"context"`)
- `mode` (value, default `"existing"`)
- `keys` (value, default `[]`)

Default block: `{"keys":[],"kind":"saveState","mode":"existing","scope":"context"}`

#### `setVariable` — Set Variable

Write a value into root scope.

Params:
- `name` (value, required)
- `value` (value)
- `expression` (value)

Default block: `{"kind":"setVariable","name":"value","value":null}`

#### `stdin` — Stdin

Read piped input from stdin (whole stream or one line) into PREVIOUS/storeAs.

Params:
- `mode` (value, default `"all"`)
- `parse` (value, default `"text"`)
- `trim` (value, default `true`)
- `storeAs` (value, default `""`)

Default block: `{"kind":"stdin","mode":"all","parse":"text","trim":true}`

#### `stdout` — Stdout

Write a message directly to stdout (pipe-friendly).

Params:
- `message` (value, default `"PREVIOUS"`)
- `input` (value, default `"PREVIOUS"`)
- `filter` (value, default `"."`)
- `format` (value, default `"auto"`)
- `newline` (value, default `true`)

Default block: `{"kind":"stdout","message":"PREVIOUS","newline":true}`

### Data

#### `iterator` — Iterator

Iterate over PREVIOUS or any named scope/context variable. Arrays fan out directly, objects become {key,value} entries, scalars run once.

Params:
- `parser` (value, default `"jq"`)
- `filter` (value, required, default `"."`)
- `input` (value, default `"PREVIOUS"`)
- `mode` (value, default `"auto"`)
- `storeAs` (value, default `"items"`)

Default block: `{"filter":".","input":"PREVIOUS","items":[],"kind":"iterator","mode":"auto","parser":"jq","storeAs":"items"}`

#### `parse` — Parse

Parse PREVIOUS or named input with a jq filter expression.

Params:
- `parser` (value, default `"jq"`)
- `filter` (value, required, default `"."`)
- `input` (value, default `"PREVIOUS"`)
- `storeAs` (value, default `"parsed"`)

Default block: `{"filter":".","kind":"parse","parser":"jq","storeAs":"parsed"}`

#### `Parse` — Parse JSON

Parse PREVIOUS or named input with a jq filter expression.

Params:
- `parser` (value, default `"jq"`)
- `filter` (value, required, default `"."`)
- `input` (value, default `"PREVIOUS"`)
- `storeAs` (value, default `"parsed"`)

Default block: `{"filter":".","kind":"Parse","parser":"jq","storeAs":"parsed"}`

### Files

#### `fsDelete` — Delete Path

Delete a file or directory. Returns true if something was deleted.

Params:
- `path` (value, required)
- `recursive` (value, default `false`)
- `storeAs` (value, default `""`)

Default block: `{"kind":"fsDelete","path":"","recursive":false,"storeAs":""}`

#### `fsExists` — Path Exists

Check whether a path exists. Stores a boolean in PREVIOUS / storeAs.

Params:
- `path` (value, required)
- `storeAs` (value, default `"exists"`)

Default block: `{"kind":"fsExists","path":"","storeAs":"exists"}`

#### `fsHash` — Hash File

Compute a file content hash. Stores the hex digest in PREVIOUS / storeAs.

Params:
- `path` (value, required)
- `algorithm` (value, default `"sha256"`)
- `prefixLength` (value, default `0`)
- `storeAs` (value, default `"hash"`)

Default block: `{"algorithm":"sha256","kind":"fsHash","path":"","prefixLength":0,"storeAs":"hash"}`

#### `fsList` — List Files

List a directory or glob. Stores an array of {name, path, type, size} in PREVIOUS / storeAs.

Params:
- `path` (value, required)
- `only` (value, default `"all"`)
- `storeAs` (value, default `"entries"`)

Default block: `{"kind":"fsList","only":"all","path":"","storeAs":"entries"}`

#### `fsMkdir` — Create Folder

Create a directory (and all parents). Stores the created path in PREVIOUS / storeAs.

Params:
- `path` (value, required)
- `storeAs` (value, default `""`)

Default block: `{"kind":"fsMkdir","path":"","storeAs":""}`

#### `fsRead` — Read File

Read a text or JSON file. Stores file content in PREVIOUS / storeAs.

Params:
- `path` (value, required)
- `encoding` (value, default `"text"`)
- `storeAs` (value, default `"fileContent"`)

Default block: `{"encoding":"text","kind":"fsRead","path":"","storeAs":"fileContent"}`

#### `fsWrite` — Write File

Write text from the content field or PREVIOUS to a file. Creates parent folders automatically.

Params:
- `path` (value, required)
- `content` (value, default `""`)
- `append` (value, default `false`)
- `storeAs` (value, default `""`)

Default block: `{"append":false,"content":"","kind":"fsWrite","path":"","storeAs":""}`

### Flow

#### `break` — Break

Break out of the current loop.

Default block: `{"kind":"break"}`

#### `case` — Case

One switch branch: runs when the switch value matches its expression.

Params:
- `comparator` (value, default `"==="`)
- `expression` (value)

Default block: `{"comparator":"===","consequent":[],"expression":"\"value\"","kind":"case"}`

#### `else` — Else

Runs when the preceding if/elseIf chain has not matched.

Default block: `{"items":[],"kind":"else"}`

#### `elseIf` — Else If

Runs when the preceding if/elseIf chain has not matched and its own condition is true.

Params:
- `condition` (value, required, default `"true"`)

Default block: `{"condition":"true","items":[],"kind":"elseIf"}`

#### `exit` — Exit

Stop the run immediately and set the process exit code.

Params:
- `code` (value, default `0`)
- `message` (value, default `""`)

Default block: `{"code":0,"kind":"exit"}`

#### `for` — For

Run child blocks over a numeric range.

Params:
- `initial` (value, required, default `"0"`)
- `comparator` (value, required, default `"<"`)
- `final` (value, required, default `"3"`)
- `modifier` (value, required, default `"+1"`)

Default block: `{"comparator":"<","final":"3","initial":"0","items":[],"kind":"for","modifier":"+1"}`

#### `group` — Group

Transparent container: runs its child blocks in the current scope.

Default block: `{"items":[],"kind":"group"}`

#### `if` — If

Run child blocks when the condition is true. Chain `elseIf`/`else` siblings after it.

Params:
- `condition` (value, required, default `"true"`)

Default block: `{"condition":"true","consequent":[],"kind":"if"}`

#### `onStart` — On Start

Run child blocks once when the document starts or ends.

Params:
- `event` (value, default `"On Start"`)

Default block: `{"event":"On Start","items":[],"kind":"onStart"}`

#### `runScript` — Run Script

Legacy alias for group: runs child blocks in the current scope.

Default block: `{"items":[],"kind":"runScript"}`

#### `switch` — Switch

Run the first matching case.

Params:
- `variable` (value, required, default `"mode"`)

Default block: `{"items":[],"kind":"switch","variable":"mode"}`

#### `switchDefault` — Default

Fallback switch branch: runs when no case matches.

Default block: `{"consequent":[],"kind":"switchDefault"}`

#### `wait` — Wait

Sleep for a fixed number of milliseconds.

Params:
- `ms` (value, required, default `500`)

Default block: `{"kind":"wait","ms":500}`

#### `while` — While

Run child blocks while a condition is true.

Params:
- `condition` (value, required, default `"false"`)
- `loopLimit` (value, default `10`)

Default block: `{"condition":"false","items":[],"kind":"while","loopLimit":10}`

### Image

#### `imageCreate` — Create Image

Generate an image from a prompt using the same core create_image API as the CLI create command.

Params:
- `prompt` (value, required)
- `outputPath` (value, default `""`)
- `provider` (value, default `""`)
- `model` (value, default `""`)
- `replicateCollection` (value, default `"official"`)
- `apiKey` (value, default `""`)
- `baseUrl` (value, default `""`)
- `aspectRatio` (value, default `""`)
- `imageSize` (value, default `""`)
- `references` (value, default `[]`)
- `resizeFirst` (value, default `false`)
- `resizeWidth` (value, default `0`)
- `preresizeRawOnly` (value, default `false`)
- `providerOptions` (value, default `{}`)
- `storeAs` (value, default `"imagePath"`)

Default block: `{"apiKey":"","aspectRatio":"","baseUrl":"","imageSize":"","kind":"imageCreate","model":"","outputPath":"","preresizeRawOnly":false,"prompt":"","provider":"","references":[],"replicateCollection":"official","resizeFirst":false,"resizeWidth":0,"storeAs":"imagePath"}`

#### `imageModelControl` — Unload Model

List or unload loaded local model instances for this xBlox process.

Params:
- `action` (value, default `"List"`)
- `key` (value, default `"llama:vlm"`)
- `storeAs` (value, default `"modelKey"`)

Default block: `{"action":"Unload","key":"llama:vlm","kind":"imageModelControl","storeAs":"modelKey"}`

#### `imageResize` — Resize Image

Resize/transform one or more image files using the same libvips pipeline as the resize CLI command.

Params:
- `input` (value, required)
- `outputPath` (value, default `""`)
- `suffix` (value, default `""`)
- `maxWidth` (value, default `0`)
- `maxHeight` (value, default `0`)
- `format` (value, default `""`)
- `fit` (value, default `"inside"`)
- `position` (value, default `"centre"`)
- `kernel` (value, default `"lanczos3"`)
- `quality` (value, default `85`)
- `pngCompression` (value, default `6`)
- `background` (value, default `"#ffffff"`)
- `rotate` (value, default `0`)
- `flip` (value, default `false`)
- `flop` (value, default `false`)
- `autorotate` (value, default `true`)
- `stripMetadata` (value, default `true`)
- `allowEnlargement` (value, default `false`)
- `cache` (value, default `true`)
- `cacheDir` (value, default `""`)
- `urlTimeoutSec` (value, default `5`)
- `urlMaxRedirects` (value, default `20`)
- `storeAs` (value, default `"imagePath"`)

Default block: `{"allowEnlargement":false,"autorotate":true,"background":"#ffffff","cache":true,"cacheDir":"","fit":"inside","flip":false,"flop":false,"format":"","input":"","kernel":"lanczos3","kind":"imageResize","maxHeight":0,"maxWidth":0,"outputPath":"","pngCompression":6,"position":"centre","quality":85,"rotate":0,"storeAs":"imagePath","stripMetadata":true,"suffix":"","urlMaxRedirects":20,"urlTimeoutSec":5}`

#### `imageScreenshot` — Screenshot

Capture a monitor, window, or webcam to an image file and/or clipboard. The input source string is typically wired from a Picker block (e.g. 'screen:0', 'screen:0:wintitle=Chrome*', or a camera device name).

Params:
- `input` (value, default `"screen:0"`)
- `outputPath` (value, default `""`)
- `copyToClipboard` (value, default `false`)
- `timeoutMs` (value, default `5000`)
- `storeAs` (value, default `"imagePath"`)

Default block: `{"copyToClipboard":false,"input":"screen:0","kind":"imageScreenshot","outputPath":"","storeAs":"imagePath","timeoutMs":5000}`

#### `imageTransform` — Transform Image

Edit one or more images with an AI prompt using the same core transform_image API as the CLI transform command.

Params:
- `input` (value, default `""`)
- `prompt` (value, required)
- `outputPath` (value, default `""`)
- `provider` (value, default `""`)
- `model` (value, default `""`)
- `replicateCollection` (value, default `"official"`)
- `apiKey` (value, default `""`)
- `baseUrl` (value, default `""`)
- `aspectRatio` (value, default `""`)
- `imageSize` (value, default `""`)
- `references` (value, default `[]`)
- `resizeFirst` (value, default `false`)
- `resizeWidth` (value, default `0`)
- `preresizeRawOnly` (value, default `false`)
- `providerOptions` (value, default `{}`)
- `storeAs` (value, default `"imagePath"`)

Default block: `{"apiKey":"","aspectRatio":"","baseUrl":"","imageSize":"","input":"","kind":"imageTransform","model":"","outputPath":"","preresizeRawOnly":false,"prompt":"","provider":"","references":[],"replicateCollection":"official","resizeFirst":false,"resizeWidth":0,"storeAs":"imagePath"}`

#### `imageUnderstand` — Image Understand

Ask the vision/recognition model a question about one or more images. Same pipeline as the image_understand agent tool: cloud providers via meta_extract, local VLM via llama (provider=llama). Pure query — no sidecar files written.

Params:
- `input` (value, required)
- `prompt` (value, required)
- `provider` (value, default `""`)
- `model` (value, default `""`)
- `replicateCollection` (value, default `"official"`)
- `apiKey` (value, default `""`)
- `baseUrl` (value, default `""`)
- `resizeFirst` (value, default `true`)
- `resizeWidth` (value, default `512`)
- `json` (value, default `false`)
- `threads` (value, default `4`)
- `gpuLayers` (value, default `-1`)
- `ctx` (value, default `4096`)
- `maxTokens` (value, default `2048`)
- `storeAs` (value, default `"answer"`)

Default block: `{"apiKey":"","baseUrl":"","ctx":4096,"gpuLayers":-1,"input":"","json":false,"kind":"imageUnderstand","maxTokens":2048,"model":"","prompt":"","provider":"","replicateCollection":"official","resizeFirst":true,"resizeWidth":512,"storeAs":"answer","threads":4}`

### Input

#### `keyEvent` — Key Event

Sample a keyboard shortcut once and emit down/pressed/released/toggle state. Designed for document loops: run it each pass, then branch with if blocks.

Params:
- `keys` (value, default `"F9"`)
- `anyKey` (value, default `false`)
- `toggle` (value, default `true`)
- `storeAs` (value, default `"key"`)

Default block: `{"anyKey":false,"keys":"F9","kind":"keyEvent","storeAs":"key","toggle":true}`

#### `keyWait` — Key Wait

Wait for a keyboard shortcut then run child blocks. on=pressed fires on key-down edge; on=released fires on key-up edge; on=held fires while the key is held; on=toggle starts children on the first press and cancels them on the second. repeat=true keeps listening across multiple events. Stores the fired key string in PREVIOUS / storeAs when the wait cycle completes.

Params:
- `keys` (value, default `"F9"`)
- `on` (value, default `"pressed"`)
- `repeat` (value, default `false`)
- `anyKey` (value, default `false`)
- `timeoutMs` (value, default `0`)
- `storeAs` (value, default `""`)

Default block: `{"anyKey":false,"keys":"F9","kind":"keyWait","on":"pressed","repeat":false,"storeAs":"","timeoutMs":0}`

### Modbus

#### `modbusConnection` — Modbus Connection

Start, stop, or inspect a named cached Modbus client connection for fast repeated reads/writes.

Params:
- `action` (value, default `"Start"`)
- `connection` (value, default `"default"`)
- `instance` (value, default `""`)
- `url` (value, default `"tcp:127.0.0.1:15020"`)
- `slave` (value)
- `unitId` (value)
- `timeoutMs` (value, default `30000`)
- `reload` (value, default `false`)
- `storeAs` (value, default `"modbusConnection"`)

Default block: `{"action":"Start","connection":"default","kind":"modbusConnection","storeAs":"modbusConnection","url":"tcp:127.0.0.1:15020"}`

#### `modbusRead` — Modbus Read

Read coils, discrete inputs, holding registers, or input registers. ModbusPoll-style aliases: area/functionCode, address, count/regCount.

Params:
- `url` (value, required, default `"tcp:127.0.0.1:15020"`)
- `connection` (value, default `""`)
- `instance` (value, default `""`)
- `reload` (value, default `false`)
- `area` (value, default `"holdingRegisters"`)
- `address` (value, default `0`)
- `count` (value, default `1`)
- `regCount` (value, default `1`)
- `addressBase` (value, default `"zero"`)
- `slave` (value)
- `timeoutMs` (value, default `30000`)
- `waitTimeMs` (value, default `20`)
- `storeAs` (value, default `"values"`)

Default block: `{"address":0,"area":"holdingRegisters","count":3,"kind":"modbusRead","storeAs":"values","url":"tcp:127.0.0.1:15020"}`

#### `modbusReadCoils` — Modbus Read Coils

Read coils (FC01).

Params:
- `url` (value, required, default `"tcp:127.0.0.1:15020"`)
- `connection` (value, default `""`)
- `instance` (value, default `""`)
- `reload` (value, default `false`)
- `area` (value, default `"holdingRegisters"`)
- `address` (value, default `0`)
- `count` (value, default `1`)
- `regCount` (value, default `1`)
- `addressBase` (value, default `"zero"`)
- `slave` (value)
- `timeoutMs` (value, default `30000`)
- `waitTimeMs` (value, default `20`)
- `storeAs` (value, default `"values"`)

Default block: `{"address":0,"area":"coils","count":8,"kind":"modbusReadCoils","storeAs":"values","url":"tcp:127.0.0.1:15020"}`

#### `modbusReadDiscreteInputs` — Modbus Read Discrete Inputs

Read discrete inputs (FC02).

Params:
- `url` (value, required, default `"tcp:127.0.0.1:15020"`)
- `connection` (value, default `""`)
- `instance` (value, default `""`)
- `reload` (value, default `false`)
- `area` (value, default `"holdingRegisters"`)
- `address` (value, default `0`)
- `count` (value, default `1`)
- `regCount` (value, default `1`)
- `addressBase` (value, default `"zero"`)
- `slave` (value)
- `timeoutMs` (value, default `30000`)
- `waitTimeMs` (value, default `20`)
- `storeAs` (value, default `"values"`)

Default block: `{"address":0,"area":"discreteInputs","count":8,"kind":"modbusReadDiscreteInputs","storeAs":"values","url":"tcp:127.0.0.1:15020"}`

#### `modbusReadHoldingRegisters` — Modbus Read Holding Registers

Read holding registers from a Modbus TCP/RTU endpoint.

Params:
- `url` (value, required, default `"tcp:127.0.0.1:15020"`)
- `connection` (value, default `""`)
- `instance` (value, default `""`)
- `reload` (value, default `false`)
- `area` (value, default `"holdingRegisters"`)
- `address` (value, default `0`)
- `count` (value, default `1`)
- `regCount` (value, default `1`)
- `addressBase` (value, default `"zero"`)
- `slave` (value)
- `timeoutMs` (value, default `30000`)
- `waitTimeMs` (value, default `20`)
- `storeAs` (value, default `"values"`)

Default block: `{"address":0,"count":3,"kind":"modbusReadHoldingRegisters","storeAs":"values","url":"tcp:127.0.0.1:15020"}`

#### `modbusReadInputRegisters` — Modbus Read Input Registers

Read input registers (FC04).

Params:
- `url` (value, required, default `"tcp:127.0.0.1:15020"`)
- `connection` (value, default `""`)
- `instance` (value, default `""`)
- `reload` (value, default `false`)
- `area` (value, default `"holdingRegisters"`)
- `address` (value, default `0`)
- `count` (value, default `1`)
- `regCount` (value, default `1`)
- `addressBase` (value, default `"zero"`)
- `slave` (value)
- `timeoutMs` (value, default `30000`)
- `waitTimeMs` (value, default `20`)
- `storeAs` (value, default `"values"`)

Default block: `{"address":0,"area":"inputRegisters","count":3,"kind":"modbusReadInputRegisters","storeAs":"values","url":"tcp:127.0.0.1:15020"}`

#### `modbusServer` — Modbus Server

Run a Modbus TCP server until cancelled, durationMs expires, or maxRequests is reached.

Params:
- `url` (value, default `"tcp:127.0.0.1:15020"`)
- `holdingRegisters` (value)
- `inputRegisters` (value)
- `registerCount` (value, default `128`)
- `inputRegisterCount` (value, default `128`)
- `coilCount` (value, default `128`)
- `coils` (value)
- `discreteInputCount` (value, default `128`)
- `discreteInputs` (value)
- `durationMs` (value, default `0`)
- `maxRequests` (value, default `0`)
- `unitId` (value, default `1`)
- `pollTimeoutMs` (value, default `100`)
- `debug` (value, default `false`)
- `storeAs` (value, default `""`)

Default block: `{"coils":[1,0,1],"discreteInputs":[0,1,0],"durationMs":3000,"holdingRegisters":[11,22,33],"inputRegisters":[44,55,66],"kind":"modbusServer","url":"tcp:127.0.0.1:15020"}`

#### `modbusWrite` — Modbus Write

Write one or many holding registers/coils. Chooses FC06/FC16 or FC05/FC15 based on area and value count.

Params:
- `url` (value, required, default `"tcp:127.0.0.1:15020"`)
- `connection` (value, default `""`)
- `instance` (value, default `""`)
- `reload` (value, default `false`)
- `area` (value, default `"holdingRegisters"`)
- `address` (value, default `0`)
- `value` (value)
- `values` (value)
- `addressBase` (value, default `"zero"`)
- `slave` (value)
- `timeoutMs` (value, default `30000`)
- `waitTimeMs` (value, default `20`)
- `storeAs` (value, default `""`)

Default block: `{"address":0,"area":"holdingRegisters","kind":"modbusWrite","url":"tcp:127.0.0.1:15020","values":[101,202]}`

#### `modbusWriteCoil` — Modbus Write Coil

Write a single coil (FC05).

Params:
- `url` (value, required, default `"tcp:127.0.0.1:15020"`)
- `connection` (value, default `""`)
- `instance` (value, default `""`)
- `reload` (value, default `false`)
- `area` (value, default `"holdingRegisters"`)
- `address` (value, default `0`)
- `value` (value)
- `values` (value)
- `addressBase` (value, default `"zero"`)
- `slave` (value)
- `timeoutMs` (value, default `30000`)
- `waitTimeMs` (value, default `20`)
- `storeAs` (value, default `""`)

Default block: `{"address":0,"area":"coils","kind":"modbusWriteCoil","url":"tcp:127.0.0.1:15020","value":1}`

#### `modbusWriteCoils` — Modbus Write Coils

Write multiple coils (FC15).

Params:
- `url` (value, required, default `"tcp:127.0.0.1:15020"`)
- `connection` (value, default `""`)
- `instance` (value, default `""`)
- `reload` (value, default `false`)
- `area` (value, default `"holdingRegisters"`)
- `address` (value, default `0`)
- `value` (value)
- `values` (value)
- `addressBase` (value, default `"zero"`)
- `slave` (value)
- `timeoutMs` (value, default `30000`)
- `waitTimeMs` (value, default `20`)
- `storeAs` (value, default `""`)

Default block: `{"address":0,"area":"coils","kind":"modbusWriteCoils","url":"tcp:127.0.0.1:15020","values":[1,0,1]}`

#### `modbusWriteRegister` — Modbus Write Register

Write a single holding register.

Params:
- `url` (value, required, default `"tcp:127.0.0.1:15020"`)
- `connection` (value, default `""`)
- `instance` (value, default `""`)
- `reload` (value, default `false`)
- `area` (value, default `"holdingRegisters"`)
- `address` (value, default `0`)
- `value` (value)
- `values` (value)
- `addressBase` (value, default `"zero"`)
- `slave` (value)
- `timeoutMs` (value, default `30000`)
- `waitTimeMs` (value, default `20`)
- `storeAs` (value, default `""`)

Default block: `{"address":0,"kind":"modbusWriteRegister","url":"tcp:127.0.0.1:15020","value":123}`

#### `modbusWriteRegisters` — Modbus Write Registers

Write multiple holding registers.

Params:
- `url` (value, required, default `"tcp:127.0.0.1:15020"`)
- `connection` (value, default `""`)
- `instance` (value, default `""`)
- `reload` (value, default `false`)
- `area` (value, default `"holdingRegisters"`)
- `address` (value, default `0`)
- `value` (value)
- `values` (value)
- `addressBase` (value, default `"zero"`)
- `slave` (value)
- `timeoutMs` (value, default `30000`)
- `waitTimeMs` (value, default `20`)
- `storeAs` (value, default `""`)

Default block: `{"address":0,"kind":"modbusWriteRegisters","url":"tcp:127.0.0.1:15020","values":[101,202]}`

### MQTT

#### `mqttClient` — MQTT Client

Connect to an MQTT broker and Publish, Subscribe, or RoundTrip a test message. For received messages, runs child items with PREVIOUS={topic,payload,host,port}.

Params:
- `action` (value, default `"RoundTrip"`)
- `host` (value, default `"127.0.0.1"`)
- `port` (value, default `1883`)
- `clientId` (value, default `"xblox-mqtt"`)
- `topic` (value, default `"xblox/smoke"`)
- `payload` (value, default `"hello from xblox"`)
- `qos` (value, default `0`)
- `timeoutMs` (value, default `5000`)
- `storeAs` (value, default `"mqtt"`)

Default block: `{"action":"RoundTrip","host":"127.0.0.1","items":[],"kind":"mqttClient","payload":"hello from xblox","port":1883,"qos":0,"storeAs":"mqtt","timeoutMs":5000,"topic":"xblox/smoke"}`

#### `mqttServer` — MQTT Server

Start, stop, or inspect a named in-process MQTT broker instance.

Params:
- `action` (value, default `"Start"`)
- `instance` (value, default `"default"`)
- `bind` (value, default `"127.0.0.1"`)
- `port` (value, default `1883`)
- `storeAs` (value, default `"mqttServer"`)

Default block: `{"action":"Start","bind":"127.0.0.1","instance":"default","kind":"mqttServer","port":1883,"storeAs":"mqttServer"}`

### Network

#### `fetch` — Fetch

Fetch a URL. With decode:json + a JSON-array response, child blocks iterate over each element (PREVIOUS = element, index = i).

Params:
- `url` (value, required, default `"https://"`)
- `method` (value, default `"GET"`)
- `queryParams` (value)
- `headers` (value, default `""`)
- `bodyType` (value, default `"none"`)
- `body` (value, default `""`)
- `bodyJson` (value)
- `bodyFields` (value)
- `bodyParts` (value)
- `decode` (value, default `"raw"`)
- `parse` (value, default `"."`)
- `auth` (value, default `"none"`)
- `authToken` (value, default `""`)
- `authUser` (value, default `""`)
- `authPass` (value, default `""`)
- `authHeader` (value, default `"X-Api-Key"`)
- `downloadAs` (value, default `""`)
- `cache` (value, default `false`)
- `cacheDir` (value, default `""`)
- `cacheTtlMs` (value, default `3600000`)
- `proxy` (value, default `""`)
- `proxyUser` (value, default `""`)
- `proxyPass` (value, default `""`)
- `sessionId` (value, default `""`)
- `sessionDir` (value, default `""`)
- `insecure` (value, default `false`)
- `verifyPeer` (value, default `true`)
- `verifyHost` (value, default `true`)
- `timeoutMs` (value, default `30000`)
- `connectTimeoutMs` (value, default `10000`)
- `followRedirects` (value, default `true`)
- `maxRedirects` (value, default `5`)
- `retries` (value, default `2`)
- `retryDelayMs` (value, default `250`)
- `statusCode` (value)
- `storeAs` (value, default `"response"`)

Default block: `{"decode":"raw","followRedirects":true,"kind":"fetch","method":"GET","storeAs":"response","timeoutMs":30000,"url":"https://"}`

#### `httpRequest` — HTTP Request

HTTP request via libcurl.

Params:
- `url` (value, required, default `"https://"`)
- `method` (value, default `"GET"`)
- `queryParams` (value)
- `headers` (value, default `""`)
- `bodyType` (value, default `"none"`)
- `body` (value, default `""`)
- `bodyJson` (value)
- `bodyFields` (value)
- `bodyParts` (value)
- `decode` (value, default `"raw"`)
- `parse` (value, default `"."`)
- `auth` (value, default `"none"`)
- `authToken` (value, default `""`)
- `authUser` (value, default `""`)
- `authPass` (value, default `""`)
- `authHeader` (value, default `"X-Api-Key"`)
- `downloadAs` (value, default `""`)
- `cache` (value, default `false`)
- `cacheDir` (value, default `""`)
- `cacheTtlMs` (value, default `3600000`)
- `proxy` (value, default `""`)
- `proxyUser` (value, default `""`)
- `proxyPass` (value, default `""`)
- `sessionId` (value, default `""`)
- `sessionDir` (value, default `""`)
- `insecure` (value, default `false`)
- `verifyPeer` (value, default `true`)
- `verifyHost` (value, default `true`)
- `timeoutMs` (value, default `30000`)
- `connectTimeoutMs` (value, default `10000`)
- `followRedirects` (value, default `true`)
- `maxRedirects` (value, default `5`)
- `retries` (value, default `2`)
- `retryDelayMs` (value, default `250`)
- `statusCode` (value)
- `storeAs` (value, default `"response"`)

Default block: `{"decode":"raw","followRedirects":true,"kind":"httpRequest","method":"GET","storeAs":"response","timeoutMs":30000,"url":"https://"}`

#### `ipcBroadcast` — IPC Broadcast

Send a message to every live XBlox session.

Params:
- `from` (value, default `"xblox"`)
- `message` (value, default `""`)
- `data` (value)
- `timeoutMs` (value, default `3000`)
- `storeAs` (value, default `"ipcBroadcast"`)

Default block: `{"data":null,"from":"xblox","kind":"ipcBroadcast","message":"","storeAs":"ipcBroadcast"}`

#### `ipcReceive` — IPC Receive

Drain or wait for messages from a live XBlox session inbox. Child blocks iterate over received messages.

Params:
- `target` (value, required)
- `peek` (value, default `false`)
- `waitMs` (value, default `0`)
- `pollMs` (value, default `100`)
- `timeoutMs` (value, default `3000`)
- `storeAs` (value, default `"messages"`)

Default block: `{"items":[],"kind":"ipcReceive","peek":false,"pollMs":100,"storeAs":"messages","target":"","waitMs":0}`

#### `ipcSend` — IPC Send

Send a message to a live XBlox session.

Params:
- `target` (value, required)
- `from` (value, default `"xblox"`)
- `message` (value, default `""`)
- `data` (value)
- `timeoutMs` (value, default `3000`)
- `storeAs` (value, default `"ipcReply"`)

Default block: `{"data":null,"from":"xblox","kind":"ipcSend","message":"","storeAs":"ipcReply","target":""}`

#### `ipcSendBatch` — IPC Send Batch

Send many messages to a live XBlox session in one IPC frame.

Params:
- `target` (value, required)
- `from` (value, default `"xblox"`)
- `message` (value, default `""`)
- `count` (value, default `1`)
- `source` (value, default `""`)
- `data` (value)
- `timeoutMs` (value, default `3000`)
- `storeAs` (value, default `"ipcBatchReply"`)

Default block: `{"count":1,"data":null,"from":"xblox","kind":"ipcSendBatch","message":"","source":"","storeAs":"ipcBatchReply","target":""}`

#### `ipcSession` — IPC Session

Host a named XBlox IPC session for this run. Reuses the same session on later loop passes.

Params:
- `name` (value, required)
- `label` (value, default `""`)
- `storeAs` (value, default `"session"`)

Default block: `{"kind":"ipcSession","name":"ipc","storeAs":"session"}`

#### `ipcSessions` — IPC Sessions

List live XBlox sessions. Child blocks iterate over each session descriptor.

Params:
- `storeAs` (value, default `"sessions"`)

Default block: `{"items":[],"kind":"ipcSessions","storeAs":"sessions"}`

#### `mcpCall` — MCP Call

Call a tool on an MCP server. Supports profile servers (mcp.json), bundled system servers, and inline custom configs (stdio + HTTP). Fresh session per call.

Params:
- `server` (value, required)
- `serverConfig` (value, default `{}`)
- `tool` (value, required)
- `arguments` (value, default `{}`)
- `timeoutMs` (value, default `60000`)
- `storeAs` (value, default `"mcpResult"`)

Default block: `{"arguments":{},"kind":"mcpCall","server":"","serverConfig":{},"storeAs":"mcpResult","timeoutMs":60000,"tool":""}`

#### `network` — Network Request

HTTP request via libcurl.

Params:
- `url` (value, required, default `"https://"`)
- `method` (value, default `"GET"`)
- `queryParams` (value)
- `headers` (value, default `""`)
- `bodyType` (value, default `"none"`)
- `body` (value, default `""`)
- `bodyJson` (value)
- `bodyFields` (value)
- `bodyParts` (value)
- `decode` (value, default `"raw"`)
- `parse` (value, default `"."`)
- `auth` (value, default `"none"`)
- `authToken` (value, default `""`)
- `authUser` (value, default `""`)
- `authPass` (value, default `""`)
- `authHeader` (value, default `"X-Api-Key"`)
- `downloadAs` (value, default `""`)
- `cache` (value, default `false`)
- `cacheDir` (value, default `""`)
- `cacheTtlMs` (value, default `3600000`)
- `proxy` (value, default `""`)
- `proxyUser` (value, default `""`)
- `proxyPass` (value, default `""`)
- `sessionId` (value, default `""`)
- `sessionDir` (value, default `""`)
- `insecure` (value, default `false`)
- `verifyPeer` (value, default `true`)
- `verifyHost` (value, default `true`)
- `timeoutMs` (value, default `30000`)
- `connectTimeoutMs` (value, default `10000`)
- `followRedirects` (value, default `true`)
- `maxRedirects` (value, default `5`)
- `retries` (value, default `2`)
- `retryDelayMs` (value, default `250`)
- `statusCode` (value)
- `storeAs` (value, default `"response"`)

Default block: `{"decode":"raw","followRedirects":true,"kind":"network","method":"GET","storeAs":"response","timeoutMs":30000,"url":"https://"}`

#### `sshExec` — SSH Exec

Run a command on a remote host over SSH using password or public-key authentication.

Params:
- `host` (value, required)
- `port` (value, default `22`)
- `username` (value, default `""`)
- `password` (value, default `""`)
- `privateKey` (value, default `""`)
- `passphrase` (value, default `""`)
- `command` (value, required)
- `configFile` (value, default `""`)
- `knownHosts` (value, default `""`)
- `verifyHost` (value, default `true`)
- `acceptUnknownHost` (value, default `false`)
- `timeoutMs` (value, default `30000`)
- `exitStatus` (value)
- `storeAs` (value, default `"ssh"`)

Default block: `{"command":"","host":"","kind":"sshExec","port":22,"storeAs":"ssh","timeoutMs":30000,"username":""}`

### OCR

#### `ocr`

Alias for ocrText.

Params:
- `input` (value, required)
- `provider` (value, default `"auto"`)
- `mode` (value, default `"layout"`)
- `model` (value, default `""`)
- `prompt` (value, default `"OCR: Extract all text verbatim, preserving line breaks and spatial layout."`)
- `json` (value, default `true`)
- `markdown` (value, default `true`)
- `backend` (value, default `"auto"`)
- `threads` (value, default `4`)
- `layoutModel` (value, default `""`)
- `layoutConf` (value, default `0.5`)
- `detModel` (value, default `""`)
- `recModel` (value, default `""`)
- `dict` (value, default `""`)
- `threshold` (value, default `0.3`)
- `recThreshold` (value, default `0.5`)
- `maxSize` (value, default `960`)
- `maxTokens` (value, default `2048`)
- `ctx` (value, default `8192`)
- `gpuLayers` (value, default `-1`)
- `result` (value)
- `storeAs` (value, default `"ocr"`)

Default block: `{"backend":"auto","ctx":8192,"detModel":"","dict":"","gpuLayers":-1,"input":"","items":[],"json":true,"kind":"ocr","layoutConf":0.5,"layoutModel":"","markdown":true,"maxSize":960,"maxTokens":2048,"mode":"layout","model":"","prompt":"OCR: Extract all text verbatim, preserving line breaks and spatial layout.","provider":"auto","recModel":"","recThreshold":0.5,"storeAs":"ocr","threads":4,"threshold":0.3}`

#### `ocrModelControl` — Unload Model

List or unload loaded local model instances for this xBlox process.

Params:
- `action` (value, default `"List"`)
- `key` (value, default `"llama:vlm"`)
- `storeAs` (value, default `"modelKey"`)

Default block: `{"action":"Unload","key":"llama:vlm","kind":"ocrModelControl","storeAs":"modelKey"}`

#### `ocrText` — OCR Text

Ready-to-go document OCR: PP-DocLayoutV3 detects layout, PaddleOCR-VL extracts text/tables, and child items can iterate documents.

Params:
- `input` (value, required)
- `provider` (value, default `"auto"`)
- `mode` (value, default `"layout"`)
- `model` (value, default `""`)
- `prompt` (value, default `"OCR: Extract all text verbatim, preserving line breaks and spatial layout."`)
- `json` (value, default `true`)
- `markdown` (value, default `true`)
- `backend` (value, default `"auto"`)
- `threads` (value, default `4`)
- `layoutModel` (value, default `""`)
- `layoutConf` (value, default `0.5`)
- `detModel` (value, default `""`)
- `recModel` (value, default `""`)
- `dict` (value, default `""`)
- `threshold` (value, default `0.3`)
- `recThreshold` (value, default `0.5`)
- `maxSize` (value, default `960`)
- `maxTokens` (value, default `2048`)
- `ctx` (value, default `8192`)
- `gpuLayers` (value, default `-1`)
- `result` (value)
- `storeAs` (value, default `"ocr"`)

Default block: `{"backend":"auto","ctx":8192,"detModel":"","dict":"","gpuLayers":-1,"input":"","items":[],"json":true,"kind":"ocrText","layoutConf":0.5,"layoutModel":"","markdown":true,"maxSize":960,"maxTokens":2048,"mode":"layout","model":"","prompt":"OCR: Extract all text verbatim, preserving line breaks and spatial layout.","provider":"auto","recModel":"","recThreshold":0.5,"storeAs":"ocr","threads":4,"threshold":0.3}`

### Service

#### `serviceFilesList` — List Files

GET /api/vfs/ls/{mount}/{path}  -  list files in a VFS directory.

Params:
- `mount` (value, default `"home"`)
- `path` (value, default `""`)
- `serverUrl` (value, default `""`)
- `auth` (value, default `"auto"`)
- `bearerToken` (value, default `""`)
- `timeoutMs` (value, default `30000`)
- `storeAs` (value, default `"fileList"`)

Default block: `{"auth":"auto","kind":"serviceFilesList","mount":"home","path":"","storeAs":"fileList"}`

#### `serviceFilesRead` — Read File

GET /api/vfs/read/{mount}/{path}  -  download a VFS file. Set downloadAs to save to disk (PREVIOUS = saved path); else PREVIOUS = body string.

Params:
- `mount` (value, default `"home"`)
- `path` (value, required, default `""`)
- `downloadAs` (value, default `""`)
- `serverUrl` (value, default `""`)
- `auth` (value, default `"auto"`)
- `bearerToken` (value, default `""`)
- `timeoutMs` (value, default `30000`)
- `storeAs` (value, default `"fileContent"`)

Default block: `{"auth":"auto","kind":"serviceFilesRead","mount":"home","storeAs":"fileContent"}`

#### `serviceFilesRemove` — Remove File

DELETE /api/vfs/delete/{mount}/{path}  -  remove a file or folder from the VFS.

Params:
- `mount` (value, default `"home"`)
- `path` (value, required, default `""`)
- `serverUrl` (value, default `""`)
- `auth` (value, default `"auto"`)
- `bearerToken` (value, default `""`)
- `timeoutMs` (value, default `30000`)
- `storeAs` (value, default `"removeResult"`)

Default block: `{"auth":"auto","kind":"serviceFilesRemove","mount":"home","storeAs":"removeResult"}`

#### `serviceFilesSearch` — Search Files (VFS)

GET /api/vfs/search/{mount}/{path}?q=...&type=...&maxResults=...&fts=1  -  search VFS files by filename walk (default) or PostgreSQL FTS index (fts=1). FTS only reflects the last index run; fresh uploads may not appear until the index is rebuilt. PREVIOUS = {results:[...], total:N, truncated:bool}.

Params:
- `q` (value, required, default `""`)
- `mount` (value, default `"home"`)
- `path` (value, default `""`)
- `type` (value, default `"all"`)
- `maxResults` (value, default `200`)
- `fts` (value, default `0`)
- `serverUrl` (value, default `""`)
- `auth` (value, default `"auto"`)
- `bearerToken` (value, default `""`)
- `timeoutMs` (value, default `30000`)
- `storeAs` (value, default `"searchResult"`)

Default block: `{"auth":"auto","fts":0,"kind":"serviceFilesSearch","maxResults":200,"mount":"home","storeAs":"searchResult","type":"all"}`

#### `serviceFilesUpload` — Upload File

POST /api/vfs/upload/{mount}/{remotePath}  -  upload any file to the VFS.

Params:
- `file` (value, required, default `""`)
- `mount` (value, default `"home"`)
- `remotePath` (value, default `""`)
- `serverUrl` (value, default `""`)
- `auth` (value, default `"auto"`)
- `bearerToken` (value, default `""`)
- `timeoutMs` (value, default `30000`)
- `storeAs` (value, default `"fileResult"`)

Default block: `{"auth":"auto","kind":"serviceFilesUpload","mount":"home","storeAs":"fileResult"}`

#### `serviceImagesUpload` — Upload Image(s)

POST /api/images?forward=vfs&original=true  -  multipart upload one or more image files. PREVIOUS = array of per-file response objects.

Params:
- `file` (value, default `""`)
- `files` (value)
- `serverUrl` (value, default `""`)
- `auth` (value, default `"auto"`)
- `bearerToken` (value, default `""`)
- `timeoutMs` (value, default `30000`)
- `failed` (value)
- `storeAs` (value, default `"uploadResults"`)

Default block: `{"auth":"auto","kind":"serviceImagesUpload","storeAs":"uploadResults"}`

#### `servicePagesCreate` — Create Page

POST /api/pages  -  create a CMS page. Provide slug + title + content, or a full body JSON object.

Params:
- `slug` (value, default `""`)
- `title` (value, default `""`)
- `content` (value, default `""`)
- `tags` (value, default `""`)
- `visibility` (value, default `"public"`)
- `ownerId` (value, default `""`)
- `body` (value)
- `serverUrl` (value, default `""`)
- `auth` (value, default `"auto"`)
- `bearerToken` (value, default `""`)
- `timeoutMs` (value, default `30000`)
- `storeAs` (value, default `"page"`)

Default block: `{"auth":"auto","kind":"servicePagesCreate","storeAs":"page","visibility":"public"}`

#### `servicePagesGet` — Get Page

GET /api/user-page/{identifier}/{slug}  -  fetch a single page by pageId or ownerId/userId + slug.

Params:
- `pageId` (value, default `""`)
- `slug` (value, default `""`)
- `ownerId` (value, default `""`)
- `userId` (value, default `""`)
- `serverUrl` (value, default `""`)
- `auth` (value, default `"auto"`)
- `bearerToken` (value, default `""`)
- `timeoutMs` (value, default `30000`)
- `storeAs` (value, default `"page"`)

Default block: `{"auth":"auto","kind":"servicePagesGet","storeAs":"page"}`

#### `servicePagesList` — List Pages

GET /api/pages?userId=...&page=...&limit=...  -  list pages.

Params:
- `userId` (value, default `""`)
- `page` (value, default `1`)
- `limit` (value, default `20`)
- `serverUrl` (value, default `""`)
- `auth` (value, default `"auto"`)
- `bearerToken` (value, default `""`)
- `timeoutMs` (value, default `30000`)
- `storeAs` (value, default `"pages"`)

Default block: `{"auth":"auto","kind":"servicePagesList","limit":20,"page":1,"storeAs":"pages"}`

#### `servicePagesRemove` — Remove Page

DELETE /api/pages/{pageId}; or resolve ownerId/userId + slug before deleting.

Params:
- `pageId` (value, default `""`)
- `slug` (value, default `""`)
- `ownerId` (value, default `""`)
- `userId` (value, default `""`)
- `serverUrl` (value, default `""`)
- `auth` (value, default `"auto"`)
- `bearerToken` (value, default `""`)
- `timeoutMs` (value, default `30000`)
- `storeAs` (value, default `"removeResult"`)

Default block: `{"auth":"auto","kind":"servicePagesRemove","storeAs":"removeResult"}`

#### `servicePagesUpdate` — Update Page

PATCH /api/pages/{pageId}; or resolve ownerId/userId + slug before updating.

Params:
- `pageId` (value, default `""`)
- `slug` (value, default `""`)
- `ownerId` (value, default `""`)
- `userId` (value, default `""`)
- `content` (value, default `""`)
- `title` (value, default `""`)
- `newSlug` (value, default `""`)
- `tags` (value, default `""`)
- `body` (value)
- `serverUrl` (value, default `""`)
- `auth` (value, default `"auto"`)
- `bearerToken` (value, default `""`)
- `timeoutMs` (value, default `30000`)
- `storeAs` (value, default `"page"`)

Default block: `{"auth":"auto","kind":"servicePagesUpdate","storeAs":"page"}`

#### `servicePicturesGet` — Get Picture

GET /api/pictures/{pictureId}  -  fetch a picture record.

Params:
- `pictureId` (value, required, default `""`)
- `serverUrl` (value, default `""`)
- `auth` (value, default `"auto"`)
- `bearerToken` (value, default `""`)
- `timeoutMs` (value, default `30000`)
- `storeAs` (value, default `"picture"`)

Default block: `{"auth":"auto","kind":"servicePicturesGet","storeAs":"picture"}`

#### `servicePicturesList` — List Pictures

GET /api/pictures?userId=...&page=...&limit=...  -  list picture records.

Params:
- `userId` (value, default `""`)
- `page` (value, default `1`)
- `limit` (value, default `20`)
- `serverUrl` (value, default `""`)
- `auth` (value, default `"auto"`)
- `bearerToken` (value, default `""`)
- `timeoutMs` (value, default `30000`)
- `storeAs` (value, default `"pictures"`)

Default block: `{"auth":"auto","kind":"servicePicturesList","limit":20,"page":1,"storeAs":"pictures"}`

#### `servicePicturesRemove` — Remove Picture

DELETE /api/pictures/{pictureId}  -  remove a picture record.

Params:
- `pictureId` (value, required, default `""`)
- `serverUrl` (value, default `""`)
- `auth` (value, default `"auto"`)
- `bearerToken` (value, default `""`)
- `timeoutMs` (value, default `30000`)
- `storeAs` (value, default `"removeResult"`)

Default block: `{"auth":"auto","kind":"servicePicturesRemove","storeAs":"removeResult"}`

#### `servicePostsCreate` — Create Post

Full publish flow: POST /api/posts then upload each image via /api/images and attach via /api/pictures. PREVIOUS = {postId, pictureIds, post}.

Params:
- `title` (value, default `""`)
- `description` (value, default `""`)
- `visibility` (value, default `"public"`)
- `ownerId` (value, default `""`)
- `file` (value, default `""`)
- `files` (value)
- `serverUrl` (value, default `""`)
- `auth` (value, default `"auto"`)
- `bearerToken` (value, default `""`)
- `timeoutMs` (value, default `30000`)
- `storeAs` (value, default `"post"`)

Default block: `{"auth":"auto","kind":"servicePostsCreate","storeAs":"post","visibility":"public"}`

#### `servicePostsGet` — Get Post

GET /api/posts/{postId}  -  fetch a post with its pictures.

Params:
- `postId` (value, required, default `""`)
- `serverUrl` (value, default `""`)
- `auth` (value, default `"auto"`)
- `bearerToken` (value, default `""`)
- `timeoutMs` (value, default `30000`)
- `storeAs` (value, default `"post"`)

Default block: `{"auth":"auto","kind":"servicePostsGet","storeAs":"post"}`

#### `servicePostsList` — List Posts

GET /api/posts?page=...&limit=...&userId=...  -  list posts.

Params:
- `userId` (value, default `""`)
- `page` (value, default `1`)
- `limit` (value, default `20`)
- `serverUrl` (value, default `""`)
- `auth` (value, default `"auto"`)
- `bearerToken` (value, default `""`)
- `timeoutMs` (value, default `30000`)
- `storeAs` (value, default `"posts"`)

Default block: `{"auth":"auto","kind":"servicePostsList","limit":20,"page":1,"storeAs":"posts"}`

#### `servicePostsRemove` — Remove Post

DELETE /api/posts/{postId}  -  remove a post.

Params:
- `postId` (value, required, default `""`)
- `serverUrl` (value, default `""`)
- `auth` (value, default `"auto"`)
- `bearerToken` (value, default `""`)
- `timeoutMs` (value, default `30000`)
- `storeAs` (value, default `"removeResult"`)

Default block: `{"auth":"auto","kind":"servicePostsRemove","storeAs":"removeResult"}`

#### `serviceSearch` — Search

GET /api/search?q=...&type=...&limit=...  -  full-text search across pages, posts, pictures, VFS files and places. Auth is optional (unauthenticated calls see only public content). PREVIOUS = array of enriched FeedPost objects.

Params:
- `q` (value, required, default `""`)
- `type` (value, default `"all"`)
- `limit` (value, default `20`)
- `sizes` (value, default `""`)
- `formats` (value, default `""`)
- `visibilityFilter` (value, default `""`)
- `serverUrl` (value, default `""`)
- `auth` (value, default `"auto"`)
- `bearerToken` (value, default `""`)
- `timeoutMs` (value, default `30000`)
- `storeAs` (value, default `"results"`)

Default block: `{"auth":"auto","kind":"serviceSearch","limit":20,"storeAs":"results","type":"all"}`

### Shell

#### `openPath` — Open Path

Open a file or folder with the system default application.

Params:
- `path` (value, required)
- `storeAs` (value, default `"openedPath"`)

Default block: `{"kind":"openPath","path":"","storeAs":"openedPath"}`

#### `shell` — Shell

Run a shell command through the native RunTool.

Params:
- `mode` (value, default `"shell"`)
- `shell` (value, default `"auto"`)
- `command` (value, required, default `"echo hello"`)
- `cwd` (value, default `""`)
- `timeoutMs` (value, default `30000`)
- `log` (value, default `false`)
- `stdout` (value, default `"info"`)
- `stderr` (value, default `"error"`)
- `storeAs` (value, default `"stdout"`)

Default block: `{"command":"echo hello","kind":"shell","log":false,"mode":"shell","shell":"auto","stderr":"error","stdout":"info","storeAs":"stdout","timeoutMs":30000}`

#### `Shell`

Run a shell command through the native RunTool.

Params:
- `mode` (value, default `"shell"`)
- `shell` (value, default `"auto"`)
- `command` (value, required, default `"echo hello"`)
- `cwd` (value, default `""`)
- `timeoutMs` (value, default `30000`)
- `log` (value, default `false`)
- `stdout` (value, default `"info"`)
- `stderr` (value, default `"error"`)
- `storeAs` (value, default `"stdout"`)

Default block: `{"command":"echo hello","kind":"Shell","log":false,"mode":"shell","shell":"auto","stderr":"error","stdout":"info","storeAs":"stdout","timeoutMs":30000}`

#### `xbloxRun` — XBlox Script

Run another XBlox document directly, with context overrides and optional document-loop controls.

Params:
- `action` (value, default `"Run"`)
- `path` (value, required)
- `context` (value, default `{}`)
- `args` (value, default `[]`)
- `reload` (value, default `false`)
- `loop` (value, default `false`)
- `loopIntervalMs` (value, default `100`)
- `loopReset` (value, default `false`)
- `background` (value, default `false`)
- `logLevel` (value, default `"off"`)
- `storeAs` (value, default `"xbloxResult"`)

Default block: `{"action":"Run","args":[],"background":false,"context":{},"items":[],"kind":"xbloxRun","logLevel":"off","path":"","reload":false,"storeAs":"xbloxResult"}`

### Vector

#### `vectorLocalAddDir` — Index Directory into Local Vector Store

Recursively index all supported files (txt, md, docx, xlsx, pptx) in a directory. Already-indexed paths are skipped. PREVIOUS = {files:[{file,count,skipped}], totalChunks:N, storePath, docCount}.

Params:
- `dir` (value, required, default `""`)
- `recursive` (value, default `true`)
- `maxFiles` (value, default `500`)
- `chunkSize` (value, default `500`)
- `chunkOverlap` (value, default `100`)
- `storePath` (value, required, default `""`)
- `model` (value, default `""`)
- `threads` (value, default `4`)
- `gpuLayers` (value, default `0`)
- `storeAs` (value, default `"addDirResult"`)

Default block: `{"chunkOverlap":100,"chunkSize":500,"kind":"vectorLocalAddDir","maxFiles":500,"recursive":true,"storeAs":"addDirResult"}`

#### `vectorLocalAddFile` — Add File to Local Vector Store

Read a text file, chunk it, embed each chunk with the local GGUF model, insert into the store. Binary/image files and files > 1 MiB are rejected. PREVIOUS = {ids:[...], count:N, file, storePath, docCount}.

Params:
- `file` (value, required, default `""`)
- `source` (value, default `"file"`)
- `title` (value, default `""`)
- `tags` (value, default `""`)
- `chunkSize` (value, default `500`)
- `chunkOverlap` (value, default `100`)
- `storePath` (value, required, default `""`)
- `model` (value, default `""`)
- `threads` (value, default `4`)
- `gpuLayers` (value, default `0`)
- `storeAs` (value, default `"addResult"`)

Default block: `{"chunkOverlap":100,"chunkSize":500,"kind":"vectorLocalAddFile","source":"file","storeAs":"addResult"}`

#### `vectorLocalAddText` — Add Text to Local Vector Store

Embed text locally (GGUF model), chunk if needed, insert into the store, and save. All embedding is offline  -  no network calls. PREVIOUS = {ids:[...], count:N, storePath, docCount}.

Params:
- `text` (value, required, default `""`)
- `source` (value, default `"text"`)
- `path` (value, default `""`)
- `title` (value, default `""`)
- `tags` (value, default `""`)
- `chunkSize` (value, default `500`)
- `chunkOverlap` (value, default `100`)
- `storePath` (value, required, default `""`)
- `model` (value, default `""`)
- `threads` (value, default `4`)
- `gpuLayers` (value, default `0`)
- `storeAs` (value, default `"addResult"`)

Default block: `{"chunkOverlap":100,"chunkSize":500,"kind":"vectorLocalAddText","source":"text","storeAs":"addResult"}`

#### `vectorLocalDelete` — Delete from Local Vector Store by Path

Remove all chunks for a given source path from the store. PREVIOUS = {deleted:N, path, storePath, docCount}.

Params:
- `path` (value, required, default `""`)
- `storePath` (value, required, default `""`)
- `model` (value, default `""`)
- `threads` (value, default `4`)
- `gpuLayers` (value, default `0`)
- `storeAs` (value, default `"deleteResult"`)

Default block: `{"kind":"vectorLocalDelete","storeAs":"deleteResult"}`

#### `vectorLocalOpen` — Open Local Vector Store

Open or create a local GGUF-backed vector store at storePath. Loads the embedding model once; subsequent blocks on the same path reuse it. Set gpuLayers to offload embedding to the GPU (-1 = all layers) for faster ingest. PREVIOUS = {docCount, dims, modelPath, gpu, gpuLayers}.

Params:
- `storePath` (value, required, default `""`)
- `model` (value, default `""`)
- `threads` (value, default `4`)
- `gpuLayers` (value, default `0`)
- `storeAs` (value, default `"storeInfo"`)

Default block: `{"kind":"vectorLocalOpen","storeAs":"storeInfo"}`

#### `vectorLocalSearch` — Search Local Vector Store

Embed the query locally (GGUF model) and return top-k results by cosine similarity. Offline, no network. PREVIOUS = {hits:[{id,source,path,title,chunk,tags,score},...], count:N, query}.

Params:
- `query` (value, required, default `""`)
- `topK` (value, default `10`)
- `filterSource` (value, default `""`)
- `filterPath` (value, default `""`)
- `storePath` (value, required, default `""`)
- `model` (value, default `""`)
- `threads` (value, default `4`)
- `gpuLayers` (value, default `0`)
- `storeAs` (value, default `"searchResult"`)

Default block: `{"kind":"vectorLocalSearch","storeAs":"searchResult","topK":10}`

#### `vectorLocalStats` — Local Vector Store Stats

Return metadata about an open store: doc count, dims, model, index size. PREVIOUS = {docCount, dims, modelPath, storePath, indexSizeBytes}.

Params:
- `storePath` (value, required, default `""`)
- `model` (value, default `""`)
- `threads` (value, default `4`)
- `gpuLayers` (value, default `0`)
- `storeAs` (value, default `"storeStats"`)

Default block: `{"kind":"vectorLocalStats","storeAs":"storeStats"}`

### Video

#### `pictureOut` — Picture Out

Encode a frame handle (or pass-through image) to a file on disk. The exit from the in-memory filter pipeline. Stores the written path in PREVIOUS / storeAs.

Params:
- `input` (value, default `""`)
- `outputPath` (value, default `""`)
- `quality` (value, default `90`)
- `storeAs` (value, default `"imagePath"`)

Default block: `{"input":"","kind":"pictureOut","outputPath":"","quality":90,"storeAs":"imagePath"}`

#### `videoCapture` — Capture Image / Video

Capture a still image or record a camera, screen, or window source to MP4. Stores the output path in PREVIOUS / storeAs.

Params:
- `action` (value, default `"Still"`)
- `input` (value, default `""`)
- `device` (value, default `""`)
- `instance` (value, default `""`)
- `outputPath` (value, default `""`)
- `fps` (value, default `30`)
- `bitrateKbps` (value, default `0`)
- `captureEngine` (value, default `"auto"`)
- `encoder` (value, default `"auto"`)
- `durationMs` (value, default `0`)
- `includeCursor` (value, default `true`)
- `pauseKey` (value, default `""`)
- `sizeMode` (value, default `"native"`)
- `zoom` (value, default `1`)
- `follow` (value, default `"none"`)
- `followSpeed` (value, default `0.2`)
- `followDeadzone` (value, default `3`)
- `transitionMs` (value, default `300`)
- `updateIntervalMs` (value, default `16`)
- `focusX` (value, default `-1`)
- `focusY` (value, default `-1`)
- `interactiveZoom` (value, default `false`)
- `zoomStep` (value, default `0.15`)
- `zoomMin` (value, default `1`)
- `zoomMax` (value, default `4`)
- `consumeZoomInput` (value, default `true`)
- `showZoomStatus` (value, default `true`)
- `hudCapture` (value, default `"auto"`)
- `audioSource` (value, default `"none"`)
- `audioDevice` (value, default `""`)
- `desktopDevice` (value, default `""`)
- `micGain` (value, default `1`)
- `desktopGain` (value, default `1`)
- `width` (value, default `0`)
- `height` (value, default `0`)
- `timeoutMs` (value, default `5000`)
- `storeAs` (value, default `"capturePath"`)

Default block: `{"action":"Still","audioDevice":"","audioSource":"none","bitrateKbps":0,"captureEngine":"auto","consumeZoomInput":true,"desktopDevice":"","desktopGain":1,"device":"","durationMs":0,"encoder":"auto","focusX":-1,"focusY":-1,"follow":"none","followDeadzone":3,"followSpeed":0.2,"fps":30,"height":0,"hudCapture":"auto","includeCursor":true,"input":"","instance":"","interactiveZoom":false,"kind":"videoCapture","micGain":1,"outputPath":"","pauseKey":"","showZoomStatus":true,"sizeMode":"native","storeAs":"capturePath","timeoutMs":5000,"transitionMs":300,"updateIntervalMs":16,"width":0,"zoom":1,"zoomMax":4,"zoomMin":1,"zoomStep":0.15}`

#### `videoColor` — Color Adjust

Adjust brightness / contrast / saturation of a frame. Pipes a frame handle in/out.

Params:
- `input` (value, default `""`)
- `brightness` (value, default `0`)
- `contrast` (value, default `1`)
- `saturation` (value, default `1`)
- `outputPath` (value, default `""`)
- `storeAs` (value, default `"imagePath"`)

Default block: `{"brightness":0,"contrast":1,"input":"","kind":"videoColor","outputPath":"","saturation":1,"storeAs":"imagePath"}`

#### `videoCrop` — Crop

Crop a rectangular region from a frame. Pipes a frame handle in/out.

Params:
- `input` (value, default `""`)
- `x` (value, default `0`)
- `y` (value, default `0`)
- `width` (value, default `0`)
- `height` (value, default `0`)
- `outputPath` (value, default `""`)
- `storeAs` (value, default `"imagePath"`)

Default block: `{"height":0,"input":"","kind":"videoCrop","outputPath":"","storeAs":"imagePath","width":0,"x":0,"y":0}`

#### `videoDetect` — Detect Objects

Capture one frame (webcam or screen) and run a YOLO model. task = detect/obb/pose -> {boxes:[{x,y,w,h,conf,cls,label,angle?,keypoints?}]}; classify -> {classes:[{cls,score,label}]}. Stores {ok, image_w, image_h, infer_ms, task, ...} in PREVIOUS / storeAs.

Params:
- `model` (value, required)
- `input` (value, default `""`)
- `task` (value, default `"auto"`)
- `labels` (value, default `""`)
- `classes` (value, default `""`)
- `filterClasses` (value, default `""`)
- `conf` (value, default `0.25`)
- `nms` (value, default `0.45`)
- `topK` (value, default `5`)
- `inputSize` (value, default `0`)
- `threads` (value, default `4`)
- `provider` (value, default `"gpu"`)
- `gpuStats` (value, default `false`)
- `instance` (value, default `""`)
- `visualize` (value, default `false`)
- `visualizeMode` (value, default `"auto"`)
- `visualizeStats` (value, default `true`)
- `visualizeLabels` (value, default `true`)
- `smoothAlpha` (value, default `0.35`)
- `smoothAge` (value, default `4`)
- `smoothMinHits` (value, default `0`)
- `trackIds` (value, default `false`)
- `trackTwoStage` (value, default `false`)
- `trackConfHigh` (value, default `0.5`)
- `trackCenter` (value, default `true`)
- `trackCenterDist` (value, default `1.2`)
- `trackVelBlend` (value, default `0.7`)
- `kptMinScore` (value, default `0.3`)
- `timeoutMs` (value, default `5000`)
- `outputPath` (value, default `""`)
- `recordPath` (value, default `""`)
- `recordFps` (value, default `30`)
- `storeAs` (value, default `"detections"`)

Default block: `{"classes":"","conf":0.25,"filterClasses":"","gpuStats":false,"input":"","inputSize":0,"instance":"","items":[],"kind":"videoDetect","kptMinScore":0.3,"labels":"","model":"","nms":0.45,"outputPath":"","provider":"gpu","recordFps":30,"recordPath":"","smoothAge":4,"smoothAlpha":0.35,"smoothMinHits":0,"storeAs":"detections","task":"auto","threads":4,"timeoutMs":5000,"topK":5,"trackCenter":true,"trackCenterDist":1.2,"trackConfHigh":0.5,"trackIds":false,"trackTwoStage":false,"trackVelBlend":0.7,"visualize":false,"visualizeLabels":true,"visualizeMode":"auto","visualizeStats":true}`

#### `videoGrayscale` — Grayscale

Convert a frame to grayscale (Rec.601 luma). Pipes a frame handle in/out.

Params:
- `input` (value, default `""`)
- `outputPath` (value, default `""`)
- `storeAs` (value, default `"imagePath"`)

Default block: `{"input":"","kind":"videoGrayscale","outputPath":"","storeAs":"imagePath"}`

#### `videoListDevices` — Video Devices

List all available video capture (camera) devices.

Params:
- `storeAs` (value, default `""`)

Default block: `{"kind":"videoListDevices","storeAs":"videoDevices"}`

#### `videoListScreens` — List Screens

Enumerate physical monitors and visible windows. Stores {monitors:[...], windows:[...]} in PREVIOUS / storeAs.

Params:
- `storeAs` (value, default `"screens"`)

Default block: `{"kind":"videoListScreens","storeAs":"screens"}`

#### `videoModelControl` — Unload Model

List or unload loaded local model instances for this xBlox process.

Params:
- `action` (value, default `"List"`)
- `key` (value, default `""`)
- `storeAs` (value, default `"modelKey"`)

Default block: `{"action":"Unload","key":"","kind":"videoModelControl","storeAs":"modelKey"}`

#### `videoResize` — Resize

Resize / resample a frame (bilinear). A 0 dimension is derived from the other to keep aspect. Pipes a frame handle in/out.

Params:
- `input` (value, default `""`)
- `width` (value, default `0`)
- `height` (value, default `0`)
- `outputPath` (value, default `""`)
- `storeAs` (value, default `"imagePath"`)

Default block: `{"height":0,"input":"","kind":"videoResize","outputPath":"","storeAs":"imagePath","width":0}`

#### `videoScreenCapture` — Screen Capture

Capture a single frame from a screen or window via GDI BitBlt. input: "screen:0", "screen:0:wintitle*". Stores output path in PREVIOUS / storeAs.

Params:
- `input` (value, default `"screen:0"`)
- `outputPath` (value, default `""`)
- `storeAs` (value, default `"imagePath"`)

Default block: `{"input":"screen:0","kind":"videoScreenCapture","outputPath":"","storeAs":"imagePath"}`

#### `videoSource` — Video Source

Pump frames from a webcam, screen/window, image, or video file. With child items it runs them once per frame (PREVIOUS = frame handle)  -  a flat pipe that transcodes a clip with no for/while and no storeAs. With no items it is a one-shot grabber emitting a handle/path in PREVIOUS / storeAs.

Params:
- `input` (value, default `""`)
- `emit` (value, default `"both"`)
- `outputPath` (value, default `""`)
- `frames` (value, default `0`)
- `durationMs` (value, default `0`)
- `progressEvery` (value, default `60`)
- `fps` (value, default `0`)
- `width` (value, default `0`)
- `height` (value, default `0`)
- `timeoutMs` (value, default `5000`)
- `storeAs` (value, default `"imagePath"`)

Default block: `{"durationMs":0,"emit":"both","fps":0,"frames":0,"height":0,"input":"","items":[],"kind":"videoSource","outputPath":"","progressEvery":60,"storeAs":"imagePath","timeoutMs":5000,"width":0}`

#### `videoStillCapture`

Alias for videoCapture (still frame capture).

Params:
- `action` (value, default `"Still"`)
- `input` (value, default `""`)
- `device` (value, default `""`)
- `instance` (value, default `""`)
- `outputPath` (value, default `""`)
- `fps` (value, default `30`)
- `bitrateKbps` (value, default `0`)
- `captureEngine` (value, default `"auto"`)
- `encoder` (value, default `"auto"`)
- `durationMs` (value, default `0`)
- `includeCursor` (value, default `true`)
- `pauseKey` (value, default `""`)
- `sizeMode` (value, default `"native"`)
- `zoom` (value, default `1`)
- `follow` (value, default `"none"`)
- `followSpeed` (value, default `0.2`)
- `followDeadzone` (value, default `3`)
- `transitionMs` (value, default `300`)
- `updateIntervalMs` (value, default `16`)
- `focusX` (value, default `-1`)
- `focusY` (value, default `-1`)
- `interactiveZoom` (value, default `false`)
- `zoomStep` (value, default `0.15`)
- `zoomMin` (value, default `1`)
- `zoomMax` (value, default `4`)
- `consumeZoomInput` (value, default `true`)
- `showZoomStatus` (value, default `true`)
- `hudCapture` (value, default `"auto"`)
- `audioSource` (value, default `"none"`)
- `audioDevice` (value, default `""`)
- `desktopDevice` (value, default `""`)
- `micGain` (value, default `1`)
- `desktopGain` (value, default `1`)
- `width` (value, default `0`)
- `height` (value, default `0`)
- `timeoutMs` (value, default `5000`)
- `storeAs` (value, default `"capturePath"`)

Default block: `{"action":"Still","device":"","height":0,"input":"","kind":"videoStillCapture","outputPath":"","storeAs":"imagePath","timeoutMs":5000,"width":0}`

#### `videoStream` — Remote Stream

Start, stop, or inspect a named remote video stream server for the mobile web remote. The current backend launches the same video stream server used by the CLI.

Params:
- `action` (value, default `"Start"`)
- `input` (value, default `"screen:0"`)
- `instance` (value, default `"default"`)
- `bind` (value, default `"0.0.0.0"`)
- `port` (value, default `8787`)
- `fps` (value, default `30`)
- `bitrateKbps` (value, default `8000`)
- `mjpegQuality` (value, default `85`)
- `includeCursor` (value, default `true`)
- `token` (value, default `""`)
- `encoder` (value, default `"auto"`)
- `open` (value, default `false`)
- `storeAs` (value, default `"stream"`)

Default block: `{"action":"Start","bind":"0.0.0.0","bitrateKbps":8000,"encoder":"auto","fps":30,"includeCursor":true,"input":"screen:0","instance":"default","kind":"videoStream","mjpegQuality":85,"open":false,"port":8787,"storeAs":"stream","token":""}`

#### `videoWriter` — Video Writer

Append a frame (handle or image path) to an .mp4. Stateful across loop iterations  -  drive it from a for/while loop or --loop run to build a video. Finalized when the run ends. Stores the output path in PREVIOUS / storeAs.

Params:
- `input` (value, default `""`)
- `outputPath` (value, default `""`)
- `fps` (value, default `0`)
- `instance` (value, default `""`)
- `storeAs` (value, default `"videoPath"`)

Default block: `{"fps":0,"input":"","instance":"","kind":"videoWriter","outputPath":"","storeAs":"videoPath"}`

### Vision

#### `visionAsk` — Vision Ask

Ask a local MiniCPM-style VLM about one or more images.

Params:
- `input` (value, default `""`)
- `frames` (value, default `[]`)
- `model` (value, default `""`)
- `slot` (value, default `"vision"`)
- `prompt` (value, default `"Describe what you see in detail."`)
- `json` (value, default `true`)
- `normalizers` (value, default `15`)
- `includeRaw` (value, default `false`)
- `threads` (value, default `8`)
- `gpuLayers` (value, default `-1`)
- `ctx` (value, default `4096`)
- `maxTokens` (value, default `512`)
- `result` (value)
- `storeAs` (value, default `"vision"`)

Default block: `{"ctx":4096,"frames":[],"gpuLayers":-1,"includeRaw":false,"input":"","items":[],"json":true,"kind":"visionAsk","maxTokens":512,"model":"","normalizers":15,"prompt":"Describe what you see in detail.","slot":"vision","storeAs":"vision","threads":8}`

#### `visionDescribe` — Vision Describe

Describe one or more images with a local MiniCPM-style VLM.

Params:
- `input` (value, default `""`)
- `frames` (value, default `[]`)
- `model` (value, default `""`)
- `slot` (value, default `"vision"`)
- `prompt` (value, default `"Describe what you see in detail."`)
- `json` (value, default `true`)
- `normalizers` (value, default `15`)
- `includeRaw` (value, default `false`)
- `threads` (value, default `8`)
- `gpuLayers` (value, default `-1`)
- `ctx` (value, default `4096`)
- `maxTokens` (value, default `512`)
- `result` (value)
- `storeAs` (value, default `"vision"`)

Default block: `{"includeRaw":false,"input":"","items":[],"json":true,"kind":"visionDescribe","normalizers":15,"prompt":"Describe what you see in detail.","storeAs":"vision"}`

#### `visionModelControl` — Unload Model

List or unload loaded local model instances for this xBlox process.

Params:
- `action` (value, default `"List"`)
- `key` (value, default `"llama:vlm"`)
- `storeAs` (value, default `"modelKey"`)

Default block: `{"action":"Unload","key":"llama:vlm","kind":"visionModelControl","storeAs":"modelKey"}`

### Supported commands in XBlox

- Registered CLI commands: `resize`, `transform`, `create`, `find`, `search`, `settings`, `provider`, `llm`, `register-explorer`, `register-startmenu`, `installer`, `service`, `batch`, `login`, `audio`, `video`, `bluetooth`, `xblox`, `test`, `status`, `commands`, `daemon`, `assistant`, `info`, `llama`, `onnx`, `hg`, `run-ipc`, `media`, `mcp`
- Custom commands from commands.json: 55
- `custom.command-mq6okpfh-b145b` — Home (app:showhome, group Home)
- `custom.command-mpx9r1ur-8c6df` — Assistant (app:togglerealtime, group Home)
- `custom.command-mpxytlpz-bcde4` — Launcher (app:togglelauncher, group Home)
- `custom.command-mpxzk7g4-67590` — Voice Recorder (cli:audio, group Home)
- `custom.command-mpxzlwc6-459a8` — Video Recorder (cli:video, group Home)
- `custom.command-mpxzouxv-ab189` — Screenshot (app:takescreenshot, group Home)
- `custom.command-mpx904lh-7da31` — Explorer (external, group Home)
- `custom.command-mq3i85bj-db474` — Share (cli:service, group Home)
- `custom.command-mq4800xa-1c3c9` — xblox-detect (cli:xblox, group Home)
- `custom.command-mppft700-137e9` — Planner Prompt (app:edit, group Home)
- `custom.command-mqauenwv-74ac8` — Mic-Journal (cli:xblox, group Home)
- `custom.assistant.realtime` — Live Voice (cli:llm, group Home)
- `custom.assistant.chat` — Chat (external, group Home)
- `custom.command-7049c0e7-674fe` — Play in VLC (external, group Images)
- `custom.command-712fbd00-f9ac4` — Product Shot (cli:transform, group Images)
- `custom.command-mpch9gdx-44982` — AI:Illustration (cli:transform, group Images)
- `custom.command-mq97rchy-5fcbf` — IllustrationX (cli:xblox, group Images)
- `custom.command-mq9a0i3l-576f4` — OCR - MD (cli:xblox, group Images)
- `custom.command-mq9azo3w-5b894` — OCR - CSV (cli:xblox, group Images)
- `custom.command-mq9b2upm-93cf4` — Vision - CSV (cli:xblox, group Images)
- `custom.command-mqj3feqz-72a1a` — Resize -HD (cli:resize, group Images)
- `custom.command-mpohmxea-c64a1` — Agent (metadata, group AI)
- `custom.command-mpi5stmy-8e9cb` — Assistant (cli:assistant, group AI)
- `custom.command-mpvpg0b7-81457` — RT-Agent-On (app:realtimestart, group AI)
- `custom.command-mpvps7tt-3f40f` — RT-Agent-Off (app:realtimestop, group AI)
- `custom.command-mpohnfaf-26b0c` — TTS (app:setVariable, group AI)
- `custom.command-mpokt0hv-41237` — Agent Type Funny (app:setVariable, group AI)
- `custom.command-mpokxo4w-0910a` — Agent Type Serious (app:setVariable, group AI)
- `custom.capture` — Capture (metadata, group Pictures)
- `custom.capture.screenshot` — Take screenshot (app:takescreenshot, group Pictures)
- ... 25 more custom commands

---

## Command variables

Custom command fields (`args`, `cwd`, `path`, `externalCommand`, `source`, `output`) support `${NAME}` substitution via `media::commands::resolve_variables` (`src/core/command_variables.cpp`).

### Environment

- `ENV:NAME` — Any process environment variable. Example: `${ENV:USERPROFILE}`, `${ENV:HOME}`. Unknown or unset names are left unchanged.

---

## Custom commands

### Advanced

#### `custom.command-mpy7w3px-8a1e0` — Log

- **Type:** button
- **Action:** app:togglelog
- **App command:** `togglelog`
- **Source:** selection

#### `custom.command-mqkxsx6y-56346` — Center

- **Type:** button
- **Action:** app:togglecenterview
- **App command:** `togglecenterview`
- **Source:** selection

#### `custom.command-mpy7z14t-bcef8` — Queue

- **Type:** button
- **Action:** app:togglequeue
- **App command:** `togglequeue`
- **Source:** selection

#### `custom.command-mqkneqp7-3fcb0` — Console

- **Type:** button
- **Action:** app:toggleconsole
- **App command:** `toggleconsole`
- **Source:** selection

#### `custom.command-mqj3lo3h-fed59` — Register Explorer

- **Type:** button
- **Action:** cli:register-explorer
- **CLI command:** `register-explorer`
- **Source:** selection

#### `custom.command-mqj4ixcu-3a87a` — Unregister Explorer (copy)

- **Type:** button
- **Action:** cli:register-explorer
- **CLI command:** `register-explorer`
- **Args:** `--unregister`
- **Source:** selection

### AI

#### `custom.command-mpohmxea-c64a1` — Agent

- **Type:** dropdown
- **Action:** metadata
- **Source:** selection

#### `custom.command-mpi5stmy-8e9cb` — Assistant

- **Type:** button
- **Action:** cli:assistant
- **CLI command:** `assistant`
- **Source:** selection

#### `custom.command-mpvpg0b7-81457` — RT-Agent-On

- **Type:** button
- **Action:** app:realtimestart
- **App command:** `realtimestart`
- **Source:** selection

#### `custom.command-mpvps7tt-3f40f` — RT-Agent-Off

- **Type:** button
- **Action:** app:realtimestop
- **App command:** `realtimestop`
- **Source:** selection

#### `custom.command-mpohnfaf-26b0c` — TTS

- **Type:** button
- **Action:** app:setVariable
- **App command:** `setVariable`
- **Source:** selection

#### `custom.command-mpokt0hv-41237` — Agent Type Funny

- **Type:** button
- **Action:** app:setVariable
- **App command:** `setVariable`
- **Source:** selection

#### `custom.command-mpokxo4w-0910a` — Agent Type Serious

- **Type:** button
- **Action:** app:setVariable
- **App command:** `setVariable`
- **Source:** selection

### Files

#### `custom.dropdown-mpqpdwuo-1affa` — Tests

- **Type:** dropdown
- **Action:** metadata
- **Source:** selection

#### `custom.command-75e6fd77-7c119` — Open

- **Type:** button
- **Action:** external
- **External:** mode `argv`
  - command: `explorer.exe`
  - args: `${CURRENT_FILE}`
- **Source:** selection

#### `custom.command-7122e2c3-65657` — Render to STL

- **Type:** button
- **Action:** external
- **External:** mode `argv`
  - command: `C:\Program Files\OpenSCAD\openscad.exe`
  - args: `-o` `${CURRENT_PATH}${PATH_SEP}${SRC_NAME}.stl` `${CURRENT_FILE}`
- **Source:** selection

#### `custom.command-7124c298-24a2a` — Open in FreeCAD

- **Type:** button
- **Action:** external
- **External:** mode `argv`
  - command: `C:\Program Files\FreeCAD 1.0\bin\FreeCAD.exe`
  - args: `${CURRENT_FILE}`
- **Source:** selection

#### `custom.command-70e693c3-290ff` — Open in Explorer

- **Type:** button
- **Action:** external
- **External:** mode `argv`
  - command: `explorer`
  - args: `/select` `${CURRENT_FILE}`
- **Source:** selection

#### `custom.command-mpcmqepq-ee6f3` — AI:Images List

- **Type:** button
- **Action:** cli:llm
- **CLI command:** `llm`
- **Args:** `agent` `--prompt` `create directory listing, for images, in images.md`
- **CWD:** `${CURRENT_PATH}`
- **Log level:** `trace`
- **Source:** selection
- **Explorer menu:** yes

### Home

#### `custom.command-mq6okpfh-b145b` — Home

- **Type:** button
- **Action:** app:showhome
- **App command:** `showhome`
- **Source:** selection

#### `custom.command-mpx9r1ur-8c6df` — Assistant

- **Type:** button
- **Action:** app:togglerealtime
- **App command:** `togglerealtime`
- **Source:** selection

#### `custom.command-mpxytlpz-bcde4` — Launcher

- **Type:** button
- **Action:** app:togglelauncher
- **App command:** `togglelauncher`
- **Source:** selection

#### `custom.command-mpxzk7g4-67590` — Voice Recorder

- **Type:** button
- **Action:** cli:audio
- **CLI command:** `audio`
- **Args:** `record` `--dst` `${KNOWNFOLDER:Desktop}/last_mic.wav` `--text-out` `${KNOWNFOLDER:Desktop}/mic_last.md`
- **Source:** selection

#### `custom.command-mpxzlwc6-459a8` — Video Recorder

- **Type:** button
- **Action:** cli:video
- **CLI command:** `video`
- **Args:** `record` `--dst` `C:\Users\zx\Desktop\1.mp4`
- **CWD:** `${KNOWNFOLDER:Desktop}`
- **Source:** selection

#### `custom.command-mpxzouxv-ab189` — Screenshot

- **Type:** button
- **Action:** app:takescreenshot
- **App command:** `takescreenshot`
- **Source:** selection

#### `custom.command-mpx904lh-7da31` — Explorer

- **Type:** button
- **Action:** external
- **External:** mode `argv`
  - command: `explorer`
  - args: `${CURRENT_FILE}`
- **Source:** selection

#### `custom.command-mq3i85bj-db474` — Share

- **Type:** button
- **Action:** cli:service
- **CLI command:** `service`
- **Args:** `files` `upload` `${CURRENT_FILE}`
- **Log level:** `trace`
- **Source:** selection
- **Explorer menu:** yes

#### `custom.command-mq4800xa-1c3c9` — xblox-detect

- **Type:** button
- **Action:** cli:xblox
- **CLI command:** `xblox`
- **Args:** `run` `--src` `C:\Users\zx\Desktop\pixlwiz\pixlwiz\tests\xblox\agent-args.xblox` `--type` `2` `--x` `0` `--ctx` `${CURRENT_PATH}`
- **CWD:** `C:\Users\zx\Desktop\pixlwiz\pixlwiz`
- **Log level:** `trace`
- **Source:** selection
- **Explorer menu:** yes

#### `custom.command-mppft700-137e9` — Planner Prompt

- **Type:** button
- **Action:** app:edit
- **App command:** `edit`
- **Args:** `${KNOWNFOLDER:Config}/prompts/planner-prompt.md`
- **Source:** selection

#### `custom.command-mqauenwv-74ac8` — Mic-Journal

- **Type:** button
- **Action:** cli:xblox
- **Tooltip:** tooltip
- **CLI command:** `xblox`
- **Args:** `run` `--src` `C:\Users\zx\Desktop\pixlwiz\pixlwiz\tests\xblox\stt-journal-ex.xblox` `--CURRENT_FILE` `${CURRENT_FILE}`
- **CWD:** `${CURRENT_PATH}`
- **Log level:** `trace`
- **Source:** files
- **Explorer menu:** yes

#### `custom.assistant.realtime` — Live Voice

- **Type:** button
- **Action:** cli:llm
- **Tooltip:** Live speech-to-speech voice session (closes with the assistant bar)
- **CLI command:** `llm`
- **Args:** `agent` `--realtime`
- **Source:** selection

#### `custom.assistant.chat` — Chat

- **Type:** button
- **Action:** external
- **Tooltip:** Open the chat window
- **External:** mode `argv`
  - command: `pm-image.exe`
  - args: `--ui-preset` `chat`
- **Source:** selection

### Images

#### `custom.command-7049c0e7-674fe` — Play in VLC

- **Type:** button
- **Action:** external
- **External:** mode `argv`
  - command: `C:\Program Files\VideoLAN\VLC\vlc.exe`
  - args: `${CURRENT_FILE}`
- **Source:** selection
- **Explorer menu:** yes

#### `custom.command-712fbd00-f9ac4` — Product Shot

- **Type:** button
- **Action:** cli:transform
- **CLI command:** `transform`
- **Args:** `--prompt` `render this as product shooting, white background, studio` `--json` `--reference` `${CURRENT_FILE}`
- **CWD:** `${CURRENT_PATH}`
- **Source:** selection

#### `custom.command-mpch9gdx-44982` — AI:Illustration

- **Type:** button
- **Action:** cli:transform
- **Tooltip:** tooltip
- **CLI command:** `transform`
- **Args:** `--src` `${CURRENT_FILE}` `--prompt` `as technical illustration` `--provider` `replicate` `--model` `google/gemini-2.5-flash` `--job-ui`
- **CWD:** `${CURRENT_PATH}`
- **Log level:** `trace`
- **Source:** files
- **Explorer menu:** yes

#### `custom.command-mq97rchy-5fcbf` — IllustrationX

- **Type:** button
- **Action:** cli:xblox
- **Tooltip:** tooltip
- **CLI command:** `xblox`
- **Args:** `run` `--src` `C:\Users\zx\Desktop\pixlwiz\pixlwiz\tests\xblox\image-pipe-blocks.xblox` `--CURRENT_FILE` `${CURRENT_FILE}`
- **CWD:** `${CURRENT_PATH}`
- **Source:** files
- **Explorer menu:** yes

#### `custom.command-mq9a0i3l-576f4` — OCR - MD

- **Type:** button
- **Action:** cli:xblox
- **Tooltip:** tooltip
- **CLI command:** `xblox`
- **Args:** `run` `--src` `C:\Users\zx\Desktop\pixlwiz\pixlwiz\tests\xblox\ocr-pipe.xblox` `--CURRENT_FILE` `${CURRENT_FILE}`
- **CWD:** `${CURRENT_PATH}`
- **Log level:** `trace`
- **Source:** files
- **Explorer menu:** yes

#### `custom.command-mq9azo3w-5b894` — OCR - CSV

- **Type:** button
- **Action:** cli:xblox
- **Tooltip:** tooltip
- **CLI command:** `xblox`
- **Args:** `run` `--src` `C:\Users\zx\Desktop\pixlwiz\pixlwiz\tests\xblox\ocr-pipe-csv.xblox` `--CURRENT_FILE` `${CURRENT_FILE}`
- **CWD:** `${CURRENT_PATH}`
- **Log level:** `trace`
- **Source:** files
- **Explorer menu:** yes

#### `custom.command-mq9b2upm-93cf4` — Vision - CSV

- **Type:** button
- **Action:** cli:xblox
- **Tooltip:** tooltip
- **CLI command:** `xblox`
- **Args:** `run` `--src` `C:\Users\zx\Desktop\pixlwiz\pixlwiz\tests\xblox\vision-pipe.xblox` `--CURRENT_FILE` `${CURRENT_FILE}`
- **CWD:** `${CURRENT_PATH}`
- **Log level:** `trace`
- **Source:** files
- **Explorer menu:** yes

#### `custom.command-mqj3feqz-72a1a` — Resize -HD

- **Type:** button
- **Action:** cli:resize
- **Tooltip:** tooltip
- **CLI command:** `resize`
- **Args:** `run` `--CURRENT_FILE` `${CURRENT_FILE}` `--max-width` `800` `--src` `${CURRENT_SELECTION}` `--format` `jpg` `--cache-dir` `${ENV:PIXLWIZ}/cache/images` `--dst` `${SRC_DIR}/${SRC_NAME}_hd.jpg`
- **Log level:** `info`
- **Source:** files
- **Explorer menu:** yes

### Pictures

#### `custom.capture` — Capture

- **Type:** dropdown
- **Action:** metadata
- **Tooltip:** Session and screenshot examples

#### `custom.capture.screenshot` — Take screenshot

- **Type:** button
- **Action:** app:takescreenshot
- **App command:** `takescreenshot`
- **Args:** `${KNOWNFOLDER:Profile}`

#### `custom.command-mpx9ka63-c756f` — Picker

- **Type:** button
- **Action:** cli:assistant
- **CLI command:** `assistant`
- **Args:** `pick` `${KNOWNFOLDER:Profile}`

#### `custom.command-mpi5b1hw-8bdc2` — browse

- **Type:** button
- **Action:** ribbon:appSettings
- **Ribbon command:** `appSettings`
- **Args:** `C:\Users\zx\AppData\Roaming\PolyMech\pm-image`
- **Source:** selection

#### `custom.mic-start` — Mic Capture Start

- **Type:** button
- **Action:** cli:audio
- **Tooltip:** Mic Start Now - Tool Tip
- **CLI command:** `audio`
- **Args:** `record` `--text-out` `${KNOWNFOLDER:Config}/last.md`
- **Log level:** `trace`
- **Source:** selection

#### `custom.mic-stop` — Mic Capture Stop

- **Type:** button
- **Action:** cli:audio
- **CLI command:** `audio`
- **Args:** `record` `stop`
- **Source:** selection

#### `custom.video-start` — Video Capture Start

- **Type:** button
- **Action:** cli:video
- **CLI command:** `video`
- **Args:** `record` `--dst` `${KNOWNFOLDER:Videos}/capture.avi`
- **Log level:** `trace`
- **Source:** selection

#### `custom.video-stop` — Video Capture Stop

- **Type:** button
- **Action:** cli:video
- **CLI command:** `video`
- **Args:** `record` `stop`
- **Source:** selection

#### `custom.video-status` — Video Capture Status

- **Type:** button
- **Action:** cli:video
- **CLI command:** `video`
- **Args:** `record` `status`
- **Source:** selection

#### `custom.tools` — Tools

- **Type:** dropdown
- **Action:** metadata
- **Tooltip:** Built-in ribbon command examples

#### `custom.tools.theme` — Toggle theme

- **Type:** button
- **Action:** ribbon:theme
- **Ribbon command:** `theme`

#### `custom.tools.resetLayout` — Reset layout

- **Type:** button
- **Action:** ribbon:resetLayout
- **Ribbon command:** `resetLayout`

#### `custom.command-70c82b28-65412` — Open in VSCode

- **Type:** button
- **Action:** external
- **External:** mode `argv`
  - command: `code`
- **Source:** selection

#### `undefined-mpq42hgj-93f53` — Open in Cursor(copy)

- **Type:** button
- **Action:** external
- **External:** mode `shell`
  - command: `cursor`
  - shell: `explorer ${CURRENT_FILE}`
- **Source:** selection

### Text

#### `custom.command-70eabea6-957e6` — Translate to Spanish

- **Type:** button
- **Action:** cli:llm
- **CLI command:** `llm`
- **Args:** `agent` `--embed` `${CURRENT_FILE}` `--prompt` `Translate to Spanish` `--no-mcp` `--preset` `quick` `--no-planner` `--no-tools` `--no-parallel-tools` `--dst` `${SRC_DIR}/${SRC_NAME}_ex.${SRC_EXT}`
- **Log level:** `trace`
- **Source:** selection
- **Explorer menu:** yes

