Banger
Blog Download

Inside the Banger Local Runtime

5 min read ยท Published February 6, 2026

The Banger desktop app is not just a window around remote APIs.

It has to sync mailboxes, maintain local state, process encrypted action streams, coordinate Gmail backfill, stage attachments, serve CLI requests, and expose a controlled bridge for MCP-based workflows. If all of that lived directly inside the UI process, the architecture would be harder to reason about and easier to break.

So Banger has a local runtime.

The runtime is the local service surface shared by the desktop app, CLI, and MCP extension. It is the piece that lets Banger behave like a real desktop system instead of a collection of disconnected tools.

Why a local runtime exists

The UI should be responsible for interaction. It should render state, accept user input, and keep the product responsive.

It should not be the only owner of long-running operational work.

Banger has background responsibilities that outlive a single screen:

  • mailbox sync
  • user-state refresh
  • Gmail backfill
  • pending action push
  • encrypted ingest processing
  • local database access
  • attachment staging
  • runtime health checks
  • MCP routing
  • CLI operations

A local runtime gives those responsibilities a stable home.

That also lets other local clients reuse the same system. The desktop UI, command-line tools, and MCP extension can all talk to one runtime surface instead of each one opening its own partial connection to the world.

The runtime is a boundary

The most important part of the runtime is not that it is local. It is that it is a boundary.

Boundaries make product systems easier to reason about. The UI can ask for mailbox state without knowing how every sync pass works. The CLI can request an operation without reimplementing session bootstrap. The MCP extension can use a constrained local bridge without receiving direct access to all internals.

That boundary gives us a place to handle:

  • compatibility versions
  • local transport details
  • startup and attach behavior
  • bearer tokens
  • service ownership
  • logging
  • failure recovery
  • runtime health

When a local app has multiple consumers, a boundary like this becomes more valuable over time.

Desktop, CLI, and MCP share one surface

Banger has three important local clients:

  • the desktop app
  • the desktop CLI
  • the MCP extension used by local AI tooling

They are not identical, but they need access to overlapping capabilities.

The desktop app needs live state and operational commands. The CLI needs administrative and debugging workflows. The MCP extension needs a safe way to inspect or propose work through Banger without bypassing user controls.

The local runtime lets those clients converge on the same state and the same permissioned operations.

That matters because email state is easy to corrupt if every tool invents its own path. A single local runtime surface helps keep the app, CLI, and MCP behavior aligned.

Discovery and environment-specific paths

Local services need to be discoverable without being globally exposed.

Banger uses platform-aware paths and environment-specific service metadata so clients can find the right local runtime for the current environment. The runtime writes connection information such as port and token metadata into known local locations. Clients use those files to attach to the correct runtime.

The environment distinction matters. Development, staging, production, and showcase modes should not accidentally collide. Local state needs namespacing just like backend state does.

The runtime also uses platform-specific app data locations. Windows, macOS, and Linux each have different conventions, and respecting those conventions makes the app easier to install, debug, and clean up.

Local bearer tokens keep the boundary explicit

The local runtime is not a public network service, but it still needs an access boundary.

Banger uses local bearer tokens for runtime access. That lets the runtime distinguish a legitimate local client from a random process that found a port. The MCP extension also avoids persisting bearer secrets unnecessarily; it discovers the runtime, keeps sensitive connection details in memory where possible, and rotates through reconnect flows.

This is not a replacement for workspace-level permissions. It is the local layer of defense. Workspace permissions still decide what a user or agent can do. The runtime token decides whether a local process can talk to the runtime at all.

Both layers matter.

Startup is part of the product

Local runtime startup sounds like implementation detail until it fails.

The desktop app needs to know whether a compatible runtime is already running, whether it should attach, whether it should start a new runtime, and whether the current runtime has usable session and user-state data.

Banger treats startup as a first-class flow:

  • load the local environment
  • resolve service paths
  • read startup metadata
  • attach to an existing runtime when possible
  • start or restart when needed
  • apply session and user-state bootstrap
  • begin event relay and user-state synchronization

That gives the UI a faster path to useful state and keeps recovery behavior predictable.

Compatibility versioning prevents confusing failures

The local app and runtime evolve together, but they can still get out of sync during development, upgrades, or partial restarts.

That is why the runtime surface has a compatibility version. If the app attaches to a runtime that speaks the wrong contract, the right behavior is not to keep going and fail later in a confusing way. The app should detect the mismatch and recover.

This is one of those details that only becomes obvious after you have lived with local services. Versioning the boundary is cheaper than debugging impossible states later.

What the runtime owns

The runtime owns the work that should be stable, shared, and operational:

  • mailbox sync runtime
  • pending action processing
  • local mailbox database access
  • Gmail ingest and backfill coordination
  • user-state synchronization
  • attachment staging
  • local MCP routing
  • service health and logs
  • transport endpoints for local clients

The UI owns presentation and interaction. The runtime owns the work that makes the product state exist.

That split keeps the UI responsive and gives the CLI and MCP extension a real foundation.

MCP needs the runtime boundary

The MCP extension is a good example of why the runtime exists.

AI tooling should not get direct, unconstrained access to every local file or internal database. It should talk to a narrow local surface that understands Banger concepts: mailboxes, threads, approvals, and agent permissions.

The runtime gives MCP that bridge.

It also keeps the security model consistent. Agent actions can become proposals. Sensitive operations can require approval. Credentials can remain scoped and revocable. Local tooling can integrate deeply without turning into a side door.

A local runtime makes the app feel native

The user does not care about runtime boundaries directly. They care that the app opens quickly, syncs reliably, keeps state consistent, and does not freeze when work happens in the background.

The runtime is one of the reasons we can aim for that.

It lets Banger behave less like a tab and more like a native email system: stateful, local, responsive, and connected to the operating system around it.

That is the architecture we want for work email. The inbox is operational infrastructure, so the app needs local infrastructure too.

Written by