@burtson-labs/bandit-stealth-cli 1.7.499 → 1.7.501
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +93 -23
- package/dist/cli.js +1647 -1527
- package/package.json +3 -2
package/README.md
CHANGED
|
@@ -8,7 +8,7 @@
|
|
|
8
8
|
|
|
9
9
|
**Local-first AI coding agent for your terminal.**
|
|
10
10
|
|
|
11
|
-
|
|
11
|
+
Runs on your machine and works with any Ollama model. Your prompts, and the files and command output the agent reads, go to the model server you configure (Ollama at `http://localhost:11434` by default). In the default permission mode, a tool that would contact another host asks you first. [Network and offline mode](#network-and-offline-mode) lists every connection Bandit makes and how to turn each one off.
|
|
12
12
|
|
|
13
13
|
_Prefer an IDE?_ The sibling Bandit Stealth extension for VS Code / Cursor ships the same runtime, skills, and tool-use loop — install from the [VS Code Marketplace](https://marketplace.visualstudio.com/items?itemName=BurtsonLabs.bandit-stealth) or [Open VSX](https://open-vsx.org/extension/BurtsonLabs/bandit-stealth).
|
|
14
14
|
|
|
@@ -45,6 +45,8 @@ _Prefer an IDE?_ The sibling Bandit Stealth extension for VS Code / Cursor ships
|
|
|
45
45
|
bandit "explain @src/auth/login.ts" # one-shot with a file mention
|
|
46
46
|
```
|
|
47
47
|
|
|
48
|
+
The CLI installs two commands that do the same thing: `bandit` and `bandit-agent`. The Python security linter [Bandit](https://github.com/PyCQA/bandit) also installs a `bandit` command; if it comes first on your PATH (common in Python environments and on shared clusters), use `bandit-agent`. `bandit doctor` tells you when that happens.
|
|
49
|
+
|
|
48
50
|
That's it. No API keys. No cloud services. The agent reads your code, searches, runs commands, and writes changes — all locally.
|
|
49
51
|
|
|
50
52
|
### Terms of Use
|
|
@@ -108,7 +110,7 @@ guard, not a guarantee of correctness; `BANDIT_VERIFY_BEFORE_DONE=0` disables it
|
|
|
108
110
|
- **Hooks + security guard** — `PreToolUse` / `PostToolUse` / `Stop` shell hooks (global `~/.bandit/settings.json` or per-workspace), plus a default-on built-in guard that blocks catastrophic commands. See [Settings file](#settings-file--hooks-permissions-security-guard)
|
|
109
111
|
- **12 themes** — Stealth Light/Dark, Midnight, Onyx, Charcoal, Dracula, Nord, Tokyo Night, Solarized Dark/Light, Catppuccin Mocha, Sepia. `/theme` to pick
|
|
110
112
|
- **Cross-platform** — macOS, Linux, Windows; Windows `.cmd`/`.bat` shims (npm/npx/pnpm/tsc) resolved correctly
|
|
111
|
-
- **Update-aware** — fire-and-forget npm-registry check at boot; `update vX.Y.Z available` shows in the status bar when a newer CLI is published. Set `BANDIT_NO_UPDATE_CHECK=1` to skip the check
|
|
113
|
+
- **Update-aware** — fire-and-forget npm-registry check at boot; `update vX.Y.Z available` shows in the status bar when a newer CLI is published. Set `BANDIT_NO_UPDATE_CHECK=1` (or `BANDIT_OFFLINE=1`) to skip the check
|
|
112
114
|
|
|
113
115
|
---
|
|
114
116
|
|
|
@@ -207,6 +209,8 @@ Bandit speaks MCP as a client, so any MCP server you can spawn (filesystem, git,
|
|
|
207
209
|
|
|
208
210
|
Servers spawn lazily on first invocation, persist for the session, and get cleaned up on REPL exit. Failures are isolated — a broken server logs an error and the rest of the loop keeps running on native tools only. Off by default — no config file = zero behavior change.
|
|
209
211
|
|
|
212
|
+
MCP tools ask before they run, because Bandit cannot see what a server does with the arguments. Add `"local": true` to a stdio server's entry to say it does not contact other hosts; its read-named tools (`list…`, `get…`, `search…`, `read…`) then run without asking, and its other tools still ask. Your Bandit Cloud key is passed to a server only when its entry has `"auth": "bandit"`.
|
|
213
|
+
|
|
210
214
|
---
|
|
211
215
|
|
|
212
216
|
## Recommended models
|
|
@@ -304,24 +308,30 @@ Workspace config overrides user config. Secrets belong in the user-level file, n
|
|
|
304
308
|
|
|
305
309
|
### Environment variables
|
|
306
310
|
|
|
307
|
-
| Var | Default | Description
|
|
308
|
-
| ------------------------ | ------------------------- |
|
|
309
|
-
| `BANDIT_PROVIDER` | `ollama` | `ollama` or `bandit`
|
|
310
|
-
| `BANDIT_MODEL` | `gemma4:e4b` | Model ID
|
|
311
|
-
| `BANDIT_API_KEY` | — | Required when `BANDIT_PROVIDER=bandit`
|
|
312
|
-
| `BANDIT_API_URL` | `https://api.burtson.ai` | Override Bandit API endpoint
|
|
313
|
-
| `OLLAMA_URL` | `http://localhost:11434` | Ollama endpoint
|
|
314
|
-
| `
|
|
315
|
-
| `
|
|
316
|
-
| `
|
|
317
|
-
| `
|
|
318
|
-
| `
|
|
319
|
-
| `
|
|
320
|
-
| `
|
|
321
|
-
| `
|
|
322
|
-
| `
|
|
323
|
-
| `
|
|
324
|
-
| `
|
|
311
|
+
| Var | Default | Description |
|
|
312
|
+
| ------------------------ | ------------------------- | -------------------------------------------------------------------------------------------------------------------- |
|
|
313
|
+
| `BANDIT_PROVIDER` | `ollama` | `ollama` or `bandit` |
|
|
314
|
+
| `BANDIT_MODEL` | `gemma4:e4b` | Model ID |
|
|
315
|
+
| `BANDIT_API_KEY` | — | Required when `BANDIT_PROVIDER=bandit` |
|
|
316
|
+
| `BANDIT_API_URL` | `https://api.burtson.ai` | Override Bandit API endpoint |
|
|
317
|
+
| `OLLAMA_URL` | `http://localhost:11434` | Ollama endpoint |
|
|
318
|
+
| `OLLAMA_HOST` | — | Ollama's own variable (`node:port`, `http://node:port`); used after `OLLAMA_URL` and config |
|
|
319
|
+
| `BANDIT_NUM_CTX` | chosen per model | Context window to request from Ollama (`32768`, `32k`); same as `--num-ctx` |
|
|
320
|
+
| `BANDIT_HOME` | `~/.bandit` | Where sessions, crash reports and the Apptainer image live; settings stay in `~/.bandit` |
|
|
321
|
+
| `BANDIT_NO_LOGIN_HINT` | `0` | `1` to hide the note shown on what looks like a cluster login node |
|
|
322
|
+
| `BANDIT_MAX_ITERATIONS` | `20` | Tool-use loop cap |
|
|
323
|
+
| `BANDIT_AUTO_APPROVE` | `0` | `1`/`true` to skip write-approval prompts |
|
|
324
|
+
| `BANDIT_TELEMETRY` | `0` | `1`/`true` to enable OTLP telemetry (opt-in) |
|
|
325
|
+
| `BANDIT_OTLP_ENDPOINT` | `https://otlp.burtson.ai` | OTLP/HTTP collector base URL |
|
|
326
|
+
| `BANDIT_OTLP_TOKEN` | — | Bearer token for the collector (defaults to your Bandit token) |
|
|
327
|
+
| `BANDIT_OTLP_MODE` | `metrics+traces` | `metrics-only` to drop span payloads |
|
|
328
|
+
| `BANDIT_NO_UPDATE_CHECK` | `0` | `1`/`true` to skip the npm-registry update check at start (one plain GET; nothing is installed) |
|
|
329
|
+
| `BANDIT_OFFLINE` | `0` | `1`/`true`: offline mode. Only the model server is contacted ([Network and offline mode](#network-and-offline-mode)) |
|
|
330
|
+
| `BANDIT_NO_MODELS_DEV` | `0` | `1`/`true` to never fetch the models.dev catalogue for an OpenAI-compatible server |
|
|
331
|
+
| `BANDIT_NO_BROWSER` | `0` | `1`/`true` to never launch the default browser (`insights`, share links); the path or link is still printed |
|
|
332
|
+
| `BANDIT_NO_CLIPBOARD` | `0` | `1`/`true` to leave the clipboard alone when a share link is printed |
|
|
333
|
+
| `BANDIT_ACCEPT_TERMS` | — | `1`/`true` to accept the [Terms of Use](#terms-of-use) for this run without a prompt (same as `--accept-terms`) |
|
|
334
|
+
| `NO_COLOR` | — | Disable ANSI colors |
|
|
325
335
|
|
|
326
336
|
### Settings file — hooks, permissions, security guard
|
|
327
337
|
|
|
@@ -416,7 +426,7 @@ Off by default. When enabled, Bandit emits **OpenTelemetry** over OTLP/HTTP: one
|
|
|
416
426
|
|
|
417
427
|
The default `endpoint` is `https://otlp.burtson.ai` only because the default audience is Bandit Cloud; **set your own** otherwise.
|
|
418
428
|
|
|
419
|
-
**
|
|
429
|
+
**What is sent:** the model name, tool names, the first 120 characters of each tool's main argument (a file path, command, URL or search query), token counts, durations and short error text, after secret redaction. The CLI does not send your prompt or the model's replies. `metrics-only` drops the traces, and with them the tool arguments. Nothing is sent unless you set `enabled: true` (or `BANDIT_TELEMETRY=1`), and nothing in offline mode.
|
|
420
430
|
|
|
421
431
|
### Remote GPU
|
|
422
432
|
|
|
@@ -460,18 +470,78 @@ Tear the pod down when you're done. ~$2/hr for an H100 SXM × 15-20 min agent se
|
|
|
460
470
|
|
|
461
471
|
**Avoid for agent work:** `gpt-oss:120b` and similar reasoning-tuned models. They're post-trained for OpenAI's harmony tool-call format, not the XML protocol Bandit uses for non-native models — they tend to narrate intent without emitting tool calls. Great for math/proofs in chat, poor for filesystem agent loops.
|
|
462
472
|
|
|
473
|
+
### University clusters (Slurm, Ollama in a GPU job)
|
|
474
|
+
|
|
475
|
+
The usual setup: a batch job starts `ollama serve` on a GPU node with a random port and writes `node:port` to a file; you work from an interactive job.
|
|
476
|
+
|
|
477
|
+
```sh
|
|
478
|
+
srun --pty bash # or salloc / your site's interactive command; not a login node
|
|
479
|
+
export OLLAMA_HOST=$(cat ~/.ollama_server) # node:port written by the Ollama job
|
|
480
|
+
export BANDIT_HOME=/scratch/$USER/bandit # sessions and caches off the home quota
|
|
481
|
+
bandit-agent --model qwen2.5-coder:32b
|
|
482
|
+
```
|
|
483
|
+
|
|
484
|
+
- **Endpoint.** Bandit reads `OLLAMA_HOST` the way Ollama's own client does (`node:port`, `http://node:port`, `0.0.0.0`), after `--ollama-url`, `OLLAMA_URL` and the config file. The line under the banner says which endpoint is in use and where it came from.
|
|
485
|
+
- **Context window.** Ollama's own default is 4,096 tokens on GPUs under 24 GB. Bandit always asks for a window per request (at least 16,384; 24,576 for most 7–14B models, 32,768 for 27B and up; never more than the model's own), so `OLLAMA_CONTEXT_LENGTH` and custom Modelfiles are not needed. Bandit's instructions and tool definitions take about 5,500 tokens before your files. At 4,096 the task itself gets cut off; at 8,192 the agent forgets what it read and goes in circles. Below 16,384 Bandit says so at startup. Set the window with `--num-ctx`, `BANDIT_NUM_CTX` or `"ollama": { "numCtx": 32768 }`. After the first reply Bandit checks what Ollama loaded and warns when part of the model spilled to the CPU, with a window that would fit.
|
|
486
|
+
- **Login nodes.** Started over SSH on a Slurm login node (outside a job), Bandit prints a one-line reminder to start an interactive job. It never blocks. `BANDIT_NO_LOGIN_HINT=1` hides it.
|
|
487
|
+
- **Home quota.** `BANDIT_HOME` moves what grows (`sessions/`, `crashes/`, `training/`, and the Apptainer sandbox image when `APPTAINER_CACHEDIR` is unset) to scratch. Settings stay in `~/.bandit` (`config.json`, `settings.json`, `mcp-servers.json`, `lessons.md`, `terms.json`; a few KB) so a scratch purge never signs you out. Each project also gets a `.bandit/` folder with turn logs and checkpoints.
|
|
488
|
+
- **Resume after reconnecting.** Sessions are saved with the directory they started in. `bandit --continue` (or `-c`) resumes the latest session of the current directory from any login; `bandit --resume` lists this directory's sessions first.
|
|
489
|
+
- **Scripts and batch jobs.** Piped stdin is sent with the prompt, and `--output json` prints one JSON object (answer, tool calls, files changed, status, timing) on stdout with progress on stderr:
|
|
490
|
+
|
|
491
|
+
```sh
|
|
492
|
+
cat slurm-${SLURM_JOB_ID}.out | bandit-agent "the job failed: explain the error"
|
|
493
|
+
bandit-agent --auto --output json "summarize results.csv" > summary.json
|
|
494
|
+
```
|
|
495
|
+
|
|
496
|
+
Exit codes: `0` done, `1` failed (model, endpoint or runtime), `2` bad usage, `3` stopped before finishing (iteration limit, or no answer). With stdin as input there is nobody to answer an approval prompt, so approvals are denied; use `--auto`, or `BANDIT_PERMISSION_MODE=dangerous` inside a sandbox, for unattended runs.
|
|
497
|
+
|
|
498
|
+
- **Sandboxed commands without Docker.** `bandit --sandbox` runs agent commands under Apptainer or SingularityCE when there is no Docker. See `bench/agent/CLUSTER.md`.
|
|
499
|
+
|
|
463
500
|
---
|
|
464
501
|
|
|
465
502
|
## Security & privacy
|
|
466
503
|
|
|
467
|
-
- **
|
|
504
|
+
- **Network** — with `provider=ollama` the conversation goes only to your Ollama server. The other connections Bandit can make, and how to turn each off, are listed under [Network and offline mode](#network-and-offline-mode). Tools that contact another host ask first in the default mode, and `BANDIT_OFFLINE=1` turns all of it off.
|
|
468
505
|
- **Approval gate** — all file writes show a unified diff before touching disk (unless `BANDIT_AUTO_APPROVE=1`).
|
|
469
506
|
- **Command allowlist** — `run_command` only executes from an internal allowlist (git, gh, kubectl, helm, brew, standard *nix tools). Arbitrary shell is refused.
|
|
470
507
|
- **Container sandbox (opt-in)** — `bandit --sandbox` or `BANDIT_SANDBOX=1` runs every agent `run_command` / `watch_command` inside a short-lived Docker or Podman container with the same policy as the Stealth IDE: one workspace mount, no network, no Linux capabilities, read-only root, `no-new-privileges`, bounded CPU/memory/pids/output/time, your uid:gid. On a cluster with neither, Apptainer or Singularity run the same image (pulled by digest into a SIF under `$APPTAINER_CACHEDIR/stealth-sandbox` or `~/.bandit/sandbox-apptainer`), as you, with the network namespace checked before every command and the command refused when it cannot be isolated (`sandbox/README.md`, Apptainer). `BANDIT_SANDBOX_RUNTIME=apptainer` (or `docker`, `podman`, `singularity`, comma-separated) picks the runtime. Fail-closed once enabled — no runtime means the command is refused, never quietly run on the host. Image: `ghcr.io/burtson-labs/stealth-sandbox`, chosen from the project's files — the base (node, git, ripgrep, python3, C toolchain) or the dotnet, go, rust or python image built on it; override with `BANDIT_SANDBOX_IMAGE` (a stack name or an image reference). `BANDIT_SANDBOX_INSTALL_NETWORK=1` gives install commands (`npm install`, `pip install`, `dotnet restore`, `go mod download`, …, run on their own) the network; every other command stays offline. Enterprise-managed installs should set `BANDIT_SANDBOX=1` in the environment.
|
|
471
508
|
- **Pre-tool security guard** (default-on) — configure `security.guard` in your [settings file](#settings-file--hooks-permissions-security-guard) to extend or explicitly disable blocking of catastrophic commands (`rm -rf /`, `curl … | sh`, disk wipes, credential exfil, writes to `/etc` or `~/.ssh`) before they run. Defense-in-depth against the model, applied in both CLI and IDE.
|
|
472
509
|
- **Custom hooks** — your own `PreToolUse` shell scripts can veto any tool call; configure globally (`~/.bandit/settings.json`) or per-project.
|
|
473
|
-
- **Secret hygiene** — API keys are redacted in `/config` output and never logged. The optional [telemetry](#telemetry-opt-in) exporter
|
|
510
|
+
- **Secret hygiene** — API keys are redacted in `/config` output and never logged. The optional [telemetry](#telemetry-opt-in) exporter sends no prompt or reply text, and runs the tool arguments it does send through secret redaction.
|
|
474
511
|
- **Local sessions** — stored as JSONL under `~/.bandit/sessions/`. Inspect at any time.
|
|
512
|
+
- **Turn logs** — each turn is logged to `<project>/.bandit/turns/` (your prompt, tool calls and short excerpts of tool output). When Bandit creates `.bandit/`, it writes `.bandit/.gitignore` so these logs, checkpoints and pasted images are not committed. It never overwrites an existing `.bandit/.gitignore`. If your project's `.bandit/` predates this, add `turns/` and `checkpoints/` to it yourself.
|
|
513
|
+
|
|
514
|
+
## Network and offline mode
|
|
515
|
+
|
|
516
|
+
**What Bandit contacts on its own:**
|
|
517
|
+
|
|
518
|
+
| Connection | When | What is sent | Turn it off |
|
|
519
|
+
| --------------------------------------------------------------------------------------------- | -------------------------------------------------------------------------------------------------------------------------------------------------------------- | ------------------------------------------------------------------------------------------------------- | ------------------------------------------ |
|
|
520
|
+
| Your model server (`OLLAMA_URL`, `OPENAI_BASE_URL`, or Bandit Cloud with `--provider bandit`) | Every turn, plus a short follow-up request after each turn for next-prompt suggestions and project memory | The conversation: prompts, system prompt, file contents and command output the agent read, tool results | Choose the server |
|
|
521
|
+
| `registry.npmjs.org` | When an interactive session starts (not in one-shot `bandit "prompt"` mode) | A plain request for the latest version number. No account, device or project data | `BANDIT_NO_UPDATE_CHECK=1` or offline mode |
|
|
522
|
+
| `models.dev` | At start-up with `--provider openai-compatible`, only when `OPENAI_BASE_URL` is a public host. Never for a server on this machine or a private network address | A request for the public model catalogue. No user data | `BANDIT_NO_MODELS_DEV=1` or offline mode |
|
|
523
|
+
|
|
524
|
+
Telemetry is off unless you turn it on ([Telemetry](#telemetry-opt-in)). Bandit has no analytics or crash reporting.
|
|
525
|
+
|
|
526
|
+
**Tools that contact another host ask first.** In the default `ask` mode, Bandit shows an approval card before any of these run, with the full address (or, for git, the remote's URL):
|
|
527
|
+
|
|
528
|
+
- `web_fetch`, `fetch_image` (any URL; private, loopback and link-local addresses are refused unless `BANDIT_ALLOW_PRIVATE_WEB_FETCH=1`), `web_search` (Tavily, only with a Tavily key);
|
|
529
|
+
- `git_push`, `git_pull`;
|
|
530
|
+
- the Bandit Cloud artifact tools (`publish_artifact`, `share_artifact`, `email_artifact`, …), which exist only when Bandit Cloud is the provider;
|
|
531
|
+
- MCP tools, unless the server's entry says `"local": true` (then its read-named tools, such as `list…`/`get…`, run without asking; its other tools still ask).
|
|
532
|
+
|
|
533
|
+
Plan mode refuses all of them. In auto mode (`--auto`), the CLI's reviewer model decides whether such a call is one you asked for, and can let it run without a card; `list_artifacts`, `get_artifact` and MCP read-named tools run there without review. `dangerous` mode runs everything. An allow rule in `.bandit/settings.json` (for example `"web_fetch:https://docs.example.com/*"`) lets matching calls run without asking. `run_command` always asks in the default mode; `--sandbox` runs commands with no network. Graph runs (`bandit graph`, `bandit spec`) cannot ask, so they leave out `web_fetch` and `web_search` unless `BANDIT_GRAPH_WEB=1`.
|
|
534
|
+
|
|
535
|
+
**MCP servers and your Bandit key.** Bandit gives your Bandit Cloud key to an MCP server only when its entry asks for it with `"auth": "bandit"` (and to Burtson Labs' own server, which `/mcp google connect` sets up).
|
|
536
|
+
|
|
537
|
+
**Offline mode.** Set `BANDIT_OFFLINE=1`, or put `"offline": true` in `~/.bandit/settings.json` or the project's `.bandit/settings.json`. An administrator can set it for every user of a machine with `{ "network": { "offline": true } }` in `/etc/bandit/policy.json` (macOS: `/Library/Application Support/Bandit/policy.json`; Windows: `C:\ProgramData\Bandit\policy.json`). Any one of these turns it on, and none of the others can turn it off. A policy file that exists but cannot be read as JSON also turns it on. In offline mode:
|
|
538
|
+
|
|
539
|
+
- Bandit connects only to your model server and to loopback addresses. An HTTP request to any other host fails at once with a message naming the host.
|
|
540
|
+
- The update check, models.dev and telemetry are off.
|
|
541
|
+
- `web_fetch`, `web_search`, `fetch_image` and the artifact tools are not offered to the model. `git_push`, `git_pull` and MCP tools from servers not marked `"local": true` are refused.
|
|
542
|
+
- Bandit Cloud features are refused with a message: the `bandit` provider, sign-in, `/remote`, `/usage`, `/artifact`, `bandit runner`, `bandit artifact` and `bandit upgrade`.
|
|
543
|
+
|
|
544
|
+
Offline mode does not control the commands the agent runs with `run_command` (they ask first in the default mode; use `--sandbox` for no network), what a stdio MCP server you configured does on its own, or `docker`/`podman`/`apptainer` pulling the sandbox image (set `BANDIT_SANDBOX_REGISTRY_MIRROR` or load the image beforehand).
|
|
475
545
|
|
|
476
546
|
---
|
|
477
547
|
|