Features

Simplicity is tied in.
All in one workbench — no tool switch required.

Each section below links to the technical documentation for the full details.

Discover and invoke

Plug a protocol in, get a live service tree. Compose requests with typed forms or raw JSON. Every call pattern — unary, streaming, duplex, REST verbs, GraphQL, MQTT publishes — ends up in the same UI.

Auto-discovery with hot reload

Plug in a protocol, get a service tree — no hand-maintained proto / OpenAPI / hub-registration code.

Each protocol plugin implements a single DiscoverAsync method: gRPC hits Server Reflection, REST reads the OpenAPI spec, SignalR enumerates mapped hubs via EndpointDataSource, GraphQL introspects __schema, MQTT subscribes to $SYS/#, and so on. Bowire merges the results into a single sidebar across every installed plugin.

The discovery pass repeats every few seconds against every configured URL. A new method registered on a running server shows up in the sidebar within the next tick — no page refresh, no re-upload, no “disconnect and retry” dance.

Read the technical docs →
Discovered service method with typed parameters, exposed in the sidebar without hand-maintained schema Discovered service method with typed parameters, exposed in the sidebar without hand-maintained schema

Every call pattern in one UI

Unary, server-stream, client-stream, duplex — plus REST verbs, GraphQL subscriptions, SignalR hubs, raw WebSocket frames, MQTT publishes. One UI, same muscle memory across all of them.

Streaming calls render into a Wireshark-style append-only list with per-frame detail. Duplex / client-stream open a persistent channel with a “send next message” composer on one side and incoming frames on the other. REST maps verbs onto the same invoke pane; GraphQL has a selection-set picker plus subscription follow-up via graphql-transport-ws.

Read the technical docs →
Streaming response — Wireshark-style frame list with detail pane Streaming response — Wireshark-style frame list with detail pane

Form or raw JSON

Schema-driven form inputs for the common case, a full JSON editor when you need to tweak something unusual. Toggle with f.

The form view auto-generates controls from the discovered message shape: typed number inputs for int32, date pickers for google.protobuf.Timestamp, dropdowns for enums, nested cards for messages, repeated-field tables. Client-side validation flags missing required fields and type mismatches before a single byte hits the wire.

The JSON view is a full editor with syntax highlighting, bracket matching, and inline validation errors. State is preserved per method, so switching away and back never loses work.

Read the technical docs →
json press f for form view
{
  // typed form mirrors this shape
  "city": "Berlin",
  "days": 7,
  "units": "celsius",
  "include_humidity": true,
  "filter": {
    "after": "2026-04-22T00:00Z"
  }
}

Build flows and chain responses

Compose multi-step API sequences visually, forward any response value into the next call, and drive everything from the keyboard.

Visual flow editor

Chain API calls into branching pipelines — visually, not in a YAML file you can’t read three months later.

Drag requests onto a canvas, forward response values into the next call with ${response.path.to.value}, branch on status or body content, loop over arrays, sleep, assert. Every node has its own response viewer so you can step through a failing flow like a debugger.

All of it is local to your machine. No seat-counted cloud subscription, no hand-maintained Postman Collections — flows are JSON files you can commit, review, and replay.

Read the technical docs →
Visual flow editor — pipeline of API calls with branching conditions and loops Visual flow editor — pipeline of API calls with branching conditions and loops

Click any JSON value to chain

The response from one call is the input for the next. Bowire skips the copy-paste round-trip.

Hover any value or key in a rendered JSON response, click it, and Bowire places the chaining expression on your clipboard — ready to paste into the next request’s body, URL path, or headers. Works on every supported protocol, not just REST: gRPC response fields, GraphQL query results, SignalR hub return values, MQTT payloads, SSE events all use the same ${response.path.to.value} grammar.

Read the technical docs →
Click any JSON value in a response to copy the chaining variable expression Click any JSON value in a response to copy the chaining variable expression

Command palette & keyboard flow

