SLOPSHOPPER

colombian-claude

Claude Code talks like a Colombian while it works: pick your accent, from rolo to costeño.

newspinnertoast
v0.1.0MITupdated 2026-10-06LucasLeguizamo/colombian-claude
A shopper browsing a rack in a slop shop
Preview · a replayed session in a sandbox
claude · ~/work/app · colombian-claude
› 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. ✻ Coronamos · 42s ✻ Camellando, sumercé… ────────────────────────────────────────────────────────────────────────────────────────────────────────────────────── › ? for shortcuts

Draws

Turn line
✻ Coronamos · 42s
README

colombian-claude

A Claude Code mod that makes Claude talk like a Colombian while it works.

✻ Atascado en el trancón… (12s · 1.2k tokens)
✻ Listo, sumercé · 12s

Instead of Sauteing… and Baked for 3s, the spinner says what a Colombian would be doing, in the accent you pick. When a /goal finishes, Claude welcomes you with "Bienvenido a la patria milagro".

Install

/plugin install colombian-claude --marketplace LucasLeguizamo/colombian-claude

Pick your accent

Open /config, find colombian-claude → Accent, and choose one:

OptionAccentWhile workingWhen done
rolo (default)BogotáAtascado en el trancón · Esperando el TransMilenio · Tomando oncesListo, sumercé · Melo, chino · Firmes
paisaAntioquiaVoleando machete · Subiendo en el Metrocable · Pidiendo una arepa con quesitoListo, pues · Qué chimba, parce · Ave María, quedó
costenoCaribbean coastBailando champeta · Cogiendo fresco bajo el palo e' mango · Prendiendo el picóAjá, quedó · Eche, qué nota · Nojoda, quedó bacano
calenoValle del CaucaBailando salsa · Pidiendo un cholao · Esperando el MÍOVe, qué bacano · Listo, mirá · Oís, quedó
santandereanoSantanderComiendo hormigas culonas · Bajando al Chicamocha · Hágale, manoListo, mano · Quedó bien verraco, mano
pastusoNariñoComiendo cuy · Achachay, qué frío · Subiendo al GalerasYa está, ve · Quedó bonito, ve
llaneroEastern plainsAsando la mamona · Templando el arpa · Cantando un joropoListo, compae · Quedó como es
boyacenseBoyacáSembrando papa · Pasando el páramo · Poniéndome la ruanaListo, sumercé · Ya quedó, mi señor
mixAll of themAnything aboveAnything above

Each turn picks one phrase and keeps it until the turn ends.

Add your own phrases

Everything lives in hooks/accents.ts: one working and one done list per accent. Add a line, open a PR. New accents are welcome too (chocoano, huilense, tolimense, cundiboyacense…): add an entry and its name to userConfig.accent.options in .claude-plugin/plugin.json.

How it works

It is a Claude Code function-hooks mod, a single module in hooks/register.tsx:

  • ui.render on Spinner and TurnDuration swaps the engine's word for one from your accent (the spinner keeps its time, tokens and effort; the closing line is redrawn as ✻ <phrase> · 12s).
  • session.append watches for the row the engine writes when a /goal ends and shows a toast.

Known limitation: Claude Code has no "goal met" event for mods yet. A goal writes one status row when it is set and another when it ends, and mods can't read which is which, so the toast fires on every second row. A goal that fails or is cleared early celebrates too.

Develop

claude plugin validate .
claude plugin test .
claude --plugin-dir .

License

MIT

