Skip to content

Repository files navigation

opencode-cockpit

CI npm npm npm License: MIT

Give OpenCode the instruments it does not ship with.

Documentation → · Install · Shell · Statusline · Changelog

A tool call has to finish. A dev server does not, and neither does the context window filling up behind you. Cockpit is the instrument panel: things your agent can use, and things that tell you what it is doing.

opencode plugin opencode-cockpit --global

🖥️ Shell — terminals that keep running

Your agent starts a dev server and the tool call blocks until you kill it. It backgrounds one instead and loses the output. Shell gives it terminals with a real PTY that outlive the turn, wait for a port or a pattern, and hand back the part that matters — and gives you a panel where every one of them reports its own health.

The shells panel: a dev server running under the conversation

A real recording. Every demo here is generated from a live OpenCode session by bun run record and re-run on release, so none of them can drift from what ships.

9 agent tools · 35 watch presets · docs · @opencode-cockpit/shell


📊 Statusline — what the session is costing you

How full is the context? Where did the tokens go? What has changed? OpenCode answers the first in a corner and the rest not at all. Statusline answers them where you are already looking.

The statusline under an OpenCode conversation: a context bar at 40%, the token total with its cache, input and output parts, the session diff, elapsed time and todo progress

The default line — no configuration written at all. Every part is a segment you can reshape, recolour or remove, or write yourself in TypeScript. Your Claude Code statusline script runs here unchanged, colours and all.

14 segments · 2 surfaces · docs · @opencode-cockpit/status


Each bay is its own npm package with a switch in config. They share the daemon, the config file and the keys, so the second costs nothing and moving between them changes nothing you already set up.

Shell, by example

"Start the dev server and wait until it's actually ready." The agent starts it in a real terminal and blocks on the port opening — not a guess, not a sleep:

shell_start  command="npm run dev"  waitFor={ port: 5173 }
→ condition met: port is accepting connections
  1| VITE v7.3.1  ready in 431 ms

"Run the tests, keep working, tell me if they fail." The suite runs in the background. When it exits, the agent is messaged once, with the error line already picked out:

<shell_exited id="sh_9wq2f1ab" title="unit tests">
exited with code 1 after 48s
last output: 37| FAIL src/auth.test.ts > refresh token expiry

"How is DB Monitoring doing?" Shells are shared across sessions and can be addressed by name:

shell_read name="DB Monitoring"

Logs that don't eat your context. Colour codes stripped, progress-bar redraws collapsed to their final frame, repeated lines folded to (×12), and every read returns a cursor so the next one only brings what's new. For full-screen programs (vitest --ui, htop, prompts) the agent can ask for the screen instead of the log.

It notices breakage on its own. Watch a process that never exits and the agent hears only about changes, never about a thousand identical recompiles:

shell_start command="tsc --watch --noEmit" description="type checker" watch=true
→ tsc: ok → fail · src/auth.ts(42,3): error TS2339: Property 'id' does not exist

Presets cover about 35 tools (tsc, vitest, jest, eslint, cargo, go, gradle, pytest, vite, next, docker compose…), and anything else takes three regexes of its own. A watched process that dies counts as a failure, so a crashed dev server is reported too.

You can find things in a huge log. / in the console filters the scrollback to matching lines, keeping line numbers and highlighting matches — and output keeps the colours the program printed.

It can type. Prompts, REPLs, migration wizards: shell_send sends text or named keys (ctrl+c, up, enter) and returns whatever the program printed back.

Why not just bash?

Built-in bash tool Cockpit Shell
Long-running processes Blocks until exit Runs in the background, survives the turn
Knowing something is ready Guess, or sleep and poll Blocks on a port, a pattern, silence or exit
Interactive programs Not possible (no TTY) Real PTY: prompts, REPLs, ctrl+c
Reading output Whole log, every time Clean lines from a cursor, with grep
Noticing a break later Never Watchers report health changes
Your visibility None until it finishes Live panel, console and sidebar
After OpenCode restarts Gone Still running

For you, not just the agent

