Skip to content

CristianBB/os-loop-bridge

Folders and files

NameName
Last commit message
Last commit date

Latest commit

 

History

1 Commit
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 

Repository files navigation

OS Loop Bridge

A native desktop bridge that connects the OS Loop web application with local system capabilities. Built with Tauri v2 and Rust.

The bridge exposes an HTTP + WebSocket server on localhost that the web app discovers automatically. It provides MCP server proxying, filesystem access, and sleep prevention — all through a well-defined contract.

Architecture

os-loop-bridge/
├── crates/bridge-core/    # Pure Rust library — contract types, server, all business logic
├── src-tauri/             # Tauri v2 shell — thin wrapper that starts the bridge
├── src/                   # Frontend (status/settings UI)
└── docs/                  # Contract specification and guides

The project is structured as a Rust workspace with two crates:

  • bridge-core — Contains all testable logic: contract types, HTTP/WS server (Axum), session management, security, and fixed-port configuration. Runs with plain cargo test, no Tauri dependency needed.
  • src-tauri — Thin Tauri v2 wrapper that spawns the bridge server on app startup and registers the osloop:// custom protocol.

Prerequisites

Getting Started

# Clone the repository
git clone <repo-url>
cd os-loop-bridge

# Install the Tauri CLI
cargo install tauri-cli@^2

# Run in development mode
cargo tauri dev

The desktop shell uses Tauri's built-in dev server for the static frontend in src/, so there is no separate frontend process to start on port 1420.

The bridge binds to a single persisted localhost listening port. The default port is 47832 and the bridge never scans for fallback ports. The desktop status window shows the configured port, the currently active bound port, bind state, any bind error, and a recent localhost connection log so users can inspect handshakes, authenticated route usage, WebSocket upgrades, and 4xx/5xx failures. If the configured port is busy, startup fails explicitly on that same port, the configured value stays persisted, and osloop://ensure-server retries that same port instead of mutating it.

Development

Run Tests

# Run all bridge-core tests
cargo test -p bridge-core

# Run all workspace tests
cargo test --workspace

Build

# Debug build
cargo build --workspace

# Release build
cargo tauri build

Project Modules

Module Path Description
contract crates/bridge-core/src/contract/ Types, constants, and event definitions matching the bridge contract
config crates/bridge-core/src/config/ Persisted listening-port and app configuration
security crates/bridge-core/src/security/ Origin policy (dev/prod) and CORS
session crates/bridge-core/src/session/ Token-based session management with expiry
server crates/bridge-core/src/server/ Axum HTTP router, route handlers, auth middleware, WebSocket
capabilities crates/bridge-core/src/capabilities/ Capability enumeration
protocol crates/bridge-core/src/protocol/ osloop:// URL parsing
ui crates/bridge-core/src/ui/ UI state model for the desktop status window

Documentation

Bridge Contract

The full contract specification lives in docs/osloop-bridge-contract.md.

Key points:

  • Protocol version: osloop.bridge.v1
  • Discovery: The web app calls GET /api/v1/health on the persisted configured port, defaulting to 47832.
  • Authentication: POST /api/v1/session/handshake returns a session token. Authenticated routes require the X-OSLOOP-BRIDGE-TOKEN header.
  • WebSocket: GET /ws/v1/events?sessionToken=<token> for real-time events.
  • Custom protocol: osloop://open, osloop://focus, osloop://ensure-server, osloop://settings
  • Strict routing: clients must use the canonical /api/v1/... contract. The desktop connection log highlights malformed requests, including accidental /api/v1/api/v1/... duplication.

HTTP Routes

