| name | tauri-bridge-setup |
| description | How to add the tauri-agent-tools Rust dev bridge to a Tauri application |
| version | 0.9.0 |
| tags | ["tauri","rust","bridge","setup","integration","multi-window","process-tree","capabilities","devtools","health"] |
Tauri Dev Bridge Setup
Add the dev bridge to a Tauri app so tauri-agent-tools can inspect DOM, evaluate JS, monitor IPC, take element screenshots, and interact with the UI. Bridge v0.7 also exposes process tree, capability audit, devtools URL, and health endpoints.
The bridge runs only in debug builds and is stripped from release builds automatically.
Re-copying for v0.8 (optional enrichment — not required)
Upgrading from v0.7: Bridge v0.8 adds cursor-mode /logs reads (non-draining, long-polling) that power logs --follow and let multiple log consumers coexist. It is a drop-in re-copy of dev_bridge.rs — no main.rs changes this time. Without it, logs --follow emits a one-time note and degrades to drain polling.
Re-copying for v0.7 (optional enrichment — not required)
Upgrading from v0.6: The bridge surface grew with four new endpoints (/process, /capabilities, /devtools, /health) and start_bridge now returns a third tuple element (the sidecar registry). These are optional enrichment: as of CLI v0.8 the commands that use them (process-tree, capabilities audit, webview attach, health) feature-detect via GET /version and degrade gracefully against an older/vendored bridge — they emit a clear note: (and fall back to an OS/eval path where possible) instead of failing. So you are not forced to re-sync dev_bridge.rs just to keep using the CLI. To unlock the richer structured output, re-copy dev_bridge.rs from the latest examples/tauri-bridge/src/dev_bridge.rs and adjust your main.rs to destructure the new return shape (Step 3). Pass --strict to any of those commands to turn a missing endpoint back into a hard error.
Bridge Endpoints
The bridge exposes eight HTTP endpoints on a random localhost port:
| Endpoint | Method | Auth | Purpose |
|---|
/eval | POST | token | Evaluate JS in a webview (supports window param for multi-window) |
/logs | POST | token | Rust tracing logs and sidecar output — bare {token} drains; {cursor, waitMs, limit} (v0.8+) reads without draining so multiple consumers can tail (powers logs --follow) |
/describe | POST | token | Report PID, window labels, and capabilities |
/version | GET | none | Bridge version and available endpoints (used for feature detection) |
/process | POST | token | Tauri PID + registered sidecars (powers process-tree) — v0.7+ |
/capabilities | POST | token | Declared Tauri capability set + live window labels (powers capabilities audit) — v0.7+ |
/devtools | POST | token | Webview inspector URL or platform hint (powers webview attach) — v0.7+ |
/health | POST | token | Uptime + webview readiness + sidecar liveness (powers health) — v0.7+ |
Step 1 — Add Cargo dependencies
Add to your Tauri app's src-tauri/Cargo.toml under [dependencies]:
tiny_http = "0.12"
serde = { version = "1", features = ["derive"] }
serde_json = "1"
scopeguard = "1"
rand = "0.8"
uuid = { version = "1", features = ["v4"] }
tracing = "0.1"
tracing-subscriber = { version = "0.3", features = ["registry"] }
[target.'cfg(unix)'.dependencies]
libc = "0.2"
(libc is used for the cheap kill(pid, 0) aliveness probe powering /process and /health sidecar reporting. Windows is supported but skips the liveness check in v0.7.)
Step 2 — Copy the bridge module
Copy dev_bridge.rs from the tauri-agent-tools package into your project:
TOOLS_DIR=$(npm root -g)/tauri-agent-tools
cp "$TOOLS_DIR/examples/tauri-bridge/src/dev_bridge.rs" src-tauri/src/dev_bridge.rs
If installed locally (not globally):
cp node_modules/tauri-agent-tools/examples/tauri-bridge/src/dev_bridge.rs src-tauri/src/dev_bridge.rs
Step 3 — Wire up in main.rs
Add the module declaration, register the bridge command, and start the bridge in your src-tauri/src/main.rs:
mod dev_bridge;
fn main() {
let mut builder = tauri::Builder::default();
if cfg!(debug_assertions) {
builder = builder.invoke_handler(tauri::generate_handler![
dev_bridge::__dev_bridge_result
]);
}
builder
.setup(|app| {
if cfg!(debug_assertions) {
if let Err(e) = dev_bridge::start_bridge(app.handle()).map(|_| ()) {
eprintln!("Warning: Failed to start dev bridge: {e}");
}
}
Ok(())
})
.run(tauri::generate_context!())
.expect("error while running tauri application");
}
If you already have an .invoke_handler() with your own commands, merge them into one handler:
builder = builder.invoke_handler(tauri::generate_handler![
your_command_one,
your_command_two,
dev_bridge::__dev_bridge_result,
]);
If you already have a .setup() call, add the if cfg!(debug_assertions) { ... } block inside it.
Step 4 — Verify
Build and run the Tauri app in dev mode, then:
tauri-agent-tools probe --json
tauri-agent-tools dom --depth 2
Both commands succeeding confirms the bridge is working. The probe output shows bridge version, available endpoints, window labels, and PID.
Multi-Window Apps
The bridge supports evaluating JS in any named webview window. The /eval endpoint accepts an optional window field (defaults to "main"). The /describe endpoint reports all registered window labels.
From the CLI, use --window-label to target a specific window:
tauri-agent-tools eval "document.title" --window-label overlay --json
tauri-agent-tools screenshot --selector ".content" --window-label settings -o /tmp/settings.png
Use probe to discover available windows:
tauri-agent-tools probe --json
Optional: Sidecar Log Capture + Process Visibility
To capture stdout/stderr from sidecar processes (external binaries) AND have them show up in process-tree/health, use spawn_sidecar_monitored() and pass the registry returned by start_bridge:
if cfg!(debug_assertions) {
let (_port, log_buffer, sidecar_registry) = dev_bridge::start_bridge(app.handle())?;
dev_bridge::spawn_sidecar_monitored(
"ffmpeg",
"ffmpeg",
&["-i", "input.mp4", "-f", "null", "-"],
&log_buffer,
Some(&sidecar_registry),
)?;
}
Pass None for the registry argument to opt out of process tracking (useful for ephemeral one-shot helpers).
If you spawn children with your own mechanism, register them after the fact so they appear in process-tree:
let child = my_own_spawn(...)?;
dev_bridge::register_sidecar(
&sidecar_registry,
"my-helper",
child.id(),
Some("/path/to/binary".to_string()),
vec!["--mode=watch".to_string()],
);
Then monitor with: tauri-agent-tools rust-logs --source sidecar --duration 10000, view the tree with tauri-agent-tools process-tree, and check liveness with tauri-agent-tools health.
Registration is only needed for the bridge's named /process view (and health liveness). If you just want to see the process tree — including children and grandchildren you spawned yourself — tauri-agent-tools process-tree --deep reads the live OS process table and needs no registration (or even no bridge, with --pid).
Troubleshooting
"No bridge found" error:
- Is the app running in dev/debug mode? The bridge only starts when
cfg!(debug_assertions) is true.
- Check for token files:
ls /tmp/tauri-dev-bridge-*.token
- The app process must be running — the bridge starts during
setup().
Stale token files:
- If the app crashed without cleanup, old token files may remain:
rm /tmp/tauri-dev-bridge-*.token
- Restart the Tauri app after cleaning.
Port conflicts:
- The bridge picks a random port. If it fails, check the app's stderr for "Failed to start dev bridge".
- Ensure no firewall blocks localhost connections.
Multi-window eval fails:
- Verify the window label matches exactly (case-sensitive). Use
probe --json to list available labels.
- The default label is
"main" — omit --window-label to target it.