Local-first, by construction

An API client that works with the cable unplugged.

Bandura is an offline API client and test runner. No account to create, no workspace to sync, no telemetry, and no licence server to be down at the wrong moment. Your flows are plain-YAML files in your own repository, your API keys are in your operating system's encrypted store, your run history is a SQLite file on your disk, and the commercial licence is verified against a public key compiled into the app rather than a service we run. This page names where every piece of that lives, and the two requests the app can make on its own.

v1.0.0-rc.8 is out now on Windows and Linux. v1.0.0 final, and signed macOS builds, in August 2026.

Download for Windows or Linux
or

One email when the signed macOS build and 1.0.0 ship, no reselling, opt out any time.

Windows · Linux · macOS when notarized  ·  What still works offline ↓  ·  Where your data lives ↓  ·  What calls out ↓

Cable unplugged

Not an offline mode. There is no other mode.

Nothing on this list degrades when the network goes away, because none of it was ever reaching a server. The engine runs in a sandboxed process on your machine, and the desktop app, the CLI, and the MCP server all execute the same file identically.

Edit, in both views

Open a folder and work. The graph canvas edits topology, wiring nodes, deleting them and duplicating them, while the Monaco code editor edits the same .aether YAML. Neither is a preview of the other, and there is no document server between them.

Run and debug

All ten node types execute locally, with a streamed console, a variables inspector that names each value's source, breakpoints, step, run-one-node, run-from-node, cancellation, and a whole-run deadline. Failed assertions carry the expected expression against the actual value. Run and debug →

Import what you already have

Postman, Insomnia v4, OpenAPI/Swagger, Bruno .bru and OpenCollection YAML, HAR captures, and raw curl, all converted by code running on your machine, with a review step before anything is written. No upload, no conversion service. Import reference →

Detect and heal API drift

Compare a flow against your OpenAPI spec and get renamed paths, changed methods and new required headers listed with per-finding fixes. It is deterministic code with no model, no key and no metering, so it produces the same answer on a plane as it does at your desk. Self-healing →

Serve a mock of your own API

Bandura turns your flows into an OpenAPI document and serves a stub of it on loopback: one palette command, or bandura mock. Useful when the real API is unreachable, which on a disconnected machine is always. The limit, stated up front: the mock is only as detailed as your flows' assertions.

Git, search, and a terminal, in the app

Stage, diff HEAD against the index, commit, review per-file history, revert a hunk from the gutter, plus project-wide search and replace and a real terminal. Push and pull are your normal Git tooling, and they are the only part that wants a network. Git-native API testing →

The Heal against an OpenAPI spec dialog: the spec path specs/storefront-openapi.yaml, a line reading 0 of 3 request nodes match the spec, and three findings labelled PATH NOT FOUND, MISSING REQUIRED HEADER and METHOD CHANGED, each with the fix it proposes and its own Apply button The Heal against an OpenAPI spec dialog: the spec path specs/storefront-openapi.yaml, a line reading 0 of 3 request nodes match the spec, and three findings labelled PATH NOT FOUND, MISSING REQUIRED HEADER and METHOD CHANGED, each with the fix it proposes and its own Apply button
Run this on a plane and you get the same three findings. It is a comparison of two files, not a service call, so there is no key to configure and no meter to run down.

Where your data lives

Every file, named. Nothing in a place you can't reach.

"Local-first" is a claim; a path is a fact. The app's own data folder is Bandura under your platform's application-data directory: %APPDATA%\Bandura on Windows, ~/.config/Bandura on Linux, and ~/Library/Application Support/Bandura on macOS.

