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

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-controlshooks/sidebar-controls.mjs 43 lines1const 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}
43types/index.d.ts 6 lines1declare module "claude-code" {
2 interface PluginState {
3 "sidebar-controls": { visible: boolean };
4 }
5}
6