SLOPSHOPPER

browser-pane-template

A starter mod for browser-pane: a tab with a page and a server module. Copy it, rename it, and build your own.

command
A shopper browsing a rack in a slop shop
README

browser-pane-template

A starter mod for browser-pane: a tab in browser-pane's shared browser window, with a page and a server module. /template <text> shows the text in the tab; the page reads the server module's data and keeps notes.

Start your own mod from it

  1. Copy this folder and give it your mod's name.
  2. Open Claude Code in the copy and ask it to build what you want, for example: "Rename this template to my-mod and turn the tab into a viewer for …". Its CLAUDE.md points Claude Code to integration.md, which explains how the mod and browser-pane fit together, and lists what to rename.

Install

From browser-pane's repository, inside Claude Code (browser-pane comes with it):

/plugin install browser-pane-template --marketplace sandipchitale/browser-pane

This folder is also a marketplace of its own: it lists this mod and browser-pane. So a copy made into a repository of its own installs in one line too:

/plugin install browser-pane-template --marketplace <owner>/<repo>

It needs what browser-pane needs: the Claude Code CLI, Node.js and Google Chrome.

Develop

claude plugin validate .
claude plugin test .          # the hooks
node --test tab-server/       # the server module

License

MIT

Source 1 files
hooks/register.ts 40 lines
1import type { Register } from 'claude-code'
2
3// The names a copy changes first (see integration.md, "Make it yours"): the tab's id and title here,
4// and the command, written as a literal where it is registered and matched (claude plugin validate
5// reads those literals to know the hook answers its own command). The tab id must be unique across
6// mods, so use your mod's name.
7const TAB = 'template'
8const TITLE = 'Template'
9
10export const register: Register = on => {
11  // Register the tab once per session. Cheap: browser-pane starts nothing until the first show.
12  on('session.start', async ($, e, next) => {
13    await $.browserPane.register({
14      id: TAB,
15      title: TITLE,
16      root: `${$.plugin.root}/tab`,
17      server: `${$.plugin.root}/tab-server/server.mjs`,
18      description: 'A starter tab: /template [text] shows the text here.',
19      pinned: true, // first in the Guide and the tab strip, until the person unpins it
20    })
21    // Data the tab's server module needs even when the tab is opened from the Guide, not by a show.
22    await $.browserPane.update({ tab: TAB, data: { session: await $.session.id() } })
23    await $.command.register({ name: 'template', description: `Show text in the ${TITLE} tab: /template [text]` })
24    return next(e)
25  })
26
27  on('command.run', { command: 'template' }, async ($, e) => {
28    const text = e.args.trim() || 'Hello from Claude Code'
29    const r = await $.browserPane.show({
30      tab: TAB,
31      select: text, // reaches the page: browserPane.onSelect
32      data: { session: await $.session.id(), shownAt: new Date().toISOString() }, // reaches the server module: update
33    })
34    if (r.isOpened) return { text: `template: "${text}" is in the ${TITLE} tab (${r.how}).` }
35    // No window here (the desktop app or an IDE has no $.process, or Node is missing): say so, or show
36    // the content another way, say in a Pane.
37    return { text: `template: no browser window (${r.reason}). You said: ${text}` }
38  })
39}
40