@tonbo/cli
v0.3.4
Published
Deploy persistent Agents and manage their Machines from the command line.
Readme
Tonbo CLI
Install the public package with Node.js 22 or newer:
npm install --global @tonbo/cli
tonbo --versionThe CLI deploys an Agent directly from a local directory without requiring Git or Tonbo calls in the Agent source. Sign in, then initialize the current directory interactively:
tonbo login
tonbo init
No Harness-specific configuration was found in this agent.
? Which supported Harness should Tonbo use?
❯ PI (`pi`) Run this agent with the pi command.
? How should this Agent connect to Tonbo?
❯ Create a new agent Create it only after you confirm the complete configuration.
Use an existing agent
Set up later
? Agent name [my-agent]:
Tonbo Agent configuration:
Agent: Create my-agent in my-account (permanent address assigned after creation)
Harness: PI
Execution: PI CLI (`pi`)
Model: claude-sonnet-4-5
? Create agent and .tonbo with this configuration?
❯ Create agent and .tonbo
Edit configuration Change the agent, Harness, execution mode, model, or SDK entrypoint.
Cancel
Created agent my-agent and .tonbo.
Agent: my-agent (my-agent-my-account.tonbo.sh)
Organization: my-account
Application: https://my-agent-my-account.tonbo.sh
Harness: PI
Mode: PI CLI
Next: tonbo deployUse the arrow keys and Enter to select a supported Harness and either create or select the one Agent owned by this source tree. Agent creation and file writes wait until the final review; cancelling leaves both local and cloud state unchanged. AGENTS.md is Harness-neutral and never identifies PI by itself. When .pi/settings.json exists, the shared source inspector identifies the PI Harness and reports its workspace-local packages. A regular PI agent defaults to the native PI CLI; choose Edit configuration only when changing the Agent, execution mode, model, or another setting. Unsupported and planned Harnesses are not shown.
The generated .tonbo is TOML:
# Tonbo Agent configuration.
# Edit this file directly or run `tonbo init` to reconfigure.
version = 2
agent = "my-agent-my-account.tonbo.sh"
[harness]
runtime = "pi"
[harness.driver]
kind = "native"
[inference]
model = "claude-sonnet-4-5"The immutable full Agent hostname is the only durable Agent authority in the source tree; it is not a credential. This keeps Agents with the same name in different Organizations unambiguous. deploy, run, ssh and secret refuse an unbound declaration. tonbo agent use <name-hostname-or-id> accepts any convenient selector, resolves it through the signed-in account and writes the selected agent-organization.tonbo.sh hostname into .tonbo; rebinding an existing declaration requires interactive confirmation or --force. UUIDs remain internal API identities and are never committed by the CLI.
The default inference model is written without prompting. Override it explicitly with --model. Headless initialization makes Harness and driver choices explicit and may bind the resulting declaration with agent use:
tonbo init --harness pi --driver native
tonbo init --harness pi --driver command --agent-entry dist/agent.mjs
tonbo agent use my-agent-my-account.tonbo.shAfter interactive initialization, deploy the current contents:
tonbo deploy
tonbo run "Reply with exactly READY."Choose Use an existing agent during init when the Agent already exists. tonbo agent create <name> and tonbo agent use <name-hostname-or-id> remain explicit automation and recovery commands.
run creates a durable Session and prints its ID in --json output. Pass that identity back to continue the same PI conversation:
tonbo run --session 4d8e9501-... "Continue the previous task."Every tonbo deploy creates one immutable Deployment: the uploaded source, the .tonbo settings and the git provenance of the source root (commit, branch, subject, author and whether the tree was dirty) when the directory is inside a git work tree. Git is optional; without it the Deployment records tonbo deploy as its source. Deployments are named by their commit subject, or by their short id (the first eight hex characters) when there is no commit, and every command that takes a Deployment accepts any unambiguous id prefix. The Agent's Production pointer names the one Deployment that serves its hostname; deploy moves Production to the new Deployment and prints the Deployment, its Production state and the exact standard OpenSSH command for the bound Agent and its username:
$ tonbo deploy
Deployed agent my-agent.
Organization: my-account
Deployment: Fix greeting (0f3a7c21)
Source: 0123456 · main
Production: promoting (generation 4)
Application: https://my-agent-my-account.tonbo.sh
Agent process: starts with the first turn and stays warm while the runtime is active.
Start the Agent:
tonbo run "<prompt>"
Connect with SSH:
ssh [email protected]When the new Deployment has the same contents as the Production Deployment it replaces, deploy says so; the record is still created. tonbo deploy --no-promote creates the Deployment without moving Production, for example to stage a build and promote it later:
tonbo deploy --no-promote
tonbo deployments # ID NAME STATUS PRODUCTION SOURCE CREATED BY
tonbo deployments show 0f3a7c21 # datasheet and Rollouts for one Deployment
tonbo deployments promote 0f3a7c21 # move Production to a Deployment
tonbo deployments rollback # move Production back to the previous Production Deployment
tonbo deployments rollback 9b8c1d22 # or to a named onetonbo deployments (alias tonbo deployments list) marks the current Production Deployment with ● and earlier ones with ○; STATUS is the Deployment's relationship to Production: current, promoting, failed, stopped, previous or none. Promotion and rollback compare-and-swap the Production generation, so two people moving Production at once cannot silently overwrite each other; a conflict is reported and the command can be retried after checking tonbo deployments. tonbo agent show prints the Production Deployment and its state alongside the Agent addresses.
Use tonbo agent show to rediscover the username, application address and SSH command later. tonbo login registers public keys found at the conventional ~/.ssh/id_ed25519.pub, id_ecdsa.pub and id_rsa.pub paths. Register a key at another path with tonbo ssh-key add <path.pub> and revoke a lost or retired key with tonbo ssh-key remove SHA256:.... The CLI is not part of the SSH connection; ordinary OpenSSH, scp and rsync connect directly:
ssh [email protected]The SSH user name is the Agent qualified by its username; the signed public key identifies the Tonbo user and is checked against membership and IAM at connection time. The CLI resolves the Agent name in .tonbo and prints the server-authoritative destination, so users never need to remember or assemble a username. The shell and HTTP turns may coexist on the singleton runtime, allowing the shell to observe the Agent while it works. Session writer fencing protects durable conversation history; ordinary workspace files retain Linux process concurrency semantics.
Deploy does not create a hidden Session just to prewarm PI. The first real tonbo run starts the Session-bound PI RPC process; successful Turns keep that process hot, including across native Session switches. The process is disposable cache rather than durable state: pause, replacement and uncertain failures remove it, and the next Turn restores authority from the durable Session JSONL.
The platform injects scoped inference access and owns PI Session capture. Do not put a model-provider API key or a Tonbo credential in .tonbo.
Deploy snapshots regular files under .tonbo, excluding .git, node_modules, PI package caches, local environment files and patterns in .tonboignore. Coding tools start in the persistent Artifacts workspace, while AGENTS.md and trusted .pi extensions, skills, prompts and settings load from the Deployment's uploaded source.
Supported PI agent shapes
1. Agent-local Agent
Keep the normal PI agent layout. Tonbo runs the same AGENTS.md, .pi/APPEND_SYSTEM.md, .pi/settings.json, .pi/extensions, .pi/skills and .pi/prompts that local pi loads:
pi
tonbo init
tonbo deploy
tonbo run "Start the task."2. PI Package agent
Use PI's agent-local package declaration as the single source of truth. A package is a PI resource, not another Tonbo execution mode: tonbo init recognizes .pi/settings.json, then the native PI driver loads the packages. Install an immutable package reference locally, verify it with PI, and deploy the agent; Tonbo excludes .pi/npm and .pi/git caches and restores packages inside the isolated runtime:
pi install -l npm:@acme/[email protected]
pi
tonbo init
tonbo deployRemote npm packages must use an exact version. Git packages must use a full 40-character commit, for example git:github.com/acme/my-pi-agent@0123456789abcdef0123456789abcdef01234567. Movable tags, branches, ranges and latest fail deployment.
3. PI SDK app
Choose Edit configuration, change Execution mode to PI SDK app, and confirm the resulting summary. In automation, use --driver command --agent-entry <file>, or declare a command driver directly:
version = 2
[harness]
runtime = "pi"
secrets = ["GITHUB_TOKEN"]
[harness.driver]
kind = "command"
protocol = "pi-rpc-v1"
command = ["node", "dist/agent.mjs"]
[build]
command = ["npm", "run", "build"]
[inference]
model = "claude-sonnet-4-5"tonbo deploy runs the build command before creating the source snapshot. The entrypoint must keep stdout exclusively for PI RPC and send logs to stderr. It receives PI_CODING_AGENT_MODULE, PI_CODING_AGENT_DIR, PI_CODING_AGENT_SESSION_DIR, TONBO_PI_SESSION_FILE, TONBO_PI_SESSION_ID, TONBO_PI_PROVIDER, TONBO_PI_MODEL and TONBO_PI_RPC_PROTOCOL. Load the platform PI SDK from PI_CODING_AGENT_MODULE, open TONBO_PI_SESSION_FILE, create an AgentSessionRuntime, and pass it to runRpcMode(). This lets the app customize tools and runtime services without forking PI while preserving Tonbo's durable Session and Turn protocol.
For a non-interactive invocation, provide a current Tonbo CLI OAuth access token; the committed .tonbo supplies the only Agent context:
TONBO_ACCESS_TOKEN=... tonbo --json deploy
TONBO_ACCESS_TOKEN=... tonbo --json run "health check"Node.js 22 or newer is required. Human OAuth tokens are stored at ${XDG_CONFIG_HOME:-$HOME/.config}/tonbo/credentials.json; the CLI atomically replaces that file with owner-only permissions and never writes it into an Agent directory.
Related design
- Design documentation map
- Agent source inspection and onboarding
- Shared source inspector
- Agent resource model
- Agent Deployments, Production and Rollouts
- ADR-0008: Tonbo CLI onboarding and credential boundaries
- Management API v1
Machines
Machines belong to an Account independently of Agents. Allocate in us-east-1, bind an available Machine from Agent detail or the CLI, inspect measured metrics, and release it when no longer needed. Allocation starts no compute. The platform handles idle pause/resume automatically; there are no customer power controls or arbitrary Machine command/upload APIs.
tonbo --json region list
tonbo --json machine allocate --account <account-uuid> --region us-east-1 --request-id <request-uuid>
tonbo --json machine allocation <request-uuid> --account <account-uuid>
tonbo --json machine list --account <account-uuid>
tonbo --json machine bind <machine-uuid> --agent <agent-uuid>
tonbo --json machine show <machine-uuid>
tonbo --json machine metrics <machine-uuid>
tonbo --json machine unbind <machine-uuid>
tonbo --json machine release <machine-uuid>Only one active Agent binding per Machine and one Machine per Agent are currently supported. Unbinding drains execution and completes physical deletion, final usage settlement and storage credential revocation before the Machine becomes available. Wait for available: true in machine show before rebinding. Cross-Agent reassignment resets rootfs; the destination mounts its own Agent Workspace and Sessions. Hidden pause/resume within the same Agent retains rootfs and process state. Release also drains an existing binding automatically; it does not delete Agent files or Sessions.
tonbo agent list lists accessible Agents without requiring a local .tonbo file. JSON command output uses agent for one Agent and agents for the list; there is no duplicate agent output alias.
Persist the allocation request UUID before sending when automating. Reuse it with the same account and region after a lost response; lookup returns the original Machine even after release. Omitting --request-id generates one, included in the success output or retry error.
