Sends rm / Remove-Item targets to the Windows Recycle Bin instead of deleting them for good

Function-hook mods for Claude Code: shell safety, secret guarding, session telemetry, context panels, and workflow tools. Each mod is an isolated plugin with its own tests, and you enable only the ones you want.
| Mod | Description |
|---|---|
guarda | Intercepts risky Bash commands (rm -rf, git reset --hard, force push, new dependencies) and asks for confirmation explaining the impact. |
lixeira | Sends rm / Remove-Item targets to the Windows Recycle Bin instead of deleting them permanently. |
cofre | Keeps API keys out of the conversation: /chave stores them in .env, secret file reads display only variable names, outputs are masked, and pasted keys are quarantined. |
atomic-commit-guard | Blocks commits that mix top-level directories, violate Conventional Commits, or lack a Co-Authored-By trailer. |
universal-audit-log | A hook on * that logs every event (tool calls, prompts, turns, fs/http/process calls from other plugins) with secret redaction. |
| Mod | Description |
|---|---|
context-monitor | Context weather and token usage above the prompt, replay and activity panels, plain-language explanation before each edit, and ai-memory notes. |
cache-frio | Confirms before submitting a prompt to a large conversation whose prompt cache has gone cold. |
session-telemetry | Timestamp on each response, TTFT and tok/s per step, and visual notice whenever the responding model switches. |
session-time-machine | /timemachine: renders the session as a timeline of prompts, tool calls, and turn completions. |
turn-inspector | Side pane displaying the session turn-by-turn: every model request and what it carried. |
clean-view | Collapses each successful tool call into a single concise line (Edit file +12 −3); errors and in-flight calls retain the full block. |
webfetch-cache | Serves repeated WebFetch requests (identical URL and prompt) directly from the session cache. |
reflexo | Detects corrections and constraints in prompts, offering to save them as rules in CLAUDE.md. |
| Mod | Description |
|---|---|
agent-flow | Live diagram of agent flow: main loop context, subagent tree, and context passed/returned by each agent. |
agent-radar | One live line per running subagent above the prompt; /radar opens a pane with messages from each. |
delegation-dock | Status line indicator showing in-flight delegations (agy/codex/ollama) and alerting when one returns empty. |
phase-tracker | Tracks and displays the current development phase (Spec → Red Test → Surgical Code → Verification). |
next-prompts | Band with 3 next-step suggestions generated by a free Ollama cloud model; click one to draft. |
git-sidebar | Lazygit-style side pane: worktrees, local branches, branch switching, and worktree checkout. |
wait-quiz | Quizzes a flashcard in a band above the prompt while Claude is working. |
meus-mods | Central hub: quick-access bar above the prompt and /mods command displaying the status of each mod. |
Requires Claude Code with function-hook mods support.
git clone https://github.com/Covre81/claude-code-mods.git ~/.claude/mods
Enable the mods by listing their absolute paths in CLAUDE_CODE_PLUGIN_DIRS inside ~/.claude/settings.json. On Windows, paths are separated by ;:
{
"env": {
"CLAUDE_CODE_PLUGIN_DIRS": "C:/Users/me/.claude/mods/guarda;C:/Users/me/.claude/mods/cofre;C:/Users/me/.claude/mods/session-telemetry"
}
}
Order matters: the last plugin in the list sits closest to the engine. For instance, lixeira should come after guarda so guarda inspects the original rm -rf first.
Several mods include a command to toggle them on or off without restarting (/webfetch-cache on|off, /radar-toggle, /telemetria…); /mods displays the status of all mods.
Each mod follows the same structure:
<mod>/
.claude-plugin/plugin.json manifest
.claude-plugin/types/ engine types (git-ignored, see below)
hooks/hooks.json hooks registered by the mod
hooks/register.ts(x) code
hooks/*.test.ts(x) tests
Engine types are not committed to the repository. To typecheck and test a mod, copy .claude-plugin/types from an existing mod or generate them with your Claude Code instance.
Tests run directly within Claude Code, not via vitest/jest:
claude plugin test guarda # single mod
for d in */hooks/hooks.json; do claude plugin test "${d%%/*}"; done # all mods
Commits follow Conventional Commits, scoped to one mod per commit (enforced by atomic-commit-guard).
Six mods (agent-flow, git-sidebar, session-time-machine, turn-inspector, universal-audit-log, webfetch-cache) originate from davila7/claude-code-templates, and agent-radar originates from hamzafer/claude-code-mods, both under the MIT License and adapted here. Copyright notices are preserved in THIRD_PARTY_NOTICES.md.
hooks/register.tsx 47 lines1import type { Register } from 'claude-code'
2
3export type Shell = 'bash' | 'powershell'
4
5// ponytail: copy of guarda's tokenize/PREFIXES — plugins load isolated, an import across mods may not exist when installed.
6function tokenize(text: string): string[] {
7 const words: string[] = []
8 const re = /"((?:[^"\\]|\\.)*)"|'([^']*)'|(\S+)/g
9 for (let m = re.exec(text); m; m = re.exec(text)) words.push(m[1] ?? m[2] ?? m[3] ?? '')
10 return words
11}
12
13const PREFIXES = new Set(['sudo', 'command', 'exec', 'env', 'nohup', 'time', 'then', 'do', 'else', '!'])
14const PS_DELETE = /(?:^|[;|{(\n]|&&)\s*(?:remove-item|rm|del|erase|ri|rd|rmdir)(?=\s|$|[;|)}])/i
15
16/** Does the line run rm (Bash) or a Remove-Item alias (PowerShell) as a command? A false positive only adds a harmless prefix. */
17export function hasDelete(command: string, shell: Shell): boolean {
18 if (shell === 'powershell') return PS_DELETE.test(command)
19 return command.split(/&&|\|\||;|\||\n/).some(seg => {
20 const words = tokenize(seg.trim().replace(/^[({]+\s*/, ''))
21 while (words.length && (PREFIXES.has(words[0]!) || /^[A-Za-z_]\w*=/.test(words[0]!))) words.shift()
22 return words[0] === 'rm'
23 })
24}
25
26/** The command with the delete shadowed by the mod's scripts in `hooks` (a folder without single quotes). */
27export function rewrite(command: string, shell: Shell, hooks: string): string {
28 // A shadow that fails to load (moved, ExecutionPolicy) stops the line instead of letting the real Remove-Item run.
29 if (shell === 'powershell') return `try { . '${hooks}/remove-item.ps1' } catch { throw 'lixeira: a sombra nao carregou; nada foi apagado' }; ${command}`
30 return `rm() { powershell.exe -NoProfile -NonInteractive -File '${hooks}/lixeira.ps1' "$@"; }; ${command}`
31}
32
33export const register: Register = on => {
34 on('tool.call', { tool: ['Bash', 'PowerShell'] }, ($, e, next) => {
35 if (e.tool !== 'Bash' && e.tool !== 'PowerShell') return next(e)
36 const sh: Shell = e.tool === 'Bash' ? 'bash' : 'powershell'
37 const command = String(e.command ?? '')
38 const hooks = `${$.plugin.root.replace(/\\/g, '/')}/hooks`
39 if (hooks.includes("'") || !hasDelete(command, sh)) return next(e)
40 return next({ ...e, command: rewrite(command, sh, hooks) } as typeof e)
41 }).catch(($, e, next) =>
42 // Before next: let the original run (a lixeira bug must not block the shell; guarda still holds rm -rf).
43 // After next: the rewritten delete already ran — running the original now would delete for good.
44 next.called ? { deny: 'A lixeira falhou depois de rodar o comando. Confira o resultado antes de repetir.' } : next(e),
45 )
46}
47