Use cases

Start from what you want to do. Each row links to the guide page that builds it. The list is generated from the guides' "Use this when" sections.

I want to… Guide
Start a plugin by hand. You want to understand each required file before you use a template. Getting started: a plugin from an empty directory
Try a local plugin. You want bb to build, install, watch, and reload a source directory. Getting started: a plugin from an empty directory
Add a server service. You want other plugins to use one typed, versioned capability. Getting started: a plugin from an empty directory
Add a first app surface. You want to add UI through a contract that its owner declared. Getting started: a plugin from an empty directory
Share behavior between plugins. Define one typed contract, provide it in one plugin, and use it from another plugin. Services and service edges
Follow the user's provider choice. A replaceable service resolves through the global winner picker. Services and service edges
Control startup after a dependency change. Choose a required, optional, or watched edge for each service dependency. Services and service edges
Use a bb domain service. Consume bb.threads, bb.workspace, bb.files, bb.vcs, or bb.providers through typed contracts. Services and service edges
Give an agent a typed action. Claim one bb.agents.tool key and add its behavior with api.tools.add(). Agent tools, tool-call policy, and AI services
Replace a tool implementation. Claim the same replaceable key and let the user select its winner. Agent tools, tool-call policy, and AI services
Apply policy to every tool call. Add a member to the ordered bb.agents.toolCalls chain. Agent tools, tool-call policy, and AI services
Offer helper AI operations. Claim one bb.agents.ai key for structured inference, voice transcription, or both. Agent tools, tool-call policy, and AI services
Add an action to menus, keybindings, and the palette. Register one app command, and all command sources use it. Commands, keybindings, and interception
Give an action a default shortcut. Add keybindings to the command record and let user overrides stay with its ID. Commands, keybindings, and interception
Stop or change a command call. Add a member to the shared command interception chain. Commands, keybindings, and interception
Add a top-level bb verb. Claim one non-core key through bb.commands.cli. Commands, keybindings, and interception
Replace the command palette. Claim its surface and keep the headless command service. Commands, keybindings, and interception
Keep a small private value. Use a key-value store for a cursor, a count, or cached JSON. Data and settings
Own tables and migrations. Use a private SQLite database for records and queries. Data and settings
Use an API token. Read a declared secret through bb.secrets, and never store or log its value. Data and settings
Add user settings. Declare a schema and let bb.settings make a form. Data and settings
Add a custom settings page. Claim the bb.settings.pages list surface. Data and settings
Update a surface after a thread change. Subscribe through bb.threads, then load the new record. Live updates
Keep a plugin active without a service provider. Use a watched edge and show an unavailable state. Live updates
Send short progress events to app sessions. Declare an event and publish it through bb.realtime. Live updates
React to a durable thread lifecycle event. Use threads.events.subscribe() for delivery and events.list() for history. Live updates
Handle a service winner change without a restart. Replace the old subscription when the watched provider changes. Live updates
Replace one UI region. Claim a single surface such as bb.layout.sidebar. Surfaces and kinds
Add one item beside other items. Claim a list surface such as bb.thread-ui.sidePanels. Surfaces and kinds
Handle one data type. Claim one key of a keyed surface such as bb.thread-ui.timeline.item. Surfaces and kinds
Wrap one operation. Claim a chain surface such as bb.thread-ui.composer.send. Surfaces and kinds
Let the user select an implementation. Claim a replaceable surface and let the global picker control the winner. Surfaces and kinds
Add an app page. Claim bb.layout.panels and give the panel navigation data. Pages, panels, and commands
Open content in a shell dock. Let the panel controller select the right, bottom, or sidebar dock. Pages, panels, and commands
Add a command to the palette. Claim one key in bb.commands.command and call api.commands.add(). Pages, panels, and commands
Add a small global action. Add an item to bb.layout.statusbar. Pages, panels, and commands
Show modal content. Add a declaration to bb.layout.modals and let the shell control focus. Pages, panels, and commands
Replace a large shell region. Claim bb.layout.main or bb.layout.sidebar and use the typed Original component. Pages, panels, and commands
Render one timeline item type. Claim the keyed bb.thread-ui.timeline.item surface. Thread timeline, composer, and side panels
Replace or wrap the composer. Claim the single bb.thread-ui.composer surface. Thread timeline, composer, and side panels
Add a composer control or card. Claim the list bb.thread-ui.composer.actions surface. Thread timeline, composer, and side panels
Check or change a send. Claim the chain bb.thread-ui.composer.send surface. Thread timeline, composer, and side panels
Add a panel beside a thread. Claim the view-declared bb.thread-ui.sidePanels surface. Thread timeline, composer, and side panels
Keep a draft through a UI change. Store it through the bb.threads service. Thread timeline, composer, and side panels
Run a machine tool. Put Git, a compiler, or another local process in a host role. The host tier
Use the machine that owns a repository. Select a host target before you call the role. The host tier
Watch machine files. Emit a typed signal when a repository changes. The host tier
Keep a public service independent of placement. Let consumers use one server service for local and remote work. The host tier
Set process limits. Declare memory, request, response, start, stop, and idle limits for each role. The host tier
Create an isolated worktree. Give each environment its own branch and root. Environment providers
Create a personal workspace. Put a managed directory below the provider data directory. Environment providers
Use an existing directory. Return an unmanaged workspace after strict path checks. Environment providers
Run on a remote host. Let bb.workspace select the host and route each host call. Environment providers
Replace one provider implementation. Claim the same provider key and join the global winner picker. Environment providers
Add a coding agent to bb. Claim one bb.providers.provider key for the agent. Provider plugins
Connect a CLI or SDK agent. Translate its native protocol through the bb.providers.bridge host role. Provider plugins
Support models, health, and usage. Use the provider contract and the shared host services. Provider plugins
Report a rate limit to the UI. Send normalized limit data and a provider error that settles the turn. Provider plugins
Request approval before a command. Send an interaction/request and wait for the typed result. Provider plugins
Replace an installed provider implementation. Claim the same provider key and use the global winner picker. Provider plugins
Keep provider processes reliable. Use the shared supervisor instead of local process control. Provider plugins
Check a contract before a build. assertContract finds invalid declarations and schema problems. Test plugin factories and contracts
Run a server factory with controlled ports. createServerHarness uses the real loader graph and commit rules. Test plugin factories and contracts
Replace one service in a test. A named service double gives typed calls without a broad runtime fake. Test plugin factories and contracts
Mount one declared surface. renderSurface supplies owner props, service doubles, routing, settings, and winner changes. Test plugin factories and contracts
Check cleanup and reload behavior. The harnesses stop generations and make old service handles stale. Test plugin factories and contracts
Call a host role without a daemon. createHostHarness checks schemas, signals, cancellation, and retained leases. Test plugin factories and contracts
Change a first-party screen. Fork the plugin that wins its surface contract. Composition, forks, and distribution
Replace a backend service. Keep the parent contract ID so current consumers follow the winner. Composition, forks, and distribution
Test a change safely. Install a fork and flip one winner without removal of the parent. Composition, forks, and distribution
Publish a plugin. Distribute a verified artifact through npm, Git, or a marketplace. Composition, forks, and distribution
Recover from a bad override. Start safe mode and restore a default winner. Composition, forks, and distribution
Move a 1.x plugin. Replace its package manifest, broad SDK access, and app slots. Migrating from the 1.x API
Plan a gradual move. Keep 1.x plugins active while other plugins use 2.0. Migrating from the 1.x API
Find a new API home. Use the coverage matrix for each old member. Migrating from the 1.x API
Choose a first plugin. Use the rebuild stories to compare real plugin shapes. Migrating from the 1.x API
Review a port. Check the manifest, contract edges, surface claims, and tier factories. Migrating from the 1.x API
Publish a typed service or surface. Put its public shape in src/contracts.ts and declare it in bb.plugin.jsonc. Typed contracts and contract.json
Use one contract from two package copies. The kernel matches the contract ID and version, not a JavaScript object. Typed contracts and contract.json
Review the exact public shape. Read the generated dist/contract.json file. Typed contracts and contract.json
Change a stable contract. Use semantic version rules and keep a deprecation period. Typed contracts and contract.json
Try an unsettled contract. Mark it as experimental and expect source changes after any release. Typed contracts and contract.json
Find an install failure. Compare claims and service edges with the declarations in contract.json. Typed contracts and contract.json
Add content to another plugin's UI. Claim its typed list surface. Cross-plugin claims
Keep domain data separate from presentation. Put data in a headless plugin and claims in a UI plugin. Cross-plugin claims
Follow the active surface graph. Let a claim become inactive when the declaring winner omits its child surface. Cross-plugin claims
Compose a replaceable surface. Render the current global winner instead of importing one implementation. Cross-plugin claims
Handle an owner change. Keep independent claims active when only one graph path changes. Cross-plugin claims
Share a concrete React component. Export a stable component that another plugin can place in its own UI. Module exports and the import map
Share a pure app helper. Export code that needs React or another app-only module. Module exports and the import map
Publish exact code. Use an export when a winner change must not select different code. Module exports and the import map
Keep one React instance. Let the host import map supply React to all app modules. Module exports and the import map
Understand app reloads. Treat each changed ESM bundle as a new generation. Module exports and the import map

