lucenity0/claude-code-mods/tree/main/seatbelt
seatbelt
Bash, Edit, Write 및 NotebookEdit 도구 호출에 대한 함수 훅을 사용하여 파괴적인 셸 명령 및 비밀 편집이 실행되기 전에 차단하는 Claude Code 플러그인입니다.
이 mod 소개
seatbelt는 lucenity0/claude-code-mods 컬렉션의 일부로, 함수 훅 API를 기반으로 구축된 작은 Claude Code 플러그인 세트입니다. seatbelt 모드는 모든 Bash, Edit, Write 및 NotebookEdit 도구 호출을 가로채고 해를 끼칠 수 있는 호출을 거부합니다. 예를 들어, / 또는 ~ 또는 상위 경로에 대한 rm -rf, 보호된 브랜치에 대한 git push -f, curl | sh 파이프, mkfs, dd of=/dev/..., chmod -R 777, 그리고 .env, .pem 또는 ~/.ssh/ 파일에 대한 편집 등이 있습니다. 규칙은 seatbelt/hooks/rules.ts에 이름, 이유 및 일치 조건자를 가진 작은 객체로 정의되어 있어 감사하거나 확장하기 쉽습니다. 이 플러그인에는 검증된 .claude-plugin/plugin.json과 register.ts를 등록하는 hooks.json이 함께 제공되며, claude --plugin-dir 또는 CLAUDE_CODE_PLUGIN_DIRS를 통해 로드할 수 있습니다. README는 이를 샌드박스보다는 사고 방지 가드레일로 설명하며, 설치 지침, 규칙 코드 샘플, 차단된 명령과 허용된 명령 표를 포함합니다.
설치
먼저 작성자의 README에서 marketplace와 플러그인 이름을 확인하세요. 저장소 구조에 따라 명령어가 달라질 수 있습니다.
claude plugin marketplace add lucenity0/claude-code-mods claude plugin install seatbelt
원문 / README
claude-code-mods
Small plugins for Claude Code. Each mod is one TypeScript file of function hooks.
<img src="assets/hero.svg" alt="Claude Code with all four mods running: seatbelt blocking a dangerous rm, the session-dash pane, the turn-meter status line and a ding toast" width="900">turn-meter a turn timer in the status line
seatbelt blocks destructive commands and edits to secrets
ding a chime when a long turn finishes
session-dash /dash, a live pane of what the session did
context-meter a context window meter under the prompt; click it for the breakdown
Also: claude-familiar, a pixel companion that sits above the prompt and reacts to your session, and claude-readout, which names the files on the folded Read 3 files line.
install
git clone https://github.com/lucenity0/claude-code-mods ~/claude-code-mods
claude --plugin-dir ~/claude-code-mods/seatbelt --plugin-dir ~/claude-code-mods/session-dash
To turn on function hooks and load the mods in every session, set this in ~/.claude/settings.json:
{
"env": {
"CLAUDE_CODE_ENABLE_FUNCTION_HOOKS": "1",
"CLAUDE_CODE_PLUGIN_DIRS": "~/claude-code-mods/turn-meter:~/claude-code-mods/seatbelt:~/claude-code-mods/ding:~/claude-code-mods/session-dash:~/claude-code-mods/context-meter"
}
}
These use function hooks, an early-access API that CLAUDE_CODE_ENABLE_FUNCTION_HOOKS turns on, and were tested on Claude Code 2.1.287.
turn-meter
The status line counts up while Claude works. When the turn ends it shows the summary.
✓ 41s · 12.3k in · 1.8k out
on('turn.start', ($, e, next) => {
ticker?.cancel()
let seconds = 0
$.ui.status('running 0s')
ticker = $.clock.every(1000, () => {
seconds += 1
$.ui.status(`running ${formatDuration(seconds * 1000)}`)
})
return next(e)
})
seatbelt
Checks every Bash, Edit and Write call before it runs, and denies the ones that would hurt.
● Bash(rm -rf /tmp/build/../../)
⎿ seatbelt: blocked `rm -rf /tmp/build/../../` (rm -rf on / or ~): it
recursively deletes the filesystem root, a top-level folder or your home folder…
blocks still allows
rm -rf / rm -fr ~ rm -rf /x/../../ rm -rf node_modules
git push -f origin main git push --force origin my-branch
curl … | sh curl -o install.sh …
mkfs dd of=/dev/… chmod -R 777 chmod 755 script.sh
edits to .env *.pem ~/.ssh/* .env.example
Each rule is a small object in rules.ts:
{
name: 'curl | sh',
reason: 'pipes a script from the internet straight into a shell',
matches: command => /\b(curl|wget)\b[^|]*\|\s*(sudo\s+)?(ba|z|da)?sh\b/.test(command),
}
It's a guardrail against accidents, not a sandbox.
ding
When a turn that ran longer than 30 seconds finishes, ding shows a toast and plays an original two-note chime. The sound plays on macOS only.
{ "pluginConfigs": { "ding": { "options": { "thresholdSeconds": 60, "sound": false } } } }
session-dash
Type /dash to open the pane. Type /dash again, or press q, to close it.
╭─ Session ─────────────────────────────╮
│ 4 turns · 2m13s · 184k in · 9.2k out │
│ │
│ Tools (23 calls) │
│ Bash ████████████████████ 9 │
│ Read ███████████████ 7 │
│ Edit █████████ 4 │
│ │
│ Turn time · max 1m12s │
│ ▂▄▃▆▁▅█▃▄▁▆▃ │
│ │
│ Recent files │
│ src/server.ts │
│ README.md │
│ │
│ [ Reset ] [ Close ] │
╰───────────────────────────────────────╯
on('tool.call', async ($, e, next) => {
const ran = await next(e)
await update($, stats, current =>
countTool(current, e.tool, { isDenied: ran.deny !== undefined, isError: ran.isError === true }),
)
return ran
})
context-meter
A meter sits at the bottom right of the prompt, under the input. It turns yellow at 60% and red at 80%.
ctx ▰▰▰▱▱▱▱▱ 42%
Click it, or type /ctx, to open the breakdown. Esc closes it.
42% 84k of 200k claude-opus-5-5 · estimated
██████████████████████████▌█░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░▒▒▒▒▒▒▒
83k free · compacts in 83k
● Messages 62k ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ 74%
● System tools 13k ━━━━━━━━ 15%
● Skills 4.9k ━━━ 6%
● System prompt 3.7k ━━ 4%
○ on demand 93k MCP tools, not in the window
last request 84k in · 82k cached · 967 out
memory
CLAUDE.md ~/code/app 900
[ Count exactly ] [ Refresh ] [ Compact ] [ Close ]
The breakdown is a local estimate. Count exactly counts it with the token-count API, as /context does.
on('session.measure', async ($, e, next) => {
await update($, fill, () => e.context)
if (e.changed.includes('context') && (await isPaneOpen($))) void loadDetails($, 'summary')
return next(e)
})
make one
hello/
├── .claude-plugin/plugin.json { "name": "hello", "version": "0.1.0", "description": "…" }
└── hooks/
├── hooks.json { "modules": ["./register.ts"] }
└── register.ts
import type { Register } from 'claude-code'
export const register: Register = on => {
on('tool.call', { tool: 'Edit' }, async ($, e, next) => {
const result = await next(e)
$.ui.toast(`edited ${e.file_path.split('/').pop()}`)
return result
})
}
claude plugin validate ./hello
claude plugin test ./hello
<sub>MIT · built with Claude Code</sub>
