Bruno v4.0.0: Native AI, Typed Variables, and Apps

Picture of Anthony Dombrowski
Bruno v4.0.0: Native AI, Typed Variables, and Apps

 

Bruno v4.0.0 is here. Most of what's in it comes straight from the papercuts Bruno users know well: string-typed variables you have to parse by hand, secrets bolted on beside your environments, docs that are hard to share, and a slow cold start on big collections. We fixed those at the foundation and added a few genuinely new capabilities on top, including native AI and Apps. Through all of it, the core contract is unchanged: your collections are plain text files, versioned in your repo, running locally with no cloud in the loop.

⚠ Upgrading from v3? Read this first

Most collections upgrade cleanly, but v4 ships a handful of breaking changes worth reviewing before you update:

  • Secret Manager migration. Secret configuration moves out of secrets.json and into your environments. The desktop app migrates a collection automatically when you open it; the CLI does not, so open it in the app once, then run with bru run --env <name>. The old {{$secrets.name.key}} reference syntax is deprecated in favor of {{name.keyname}} and will be removed after three months.
  • Scripts now persist environment-variable changes to disk (API change). bru.setEnvVar(), bru.deleteEnvVar(), and bru.setGlobalEnvVar() now write to your environment file by default. If any of them set tokens, keys, or other secrets, either keep the same methods and pass { persist: false } to keep the value in memory for the run, or switch those calls to bru.setVar() / bru.deleteVar(), so nothing sensitive gets committed by accident.
  • Mixed-version teams, coordinate the upgrade. The new multi-message WebSocket format and the new description and variable-type annotations mean a collection saved in v4 can fail to load for teammates still on older Bruno versions.
  • CLI JUnit output. Each test's classname now uses the collection path (Folder/Request Name) instead of the request URL, so update any CI such as Xray or Azure DevOps that keys off it.

Full migration steps and before/after examples are in the full v4 release guide →

AI Request Assistance, Built Into the Tab You're Already In

Most AI coding help lives in a different window. You copy your request out, paste it into a chatbot, describe the context the model can't see, and paste the answer back. It works, but it's a lot of tab-tennis.

Bruno v4 puts the assistant inside the request view. A new chat sidebar stays grounded in your active request tab, so its suggestions are always about the thing you're actually looking at: this endpoint, these headers, this response shape. Think of it less like a chatbot and more like a pair-programmer reading over your shoulder at the same screen.

From there it can:

  • Generate pre-request and post-response scripts from a plain-English description.
  • Write test cases against the response you're seeing, so assertions actually match your data.
  • Draft inline documentation directly from the request view.

The scripting editor also gets autocomplete, so even when you're writing by hand there's less reaching for the docs. Together, these cut the manual overhead of building collections that are well-tested and well-documented, the chores everyone means to do and nobody enjoys.

GET /api/orders/{id} Active request tab 200 OK · 142 ms AI Assistant Grounded in this tab "Write tests for this response" Generate

The assistant reads the same context you do, so there's no copy-paste required.

Bring Your Own Key. There's no Bruno-hosted model and no new account. Connect your own OpenAI, Anthropic, or any OpenAI-compatible endpoint, and AI runs through your existing provider. Your keys, your bill, your data path: exactly how a local-first tool should do it.

Apps: Build Your Own UI Right Inside Bruno

Sometimes a raw request-and-response view isn't the interface you want. Maybe the person running the request shouldn't have to know which header to tweak. Maybe you want a dashboard that fires ten endpoints and shows a wall of green checkmarks. Maybe the JSON coming back is easier to reason about as a chart than as 400 lines of text.

v4 ships the first version of Apps: a way to embed a custom UI, written in plain HTML and JavaScript, right alongside a request or collection. Flip a tab into App mode and your interface takes over the request/response area for that tab. Think of it as a little browser window living inside Bruno, wired directly into your API workflow, with a friendly toggle to hop back to the normal editor whenever you want.

Because an App's code is saved into the item's own file, it travels with your collection through Git just like everything else in Bruno. Your custom tooling is versioned, reviewable, and shareable by default, with nothing living in a cloud you don't control.