Every piece of Bandura data, where it is stored on your disk, and whether it leaves your machine.
Where it lives Leaves your machine?
Flows .aether YAML files, wherever you put them in your repo Only when you push
Project config A bandura.json manifest beside the flows: globs, environments, required variable names Only when you push
Secrets Your environment, or a .env you don't commit; flows carry env.* references, never literals No
AI provider keys The OS-encrypted store (macOS Keychain, Windows DPAPI, libsecret) in a secrets.json that can't be decrypted on another machine. Never in settings, never in the workspace No
Preferences A hand-editable settings.json in the app's data folder. Comments allowed; delete a key to restore its default No
Licence key Stored separately from settings, so hand-editing preferences can't invalidate it; verified offline against an Ed25519 public key compiled into the app No
Run history history.db, a local SQLite file: durations, per-node results, captured bodies No
Breakpoints & UI state The app's own local storage, per flow path. Deliberately not in the .aether file, so your debugging never lands in a teammate's diff No
Crash & error log An append-only logs/error.log, surfaced as Help: Show error log so a bug report can be a file you chose to attach Only if you send it
Telemetry Not collected. No analytics, no usage counters, no automatic crash upload Nothing to send

Two consequences worth stating. Your laptop carries your state (history, overrides, breakpoints, selected environment) and your repository carries the tests, so a teammate's clone never inherits your machine. And the exit is cp -r: .aether is documented YAML you can parse with your own tools, so nothing here needs an export feature to get out of. Settings reference →

The two exceptions

Two requests the app can make on its own. Both, in full.

Everything above happens without a network. These are the only places the app itself reaches out, as opposed to the requests your flows tell it to send. Both are named in the licence, and both can be switched off.

1. A hosted AI provider, if you configure one

Bandura's AI is bring-your-own. Choose Anthropic, Gemini, or any OpenAI-compatible endpoint and your prompts go to that vendor, under their terms, billed by them. A useful prompt about a failing flow contains the request, the headers, the token captured two steps ago, and the response body. That is a data transfer, and calling it anything else would be dishonest.

We never proxy it. There is no Bandura relay in the path, no credit meter, and no markup. The connection is between your machine and the endpoint you named.

2. A once-a-day check for a newer version

At most once a day the app asks our public releases list whether a newer build exists, and raises a dismissible notification with a link to the download page if one does. It is an anonymous read of a public list, and it carries no information about you, your machine, or your flows.

Downloading it is a separate step, and it is yours: the installer is fetched only after you press the button, or if you turn on automatic downloads, which ship off. Fetching a file necessarily tells GitHub which file, so the operating system, architecture, and version. Settings → Notifications → Check for new versions turns the automatic check off and leaves the manual Check for Updates… in the Help menu.

Two ways to make the first one zero

Leave it unconfigured. Nothing is sent, and the only features that stop working are the three AI ones. Editing, running, debugging, importing, drift detection, export, the mock server, the CLI, and Git all behave identically.

Or point it at localhost. Set the base URL to http://localhost:11434/v1 (Ollama) or http://localhost:1234/v1 (LM Studio) and leave the key field empty. A local runtime authenticates with nothing, so no Authorization header is sent, and the chat, flow generation and the ai-action node run on your hardware. Local models, in detail →

Switch both off and the app makes no request of its own at all. What is left is the obvious traffic, and it is yours: the requests your flows make go wherever you addressed them. An offline client does not mean an offline API.

Headless

The same properties in CI and in an agent.

The CLI is a compiled native binary that reads files and exits with a code. No login, no licence check over the network, no telemetry, and nothing to allow through a firewall except the API you are testing.

# Airgapped CI: a model served on the same host as the job.
export BANDURA_AI_BASE_URL=http://localhost:11434/v1
export BANDURA_AI_MODEL=llama3.1

bandura run "flows/**/*.aether" --reporter junit

A base URL on its own selects the OpenAI-compatible adapter, so there is no provider flag to remember and a local endpoint needs no key variable. On a self-hosted runner serving the model on the same host, an ai-action suite runs with no third-party AI API in the pipeline at all. API testing in CI →

An agent that never leaves the box

bandura mcp boots a stdio MCP server out of the same binary: fourteen tools for Claude Code or Cursor to list, read, run, lint, search, and edit flows, detect drift, import, export a spec, and replay this session's runs. It is a local process speaking over a pipe, so your flows and responses do not transit a vendor's cloud to reach it. Writes are parse-validated and confined to the workspace. The MCP server →