Press / anywhere to search methods, switch environments, filter protocols — never leave the keyboard.

Vim-style j / k to hop between methods, f to flip form / JSON, r to repeat the last request, t to cycle themes, Ctrl+Enter to execute. Recently-used methods surface when the palette query is empty. Power users who live in the shell will feel at home.

Read the technical docs →
Command palette open with method suggestions, environment jumps, and protocol filters Command palette open with method suggestions, environment jumps, and protocol filters

Keyboard-first everything

Every action has a shortcut. Power users never touch the mouse; newcomers get a cheat sheet at ?.

Vim-style j / k to hop between methods in the sidebar, f to flip form ↔ JSON, r to repeat the last request, t to cycle light / dark / auto themes, Ctrl+Enter (or +Enter) to execute, Esc to close any modal, / to open the command palette, ? to see the full list without leaving the page.

Shortcuts are configurable per-user in Settings → Shortcuts, with conflict detection so the same chord never binds two actions silently.

Read the technical docs →
shortcuts press ? for the full list
/             open command palette
j  / k        hop between methods
f             toggle form ↔ JSON
r             repeat last request
⌘ Enter       send request
t             cycle theme
Esc           close modal
?             full cheat sheet

Capture, replay, and stress

Every call captured in a filterable timeline, replayable against any environment, and ready for a quick load check — all in the same workbench.

Record & replay

Click record, run a sequence of calls, click stop. Now you have a reproducible test case, a debug artifact, and a future mock server in one file.

Recordings capture request, response, status, timing, and metadata for every call across every protocol — gRPC streams, SignalR hub invocations, WebSocket frames, MQTT publishes, REST hits, all in one timeline. Replay against another environment to check drift, convert into test assertions for CI, export as HAR for teammates, or (coming soon) serve the recording back as a live mock.

Read the technical docs →
Recording manager — timeline of captured calls with per-step pass/fail markers Recording manager — timeline of captured calls with per-step pass/fail markers

Wireshark-style streaming view

An append-only message list on the left, a detail pane on the right — built for long-running duplex sessions, not a chat transcript.

Every incoming frame lands in a filterable table (substring, regex, or protocol-specific fields). Click one to see the full payload. Pin the latest to auto-follow, or pin a specific frame to keep the detail view stable while new messages scroll in. Works for gRPC server / client / duplex streams, SignalR real-time events, GraphQL subscriptions, WebSocket frames, SSE events, and MQTT subscribe streams — all with the same UI.

Read the technical docs →
Streaming response view — append-only message list on the left, detail pane on the right Streaming response view — append-only message list on the left, detail pane on the right

Performance testing, built in

Repeat any call N times, watch the latency histogram and timeline render in real time.

P50 / P90 / P99 / P99.9 percentiles, success rate, and throughput all in the same pane as the request. No separate load tool to install, no CI pipeline to wire up — just a quick “is this endpoint holding up?” check when you suspect a regression. Scales enough for smoke tests; for full-blown soak tests, export the call as k6 / vegeta and run it from a proper load runner.

Read the technical docs →
Performance graph — latency histogram with P50 / P90 / P99 percentiles Performance graph — latency histogram with P50 / P90 / P99 percentiles

Inline test assertions

Write Newman-style checks once, Bowire runs them after every successful response and shows a green / red badge inline.

Eleven comparison operators (eq, ne, gt, gte, lt, lte, contains, startsWith, endsWith, matches, type) target any value via response.path.to.value JSONPath. Assertions are stored per method, replay with every invocation, and can be exported into a recording so a flow becomes its own regression test.

For streaming responses, assertions run on the accumulated frames — “expect at least 3 frames of type TICK within 2 s” is one rule. No plugins, no pipeline, just a test that lives next to the request.

Read the technical docs →
assertions 4/4 passing
response.status   eq   200        
response.time     lt   500        
body.user.id      eq   "42"       
body.items[0]     type "object"   

