SLOPSHOPPER

sidebar-controls

Move Compact tools and Live thinking controls into a top-right sidebar.

newpanebandcommand
v0.1.0no licenseupdated 2026-10-02AJclemendor/my-mods/plugins/sidebar-controls
A shopper browsing a rack in a slop shop
Preview · a replayed session in a sandbox
claude · ~/work/app · sidebar-controls
│ ┃ sidebar-controls ✕ › fix the failing auth test and add an audit log call │ ┃ ⟨Claude Code's own drawing⟩ │ ⏺ Read(src/auth.ts) │ ⎿ Read 6 lines │ ⏺ Update(src/auth.ts) │ ⎿ Added 2 lines, removed 1 line │ ⏺ Bash(bun test) │ ⎿ 3 pass, 1 fail │ │ ● Done. refresh now rejects expired claims and logs an audit event. │ │ ✻ Worked for 42s · done 4:20 PM │ │ › /sidebar-controls │ ⎿ sidebar-controls: Mod controls returned above the prompt. │ │ ────────────────────────────────────────────────────────────────────────────────────────────────────────────────────── › ? for shortcuts

Draws

Pane · sidebar-controls
⟨Claude Code's own drawing⟩
README

Sidebar controls

Move the Compact tools and Live thinking ON/OFF buttons into a sidebar at the top right of Claude Code. This plugin changes where the controls appear; thinking and tool output remain inline in the conversation.

/plugin marketplace add AJclemendor/my-mods
/plugin install sidebar-controls@my-mods
/reload-plugins

Installing this plugin also installs compatible versions of compact-tools and live-thinking. Update older copies if Claude reports a dependency version mismatch.

The sidebar requests 28 columns and opens without taking keyboard focus. Click either button to toggle its mod. The existing /compact-tools and /live-thinking commands still work.

  • /sidebar-controls on: open the sidebar.
  • /sidebar-controls off: close it and return the buttons above the prompt.
  • /sidebar-controls: toggle it open or closed.

The sidebar uses a full-height column, not a floating corner overlay. Claude normally opens it automatically from 144 columns in fullscreen mode. Below that width it can wait for space, leaving the original buttons above the prompt. An explicit /sidebar-controls on opens it at any width: fullscreen mode docks it from 110 columns; narrower terminals and classic mode place the pane above the prompt. Claude remembers manually opened panes and may subsequently open them automatically from 110 columns. Resizing the pane can override the requested width.

Closing the pane with its close button also restores the original controls. Disabling or uninstalling this plugin restores their normal placement after reload; the other two mods continue working.

Tested with Claude Code 2.1.287. The runtime tests cover open/close commands and visibility; terminal replays verify top-right placement, mouse toggling, and returning controls to the prompt when closed.

claude plugin validate ./plugins/sidebar-controls --strict
claude plugin test ./plugins/sidebar-controls
Source 2 files
hooks/sidebar-controls.mjs 43 lines
1const pane = { id: "sidebar-controls", title: "Mod controls", columns: 28, rows: 3 };
2
3export function register(on) {
4  // Compute visibility from the host instead of storing a flag that could outlive this plugin.
5  on("state.get", { plugin: "sidebar-controls", key: "visible" }, async ($) => {
6    const visible = (await $.ui.panes()).some(item => item.id === pane.id && item.isPlaced);
7    return { value: { value: visible, version: 0 } };
8  });
9
10  on("session.start", async ($, e, next) => {
11    const result = await next(e);
12    await $.command.register({ name: "sidebar-controls", description: "Open or close the mod controls sidebar", argumentHint: "[on|off]", immediate: true });
13    await $.ui.open(pane);
14    $.ui.invalidate("ui.render");
15    return result;
16  });
17
18  on("command.run", { command: "sidebar-controls" }, async ($, e) => {
19    const arg = e.args.trim().toLowerCase();
20    if (arg && arg !== "on" && arg !== "off") return { text: "Usage: /sidebar-controls [on|off]" };
21    const isOpen = (await $.ui.panes()).some(item => item.id === pane.id);
22    const open = arg ? arg === "on" : !isOpen;
23    if (open) await $.ui.open(pane);
24    else await $.ui.close({ id: pane.id });
25    $.ui.invalidate("ui.render");
26    return { text: open ? "Mod controls sidebar open." : "Mod controls returned above the prompt." };
27  });
28
29  on("ui.close", { id: "sidebar-controls" }, async ($, e, next) => {
30    const result = await next(e);
31    $.ui.invalidate("ui.render");
32    return result;
33  });
34
35  on("ui.render", { component: "Pane", requestId: "sidebar-controls" }, async ($, e, next) => {
36    const original = await next(e);
37    return $.ui.resolve(e).Box({ flexDirection: "column", children: [original] });
38  });
39
40  // Include the original control band when a pane open/close invalidates this mod's sites.
41  on("ui.render", { component: "AbovePrompt" }, ($, e, next) => next(e));
42}
43
types/index.d.ts 6 lines
1declare module "claude-code" {
2  interface PluginState {
3    "sidebar-controls": { visible: boolean };
4  }
5}
6