instabox (npm)
npx instabox@latest # sign in, install the CLI and the agent skills (--no-skills: no skills)
npx instabox@latest sh # the same, then start a new box and SSH into it
npx instabox@latest skills install -y # only the agent skills: no sign-in, no network
npx instabox@latest signs you in to instabox with a device code (first run only: open the page it prints on any device and enter the code; it opens the page for you where there is a browser, never with --no-browser), installs the instabox CLI already signed in or updates an out-of-date one (skip with --no-cli), installs or updates the agent skills from ../skills in ~/.claude/skills, ~/.agents/skills and ~/.gemini/config/skills (skip with --no-skills), and prints the next steps. It does not touch your boxes.
npx instabox@latest sh does all that, then starts a new box (box-<hex>) and drops you into it over SSH, no questions. Run by an agent (no terminal), it starts the box and prints instabox ssh <box> -- <command> instead of opening a shell. At the box limit it starts nothing and lists your boxes, to remove one (instabox rm --yes <box>) or open one (instabox ssh <box>).
A GitHub and a Google sign-in are separate instabox accounts, each with its own boxes. Both this entry point and instabox login let the sign-in page offer both. --google asks for Google directly, as does instabox login --provider google. An agent with no browser and nobody at the keyboard signs itself up instead with instabox login --agent once the CLI is installed (docs/agent-auth.md): it prints a claim page and a code for the account owner, who approves later from any device.
Without a terminal (an agent, CI), nobody can enter a device code, so the sign-in comes from INSTABOX_API_KEY (an ibk_... key, as the CLI takes it: no browser, no device code, nothing saved), a sign-in already saved, or an agent key from instabox login --agent. With none of them it exits at once with status 3 and says how to go on, instead of waiting for a code nobody will enter. --device-code asks for the device code anyway, for an agent that relays it to a person. -y (--yes) asks nothing: no invite-code prompt.
npx instabox@latest skills install [-y] [--claude|--codex|--cursor|--opencode|--antigravity|--all] installs only the agent skills, with no sign-in: Claude Code's in ~/.claude/skills, Codex's, Cursor's and OpenCode's in ~/.agents/skills (all three read it, so one copy serves them), Antigravity's in ~/.gemini/config/skills. With no agent named it installs for all of them, asking first at a terminal unless -y. An unknown flag is a usage error, status 2.
Any other command line is the instabox CLI's (cmd/instabox): npx instabox@latest ls runs instabox ls, the build this package carries.
This package is the only place the CLI comes from, and npx instabox@latest (or npm install -g instabox in scripts and CI) is how to install it. Two older paths read it from the npm registry too: curl -fsSL https://api.instabox.sh/install.sh | sh, still served for existing scripts but no longer advertised (the server serves the script; the script asks $INSTABOX_NPM_REGISTRY/instabox/$INSTABOX_VERSION, default https://registry.npmjs.org and latest, for dist.tarball, verifies the tarball against dist.integrity (sha512), and extracts package/cli/instabox-<os>-<arch>), and instabox update (the same in Go). The control plane builds, stores and serves no CLI: a CLI change is on npm minutes after its merge, with no release and no deploy.
How it works
bin/instabox.mjsruns instabox's device-code sign-in (RFC 8628,POST /v1/auth/device, then polls/v1/auth/device/token), asinstabox logindoes, and saves the tokens where the CLI keeps its own,~/.config/instabox/credentials.json, so both are signed in at once. There is one copy on purpose: the server rotates refresh tokens and ends the session when a rotated one comes back.shalways starts a new box, with no timeout and no idle auto-suspend of its own. An existing box is entered with the CLI:instabox ssh <box>.- The package carries the Go CLI: all six builds (darwin, linux and windows; amd64 and arm64) under
cli/, andbin/instabox.mjspicks the one for this machine (lib/platforms.mjs). One package rather than one per platform keeps publishing to a single package and a single trusted-publisher setting; the price is that every install downloads the other platforms' builds too (about 22 MB compressed, cached by npx per version). It copies that binary onto PATH ($INSTABOX_INSTALL_DIR, else/usr/local/binwhen writable, else~/.local/bin; Windows:%LOCALAPPDATA%\Programs\instabox), replaces an installed CLI whose content differs in place, and leaves a development build (instabox dev, or-dirty) alone. No network is needed for the CLI, andnpx instabox@latest <command>runs the bundled binary directly, whatever is on PATH. - Without a bundled binary (a platform with no build, or this directory run from a checkout, where
cli/does not exist untilscripts/bundle-cli.mjsfills it) nothing is installed and nothing is downloaded: the output says why in one line (lib/cli.mjs,missingBundledCli), an installed CLI is left as it is, andnpx instabox@latest <command>runs the installed CLI if there is one. - Skills are written only over copies marked
installed-by: instabox; the output says which were installed, updated, already up to date, or kept because they are the user's own. - On Windows the bundled
instabox.exegoes to%LOCALAPPDATA%\Programs\instabox; the output gives the PowerShell line that puts that folder on the user's PATH, andnpx instabox@latest <command>finds it without that. - The bin is also called
instabox, solib/cli.mjsfinds the real CLI the way the insta CLI does: PATH withoutnode_modulesdirs and without links back to this script, then the installer's own targets. prepackcopies../skillsinto the package; every skill there ships on the next publish.
Develop
npm ci
npm test
npm run format:check
npm pack # copies ../skills, then builds instabox-<version>.tgz
npx --package=./instabox-0.4.3.tgz instabox --help
INSTABOX_API_URL points it at another instabox server. From a checkout there is no bundled binary (cli/ is not in version control), so the wrapper installs nothing and says so; to try the real thing, fill cli/ the way CI does:
../scripts/build-cli.sh --out ../out/cli --version 0.0.0-local
node scripts/bundle-cli.mjs --cli-dir ../out/cli # -> cli/, checked against SHA256SUMS
node bin/instabox.mjs --version # runs cli/<build> for this machine
npm pack # a tarball with the binaries, ~22 MB
Release
Nothing to do by hand. npm-release.yml runs on every push to main. When anything the package ships has changed since the last npm-v* tag (cmd/instabox and the packages of this module it imports, npm/, skills/, go.mod, go.sum, scripts/build-cli.sh), it builds the six CLI binaries with scripts/build-cli.sh, puts them in cli/ with scripts/bundle-cli.mjs (each checked against SHA256SUMS), publishes instabox through npm trusted publishing (no npm token anywhere), and tags the commit npm-v<version>. Anyone who can merge can release.
The version is scripts/next-version.mjs's: package.json names a line (0.8.0), and merges ship 0.8.0, 0.8.1, 0.8.2, … on it. package.json changes only to start a new line (a new minor or major); a line below the highest published stable version is refused, so a reverted package.json cannot move latest back. A version with a - (0.9.0-rc.1) is published as written, once, under the next dist-tag. The workflow sets the version with npm version at publish time; the committed package.json keeps the line's base. instabox --version prints <npm version>+<commit>.
A commit is published once. npm records the commit of every version it publishes (gitHead), and the version step reads the registry's packument first: when a version built from this commit is already there (a rerun after the publish succeeded but the tag job failed), nothing is published again and only the missing npm-v<version> tag is created. So a failed run is simply re-run from the Actions tab (workflow_dispatch). Its force input publishes a new patch with nothing changed.
Trusted publishing is one setting on npmjs.com, package instabox → Settings → Trusted Publisher: GitHub Actions, InsForge / instabox / npm-release.yml. It is set. Renaming the workflow file breaks publishing until the setting is updated; npm does not follow renames.
The CLI a user gets, from npm, install.sh or instabox update alike, is the newest published, which can be ahead of the release a site runs.