Open-source learning lab

Understand mods.
Then make one.

A small, hands-on guide to customizing Claude. Try an example, follow the code, and change one thing.

2 plugins6 code recipesMIT licensed
THE ANATOMY OF A MOD01 / EVENT FLOW
An event enters your hook and takes one of three paths: observe forwards the same event, rewrite forwards a changed event, and answer returns a result locally without continuing.
One event. Three ways to respond. Try the interactive version ↓
A TINY FIRST EXAMPLE

A click can change the UI without a model request.

Same desktop app. Different extension surfaces. Cowork workflow commands and Claude Code UI mods have different capabilities. This guide gives you a working starting point for each. Choose your surface →

01 / CHOOSE A PATH

Start with the Claude you use.

Choose a path. You can explore the browser explainer below before installing anything.

Surface support: official mods documentation · Cowork setup: official plugin help. Labels and availability vary by rollout and organization policy.

02 / THE BUILDING BLOCKS

Four pieces. Different jobs.

Start with the smallest extension that solves your problem. A UI mod is one option in a larger toolkit.

A

Skill or command

Reusable instructions for a recurring job. Our Cowork command asks for an experiment card with four fields.

“Do this the way I like.”
B

Connector / MCP

Tools or data supplied by an external service or process. The starter doesn’t need a connected account.

“Reach this system.”
C

Plugin

The package people install. This repo ships two independent plugins through one small marketplace.

“Bundle these pieces.”
D

Mod

Code inside a Claude Code plugin that reacts to events. Our mod adds a pane and changes selected behavior.

“React when this happens.”
Two meanings of “hook.” A settings hook runs a configured command, request, or prompt. A mod hook is a JavaScript or TypeScript function inside Claude Code. The examples here use mod functions. Compare the extension types ↗

03 / THE EVENT LOOP

Follow an event through a hook.

A hook receives an event and decides what happens next. Try all three choices in this browser simulation.

ObserveForward the same event.

RewriteForward a changed copy.

AnswerReturn a result here.

BROWSER SIMULATION · NO CLAUDE CONNECTION
EventOur hookNext handler

Observe the call and pass the same event to the next handler.

TRACE
Ready. Nothing has run yet.

What are $, e, and next?

$ · the host API
Register a command, fill a draft, save a value, or ask the UI to redraw.
e · the event
The data for this action. Treat it as immutable; create a copy to change it.
next(e) · continue the chain
Pass the event to downstream mods and the engine. Return your own result to handle it instead.
A minimal observer JavaScript
on('tool.call', async ($, e, next) => {
  calls += 1;
  $.ui.invalidate('ui.render');
  return next(e);
});

Counting is ordinary JavaScript. Redrawing is a host API call. Forwarding preserves the tool’s normal behavior.

04 / WORKING EXAMPLES

Pick a recipe. Read the real code.

These excerpts are extracted from the actual starter when the site builds. Pick a recipe, then open its surrounding source.

05 / YOUR FIRST CHANGE

Make one small change.

Keep a working baseline. Change a small behavior. Check the result where you intend to use it.

  1. 1

    See the original work.

    In Cowork, run the experiment command with the supplied notes. In Code, open /kitchen and click the counter. Write down what you expect to change.

  2. 2

    Edit one observable detail.

    Change a field name in commands/experiment.md, or change the counter button’s label in hooks/register.js. Repackage Cowork; use --plugin-dir for Code’s edit/reload loop.

  3. 3

    Prove that specific change.

    Invoke the command again or press the button. Run the relevant checks, then record the app surface and version. A host test can validate an element tree; the app still needs a visual check.

Useful local checks

No npm install is needed. Node.js 20+, Python 3.9+, and a recent Claude Code are enough for the full set.

npm test
npm run validate
npm run test:native
npm run site:build
npm run site:check
Keep these boundaries visible. This mod makes no network calls, spawns no processes, and makes no extra model requests. Its saved note uses local plain-text plugin storage. Installed mods can have much broader access: review their code and validator inventory before loading them. Understand mod access ↗

06 / GET UNSTUCK

Find the next useful check.

I installed it in Cowork. Where is the custom pane?

The Cowork plugin demonstrates prompt commands. The UI pane belongs to the separate kitchen-sink mod in a supported Claude Code session. Start with the Desktop Code or Terminal path above.

/kitchen isn’t in the command list.

Check /plugin for an active kitchen-sink mod, then /status for the version. Validate the correct plugin directory. In an existing session, try /reload-plugins. Managed policy can prevent mods from loading.

The command works, but no UI appears.

Run /kitchen-status and inspect the reported surfaces. Headless sessions do not draw. Remote Control shows mod drawings in the host terminal. VS Code has different supported render sites, and the full desktop example should be checked in a local Code session.

My edit isn’t showing up.

For mod development, launch with --plugin-dir ./plugins/kitchen-sink from the repository root. An installed marketplace copy may differ from your working tree. For Cowork, rebuild the ZIP and re-upload. In-memory counters reset when the module reloads.

The draft button did nothing.

It preserves an existing prompt. Clear or send your draft first; the button displays a notice instead of combining unrelated text. It fills the box and leaves sending to you.

Can this be my production command-security policy?

The sample guard only checks the plugin’s imaginary mixing tool. It is a teaching example, not a general shell policy. Read the host’s permission and managed-policy documentation before designing real controls.

How do I remove it or delete my scratch note?

Use the Notes tab’s delete button for the saved note. For an installed plugin, open /plugin and disable or uninstall it. A session loaded with --plugin-dir stops using that copy when you exit. In Cowork, remove the uploaded plugin through Customize.

07 / KEEP GOING

Learn it. Change it.
Share what you make.

Fork the workshop. Add one useful example, explain its boundaries, and help the next person understand what changed.