By guide

Getting started: a plugin from an empty directory

  • Start a plugin by hand. You want to understand each required file before you use a template.
  • Try a local plugin. You want bb to build, install, watch, and reload a source directory.
  • Add a server service. You want other plugins to use one typed, versioned capability.
  • Add a first app surface. You want to add UI through a contract that its owner declared.

Services and service edges

  • Share behavior between plugins. Define one typed contract, provide it in one plugin, and use it from another plugin.
  • Follow the user's provider choice. A replaceable service resolves through the global winner picker.
  • Control startup after a dependency change. Choose a required, optional, or watched edge for each service dependency.
  • Use a bb domain service. Consume bb.threads, bb.workspace, bb.files, bb.vcs, or bb.providers through typed contracts.

Agent tools, tool-call policy, and AI services

  • Give an agent a typed action. Claim one bb.agents.tool key and add its behavior with api.tools.add().
  • Replace a tool implementation. Claim the same replaceable key and let the user select its winner.
  • Apply policy to every tool call. Add a member to the ordered bb.agents.toolCalls chain.
  • Offer helper AI operations. Claim one bb.agents.ai key for structured inference, voice transcription, or both.

Commands, keybindings, and interception

  • Add an action to menus, keybindings, and the palette. Register one app command, and all command sources use it.
  • Give an action a default shortcut. Add keybindings to the command record and let user overrides stay with its ID.
  • Stop or change a command call. Add a member to the shared command interception chain.
  • Add a top-level bb verb. Claim one non-core key through bb.commands.cli.
  • Replace the command palette. Claim its surface and keep the headless command service.

