Bandura · API testing IDE

v1.0.0-rc.9 is out now on macOS, Windows and Linux. macOS builds are unsigned early access.

See where your API test breaks.

Trace login, token capture and dependent requests on one visual graph. Inspect the failing step, fix it, and run the same test in CI. Your files stay in your Git repo.

Download for macOS or Windows or Linux Run your first flow

One email when 1.0.0 final ships, no reselling, opt out any time.

macOS: read the first-launch instructions.

Free for personal and commercial use. No account. No trial.

The Bandura desktop app after a run: file explorer on the left, the checkout flow on the graph canvas with green passed rings on every node and a labelled then/else branch, the node inspector on the right showing the resolved POST request, and the console streaming the run below The Bandura desktop app after a run: file explorer on the left, the checkout flow on the graph canvas with green passed rings on every node and a labelled then/else branch, the node inspector on the right showing the resolved POST request, and the console streaming the run below
The whole app, captured from the running build: the flow on the canvas after a green run, and the inspector showing exactly what the selected node sent.
  • Works fully offline

    Edit, run, import, debug. No network, no account, no sign-in wall.

  • Plain text, in your Git repo

    .aether YAML you can diff, review, and blame. No export step, no lock-in.

  • No account, no telemetry

    Tests, tokens, and run history stay local; the only two destinations the app reaches on its own behalf are the AI provider you choose and GitHub, for a switchable once-a-day update check. The complete list.

  • Free for work, too

    No paid seat, trial countdown or activation key.

Import and build

Not an export. Not a sync. Two renderings of one file.

Postman Flows hides the code. Bruno has no graph. Here both views are the same .aether YAML, so there is nothing to keep in sync.

Every YAML block that lands in the Code panel pops the same node into the Graph, and each routing line draws its edge.
- id: login
  type: request
  config:
    method: POST
    url: ${{ variables.baseUrl }}/auth/login
    body: |
      { "email": "${{ env.DEMO_EMAIL }}", "password": "${{ env.DEMO_PASSWORD }}" }
    capture:
      accessToken: response.body.token   # every later node can read this
  next: get_product

Plain YAML with embedded JavaScript: diffable, and readable by any AI assistant.

The same checkout flow as plain .aether YAML in the code editor, showing variables, capture, and routing as text, with the node inspector's Variables tab beside it The same checkout flow as plain .aether YAML in the code editor, showing variables, capture, and routing as text, with the node inspector's Variables tab beside it
The Code tab: the whole flow as YAML. Routing lives on each node, so edges are derived, never stored twice.

Run and inspect

Watch it run. Then ask any node what actually happened.

A run lights the graph node by node. Click any node for its resolved request and response: not the template, the real thing that went over the wire.

The node inspector showing the resolved request: POST /orders with the Authorization header carrying the captured bearer token and the JSON body The node inspector showing the resolved request: POST /orders with the Authorization header carrying the captured bearer token and the JSON body
Method, URL, headers (including the token captured two nodes earlier) and body, fully resolved.
The variables panel after a run: baseUrl, productId, and quantity tagged as flow variables with override fields, and accessToken tagged as captured, linking to the login node that captured it The variables panel after a run: baseUrl, productId, and quantity tagged as flow variables with override fields, and accessToken tagged as captured, linking to the login node that captured it
Flow defaults and captured values, each with its source badge. Captured ones link to the node that produced them.

Unresolved references get a before the run, not a silent undefined three nodes deep.

A flow mid-run: the login, product and stock nodes already ringed green, the order-verification node highlighted as running, and the console below streaming each executed step with its status and duration A flow mid-run: the login, product and stock nodes already ringed green, the order-verification node highlighted as running, and the console below streaming each executed step with its status and duration
Runs you can watch: every node reports as it finishes and the console streams each step. When something fails, it names the node and shows expected against actual.

Commit and share

Sharing a test suite is git clone.

No workspace invite, no export. A Bandura project is a folder of plain-text files, so it was already in your repo. Your teammate clones it and runs.

  1. git clone … && open the folder

    Recognized from bandura.json. Nothing to convert.

  2. fill in the two env vars it asks for

    The manifest declares variable names, never values. Secrets stay in a git-ignored .env or the OS keychain.

  3. ▶ Run

    Under a minute from clone to a green graph.

Review API tests like code, because they are code

@@ flows/checkout-flow.aether @@
   - id: create_order
     type: request
     config:
       method: POST