What it costs you

What local-first costs you.

These are real trade-offs, not softened ones. If any of them is load-bearing for your team, a hosted tool is the better answer today and we would rather you knew now.

No hosted workspace or presence

There is no shared collection updating live, no presence indicators, and no server-side team sync. Collaboration is branches, pull requests, and review. For a team already working that way this is the feature; for one that wants non-developers editing in a browser, it is not.

No cloud runs, schedules, or monitors

Bandura executes where you are: the app, the CLI, your CI runner. There is no remote execution service and no scheduled monitoring; cron and your pipeline cover the common case. Remote and scheduled execution are on the post-1.0 list, and until they ship this page will keep saying they are not built.

Your machine is the backup

Nothing syncs, which cuts both ways: a wiped disk takes your run history and your settings with it. The flows survive because they are in Git, which is the point. History and preferences are per-machine, and we do not keep a copy.

The mock is only as good as your assertions

A generated stub is derived from what your flows actually check. A flow that asserts a status code produces a mock that returns a status code. That is the honest limit of deriving a spec from tests, not a bug to be fixed later.

The installers are unsigned, and macOS isn't out

Windows and Linux builds are on the download page today; the Windows one is unsigned, so SmartScreen shows a warning you click through. macOS builds are held until they are signed and notarized, because "right-click and choose Open" is not an install instruction we are willing to print. Certificates are the last item before 1.0.0 final.

Nothing here is audited by a third party

Every claim on this page is checkable. Watch the process with lsof, run it behind a blocking firewall, read the settings.json and history.db on your own disk. What there is not is a SOC 2 report or an external code audit, and a security review that requires one will not accept this page instead.

If someone else has to sign this off, send them the vendor-questionnaire answers rather than this page. Same facts, arranged the way a reviewer asks for them, plus the app's sandboxing and the compliance claims we deliberately do not make.

Questions, answered straight

FAQ

Does Bandura work without an internet connection?

Yes. Opening a workspace, editing a flow in the graph or the code editor, running it, debugging it with breakpoints, importing a Postman/Insomnia/Bruno/OpenAPI/HAR/curl file, detecting drift against an OpenAPI spec, exporting a spec, starting the local mock server, searching and replacing across the project, using the in-app Git view and terminal, and running the CLI or the MCP server all happen on your machine with no network involved. The only thing that needs the network is whatever your own flows request: a flow pointed at a staging API still has to reach that API. Two things reach out on their own, and neither is needed for any of the above: AI features contact the provider you configured, and once a day the app asks our public releases list whether a newer version exists. Offline, that check fails quietly and nothing else notices, and a switch in Settings turns it off for good.

Do I need an account or a login?

There is none to create. Bandura has no user accounts, no sign-in screen, and no server on our side holding your data, which means there is also no session to expire, no seat to be revoked, and no outage that can lock you out of your own files. Even buying a licence does not create an account: you get a key, you paste it in once, and it is verified locally.

Does Bandura send telemetry, analytics, or crash reports?

No, none of the three. Nothing is collected, so there is no opt-out toggle to hunt for and no anonymised-usage clause to read. Crashes are written to an append-only error.log inside the app's own data folder and surfaced under Help: Show error log, which exists so a bug report can be a file you choose to attach. If telemetry is ever added it will be opt-in, and this paragraph will change before the code does.

Where does each piece of my data actually live?

Flows are .aether YAML files wherever you put them in your repository, alongside a bandura.json manifest. Secrets are env.* references resolved from your environment or a .env you do not commit. AI provider keys go into your operating system's encrypted store (macOS Keychain, Windows DPAPI, libsecret on Linux) in a secrets.json the app cannot read on another machine, and never into settings. Preferences are a hand-editable settings.json in the app's user-data folder, comments allowed. Run history is a local SQLite file, history.db, beside it. Breakpoints are per-machine debug state in the app's own local storage, never in the flow file. The licence key is held separately again, so editing settings cannot invalidate it.

