Skip to content
    ↑↓ select↵ openesc close
    English中文
    lesquel

    Pilot

    v1.21.0Notifications
    @lesquel/opencode-pilot

    Remote control web dashboard for OpenCode — multi-project tabs, live SSE streaming, mobile-friendly, push/Telegram notifications, tunnel for phone access from anywhere.

    GitHub stars

    5

    +1 in 30 days

    Monthly installs

    446

    60 in 7 days

    Composite scoreSCORE

    44.3

    Multi-signal model

    Last commit

    14 days ago

    2026-08-05

    Install and configure

    opencode.json

    Writes to this project's opencode.json — applies to this repository only.

    opencode.json

    {
      "$schema": "https://opencode.ai/config.json",
      "plugin": ["@lesquel/opencode-pilot@1.21.0"]
    }

    opencode loads npm dependencies through its embedded runtime on startup and caches them locally — no manual global install needed.

    Remote control plugin for OpenCode and Codex CLI — monitor sessions, send prompts, approve permissions, switch agents, and get notifications from your phone or any browser.

    npm version npm downloads License: MIT GitHub stars


    What it does

    Spin up OpenCode locally, get a web dashboard you can open on your laptop or phone. From the dashboard you can:

    • See all your sessions across all your projects (multi-project tabs)
    • Send prompts and watch responses stream live
    • Approve / deny tool permissions remotely
    • Switch agents (build / plan / general / explore) per session
    • Track cost per session, per day, per week
    • Get sound, browser, push, and Telegram notifications when an agent finishes
    • Pin TODOs that survive across sessions
    • Diff view of all files changed
    • File browser with live filter
    • Connect from your phone via QR code (LAN or public tunnel)
    • Monitor Codex CLI sessions too via the /codex/hooks/:event HTTP bridge — same dashboard, same notifications, same permission flow (see docs/CODEX-INTEGRATION.md)

    All from one keyboard shortcut (? opens the command palette).


    Install once, use everywhere

    opencode-pilot installs globally into your OpenCode config dir (~/.config/opencode on Linux/macOS, %APPDATA%\opencode on Windows). One install and the plugin auto-loads every time you run opencode from any project directory — no per-project setup, no .opencode/ folders to copy around, no duplicate configs.

    That's the whole point of running the installer: drop it in once, then just use opencode normally and the dashboard is always there.

    Quick Start

    One command (recommended)

    npx @lesquel/opencode-pilot init
    # or
    bunx @lesquel/opencode-pilot init
    

    That's it. The installer:

    1. Locates your OpenCode config dir (~/.config/opencode or your XDG path / %APPDATA%).
    2. Installs the plugin there (@lesquel/opencode-pilot@latest + @opencode-ai/plugin@latest).
    3. Adds "@lesquel/opencode-pilot@latest" to both opencode.json::plugin (for the dashboard server) and tui.json::plugin (for the slash commands). OpenCode uses two separate plugin loaders — one file each.
    4. Cleans up stale wrappers, cache entries, and legacy subpath specs left by earlier (<=1.12.x) installs.

    Fully close any running OpenCode sessions and reopen. A toast should appear:

    OpenCode Pilot — Remote control plugin loaded. Use /pilot or /pilot-token.

    The banner also prints in the terminal with URL + token + QR. If the toast doesn't appear, see Troubleshooting.

    Configuration is done from the dashboard (gear icon → Plugin configuration). You do NOT need to create a .env — though you still can if you prefer.

    Manual install (if you want to)

    # 1. Install in your OpenCode config dir
    cd ~/.config/opencode    # or your XDG_CONFIG_HOME path
    bun add @lesquel/opencode-pilot@latest @opencode-ai/plugin@latest
    
    # 2. Add the spec to BOTH config files:
    #
    #    opencode.json  — registers the dashboard server plugin:
    #    {
    #      "plugin": ["@lesquel/opencode-pilot@latest"]
    #    }
    #
    #    tui.json  — registers the slash commands (create this file if missing):
    #    {
    #      "$schema": "https://opencode.ai/tui.json",
    #      "plugin": ["@lesquel/opencode-pilot@latest"]
    #    }
    

    OpenCode runs two separate plugin loaders: the server loader reads opencode.json::plugin (for server() exports like the dashboard), and the TUI loader reads tui.json::plugin (for tui() exports like slash commands). A spec in only one of them gets you half the plugin. Do not add wrappers in <config>/plugins/ — they conflict with the server loader's strict validation.

    Run opencode from any project directory. Banner prints with URL + token + QR.


    Going deeper? docs/INSTALL.md explains OpenCode's two-loader plugin architecture, documents every gotcha we hit, and has a complete troubleshooting matrix. Read it if you're debugging, contributing, or publishing your own OpenCode plugin.

    How to use it day-to-day

    Once installed and OpenCode restarted, you have four entry points:

    1. Slash commands from inside OpenCode TUI

    Type any of these at the prompt:

    Command What it does
    /pilot Show the current dashboard URL + token
    /pilot-token Rotate the auth token (invalidates any open dashboards/phones)
    /dashboard Same as /pilot — alias
    /remote Print connection info (host, port, tunnel URL if active)
    /remote-control Full status block with all the above plus QR hint

    2. Terminal banner at startup

    Every opencode launch prints a banner with the dashboard URL, a token, and a QR code. Open the URL in any browser on the same machine, or scan the QR with your phone (requires PILOT_HOST=0.0.0.0 for LAN — see below).

    3. The web dashboard itself

    Open the URL. Then:

    • ? opens the command palette — every action is reachable from there.
    • Left sidebar: sessions grouped by folder. Click one to switch. + creates a new session.
    • Center pane: the live transcript — user messages appear instantly, the assistant's response streams token by token, tool calls animate pending → running → completed with their inputs and outputs expandable inline.
    • Right panel: context usage, MCP servers, LSP status, project path, pinned TODOs.
    • Tabs at the top: open multiple projects in parallel (v1.11+).
    • Gear icon (⚙): Settings UI — change port/host, enable tunnel, wire up Telegram bot, generate VAPID keys for Web Push. Everything is editable from here; you rarely need to touch .env files anymore.

    4. From your phone

    See Connect from your phone below. Either same-WiFi (LAN) with PILOT_HOST=0.0.0.0, or anywhere with a Cloudflare / ngrok tunnel. The dashboard is mobile-friendly — bottom-sheet modals, 44px tap targets, swipe-to-close. Permissions approvals, prompt sending, session switching all work from the phone.

    Troubleshooting — slash commands don't appear

    Other symptoms (port conflicts, /remote says "server not running", dashboard 401s, push/telegram silent, wrong tab opens) are covered in docs/TROUBLESHOOTING.md. This section is specifically about the "I installed it but slash commands are missing" case.

    If the plugin loads (you see the banner in the terminal) but typing /remo<Tab> in the TUI doesn't autocomplete /remote, /dashboard, /pilot, /pilot-token, or /remote-control:

    1. Check the canary toast. On startup the TUI should toast "OpenCode Pilot — Remote control plugin loaded". No toast → the TUI plugin didn't register, even if the dashboard server did.

    2. Inspect the latest log:

      tail -200 $(ls -t ~/.local/share/opencode/log/*.log | head -1) | grep -iE "pilot|tui.plugin|error"
      
      • Windows: %LOCALAPPDATA%\opencode\log\<timestamp>.log
      • macOS: ~/Library/Logs/opencode/<timestamp>.log
    3. Re-run init. It cleans up stale wrappers and stale subpath entries left behind by 1.11.x–1.12.x:

      npx @lesquel/opencode-pilot@latest init
      

      Then fully close all OpenCode sessions (the plugin loader is cached per running process) and reopen.

    4. Verify BOTH opencode.json::plugin AND tui.json::plugin each have exactly one entry for the pilot:

      "plugin": ["@lesquel/opencode-pilot@latest"]
      

      If tui.json is missing entirely, the TUI plugin was never registered and slash commands never appear — init in 1.13.1+ creates this file. If you see "@lesquel/opencode-pilot/tui" anywhere or wrapper paths in the array, the old install pattern got in — npx init in step 3 fixes that.

    5. Verify no stale wrappers in ~/.config/opencode/plugins/. Safe to delete: opencode-pilot.ts, opencode-pilot-tui.ts. These were auto-generated by 1.11.x–1.12.x and are no longer needed. init does this cleanup automatically.


    Connect from your phone

    Same WiFi (LAN access)

    1. Set PILOT_HOST=0.0.0.0 in .env
    2. Restart OpenCode
    3. Click the phone icon in the dashboard header (c shortcut)
    4. Scan the QR from the "Local network" tab with your phone camera
    5. Done — same dashboard, on your phone

    Anywhere (public tunnel)

    1. Install cloudflared (brew install cloudflared on Mac)
    2. Add PILOT_TUNNEL=cloudflared to your .env
    3. Restart OpenCode — it spawns the tunnel automatically
    4. Phone modal "Public tunnel" tab now has a QR with a public HTTPS URL
    5. Works from cellular, hotel WiFi, anywhere

    🔐 Security note: the tunnel URL contains your token. Treat it like a password. See docs/TUNNEL_TESTING.md for security checklist.


    Features

    Dashboard

    • Sessions sidebar with folder grouping and agent filter
    • Multi-view to watch multiple sessions side-by-side (desktop only)
    • Project tabs at the top — open multiple projects in parallel
    • Right info panel with Context, MCP servers, LSP clients, project path, instance version
    • Pinned TODOs survive across sessions and project switches
    • Cost panel with per-session, daily, and weekly totals + budget alerts
    • Diff tab showing all files changed in current session

    Notifications

    Type Trigger Setup
    Sound Page hidden + assistant turn complete Toggle in Settings
    Browser notification Page hidden + permission granted Toggle, allow when prompted
    Push (Web Push) Anywhere, even browser closed VAPID keys in .env (guide)
    Telegram Permission requests + completions Bot token in .env

    Mobile-friendly

    • Drawer sidebar with backdrop
    • Full-screen modals
    • Multi-view auto-hidden (use desktop for split view)
    • Right panel as bottom toggle
    • Live filter on file browser
    • 44×44 touch targets everywhere

    Keyboard shortcuts

    Single-key (when no input focused):

    Key Action
    ? Open command palette + show shortcuts
    n New session
    s Toggle sidebar
    m Toggle multi-view (desktop only)
    t Toggle theme
    c Connect from phone modal
    / Focus prompt input
    Esc Close modal/picker/palette

    Modifier:

    Key Action
    Cmd/Ctrl+K Command palette
    Cmd/Ctrl+Enter Send prompt
    Alt+I Toggle right info panel

    Configuration — two ways

    Since v1.12 you can configure the plugin two ways (or both):

    Easy: the Settings UI

    1. Open the dashboard
    2. Click the gear icon (⚙) in the header
    3. Go to Plugin configuration
    4. Edit port, host, tunnel, Telegram token, VAPID keys, permission timeout, and the glob opener toggle
    5. Click Save — values are written to ~/.opencode-pilot/config.json and survive restarts

    Some fields (port, host, tunnel, VAPID keys) require an OpenCode restart to take effect — the UI shows an inline warning for those. A Generate VAPID keys button calls the server to create a key pair in one click.

    Each field shows a small badge telling you where its current value comes from: saved (UI), .env, shell, or default. Fields set via shell env vars are locked from the UI — you must unset the shell var to override.

    Power user: .env file

    Full env-var reference with example .env files for common scenarios lives in docs/CONFIGURATION.md. Quick overview:

    Variable Default What
    PILOT_PORT 4097 HTTP server port
    PILOT_HOST 127.0.0.1 Bind address (0.0.0.0 for LAN)
    PILOT_TUNNEL (off) cloudflared or ngrok for public access
    PILOT_PERMISSION_TIMEOUT 300000 Permission-request timeout in ms
    PILOT_TELEGRAM_TOKEN (off) Telegram bot token from @BotFather
    PILOT_TELEGRAM_CHAT_ID (off) Your Telegram chat ID
    PILOT_VAPID_PUBLIC_KEY (off) Web Push public key (bunx web-push generate-vapid-keys)
    PILOT_VAPID_PRIVATE_KEY (off) Web Push private key
    PILOT_ENABLE_GLOB_OPENER false Enable /fs/glob for the dashboard's glob search
    PILOT_FETCH_TIMEOUT_MS 10000 Timeout for outbound HTTP calls (Telegram, push)

    Priority (highest wins)

    1. Shell env vars                         e.g. PILOT_PORT=5000 opencode
    2. ~/.opencode-pilot/config.json          written by the Settings UI
    3. .env file (process.cwd or plugin dir)  power-user file-based config
    4. Hardcoded defaults                     fallback
    

    The .env file is searched in: (1) process.cwd()/.env then (2) the plugin's install dir. Shell env vars always win over both .env and the Settings UI.


    Documentation

    For users

    For contributors and AI agents


    Architecture (one line)

    The plugin runs ONE HTTP+SSE server inside your OpenCode process. The dashboard is a vanilla ES-modules SPA served from the same origin. All API calls go through the SDK with ?directory= for multi-project routing.

    If you want the deep version, see the docs/ folder.


    Tech stack

    • Server: Bun + TypeScript (strict)
    • Dashboard: vanilla ES modules, plain CSS, ~9000 LOC. No React, no build step.
    • Optional deps: cloudflared / ngrok (tunnel), @modelcontextprotocol/sdk (MCP), web-push (push notifications)
    • Tests: 228 (Bun test runner), all green

    Contributing

    Issues are welcome. Pull requests are welcome only after maintainer approval.

    Please start with an issue first: bug report, feature request, or discussion. The maintainer will triage it and either:

    • fix it directly and comment on the issue,
    • ask you to send a PR, or
    • close it as out of scope / duplicate / needs more information.

    Read CONTRIBUTING.md for the full issue-first workflow, PR rules, review expectations, contributor credit, and local development setup.

    Maintainer notes for contributors:

    • One PR per approved issue.
    • Keep PRs small and reviewable.
    • Add tests for behavior changes.
    • Do not bump versions, edit CHANGELOG.md, or publish releases.
    • Follow AGENTS.md for codebase conventions: no any, no server console.log, factory functions, release safety rules.

    Security reports are private: see SECURITY.md. Community expectations are in CODE_OF_CONDUCT.md.

    Shipping a new version is maintainer-only: follow docs/RELEASE.md. Pushing a vX.Y.Z tag is the only supported way to publish.


    License

    MIT © lesquel