SLOPSHOPPER

system-instruction

Edit a persistent custom system instruction in a panel; it is given to the model at every session start, including /clear.

newpanecommandtoastprompt
A shopper browsing a rack in a slop shop
Preview · a replayed session in a sandbox
claude · ~/work/app · system-instruction
│ ┃ Instructions ✕ › fix the failing auth test and add an audit log call │ ┃ Initial instructions │ ┃ Nothing set yet. ⏺ Read(src/auth.ts) │ ┃ [ Edit ] ⎿ 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 │ │ › /instructions │ ⎿ system-instruction: System instruction panel opened. │ │ ────────────────────────────────────────────────────────────────────────────────────────────────────────────────────── › ? for shortcuts

Draws

Pane · Instructions
Initial instructions Nothing set yet. [ Edit ]
README

claude-plugins

Claude Code plugins by @josselinonduty.

PluginDescription
commit-changesBand above the prompt that splits uncommitted changes into logical sections and commits them one by one or automatically, with clean canonical messages.
secret-guardDetects secrets in prompts and conversation rows, moves them to the project's .env file and redacts them from the history.
prompt-librarySave past prompts to a searchable library; fuzzy search, then Copy or Apply to the prompt field.
system-instructionPanel (/instructions) to edit a persistent custom system instruction, given to the model at every session start, /clear included.

Install

/plugin marketplace add josselinonduty/claude-plugins
/plugin install commit-changes@josselinonduty-plugins
/plugin install secret-guard@josselinonduty-plugins
/plugin install prompt-library@josselinonduty-plugins
/plugin install system-instruction@josselinonduty-plugins
Source 2 files
hooks/register.tsx 104 lines
1import { atom, read, update } from 'claude-code'
2import type { Register } from 'claude-code'
3
4const PANE = 'system-instruction'
5const text = atom({ plugin: 'system-instruction', key: 'text' } as const, '')
6const isEditing = atom({ plugin: 'system-instruction', key: 'isEditing' } as const, false)
7
8async function load($: any): Promise<string> {
9  const saved = await $.store.get('text')
10
11  if (typeof saved === 'string') {
12    return saved
13  }
14
15  const legacy = await $.store.get('lines')
16
17  return Array.isArray(legacy) ? legacy.map(String).join('\n') : ''
18}
19
20export const register: Register = on => {
21  on('session.start', async ($, e, next) => {
22    const saved = await load($)
23    await update($, text, () => saved)
24    await $.command.register({
25      name: 'instructions',
26      description: 'Edit the custom system instruction given to the model at every session start',
27    })
28
29    return next(e)
30  })
31
32  on('command.run', { command: 'instructions' }, async $ => {
33    const saved = await load($)
34    await update($, text, () => saved)
35    await $.ui.open({ id: PANE, title: 'Instructions', focus: true })
36
37    return { text: 'System instruction panel opened.' }
38  })
39
40  on('prompt.compose', async ($, e, next) => {
41    const result = await next(e)
42    const instruction = (await load($)).trim()
43
44    if (!instruction) {
45      return result
46    }
47
48    return {
49      sections: [
50        ...result.sections,
51        { id: 'system-instruction:text', text: instruction, scope: 'session' as const },
52      ],
53    }
54  })
55
56  on('ui.render', { component: 'Pane', requestId: PANE }, async ($, e) => {
57    const { Box, Text, Button } = $.ui.resolve(e)
58    const current = await read($, text)
59    const editing = await read($, isEditing)
60
61    const edit = async () => {
62      const saved = await load($)
63      await $.prompt.fill({ text: saved, mode: 'replace' })
64      await update($, isEditing, () => true)
65    }
66
67    const save = async () => {
68      const box = await $.prompt.read()
69      const value = box.text.trim()
70      await $.store.set('text', value)
71      await update($, text, () => value)
72      await $.prompt.fill({ text: '', mode: 'replace' })
73      await update($, isEditing, () => false)
74      $.ui.toast('System instruction saved')
75    }
76
77    const cancel = async () => {
78      await $.prompt.fill({ text: '', mode: 'replace' })
79      await update($, isEditing, () => false)
80    }
81
82    return (
83      <Box flexDirection="column">
84        <Text bold>Initial instructions</Text>
85        {current ? <Text>{current}</Text> : <Text dimColor>Nothing set yet.</Text>}
86        {editing ? (
87          <Box flexDirection="column">
88            <Text dimColor>
89              Editing in the prompt box below (Shift+Enter for a new line). Do not press Enter to
90              send; press Save.
91            </Text>
92            <Box>
93              <Button key="save" label="Save" hotkey="s" onPress={save} />
94              <Button key="cancel" label="Cancel" hotkey="c" onPress={cancel} />
95            </Box>
96          </Box>
97        ) : (
98          <Button key="edit" label="Edit" hotkey="e" onPress={edit} />
99        )}
100      </Box>
101    )
102  })
103}
104
types/index.d.ts 6 lines
1declare module 'claude-code' {
2  interface PluginState {
3    'system-instruction': { text: string; isEditing: boolean }
4  }
5}
6