Does the licence check phone home?

It cannot. A Bandura licence is an offline Ed25519-signed key: the app verifies the signature against a public key compiled into the binary, on your machine, with no network call, at purchase, at activation, and every time after. There is no activation server to be down, no seat count being watched, and no way for us to switch off a copy you already have. That also means a build you have keeps working after the 12-month update window ends, because nothing is checking.

What leaves the machine, and when?

Two things reach out on their own, and only one of them can carry anything of yours. The first is a hosted AI provider, if you configure one: Bandura's AI is bring-your-own, so pick Anthropic, Gemini, or any OpenAI-compatible endpoint and prompts go to whoever you pointed it at, under their terms and billed by them, not us. A useful question about a failing flow carries the request, the headers, and the response body with it. The second is updates: at most once a day the app asks our public releases list whether a newer version exists. That question carries no information about you, your machine, or your flows. If a newer version is there, Bandura can fetch and install it, but only once you press the button, and fetching a file necessarily tells GitHub which file, so the platform and the version. updates.checkOnStartup turns the whole thing off. Leave the AI unconfigured, or point it at localhost, and turn that switch off, and the app makes no request of its own at all. Separately from both: your flows' own requests go wherever you addressed them.

Can the AI run offline too?

Yes, on your own hardware. The OpenAI-compatible adapter targets the wire format, not the vendor, so a local runtime is just another endpoint: base URL http://localhost:11434/v1 for Ollama or http://localhost:1234/v1 for LM Studio, a model id, and no API key. A local server authenticates with nothing, so no Authorization header is sent. Chat, the agentic tool loop, flow generation, and the ai-action node all run against it. Separately, half of what looks like intelligence never involves a model at all: importing, drift detection and healing, OpenAPI export, and the mock server are deterministic code.

Will this pass a security review?

That depends on what your reviewer needs, and /security/ is written for them rather than for you: what crosses the network and when, where flows, credentials and run history are stored, how the desktop app is sandboxed, and the answers most vendor questionnaires ask in the order they ask them. It also states the claims we deliberately do not make. There is no SOC 2 report and no external code audit, and a review that requires one will not accept a page instead.

Can CI run offline, on a self-hosted runner?

Yes. The CLI is a compiled native binary that reads files and exits with a code: no login, no licence server, no phone-home step in the pipeline. On a self-hosted runner with a model served on the same host, even ai-action nodes run with no third-party API in the pipeline; with nothing configured, only those nodes fail while the rest of the suite runs normally. The MCP server reads the same environment variables, so an agent-driven run has the same properties.

Keep reading

The same argument, from other angles.

Tests as files in your repo

The other half of having no server: the flows are yours to move, review and restore with the same tools as the code.

Close the last outbound call

Ollama or LM Studio on localhost: no API key, and no prompt or payload sent anywhere.

Postman vs Bruno, sourced

The cloud workspace and the local files, compared on their own terms, with Bandura as the third option rather than the headline.

Coming from Postman

The account, the workspace sync, and the credit meter, plus what the migration actually looks like.

Coming from Insomnia

What the 2023 account episode did and didn't change, and how Git Sync differs from files on disk.

Already offline with Bruno?

Then this page told you nothing new. The straight answer to "why pay for this instead" is here.

Also relevant: running the suite in CI with no login step in the pipeline, and the privacy policy, which is short because there isn't much to say.

v1.0.0-rc.8 is out now. v1.0.0 final in August 2026

Nothing to log into. Nothing to sync. Nothing collected.

Don't take the table on trust. Install it, pull the network cable, and see which of these claims survives: the whole page is written to be falsifiable in an afternoon. Windows and Linux builds are up; on a Mac, leave an address and you get the signed build the day it is notarized.

Download for Windows or Linux

One email when the signed macOS build and 1.0.0 ship, no reselling, opt out any time.

Not the one who installs it? Send your reviewer to the security and procurement page.