unbound-cli
v1.10.0
Published
CLI tool for Unbound - AI Gateway management
Maintainers
Readme
Unbound CLI
Command-line tool for managing your Unbound AI Gateway. Configure policies, manage users and groups, connect AI coding tools, and set up tools like Cursor, Claude Code, Gemini CLI, and more.
Installation
npm install -g unbound-cliQuick Start
# Login via browser
unbound login
# Or login with an API key (for CI/CD or headless environments)
unbound login --api-key <your-api-key>
# Check your status, role, and connected tools
unbound status
# List policies
unbound policy list
# Set up multiple tools interactively
unbound setup
# Set up a single tool
unbound setup cursorOnboarding (one command)
For new users, the fastest path from install to a fully-configured device is the onboard command. It logs you in, installs the default tool bundle (Cursor, Claude Code hooks, Codex hooks), and runs device discovery — all in one step.
# End user
npm install -g unbound-cli
unbound onboard --api-key <USER_KEY>
# Admin enrolling a device via MDM (requires root)
sudo unbound onboard --api-key <ADMIN_KEY> --discovery-key <DISCOVERY_KEY>The user API key and discovery API key are separate — discovery uses its own key that the CLI does not store. Run with sudo to let the discovery step scan all users on the device; without it, only the current user is scanned.
Commands
Authentication
| Command | Description |
|---------|-------------|
| unbound login | Sign in via browser |
| unbound login --api-key <key> | Sign in with an API key (non-interactive) |
| unbound login --domain <domain> | Sign in via a custom domain |
| unbound logout | Remove stored credentials |
| unbound status | Show CLI status, role, and connected tools |
| unbound doctor | Diagnose per-tool health (config, hook, env) and API key |
Tool Setup
Interactive batch setup:
| Command | Description |
|---------|-------------|
| unbound setup | Select and install multiple tools interactively |
| unbound setup --all | Install the default bundle: Cursor + Copilot + Augment + Claude Code hooks + Codex hooks |
Automated setup (downloads scripts, sets env vars, configures tool):
| Command | Description |
|---------|-------------|
| unbound setup cursor | Download hooks, set env, restart Cursor |
| unbound setup copilot | Download hooks, set env, configure GitHub Copilot |
| unbound setup augment | Download hooks, set env, configure Augment Code |
| unbound setup claude-code | Interactive mode selection (subscription or gateway) |
| unbound setup claude-code --subscription | Hooks only (keep your Claude subscription) |
| unbound setup claude-code --gateway | Use Unbound as the AI provider |
| unbound setup gemini-cli | Set GEMINI_API_KEY and base URL |
| unbound setup codex | Interactive mode selection (subscription or gateway) |
| unbound setup codex --subscription | Hooks only (keep your OpenAI subscription) |
| unbound setup codex --gateway | Use Unbound as the AI provider |
Instruction-only (shows API key and base URL to configure manually):
| Command | Description |
|---------|-------------|
| unbound setup roo-code | Show Roo Code config values |
| unbound setup cline | Show Cline config values |
| unbound setup kilo-code | Show Kilo Code config values |
| unbound setup custom-access | Show API key and base URL for direct API access |
Remove configuration:
| Command | Description |
|---------|-------------|
| unbound setup cursor --clear | Remove Unbound config for Cursor |
| unbound setup copilot --clear | Remove Unbound config for GitHub Copilot |
| unbound setup augment --clear | Remove Unbound config for Augment Code |
| unbound setup claude-code --clear | Remove Unbound config for Claude Code |
| unbound setup gemini-cli --clear | Remove Unbound config for Gemini CLI |
| unbound setup codex --clear | Remove Unbound config for Codex |
MDM Setup (Admin)
Configure all users on a device via MDM. Requires root.
| Command | Description |
|---------|-------------|
| sudo unbound setup --api-key KEY --all | Set up all tools |
| sudo unbound setup --api-key KEY cursor codex-subscription | Set up specific tools |
| sudo unbound setup --clear cursor | Remove config for specific tools |
Available tools: cursor, copilot, augment, claude-code-subscription, claude-code-gateway, gemini-cli, codex-subscription, codex-gateway
claude-code-subscription and claude-code-gateway are mutually exclusive. codex-subscription and codex-gateway are mutually exclusive. When using --all, subscription mode is used by default for Claude Code and Codex.
MDM AI Tools Discovery
Scan a device for installed AI coding tools and report findings to Unbound. Uses a separate discovery-specific API key. --domain defaults to the configured backend URL (or https://backend.getunbound.ai when unset).
| Command | Description |
|---------|-------------|
| sudo unbound discover --api-key KEY | Scan all users on the device (requires root) |
| unbound discover --api-key KEY | Scan current user only |
| sudo unbound discover --api-key KEY --domain URL | Scan with a custom backend URL |
| unbound discover --set-cron --api-key KEY | Set up daily scan at 09:00 (cross-platform) |
| unbound discover unschedule | Remove the scheduled scan |
| unbound discover status | Show scan schedule and log paths |
Policies (Admin only)
Unbound has four policy types. Each has its own subcommand with guided flag-based create/update. Tool policies live on a separate backend endpoint but are reachable under the same policy command tree.
Docs: https://docs.getunbound.ai/policies
| Type | Subcommand | Purpose | Docs |
|---|---|---|---|
| Cost | unbound policy cost | Monthly budget limits per user group | https://docs.getunbound.ai/policies/cost-policies |
| Model | unbound policy model | Control which AI models are available | https://docs.getunbound.ai/policies/model-policies |
| Security | unbound policy security | Guardrails (PII, secrets), routing rules | https://docs.getunbound.ai/policies/security-policies |
| Tool | unbound policy tool | Shell command and MCP tool controls | https://docs.getunbound.ai/policies/tool-policies |
Generic commands (Cost/Model/Security only):
| Command | Description |
|---------|-------------|
| unbound policy | Overview of types and subcommands |
| unbound policy list [--type COST\|MODEL\|SECURITY] | List policies |
| unbound policy get <id> | Get a policy's details |
| unbound policy delete <id> | Delete a policy |
| unbound policy form-data | Reference data: user groups, models, guardrails, tool types, command policies |
| unbound policy effective <id> [--user\|--group] | View effective policies for a user or group |
Cost policy examples:
# Create a $1,000/month cap for the engg user group
unbound policy cost create --name "Eng Budget" --monthly-budget 1000 --group engg
# Change the budget
unbound policy cost update 5 --monthly-budget 1500
# List just cost policies
unbound policy cost listModel policy examples:
# Allow only specific models
unbound policy model create --name "Sonnet Only" --allowed claude-3-5-sonnet
# Allow everything except specific models
unbound policy model create --name "No Opus" --all-models --excluded claude-3-opus
# List all model policies
unbound policy model listSecurity policy examples:
# Block PII, redact secrets, for the engg group
unbound policy security create --name "Block PII" --sub-type guardrails \
--guardrail PII:BLOCK --guardrail Secrets:REDACT --group engg
# Default-route gpt-4 traffic to claude-3-5-sonnet
unbound policy security create --name "Prefer Sonnet" --sub-type default-routing \
--route gpt-4:claude-3-5-sonnet
# Fall back on 429s
unbound policy security create --name "429 Fallback" --sub-type error-code-routing \
--error-route 429:gpt-4:claude-3-5-sonnetTool policy examples:
BREAKING CHANGE in 1.5.0:
create-terminalandcreate-mcpnow require either--prompt(AI-assisted creation) or an explicit--no-aiopt-out. Invocations with raw classification flags but no--no-aiexit with code 2 and a remediation message. Under Claude Code (CLAUDECODE=1), even--no-aiis rejected unless you also setUNBOUND_ALLOW_NO_AI_UNDER_CLAUDE=1— this is intended for interactive humans, not agents.
# AI-assisted (preferred): describe the policy in natural language.
unbound policy tool create-terminal --prompt "block rm -rf"
# AI-assisted MCP policy: describe the service and intent in natural language.
unbound policy tool create-mcp --prompt "audit all Linear writes"
# See what command families and MCP servers are available
unbound policy tool families
unbound policy tool mcp-servers
# Flag-based fallback: block destructive shell commands explicitly
unbound policy tool create-terminal --no-ai --name "Block rm -rf" --command-family filesystem \
--field command='rm -rf*' --action BLOCK --custom-message "Destructive command blocked."
# Flag-based MCP fallback: audit Linear write operations
unbound policy tool create-mcp --no-ai --name "Audit Linear writes" --mcp-server Linear \
--mcp-action-type write --action AUDIT
# List, get, delete
unbound policy tool list
unbound policy tool get <id>
unbound policy tool delete <id>Before creating any policy, run unbound policy form-data to see available user group names, model names, guardrail names, and existing command policies. The CLI accepts names (e.g. engg, claude-3-opus, PII) and resolves them to backend IDs automatically. You can also pass numeric IDs directly.
Users
| Command | Description |
|---------|-------------|
| unbound users list | List organization members |
| unbound users effective-policies <id> | View effective policies for a user |
User Groups (Admin only)
| Command | Description |
|---------|-------------|
| unbound user-groups list | List all groups |
| unbound user-groups get <id> | Get group details |
| unbound user-groups create --name <n> | Create a group |
| unbound user-groups update <id> | Update a group |
| unbound user-groups delete <id> | Delete a group |
| unbound user-groups effective-policies <id> | View effective policies |
Alias: unbound groups works the same as unbound user-groups.
Tools
| Command | Description |
|---------|-------------|
| unbound tools list | List connected tools |
| unbound tools connect <type> | Connect a tool |
| unbound tools approved | List approved tool types |
Supported tool types: CLAUDE_CODE, UNBOUND_CLAUDE_CODE, CURSOR, COPILOT, AUGMENT_CODE, ROO_CODE, CLINE, GEMINI_CLI, CODEX, UNBOUND_CODEX, KILO_CODE, CUSTOM_ACCESS
Configuration
Config is stored in ~/.unbound/config.json. For tenant deployments, point the CLI at your own hosts in one command (recommended for new installs):
unbound config urls <gateway-url> <frontend-url> <backend-url>
# example
unbound config urls https://api.acme.com https://gateway.acme.com https://backend.acme.com
unbound login --api-key <YOUR_API_KEY>Or set them one at a time when changing a single host:
unbound config set-gateway-url https://api.acme.com # AI gateway host (used by tool setup)
unbound config set-frontend-url https://gateway.acme.com # Browser login host
unbound config set-backend-url https://backend.acme.com # REST API host
unbound config showBare hostnames are accepted (backend.acme.com becomes https://backend.acme.com). Each URL also accepts a per-process override via env var.
Backend URL priority (highest to lowest):
UNBOUND_API_URLenvironment variablebase_urlin~/.unbound/config.json(set viaunbound config set-backend-url)- Default:
https://backend.getunbound.ai
Frontend URL priority (highest to lowest):
UNBOUND_FRONTEND_URLenvironment variablefrontend_urlin~/.unbound/config.json(set viaunbound config set-frontend-url)- Default:
https://gateway.getunbound.ai
Gateway URL priority (highest to lowest):
UNBOUND_GATEWAY_URLenvironment variablegateway_urlin~/.unbound/config.json(set viaunbound config set-gateway-url)- Default:
https://api.getunbound.ai
Global Options
All list/get commands support --json for machine-readable JSON output.
unbound policy list --json
unbound users list --json | jq '.members[].email'Onboarding failure reporting & telemetry
So onboarding steps never fail silently, the CLI:
- Fails loud. A failed setup or discovery step exits non-zero (no fake successes). A broken script download (GitHub down/404/empty body) is detected before the script runs, so it can no longer "succeed" with an empty script.
- Reports failures to the backend. When a setup step fails, the CLI makes a
best-effort
POST /api/v1/setup/failed/with the failing step name and exit code so the failure is visible server-side. The device is identified byos.hostname()(used only as an org-scoped key, not a true hardware serial). This report is best-effort: if it can't be sent (offline / rate-limited), the CLI still shows the real error and keeps its non-zero exit code.
Error reporting (Sentry) — opt-out
Crash/error reporting is off by default and only activates when a DSN is configured. Secrets (API/discovery keys), home-directory paths, and your OS username are scrubbed before any event is sent.
| Env var | Effect |
|---------|--------|
| UNBOUND_CLI_SENTRY_DSN | Set to enable error reporting. Unset = fully disabled (nothing initializes, no network). |
| UNBOUND_TELEMETRY | Set to 0, false, or no to disable error reporting even if a DSN is configured. |
