Tap
rozenite agent tap connects to a device and prints Rozenite plugin messages as they flow, in both directions, without opening a browser or React Native DevTools.
The full loop for checking that a plugin’s native side behaves — Metro, a simulator, the app, a browser running React Native DevTools, the shell, and the panel — is a lot of overhead just to watch a handful of messages when the thing you’re testing lives on the device. tap skips the browser half entirely.
Watch a plugin’s traffic
Section titled “Watch a plugin’s traffic”npx rozenite agent tap @acme/sqlite-plugin← 12:04:31.220 sqlite:list-tables-request {"requestId":"a1"}→ 12:04:31.244 sqlite:list-tables-response {"requestId":"a1","tables":["users","posts"]}Each line is a direction arrow, a local timestamp, the message type, and the JSON payload:
←— received from the device.→— sent to the device.
Omit the plugin to watch every plugin’s traffic on the session. tap uses the same session as every other rozenite agent command, and creates it on first use. tap keeps running until you stop it with Ctrl-C, closing the underlying connection cleanly.
Poke a plugin and watch what comes back
Section titled “Poke a plugin and watch what comes back”Because the stream is bidirectional, tap doubles as a minimal stand-in for DevTools: send one message from the terminal, then keep watching for whatever comes back.
npx rozenite agent tap @acme/sqlite-plugin --send sqlite:query --payload '{"sql":"select 1"}'The plugin, --send, and --payload map directly onto the three fields of the message sent to the device (pluginId, type, payload). --payload defaults to {} and is validated as JSON on its own, so a malformed payload is reported against --payload, not against a blended argument. --send requires a plugin, since a message needs to know which plugin it’s addressed to.
The plugin also filters the stream — --send does not, since filtering on it would hide the very response your poke is meant to surface.
Machine-readable output
Section titled “Machine-readable output”When stdout is not a terminal, tap writes newline-delimited JSON, one message per line, so another program or agent can consume the stream directly instead of screenshotting a terminal:
npx rozenite agent tap @acme/sqlite-plugin | your-script{ "direction": "in", "timestamp": 1700000000000, "pluginId": "@acme/sqlite-plugin", "type": "list-tables-request", "payload": { "requestId": "a1" }}Each line has this shape:
| Field | Description |
|---|---|
direction |
"in" (received from the device) or "out" (sent to the device). |
timestamp |
Milliseconds since the Unix epoch. |
pluginId |
The plugin the message belongs to. |
type |
The message type. |
payload |
The message payload, unmodified. |
Options
Section titled “Options”[plugin]— only stream this plugin ID; required together with--send.--send <type>— send one message of this type before watching. Requires a plugin.--payload <json>— JSON payload for the sent message. Defaults to{}.--device <id>— the device to tap when more than one is connected;--session <id>picks one session directly.--host <host>/--port <port>— Metro host and port:npx rozenite agent tap @acme/sqlite-plugin --host 192.168.1.10 --port 8082(defaults to127.0.0.1:8081).
tap and React Native DevTools
Section titled “tap and React Native DevTools”tap rides the same connection rozenite agent uses, and neither disconnects React Native DevTools. You can keep a plugin’s panel open in DevTools and watch the same messages in the terminal. Stop the tap with Ctrl-C when you’re done.
Next steps
Section titled “Next steps”- Rozenite for Agents — the wider agent-facing workflow
tapis part of. - Agent SDK — build custom tooling on top of the same session
tapuses.