A Claude Code mod is a small plugin of function hooks that runs inside your own Claude Code session. It can add a pane, a status line or a check before or after a tool call. These two prompts are the ones we used to find and build Duckboard, our own mod. Run them in order.
Prompt 1 reads your own session transcripts and tells you which five mods would save you the most time. It builds nothing. Prompt 2 builds Duckboard: one pane that shows every Claude Code session on your computer, with context, cache, usage, test and push state, and a compact button per session.
Nothing is gated. Copy, paste, send.
Prompt 1: audit how you use Claude Code
Open Claude Code in any folder, paste this, and send it. It reads only files on your own computer. Expect a ranked list of five mod ideas, each tied to a real moment from your sessions.
Audit how I use Claude Code. Read my last 30 sessions in ~/.claude/projects/ (the .jsonl transcripts), newest first. Look for: - things I ask for over and over - things I check by hand (usage, prompt cache, git state, which files are staged) - steps I always do before or after a certain kind of task Then suggest five Claude Code mods that would fix those. For each one, give me: 1. The name 2. The problem it solves 3. A quote from the session moment that shows it 4. The event it plugs into, and whether it acts before, after, or instead 5. What it shows on the screen, and when 6. Whether it costs any usage Rank them by how much time they save me. Don't build anything yet.
Free, ungated, no email required. Copy it as many times as you like.
Prompt 2: build Duckboard
Duckboard is the mod our own audit pointed to. Paste this in a new session. Claude loads the built-in mod skill and checks the engine facts against your installed version. Then it makes an HTML mockup of the pane for you to approve. After you approve, it builds the mod with tests first. It asks before it changes anything outside the mod folder.
Build me a Claude Code mod called "duckboard": one pane that shows every Claude Code session on this computer, so I stop checking things by hand. Work in the order below. Do not skip a step. Do not guess about the engine or about my files: read them.
RULES
- Real data only. Every number, line and button comes from a real file, a real command or a real engine call. No placeholder text, no fake sample data on screen. If a value is unknown, show "unknown" or hide it.
- Tests first. For each feature, write a failing test, then the code, then run the gate. Pure logic (parsing, formatting, grouping, the compact state machine, the drawing) lives in plain .ts files with no engine calls so it is easy to test.
- No silent catch. Every caught error writes a log line or shows a message.
- Plain ASCII in anything you write for me to read, except where I say otherwise.
- Never read, print or store a credential, token or key. Never edit my settings files without telling me what you changed.
- Ask me before any step that changes a file outside the mod folder.
STEP 1: LOAD THE MOD SKILL
Load the built-in skill "plugin-authoring" (use the Skill tool). It tells you where to write the mod, the file layout, and where the engine type file is (about 14,700 lines: grep it for the name you need, do not read it whole). If the skill is missing, stop and tell me my Claude Code is too old for mods (I need a build that has `claude plugin validate`).
STEP 2: AUDIT MY OWN USE (no building yet)
Read my last 30 session transcripts, newest first: ~/.claude/projects/<project>/<session>.jsonl (on Windows: %USERPROFILE%\.claude\projects). Also look at ~/.claude/sessions/<pid>.json (the live-session registry: it has the session id, a busy or idle status, a kind, the pid and a name; check the real keys on my machine, they are not in the engine type file) and at subagent files under each session folder. Do not read a file over 4 MiB whole: read its last 600 lines only.
If I already ran the audit prompt in this session, reuse its result and go straight to the question at the end of this step. Otherwise, find what I do by hand again and again: check usage, check the prompt cache, check git state, run tests, ask "is it pushed", compact a long session. Quote the transcript moment for each. Then suggest the 5 mods that would save me the most time. For each one give the name, the problem, the quote, the engine event it uses, and what it shows. Rank them. Then ask me which to build. Recommend the board in step 3 if it fits what you found. Wait for my answer.
STEP 3: DESIGN THE BOARD FIRST (no engine code yet)
Make a self-contained HTML mockup file of the pane with real-looking states: the top, the three groups, a row, an opened row (Details), and each compact state. Show it to me. Fix it until I say "build it". Then keep that file: it is the spec, and the drawing in step 4 must match its font sizes, padding, rules and colors. Keep the mockup simple: calm, high level, no badge or chip that I did not ask for. Say which fields you left out and why.
STEP 4: THE BOARD (build this unless I picked something else)
One pane. Build the parts one at a time, each with tests.
1. Session list. Which sessions: every session that is live in the registry (a live pid), whatever its age, plus sessions written in the last 6 hours (newest 40), plus idle main sessions up to 7 days old (newest 60) for the Cold group. Read the old ones once, cache by file time, and never scan them for agents. A session with no live registry entry is "closed": it is always Cold. A dead pid in the registry does not count as live (one ps call; tasklist on Windows); if two entries name one session, the newest wins. Keep four kinds apart: main sessions (shown as rows), headless runs (-p or SDK: not rows; only a count), subagents and workflow agents (never rows; they appear under their session). Title: the registry name if I set one, else the transcript title, else the project.
2. Groups, in this order. "Working": the registry says busy, or an agent of the session is running now (its file was written in the last minute, or it has an open tool call under an hour old). "Your turn": idle, the last reply was Claude's, and the prompt cache is still warm. "Cold": idle with the cache gone, or closed. Cold is folded by default; its header has a Show or Hide button that must visibly work; no row cap. Find out the real cache lifetime for my setup from the transcripts (compare cache_read_input_tokens and cache_creation_input_tokens across a long gap) and write the number you found at the top of the code. Do not assume 60 minutes without checking.
3. Row, always visible: a status dot (one color per group), the title, a "this one" tag on the session that runs the mod, ONE line "what it does" (the first plain line of the newest assistant text block of the main thread; skip tool-only turns), then a meta line: "N agents running" or "No agents" (a cold row shows how long it has been idle), a small cache bar with "Cache 41m" (amber under 10 minutes, "Cache <1m" in the last minute; a working row with a cold cache says how many tokens its next turn rewrites), and the context percent. Add an option addressName (default empty): if a reply line starts with that name and a comma or colon, drop it on the board.
4. Details (a button on each row opens and closes it): Last update (first 2 lines of the reply), Context ("182k of 1M tokens (18%)" with a bar), Cache ("23 min left" with a bar; "Cold. The next turn rewrites the context." when cold), up to 5 running agents (name, model, running time) and "N agents done in the last hour", and the facts that are known: a ticket id (read from the session's branch name, newest commit or prompts; never call a tracker), "Pushed" or "N not pushed" (run git in the session's folder, cache it 60 s), "Tested 5m ago", "Tests failed" or "Testing" (from the newest test run in the transcript, a background run's output file too).
5. Context: tokens in the last assistant turn = input_tokens + cache_read_input_tokens + cache_creation_input_tokens. Show a percent only when the window is known: the engine's value from the session usage call, else 1M for a model name ending in [1m] or a count over 200k, else unknown. Never guess 200k. Unknown: show the token count alone.
6. Top and footer. Top: the 5-hour limit and the weekly limit, each with a percent, a thin bar and its reset time, from the engine call that reports session usage; hide a value the engine does not give. Under it one line: "N working, N your turn, N agents running". Footer: "N background runs in the last 6 hours" and "Updated Ns ago". Scan by timer; no Refresh button; no cost.
7. Compact. A button on a main session row that is idle, has a warm cache and is live in the registry. Never on a working row, a cold row, a subagent or a headless run. For this session, use the engine's compact call. For another session, send it a one-line request with the engine's session send call, and handle it in a session-receive hook (only a peer's message; only your exact protocol line; everything else goes on with next(e)). Protocol lines, each one line with a random id: compact-request, compact-started, compact-queued (the receiver is mid-turn and compacts when the turn ends), compact-result (ok with tokens before and after, or fail with the reason). States on the row: Ready; Ready-low (amber "Cache ends in N min" under 10 minutes); Sent ("Request sent. Waiting for the session to start it."); Compacting ("Do not send this session a message."); Busy ("It compacts when this turn ends."); Done ("Compacted just now: 182k to 21k tokens. Cache is fresh."; read the after count from the next scan; show it 10 minutes); No answer or Failed, both with a Retry button and the real reason. Timers: Sent with no reply in 30 seconds becomes No answer. Compacting or Busy with no result in 10 minutes becomes No answer. Retry keeps the first request's id open, so a late first result still lands. If the send is refused (auto permission mode can answer "no verdict" and block a send), show the engine's real reason and Retry; never say "session not running" unless the engine says so. Optional settings in userConfig: auto compact after N idle minutes (N under the cache lifetime; default 50 only if you measured 60), only above a minimum context size (default 100000), on or off.
8. Slash command /duckboard that opens the pane. The pane also opens when a session starts.
9. A terminal fallback (Box, Text, Button rows; bars drawn as text) for when the surface has no Svg. On the terminal, a real compact error is the answer; do not queue a /compact.
STEP 5: ENGINE FACTS (verify each one in the engine type file before you rely on it)
- A mod exports register(on, options). Hooks are ($, e, next). The module has no DOM and no Node: only `$` reaches files, processes and the clock.
- The pane is drawn in a ui.render hook for { component: 'Pane', requestId: <id> } and opened with $.ui.open({ id, title }). Get element tags from $.ui.resolve(e). Every surface has Box, Text, Button; the desktop, vscode and mobile also have Svg; the terminal has no Svg.
- Only a Button takes a press. Box, Text and Svg have no onPress, so a row opens with a Button. A Text has color, bold, dim and similar, but no font size, so a Text cannot match a design file's type sizes.
- Svg: a markup string, at most 131072 characters, an `alt` text is required, drawn as an image (no HTML, CSS or script from the page). Keep each picture small: one for the top, one per group header, one per row, one for Details, one for the footer.
- To match the HTML mockup on the desktop: write pure functions that return SVG strings with the mockup's font sizes, padding, rule lines and colors (the engine cannot draw HTML, and nothing converts it for you). You must estimate text widths and cut long text with an ellipsis to fit; test that. Keep Details, Compact and Show or Hide as native Buttons beside the pictures. Box has a hover prop, so use it to light a row. A picture with no press takes no key: put each in a keyed Box. On the terminal use the plain Text rows.
- Keep values the drawing reads in $.state with a types/index.d.ts contract (a hot reload clears module variables). A render hook never writes state.
- $.fs.read rejects a file over 4 MiB, and a live transcript grows between listing and reading. Read whole only under about 3.5 MiB. Above that, read a tail.
- $.session.send and the session-receive hook carry messages between sessions. A peer message arrives wrapped in an envelope; check the origin is a peer and that the text is exactly your protocol line.
- $.session.compact is NOT available in a headless (-p or SDK) session, and the desktop app runs sessions headless. Catch that rejection and fall back to running the /compact command with $.command.run, then read the before and after counts from the session.compact event it causes. It also rejects while a turn runs. Test every path.
- Use $.clock.every for the scan timer (about every 20 seconds) and cache slow calls (git) per key.
- Mods load at session start. After a change, I must open a NEW session to see it. Every open session must run the same version of the mod, or the compact lines of an old version show up as plain text in a new one: after an install, tell me to restart my open sessions.
STEP 6: GATES
After every feature run, and show me the last 10 lines of each:
claude plugin validate <mod folder>
claude plugin test <mod folder>
If `claude` on my PATH is older than the app I use, use the app's own binary. Tell me which one you used and its version. Do not say "done" until both pass. Tests live in hooks/*.test.ts and import from 'claude-code/testing'. Do not publish tests that contain my real paths or names.
STEP 7: PROVE IT ON SCREEN
Unit tests cannot show the look or a real compact. Tell me exactly how to open a new session, run /duckboard, and what I should see: compare it with the mockup from step 3, row by row. Ask me to confirm each button (Details, Show or Hide on Cold, compact this session, compact another session) with a real session before you call it finished. Say what you could not prove.
STEP 8: INSTALL FOR LATER
Tell me how to load the mod in every session: put the folder at ~/.claude/mods/duckboard and add its absolute path to env.CLAUDE_CODE_PLUGIN_DIRS in ~/.claude/settings.json (colon-separated on macOS and Linux, semicolon on Windows), or run `claude --plugin-dir <folder>`. Show me the edit and wait for my yes before you write settings.json. Then tell me to restart my open sessions.
Start with Step 1 now.Free, ungated, no email required. Copy it as many times as you like.
Set it up
- Update Claude Code. Mods need a build that has the
claude plugin validatecommand. - Run Prompt 1 and read the five ideas. Pick one, or take the board.
- Run Prompt 2 in a new session. It shows you the mockup first. Approve it or ask for changes, then answer its questions as it works.
- Open a new session when it is done. Mods load when a session starts.
What you should know going in
- Both prompts read your session transcripts. They stay on your computer. Claude reads them inside your own session, the same way it reads any other file.
- Prompt 2 asks before it edits your settings file. Say no and run the mod with
claude --plugin-dir <folder>instead. - After you install the mod, restart your open sessions so they all run the same version.
- A unit test cannot prove how a pane looks or that a real compact worked. Prompt 2 tells you what to check on screen yourself.
Talk to Claude instead of typing to it.
Ducktate turns what you say into clean text, on your Mac, and pastes it anywhere.
Get early access