SLOPSHOPPER

educa-lateral

Painel lateral (~50% do terminal, aberto sob comando /educar) com textos curtos que explicam as tecnologias escolhidas enquanto algo é desenvolvido.

newpaneguardcommandtool
v0.1.1no licenseupdated 2026-10-21osceiatech/skills-osceia/educa-lateral
A shopper browsing a rack in a slop shop
Preview · a replayed session in a sandbox
claude · ~/work/app · educa-lateral
│ ┃ Aprendendo ✕ › fix the failing auth test and add an audit log call │ ┃ As tecnologias escolhidas aparecerão aqui, │ ┃ com uma explicação curta de cada uma. ⏺ 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 │ │ › /educar │ ⎿ educa-lateral: Painel aberto. │ │ ────────────────────────────────────────────────────────────────────────────────────────────────────────────────────── › ? for shortcuts

Draws

Pane · Aprendendo
As tecnologias escolhidas aparecerão aqui, com uma explicação curta de cada uma.
README

educa-lateral

Mod do Claude Code: um painel à direita (largura fixa, pensada para ~50% de um terminal comum — ajuste LARGURA_PAINEL em hooks/register.tsx se destoar do seu terminal) que mostra textos curtos explicando as tecnologias que estão sendo escolhidas enquanto algo é desenvolvido.

  • A IA chama a ferramenta explicar (titulo, texto, tecnologia?) antes de decidir ou usar uma tecnologia.
  • /educar abre ou fecha o painel; /educar limpar apaga as notas.
  • O mod não injeta instrução no system prompt (não existe esse hook na API de mods hoje). O aviso para a IA chamar explicar vive na própria descrição da ferramenta; para reforçar em todos os projetos, uma instrução global complementar pode ser adicionada ao ~/.claude/CLAUDE.md do usuário.

Instalar

/plugin marketplace add osceiatech/skills-osceia
/plugin install educa-lateral --marketplace osceiatech/skills-osceia

Para testar a partir da pasta, sem instalar:

claude --plugin-dir ~/.agents/skills/educa-lateral

Verificar

claude plugin validate .

(claude plugin test . não existe nesta versão do CLI — tests/educa.test.ts usa uma API de teste de mods que não pôde ser confirmada como real; trate-a como não verificada até alguém confirmar o comando/API corretos.)

Tipos: tsc -p com o tsconfig.json da pasta, depois que o Claude Code carregar o mod uma vez (ele grava .claude-plugin/types/).

Source 2 files
hooks/register.tsx 94 lines
1import type { Register } from 'claude-code'
2
3import type { Nota } from '../types'
4
5const PANE = 'educa'
6const TOOL = 'explicar'
7// Largura fixa aproximando ~50% de um terminal comum; sem acesso à largura real no
8// momento da abertura, ajuste este valor se o painel ficar maior/menor que o esperado.
9const LARGURA_PAINEL = 60
10
11export const register: Register = on => {
12  let notas: Nota[] = []
13  let painelAberto = false
14  let proximoId = 1
15
16  on('session.start', async ($, e, next) => {
17    await $.tool.register({
18      name: 'explicar',
19      isDeferred: false,
20      description:
21        'Mostra no painel lateral um texto curto e didático (pt-BR) que explica uma tecnologia ou decisão técnica que está sendo usada agora. Chame esta ferramenta sempre que escolher ou usar uma tecnologia, biblioteca, padrão ou técnica relevante, antes de agir. Escreva em português, em 2 a 4 frases curtas: o que é, por que foi escolhida aqui e o que ela evita ou resolve. Uma nota por decisão; não repita o que já explicou. Nunca inclua dado pessoal, segredo ou conteúdo de registro nas notas.',
22      inputSchema: {
23        type: 'object',
24        properties: {
25          titulo: { type: 'string', description: 'Nome curto do assunto, ex.: "TanStack Query".' },
26          texto: { type: 'string', description: '2 a 4 frases: o que é, por que aqui, o que resolve.' },
27          tecnologia: { type: 'string', description: 'Categoria opcional, ex.: "estado de servidor".' },
28        },
29        required: ['titulo', 'texto'],
30      },
31    })
32    await $.command.register({
33      name: 'educar',
34      description: 'Abre ou fecha o painel lateral que explica as tecnologias em uso (/educar limpar apaga as notas)',
35    })
36
37    return next(e)
38  })
39
40  on('tool.call', { tool: TOOL }, async ($, e) => {
41    const entrada = e as unknown as { titulo?: string; texto?: string; tecnologia?: string }
42    const titulo = String(entrada.titulo ?? '').slice(0, 80)
43    const texto = String(entrada.texto ?? '').slice(0, 600)
44
45    if (titulo === '' || texto === '') {
46      return { deny: 'educa-lateral: informe titulo e texto.' }
47    }
48    notas = [...notas, { id: proximoId++, titulo, texto, tecnologia: entrada.tecnologia?.slice(0, 40) }].slice(-50)
49
50    return { result: 'Nota exibida no painel lateral.' }
51  })
52
53  on('command.run', { command: 'educar' }, async ($, e) => {
54    const args = String((e as unknown as { args?: string }).args ?? '').trim()
55
56    if (args === 'limpar') {
57      notas = []
58
59      return { text: 'Notas apagadas.' }
60    }
61    if (painelAberto) {
62      await $.ui.close({ id: PANE })
63      painelAberto = false
64
65      return { text: 'Painel fechado.' }
66    }
67    await $.ui.open({ id: PANE, title: 'Aprendendo', columns: LARGURA_PAINEL })
68    painelAberto = true
69
70    return { text: 'Painel aberto.' }
71  })
72
73  on('ui.render', { component: 'Pane', requestId: PANE }, async ($, e) => {
74    const { Box, Text } = $.ui.resolve(e)
75    const espaco = Math.max(1, 24 - 4)
76    const visiveis = notas.slice(-Math.max(1, Math.floor(espaco / 5)))
77
78    return (
79      <Box flexDirection="column">
80        {notas.length === 0 && (
81          <Text dimColor>As tecnologias escolhidas aparecerão aqui, com uma explicação curta de cada uma.</Text>
82        )}
83        {visiveis.map(n => (
84          <Box key={`nota-${n.id}`} flexDirection="column" marginBottom={1}>
85            <Text bold>{n.titulo}</Text>
86            {n.tecnologia && <Text dimColor>{n.tecnologia}</Text>}
87            <Text>{n.texto}</Text>
88          </Box>
89        ))}
90      </Box>
91    )
92  })
93}
94
types/index.d.ts 2 lines
1export type Nota = { id: number; titulo: string; texto: string; tecnologia?: string }
2