Environments, schemas, and setup

Compare what’s actually running where, work from a schema when the server isn’t reachable, authenticate against any auth scheme, and script everything from the CLI when you don’t want the UI.

Environment diff

Compare two environments side-by-side — spot drift before it hits production.

Pick any two configured environments (Dev, Staging, Prod, or per-URL overrides) and get a colour-coded diff across every variable and header. Equal rows are folded away, changed rows highlighted, only-in-A / only-in-B clearly marked. Catches missing secrets, mistyped keys, and accidental overrides that would otherwise burn an afternoon of debugging.

Read the technical docs →
Environment diff view — two environments compared side by side with colour-coded rows Environment diff view — two environments compared side by side with colour-coded rows

Every auth scheme, built in

Every auth scheme worth supporting, built in. Set it once per environment, Bowire signs every request.

Bearer tokens, HTTP Basic, API Key (header or query), JWT issuance (HS256 / RS256 / ES256) with custom claims, OAuth 2.0 client_credentials, OAuth 2.0 authorization_code with PKCE for local CLI flow, a custom token endpoint with auto-refresh, and AWS Signature v4 for S3 / Lambda / API Gateway. Each scheme stores its values in the environment, substituted at request time — tokens never touch the page source.

Expired tokens refresh transparently. Metadata headers on gRPC, authorization headers on REST / GraphQL / SignalR / WebSocket / MQTT (Username-Password CONNECT) all share the same credential store.

Read the technical docs →
auth schemes env: staging
Bearer token         auto-refresh
HTTP Basic          
API key (header)    
JWT (HS / RS / ES)   custom claims
OAuth 2.0 client    
OAuth 2.0 + PKCE    
AWS Sig v4          

Work offline from a schema file

Drop in a .proto, OpenAPI spec, or GraphQL SDL — browse the API surface without a running server.

Great for reviewing a contract during a PR, sharing a service’s shape with a teammate who can’t reach staging, prototyping a client before the backend exists, or teaching someone what an API looks like without spinning up infrastructure. Supports .proto (buf-style imports included), OpenAPI 3 / Swagger 2, and GraphQL SDL — other formats via plugin.

Read the setup docs →
Schema upload — drop in a .proto, OpenAPI spec, or GraphQL SDL and browse the API offline Schema upload — drop in a .proto, OpenAPI spec, or GraphQL SDL and browse the API offline

Smart empty states

Every screen where Bowire could be blank has something useful instead — a welcome, a retry, a diff of what connected and what didn’t.

First-run without a --url gets two onboarding paths: connect to a live server, or drop in a schema file for offline browsing. When discovery fails, the page surfaces the actual error plus four common-cause troubleshoot bullets. With multiple URLs configured, a per-URL status table lets you retry the ones that failed without touching the ones that connected.

When everything works, the landing shows a service summary, recent-history quick-recall, keyboard shortcut tips, and a guided tour entry point for new team members.

Read the technical docs →
Connected & ready landing — service summary, recent history, keyboard tips Connected & ready landing — service summary, recent history, keyboard tips First-run welcome screen with two onboarding cards First-run welcome screen with two onboarding cards Multi-URL status table with retry buttons for failed servers Multi-URL status table with retry buttons for failed servers Discovery-failed state with error and troubleshooting bullets Discovery-failed state with error and troubleshooting bullets

No CORS proxy to set up

Bowire talks to any API — local, internal, cloud — without browser-CORS friction. The architecture is the proxy.

The UI only ever hits localhost:5080 (same-origin, no CORS involved). The actual gRPC, REST, GraphQL, WebSocket, SSE, MCP, and MQTT calls are made by the Bowire process server-to-server, not from the browser. Same-origin policy doesn’t apply to server-to-server traffic, so endpoints without permissive CORS headers still work — no proxy layer to configure, no dev-tunnel to spin up, no *-origin security hole to poke.