Key / command Does
ctrl+x o · /shells Toggle the shells panel under the chat
ctrl+x i · /shell Open the shell console
/shell-new Start a shell yourself
/shells-clear Remove finished shells
/cockpit-update Update the plugin when a newer release exists

Status reads the same everywhere — RUN (with a spinner), FAIL, STOP, DONE — running shells and recent failures stay in view, the rest folds behind ▸ N more. In the console: i types straight into the program (ctrl+] to stop), c sends ctrl+c, r restarts, x stops, tab switches between the live screen and the scrollback, ? shows details.

Install

Everything

opencode plugin opencode-cockpit --global

Only what you want

opencode plugin @opencode-cockpit/shell --global

Restart OpenCode. Requires OpenCode 1.18+ on macOS or Linux. Install a feature either through opencode-cockpit or on its own — if both are configured, the first one loaded is used and OpenCode warns you which entry to remove.

Turn features off (in both opencode.json and tui.json):

{
  "plugin": [["opencode-cockpit", { "features": { "shell": true } }]]
}

Configure them in one file, read by both halves of the plugin and by every project:

~/.config/opencode-cockpit/config.json   →   <project>/.cockpit.json   →   plugin-entry options
{
  "kinds": { "e2e": "playwright|cypress" },
  "defaults": { "logFile": true, "timeoutSeconds": 900 },
  "ui": { "dockHeight": 16, "historyMinutes": 60 }
}

Later sources win key by key, and an invalid file is ignored rather than fatal. You can categorize your own commands, define watch rules, cap how long shells live, choose what may interrupt the agent, and trade context tokens for accuracy. Each feature's README documents its own settings: Shell.

How it works

OpenCode TUI thread ── feature plugins (tui) ──┐
                                                ├── unix socket, JSON-RPC ── cockpitd ── processes
OpenCode server worker ─ feature plugins (server) ┘

OpenCode runs its interface and its server in separate threads, so a plugin's two halves can't share memory. Both talk to cockpitd, a small daemon that owns every long-lived process: it starts on demand, is shared by every OpenCode window, upgrades itself when a newer plugin connects, cleans up processes left by a crash, and exits when idle. That's why shells outlive OpenCode restarts, and why one session can look at a shell another session started.

Each shell's output feeds three views at once: a normalized log for the agent, an emulated screen for you, and a raw ring buffer so a panel opened late can catch up.

Packages

Package What it is Docs
opencode-cockpit The bundle: every bay, each switchable README
@opencode-cockpit/shell Bay 01 — background terminals README · docs
@opencode-cockpit/status Bay 02 — the statusline README · docs
@opencode-cockpit/daemon cockpitd, the shared process host README
@opencode-cockpit/client Typed, auto-spawning client README
@opencode-cockpit/protocol Wire contracts and schemas README

What is being worked on

Not a roadmap of promises — the next thing, and why it is next.

Review — a pull request, in the terminal. A turn ends and you read the whole diff at once, or you read none of it and hope. GitHub solved the reading part years ago: comment on a line, comment on a file, mark a file read, suggest the change instead of describing it — and nothing reaches the author until you press submit review. The same shape fits here, with the review going to the chat as one message instead of six interruptions.

OpenCode already exposes what it needs: session.diff returns each file's before and after in full, session.revert undoes a single message or part, and a plugin can write to the prompt. What is missing is the view and the keys.

Doctor. One command that checks your setup and says how to fix it.

Contributing

Issues and pull requests are welcome. CONTRIBUTING.md covers the architecture, the invariants worth knowing before changing anything, and how to run your working copy inside OpenCode.

bun install
bun run check        # lint, typecheck, tests (real PTYs, real daemon)
bun run pack:check   # pack, install the tarballs, run a shell through them
bun run smoke:tui    # drive a real OpenCode against the packed plugin

License

MIT

About

OpenCode superpowers: background shells the agent can start, wait on and drive, with a docked TUI panel

Topics

Resources

Contributing

Security policy

Stars

2 stars

Watchers

0 watching

Forks

Releases

Packages

Contributors

Languages