Pane that lists the installed mods with a switch each to turn them on or off

Claude Code mod 모음. 이 저장소 자체가 마켓플레이스(.claude-plugin/marketplace.json)라서 누구나 아래 방법으로 설치할 수 있다.
| Mod | 설명 |
|---|---|
context-bars | 컨텍스트 윈도우를 카테고리별 비례 막대 하나로 프롬프트 위에 표시 |
token-weather | 컨텍스트 윈도우 사용량을 날씨 아이콘·퍼센트·최근 턴 차트로 프롬프트 위에 표시 |
y-change | Claude가 코드를 수정할 때마다 diff와 변경 이유(처음 보는 언어의 문법 설명 포함)를 오른쪽 pane에 표시 (기본은 숨김, /y-change로 열기/닫기) |
enhance-prompt | 입력한 프롬프트를 AI가 더 잘 알아듣도록 [THE JOB]/[THE WHY]/[GUARDRAILS]/[DONE MEAN] 구조로 개선해 입력창 위에 보여주고(불명확한 부분은 먼저 입력창 위 질문으로 되묻고 답하면 반복, 최대 3개), [허용]하면 개선본을, [거부]하면 원본을 전송. enhance-prompt: ON/OFF 버튼(데스크탑 입력창 위)을 눌러, 또는 /enhance-prompt로 켜기/끄기 |
task-progress | Claude의 작업 목록(TodoWrite·TaskCreate/TaskUpdate) 진행률을 막대와 완료/전체, 진행 중인 항목 이름으로 프롬프트 위(스피너 아래)에 표시 |
mod-switch | 설치된 mod 목록을 오른쪽 pane에 토글 스위치와 함께 표시하고, 스위치를 누르면 해당 mod를 켜거나 끔 (기본은 숨김, /mod-switch로 열기/닫기) |
터미널의 Claude Code 세션 프롬프트에서 입력한다. 마켓플레이스 등록과 설치가 한 번에 된다.
/plugin install context-bars --marketplace nalpari/claude-mods
/plugin install token-weather --marketplace nalpari/claude-mods
/plugin install y-change --marketplace nalpari/claude-mods
/plugin install task-progress --marketplace nalpari/claude-mods
/plugin install enhance-prompt --marketplace nalpari/claude-mods
/plugin install mod-switch --marketplace nalpari/claude-mods
처음이면 Add marketplace? 에 y 로 답하고 scope(user 권장)를 고르면 Installed <mod>. Plugin is now active. 가 뜬다. 재시작이나 리로드 없이 바로 적용되고, user scope 는 이후 세션에도 유지된다. 마켓플레이스를 이미 추가했다면 확인 질문은 건너뛴다.
마켓플레이스를 먼저 등록하고 나중에 골라 설치해도 된다.
/plugin marketplace add nalpari/claude-mods
/plugin install context-bars@claude-mods
셸에서는 claude plugin marketplace add nalpari/claude-mods 와 claude plugin install context-bars@claude-mods --scope user 로 같은 일을 한다.
claude plugin marketplace update claude-mods # 마켓플레이스 최신화
claude plugin update context-bars@claude-mods # mod 업데이트
claude plugin list # 설치 확인
claude plugin uninstall context-bars # 제거
git clone https://github.com/nalpari/claude-mods.git
cd claude-mods
# 이번 세션에서만 시험
claude --plugin-dir ./context-bars
# 로컬 마켓플레이스로 설치
claude plugin marketplace add ./
claude plugin install context-bars@claude-mods --scope user
token-weather/README.md 기준)./plugin install 은 터미널 전용이다. 데스크톱 앱 Code 탭에서는 쓸 수 없지만, 터미널에서 user scope 로 설치하면 로컬 세션에서도 로드된다.hooks/register.tsx 91 lines1import { atom, read, update } from 'claude-code'
2import type { EngineInterface, Register } from 'claude-code'
3
4import type { Mod } from '../types'
5
6const PANE = 'mod-switch'
7const TITLE = 'mods'
8
9const mods = atom({ plugin: 'mod-switch', key: 'mods' } as const, [])
10
11type Installed = { id: string; scope: string; enabled: boolean; installPath: string; projectPath?: string }
12
13// a mod is a plugin whose hooks.json names a hooks module; the others (skills, MCP servers) are not this pane's to switch
14const isMod = async ($: EngineInterface, dir: string) => {
15 try {
16 return 'modules' in JSON.parse(await $.fs.read(`${dir}/hooks/hooks.json`))
17 } catch {
18 return false
19 }
20}
21
22// the mods installed for this session (user scope, or this project's), on or off
23const load = async ($: EngineInterface) => {
24 const root = await $.session.root()
25 const { stdout } = await $.process.run(['claude', 'plugin', 'list', '--json'])
26 const list: Mod[] = []
27 for (const p of JSON.parse(stdout) as Installed[]) {
28 if ((p.projectPath ?? root) === root && await isMod($, p.installPath)) list.push({ id: p.id, scope: p.scope, enabled: p.enabled })
29 }
30 await update($, mods, () => list)
31}
32
33// the CLI writes the setting; /reload-plugins makes the running session follow it. The switch is flipped before the reload, which reloads this module too
34const flip = async ($: EngineInterface, id: string, scope: string) => {
35 const same = (m: Mod) => m.id === id && m.scope === scope
36 const mod = (await read($, mods)).find(same)
37 if (mod === undefined) return
38
39 const ran = await $.process.run(['claude', 'plugin', mod.enabled ? 'disable' : 'enable', id, '--scope', scope])
40 if (ran.exitCode !== 0) {
41 $.ui.toast(`mod-switch: ${id} 전환 실패 (${(ran.stderr || ran.stdout).trim()})`)
42
43 return
44 }
45 await update($, mods, list => list.map(m => (same(m) ? { ...m, enabled: !mod.enabled } : m)))
46 await $.command.run({ command: 'reload-plugins' }).catch(() => $.ui.toast('mod-switch: /reload-plugins 를 직접 실행하면 적용됩니다'))
47}
48
49export const register: Register = on => {
50 on('session.start', async ($, e, next) => {
51 await $.command.register({ name: 'mod-switch', description: '설치된 mod 목록 pane 열기/닫기' })
52
53 return next(e)
54 })
55
56 // a toggle; a pane waiting undrawn (opened unasked in a narrow terminal) is opened, not closed
57 on('command.run', { command: 'mod-switch' }, async $ => {
58 const isShown = (await $.ui.panes()).some(pane => pane.id === PANE && pane.isPlaced)
59 if (isShown) {
60 await $.ui.close({ id: PANE })
61
62 return { text: 'mod 목록 pane을 닫았습니다.' }
63 }
64 // read afresh at each opening: /plugin may have installed or switched mods since
65 await load($)
66 await $.ui.open({ id: PANE, title: TITLE })
67
68 return { text: 'mod 목록 pane을 열었습니다.' }
69 })
70
71 on('ui.render', { component: 'Pane', requestId: PANE }, async ($, e) => {
72 const { Box, Button, Text } = $.ui.resolve(e)
73 const list = await read($, mods)
74
75 return (
76 <Box flexDirection="column">
77 {list.length === 0 && <Text dimColor>설치된 mod가 없습니다.</Text>}
78 {list.map(m => (
79 <Box marginBottom={1}>
80 {/* switching itself off would take this pane, and the way back, with it */}
81 {m.id.split('@')[0] === $.plugin.name
82 ? <Text dimColor>{' - '}</Text>
83 : <Button key={`${m.id}/${m.scope}`} label={m.enabled ? '● ON' : '○ OFF'} variant={m.enabled ? 'primary' : 'secondary'} onPress={() => flip($, m.id, m.scope)} />}
84 <Text wrap="truncate" dimColor={!m.enabled}>{` ${m.id}`}</Text>
85 </Box>
86 ))}
87 </Box>
88 )
89 })
90}
91types/index.d.ts 9 lines1// one installed mod: `id` is `<name>@<marketplace>`, `scope` where it was installed (user, project, local)
2export type Mod = { id: string; scope: string; enabled: boolean }
3
4declare module 'claude-code' {
5 interface PluginState {
6 'mod-switch': { mods: Mod[] }
7 }
8}
9