# BuoyDevTools

The `BuoyDevTools` widget is the entry point for Buoy on Flutter — the analog of React Native's `FloatingDevTools`. It wraps your app and renders a draggable floating button that opens a menu containing all your registered debugging tools.

<!-- ::floating-menu-live-demo-flutter -->

## Basic Usage

```dart
import 'package:buoy/buoy.dart';

MaterialApp(
  builder: (context, child) => BuoyDevTools(
    licenseKey: 'YOUR_LICENSE_KEY',
    child: child ?? const SizedBox.shrink(),
  ),
)
```

The [`buoy` umbrella](./installation) explicitly registers its bundled tools on mount. Don't have a key yet? Grab one at [buoy.gg/pricing](https://buoy.gg/pricing).

Mount it from `MaterialApp.builder` (or `MaterialApp.router`) so it sits above your Navigator and survives every route change.

## Props

| Prop | Type | Default | Notes |
|------|------|---------|-------|
| `child` | `Widget` | required | Your app (usually the `MaterialApp` builder child) |
| `licenseKey` | `String?` | `null` | Free or Pro account key; widget remains debug-only |
| `deviceName` | `String?` | auto | Label in Buoy Desktop / MCP. Default: `'Flutter App (ios · 2c1d)'` — the app, the platform, and the last 4 of the install id |
| `deviceId` | `String?` | auto | Leave unset: each install mints `flutter-app-ios-<8 hex>` once and keeps it. If you pin one it MUST be unique per device — two devices under one id look like one device to the broker |
| `socketUrl` | `String?` | auto | LAN broker URL for physical devices |
| `tools` | `List<BuoyTool>` | `[]` | Extra custom tools beyond self-registered ones |

## How Tools Register

React Native discovers tools by optional-require; Dart has no equivalent, so Flutter tools register explicitly — but with the umbrella package you never write the call yourself:

- **Umbrella** — `package:buoy` calls the registration functions for its bundled tool list when `BuoyDevTools` mounts. Adding a separate dependency does not extend that list. Install and it shows up:

  ```bash
  flutter pub add buoy
  ```

- **À la carte** — depend on the individual packages instead, call `registerBuoyNetwork()` (etc.) yourself before `runApp`, and mount `BuoyDevTools` from `buoy_core`.

A few tools still need one app-owned hook — the router for Routes, a `ProviderScope` observer for Riverpod, `BuoyImage` for Images, a search callback for Impersonate. The umbrella can't supply those, so each tool page notes its one line.

## Custom Tools

Need something specific to your app? Pass your own `BuoyTool`s via the `tools` prop (or `Buoy.registerTool` before mount):

```dart
import 'package:buoy/buoy.dart';
import 'package:flutter/material.dart';

MaterialApp(
  builder: (context, child) => BuoyDevTools(
    tools: [
      BuoyTool(
        id: 'flags',
        name: 'Flags',
        color: const Color(0xFF34D399),
        icon: (size, color) => Icon(Icons.flag, size: size, color: color),
        screenBuilder: (context) => const FeatureFlagDebugger(),
      ),
    ],
    child: child ?? const SizedBox.shrink(),
  ),
)
```

See [Custom Tools](./custom-tools) for the full schema and desktop-sync adapters.

## Draggable Button

The floating button can be dragged anywhere on screen. It remembers its position between sessions, so it stays where your team likes it, and it tucks out of the way on its own while the dial or a tool is open. Tools you minimize dock above it and come back with a tap.

## Beyond the in-app menu

`BuoyDevTools` is also the source of truth for Buoy's other surfaces. The same tools you see in the menu sync out over a local broker, so once this is set up you can — with no extra code — also:

- open the [Buoy Desktop](../desktop) dashboard and inspect the same live app on a full screen, or
- point an AI agent at your app with the [MCP server](../mcp).

Simulators and emulators connect automatically. Physical devices take one `socketUrl` pointing at your machine:

```dart
BuoyDevTools(
  socketUrl: 'http://192.168.1.20:42831',
  child: child ?? const SizedBox.shrink(),
)
```

The current sync target and connection state show up in the menu's Settings tab under desktop sync.

## Debug builds only

`BuoyDevTools` renders your child and nothing else outside a debug build — no button, no dial, no sync, no capture. There is no flag to change that on Flutter yet, This describes initialization managed by the widget; separately initialized code has its own behavior.

Two React Native options have no Flutter counterpart today:

- **`environment`** — the RN floating button prints an environment badge (`local`, `dev`, `staging`, `qa`, `prod`). The Flutter bubble doesn't.
- **`headless` and release-build sync** — RN can mount sync-only with no on-device UI, and can opt a release build into sync with `externalSync.enableInRelease` plus a Pro license. Flutter's debug-only gate means neither applies yet.

Both are on the Flutter roadmap.

## Next Steps

- [Custom Tools](./custom-tools) — Build team-specific debugging tools
- [Buoy Desktop](../desktop) — Inspect the same app on a full dashboard
- [AI / MCP Server](../mcp) — Drive your app from your AI editor
- [Quick Start](./quick-start) — Full setup walkthrough