-      url: ${{ variables.baseUrl }}/order
+      url: ${{ variables.baseUrl }}/orders
       capture:
+        orderId: response.body.id

A test change in a pull request: reviewable, blameable, revertable. Try that with a database-backed collection. More on Git-native API testing →

A close-up of the checkout flow's node cards after a passing run: request, condition and assertion cards with green passed rings and their capture badges, wired left to right A close-up of the checkout flow's node cards after a passing run: request, condition and assertion cards with green passed rings and their capture badges, wired left to right
Your teammate's first run: the same graph you committed, green. If an env var is missing, the app says which one before anything runs.

Automate in CI

The same engine runs everywhere the work happens.

The desktop app, the CLI, and the MCP server share one execution engine. What passes on your machine passes in CI: same code, same file.

On npm now

# Installs a self-contained native binary. No runtime to load.
npm install -g @bandura/cli
bandura --version

# ...or run without installing
npx @bandura/cli run

A native binary per platform: macOS, Linux (glibc & musl), Windows. No account, no backend, and the CLI also runs on macOS without the desktop app. Read the CLI reference →

bandura run with the pretty reporter, then echo $? prints 0.

Exit 0 on green, non-zero on any failure: the CI contract. Reporters: pretty, JSON, JUnit XML, GitHub annotations. Run a file, a glob, or a named collection.

# .github/workflows/api-tests.yml (generated by "Export to CI/CD")
- run: npx @bandura/cli run "flows/**/*.aether" --reporter github
  env:
    BASE_URL: ${{ secrets.STAGING_URL }}

That block runs today: @bandura/cli is on npm and the in-app "Export to CI/CD" writes the file for you. A composite bandura-io/run@v1 Action shortens it to three lines and publishes at launch; until it is on the Marketplace we print the version that works. Secrets arrive as environment variables. The full setup: API tests in CI →

Optional AI

Start with your API. Add AI if it helps.

Build, run and debug flows without a model or API key. If you want help drafting a flow, connect your own provider or use a local model with Ollama or LM Studio. See local model setup →

A flow generated from a natural-language prompt, open on the graph canvas after a passing run: five password-reset nodes with green borders, and the inspector showing the login request spending the captured reset token A flow generated from a natural-language prompt, open on the graph canvas after a passing run: five password-reset nodes with green borders, and the inspector showing the login request spending the captured reset token
Describe the flow; get a schema-valid graph. This one was generated from a one-sentence prompt, validated before it touched disk, then run, and it passed.
The Heal modal comparing a flow against an OpenAPI spec: three drifts found (a renamed path, a missing required header, and a changed method), each with a one-click Apply fix The Heal modal comparing a flow against an OpenAPI spec: three drifts found (a renamed path, a missing required header, and a changed method), each with a one-click Apply fix
Point a flow at your OpenAPI spec: renamed paths, changed methods, new required headers, detected deterministically and fixed with one click. No AI key needed.
The whole loop: run → one node 404s → drift detected → Apply → re-run green. Offline, about eight seconds.

Your agent can run the whole loop

The MCP server exposes your workspace to Claude Code, Claude Desktop, or Cursor: an agent runs a flow, reads the failing node's request and response, edits the YAML, re-runs. It runs where your files are, as a local stdio process, not a vendor cloud relay, so your flows, tokens, and responses never transit anyone's servers. Details: the MCP server →

claude · working in ~/storefront-api
> The checkout flow is failing after the API update. Fix it ⏺ bandura-mcp: run_flow(checkout-flow.aether) ✗ get_receipt · 404 Not Found (GET /order/ord_1042) ⏺ bandura-mcp: detect_drift(checkout-flow.aether, specs/openapi.yaml) path-not-found: GET /order is not in the spec; closest match is GET /orders ⏺ Edit(checkout-flow.aether) /order → /orders ⏺ bandura-mcp: run_flow(checkout-flow.aether) ✓ 7 nodes passed (14ms) Fixed. The orders endpoint moved to /orders, and the flow now passes.

macOS or Windows or Linux? It is live.

v1.0.0-rc.9 is available now. Try a sample flow, then run it against your own API.

Download for macOS or Windows or Linux

One email when 1.0.0 final ships, no reselling, opt out any time.

The rest of the workbench

The parts you only miss when they are gone.

Building the flow

Data-driven runs

Attach a CSV or JSON dataset and the flow runs once per row, that row in scope as data, each row an independent test case.

