SLOPSHOPPER

copy-session-id

Adds a Copy Session ID button to the band above the prompt

newbandtoast
v1.0.0MITupdated 2026-10-15aquarius-wing/copy-session-id
A shopper browsing a rack in a slop shop
Preview · a replayed session in a sandbox
claude · ~/work/app · copy-session-id
› fix the failing auth test and add an audit log call ⏺ 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 ⟨Claude Code's own drawing⟩ Copy Session ID ────────────────────────────────────────────────────────────────────────────────────────────────────────────────────── › ? for shortcuts

Draws

Band
⟨Claude Code's own drawing⟩ Copy Session ID
README

Copy Session ID

A Claude Code mod that adds a Copy Session ID button to the band above the prompt. One click copies the current session's ID to the clipboard, the same ID that claude --resume <id> takes, and shows it in a toast.

The Copy Session ID button at the right end of the band above the prompt, next to another mod's line

Install

In a Claude Code session:

/plugin install copy-session-id --marketplace aquarius-wing/copy-session-id

Or from your shell:

claude plugin marketplace add aquarius-wing/copy-session-id
claude plugin install copy-session-id@copy-session-id --scope user

If a session is already open, run /reload-plugins in it.

Requirements: Claude Code 2.1.287 or later, where mods load by default. The button shows in the terminal and in the Code tab of the Desktop app. Tested in the Desktop app's Code tab with Claude Code 2.1.295.

How it works

The mod is one hook, on ui.render for the AbovePrompt site:

  • It calls next(e) first and keeps what the mods after it draw, then adds the button beside that.
  • While a survey holds the band (e.props.hasSurvey), it passes the band on untouched.
  • Pressing the button reads $.session.id(), writes it to the clipboard of the app you pressed it in with $.ui.copy, and shows it with $.ui.toast. If the clipboard write fails, the toast still shows the ID, with the reason.

It reads no files, starts no processes and makes no network requests. claude plugin validate lists everything it calls:

hooks: ui.render{component=AbovePrompt}
calls: $.session.id, $.ui.copy, $.ui.resolve, $.ui.toast

Sharing the band with other mods

The band above the prompt is one site that every mod drawing there shares. Mods run as a chain, and the first one decides what the band shows. This mod keeps whatever the mods after it draw, so it never hides them. A mod that runs before it and returns its own line without calling next(e) hides this button, along with every other band mod after it.

If the button doesn't show while another band mod is installed:

  • Ask that mod to compose with next(e). The mods docs describe this: put the result of await next(e) in your own tree to keep what the others draw. For example, the Token Weather sample mod hides other band mods; anthropics/claude-code-playground#7 changes that.
  • Run this mod first. On a machine with no managed settings, and when you aren't signed in with a Team or Enterprise plan, you can list plugin ids in prependPlugins in ~/.claude/settings.json to run them before the other mods you install (see the mods admin docs):
  {
    "prependPlugins": ["copy-session-id@copy-session-id"]
  }

Then run /reload-plugins in each open session. To check it took, start claude --debug-file debug.log and look for hooks module copy-session-id@copy-session-id loaded (..., tier prepend). Tested with Claude Code 2.1.295 on a personal Max plan.

Development

claude plugin validate .
claude plugin test .

The tests in hooks/register.test.ts mount the band on the terminal and Desktop surfaces with a stand-in for another band mod, press the button, and check what reaches the clipboard and the toast.

License

MIT

Source 1 files
hooks/register.tsx 35 lines
1import type { EngineInterface, Register, RenderSurface } from 'claude-code'
2
3async function copyId($: EngineInterface, surface: RenderSurface) {
4  const id = await $.session.id()
5  const copied = await $.ui.copy({ text: id, surface })
6  $.ui.toast(copied.isCopied ? `Copied session ID: ${id}` : `Session ID: ${id} (not copied: ${copied.reason})`)
7}
8
9export const register: Register = on => {
10  // The band above the prompt is shared by every mod that draws there. Keep what
11  // the mods after this one draw, then add the button beside it.
12  on('ui.render', { component: 'AbovePrompt' }, async ($, e, next) => {
13    // A survey holds the band: leave it alone.
14    if (e.props.hasSurvey) {
15      return next(e)
16    }
17
18    const { Box, Button } = $.ui.resolve(e)
19    const theirs = await next(e)
20
21    return (
22      <Box flexDirection="row" columnGap={2} alignItems="center">
23        {theirs}
24        <Button
25          key="copy-session-id-band"
26          label="Copy Session ID"
27          plain
28          dimColor
29          onPress={press => copyId($, press.surface)}
30        />
31      </Box>
32    )
33  })
34}
35