@ai-monitor/bridge
v1.0.110
Published
Unified AI tool log bridge — local gateway for iOS AI Partner app + optional cloud upload
Readme
@ai-monitor/bridge
Local gateway that bridges AI tool logs to the My AI Partner iOS app via WebSocket RPC.
Install
npm install -g @ai-monitor/bridgeRequirements: Node.js 20.x to 22.x (native dependencies are not validated on newer majors).
Quick Start
# 1. Generate config
ai-monitor-bridge init
# 2. Start the bridge
ai-monitor-bridge daemon install
# or run `ai-monitor-bridge start` for a foreground sessionCLI Commands
| Command | Description |
|---------|-------------|
| init | Generate ~/.config/ai-monitor-bridge/config.json |
| login [--copy] [--open] / connect | Default cross-network phone pairing flow with automatic QR output in a terminal |
| pair [--rotate] [--copy] [--qr] [--open] [--host auto] [--wait] [--cloud] | Generate a QR-friendly local or cloud pairing flow |
| start | Start the bridge in the foreground (gateway + watchers + spool worker) |
| daemon install / daemon status / daemon uninstall | Manage the background service (macOS launchd, Linux systemd) |
| attach <tool> [args...] | Wrap a tool with PTY logging. Supports: claude, codex, gemini, and any OpenClaw-family tool name ending in claw |
| import cursor [--since 24h] | Import Cursor IDE session history via cursor-history |
| import claude [--since 24h] | Import Claude Code JSONL history from ~/.claude/projects/ |
| import gemini [--since 24h] | Import Gemini log history from ~/.gemini/ + XDG path |
| import codex [--since 24h] | Import Codex history from ~/.codex/ |
| status | Show spool status and bridge info |
| flush | Force-flush pending spool records to cloud |
| spool retry-failed [--flush] | Requeue failed spool records and optionally upload them immediately |
| spool purge-failed | Delete failed spool records permanently |
OpenClaw-family branding notes:
tools.openclawFamily.sources[].branding.iconPathcan point to a localpng/jpg/webp/icnsfile.- On macOS, if
iconPathis omitted for a*clawsource, the bridge will try to discover the matching.appbundle icon automatically and upload it assourceIconBase64. - If a future
*clawruntime creates a recognizable state directory such as~/.arkclawor~/.openclaw-arkclaw, the bridge will auto-discover it even before you add an explicit config entry. - If
~/.happycapy/exists, the bridge now enables built-in HappyCapy matchers that treat the machine as a HappyCapy host based on the install markers alone, then fall back to transcript content for offline imports. - MuleRun is bundled as a Claude-family wrapper source. The default matcher keys off a startup-visible multi-path workspace signature that includes
.claude/skills/mulerouter-skills,.mcp.json, andtemplate/CLAUDE.md, then falls back to transcript paths like/var/lib/mule/, and brands those sessions withmulerun-icon. - Non-gateway branded sources can still be surfaced explicitly by re-labeling Claude sessions with
tools.claude.derivedSources[];happycapyis bundled as an OpenClaw-family presentation withhappycapy-icon. - The iOS app prefers uploaded source icon bytes first, then bundled asset fallbacks.
Adapter Capability Matrix
| Adapter | watch (passive) | attach (PTY) | import (batch) |
|---------|:-:|:-:|:-:|
| Claude Code | ✓ (JSONL watcher) | ✓ | — |
| Gemini | ✓ (~/.gemini/**) | ✓ (with args) | ✓ |
| Codex | ✓ (~/.codex/**, no args) | ✓ (with args) | ✓ |
| OpenClaw | — | ✓ (WebSocket proxy) | — |
| Cursor | ✓ (cursor-history incremental sync + filesystem-triggered poll) | — | ✓ (cursor-history) |
Configuration
Config file: ~/.config/ai-monitor-bridge/config.json
{
"gateway": {
"port": 18790,
"auth": "device-token"
},
"upload": {
"endpoint": "",
"apiKey": "env:AI_BRIDGE_API_KEY",
"requireContentEncryption": true,
"batchSize": 50,
"flushIntervalMs": 3000
},
"retry": {
"maxAttempts": 8,
"baseDelayMs": 500,
"maxDelayMs": 60000
},
"spool": {
"dir": "~/.ai-monitor-bridge/spool",
"maxMb": 1024,
"encryption": "aes-256-gcm",
"keyFile": "~/.config/ai-monitor-bridge/spool.key"
},
"privacy": {
"enableRedaction": true,
"rules": ["openai_key", "aws_key", "anthropic_key", "email", "phone"]
},
"tools": {
"claude": {
"projectsDir": "~/.claude/projects",
"sessionEnvDir": "~/.claude/session-env",
"hooksPort": 18791,
"autoInjectHooks": false
}
}
}If the machine has ~/.happycapy/happycapy.json or ~/.happycapy/agents/, the default config already registers HappyCapy startup matchers that treat the current home directory as a HappyCapy host based on those install markers alone, plus transcript fallbacks for offline imports. The default config also registers MuleRun startup matchers for a stronger workspace signature rooted in .claude/skills/mulerouter-skills, .mcp.json, and template/CLAUDE.md, plus transcript fallbacks for /var/lib/mule/.
tools.claude.derivedSources[] is intended for wrappers that persist their actual chat stream in Claude JSONL but keep identity/memory/config elsewhere. Each configured matcher is an AND across matcher groups, with OR semantics inside a group:
jsonlPathContains: substring match against the JSONL file pathprojectPathContains: substring match against the Claude project root underprojectsDircwdContains: substring match against the observed runtime cwdcwdPathExists: require one of these files/directories to exist under the observed runtime cwdcwdAllPathExists: require all of these files/directories to exist under the observed runtime cwdsessionEnvContains: substring match against the corresponding entry undersessionEnvDirhomePathExists: require one of these files/directories to exist under the current home directoryhomeAllPathExists: require all of these files/directories to exist under the current home directorytranscriptContains: substring match against extracted text/tool input/tool result content from the JSONL transcript itself
User-defined tools.claude.derivedSources[] entries are appended after the built-in HappyCapy/MuleRun defaults, not replaced wholesale.
When a matcher hits, the adapter emits that session as tool=<sourceId> instead of claude-code, so grouping, filtering, branding, and dashboard cards all stay source-native.
Example override for custom wrappers or non-standard HappyCapy deployments:
{
"tools": {
"claude": {
"derivedSources": [
{
"sourceId": "happycapy",
"match": {
"homePathExists": [
".happycapy/happycapy.json",
".happycapy/agents/capy-default"
]
}
},
{
"sourceId": "happycapy",
"match": {
"transcriptContains": [
".happycapy/happycapy.json",
".happycapy/agents/capy-default/identity.md"
]
}
},
{
"sourceId": "mulerun",
"match": {
"cwdAllPathExists": [
".claude/skills/mulerouter-skills",
".mcp.json",
"template/CLAUDE.md"
]
}
},
{
"sourceId": "mulerun",
"match": {
"transcriptContains": [
".claude/skills/mulerouter-skills",
"/var/lib/mule/logs/",
"/var/lib/mule/segments/"
]
}
}
]
}
}
}Authentication Modes
device-token (default, recommended)
On first startup the bridge generates an internal bridge token for pairing bootstrap, prepares a secure one-time pairing session, and tells you to generate the handoff link explicitly:
[GatewayServer] Secure pairing is ready (10 min). Press Enter in an interactive `ai-monitor-bridge start` session, or run `ai-monitor-bridge login`, for the shortest cross-network QR flow. Use `ai-monitor-bridge pair` for LAN-only pairing.
[GatewayServer] gateway.host is still loopback (127.0.0.1). For a physical iPhone on the same LAN, set gateway.host to `0.0.0.0` or your LAN IP, restart the bridge, then run `ai-monitor-bridge pair`.First-time pairing:
- Run
ai-monitor-bridge start - Press Enter in the bridge terminal
- Scan the QR code on the iOS device and approve the machine
- The bridge claims the trusted device automatically once approval completes
- Subsequent reconnects use the trusted device identity plus the encrypted transport automatically
For same-LAN local pairing instead of relay-mediated pairing, set gateway.host to 0.0.0.0 or your LAN IP, restart the bridge, then run ai-monitor-bridge pair.
You can also paste the secure pairing URI directly into the iOS local gateway settings screen. Current builds only support the secure v=3 form (request ID + bridge ephemeral public key).
Generate, rotate, or copy the current secure pairing link at any time:
ai-monitor-bridge login
ai-monitor-bridge login --copy
ai-monitor-bridge pair
ai-monitor-bridge pair --rotate
ai-monitor-bridge pair --copy
ai-monitor-bridge pair --open
ai-monitor-bridge pair --cloud --copyWhen stdout is an interactive terminal, both ai-monitor-bridge login and ai-monitor-bridge pair render a QR code automatically. login defaults to the relay-mediated cross-network flow. pair stays local and prefers the first LAN IPv4 only when the bridge itself listens on a LAN-reachable host such as 0.0.0.0; otherwise it stays on loopback and warns instead of generating a broken LAN link. Re-run with --host 127.0.0.1 if you explicitly want a simulator-only link.
Important transport boundary:
- Local secure pairing encrypts the bootstrap exchange and avoids putting the long-lived device token into the QR/link.
- Current My AI Partner builds then negotiate an application-layer encrypted channel for local RPC/event/tick traffic, even though the socket URL remains
ws://. - The bridge rejects local clients that do not advertise
transport.enc.v1. - Prefer
ai-monitor-bridge loginwhen you want relay-mediated approval or encrypted access across networks.
On macOS, --copy works well with Universal Clipboard: run it on the Mac, then use the iPhone app's pairing sheet to paste or open the secure link in one tap. --open is useful when you want the browser landing page on the Mac immediately without manually pasting the printed URL.
For remote relay trust, create a cloud-mediated approval request:
ai-monitor-bridge login
ai-monitor-bridge connect
ai-monitor-bridge pair --cloud
ai-monitor-bridge pair --cloud --copyThe cloud QR/link carries only the relay URL plus request ID. The iPhone app shows the machine details, requires an explicit approval tap, and the bridge then claims the trusted device automatically.
Clients that do not present a valid token are rejected with PAIR_REQUIRED.
The token is persisted at ~/.config/ai-monitor-bridge/device-token (mode 0600).
token (explicit secret)
Set auth: "token" and token: "<secret>" to require a specific secret:
{
"gateway": {
"port": 18790,
"auth": "token",
"token": "my-secret-token"
}
}Note: If
authis"token"buttokenis empty, the bridge will refuse to start.
none (development only)
No authentication — any local process can connect. A warning is printed on startup.
iOS Integration
The iOS app connects to ws://127.0.0.1:18790 by default (configurable in Settings) and negotiates transport.enc.v1 automatically after pairing. If the app no longer has the trusted machine key, the local connection is rejected until the bridge is paired again.
Supported RPC methods:
| Method | Description |
|--------|-------------|
| connect | Handshake (required first) |
| sessions.list | List AI partner sessions |
| sessions.events | Fetch canonical timeline history for a session |
| health | Returns { status: "ok", version: "1.0" } |
| chat.send | Proxied to upstream OpenClaw gateway |
| chat.abort | Proxied to upstream OpenClaw gateway |
| bridge.status | Returns adapter status, spool stats, uptime |
Cursor Import
cursor-history is bundled with @ai-monitor/bridge and used by the built-in Cursor adapter. ai-monitor-bridge start keeps Cursor sessions warm via incremental sync, and import cursor can still backfill older history on demand.
npm install -g @ai-monitor/bridge
ai-monitor-bridge import cursor --since 24hLocal Cursor Extension Sync
When the bridge starts, it also launches a loopback-only local plugin server for editor extensions and writes a manifest to ~/.config/ai-monitor-bridge/local-plugin.json.
- Endpoint auth is protected by a per-user bearer token stored alongside the manifest.
- The bundled Cursor extension in
extensions/ai-monitor-cursor-bridge/reads that manifest automatically. - The extension watches Cursor storage changes and triggers immediate
cursorsyncs back into the bridge, while the bridge remains the single parser/uploader.
Spool & Reliability
Events are persisted to ~/.ai-monitor-bridge/spool/spool.db (SQLite WAL mode).
The attach command also uses the spool — events survive bridge restarts.
If better-sqlite3 is unavailable at runtime, the bridge falls back to an in-memory spool (non-persistent).
Publishing
Use the publish script to release both @ai-monitor/types and @ai-monitor/bridge:
# Patch release (default)
./scripts/publish.sh
# Minor / major
./scripts/publish.sh minor
./scripts/publish.sh major
# Publish current version without bumping (e.g. retry a failed publish)
./scripts/publish.sh --no-bumpThe script publishes @ai-monitor/types first (since bridge depends on it), then @ai-monitor/bridge.