Typing never blanks the canvas

Half-written YAML doesn't parse, which is normal rather than broken. The last graph that parsed stays on screen, dimmed and marked stale, with editing paused until the file is valid again.

Talking to real APIs

Auth you declare, not assemble

An auth block on a node or the whole flow: basic, bearer, API key, OAuth2, AWS SigV4. OAuth2 fetches the token once per run and refreshes it before it expires, so ten requests make one token call. SigV4 signs the request that actually ships, and re-signs on every retry.

Cookies just work

Set-Cookie is captured and replayed by domain, path and expiry, so log-in-then-use-the-session is two nodes with no Cookie header anywhere. An explicit header still wins, and one flag opts a request out.

Watching it run

Step through it like code

Set a breakpoint on a node, run, and the flow stops there with every captured variable in scope. Step to the next node, run just one, or resume. Breakpoints live in the app, never in the .aether file, so debugging state never lands in a diff.

Run history

Every execution persisted locally in SQLite: durations, per-node results, what changed between runs. It never leaves your machine.

Fitting your setup

Copy any request as code

cURL, JavaScript fetch, Node axios, Python requests, Go, HTTPie. Generated from the request that actually went out, variables already substituted, so what you paste is what ran.

Plays well with other editors

Edit in VS Code or pull from Git and Bandura notices: clean files reload silently, dirty ones ask. It's your file, not the app's.

Node types
10

request · grpc · websocket · assertion · condition · loop · parallel · ai-action · subflow · script

Protocols in one engine
5

REST, GraphQL, gRPC, WebSocket, Server-Sent Events

Import formats
6

Postman, OpenAPI/Swagger, Insomnia, Bruno, HAR, curl

CLI reporters
4

pretty, JSON, JUnit XML, GitHub annotations

MCP tools for agents
14

read, run, lint, search, import, export, drift-detect, create and edit flows, replay runs, schema introspection

Places the same engine runs
3

desktop app, headless CLI, MCP server: one binary's behaviour, not three ports

Side by side

What actually differs, and where the others win.

The differences that decide a switch. Everything else, the good tools all do well.

How Bandura compares with Postman, Bruno and Insomnia on six capabilities and price. Pricing reviewed July 2026.
Bandura Postman Bruno Insomnia
Plain-text, Git-native format ✓ YAML in your repo ✗ cloud workspace ✓ .bru files partial, via Git sync
Graph and code over one file Flows, no code view ✗ code only ✗ code only
Works offline, no account ✗ account + sync account gates most features
AI pricing model BYO model, no credits or metering credit economy n/a BYO LLM
Runs AI on a local model ✓ Ollama / LM Studio, no key, nothing leaves the machine ✗ vendor cloud n/a n/a
Self-healing against OpenAPI drift ✓ deterministic, offline
What it costs Free for personal and commercial use $9–$49 per user/mo $6–$11 per user/mo $12–$45 per user/mo

When Postman is still the right call: protocols we don't speak yet (MQTT, SOAP), a hosted team workspace, or a monitoring cloud. Full matrix and switching guide: Bandura vs Postman. Pricing from our July 2026 review; corrections to hello@bandura.dev.

Deeper comparisons: vs Postman · vs Insomnia · vs Bruno · Postman vs Bruno · the offline case

The Import flows modal with a Postman collection pasted and the format dropdown set to auto-detect, ready to convert into .aether files The Import flows modal with a Postman collection pasted and the format dropdown set to auto-detect, ready to convert into .aether files
Paste a Postman collection, an OpenAPI spec, or a curl command. The format is auto-detected, then shown to you before anything is written.

Import has a review step. You see the detected format, every flow it found with its node count and the calls it makes, the environment variables it picked up, checkboxes to take only the ones you want, and the folder they'll land in. Nothing touches disk until you press Import. (A HAR capture is a recording of one session, so it becomes a single chained flow, not one flow per request.)

Shipping in the open

What's shipped, what's next.

A release cadence is a fact you can check, so here it is: the last five builds, each dated from its release tag. Everything that isn't shipped says so.

  1. 18 September 2026 v1.0.0-rc.9 Bandura is free for personal and commercial use. Release notes
  2. 15 August 2026 v1.0.0-rc.8 Twenty things the editor could not do, most of them about reading a project rather than writing one: moving around it, seeing what a reference points at, and what git thinks you have changed. Release notes
  3. 9 August 2026 v1.0.0-rc.7 Correctness and speed, plus two changes to how your stored credentials are protected that are worth reading even if you skip the rest. Release notes
  4. 8 August 2026 v1.0.0-rc.6 A hardening release: security fixes, a production build that is compiled rather than shipped in readable form, and a considerably smaller install. Release notes
  5. 8 August 2026 v1.0.0-rc.5 The AI assistant became a harness rather than a text box: conversations that survive a restart, a context budget that summarizes instead of forgetting, local workspace search, and tools that let it check this build's schema instead of recalling one. Release notes

