CLI
The boxline command line: run the AI agent from your terminal, search the web, fetch pages, and work with sessions, shells and files.
The boxline command line gives the AI agent a task and shows it working, searches the web, turns any page into Markdown, a screenshot or a PDF, and opens a terminal in an isolated machine. It is built on the Node SDK and needs Node 20 or newer.
Install
npx @boxline/cli login # run it without installingnpm install -g @boxline/cli # or install it: the command is then boxlineThe npm package is @boxline/cli and the command it installs is boxline. Everything below uses the command. Without installing, use npx @boxline/cli in place of boxline, for example npx @boxline/cli run "…".
Open source (MIT licence): github.com/Boxline-dev/cli. The package on npm: @boxline/cli.
This page describes version 2.0.0.
Your API key
Create a key in the console (API keys), then:
boxline login # asks for the key (not shown while you type), checks it, saves itboxline whoami # the project, plan and API it belongs toboxline logout # forgets it- The key is saved in your user config folder, in a file only you can read (mode 600):
~/Library/Application Support/boxline/config.jsonon macOS,~/.config/boxline/config.jsonon Linux (or$XDG_CONFIG_HOME), and%APPDATA%\boxline\config.jsonon Windows.BOXLINE_CONFIG_DIRpicks another folder. - Piped input works for scripts:
boxline login < key.txt. The key is never printed.
Environment variables
| Variable | What it does |
|---|---|
BOXLINE_API_KEY | Used instead of the saved key when it is set. Handy in CI. |
BOXLINE_API_URL | The API to use, https://api.boxline.dev. Without it, the CLI uses the API the saved key belongs to (boxline login --api-url <url>), else the public API. |
BOXLINE_CONFIG_DIR | Where the saved key lives. |
NO_COLOR, FORCE_COLOR=1 | Colours are used only on a terminal, never with NO_COLOR; FORCE_COLOR=1 turns them on anyway. |
Run the AI agent
boxline run "Open https://example.com and tell me what the page is about"boxline run "Download the CSV from https://example.com/report and add up the revenue column" --shellboxline run "Convert every video in the workspace to MP4" --shell --no-browser # a shell-only runThe steps show as they happen, on stderr: pages opened, clicks and typing, bash commands with their output, CAPTCHAs, and what the model is thinking (dimmed). The answer comes last, on stdout, so boxline run "…" > answer.txt keeps just the answer. Ctrl+C stops the run.
Agent run run_8f2k… · openai gpt-6-sol · session 3c1e… I'll open the page first.→ browser_navigate https://example.com 1.2 s Loaded https://example.com/ (HTTP 200) — title: Example Domain✓ completed in 6.4 s · 4,210 tokens · $0.0210The page is the placeholder site for documentation examples.| Option | What it does |
|---|---|
--shell | Give the agent a bash shell (Python, Node, sudo) next to the browser. |
--no-browser | With --shell: a shell-only run. The session has no browser, so the AI works with the shell and the files only. |
--session <id> | Work in a session you started. It keeps its own settings. |
--model <id> | Pick the model, for example claude-sonnet-5-5 or gpt-6-sol. |
--var name=value | A value the task uses as %name%. Repeat it for more. |
--secret NAME | A value the task uses as %NAME%, read from the environment variable NAME, for this run only. |
--secret NAME@https://example.com | The same, typed only into fields on that site. Use this for passwords you do not save. |
--credential NAME | A saved credential the AI may type, only on its sites: %NAME% for a secret, %NAME.username%, %NAME.password% and %NAME.otp% for a password. Repeat it for more. |
--captcha ask|solve|ignore | When a CAPTCHA appears: ask a person (default), try to solve it (paid plans), or carry on. |
--keep | Keep the run's session afterwards, to look at it or run more. |
--steps <n> | Stop after this many steps, 1 to 1000 (default 30). --steps none (or --no-step-limit): no step limit. |
--max-cost <usd> | Stop once the run's model cost reaches this many US dollars (0.01 to 100). |
--timeout <seconds> | The run's own session's time (default 1800, or your plan's maximum). The run stops when it ends. |
Values for one run
Passwords and tokens never go on the command line, where shell history and process lists would show them. For a value you give once, put it in the environment and pass its name:
export SITE_PASSWORD=… # or read it from your password managerboxline run "Sign in to https://example.com as %email% with %SITE_PASSWORD% and open the billing page" \ --var email=ada@example.com --secret SITE_PASSWORD@https://example.comThe model only ever sees %SITE_PASSWORD%. The platform fills in the value right before typing, and hides it in everything it shows and keeps. See Variables. For a value you use again, save a credential.
Credentials
Credentials are saved once and used by name. There are two types: a website password (sites, user name, password and an optional source of 2FA codes) and a secret (one value, such as an API token). Values never go on the command line: set asks for them at a hidden prompt, or reads them from a pipe.
boxline credentials set GITHUB_TOKEN --scope shell # a secret (the default type); asks for the valueboxline credentials set SHOP --type password --username ops@example.com --origin https://shop.example.com # asks for the passwordprintf '%s\n%s\n' "$SHOP_PASSWORD" "$SHOP_2FA_KEY" | boxline credentials set SHOP --type password \ --username ops@example.com --origin https://shop.example.com --2fa # the password, then its 2FA keyboxline credentials list # never the valuesboxline credentials delete GITHUB_TOKENboxline run "Sign in to https://shop.example.com with %SHOP.username% and %SHOP.password%, then list my orders" --credential SHOP- A secret is the default type. A password needs
--usernameand at least one--origin, and a plan with password credentials (Hobby and up). - A password is the first line, and with
--2faits 2FA setup key (or anotpauth://link) is the second.--remove-2fatakes the key off. A secret is taken whole, less one final line break, so keys of several lines work. seton a name that exists gives it the new values and keeps the options you leave out. A new site needs the values again, and so does a--scope shellor--scope all(or--shell) that lets shells read a credential only the AI could use: a password with 2FA also needs--2fa(or--remove-2fa), or the platform refuses the change.--scopeand--shelldecide where it may be used, as in the API. Aresumekeeps the run’s credentials.- To let a run sign in again by itself, link a password to a browser profile with the SDK or the console.
Codes by email or SMS, and signing in
A password’s 2FA codes can come from an authenticator key (--2fa, the same as --code-source totp), from you (--code-source push) or from an endpoint of yours (--code-source url --code-url https://…). The AI never sees a code or a sign-in link. --code-timeout 300 is how many seconds a run waits for one (5 to 900).
boxline credentials set SHOP --type password --username ops@example.com --origin https://shop.example.com \ --code-source pushboxline credentials set SHOP --type password --username ops@example.com --origin https://shop.example.com \ --code-source url --code-url https://ops.example.com/boxline-codes # prints a signing secret, once# When a run waits (the webhook credential.code_needed says so), send what the site emailed or texted:printf '%s\n' "$CODE" | boxline credentials push-code SHOP # a code, or a sign-in link (https://…)boxline credentials push-code SHOP # or type it at the hidden promptboxline sessions login $SESSION_ID SHOP --url https://shop.example.com/signin # sign a session in, in one call- A code or link is never an argument.
push-codeasks for it without showing it, or reads one line from a pipe. A value that starts withhttp://orhttps://is sent as a sign-in link, anything else as a code. - It is used once, by a wait that began before it arrived, and kept for 10 minutes. A link must be on one of the credential’s sites.
- With
url, the platform asks your address every 5 seconds while a run waits, with a signed request. The signing secret is printed once, when you set the address: keep it in your secret manager. See Credentials. - Changing where the codes come from needs the password again, so
setasks for it.--remove-2fatakes 2FA off, whatever its source. sessions loginruns a short AI run in the session with only that credential, on its sites.--urlpicks the sign-in page. It needs a plan with password credentials and counts as an agent run. A failure names the run to look at, and a login that takes too long (15 steps, plus the credential’s code timeout) fails withcredential_login_timeout. See Sign in in one call.
Resume a run
A run that stops at a limit (its steps, its cost, or errors in a row) or after a server restart keeps its session for 10 minutes. boxline resume carries on the same run: it keeps its id, and its steps and usage add up. It is shown like boxline run.
boxline run "Download the CSV from https://example.com/report and add up the revenue column" --shell --steps 10boxline resume run_Xy12Ab34Cd56Ef78 # another stretch, with the run's own limitsboxline resume run_Xy12Ab34Cd56Ef78 --steps 50 --note "The download is done; do the upload"--steps <n>: the steps of this stretch, 1 to 1000 (the run’s own limit when left out).--no-step-limit: no step limit for it.--max-cost <usd>: the model cost this stretch may add, 0.01 to 100 US dollars.--note <text>: one text for the AI, up to 2,000 characters: what to do next after a limit, or what a person did after a pause.--var name=valueand--secret NAME: the run’s variables again (see below).
A run that had --var or --secret values needs them again; each keeps the sites it had. A run that completed, was canceled or failed for another reason, or whose 10 minutes have passed, cannot be resumed: start a new one.
When the agent asks for help
When the agent asks for help, to sign in for example, the run pauses. Open the browser with the command it shows (boxline sessions live <id>), do what is needed, then press Enter in the terminal to resume the run (type a note first if you like). A CAPTCHA that waits for a person works the same way, and the run carries on by itself once it is solved.
Search
boxline search "hono routing docs" # titles, addresses and snippetsboxline search "site:docs.python.org asyncio" --limit 5 --fetch 2 # and the top 2 pages as Markdownboxline search "zod" --recency month --json # the API's answer, for programsOperators work in the query: "exact words", -word, site: and filetype:. Each search counts against your plan’s monthly searches; the same search within an hour is free. See Web search.
Pages
Every page is opened by a real browser inside a sandbox, never on your computer.
boxline fetch https://example.com # Markdown on stdoutboxline fetch https://example.com --format text > page.txtboxline screenshot https://example.com # saves example.com.pngboxline screenshot https://example.com -o shot.jpg --full-pageboxline pdf https://example.com -o example.pdfboxline extract https://example.com/pricing --prompt "the plan names and prices"boxline extract https://example.com/product --schema product.json # a JSON Schema fileboxline crawl https://example.com/docs --limit 50 -o docs # one Markdown file per page-o - writes a screenshot or PDF to stdout. --proxy residential:DE (or datacenter, or your own http://user:pass@host:port, or JSON) opens the page through a proxy. Crawls respect robots.txt.
Sessions
boxline sessions create # a browser (the default); add --proxy, --timeout 900, --captcha solve…boxline sessions create --no-browser --shell # a shell onlyboxline sessions create --shell # a browser and a shellboxline sessions list # --status running,stopped, --limit 50, --allboxline sessions get $SESSION_ID # when it stopped, and when it will be deletedboxline sessions live $SESSION_ID # the live view link: watch and take over in a browserboxline sessions login $SESSION_ID SHOP # sign the browser in with a saved password credentialboxline sessions stop $SESSION_ID # save it and free the machine (billing stops)boxline sessions resume $SESSION_ID # bring it back, as it wasboxline sessions delete $SESSION_ID # delete it, with its recording and logs (no undo)Shell and files
boxline exec $SESSION_ID -- ls -la # streams the output, exits with the command's exit codeboxline exec $SESSION_ID -- 'python3 -c "print(2**10)" | tee out.txt'boxline exec $SESSION_ID -- 'nohup ./build.sh > job.log 2>&1 &' # a long job: start it in the background…boxline exec $SESSION_ID -- tail -n 20 job.log # …and read its log laterboxline shell $SESSION_ID # an interactive terminal; Ctrl+D leavesboxline files ls $SESSION_ID downloadsboxline files get $SESSION_ID downloads/report.csv # saves report.csv here ("-" prints it)boxline files get $SESSION_ID output # a folder comes down as a .tar.gzboxline files put $SESSION_ID data/input.csv ./input.csvecho hello | boxline files put $SESSION_ID hello.txt -boxline files rm $SESSION_ID hello.txtexec runs the words after -- in bash, joined with spaces (like ssh), in the session’s persistent shell: cd and export carry over to the next command. In boxline shell, Ctrl+C goes to the remote program, Ctrl+D (or exit) leaves, and Ctrl+] disconnects at once. The session keeps running either way. See Shell and Files.
exec and shell need a session with a shell. files ls and files get also work on a stopped session, until it is deleted. A folder comes down as one .tar.gz file. See Long jobs and folder downloads.
Output for programs
Every command takes --json: it prints the API’s answer as JSON on stdout and nothing else. Errors are JSON too:
{ "error": { "code": "not_found", "message": "not found", "status": 404, "requestId": "req_…" } }For people, errors look like Error: <message> (request id req_…). Quote the request id when you ask for support. See Errors and request ids.
Exit codes
| Code | Meaning |
|---|---|
0 | Done. For run: the run completed. |
1 | An error from the API or the network, or a run that failed. |
2 | A mistake in the command line. The message says which. |
124 | exec: the command ran out of time. |
130 | Stopped with Ctrl+C. |
other | exec: the command's own exit code. |
Every command
| Command | What it does | Options |
|---|---|---|
boxline run "<task>" | Give the AI agent a task and watch it work. While it works, type a line and press Enter to send it a message. | --shell, --no-browser, --session, --model, --var, --secret, --credential, --captcha, --keep, --steps <n|none>, --max-cost <usd>, --timeout <seconds> |
boxline resume <runId> | Keep a run going and watch it: the same run, with the same id. It works on a run that stopped at a limit or after a server restart (within its 10-minute window). | --steps <n>, --no-step-limit, --max-cost <usd>, --note <text>, --var, --secret |
boxline message <runId> <text> | Tell a working run something; it reads it at its next step. | none |
boxline tasks list | List saved tasks, newest first, with their schedules. | --limit <n> (default 20), --all |
boxline tasks run <id> | Run a saved task, wait for it, and print its result (JSON when the task has an output schema). Exit code 0 when it completed, 1 when it failed. | --var name=value, --secret NAME, --session <id> |
boxline credentials list | List the project's credentials (passwords and secrets): names, types, sites, user names and where a password's 2FA codes come from. Never their values. | --limit <n> (default 100), --all |
boxline credentials set <name> | Create a credential, or give one new values. Values come from a hidden prompt or stdin, never an argument. | --type password|secret, --username, --2fa, --remove-2fa, --code-source totp|push|url, --code-url <https://…>, --code-timeout <seconds>, --scope agent|shell|all, --origin <site>, --shell, --description |
boxline credentials push-code <name> | Send the 2FA code or sign-in link a site emailed or texted, to a run that waits for it. It is read from a hidden prompt or stdin, never an argument. | none |
boxline credentials delete <name> | Delete a credential. Profiles that link it are unlinked. | none |
boxline search "<query>" | Search the web: titles, addresses and snippets, and with --fetch the top pages as Markdown. | --limit <n> (1 to 20, default 10), --country <CC>, --language <lang>, --recency day|week|month|year, --fetch <n> (0 to 5) |
boxline fetch <url> | Print a page as Markdown, HTML or text. | --format markdown|html|text, --proxy |
boxline screenshot <url> | Save a screenshot of a page (default <host>.png; .jpg saves a JPEG). | -o <file> (- for stdout), --full-page, --proxy |
boxline pdf <url> | Save a page as a PDF (default <host>.pdf). | -o <file> (- for stdout), --proxy |
boxline extract <url> | Pull structured data out of a page with AI, printed as JSON. | --prompt, --schema <file.json>, --model, --proxy |
boxline crawl <url> | Follow links from a page and collect what they say. | --limit <n> (default 20), -o <dir>, --format |
boxline sessions list | List sessions, newest first. | --status running,stopped,deleted,error, --limit <n> (default 20), --all |
boxline sessions create | Start a session: a browser (the default), a shell only (--no-browser --shell), or both (--shell). | --shell, --no-browser, --proxy, --timeout <seconds>, --idle-timeout <seconds>, --captcha, --keep-alive |
boxline sessions get <id> | Show one session. | none |
boxline sessions stop <id> | Stop a session: save it as it is (the whole browser and its files) and free its machine. Billing stops. It is kept for your plan's days, then deleted. | none |
boxline sessions resume <id> | Bring a stopped session back on a fresh machine, as it was. | none |
boxline sessions delete <id> | Delete a session for good, with what it saved, its recording and its logs. It cannot be undone. | none |
boxline sessions login <id> <credential> | Sign the session's browser in with a saved password credential, in one call: a short AI run types it on its own sites. It waits for a code or sign-in link when the credential takes them from your system. | --url <page> (the sign-in page, on one of its sites) |
boxline sessions live <id> | Print the session's live view link. | none |
boxline exec <id> -- <command…> | Run a command in a session's shell and stream its output. | --cwd, --env NAME=value, --timeout <seconds> (1 to 3600, default 120) |
boxline shell <id> | Open an interactive terminal in a session. | none |
boxline files ls <id> [path] | List files in the session's workspace. Works on a stopped session too. | none |
boxline files get <id> <path> [local] | Download a file (local "-" prints it), or a folder, which comes down as a .tar.gz. Works on a stopped session too. | none |
boxline files put <id> <path> [local] | Upload a file (local "-" reads stdin). | none |
boxline files rm <id> <path> | Delete a file. | none |
boxline usage | Usage and cost, this month so far. | --from <date>, --to <date> |
boxline whoami | The project, plan and API of your key. | none |
boxline login / logout | Save or forget your API key. | --api-url <url> (login) |
Every command also takes --json and --help. boxline <command> --help shows every option.
These docs describe a beta API. Endpoints, fields and SDK methods may change before general availability; breaking changes will be listed in the changelog.