A collection of Command Code mods — tiny plugins that extend the agent loop.
The point of this repo isn't the mods themselves; it's what they demonstrate. Each mod is a minimal, readable example of the Command Code mod API, so you can lift the patterns into your own mods. hooku is the flagship showcase: it touches nearly every capability a mod can use.
command-code-mods/
├── .gitignore
├── LICENSE
├── README.md
└── .commandcode/
├── mods/
│ ├── clock.ts
│ ├── hex-color-swatch.ts
│ ├── hooku.ts
│ ├── tamagotchi.ts
│ └── weather.ts
└── taste/
└── taste.md
Each .ts file under .commandcode/mods/ is a standalone Command Code mod you can load with cmd --mod.
A mod is a TypeScript file that exports a single function receiving the
ModApi (the cmd object). Everything a mod can do hangs off that object:
register flags, attach hooks, and surface UI feedback.
Composes a three-line haiku poem about every run's output. Entirely useless, therefore essential.
addFlag— mod-defined configuration. hooku registershooku.enabledandhooku.modelas first-class CLI options, and reads them at runtime viacmd.getFlag. Users can flip them on the command line:--mod-option hooku.enabled=false.onStopwith{continue: true}— injecting work into the agent loop. When a run would end,onStopforces one extra turn with a custom prompt (reason). This is the core mechanism for follow-up work — summarization, post-processing, anything you want to run after the assistant finishes.- Two-phase state machine. Because the hook fires again on the turn it
injected, hooku uses a
haikuPendingflag to distinguish phase 1 (kick off the haiku) from phase 2 (the haiku came back). prepareNextTurn— model switching. Before that injected turn runs, hooku routes it to a cheaper model viaprepareNextTurn, keeping the expensive main-loop model on real work.cmd.ui.notify— transient UI feedback. Status ("writing hooku...") and outcome ("done") go through notify, so the mod never pollutes the run's own output.- Data shaping. The run output is sampled (start / middle / end) before being fed to the haiku model — a small, real example of preparing data for a follow-up LLM call.
hooku.enabled(boolean, defaultfalse) — toggle haiku generation.hooku.model(string, defaultdeepseek/deepseek-v4-flash) — LLM model for haiku generation.
# Default: disabled, use --mod-option to enable
cmd --mod-option hooku.enabled=true
# Use a different model
cmd --mod-option hooku.model=claude-haiku-4-5-20251001A virtual pet that lives in the TUI footer and reacts to the agent's lifecycle — it wakes on session start, gets busy during tool calls, frets after failures (or red tests), celebrates green tests, and sleeps when the session ends.
onSessionStart/onSessionEnd— cross-agent lifecycle hooks. The once-per-session wake/sleep bookends. They carry a typedsource/reason(resume vs. startup, replaced vs. shutdown) the baresession_start/session_shutdownevents don't — so a resumed session can "pick up where it left off" instead of just waking.beforeToolCall+afterToolCall— the pre/post tool seams.beforeToolCallsets a busy, category-aware "starting" line;afterToolCallreacts toisErrorand sniffsresultfor green/red test-runner output, then settles back to idle. Both returnundefined(no mutation) — a hook is allowed to only observe.- Session time & system time tracking — The pet maintains both a session clock (how long the session has run) and a system clock (current local hour). Late-night hours bias the pet toward drowsy sleepy variants; early mornings inject energetic wake-up lines. Turns exceeding 15 s trigger a slow-turn alert; sessions past ~10 min ramp fatigue messages. State deduplication ensures the footer never flickers through redundant updates.
- Tool-category messaging. Reads 📖, writes ✏️, commands 🪄, and shell 💻 each get their own fun before/after sets (picked at random); when the pet is sleepy the messages swap to tired/fatigued variants so the pet "becomes" the tool it's using.
cmd.ui.setStatus— messaging and status in one segment. The pet's voice is a single per-mod footer line, replaced on every change — nonotify. (Headless: stored, rendered nowhere.)addFlag— mod-defined configuration. Name and idle emoji are first-class CLI options, read back at runtime viacmd.getFlag.
tamagotchi.name(string, defaultPixel) — the pet's name.tamagotchi.emoji(string, default🐣) — the pet's awake/idle emoji.
# Defaults: Pixel 🐣
cmd
# Name your pet and pick its idle face
cmd --mod-option tamagotchi.name=Mochi --mod-option tamagotchi.emoji=🐱
A persistent multi-zone world clock displayed in the TUI footer. Shows your local time plus 1–3 configurable extra zones (London, LA, Sydney by default), each with a sun/moon emoji that matches the actual hour. Updates live every ~8 seconds and refreshes right before every tool call.
addFlag+getFlag— slot-based optional configuration. The clock exposes five flags:format(12 h / 24 h) andtz1/tz2/tz3(timezone strings). Each slot's flag defaults to an empty string; when empty the mod falls back to a built-in default (Europe/London,America/Los_Angeles,Australia/Sydney). This pattern lets you expose powerful per-slot options without forcing the user to configure them all.onSessionStart— once-per-session lifecycle bookend. Fires when a session begins (startup or resume). The clock uses this to kick off its interval timer and render immediately so the clock appears on-screen without waiting for the first tick. The hook receives a typedsourceparam ('startup'vs'resume') the baresession_startevent doesn't carry.onSessionEnd— once-per-session teardown bookend. Fires when a session ends (interrupted, replaced, finished). The clock clears its interval here to prevent timer leaks across sessions. Manual cleanup (vs. a Disposable handle fromwidget/addRenderer) — appropriate when you own a non-harness resource directly.beforeToolCall— reactive hook on every tool invocation. Secondary freshness mechanism. While the interval ticks independently, this hook guarantees a refresh right before the model observes any tool result. Useful for rapid tool chains where users want a real-time ticking feel. Returnsundefined(no mutation): hooks can also block calls, rewrite input, or terminate the run.cmd.ui.setStatus— persistent footer segment. Not transientnotify. One segment per mod painted side-by-side in load order beneath the input panel. New calls replace old text; whitespace-only clears it. Headless: stored, rendered nowhere. Combined with thebeforeToolCallhook and interval timer, creates a clock that never stales whether the agent is idle or deep in tool calls.- Slash commands —
/clockshows current times inline;/clock formatchecks the format flag;/clock tz1|2|3 <zone>shows how to set slots via CLI flags. Commands return{message}(info row data), not{prompt}(automated turns) or nothing (pure side effect). - Intl.DateTimeFormat — zero-dependency timezone handling. Native locale-aware formatting, timezone parsing, and offset extraction. No external packages needed.
EMOJIS[0–23] maps each local hour to a celestial body: ☀️ anchors midday (noon = full sun ☀️), 🌕 anchors midnight (midnight = full moon 🌕). Hours between cycle through waxing/waning crescent phases as daylight fades or increases — pure sun and moon, no clouds or stars. Each zone computes its own emoji from its local hour.
clock.format(string, default''→ 24 h) —'12'switches to 12-hour format.clock.tz1(string, default'Europe/London') — optional timezone slot 1.clock.tz2(string, default'America/Los_Angeles') — optional timezone slot 2.clock.tz3(string, default'Australia/Sydney') — optional timezone slot 3.
# Defaults: local + London + LA + Sydney, 24 h format
cmd
# Use Tokyo instead of LA, and 12-hour format
cmd --mod-option clock.tz2=Asia/Tokyo --mod-option clock.format=12
# Disable a slot by passing an empty value
cmd --mod-option clock.tz3="" # removes Sydney
A Command Code mod that makes hex colors visible in your terminal by rendering true-color ANSI swatches.
Two jobs, nothing else:
When you type a hex color like #fefefe, the prompt is transformed before
the model sees it — each color becomes a 2-wide solid box painted the actual
color, inline:
type: use #fefefe and #0af for the theme
becomes: use ██ #fefefe and ██ #0af for the theme
The model sees the annotated color too, so it can reason about it.
When the model's reply contains hex colors, the response is not rewritten or echoed back. Instead, each unique color is extracted and rendered as a compact list of swatches in the feed:
██ #fefefe ██ #3b82f6 ██ #00aaff
The model's original answer stays exactly as written — the list is just a visual aid so you can see the colors at a glance.
hooks.transformInput— annotate typed input inline. Runs on every keystroke (after a run starts). Hex colors in the prompt get painted██blocks before the model ever sees them. Returns{ action: "transform", text }.hooks.onStop— post-run extraction. Fires when the assistant finishes; scans the final assistant text for hex colors using a regex that only matches real 3/6-digit codes (#12345is ignored, CSS keywords are safe). Callscmd.showEntrywith extracted colors.cmd.addRenderer('hex-colors', …)+cmd.showEntry— custom feed renderer. A single-line renderer that joins deduplicated, normalized swatches into a compact row.
Ask for colors in any way and the mod renders a swatch list from the reply:
Rainbow
Give me the hex colors of a rainbow
Color variants
Show me 5 shades of blue from dark to light with their hex codes
Gradient builder
Give me a hex gradient from #ff6b6b to #4ecdc4 in 6 steps
Sports team colors
Do a web search for the San Diego Padres' official colors and list their hex codes Search for the Vegas Golden Knights' team colors and show them as hex codes What are the MLB team colors? List a few teams with their brand hexes
More ideas
Give me the Tailwind 500 palette What's the hex for bright green? List 10 material design colors
Copy to .commandcode/mods/hex-color-swatch.ts (this repo already has it
there). It loads once the workspace is trusted.
mkdir -p ~/.commandcode/mods
cp .commandcode/mods/hex-color-swatch.ts ~/.commandcode/mods/The repo ships a package.json with a commandcode mods entry, so it can be
installed from a local dir:
cmd mods add ./path/to/this-repo# Load without installing
cmd --mod ./.commandcode/mods/hex-color-swatch.ts
# Confirm it registered (no warnings)
cmd mods list
# Reload to pick up changes
/reloadhooks.transformInput— annotate typed prompts inline.hooks.onStop— when the run finishes, extract hex colors from the model's final text.cmd.addRenderer('hex-colors', …)+cmd.showEntry— render the extracted colors as a swatch list feed row.
- Short hex —
#0afworks and is expanded to#00aaffin the list. - Deduplication —
#FEFEFEand#fefefecount as one color. - Safe matching — only real 3/6-digit hex codes match (
#12345is not a color); no false positives on CSS keywords. - The response is never altered — the color list is a separate feed row.
- A terminal with 24-bit ("truecolor") ANSI support (most modern terminals).
Without it, the
██renders as a plain colored glyph rather than a true color swatch.
Shows current weather & temperature in the TUI footer using the free Open-Meteo API — no API key required. Shows a widget panel above the editor with full details, and a compact one-liner in the footer status.
Fetches today's temperature, wind speed, and condition code for a configured city, then displays both a persistent widget (above the editor) and a compact status line (footer). Updates live every 10 minutes and caches responses so repeated calls don't hit the API unnecessarily.
# Default: Boston, MA in Fahrenheit / mph
cmd
# Custom city, Celsius, km/h
cmd --mod-option weather.city="Paris,FR" \
--mod-option weather.temp_unit=celsius \
--mod-option weather.wind_speed_unit=kmhcmd.ui.widget({placement, render})— floating overlay panel. The mod registers a widget anchoredabove-editorthat re-renders with each weather fetch. The render function returns a single-element array so the panel shows just the formatted line. Calling.dispose()before re-registration prevents stale panels from stacking.cmd.ui.setStatus— compact footer presence. A parallel one-liner like☀️ Boston — 72°F, Wind 8 mphsits in the footer alongside other mods' segments. Headless mode stores the value but renders nowhere.cmd.addFlag— first-class CLI options. Three flags (city,temp_unit,wind_speed_unit) read back at runtime viacmd.getFlag. Each has a sensible default and validates against a small set of allowed values.cmd.addCommand— inline slash commands./weather [city] [f|m]lets you refresh weather or switch units without shell flags — e.g./weather Paris fsets city to Paris and temperature to Fahrenheit in one invocation. The handler parses positional args and flag-style tokens alike.hooks.onSessionStart/onSessionEnd— lifecycle bookends. Weather auto-fetches when a session begins so the widget is populated immediately; cleanup disposes the widget and clears the footer status on session end.- Async API + memoized caching. A
CACHE_LIFE_MScheck skips redundant fetches within 10 minutes, preventing rate-limit hits during rapid tool-call chains. Geocoding queries are fire-and-forget — if a city lookup fails, the widget shows "Weather unavailable." - WMO code → emoji mapping. Numeric weather codes map to standardized icons (☀️ clear, ⛅ partly cloudy, 🌧️ rain, ❄️ snow, ⛈️ thunderstorm), keeping the output visual without pulling in emoji description text.
Copy to .commandcode/mods/weather.ts (this repo already has it there).
mkdir -p ~/.commandcode/mods
cp .commandcode/mods/weather.ts ~/.commandcode/mods/cmd mods add ./path/to/this-repo# Load without installing
cmd --mod ./.commandcode/mods/weather.ts
# Confirm registration
cmd mods list
# Inline shortcut — no shell restart needed
/reload- Geocoding —
geoQuery()resolves a city string to{lat, lon}via Open-Meteo's geocoding API. If no results match, weather defaults to "unavailable." - Forecast fetch — once per session (or every 10 min cache expiry), the
current weather endpoint pulls
temperature_2m,windspeed_10m, andweathercode. Temperature and wind units come from flags. - Dual display —
widgetpaints above the editor with the full formatted line;setStatuskeeps the footer one-liner updated in lock step. - Cleanup —
onSessionEnddisposes the widget, clears the interval timer, and resets the footer status to avoid stale data leaking into the next session.
- No API key — Open-Meteo is free and requires no authentication.
- Units pass-through — temperatures and windspeed are rendered with the
unit label returned by the API (
°F,°C,mph,km/h). No local conversion logic. - Graceful degradation — network errors, bad cities, or missing fields all
result in a friendly
"🌡️ Weather unavailable"message instead of a crash.
hooku covers the core mutating surface; tamagotchi covers the tool-hook +
UI-status surface (beforeToolCall/afterToolCall, the lifecycle hooks, and
cmd.ui.setStatus). Mods can do more still: register slash commands,
intercept input, add custom renderers, and register entire model providers.
New mods in this repo should each showcase one of those capabilities.