Every release, in full →

Shipped

  • Desktop IDE: graph + code over .aether, ten node types, step-through debugging
  • REST, GraphQL, gRPC, WebSocket, SSE on one engine; declared auth and an automatic cookie jar
  • Import from Postman, OpenAPI/Swagger, Insomnia, Bruno, HAR and curl; self-healing against OpenAPI drift
  • Headless CLI, MCP server for agents, AI on your own model including a local one
  • The full list

Next

  • Developer ID signing for macOS when funding permits; no date set
  • Official GitHub Action on the Marketplace; not published yet
  • More protocols (MQTT, SOAP), ordered by early-user demand

Later

  • Scheduled monitors & remote execution
  • Web app
  • Team workspaces (hosted collaboration)

Free to use

Your API tests. No subscription.

Free for personal and commercial use. No trial, paid seat or subscription.

The complete desktop app, CLI and MCP server. No account or activation key required. Bring an API request, build a scenario, and keep the files in your repo.

Download Bandura

If it helps you, support development on Patreon. Support is optional and unlocks no extra features.

Why "Bandura"

Named after an instrument you play with both hands.

The bandura is a Ukrainian string instrument: a lute's fretted neck and a zither's open strings over one soundboard. Two ways of playing, every string tied to the same board: the graph and the code are two hands, and the .aether file is the soundboard underneath.

Questions, answered straight

FAQ

Free use, local files, imports and optional AI.

Getting it

Can I download Bandura today?

Yes, on macOS, Windows and Linux: an early-access release candidate is on the download page now. macOS builds are unsigned early access; the download page explains how to approve the first launch. The CLI, which runs the same engine, is already public on npm as @bandura/cli.

What platforms does it run on?

macOS (Apple Silicon and Intel), Windows, and Linux (AppImage and .deb), each built natively. macOS, Windows and Linux are downloadable today. The Windows build is unsigned until a certificate lands, so expect a one-time SmartScreen warning there; SmartScreen is a Windows thing, so Linux installs run without one. macOS builds are not Developer ID-signed or notarized. First launch requires approval in System Settings → Privacy & Security.

Is Bandura open source?

Not today, but there is no lock-in by design. .aether is documented plain YAML, readable by any tool. Your tests live in your Git history, never in our database.

What happens to my tests if you stop building Bandura?

They keep working, and that is a design constraint rather than a promise. Your flows are plain YAML in your own repository, in a format documented in full, so they are readable and editable with no Bandura installed at all. The runner is a published npm package you already hold a copy of. No activation server controls whether you can run the application. Nothing you own routes through us, which means there is no version of us disappearing that takes your work with it.

Free use and support

Is Bandura free?

Yes. The complete application is free for personal and commercial use. No trial, paid seat, activation key or subscription is required.

How can I support Bandura?

You can contribute through Patreon. Support is optional and unlocks no extra application features.

Support on Patreon →

Why try Bandura if I already use an API client?

Try it on one scenario with dependent requests: login, capture a token, create an object and verify it. The graph shows the dependency chain and the failing step; the same files can run in CI. You do not need to migrate your whole workspace.

An older build asks me to buy a licence. Do I need one?

No. The free-use permission also covers earlier official releases. Older builds may still show the retired reminder; no payment is required. See the download page for the latest available build.

How it works

What is an .aether file?

One flow, as plain YAML with embedded JavaScript: an ordered, branching set of nodes. Routing lives on each node, so there is no separate graph state to drift out of sync.

Isn't this just a wrapper around curl?

No. Nothing shells out. Requests run inside a sandboxed execution engine with its own scheduler, so a flow can branch on a response, loop over a dataset, fan out in parallel, call another flow, hold a WebSocket open, collect an SSE stream, and carry captured variables between nodes with per-run isolation. The same engine binary runs in the desktop app, the CLI, and the MCP server, which is why a run in CI behaves identically to the one you just watched on the canvas.