It’s the reason you can browse a staging gRPC cluster or an internal REST service from your laptop without the backend team adding Access-Control-Allow-Origin.

Read the architecture docs →
request flow same-origin on the browser side
browser  ──▶  localhost:5080   (same-origin, no CORS)
                   │
                   ▼
             bowire host      (server-to-server, no SOP)
                   │
                   ▼
      target API (gRPC | REST | WS | MQTT | …)

Install, update, inspect — protocol plugins as NuGet packages

Every protocol plugin is a NuGet package. bowire plugin install fetches it, update bumps it, inspect shows what's loaded. No dotnet restore detour, no .NET SDK required at install time — only the runtime.

Plugins install into ~/.bowire/plugins/ (override via --plugin-dir or appsettings.json), each in its own isolated AssemblyLoadContext so two plugins can ship different versions of the same third-party library without clashing. Shared contract assemblies (Kuestenlogik.Bowire.*, System.*, Microsoft.*) delegate to the host so IBowireProtocol stays type-identity-identical across the boundary.

Need a private feed? --source https://nuget.mycorp.internal/v3/index.json is repeatable; multiple sources are tried in order. bowire plugin inspect MyCompany.Protocol.X loads the plugin live and reports the load-context, the resolved version, every assembly it pulled in, and every IBowireProtocol implementation reflection finds — instant verification that a freshly-packed plugin is wired correctly.

Read the technical docs →
bash $ bowire plugin ...
$ bowire plugin install Acme.Bowire.Protocol.Amqp
  Installed Acme.Bowire.Protocol.Amqp 1.2.0 (4 file(s))

$ bowire plugin update                     # bump all
  Updating Acme.Bowire.Protocol.Amqp 1.2.0 -> 1.3.0...

$ bowire plugin inspect Acme.Bowire.Protocol.Amqp
  Load context
    name:        BowirePlugin:Acme.Bowire.Protocol.Amqp
    collectible: True
    assemblies:  4
      Acme.Bowire.Protocol.Amqp 1.3.0
      RabbitMQ.Client            7.0.0
      ...
  Bowire contract implementations
    IBowireProtocol  Acme.Bowire.Protocol.Amqp.AmqpProtocol

Per-plugin settings

Every protocol plugin contributes its own settings section — granular control without leaving the UI.

General settings (theme, keyboard shortcuts), data management (where recordings, history, and environments live on disk), and a dedicated panel per installed protocol plugin. Each plugin implements its own BowirePluginSetting schema, so the UI always reflects exactly what that plugin supports — no hidden configuration in environment variables or JSON files.

Read the technical docs →
Settings dialog — general, shortcuts, data management, and per-plugin configuration Settings dialog — general, shortcuts, data management, and per-plugin configuration

One binary, three modes

Run as a .NET global tool and get three flavours of the same workbench — CLI subcommands for scripts, an HTTP-served UI for interactive use, and embedded middleware for teams that want the UI inside their own app.

bowire list <url> enumerates services, bowire describe <service.method> prints the full schema, bowire call <service.method> --body '{...}' invokes it — same output shape as the UI uses, so the CLI is scriptable against CI. Add --format json for machine-readable piping, or --recording to capture an output for later replay.

The standalone UI is just bowire --url https://api.example.com — the UI runs locally, hits the API with your auth, zero host-side changes. Plugin management (bowire plugin install / list / uninstall) shares the same state with the embedded mode.

Read the technical docs →
bash $ bowire
$ bowire list --url https://api.example.com
WeatherService   gRPC
UserApi          REST
EventsHub        SignalR

$ bowire call UserApi.GetUser -d '{"id":42}'
{ "id": 42, "name": "Ada" }

$ bowire --url https://api.example.com  # opens UI

Into the engine room

That was the topside tour. For SDK generation, protocol-plugin authoring, and everything else that lives below the waterline — read the docs or dive into the source.

The engine room runs on hands. Join the crew →