Two flavors, depending on what you're building

  • Request-level apps attach to a single request. They can send that request through the full pipeline (pre and post scripts, tests, assertions, timeline, and all) and read its live response, assertion results, and test results as they come in. Great for wrapping one gnarly endpoint in a clean form, or visualizing its response.
  • Collection and folder-level apps attach to a collection or folder. They can't drive one specific request, but they can list and run any request in the collection. This is the sweet spot for dashboards, health checks, and "run everything and show me the status" control panels.
Bruno (host) Your requests & collection Live responses, tests, variables, theme send · run · assert bridge state pushed in actions relayed out Your App (sandboxed) Custom button HTML + JS · load React, charts, anything isolated document · no access to Bruno's storage or renderer Request-level: drive one request Collection-level: run many

An App is an isolated UI. Bruno pushes live state in and relays your actions back out.

Isolated by design, powerful in practice

Each App runs in its own sandboxed container with its own document. It can't read Bruno's storage or cookies, can't reach into the host, and has no privileged system access. Everything flows through a small, well-defined bridge that Bruno injects: your current theme, the resolved variables for the active environment, the latest response, and your test and assertion results all get pushed in and kept fresh, so there's no polling and no manual refresh.

The upside of that isolation is freedom. Because the App isn't bound by Bruno's own content-security rules, you can pull in libraries straight from a CDN and build a genuinely rich interface. Want to render your dashboard with React and a charting library? Drop in the script tags and go. It behaves like the web you already know, sitting one bridge away from your live API data.

A quick heads-up for early adopters. Apps ship as a first version in v4, and the exact shape of the bridge Bruno exposes to your code may still evolve as the feature matures. Build away, just expect the surface to firm up over the next few releases.

Secret Management, Rebuilt From the Ground Up

Older Bruno kept secret configuration in its own file, secrets.json, sitting off to the side of your environments. It worked, but it meant secrets played by different rules than everything else: a separate mental model for something that's really just another kind of environment value.

v4 collapses that split. Secret mappings now live alongside your environments, so configuring a secret behaves exactly like configuring any other environment variable. One system, one set of rules.

BEFORE · v3 environments env config secrets.json separate rules Two systems, two mental models. AFTER · v4 environments + secrets env values secret mappings One unified system, one set of rules.

Secrets stop being a special case and become part of the environment system.

What you get out of the move:

  • A unified environments + secrets experience, so you configure both in the same place.
  • Better sharing and precedence rules, so it's clear which value wins where.
  • A cleaner UX for wiring up external secret providers.

The CLI grew up alongside it

The Bruno CLI has been updated to speak the new Secret Manager architecture, and it now has native support for the secret stores real teams actually run: AWS Secrets Manager, Azure Key Vault, and HashiCorp Vault. On top of that, this release brings JUnit reporting fixes (your CI dashboards will thank you) and better support for YAML-based gRPC collections.

Collection Docs, Completely Reimagined

This is the largest update Collection Docs has ever received. Documentation is no longer a single scroll of text. It's a modern documentation website, with shareable pages, global search, richer request information, and navigation that actually scales to a big collection.

API Docs Search everything... D Create order POST Try it Playground 200 OK

Sidebar, global search, light/dark, and an interactive Playground: docs that feel like docs.

The highlights reel:

  • Shareable page URLs, so you can link a teammate straight to the endpoint, not "scroll to the third heading."
  • A brand-new design system with light & dark themes.
  • A redesigned sidebar for real navigation.
  • Variable types and resolved-value previews, so you see what a value actually becomes.
  • Execution context surfaced for requests, folders, and collections.

And the interactive Playground inside docs is now much closer to the full Bruno experience. With a redesigned application shell and far broader request support, readers can execute requests directly from the documentation. Your docs stopped being a museum exhibit behind glass and became a place people can press the buttons.

Typed Variables and Better Scripting

Here's a papercut every Bruno scripter knows. In previous versions, every variable was a string. Store the number 3, get back "3". Store an object, and you'd better JSON.stringify it on the way in and JSON.parse it on the way out, every single time. It's like a filing cabinet that only accepts photocopies: whatever you put in, you get a flat picture of it back, never the real thing.

