__DESCRIPTION__

__DESCRIPTION__
<!-- Two or three sentences a stranger understands: what pain it removes, and what you see when it works. -->
<!-- Required if the mod draws anything. Put files in screenshots/ and reference them here. -->
/plugin marketplace add MDmubarak786/claude-mods
/plugin install __NAME__@modhub
Try it for one session without installing:
claude --plugin-dir ./mods/__NAME__
<!-- Commands, keys, buttons. What happens in claude -p or the Desktop app if that differs. -->
/__NAME__ prints how many tool calls Claude has made since the mod loaded.Paste the lines from claude plugin validate ./mods/__NAME__ so users can see what the mod does without reading the code:
hooks: session.start, tool.call, command.run{command=__NAME__}, ui.render{component=Spinner}
calls: $.command.register, $.ui.invalidate, $.ui.log
<!-- If the mod reads env vars, runs processes, or makes network requests, say why here. -->
X.Y.Z in the terminal <!-- and/or the Desktop app --><!-- What it can't catch, doesn't handle, or where it falls back. Honest limits build trust. -->
MIT, see the repository root.
hooks/register.ts 44 lines1// __NAME__: __DESCRIPTION__
2//
3// This starter counts the tool calls Claude makes, shows the count beside the
4// spinner, and adds a /__NAME__ command that prints it. Replace it with your mod.
5// Every hook gets ($, e, next): the mods API, the event, and the next handler.
6// Return next(e) to observe, next({ ...e, changed }) to rewrite, or an object to answer.
7
8// Shared by the hooks below. Resets when the module reloads; use $.state or $.store to keep it.
9let calls = 0
10
11export function register(on) {
12 // Runs once before the first prompt, and again after each reload.
13 on('session.start', async ($, e, next) => {
14 try {
15 await $.command.register({
16 name: '__NAME__',
17 description: 'Show how many tool calls Claude has made',
18 })
19 } catch (error) {
20 // A taken name throws. Catch it so the rest of the hook still runs.
21 $.ui.log('could not register /__NAME__: ' + error)
22 }
23 return next(e)
24 })
25
26 // Observe: runs before each tool call and lets it continue unchanged.
27 on('tool.call', async ($, e, next) => {
28 calls += 1
29 $.ui.invalidate('ui.render')
30 return next(e)
31 }).catch(async ($, e, next) => next(e))
32
33 // Answer: the command's reply prints in the transcript. No next(), so nothing else runs.
34 on('command.run', { command: '__NAME__' }, async () => {
35 return { text: 'Claude has made ' + calls + ' tool calls since this mod loaded' }
36 }).catch(async () => ({ text: '__NAME__: the command failed' }))
37
38 // Rewrite: keep Claude Code's spinner and add text after its word.
39 on('ui.render', { component: 'Spinner' }, async ($, e, next) => {
40 if (calls === 0) return next(e)
41 return next({ ...e, props: { ...e.props, suffix: ' · tool calls: ' + calls + '…' } })
42 })
43}
44