Data and settings

  • Keep a small private value. Use a key-value store for a cursor, a count, or cached JSON.
  • Own tables and migrations. Use a private SQLite database for records and queries.
  • Use an API token. Read a declared secret through bb.secrets, and never store or log its value.
  • Add user settings. Declare a schema and let bb.settings make a form.
  • Add a custom settings page. Claim the bb.settings.pages list surface.

Live updates

  • Update a surface after a thread change. Subscribe through bb.threads, then load the new record.
  • Keep a plugin active without a service provider. Use a watched edge and show an unavailable state.
  • Send short progress events to app sessions. Declare an event and publish it through bb.realtime.
  • React to a durable thread lifecycle event. Use threads.events.subscribe() for delivery and events.list() for history.
  • Handle a service winner change without a restart. Replace the old subscription when the watched provider changes.

Surfaces and kinds

  • Replace one UI region. Claim a single surface such as bb.layout.sidebar.
  • Add one item beside other items. Claim a list surface such as bb.thread-ui.sidePanels.
  • Handle one data type. Claim one key of a keyed surface such as bb.thread-ui.timeline.item.
  • Wrap one operation. Claim a chain surface such as bb.thread-ui.composer.send.
  • Let the user select an implementation. Claim a replaceable surface and let the global picker control the winner.

Pages, panels, and commands

  • Add an app page. Claim bb.layout.panels and give the panel navigation data.
  • Open content in a shell dock. Let the panel controller select the right, bottom, or sidebar dock.
  • Add a command to the palette. Claim one key in bb.commands.command and call api.commands.add().
  • Add a small global action. Add an item to bb.layout.statusbar.
  • Show modal content. Add a declaration to bb.layout.modals and let the shell control focus.
  • Replace a large shell region. Claim bb.layout.main or bb.layout.sidebar and use the typed Original component.

