Install the command-line tool for creating apps.
Prerequisites
For Python Apps: uv
The CLI uses uv for Python environment management:
1curl -LsSf https://astral.sh/uv/install.sh | sh23# Windows4powershell -ExecutionPolicy ByPass -c "irm https://astral.sh/uv/install.ps1 | iex"For Node.js Apps: Node.js
Node.js v20 or later:
1# macOS / Linux (via fnm)2curl -fsSL https://fnm.vercel.app/install | bash3fnm install 2245# Or via nvm6curl -o- https://raw.githubusercontent.com/nvm-sh/nvm/v0.40.0/install.sh | bash7nvm install 22Hardware
| App Type | Development Environment |
|---|---|
| CPU apps | Any machine |
| GPU apps | Requires NVIDIA CUDA GPU |
Install CLI
1curl -fsSL cli.inference.sh | shOr via package managers:
1brew install inference-sh/tap/belt # macOS / Linux2npx @inferencesh/belt # Node.js3scoop bucket add inference https://github.com/inference-sh/scoop-bucket && scoop install belt # WindowsCommand name
The same CLI is available as belt, infsh, and inferencesh (package installs may expose one or all of these names). Subcommands are identical:
1belt version2infsh version # same CLIConnector and MCP examples in this documentation often use belt. App development examples use infsh. Either prefix works.
Verify
1infsh versionUpdate CLI
1belt update # or: infsh updateShell installer (curl … | sh): belt update downloads and replaces the binary in place.
Homebrew or Scoop: the CLI detects package-manager installs and refuses to self-update over a managed binary. Run the manager's command instead:
1brew upgrade belt # Homebrew2scoop update belt # ScoopIf you installed with brew install inference-sh/tap/belt or scoop install belt, belt update prints the matching command when an upgrade is available.
Auto-update runs in the background on most commands. It is skipped for belt version, belt update, and help flags. Set INFSH_NO_AUTOUPDATE=1 to disable automatic upgrades.
Login
1infsh login2belt login --key inf_… # non-interactive: skip browser flow (CI, scripts)Opens a browser for device authorization in interactive terminals. In non-interactive shells (no TTY, CI set, or BELT_NON_INTERACTIVE=1), pass --key or set INFSH_API_KEY instead.
Credentials are stored in ~/.inferencesh/config.json with 0600 permissions (owner read/write only).
Check your account
1infsh me2belt me --json # same payload as GET /me — for scripts and automationShows your username and team. When a team override is active, belt me prints a hint to use belt auth switch.
With --json, stdout is compact JSON for the GET /me response (user and team objects). Use --pjson for indented output. See Teams API — Get current user. On failure, stdout is a JSON error object (same as other --json / --pjson commands); stderr still has the formatted message.
Balance: belt balance is a top-level alias for belt me balance (agents often try belt balance first). It prints your team's current balance and nudges you to top up when below $5. Use --json for {"balance": <microcents>, "balance_dollars": <float>}.
1belt balance2belt me balance --jsonRequires billing:read scope (included in standard API keys). See Billing API.
Switch teams
If you belong to multiple teams, switch the active team context for all CLI commands:
1belt auth switch # interactive team picker2belt auth switch my-org # switch directly by team username3belt auth sw my-org # aliasThe CLI stores the override in ~/.inferencesh/config.json and sends it as the X-Team-ID header on API requests. Switching back to your default team clears the override.
Print API key for scripts
1belt auth tokenPrints the stored API key to stdout with no trailing newline — for subshells, curl, and shell scripts:
1curl -H "Authorization: Bearer $(belt auth token)" https://api.inference.sh/me2export INFSH_API_KEY=$(belt auth token)Requires belt login first (or INFSH_API_KEY set in the environment). When not logged in, errors go to stderr and stdout stays empty.
What you can do
Development
| Command | Purpose |
|---|---|
infsh app init | Create a new app |
infsh app test | Test locally |
infsh app deploy | Deploy to inference shell |
Running Apps
| Command | Purpose |
|---|---|
infsh app run | Run an app in the cloud |
infsh app sample | Generate sample input (file fields use ./your-file.jpg placeholders) |
For multi-function apps, belt app sample defaults to the resolved default function (run, explicit default_function, or the sole function). Use -f / --function for other entry points. belt app get lists all functions with run/sample hints.
When an app is missing required secrets or integrations, infsh app run (and belt agent run) prints categorized setup hints instead of a generic API error — for example belt secrets set <KEY> <VALUE> or belt integrations connect <provider>. MCP requirements suggest belt mcp connect <slug>. The same requirement shape is returned by POST /run as HTTP 412 — see Check requirements.
JSON input — belt app run, belt mcp run, and belt flow run resolve input from three sources, in priority order: --input / -i flag → positional argument → piped stdin (when stdin is not a TTY). Each source accepts inline JSON ('{"prompt": "a cat"}'), @filename, or a path to an existing JSON file.
1belt app run namespace/my-app '{"prompt": "a cat"}' # positional2echo '{"prompt": "a cat"}' | belt app run namespace/my-app # stdin3belt mcp run linear:list_issues '{"project": "INF"}' # positional4belt flow run abc123 --input '{"text":"hello"}' -f # flag (unchanged)Omit input entirely when the app, tool, or flow does not require it.
Filter output (--jq) — belt app run and belt mcp run accept --jq with a jq expression to filter JSON on stdout without piping to an external jq binary (the CLI embeds the same pure-Go engine GitHub CLI uses). String results are printed unquoted (like jq -r); other values are compact JSON, one per line.
1belt mcp run linear:list_issues --jq '.issues[] | {id, title}'2belt app run okaris/flux -i '{"prompt": "a cat"}' --jq '.output.url'3belt app run okaris/flux -i '{"prompt": "a cat"}' --no-wait --jq '.id' # task id onlybelt app run --jq evaluates against the task object (id, status, status_text, output, error, session_id, created_at, updated_at). App outputs live under .output — for example .output.url for a generated file URL. --jq suppresses progress lines on stdout (same as --json). Use --json or --pjson when you need the full task or tool payload instead.
Managing Apps
| Command | Purpose |
|---|---|
belt app list | List your deployed apps (--search, --limit, --cursor, --json; infsh app my / infsh app list aliases) |
belt app store | Browse the public app store (--featured, --category, --new, --limit, --cursor, --json, --save) |
infsh app search | Search apps by name or description |
belt suggest <query> | Unified discovery (apps, skills, knowledge, docs) |
infsh app get | Get app details |
infsh app pull | Download or sync an app |
Programmatic listing:
1belt app list --json # your deployed apps (requires login)2belt app list --search "flux" --json3belt app list --limit 50 --cursor <next> # cursor pagination (see hints in table output)4belt app store --json # public store with cursor pagination metadata5belt app store search "video" --category video --json6belt app store --save store-snapshot.json # write JSON to file instead of stdoutbelt app list --json prints the full cursor-list response from POST /apps/list (items as AppDTO[], plus next_cursor, has_next, total_items, …). belt app store --json prints the same cursor-list shape from POST /store/apps/list (items as PublicAppStoreDTO[]) — see List approved apps. In table output, both commands print next page: / prev page: hints with the --cursor value when more results exist. --save writes the store payload to a file (always pretty-printed) and prints a confirmation line to stdout.
infsh app pull syncs app code and metadata from inference shell:
1infsh app pull # sync current app (from inf.yml in cwd)2infsh app pull --meta # sync inf.yml metadata only (no code)3infsh app pull <app-id> # download app by ID to namespace/name/4infsh app pull --all # sync every local app (finds inf.yml recursively)5infsh app pull <app-id> --force # overwrite existing directory without promptPulled apps write namespace, name, and other metadata into inf.yml so deploy and run commands resolve the correct namespace/name ref.
When syncing an existing directory, the CLI removes old app files before extracting the new archive but preserves local environment and VCS paths: .git, .env, .infsh, .venv, venv, node_modules, and __pycache__.
belt app get shows schemas, pricing, and run/sample hints for an app ref (namespace/name, namespace/name@version-id, or app ID). With --json, stdout is {"app": <AppDTO>, "pricing": ...} from GET /apps/{ref}.
1belt app get okaris/flux2belt app get okaris/flux@abc123 --versions # version history3belt app get okaris/flux --json # includes status fields for scriptsWhen lifecycle status is not active, human-readable output shows a banner after the description:
| Status | Display | Run hints |
|---|---|---|
deprecated | ⚠ deprecated (warning) plus optional status_message | Shown — app still accepts runs |
maintenance | ⚙ under maintenance (warning) plus optional status_message | Omitted — the banner already indicates runs are unavailable |
retired | ✕ retired (error) plus optional status_message | Omitted — the banner already indicates runs are unavailable |
belt app run against a maintenance or retired app returns API errors (503 app_maintenance, 410 app_retired) — see Tasks API. Use belt app get before scripting runs to check status and the owner's message (for example, a replacement app ref).
belt suggest calls the same discovery API as GET /suggest. Results include a suggested CLI command or URL for each hit:
1belt suggest "flux image"2belt suggest "web search" --json # JSON for agent hooks3belt suggest "deploy" --agent # full descriptions from API (agent: true)With no arguments, belt suggest reads stdin (hook JSON or plain text). CLI args take precedence over stdin.
Human-readable output groups results by category (app, skill, knowledge, and so on). Each section header shows the category and a command template (for example belt skill use <name>). Result lines include an optional inline [tag], the name, and description. After a cross-collection search, stderr may suggest scoped follow-ups such as belt app suggest "...".
Hook mode (--json): Returns hookSpecificOutput.additionalContext with one line per match: - [type] name — description, then run: <command> on the next line. Results are ranked by score and deduped server-side. Hook stdin is JSON with a prompt field (or plain text). When transcript_path is present, belt extracts assistant text from the current turn (since the last user message, up to 1000 characters) and sends it as the context field to POST /suggest for semantic ranking — keyword matching still uses prompt only. Belt also sends scope signals from the current directory (git: remote, lang:, module:, and similar tags) on every suggest call so knowledge captured in the same repo or language ranks higher. API failures are silent in --json mode so hooks do not pollute agent stderr.
Use --agent to send agent: true in the suggest request body (full descriptions, no 200-rune truncation). Hook integrations installed via belt plugin init <agent> call belt suggest --json automatically.
belt suggest also sends scope tags from the current working directory (git remote, module name, language, path) so project-relevant knowledge ranks higher in results. Entries uploaded with belt know upload carry the same tags unless you used --global.
Use infsh app search when you only need apps. Use belt suggest for cross-collection discovery (skills, knowledge, docs, and apps).
Secrets
| Command | Purpose |
|---|---|
infsh secrets list | List all secrets (--json) |
infsh secrets set <key> <value> | Create or update a secret |
infsh secrets get <key> | Get a secret (masked) |
infsh secrets delete <key> | Delete a secret |
Connectors (MCP)
| Command | Purpose |
|---|---|
belt mcp list | Browse MCP connector servers (--category, --featured, --json) |
belt mcp search <query> | Search servers by name or description (same filters as list) |
belt mcp get <slug> | Show server details and connection status |
belt mcp connect <slug> | Connect OAuth for a server |
belt mcp refresh <slug> | Re-run discovery and enrichment on a server |
belt mcp tools <slug> | List tools on a connected server (slug:tool to show one tool's schema) |
belt mcp run <slug>:<tool> | Call a connector tool from the terminal (<slug> alone lists tools, same as mcp tools) |
belt mcp run and belt mcp tools use slug:tool format — the first colon splits the server slug from the tool name (for example linear:list_issues). Pass only the slug to belt mcp run to list available tools instead of calling one. If you mistype an MCP subcommand, the CLI prints this format hint. After belt mcp list, stderr may show tips for belt mcp search, get, and connect.
→ Connectors overview · Browsing connectors
Integrations (CLI)
List, connect, and inspect OAuth, service account, and MCP connections for your team:
| Command | Purpose |
|---|---|
belt integrations list | List connected integrations (--json for raw API payload) |
belt integrations get <provider> | Show one integration by provider key (--json for scripts) |
belt integrations connect <provider> | Connect a native provider (OAuth or service account) |
belt integrations disconnect <provider> | Remove a team connection |
1belt integrations list2belt integrations get google3belt integrations get mcp:mcp.linear.app --json # includes integration id for agent tools4belt integrations connect google5belt integrations connect slack6belt integrations disconnect googlebelt integrations connect looks up the provider in GET /integrations/configs, opens your browser for OAuth when needed, and polls for up to two minutes. If the provider is already connected, the CLI prints the account and suggests disconnecting first. Unknown providers list available options; for MCP servers, use belt mcp connect <slug> instead.
Google OAuth and the managed service account are separate providers (google vs google-sa). Connect the service account from Settings → Integrations (google-sa slug) or with belt integrations connect google-sa.
Non-interactive OAuth (CI, scripts): When stderr is not a TTY, CI is set, or BELT_NON_INTERACTIVE=1, belt integrations connect prints the authorization URL but does not open a browser or poll. Open the URL manually, then verify with belt integrations get <provider>.
Provider keys match the REST API: google, google-sa, gcp, slack, mcp:mcp.linear.app, and so on. MCP servers use compound names (mcp:{hostname}) because each connection is a separate instance. Use belt integrations get --json when you need the integration id for agent connector tools.
→ Integrations API · Connectors overview
Flows (CLI)
Create, edit, run, and publish flows from the terminal — same APIs as Flows and Flow Runs.
| Command | Purpose |
|---|---|
belt flow create --name <name> | Create an empty flow (--json for raw response) |
belt flow list | List your flows (ls alias; --json) |
belt flow get <id> | Show flow metadata (--json) |
belt flow describe <id> | Show the full graph with node I/O fields and connections |
belt flow duplicate <id> | Copy a flow (dup / cp aliases) |
belt flow delete <id> | Delete a flow |
belt flow run <id> | Start a flow run (--input JSON, -f to stream progress) |
belt flow runs | List recent flow runs (--limit, --json) |
belt flow run-get <run-id> | Get run status and output (-f to follow until complete) |
belt flow cancel <run-id> | Cancel a running flow |
belt flow publish <id> | Deploy the flow as a standalone app |
Graph editing — belt flow edit applies draft mutations via POST /flows/{id}/actions:
| Command | Purpose |
|---|---|
belt flow edit node add <id> <name> --app <ref> | Add an app node (resolves namespace/name to app ID) |
belt flow edit node rm <id> <name> | Remove a node |
belt flow edit node inspect <id> <name> | Show input/output fields with types and defaults |
belt flow edit node set-input <id> <name> <key> [value] | Set a static value or --from node:key connection |
belt flow edit node clear-input <id> <name> <key> | Clear an input value or connection |
belt flow edit edge add <id> <source> <target> | Add a structural edge between nodes |
belt flow edit edge rm <id> <source> <target> | Remove an edge |
belt flow edit output set <id> <field> --from <node>:<key> | Map a node output to the flow output |
belt flow edit output rm <id> <field> | Remove an output mapping |
belt flow edit set-schema <id> --input '...' --output '...' | Set flow-level input/output JSON Schema (type must be "object"; see Flows API) |
belt flow edit actions <id> [json] | Apply raw action JSON (escape hatch for uncovered mutations) |
1belt flow create --name voice-pipeline2belt flow edit node add abc123 tts --app elevenlabs/tts3belt flow edit node set-input abc123 tts text "hello world"4belt flow edit node set-input abc123 voice-changer audio --from tts:audio5belt flow edit output set abc123 audio --from voice-changer:audio6belt flow describe abc1237belt flow run abc123 -f8belt flow publish abc123Use input as the source node in --from to wire a node input to a flow-level input (for example --from input:text). belt flow run -f streams NDJSON progress events with polling fallback when SSE is unavailable.
→ Flows guide · Creating a flow · Flows API · Flow Runs API
Agent integration (CLI)
Wire belt into a local coding agent runtime (discovery hooks and core skills):
| Command | Purpose |
|---|---|
belt plugin init claude | Install belt plugin for Claude Code (marketplace; patches cached hook shims after install) |
belt plugin init codex | Install belt plugin for OpenAI Codex (requires Codex CLI) |
belt plugin init cursor | Install belt skills and hooks for Cursor |
belt plugin init gemini | Install belt skills and hooks for Gemini CLI |
belt plugin init opencode | Install belt skills and OpenCode plugin (npm install + opencode plugin --global when CLI is on PATH) |
belt plugin init pi | Install belt skills and Pi TypeScript extension (pi install when Pi CLI is on PATH) |
belt plugin init windsurf | Install belt skills and hooks for Windsurf |
belt plugin info | Show belt plugin capabilities and install status |
belt plugin doctor | Check Claude Code belt plugin health (--fix to auto-repair stale caches and hook shims; lists each fix and prompts restart) |
belt plugin history | Import knowledge from Claude Code conversation history |
belt review --agent <name> | Extract knowledge from agent sessions (hook command) |
belt review is called by Stop and PreCompact hooks installed via belt plugin init <agent>. Claude Code plugin hooks call belt plugin review instead. It reads hook JSON from stdin, evaluates the session transcript, and saves reusable knowledge to your workspace.
1belt review --agent cursor --trigger stop # called by Cursor Stop hook2belt plugin review --trigger stop # called by Claude Code Stop hook3belt review --agent claude-code --trigger stop # same pipeline as belt plugin review4belt review --agent codex --dry-run # preview without saving5belt review --agent cursor --force # skip 10-turn gating| Flag | Purpose |
|---|---|
--agent | Runtime: claude-code, codex, cursor, gemini, or windsurf (defaults to claude-code) |
--trigger | Hook that invoked review: stop, precompact, or session-end (default stop) |
--force | Run immediately instead of every 10 user turns on Stop |
--dry-run | Print extraction results without saving |
Claude Code uses fork-based extraction and can auto-publish skills. Other agents use transcript-based extraction through the inference shell API. Requires belt login.
→ Coding agents — skills directories, hook behavior, and Claude Code details
Agents (CLI)
| Command | Purpose |
|---|---|
belt agent create <name> [description] | Create an agent from flags (no YAML file) |
belt agent deploy <path> | Create or update an agent from a YAML definition |
belt agent list | List your agents |
belt agent get <ref> | Show agent details (version, tools, skills, context) |
belt agent delete <ref> | Delete an agent (rm alias) |
belt agent run <ref> "<message>" | Run an agent from the terminal |
belt agent run <ref> "<message>" --chat <id> | Continue an existing chat |
belt agent run <ref> "<message>" --no-wait | Return chat ID immediately (use belt chat to follow up) |
belt agent run <ref> "<message>" --timeout <duration> | Max wait for response (default 4m; e.g. 10m) |
belt agent create calls POST /agents with a first version. Use it for quick agents from the terminal; use belt agent deploy when you need skills, context fields, output schema, or other YAML-only options.
Redeploying the same agent name creates a new version instead of failing with a name conflict — the same upsert behavior as infsh app deploy. The namespace is assigned from your logged-in team server-side, so the namespace field in YAML is optional. You only need a stable name in the file to update an existing agent.
1belt agent create my-helper "A helpful assistant"2belt agent create todo-bot --model openrouter/claude-sonnet-46 --prompt "You manage Todoist tasks"3belt agent create todo-bot --model openrouter/claude-sonnet-46 \4 --mcp 46e8a4bq...:find-projects \5 --mcp 46e8a4bq...:add-tasks6belt agent create my-bot --json # raw AgentDTO on stdout| Flag | Purpose |
|---|---|
--model | Core app ref (e.g. openrouter/claude-sonnet-46) |
--prompt | System prompt |
--mcp | MCP tool as integration_id:tool_name (repeatable). Find integration IDs after belt mcp connect — see Connector tools on agents; list tool names with belt mcp tools <slug> |
--json | Output the created agent as JSON |
On success, the CLI prints namespace/name@version-id for use with belt agent run.
belt agent get accepts the same refs as belt agent run — namespace/name, namespace/name@version-id, or agent ID. With --json, stdout is the full AgentDTO from GET /agents/{ref}.
1belt agent get myteam/support-bot2belt agent get myteam/support-bot@latest3belt agent get agent_abc123Human-readable output uses lowercase labels and lists attached skills with their resolved ref and version pin:
1 agent: myteam/support-bot2 version: abc1233 description: Handles customer support4 system prompt: You are a helpful support agent...5 core app: openrouter/claude-sonnet-4667 tools:8 - search (call): Search the web910 skills:11 - myteam/pricing-rules@ver_xyz: Pricing guidelines1213 context:14 - tenant_id (required): Tenant identifierEach skill line shows skill_id@version_id when the agent pins a specific skill version; otherwise it falls back to the skill name from the agent definition. System prompts longer than 200 characters are truncated.
With --no-wait, the CLI returns as soon as the run is accepted. Without --json, it prints Chat started: <chat-id> with muted belt chat get / belt chat pending hints. With --json --no-wait, stdout is only {"chat_id": "<id>"} — use this in scripts that poll with belt chat get or belt chat watch.
Without --no-wait, belt agent run streams chat events until the agent finishes, needs approval, or hits --timeout (default 4m). On timeout, the CLI prints the chat ID so you can follow up with belt chat get or belt chat pending. With --json (and no --no-wait), stdout is the full POST /agents/run response after streaming completes. Tool calls print as muted progress lines while they run:
1→ calling search...2→ search completedFailed tools print → {name} failed. The final assistant message is printed when the run completes. After a successful run, the CLI prints a muted continuation hint with the chat ID — use belt chat send <chat-id> "<message>" for follow-ups without starting a new run.
Chat (CLI)
Manage agent conversations and human-in-the-loop approvals from the terminal:
| Command | Purpose |
|---|---|
belt chat list | List chats (--status busy, awaiting_input, idle, completed); prints a continuation hint below the table |
belt chat get <chat-id> | Show transcript and pending tool invocations (--last N, --all, --full) |
belt chat send <chat-id> "<message>" | Send a follow-up message |
belt chat watch <chat-id> | Stream until idle or another approval is needed |
belt chat pending | List tool invocations awaiting approval |
belt chat approve <invocation-id> | Approve HIL tool (--watch / -w to stream the response) |
belt chat reject <invocation-id> | Reject (--reason "...") |
belt chat stop <chat-id> | Stop a running chat |
When belt agent run stops at awaiting_input, the CLI prints belt chat approve / reject commands for each pending invocation.
belt chat get shows the last 3 messages by default. Use --last N for more, --all for the full transcript, or --full to disable truncation of message text and tool argument JSON (default truncates at 200 and 100 characters respectively). Pending tool invocations always show full args and an approve: hint.
→ Agents REST API · Approval settings · Human-in-the-loop
Skills (CLI)
Refs use namespace/name or namespace/name@version-id (same as the REST API). belt skill use without a version fetches the latest.
| Command | Purpose |
|---|---|
belt skill list | List your uploaded skills (--json; table includes relative updated times) |
belt skill upload <path> | Publish or update a skill from a local directory |
belt skill use <ref> | Print a skill's instructions to stdout |
belt skill add <ref> | Install a skill into your workspace |
belt skill files <ref> | List supporting files (references, scripts, examples) |
belt skill view <ref> <path> | View one supporting file |
belt skill versions <namespace>/<name> | List version history (version ID, date, notes) |
belt skill supersede <old> <new> | Mark an outdated skill as superseded by a replacement |
belt skill use does not inline supplementary files. When a skill has extra files, stderr prints tips for belt skill add and belt skill files.
belt skill versions requires belt login — it resolves the skill by name, then calls GET /knowledge/{id}/versions. The table marks the current version at the bottom.
belt skill supersede requires belt login. Both arguments are namespace/name refs or skill IDs. The old skill is hidden from belt suggest and other discovery results; the replacement skill is unchanged. Use this when you publish a replacement under a new name instead of versioning in place.
1belt skill versions myteam/code-review2belt skill use myteam/code-review@abc123 # specific version3belt skill supersede myteam/old-review myteam/code-review→ Skill registry · Supersede Skill API · Search concept · Search API · Knowledge API — versions
Knowledge (CLI)
belt know is an alias for belt knowledge. Refs use namespace/name or namespace/name@version-id (same as the REST API). The CLI sends X-API-Version: 2 on API calls automatically.
| Command | Purpose |
|---|---|
belt know list | List entries (--type, --search, --json, pagination) |
belt know search <query> | Search your knowledge entries |
belt know get <ref> | Show metadata, file list, and instructions (up to 64KB) |
belt know upload <path> | Upload a directory, file, or stdin (--type, --name, --global) |
belt know delete <id> | Delete an entry |
1belt know list --type observation2belt know get acme/onboarding # latest version (no login for public entries)3belt know get acme/onboarding@abc123 # specific version4belt know upload ./my-skill/ # directory with SKILL.md → skill5belt know upload ./notes.md --type reference6belt know upload ./notes.md --global # skip project scope tagsBy default, belt know upload attaches project scope tags from the working directory (git remote, module name, language, path) so /suggest can rank the entry higher in matching projects. Pass --global to omit scope — use this for team-wide references that should surface everywhere.
When belt know get finds supplementary files (references, scripts, examples), the CLI prints tips for belt skill add and belt skill files so you can install or inspect them locally.
belt know upload auto-collects scope signals from the current directory (git remote, module name, language) and stores them on the new version — see Knowledge — Scoping.
→ Knowledge API · Creating skills
Files (CLI)
belt file (alias belt files) lists, uploads, downloads, and deletes files in your workspace. Use it to save outputs from belt app run or belt mcp run without shelling out to curl.
| Command | Purpose |
|---|---|
belt file list | List your files (ls alias; --json, --limit, --cursor, --type, --search / -q, -l / --long) |
belt file download <url-or-id> | Download to cwd or -o / --out path (-o - pipes to stdout) |
belt file upload <path> [path...] | Upload via presigned URL; returns permanent URI (--name for a single file only) |
belt file info <id> | Show metadata including media dimensions, duration, and codec |
belt file delete <id> | Delete a file (rm alias; --force / -f to skip confirmation) |
1belt file list --type image --limit 202belt file list --search photo3belt file list -q avatar --type image4belt file download https://files.inference.sh/abc/image.png5belt file download 01abc123def456 -o ./output.png6belt file upload ./photo.jpg --name avatar.jpg7belt file upload *.png8belt file info 01abc123def456 --json9belt file delete 01abc123def456 --force--type filters by content category (image, video, audio, text) — the CLI matches MIME types like image/%. --search / -q filters by filename substring (case-insensitive). Combine both to narrow results (for example -q avatar --type image). In table output, the type column shows short labels (image, video, audio, or subtypes like json, pdf, docx, csv, text) instead of raw MIME strings. Downloads accept a file URL (for example from task output) or a file ID from belt file list. If the destination filename already exists, download auto-renames with (1), (2) suffixes. Uploads and downloads show live progress (speed, bytes transferred, ETA); batch uploads print a [1/N] counter per file.
belt app run auto-uploads local file paths in --input JSON — use belt file upload when you need a URI outside a task run.
Feedback (CLI)
Submit customer-discovery answers and open feedback. Responses are stored on your account via POST /me/survey (requires belt login).
| Command | Purpose |
|---|---|
belt feedback | List pending survey questions (or show answers already submitted) |
belt feedback <question-id> "<answer>" | Answer a structured question |
belt feedback "<message>" | Send open feedback (question_id = open) |
Structured question IDs: use_case, discovery, need, testimonial (legacy feedback is still accepted by the API).
1belt feedback # see what's pending2belt feedback discovery "found it on github"3belt feedback use_case "building AI agents for customer support"4belt feedback need "better template discovery"5belt feedback testimonial "fastest way to ship agents with real integrations"6belt feedback "love the speed, wish there were more templates"Before most commands, the CLI may show one unanswered question at the top of stderr (the notice block). Each question has a 1-hour cooldown; after you answer one, the next unanswered question appears on a later command. When all four structured questions are answered, an occasional freeform prompt (72-hour cooldown) suggests belt feedback "...". Survey notices are skipped for belt version, belt update, belt feedback, belt login, and belt logout so scripts and agents parsing those commands get clean output.
Survey prompts are not injected into belt suggest --json hook output — only the stderr notice path above. Submissions include optional metadata: agent (detected runtime, e.g. cursor) and context (your five most recent belt commands, comma-separated).
The CLI records the last 10 commands you run in ~/.belt/history (via the post-command tips hook; skipped for belt feedback itself and when tips are suppressed with INFSH_NO_TIPS=1, --json, or --pjson). When you submit feedback, the last five entries are sent as context.
Suppress survey prompts and other stderr tips with INFSH_NO_TIPS=1.
Tasks (CLI)
| Command | Purpose |
|---|---|
belt task list | List recent tasks (--status, --limit, --cursor, --app) |
belt task get <id> | Get task status and output (-f / --follow to stream until complete) |
belt task logs <id> | View execution logs (--type to filter; -f to tail live output) |
belt task cost <id> | Show cost breakdown in microcents |
belt task timings <id> | Show timing breakdown by phase |
belt task cancel <id> | Cancel a running task |
For HTTP equivalents, see Tasks API (list, logs, timings, telemetry, and status endpoints). Resource telemetry is available via GET /tasks/:id/telemetry or client.tasks.getTelemetry(id) in the JavaScript SDK.
JSON output (--json / --pjson)
Many commands accept --json (-j) for machine-readable output on stdout. As of CLI v1.15.13, --json writes compact single-line JSON so it pipes cleanly to jq and other tools. Use --pjson when you want indented JSON for human debugging in the terminal.
For belt app run and belt mcp run, --jq '<expr>' filters output inline (no external jq required) — see Filter output (--jq) above.
Both flags suppress contextual stderr tips (post-command tips only — hook tip: lines inside belt suggest --json output are unchanged). Commands that support --save (for example belt app store --save) always write pretty-printed JSON to the file, regardless of --json or --pjson.
All list commands support JSON output: belt agent list, belt chat list, belt task list, belt flow list, belt flow runs, belt integrations list, belt app list, belt app store, belt skill list, belt know list, belt file list, belt mcp list, belt secrets list, and others. Detail commands include belt me, belt balance, belt task get, belt chat send, belt app get, belt agent get, belt agent create, belt file info, belt file download, belt file upload, belt file delete, and belt agent run ({"chat_id": "..."} with --no-wait; full run response otherwise).
1belt task list --json | jq '.[].id' # compact — pipes cleanly2belt task get task_abc --pjson # indented — easier to read3belt app store --json --save store.json # stdout compact; file pretty-printedOn failure with --json or --pjson active, the CLI writes a JSON error object to stdout in addition to the human-readable message on stderr:
1{"error": "not logged in or session expired. run 'belt login' to authenticate"}Parse stdout for automation; ignore stderr unless you need the formatted message. Successful JSON responses use the command-specific schema documented in each command's help (belt task get --help).
Billing and plan limits
Billing and plan-limit errors include upgrade URLs in the error message when the API returns entitlement metadata with upgrade_available: true — under top-level meta on version 2 problem+json responses, or error.meta on legacy version 1 envelopes.
| Error kind | Typical message | What to do |
|---|---|---|
| Insufficient balance | Billing URL in message | Add credits at Billing |
| Plan limit | Subscription URL in message | Upgrade at Subscription |
| Addon entitlement | Add-ons URL in message | Subscribe at Add-ons |
| Not logged in | Session expired | Run belt login |
When addon_plan_id is present in entitlement metadata, the CLI links to the add-ons page instead of the subscription page.
Inspect usage programmatically with GET /entitlements/usage — see Entitlements API.
→ Billing API · Subscription API · Troubleshooting — Plan limits
Environment Variables
| Variable | Description |
|---|---|
INFSH_API_KEY | API key (overrides config file) |
BELT_NON_INTERACTIVE | Force non-interactive mode (skip browser login, MCP OAuth polling, spinners, and stdin prompts). Also set automatically when CI is truthy. |
INFSH_NO_AUTOUPDATE | Disable automatic CLI updates |
INFSH_NO_TIPS | Disable stderr tips and survey prompts after commands |
INFSH_ENGINE_BIN | Path to a custom private engine binary |
Shell Completions
1infsh completion bash # or zsh, fish, powershellNext
→ Coding Agents — Build with AI assistants
→ Creating an App — Manual setup