Source 2 files
hooks/register.tsx 47 lines
1import type { Register } from 'claude-code'
2
3import { accentFor, GOAL_MET } from './accents'
4
5// Hash the engine's sampled word so one turn keeps one phrase across redraws.
6export const pick = (list: string[], seed: string) => {
7  let h = 0
8  for (const c of seed) h = (h * 31 + c.charCodeAt(0)) | 0
9  return list[Math.abs(h) % list.length] ?? list[0]!
10}
11
12export const duration = (ms: number) => {
13  const s = Math.round(ms / 1000)
14  return s < 60 ? `${s}s` : `${Math.floor(s / 60)}m ${s % 60}s`
15}
16
17// The engine raises no goal event. A /goal writes a 'goal_status' row when it is
18// set and another when it ends, and the row carries no text a hook can read, so
19// every second one is the end.
20// ponytail: counts rows; a goal that fails or is cleared early also ends on an even row and celebrates too.
21export const goalWatch = () => {
22  let rows = 0
23  return (name: string | undefined) => name === 'goal_status' && ++rows % 2 === 0
24}
25
26export const register: Register = (on, options) => {
27  const accent = accentFor(options.accent)
28  const isGoalEnd = goalWatch()
29
30  on('ui.render', { component: 'Spinner' }, ($, e, next) =>
31    next({ ...e, props: { ...e.props, word: pick(accent.working, e.props.word + e.requestId) } }),
32  )
33
34  // Drawn whole: rewriting the word alone would leave the engine's English 'for'.
35  on('ui.render', { component: 'TurnDuration' }, ($, e) => {
36    const { Text } = $.ui.resolve(e)
37    const word = pick(accent.done, e.props.word + e.requestId)
38    return <Text dimColor>✻ {word} · {duration(e.props.durationMs)}</Text>
39  })
40
41  on('session.append', async ($, e, next) => {
42    const result = await next(e)
43    if (!e.agentId && isGoalEnd(e.message.name)) $.ui.toast(GOAL_MET)
44    return result
45  })
46}
47
hooks/accents.ts 124 lines
1// Each accent has two lists: what the spinner says while a turn runs (`working`)
2// and the word that closes the turn in the transcript (`done`, drawn before the
3// duration: "Listo, sumercé 4s").
4
5export type Accent = { label: string; working: string[]; done: string[] }
6
7export const ACCENTS = {
8  rolo: {
9    label: 'Rolo (Bogotá)',
10    working: [
11      'Camellando, sumercé', 'Echándole cráneo', 'Dándole juicio', 'Haciendo la vuelta',
12      'Pidiendo un tintico', 'Comiendo changua', 'Tomando onces', 'Atascado en el trancón',
13      'Esperando el TransMilenio', 'Subiendo a Monserrate', 'Cuadrando la vuelta, chino',
14      'Sacando el paraguas', 'Pidiendo el ajiaco', 'Mojando la almojábana',
15      'Caminando por la Séptima', 'Haciendo fila en el SITP', 'Esquivando el pico y placa',
16      'Escampando el aguacero', 'Calentando el chocolate santafereño', 'Poniéndome la ruana',
17      'Haciendo vaca', 'Pensándola juiciosamente', 'Firmes',
18    ],
19    done: [
20      'Listo, sumercé', 'Qué chévere', 'Bacanísimo', 'Quedó una chimba', 'Melo, chino',
21      'Coronamos', 'Qué nota', 'Juicioso', 'Llegó la buseta', 'De una, sumercé', 'Firmes',
22    ],
23  },
24  paisa: {
25    label: 'Paisa (Antioquia)',
26    working: [
27      'Camellando, parce', 'Echándole berraquera', 'Voleando machete', 'Pensando, pues',
28      'Haciendo la vuelta, mijo', 'Subiendo en el Metrocable', 'Comiéndome una bandeja paisa',
29      'Tomando tinto en el parque', 'Arriando las mulas', 'Desvarando', 'Bajando de Santa Elena',
30      'Armando la silleta', 'Pidiendo una arepa con quesito', 'Montando el sancocho',
31      'Echándole cabeza, pues', 'Dándole como a rata',
32    ],
33    done: [
34      'Listo, pues', 'Qué chimba, parce', 'Eso, mijo', 'Ave María, quedó', 'Bien pueda',
35      'Bacano, parcero', 'Melo, pues', 'Hágale pues', 'Quedó berraco',
36    ],
37  },
38  costeno: {
39    label: 'Costeño (Caribe)',
40    working: [
41      'Rebuscándomela, ajá', 'Echando cerebro', 'Mamando gallo', 'Bailando champeta',
42      "Comiendo arepa e' huevo", 'Esperando la brisa', 'Prendiendo el picó',
43      "Cogiendo fresco bajo el palo e' mango", 'Echando cuento en la terraza',
44      'Tomando Kola Román', 'Haciendo la vaina', 'Arreglando la vaina', 'Pidiendo un bollo limpio',
45      'Comprando raspao', 'Esperando el Carnaval',
46    ],
47    done: [
48      'Ajá, quedó', 'Eche, qué nota', 'Ya está, mi llave', 'Nojoda, quedó bacano',
49      'Erda, coronamos', 'Listo, compadre', 'Quedó fue lo que es', 'Bien hecho, mi llave',
50    ],
51  },
52  caleno: {
53    label: 'Caleño (Valle)',
54    working: [
55      'Camellando, mirá', 'Haciendo el oficio, ve', 'Bailando salsa', 'Tomando lulada',
56      'Comiendo pandebono', 'Pidiendo un cholao', 'Esperando el MÍO', 'Subiendo a San Antonio',
57      'Pegándome un aborrajado', 'Pensándola, oís', 'Dándole al tumbao',
58      'Cogiendo la brisa de las cinco', 'Pidiendo un champús',
59    ],
60    done: [
61      'Ve, qué bacano', 'Listo, mirá', 'Oís, quedó', 'Qué chimba, ve', 'Bien pueda, pues',
62      'Ya está, mi socio',
63    ],
64  },
65  santandereano: {
66    label: 'Santandereano',
67    working: [
68      'Camellando, mano', 'Echándole verraquera, mano', 'Comiendo hormigas culonas',
69      'Pidiendo un mute', 'Tomando chicha', 'Bajando al Chicamocha', 'Hágale, mano',
70      'Pensándola con calma, mano', 'Dándole como es, mano', 'Comiendo carne oreada',
71      'Pidiendo una pepitoria',
72    ],
73    done: [
74      'Listo, mano', 'Quedó bien verraco, mano', 'Qué chimba, mano', 'Coronamos, mano',
75      'Así es, mano',
76    ],
77  },
78  pastuso: {
79    label: 'Pastuso (Nariño)',
80    working: [
81      'Camellando, ve', 'Comiendo cuy', 'Tomando hervido', 'Achachay, qué frío',
82      'Esperando el Carnaval de Negros y Blancos', 'Echándole cabeza, ve', 'Subiendo al Galeras',
83      'Pidiendo un helado de paila', 'Bajando a la Laguna de la Cocha', 'Pasando el frío, ve',
84    ],
85    done: ['Ya está, ve', 'Listo, pues', 'Quedó bonito, ve', 'Coronamos, ve', 'Bien, pues'],
86  },
87  llanero: {
88    label: 'Llanero (Orinoquía)',
89    working: [
90      'Arreando el ganado', 'Asando la mamona', 'Echando cuento al pie del fogón',
91      'Templando el arpa', 'Cantando un joropo', 'Cruzando el caño', 'Ensillando el caballo',
92      'Tomando guarapo', 'Echándole cabeza, compae', 'Esperando que escampe en el llano',
93    ],
94    done: ['Listo, compae', 'Ajá, compae', 'Quedó como es', 'Coronamos, compadre', 'Bien llanero'],
95  },
96  boyacense: {
97    label: 'Boyacense',
98    working: [
99      'Camellando, sumercé', 'Pidiendo un cuchuco', 'Tomando guarapo', 'Ordeñando las vacas',
100      'Arando la tierrita', 'Poniéndome la ruana', 'Sembrando papa', 'Echándole cabeza, sumercé',
101      'Comiendo arepa boyacense', 'Pasando el páramo', 'Subiendo a Villa de Leyva',
102      'Haciendo el mandado, mi señor',
103    ],
104    done: [
105      'Listo, sumercé', 'Ya quedó, mi señor', 'Juicioso, sumercé', 'Qué bonito quedó, sumercé',
106    ],
107  },
108} satisfies Record<string, Accent>
109
110export type AccentName = keyof typeof ACCENTS
111
112const all = Object.values(ACCENTS)
113
114export const MIX: Accent = {
115  label: 'Mix',
116  working: all.flatMap(a => a.working),
117  done: all.flatMap(a => a.done),
118}
119
120export const accentFor = (name: unknown): Accent =>
121  typeof name === 'string' && name in ACCENTS ? ACCENTS[name as AccentName] : name === 'mix' ? MIX : ACCENTS.rolo
122
123export const GOAL_MET = 'Bienvenido a la patria milagro'
124