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 updateAuto-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.
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 the indented GET /me response (user and team objects). See Teams API — Get current user. On failure, diagnostics go to stderr only — stdout stays empty (no {"error":...} object).
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.sh |
Running Apps
| Command | Purpose |
|---|---|
infsh app run | Run an app in the cloud |
infsh app sample | Generate sample input |
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.
Managing Apps
| Command | Purpose |
|---|---|
infsh app my | List your deployed apps |
infsh app list | Browse available apps |
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 |
infsh app pull syncs app code and metadata from inference.sh:
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 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.
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. When stdin is hook JSON with transcript_path, belt prepends assistant text from the current turn (up to 1000 characters) before searching.
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.
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 |
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 |
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 |
belt mcp run <slug>:<tool> | Call a connector tool from the terminal |
→ 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 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.sh 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 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.
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. 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.
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) |
belt chat get <chat-id> | Show transcript and pending tool invocations |
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.
→ Agents REST API · Approval settings · Human-in-the-loop
Skills (CLI)
| Command | Purpose |
|---|---|
belt skill use <namespace>/<name> | Print a skill's instructions to stdout |
belt skill add <namespace>/<name> | Install a skill into your workspace |
belt skill files <namespace>/<name> | List supporting files (references, scripts, examples) |
belt skill view <namespace>/<name> <path> | View one supporting file |
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.
→ Skill registry · Search concept · Search API
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, 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) |
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 referenceWhen 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.
→ Knowledge API · Creating skills
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: discovery, use_case, feedback.
1belt feedback # see what's pending2belt feedback discovery "found it on github"3belt feedback use_case "building AI agents for customer support"4belt feedback "love the speed, wish there were more templates"After most commands, the CLI may show one unanswered question in the tips area (stderr). Each question has its own 72-hour cooldown; after you answer one, the next unanswered question appears on the following command. When all three structured questions are answered, a one-time freeform prompt suggests belt feedback "...".
The same questions can appear in coding-agent hook context via belt suggest --json — agents can run belt feedback on your behalf. 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 or --json). When you submit feedback, the last five entries are sent as context.
Suppress survey prompts and other stderr tips with INFSH_NO_TIPS=1.
→ Survey API · Coding agents — hook context
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)
Many commands accept --json for machine-readable output (belt task get, belt agent list, belt chat send, and others). belt me --json is an exception: it prints the API payload on success but does not emit a JSON error object on failure.
On failure with --json 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 string when the API returns entitlement metadata (upgrade_available: true).
| 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 |
| Not logged in | Session expired | Run belt login |
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