Does it support GraphQL, gRPC, WebSocket, or SSE?

All four are shipped. GraphQL and SSE ride the request node as optional blocks; gRPC (unary and server-streaming, via .proto or reflection) and WebSocket are their own node types. All run identically in the desktop app, the CLI, and the MCP server.

Can I run one flow against many rows of test data?

Attach a CSV or JSON dataset and the flow runs once per row, that row in scope as `data`. Each row is an independent test case, and a captured value never leaks into the next.

What does a failed run actually tell me?

Which node failed and why: an assertion's expected value against the actual one, the HTTP status, or the unwrapped transport cause, so a DNS or TLS fault reads as itself rather than as a generic `fetch failed`. Each one carries a jump to the matching log line. Repeated identical notifications collapse into one row with a count instead of stacking up.

How do I run API tests in CI?

The bandura CLI runs any flow or glob headlessly and exits non-zero on failure. Reporters: pretty, JSON, JUnit XML, and GitHub annotations.

Migrating, privacy and AI

Is Bandura a Postman alternative?

Yes, and it is the most common migration. No account, no cloud sync: your tests are plain-text .aether files in your own Git repository, and one-click Postman Collection v2.1 import is shipped.

Can I import Postman collections, OpenAPI specs, or curl commands?

Yes, all shipped: Postman Collection v2.1, OpenAPI 3.0/3.1 and Swagger 2.0, pasted curl, Bruno, Insomnia v4, HAR captures, and Postman environment files.

Can I see what an import will do before it writes files?

Yes. Import shows a review step first: the detected format, each flow it found with its node count and the requests it makes, the environment variables it picked up, checkboxes to import only the flows you want, an editable destination folder, and a flat option. Nothing is written to disk until you press Import.

Does Bandura work offline?

Fully. Editing, running, importing, drift detection, the CLI: all local, no account, no network. Two things call out, and nothing else does. AI generation and chat reach whichever provider you configure, and if that is a local Ollama or LM Studio, nothing leaves your machine at all. Separately, the app asks our public releases list once a day whether a newer version exists so it can tell you: it sends no identifier, it fails silently when you are offline, and one switch in Settings turns it off. Nothing is fetched or installed unless you press the button that does it.

Where does Bandura store my settings, API keys, and licence key?

Settings live in a hand-editable `settings.json` next to the app's data, following VS Code's model, with a typed schema: theme, a custom hex accent, font, density, line height, per-token colour overrides, and the AI provider block. Comments are allowed, deleting a key restores its default, an invalid value degrades to the default with a warning instead of breaking the app, and writes are atomic so an interrupted save can't corrupt it. API keys are deliberately not in that file. They stay in the OS-encrypted secret store. The licence key is kept separately too, so hand-editing settings can never invalidate it.

What does the AI cost?

Whatever your own provider costs you. No markup, no credits, no metering. Run it on a local model and it costs nothing. Most of the intelligence needs no key at all either: import, drift detection, and self-healing are deterministic and offline.

Can I use a local LLM, Ollama, or an OpenAI-compatible endpoint?

Yes. There are three providers: Anthropic and Google Gemini natively, and OpenAI-compatible, meaning any /chat/completions endpoint, which covers OpenAI, Groq, OpenRouter, Together, Ollama, and LM Studio. Point the base URL at http://localhost:11434/v1 and a local model powers chat, the agentic tool loop, flow generation, and ai-action nodes with no API key at all and no traffic leaving your machine. A Test connection button confirms it before you rely on it, and the CLI and MCP server read the same provider, base URL, and model from the environment.

Can I use Bandura's AI if my company forbids sending API payloads to a third party?

That is what the local-model path is for. With the provider pointed at an Ollama or LM Studio endpoint on your machine, no prompt, request payload, or response body leaves it, and the deterministic half of the intelligence (import, drift detection, self-healing, mock generation) never calls a model at all.

v1.0.0-rc.9 out now. Early access. No date set for 1.0.0 final.

Run it against your own API tonight.

Download v1.0.0-rc.9 and run your first flow tonight.

Want the v1.0.0 final release link? Leave an address and it arrives when the release is ready. Founding users get credited by name in the release notes, if they want to be. One or two emails, nothing else.

Download for macOS or Windows or Linux

One email when 1.0.0 final ships, no reselling, opt out any time.

No account, no telemetry. Two destinations on the app's own behalf, your AI provider and GitHub, both listed The roadmap marks what has shipped and what hasn't