Thread timeline, composer, and side panels

  • Render one timeline item type. Claim the keyed bb.thread-ui.timeline.item surface.
  • Replace or wrap the composer. Claim the single bb.thread-ui.composer surface.
  • Add a composer control or card. Claim the list bb.thread-ui.composer.actions surface.
  • Check or change a send. Claim the chain bb.thread-ui.composer.send surface.
  • Add a panel beside a thread. Claim the view-declared bb.thread-ui.sidePanels surface.
  • Keep a draft through a UI change. Store it through the bb.threads service.

The host tier

  • Run a machine tool. Put Git, a compiler, or another local process in a host role.
  • Use the machine that owns a repository. Select a host target before you call the role.
  • Watch machine files. Emit a typed signal when a repository changes.
  • Keep a public service independent of placement. Let consumers use one server service for local and remote work.
  • Set process limits. Declare memory, request, response, start, stop, and idle limits for each role.

Environment providers

  • Create an isolated worktree. Give each environment its own branch and root.
  • Create a personal workspace. Put a managed directory below the provider data directory.
  • Use an existing directory. Return an unmanaged workspace after strict path checks.
  • Run on a remote host. Let bb.workspace select the host and route each host call.
  • Replace one provider implementation. Claim the same provider key and join the global winner picker.

Provider plugins

  • Add a coding agent to bb. Claim one bb.providers.provider key for the agent.
  • Connect a CLI or SDK agent. Translate its native protocol through the bb.providers.bridge host role.
  • Support models, health, and usage. Use the provider contract and the shared host services.
  • Report a rate limit to the UI. Send normalized limit data and a provider error that settles the turn.
  • Request approval before a command. Send an interaction/request and wait for the typed result.
  • Replace an installed provider implementation. Claim the same provider key and use the global winner picker.
  • Keep provider processes reliable. Use the shared supervisor instead of local process control.

Test plugin factories and contracts

  • Check a contract before a build. assertContract finds invalid declarations and schema problems.
  • Run a server factory with controlled ports. createServerHarness uses the real loader graph and commit rules.
  • Replace one service in a test. A named service double gives typed calls without a broad runtime fake.
  • Mount one declared surface. renderSurface supplies owner props, service doubles, routing, settings, and winner changes.
  • Check cleanup and reload behavior. The harnesses stop generations and make old service handles stale.
  • Call a host role without a daemon. createHostHarness checks schemas, signals, cancellation, and retained leases.

Composition, forks, and distribution

  • Change a first-party screen. Fork the plugin that wins its surface contract.
  • Replace a backend service. Keep the parent contract ID so current consumers follow the winner.
  • Test a change safely. Install a fork and flip one winner without removal of the parent.
  • Publish a plugin. Distribute a verified artifact through npm, Git, or a marketplace.
  • Recover from a bad override. Start safe mode and restore a default winner.

Migrating from the 1.x API

  • Move a 1.x plugin. Replace its package manifest, broad SDK access, and app slots.
  • Plan a gradual move. Keep 1.x plugins active while other plugins use 2.0.
  • Find a new API home. Use the coverage matrix for each old member.
  • Choose a first plugin. Use the rebuild stories to compare real plugin shapes.
  • Review a port. Check the manifest, contract edges, surface claims, and tier factories.

Typed contracts and contract.json

  • Publish a typed service or surface. Put its public shape in src/contracts.ts and declare it in bb.plugin.jsonc.
  • Use one contract from two package copies. The kernel matches the contract ID and version, not a JavaScript object.
  • Review the exact public shape. Read the generated dist/contract.json file.
  • Change a stable contract. Use semantic version rules and keep a deprecation period.
  • Try an unsettled contract. Mark it as experimental and expect source changes after any release.
  • Find an install failure. Compare claims and service edges with the declarations in contract.json.

Cross-plugin claims

  • Add content to another plugin's UI. Claim its typed list surface.
  • Keep domain data separate from presentation. Put data in a headless plugin and claims in a UI plugin.
  • Follow the active surface graph. Let a claim become inactive when the declaring winner omits its child surface.
  • Compose a replaceable surface. Render the current global winner instead of importing one implementation.
  • Handle an owner change. Keep independent claims active when only one graph path changes.

Module exports and the import map

  • Share a concrete React component. Export a stable component that another plugin can place in its own UI.
  • Share a pure app helper. Export code that needs React or another app-only module.
  • Publish exact code. Use an export when a winner change must not select different code.
  • Keep one React instance. Let the host import map supply React to all app modules.
  • Understand app reloads. Treat each changed ESM bundle as a new generation.