v4 gives variables real, native data types across collections, environments, folders, and requests. Strings, numbers, booleans, and objects all keep their type all the way through your workflow.

v3, everything is a string:

// store a retry count and a config object
bru.setVar("retryCount", "3");              // stringly typed
const count = parseInt(bru.getVar("retryCount"), 10); // manual parse

bru.setVar("config", JSON.stringify({ region: "us-east-1" }));
const cfg = JSON.parse(bru.getVar("config"));   // deserialize, again

v4, variables keep their type:

// store the real values, no ceremony
bru.setVar("retryCount", 3);                   // number
const count = bru.getVar("retryCount");         // -> 3  (a number)

bru.setVar("config", { region: "us-east-1" }); // object
const cfg = bru.getVar("config");             // -> { region: "us-east-1" }

if (count > 0 && cfg.region === "us-east-1") { /* just works */ }

Whether you're stashing configuration objects, feature flags, numeric thresholds, or JSON payloads, variables now behave like the native JavaScript values you already think in. Less boilerplate, fewer parseInt landmines.

To round it out, the scripting APIs got some love too. Variable mutations now persist by default, and there's a complete set of APIs for managing collection variables, which makes reusable, multi-step workflows a lot easier to build. The net effect: a scripting model that's more expressive, more predictable, and genuinely ready for sophisticated testing and automation.

More Headliners

Faster startup for large collections (Beta)

Big collections used to be re-parsed from scratch every time Bruno launched, like re-reading an entire book from page one just to remember where you left off. Now parsed collection data is cached across sessions, so startup for large workspaces is dramatically quicker. It ships as Beta while we keep validating it; flip it on under Preferences → Cache (the File Cache toggle).

FIRST LAUNCH parse collection write cache EVERY LAUNCH AFTER read cache ready, fast no re-parse

Parse once, reuse forever, until the collection changes.

More authentication options (Beta)

Bruno now supports Akamai EdgeGrid authentication natively, which is one less custom-signing script to maintain if you're working against Akamai-fronted APIs.

Better WebSocket workflows

WebSocket requests can now hold multiple saved messages within a single connection. Build and manage a little library of payloads and fire them individually, instead of retyping the same message every time you want to poke the socket. It's the difference between a set of labeled buttons and a blank text box.

Changelog and notifications, redesigned

Release notes no longer ambush you in a modal. Every update now gets its own dedicated Changelog page that opens as a tab when you upgrade: readable, linkable, and out of your way. Notifications have been rethought too, and now focus on product news, announcements, and feature discovery rather than dumping raw release notes on you.

OpenCollection YAML Is the Future of Bruno

With v4 we're officially beginning the transition away from the legacy .bru format in favor of OpenCollection YAML. Since we introduced YAML in Bruno v3, the community adopted it fast for its readability, portability, and ecosystem compatibility. It's clearly the natural direction, so we're leaning in.

Don't panic, nothing breaks today. The .bru format is now deprecated, but existing .bru collections keep working, and we expect to support the format for at least the next twelve months. Throughout that window we'll maintain feature parity between .bru and YAML, so every new feature and improvement works no matter which format you're on.

v4 today .bru deprecated, still fully supported ~12 months feature parity maintained, migrate at your own pace YAML-first OpenCollection YAML as the default

A guided, unhurried migration where you set the pace.

To make the move painless, there's a new guided in-app migration experience. The goal is simple: give the community and our customers ample runway to migrate on their own schedule, with a tool that does the mechanical work for you.

Dozens of Quality Improvements

Beneath the headliners, v4 sweeps up a long list of refinements across Desktop, CLI, and API Docs:

  • Better path parameter handling.
  • Improved migration fidelity when importing Postman collections.
  • UI polish throughout the application.
  • Documentation rendering fixes.
  • Tons of bug fixes across Desktop, CLI, and API Docs.

Conclusion

v4.0.0 is a big step forward, but the through-line is the same one that's always defined Bruno: a fast, capable, developer-first API client that treats your collections as code and keeps your data on your machine. Native AI, rebuilt secrets, typed variables, and reimagined docs just make that foundation a lot more powerful to build on.

Grab the latest build, skim the new in-app Changelog tab, and go break something in a good way. We'd love to hear what you build.

Related posts