Masks credential-shaped strings in a Read tool result before the model reads it.

A comprehensive configuration system for Claude AI with custom commands, development principles, and workflow optimizations.
📌 日本語版
This repository contains personal configurations for Claude AI, including:
.claude/
├── CLAUDE.md # Main configuration (AI reads this)
├── README.md # This file - Quick start guide
├── rules/ # Rule definitions
│ ├── core/ # Core AI operation principles
│ ├── conventions/ # Documentation conventions
│ └── development/ # Development patterns & methodologies
├── skills/ # Skill-based knowledge modules (27 skills)
├── agents/ # Specialized AI agents (28 agents)
│ ├── critics/ # Finding challengers (devils-advocate)
│ ├── enhancers/ # Code enhancers & simplifiers
│ ├── explorers/ # Codebase exploration agents
│ ├── generators/ # Test & snapshot generation
│ ├── resolvers/ # Build error resolvers
│ └── reviewers/ # Code review agents (18 reviewers)
├── docs/ # Design docs & guides (DRs under decisions/)
├── hooks/ # Pre/Post tool-use hooks
├── output-styles/ # Output style definitions
├── .claude-plugin/ # Plugin marketplace config
└── .ja/ # Japanese translations
This repository is available as a Claude Code plugin, allowing you to easily install specific workflow sets:
/plugin marketplace add thkt/dotclaude
/plugin
/plugin install build
For using this as your personal .claude configuration:
git clone https://github.com/thkt/dotclaude.git ~/.claude
.claude directory, back it up first: mv ~/.claude ~/.claude.backup
git clone https://github.com/thkt/dotclaude.git ~/.claude
Note: Manual installation applies all skills, agents, rules, and personal configuration. Plugin installation also clones the whole repository, but Claude Code loads only its skills, agents, and workflows; personal CLAUDE.md, rules/, and settings.json are not applied as rules or settings. A skill that cites rules/ reads the copy inside the plugin.
Claude Code's sandbox feature provides secure command execution with automatic permission handling, reducing approval fatigue while maintaining safety.
brew install jq# 1. Install sandbox runtime
npm install -g @anthropic-ai/sandbox-runtime
# 2. Verify installation
srt --version
# 3. Enable in Claude Code
# Run this command in Claude Code session:
/sandbox
# Select option 1: "Sandbox BashTool, with auto-allow in accept edits mode"
Create ~/.srt-settings.json for custom settings:
{
"sandbox": {
"enabled": true,
"autoAllowBashIfSandboxed": true,
"excludedCommands": ["docker"],
"network": {
"allowLocalBinding": true,
"httpProxyPort": 8080
}
}
}
The build workflow runs gh inside the sandbox. On macOS with the sandbox enabled, gh's TLS verification requires sandbox.enableWeakerNetworkIsolation: true in ~/.claude/settings.json. Without it, the build fails at the issue-fetch step.
Quality pipeline hooks wired in settings.json run automatically during Claude Code sessions to catch lint errors, format code, and enforce quality gates. The install command includes reviews, but settings.json does not wire it, so it does not run automatically.
brew tap thkt/tap
brew install guardrails formatter reviews gates
| Tool | Hook | Timing | Role |
|---|---|---|---|
| guardrails | PreToolUse | Before Write/Edit | Lint (oxlint) + security checks |
| formatter | PostToolUse | After Write/Edit | Auto-format (oxfmt) |
| reviews | Not wired | No automatic run | Static-analysis command |
| gates | PostToolUse | After Write/Edit/Bash | Quality gates (knip, tsgo, madge) |
Per-project configuration is done via .claude/tools.json. See thkt/tap for details.
Some commands use external CLI tools for data source integration. codegraph needs codegraph init per repository to create .codegraph/ before use.
| Tool | Required By | Purpose | Install |
|---|---|---|---|
gh | /issue, /pr, /preview, /build | GitHub API access | brew install gh && gh auth login |
scout | /research, use-cli-scout skill | Web search, page fetch, GitHub repo exploration, Slack fetch | brew install thkt/tap/scout |
codegraph | /research, use-cli-codegraph skill | Symbol-level structure queries (callers, impact) | npm i -g @colbymchenry/codegraph |
Slack reading: scout fetch <slack-url> reads any Slack message/thread URL directly. No additional setup needed if scout is configured.
/code can run as an autonomous multi-turn loop via the native /goal command (Claude Code 2.1.139+). No plugin install is required.
/goal all tests pass and lint is clean
Wrap a /code session in /goal <condition>; Claude continues until a fast model judges the condition met from the conversation.
See the complete command reference:
/research → /think → /issue → build workflow → /audit · /polish
/research → /fix
docs/*.md are available in English and Japanese; the seven docs/wiki/*.md files are English-only~/.Trash/), destructive operations require confirmationFull details: PRINCIPLES.md
Feel free to fork this repository and customize it for your needs. Pull requests for improvements are welcome!
MIT License - Feel free to use and modify as needed.
thkt
hooks/register.ts 15 lines1import type { On } from "claude-code";
2
3import { maskedRead } from "./redact.ts";
4
5export function register(on: On) {
6 on("tool.call", { tool: "Read" }, async ($, e, next) => {
7 const r = await next(e);
8 if (e.tool !== "Read" || r.deny !== undefined || r.isError) return r;
9 const masked = maskedRead(r.result);
10 // Returning r keeps core's own messages (ref), which still carry the raw content.
11 // Only a hook's own { result } makes core re-map the output for the model.
12 return masked === null ? r : { result: masked, context: r.context };
13 });
14}
15hooks/redact.ts 36 lines1// Credential shapes whose prefix or framing makes a false match unlikely. A generic
2// high-entropy detector is left out on purpose: it would mask hashes and ids the model
3// needs to read.
4const PATTERNS: readonly { kind: string; pattern: RegExp }[] = [
5 { kind: "private-key", pattern: /-----BEGIN [A-Z ]*PRIVATE KEY-----[\s\S]*?-----END [A-Z ]*PRIVATE KEY-----/g },
6 { kind: "anthropic", pattern: /\bsk-ant-[A-Za-z0-9_-]{20,}/g },
7 { kind: "openai", pattern: /\bsk-(?:proj-)?[A-Za-z0-9_-]{32,}/g },
8 { kind: "github", pattern: /\b(?:gh[pousr]_[A-Za-z0-9]{36,}|github_pat_[A-Za-z0-9_]{60,})/g },
9 { kind: "aws-access-key", pattern: /\b(?:AKIA|ASIA)[0-9A-Z]{16}\b/g },
10 { kind: "slack", pattern: /\bxox[abprs]-[A-Za-z0-9-]{10,}/g },
11 { kind: "google-api", pattern: /\bAIza[0-9A-Za-z_-]{35}\b/g },
12];
13
14/** The text with every credential-shaped match replaced, and how many were replaced. */
15export function redact(text: string): { text: string; count: number } {
16 let count = 0;
17 let out = text;
18 for (const { kind, pattern } of PATTERNS) {
19 out = out.replace(pattern, () => {
20 count++;
21 return `[REDACTED:${kind}]`;
22 });
23 }
24 return { text: out, count };
25}
26
27type ReadResult = { type: string; file?: { content?: unknown } };
28
29/** The Read result with its text content masked, or null when nothing needed masking. */
30export function maskedRead<R extends ReadResult>(result: R): R | null {
31 const content = result.file?.content;
32 if (result.type !== "text" || typeof content !== "string") return null;
33 const { text, count } = redact(content);
34 return count === 0 ? null : { ...result, file: { ...result.file, content: text } };
35}
36