Route Auth Description
GET /api/v1/health No Health check and discovery
POST /api/v1/session/handshake No Create a session
POST /api/v1/session/refresh No Refresh a session
GET /api/v1/bridge/info Yes Bridge metadata
GET /api/v1/capabilities Yes List capabilities
GET /api/v1/mcp/servers Yes List MCP servers
POST /api/v1/mcp/servers Yes Register an MCP server
PATCH /api/v1/mcp/servers/:serverId Yes Update an MCP server
DELETE /api/v1/mcp/servers/:serverId Yes Remove an MCP server
POST /api/v1/mcp/servers/:serverId/connect Yes Connect to an MCP server
POST /api/v1/mcp/servers/:serverId/disconnect Yes Disconnect from an MCP server
GET /api/v1/mcp/servers/:serverId/capabilities Yes Get MCP server capabilities
POST /api/v1/mcp/call Yes Call an MCP tool
GET /api/v1/awake/status Yes Sleep prevention status
POST /api/v1/awake/acquire Yes Prevent system sleep
POST /api/v1/awake/release Yes Release sleep lock
GET /api/v1/filesystem/targets Yes List filesystem targets
POST /api/v1/filesystem/select Yes Open file/directory picker
POST /api/v1/filesystem/read Yes Read file content
POST /api/v1/filesystem/write Yes Write file content
GET /api/v1/system/info Yes OS, shell, and package manager info
GET /api/v1/system/tools Yes List known/installed tools
POST /api/v1/system/tools/locate Yes Locate tools by name
POST /api/v1/system/tools/install Yes Install a tool (always requires approval)
GET /api/v1/system/tools/recipes Yes List install recipes
POST /api/v1/system/tools/recipes/resolve Yes Resolve recipe for platform
POST /api/v1/system/commands/execute Yes Execute a system command
GET /api/v1/system/commands/runs Yes List command runs
GET /api/v1/system/commands/runs/:runId Yes Get run details (stdout/stderr)
POST /api/v1/system/commands/runs/:runId/terminate Yes Terminate a running command
GET /api/v1/system/permissions/commands Yes List whitelist rules
GET /api/v1/system/permissions/commands/:ruleId Yes Get whitelist rule
DELETE /api/v1/system/permissions/commands/:ruleId Yes Delete whitelist rule
POST /api/v1/system/permissions/prompts/:requestId/resolve Yes Resolve pending permission prompt
GET /api/v1/bridge/runtime Yes Runtime config (port, tray, timeout)

Capabilities (10)

mcp_proxy, filesystem, awake, system_info, system_tools, tool_install_recipes, health, version, command_permissions, tray_mode

WebSocket Events (33)

Real-time events via GET /ws/v1/events?sessionToken=<token>. Includes bridge lifecycle, MCP, awake, filesystem, system tool install/inventory, system command execution (started/stdout/stderr/completed/failed/terminated), permission prompts/decisions, whitelist updates, and runtime state changes. Full list in contract spec.

Permission Authority Model

The bridge is the final authority for command execution and tool installation:

  • Commands may be: allowed by existing whitelist, allowed once, allowed and whitelisted, or rejected.
  • Installs always require explicit user approval — they can never be whitelisted.
  • Rejections return structured codes: rejected_by_user, bridge_policy_denied, invalid_request.
  • Whitelist rules match against template fields (with __OSL_SECRET[...]__ placeholders), never resolved secret values.
  • Users can inspect and revoke whitelist rules via the permissions API.

Secret Safety

The bridge is secret-unaware by design. It receives already-resolved values from the web app and executes them. Secret interpolation (replacing __OSL_SECRET[...]__ placeholders with decrypted values) and output redaction (replacing secret values back to placeholders in stdout/stderr) are handled entirely by the web app before/after bridge interaction. The bridge never stores, manages, or has knowledge of secret IDs or placeholder syntax.

Tray / Background Mode

The bridge can run in the system tray (notification area). When tray mode is enabled:

  • Window close hides the app to tray instead of quitting
  • Permission prompts appear via tray notifications with a 60-second timeout
  • bridge.runtime.updated events reflect tray state changes
  • Tray menu: "Show Status", "Quit"

Default Timeout

Command execution and tool installation default to 300,000ms (5 minutes). The web app can override this per-request via the timeoutMs field. No maximum cap is enforced by the bridge. Stdout/stderr are buffered up to 10 MB per stream. Runs exceeding the buffer are marked partial_output: true. WebSocket events continue streaming regardless of the buffer limit.

Tech Stack

  • Tauri v2 — Desktop app framework
  • Axum — HTTP/WebSocket server
  • Tokio — Async runtime
  • Serde — Serialization

License

See LICENSE for details.

About

Native companion for OS Loop AI that extends browser agents with secure local capabilities—filesystem access, MCP connectivity, long-running tasks, and system-level execution

Topics

Resources

License

Stars

Watchers

Forks

Releases

No releases published

Packages

 
 
 

Contributors