Conversation
Shared keys (enabled, keybinds, sidebar, sidebarRows, hideWhenEmpty) spelled once, defaults per bay, type-checked with a notice. The top-level sidebar list is the only order (default status, subagents, shell, trail, trust at 110-150, between OpenCode 1's Context and MCP). Old pre-0.9 names are detected, not read: each is a notice saying to run /cockpit-setup. Unknown sidebar entries name the closest bay. Never throws. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Presence over silence: the muted row sits in the first item's slot, so empty to one item keeps the height; hideWhenEmpty draws nothing. EmptyRow element, and a preview of empty blocks and settings notices. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
v1 tool.execute.after with MCP output read from content[]; v2
tool.hook("execute.after") from content[].text, skipping Code Mode's outer
execute call. A listener's failure is logged and never reaches the call.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Doctor prints every settings notice as a fix line, and a file it calls fine is one the bays can use. Trust takes its section and order from the loader. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
…ent reads A new package, @opencode-cockpit/trail, version-agnostic and with no OpenCode adapter yet: an append-only events.ndjson per project outside the repo (Trust's scheme: torn last line, several writers, reconcile on load), one record per thing merged by url else ref, deleted conversations marked, links cleaned of secrets, the system read from the host, grouping by what a record is for, and the tool descriptions, guidance and per-request lines. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Pure rows on the design system, drawn by `bun packages/trail/src/cli/preview.ts` for every sample (empty, one, busy, long, a project with a deleted conversation) at any width: the sidebar's heading, none-yet slot, ↗ and + N more; /trail's two tabs, found-not-recorded rows, search, a window that keeps the cursor in view, and the agreed footer with esc last. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
…ened Binary detection by git's rule (a NUL in the first 8000 bytes); both sides read as bytes (cat-file blob, never through UTF-8), with a 32 MB binary cap beside the 400 KB text cap, so a screenshot is in the review instead of skipped or shown as U+FFFD. - Header readers for PNG/APNG, JPEG, GIF, WebP (VP8/VP8L/VP8X), BMP: `PNG 2880×1800 · 807 KB → 789 KB`; other binaries `binary · 12.3 KB → 14.0 KB`. - PNG and GIF decoded in slices off the draw path (async inflate, then generators that yield every ~256K pixels); pixel diff for same-size pairs with % changed, bounding box and a mask. - Half-block preview, before and after side by side, changes lit; drawn through the row pool with a new exact `background` on Run. Thumbs and diffs cached by content hash. - `o` opens both versions in the system viewer: old bytes into a temp file, Bun.which on the spawn's PATH, detached spawn with its error reported in the footer; temp dir cleaned on close. - `[?] Keys` screen; `ctrl+p` (the host palette's key) makes the review step aside. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
…write The trim only removed what was identical at the very ends, so edits at lines 40 and 2,900 left a 2,860-line middle past the alignment table's cap, drawn as every line out and back in. A stretch past the cap is now split on lines unique to both sides (patience diff's anchors, longest run in order) and each piece aligned on its own; only a stretch with no such line is drawn as a rewrite. Below the cap nothing changes. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
… shows Shrink and compare yield twice as often: the longest event-loop stall analysing a 2880×1800 pair went from 13 ms to 9 ms (the pair blocked 114–124 ms inside OpenCode before slicing). README: `o`, `?`, ctrl+p while the review is open, and the images section. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
…eps its fix Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
…, and /status-setup
- Settings through baySettings("status"): the `status` section only. `statusline`, root keys,
a bay-level `maxRows` and `sidebarOrder` are old names — `!` rows, not read. `sidebarRows` is
the column's cap; `sidebar: false` means the bottom; order from the top-level list.
- The `sidebar` preset is the budget table, and the default surface is the sidebar. Its rows are
built-ins now: title, in, out, cache, write, sep, spend, avail, git, plus `context` style
`solid` and `tokens` style `row`. spend/avail read a proxy's file and draw nothing without
one; a hairline draws only between two rows.
- examples/sidebar.ts, sidebar-full.ts, sidebar-budget.ts removed; a config pointing at one, or
naming a preset that does not exist, gets a `!` row rather than a blank column.
- Status draws cockpitNotices (unreadable file, unknown top-level name, unknown sidebar entry)
and its own, wrapped by warnRows to the measured sidebar width.
- /statusline is /status-setup; /statusline stays one release as a twin that toasts the new
name and still briefs the agent. The brief speaks of the `status` section.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
…eCheck is an old name Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
…ow fewer with one shell Shell reads through baySettings: the file's shell section and the plugin entry, JSONC, the order from the top-level sidebar list. Root keys and ui.* are no longer read; each is a ! row in the Shells block. ui.historyMinutes is hideFinishedAfterMinutes. With no shells the block draws its heading and none yet unless hideWhenEmpty. The fold toggle shows only while folding hides something, and an expansion the list outgrew folds itself back (and is no longer kept across restarts). Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Both halves read the subagents section through baySettings (sidebarRows, hideWhenEmpty, hideFinishedAfterMinutes, hideNestedAfterSeconds, guidance, keybinds); old names are ! rows in the block. The block is present when empty. Every row names its agent, muted, general too; the agent shortens before the title, and a run with no title is named by its task's first words. The pane has a [?] Keys screen like Review's and Trust's. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
variant and source are read through baySettings from the files and the plugin entry; an unknown value is the default and a notice, said once as a toast since Review has no sidebar block. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Seen on OpenCode 1 with hideWhenEmpty: the block's empty box still got the host's gap between blocks, so the sidebar had a blank row for nothing. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
…till shows the fix Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
…ty net; the sidebar, /trail and /link The agent half (dualServer): the two tools, GUIDANCE on every request with the conversation's produced line and the links seen in what it ran, rebuilt from events.ndjson every time; subagents' records go to the root session and name the subagent; each record keeps the conversation's title. The interface half: the sidebar block at the settings' order (client emptyBlock, warnRows for notices), rows that open the page or /trail, /trail on both versions, /link, and the conversation's stored history read for finds, offered and never added. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
…st end in trail_add Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
…ols, settings, team conventions Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
…turn is about the PR Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
…e settings, the old names and OpenCode's own blocks Registered by the first Cockpit entry in a window (dualTui), listing the bays that claimed themselves there; defaults come from what each bay hands baySettings. From home on OpenCode 2 it opens a conversation for the brief; while the agent is busy it queues rather than steers. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
…er's rule Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
…it opens a conversation, behind a reply it queues Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
…each palette step waits for the last one's toast to go Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
…ong; Trail's time says when; Trail measured two of three Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
…ist, its history scan and `a` are gone; the agent's reminder stays; /link is taught as /link, then the link The per-request "seen in output — record it if you created or changed it" line, fed by toolAfter on shell and MCP output, is kept: the agent decides. /link opens its prompt; the one-line `/link <url> note` form was OpenCode sending unknown slash text to the model, so no doc teaches it. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
…ent ctrl+x k — the same on OpenCode 1 and 2, and none of them OpenCode's own OpenCode 2 binds <leader>w (close tab) and <leader>i (image attachments), and both versions bind <leader>r (redo). A test holds every Cockpit default unique, bound by its bay as the catalog says, and clear of OpenCode's default leader letters. keybinds restores the old keys. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
… and build read whole One width per block — the longest agent shown, cut with … past eight — and no column when it would leave the titles fewer than six cells. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
…lder Cockpit The agent side records which install it loaded (agents/<pid>.json in Cockpit's home: version and when its package.json was written, read once per process). A window reads the record of the pid in OpenCode's service.json and, when the service's install is older, shows one toast: "Cockpit was updated — OpenCode's background service still runs the old one. Run: opencode service restart", with both versions when they differ. Never restarts it; says nothing when it cannot tell (no service, no record, a record from another pid). Doctor reads the same record instead of comparing the service's start time with the install's. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
…ne" means no ! row The audit: after /cockpit-setup the agent said "Notices now: none", and after a restart Status still warned that override "gti" matches no segment and Trust that threshold "3" is a string. cockpit_settings and doctor saw only the loader's notices. Now each bay's come from the bay (client checks.ts): its keys' kinds through the loader with its defaults, and a bay's own check where it has one — Status offers statusNotices (presets, surfaces, overrides, each naming the file its key is in) from its agent side, and the bundle's doctor loads it too, guarded. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
…ded Status and counts what is uncommitted Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
…l Trail and Subagents rows, Review and Updater settings, eight Shell tools Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
…ase, keys, OpenCode's own blocks per version, doctor's Service check, Review images, recounted tools Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
…mples follow the release Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
…ient/brief
setup.ts (925 lines, eight concerns) becomes the ./setup entry that gathers
setup/{names,previews,installs,host-blocks,report,text,tune,server,palette}.ts;
every name it exported is still exported. briefAgent, a general "send this line
to the agent" helper, is client/src/brief.ts with its own ./brief subpath, and
Status's interface imports it from there.
host.ts imports only setup/palette.ts and server.ts only setup/server.ts, so an
interface entry no longer loads the settings report, AGENTS.md writes and git
scans of the agent side. No behaviour change: every preview renders the same.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
updater/src/core/jsonc.ts was a byte-for-byte copy of client/src/jsonc.ts. Client exports it as @opencode-cockpit/client/jsonc; the Updater's config reader and doctor import it, updater/core still re-exports parseJsonc, and its tests move to client with the parser. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
…le and doctor client/settings' BAYS is the list: the bundle's FEATURES is it, and doctor's copy is gone. Doctor's SERVER_BAYS stays its own (which bays it checks have an agent half) but is typed with client's Bay, and a test checks each publishes ./server. client/src/plugin-entries.ts (./plugin-entries) reads Cockpit's entries in OpenCode's plugin lists for /cockpit-setup and doctor alike: pluginEntries replaces doctor's specsIn, bayOf moves from doctor, and baysOfEntry is written on bayOf. Same answers as before for every entry. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
… no copy
Shell, Review, Subagents, Trail and Trust each kept their own DEFAULT_KEYS beside
the catalog's, and a test compared the two by reading the bays' source. Each now
reads defaultKeys("<bay>") from @opencode-cockpit/client/catalog; why each key is
free on both OpenCodes moves to the catalog with the keys, and the test now checks
every bay reads the catalog and holds no copy. Same keys as before.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
…ockpitNotices, lastStep, refusedText No production caller of any of them (checked with rg across packages and scripts): client/sidebar's deprecated sidebarOrder and sidebarList (bays take order from baySettings; their tests go with them, settings.test covers the order), Status's loadStatusConfig, Status's private copy of cockpitNotices (it uses client/settings' now), Trail's lastStep and refusedText, and the key Trail's addByYou returned to a caller that never read it. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
tui/index.tsx (599 lines, one closure) keeps the wiring: settings, the conversation on screen, the palette's commands, the sidebar slot and the tick. paint.ts paints both surfaces into their signals (draw folds a turn's changes into one paint), actions.ts reads and appends the trail file and does what a person asks (open, copy, /link, copy as markdown), and dialog.tsx is /trail — opening it, its keys, the search intercept. What they share is one Live object (state, root, trouble, inSidebar, titles) and the dialog's state. Same calls in the same order; every preview renders the same. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Recognising the pre-0.9 spellings (statusline, Shell's root keys and ui group, Status's root keys, <bay>.sidebarOrder, the renamed time keys) is one file now, so removing it in 0.10 is deleting that file and its two calls in settings.ts (oldInSection in a bay's section, oldAtTop at a file's top level). OLD_NAMES is still exported from client/settings. Same notices, same order. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
…ages Review (core/viewer.ts) and Trail (core/open.ts) each decided which program opens a thing, and had drifted. client/src/opener.ts (./opener) is the one now, with its argv unit-tested per platform; Trail's core/open.ts is gone (unreleased). Deliberate changes, as the review asked: - Review now tries macOS's /usr/bin/open before PATH and honours COCKPIT_OPENER, as Trail did. A live check stubs Review's `o` with COCKPIT_OPENER now: a PATH shim is passed over on macOS. - Windows: start's title is an empty argument (Review's form); Trail passed '""', which Node quotes as \"\" and cmd does not read as an empty title. & is escaped as ^& only where Node leaves the argument unquoted (no space, tab or quote). - Windows falls back to a bare `cmd` when PATH has none (Trail's), so Review no longer says "cmd is not on PATH" there. Trail still hands over only http(s); its openUrl is unchanged otherwise. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
…bay without its dist build empties every dist/ before compiling; v1 and v2 smoke in parallel packed Trust in that window, so OpenCode 2 said "1 plugin failed" and Trust's palette commands were missing. The harness, not the product: every lone run passed. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
…le characters OpenCode 2 refuses packages/opencode from the checkout (a second OpenTUI and Solid), so a take on it packs this checkout and installs it under the take's own directory, the way the smoke does, and starts a private server instead of attaching to the background service. Plugins go under `plugins` in opencode.json and cli.json there. Each PTY chunk was decoded on its own, so a character split across two chunks recorded as a pair of U+FFFD — a spinner frame, a `›`. One streaming decoder now. The shells' daemon the take started is stopped with it. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
…rail leads back to it tapes/trail.ts on OpenCode 2 with the free Zen model: a ticket's fix, a commit, gh pr create (a stub on PATH), and trail_add without the prompt mentioning Trail; then /trail, a second conversation answering from trail_list, All conversations and g. media/trail.png is now a still from the take rather than the preview. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
…plays the cast, the still is the /trail dialog Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Codestz
marked this pull request as ready for review
October 4, 2026 04:50
This was referenced Oct 4, 2026
Closed
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
0.9.0 — Trail, one settings shape, setup as skills. Merged with a merge commit to keep the history.
What 0.9 is
Trail — a new bay (
@opencode-cockpit/trail). The agent records what a conversation creates or changes outside the repo — PRs, tickets, doc pages, deploys — withtrail_add; Cockpit keeps, groups (by ticket, withfor) and shows it: a sidebar block,/trail(this conversation / all conversations in the project, search, open, go to the conversation, copy, markdown),/linkto add one by hand, andtrail_listso any conversation can answer "what did we ship for COM-1736?". Guidance in the system prompt plus a one-line reminder when a command's output holds a PR link not yet recorded; the agent decides.One settings shape. One JSONC loader (comments and trailing commas no longer drop the file), one section per bay, the same shared keys everywhere (
enabled,keybinds,sidebar,sidebarRows,hideWhenEmpty), onesidebarorder list. Old names are not read: each shows a!notice pointing to/cockpit-setup.Setup as skills.
/cockpit-setupand/status-setupload shipped skills;cockpit_settingsreads the live state (bays, values and where they came from, notices, OpenCode's own sidebar blocks per version); an opt-in second phase tunes Cockpit to the project and writes one marked## Cockpit conventionssection in AGENTS.md (cockpit_conventions).Status. The sidebar table is the default (
spend/avail/gitbuilt in);overridechanges a row by name without copying the preset;gitcounts uncommitted work;diagnosticsin the table; preview reads a config on stdin.Fixes and the rest. #34 (
diagnosticsflagged every MCP server on OpenCode 2); Review renders image diffs (metadata, pixel diff, half-block preview,oopens both); blocks saynone yetwhen empty; subagent rows line up and name their agent; Shell's "show fewer"; OpenCode 2's background service keeps old plugin code —dev:installrestarts it, doctor and update say so; per-bay guidance tightened and measured with real agent turns (AGENT=1smoke).Full list: CHANGELOG.md, Unreleased.
Also in
/linkadds by hand, a reminder line nudges.ctrl+x d/j/k), the same on both versions.client/src/setup.ts925 → 51 lines +setup/; Trail's interface split; one JSONC parser, one bay list, one link opener), checked against a byte-for-byte baseline of 60 preview renders.Checks so far
bun run check(2170 pass),pack:check(Trail included),AGENT=1 bun run smoke:tuion OpenCode 1.18.32 and 2.0.18 (behaviour measured with real agent turns), CI on macOS and Linux, and a live check by the maintainer on the final install.🤖 Generated with Claude Code