commit 00183c41fe8d4a55e482e525c5e1fcffa08e1832 Author: Dan Guido Date: Thu Feb 12 00:59:39 2026 -0500 Initial commit Co-Authored-By: Claude Opus 4.6 diff --git a/.claude/commands/trailofbits/config.md b/.claude/commands/trailofbits/config.md new file mode 100644 index 0000000..7795134 --- /dev/null +++ b/.claude/commands/trailofbits/config.md @@ -0,0 +1,47 @@ +You are installing or updating Trail of Bits' Claude Code configuration into the user's `~/.claude/` directory. + +## Source files + +Fetch each file from GitHub using WebFetch. The base URL is: + +``` +https://raw.githubusercontent.com/trailofbits/claude-code-config/main/ +``` + +Files to fetch when needed: +- `settings.json` +- `claude-md-template.md` +- `mcp-template.json` +- `scripts/statusline.sh` +- `commands/review-pr.md` +- `commands/fix-issue.md` + +## Steps + +1. **Inventory what exists.** Read `~/.claude/settings.json`, `~/.claude/CLAUDE.md`, `~/.mcp.json`, `~/.claude/statusline.sh`, and check for `~/.claude/commands/review-pr.md` and `~/.claude/commands/fix-issue.md`. Note which files exist and which don't. + +2. **Ask the user what to install.** Use AskUserQuestion with a single multi-select question. List each component with a short description. Pre-label components that are missing from `~/.claude/` as recommended. Components: + - **settings.json** — permissions, hooks, telemetry, statusline config + - **CLAUDE.md** — global development standards and tool preferences + - **MCP servers** — Context7, Exa, Granola + - **Statusline script** — two-line status bar with context/cost tracking + - **review-pr command** — multi-agent PR review workflow + - **fix-issue command** — end-to-end issue fixing workflow + +3. **Fetch selected files.** Use WebFetch to download only the files needed for the user's selections from the GitHub URLs above. Extract the raw file content from each response. + +4. **For each selected component, install it:** + + - **settings.json**: If `~/.claude/settings.json` doesn't exist, write it directly. If it does exist, read both files and merge the repo's keys into the existing file — preserve any user keys that don't conflict. Show the user the merged result and ask for confirmation before writing. + + - **CLAUDE.md**: If `~/.claude/CLAUDE.md` doesn't exist, write the fetched `claude-md-template.md` content to `~/.claude/CLAUDE.md`. If it already exists, tell the user it exists and ask whether to overwrite, skip, or show a diff. Never silently overwrite CLAUDE.md — it likely has personal customizations. + + - **MCP servers**: If `~/.mcp.json` doesn't exist, write the fetched template to `~/.mcp.json` and remind the user to replace `your-exa-api-key-here`. If it exists, read it, merge any missing server entries from the template, and show the result before writing. + + - **Statusline script**: Write to `~/.claude/statusline.sh` and `chmod +x` it. Safe to overwrite — it has no user customization. + + - **Commands**: Write to `~/.claude/commands/review-pr.md` and/or `~/.claude/commands/fix-issue.md`. Create the directory if needed. Safe to overwrite. + +5. **Self-install.** After completing the user's selections, also install this setup command itself to `~/.claude/commands/trailofbits/config.md` so the user can run `/trailofbits:config` from any directory in the future without needing the repo cloned. + +6. **Post-install.** Summarize what was installed/updated. If MCP servers were installed, remind the user about the Exa API key. If CLAUDE.md was installed, suggest they review and customize it. diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..bc9c49c --- /dev/null +++ b/.gitignore @@ -0,0 +1,6 @@ +.DS_Store +*.swp +*.swo +*~ +.env +.env.* diff --git a/README.md b/README.md new file mode 100644 index 0000000..52402c6 --- /dev/null +++ b/README.md @@ -0,0 +1,562 @@ +# Trail of Bits Claude Code Config + +Opinionated defaults, documentation, and workflows for Claude Code at Trail of Bits. Covers sandboxing, permissions, hooks, skills, MCP servers, and usage patterns we've found effective across security audits, development, and research. + +**First-time setup:** + +```bash +git clone https://github.com/trailofbits/claude-code-config.git +cd claude-code-config +claude +``` + +Then inside the session, run `/trailofbits:config`. It walks you through installing each component, detects what you already have, and self-installs the command so future runs work from any directory. Run `/trailofbits:config` again after updates. + +## Contents + +**[Getting Started](#getting-started)** +- [Read These First](#read-these-first) +- [Prerequisites](#prerequisites) +- [Shell Setup](#shell-setup) +- [Settings](#settings) +- [Global CLAUDE.md](#global-claudemd) + +**[Configuration](#configuration)** +- [Sandboxing](#sandboxing) +- [Hooks](#hooks) +- [Plugins and Skills](#plugins-and-skills) +- [MCP Servers](#mcp-servers) +- [Fast Mode](#fast-mode) +- [Local Models](#local-models) + +**[Usage](#usage)** +- [Continuous Improvement](#continuous-improvement) +- [Context Management](#context-management) +- [Web Browsing](#web-browsing) +- [Commands](#commands) +- [Recommended Skills](#recommended-skills) + +## Getting Started + +### Read These First + +Before configuring anything, read these to understand the context for why this setup works the way it does: + +- [Best practices for Claude Code](https://code.claude.com/docs/en/best-practices) -- Anthropic's official guide to working effectively with Claude Code +- [Here's how I use LLMs to help me write code](https://simonwillison.net/2025/Mar/11/using-llms-for-code/) -- Simon Willison on practical LLM-assisted coding techniques +- [AI-assisted coding for teams that can't get away with vibes](https://blog.nilenso.com/blog/2025/05/29/ai-assisted-coding/) -- Nilenso's playbook for teams integrating AI tools with high standards +- [My AI Skeptic Friends Are All Nuts](https://fly.io/blog/youre-all-nuts/) -- Thomas Ptacek on why dismissing LLMs for coding is a mistake +- [Harness engineering](https://openai.com/index/harness-engineering/) -- OpenAI on building a product with zero manually-written code + +### Prerequisites + +#### Terminal: Ghostty + +Use [Ghostty](https://ghostty.org). It's the best terminal for Claude Code because it uses native Metal GPU rendering, so it handles the high-volume text output from long AI sessions without lag or memory bloat (~500MB vs ~8GB for two VS Code terminal sessions). Shift+Enter and key bindings work out of the box with no `/terminal-setup` needed, built-in split panes (Cmd+D / Cmd+Shift+D) let you run Claude Code alongside a dev server without tmux, and it never crashes during extended autonomous runs. + +```bash +brew install --cask ghostty +``` + +macOS only. On Linux, see the [Ghostty install docs](https://ghostty.org/docs/install/binary#linux-(official)). No Windows support yet -- use WezTerm there. + +#### Tools + +Install core tools via Homebrew: + +```bash +brew install jq ripgrep fd ast-grep shellcheck shfmt \ + actionlint zizmor macos-trash node@22 pnpm uv +``` + +Python tools (via uv): + +```bash +uv tool install ruff +uv tool install ty +uv tool install pip-audit +``` + +Rust toolchain: + +```bash +curl --proto '=https' --tlsv1.2 -sSf https://sh.rustup.rs | sh +cargo install prek worktrunk cargo-deny cargo-careful +``` + +Node tools: + +```bash +npm install -g oxlint agent-browser +``` + +LM Studio (for [local models](#local-models)): + +```bash +curl -fsSL https://lmstudio.ai/install.sh | bash +``` + +This installs `lms` (the CLI) and `llmster` (the headless daemon). Or install the [LM Studio desktop app](https://lmstudio.ai/download) if you prefer a GUI. + +### Shell Setup + +Add to `~/.zshrc`: + +```bash +alias claude-yolo="claude --dangerously-skip-permissions" +``` + +`--dangerously-skip-permissions` bypasses all permission prompts. This is the recommended way to run Claude Code for maximum throughput -- pair it with sandboxing (below). + +If you're using [local models](#local-models), also add: + +```bash +claude-local() { + ANTHROPIC_BASE_URL=http://localhost:1234 \ + ANTHROPIC_AUTH_TOKEN=lmstudio \ + CLAUDE_CODE_DISABLE_NONESSENTIAL_TRAFFIC=1 \ + claude "$@" +} +``` + +`claude-local` wraps `claude` with the local server env vars and disables telemetry pings that won't reach Anthropic anyway. Use it anywhere you'd normally run `claude`. + +### Settings + +Copy `settings.json` to `~/.claude/settings.json` (or merge entries into your existing file). The `$schema` key enables autocomplete and validation in editors that support JSON Schema. The template includes: + +- **`env` (privacy)** -- disables three non-essential outbound streams: Statsig telemetry (`DISABLE_TELEMETRY`), Sentry error reporting (`DISABLE_ERROR_REPORTING`), and feedback surveys (`CLAUDE_CODE_DISABLE_FEEDBACK_SURVEY`). Avoid the umbrella `CLAUDE_CODE_DISABLE_NONESSENTIAL_TRAFFIC` -- it also disables auto-updates. +- **`env` (agent teams)** -- `CLAUDE_CODE_EXPERIMENTAL_AGENT_TEAMS` enables [multi-agent teams](https://code.claude.com/docs/en/agent-teams) where one session coordinates multiple teammates with independent context windows. Experimental -- known limitations around session resumption and task coordination. +- **`enableAllProjectMcpServers: false`** -- this is the default, set explicitly so it doesn't get flipped by accident. Project `.mcp.json` files live in git, so a compromised repo could ship malicious MCP servers. +- **`alwaysThinkingEnabled: true`** -- persists [extended thinking](https://code.claude.com/docs/en/common-workflows#use-extended-thinking-thinking-mode) across sessions. Toggle per-session with `Option+T`. Adds latency and cost on simple tasks; worth it for complex reasoning. +- **`permissions`** -- deny rules that block reading credentials/secrets and editing shell config (see [Sandboxing](#sandboxing)) +- **`cleanupPeriodDays: 365`** -- keeps conversation history for a year instead of the default 30 days, so `/insights` has more data +- **`hooks`** -- two `PreToolUse` hooks on Bash that block `rm -rf` and direct push to main (see [Hooks](#hooks)) +- **`statusLine`** -- points to the statusline script (see below) + +#### Statusline + +A two-line status bar at the bottom of the terminal: + +``` + claude-code-config │ main │ +42 -17 + Claude Opus 4.6 │ $0.83 │ 12m 34s │ 72% ↻89% +``` + +Line 1 shows the repo name, git branch, and lines changed. Line 2 shows the model, session cost, elapsed time, context window remaining (color-coded: green >50%, yellow >20%, red below), and prompt cache hit rate. + +Copy the script: + +```bash +mkdir -p ~/.claude +cp scripts/statusline.sh ~/.claude/statusline.sh +chmod +x ~/.claude/statusline.sh +``` + +The `statusLine` entry in `settings.json` points to this script. Requires `jq`. + +### Global CLAUDE.md + +The global `CLAUDE.md` file at `~/.claude/CLAUDE.md` sets default instructions for every Claude Code session. It defines code quality limits, tooling preferences, workflow conventions, and skill triggers. + +Copy the template into place: + +```bash +cp claude-md-template.md ~/.claude/CLAUDE.md +``` + +Review and customize it for your own preferences. The template is opinionated -- it assumes specific tools (`ruff`, `ty`, `oxlint`, `cargo clippy`, etc.) and enforces hard limits on function length, complexity, and line width. For background on how CLAUDE.md files work (hierarchy, auto memory, modular rules, imports), see [Manage Claude's memory](https://code.claude.com/docs/en/memory). + +#### Project-level CLAUDE.md + +The global file sets defaults; project-level `CLAUDE.md` files at the repo root add project-specific context. A good project CLAUDE.md includes architecture (directory tree, key abstractions), project-specific commands (`make dev`, `make test`), codebase navigation patterns (ast-grep examples for your codebase), domain-specific APIs and gotchas, and testing conventions unique to the project. + +For an example of a well-structured project CLAUDE.md, see [crytic/slither's CLAUDE.md](https://github.com/crytic/slither/blob/master/CLAUDE.md). It layers slither-specific context -- SlithIR internals, detector traversal patterns, type handling pitfalls -- on top of the same global standards from this repo. + +## Configuration + +### Sandboxing + +At Trail of Bits we run Claude Code in bypass-permissions mode (`--dangerously-skip-permissions`). This means you need to understand your sandboxing options -- the agent will execute commands without asking, so the sandbox is what keeps it from doing damage. + +#### Built-in sandbox (`/sandbox`) + +Claude Code has a native sandbox that provides filesystem and network isolation using OS-level primitives (Seatbelt on macOS, bubblewrap on Linux). Enable it by typing `/sandbox` in a session. In auto-allow mode, Bash commands that stay within sandbox boundaries run without permission prompts. + +**Default behavior:** The agent can write only to the current working directory and its subdirectories, but it can **read the entire filesystem** (except certain denied directories). Network access is restricted to explicitly allowed domains. This means the sandbox protects your system from modification, but doesn't provide read isolation -- the agent can still read `~/.ssh`, `~/.aws`, etc. + +**Hardening reads:** The `settings.json` template in this repo includes `Read` and `Edit` deny rules that block access to credentials and secrets: + +- **SSH/GPG keys** -- `~/.ssh/**`, `~/.gnupg/**` +- **Cloud credentials** -- `~/.aws/**`, `~/.azure/**`, `~/.kube/**`, `~/.docker/config.json` +- **Package registry tokens** -- `~/.npmrc`, `~/.npm/**`, `~/.pypirc`, `~/.gem/credentials` +- **Git credentials** -- `~/.git-credentials`, `~/.config/gh/**` +- **Shell config** -- `~/.bashrc`, `~/.zshrc` (edit denied, prevents backdoor planting) +- **macOS keychain** -- `~/Library/Keychains/**` +- **Crypto wallets** -- metamask, electrum, exodus, phantom, solflare app data + +**How these rules interact with the sandbox:** Permission deny rules and the sandbox are two layers enforcing the same rules. Without `/sandbox`, a `Read(~/.ssh/**)` deny rule only blocks Claude's built-in Read tool -- a Bash command like `cat ~/.ssh/id_rsa` can still reach the file. With `/sandbox` enabled, the sandbox takes the same `Read` and `Edit` deny rules and enforces them at the OS level (Seatbelt/bubblewrap), so Bash commands are also blocked. Use both: deny rules as the baseline, `/sandbox` for OS-level enforcement that survives prompt injection. + +For the design rationale behind sandboxing, see Anthropic's [engineering blog post](https://www.anthropic.com/engineering/claude-code-sandboxing). For the full configuration reference, see the [sandboxing docs](https://code.claude.com/docs/en/sandboxing). + +#### Devcontainer + +For full read and write isolation, use a devcontainer. The agent runs in a container with only the project files mounted -- it has no access to your host filesystem, SSH keys, cloud credentials, or anything else outside the container. + +- [trailofbits/claude-code-devcontainer](https://github.com/trailofbits/claude-code-devcontainer) -- preconfigured devcontainer with VS Code integration, Claude Code pre-installed, and common development tools + +#### Remote droplets + +For complete isolation from your local machine, run the agent on a disposable cloud instance: + +- [trailofbits/dropkit](https://github.com/trailofbits/dropkit) -- CLI tool for managing DigitalOcean droplets with automated setup, SSH config, and Tailscale VPN. Create a droplet, SSH in, run Claude Code, destroy it when done. + +### Hooks + +Hooks are shell commands (or LLM prompts) that fire at specific points in Claude Code's lifecycle. They are a way to talk to the LLM at decision points it wouldn't otherwise pause at. Every `PreToolUse` hook is a chance to say "stop, think about this" or "don't do that, do this instead." Every `PostToolUse` hook is a chance to say "now that you did that, here's what you should know." Every `Stop` hook is a chance to say "you're not done yet." + +This is more powerful than system prompt instructions alone because hooks fire at specific, contextual moments. An instruction in your CLAUDE.md saying "never use `rm -rf`" can be forgotten or overridden by context pressure. A `PreToolUse` hook that blocks `rm -rf` fires every single time, with the error message right at the point of decision. + +Hooks are not a security boundary -- a prompt injection can work around them. They are **structured prompt injection at opportune times**: intercepting tool calls, injecting context, blocking known-bad patterns, and steering agent behavior. Guardrails, not walls. + +In practice, use them to: +- **Block known-bad patterns** -- `rm -rf`, push to main, wrong package manager +- **Add your own logging** -- audit trails, bash command logs, mutation tracking +- **Nudge Claude to keep going** -- a `Stop` hook can review Claude's final response and force it to continue if it's rationalizing incomplete work +- **Inject context at decision points** -- post-write lint results, pre-tool security warnings + +Guide and examples: [Automate workflows with hooks](https://code.claude.com/docs/en/hooks-guide) + +#### Hook events + +| Event | When it fires | Can block? | +|-------|---------------|------------| +| `PreToolUse` | Before a tool call executes | Yes | +| `PostToolUse` | After a tool call succeeds | No (already ran) | +| `UserPromptSubmit` | When user submits a prompt | Yes | +| `Stop` | When Claude finishes responding | Yes (forces continue) | +| `SessionStart` | When a session begins/resumes | No | +| `SubagentStart`/`Stop` | When a subagent spawns/finishes | Start: no, Stop: yes | +| `TaskCompleted` | When a task is marked complete | Yes | +| `TeammateIdle` | When a teammate is about to idle | Yes | + +#### Exit codes + +| Exit code | Behavior | +|-----------|----------| +| 0 | Action allowed (stdout parsed for JSON control) | +| 1 | Error, non-blocking (stderr shown in verbose mode) | +| 2 | Blocking error (stderr fed back to Claude as error message) | + +#### Examples + +> **These are patterns to adapt, not drop-in configs.** Only the two blocking hooks in `settings.json` are recommended defaults. Everything else below is here for inspiration -- read the code, understand what it does, and tailor it to your workflow before using it. + +**Blocking patterns** (`PreToolUse`, in `settings.json`): The two hooks in this repo's `settings.json` block `rm -rf` (suggests `trash` instead) and direct push to main/master (requires feature branches). Both read the Bash command from stdin via `jq`, match with regex, and exit 2 with an error message that tells Claude what to do instead. + +**Audit logging** (`PostToolUse`): [`hooks/log-gam.sh`](hooks/log-gam.sh) shows how to build an audit trail for a CLI tool. This example tracks GAM (Google Apps Manager) commands -- it classifies each as read or write using verb pattern lists, skips reads, and logs mutations with timestamp, action, command, and exit status. The pattern generalizes: swap the verb lists for any CLI where you want to log mutations. Wire it up as a `PostToolUse` hook on `Bash`. + +**Bash command log** (`PostToolUse`): Appends every Bash command the agent runs to a log file with a timestamp. Useful for post-session review of what the agent actually did. + +```json +{ + "PostToolUse": [ + { + "matcher": "Bash", + "hooks": [ + { + "type": "command", + "command": "jq -r '\"[\" + (now | todate) + \"] \" + .tool_input.command' >> ~/.claude/bash-commands.log" + } + ] + } + ] +} +``` + +**Desktop notifications** (`Notification`): Fires a native OS notification when Claude needs your attention, so you can switch to other work during long autonomous runs instead of watching the terminal. + +```json +{ + "Notification": [ + { + "matcher": "", + "hooks": [ + { + "type": "command", + "command": "osascript -e 'display notification \"Claude needs your attention\" with title \"Claude Code\"'" + } + ] + } + ] +} +``` + +On Linux, replace the command with `notify-send 'Claude Code' 'Claude needs your attention'`. + +**Enforce package manager** (`PreToolUse`): [`hooks/enforce-package-manager.sh`](hooks/enforce-package-manager.sh) blocks `npm` commands in projects that use `pnpm` and tells Claude to use the right tool. Generalizes to any "use X not Y" convention. + +**Anti-rationalization gate** (`Stop`, prompt hook): Claude has a tendency to declare victory while leaving work undone. It rationalizes skipping things: "these issues were pre-existing," "fixing this is out of scope," "I'll leave these for a follow-up." A prompt-based `Stop` hook catches this by asking a fast model to review Claude's final response for cop-outs before allowing it to stop. + +```json +{ + "Stop": [ + { + "hooks": [ + { + "type": "prompt", + "prompt": "Review the assistant's final response. Reject it if the assistant is rationalizing incomplete work. Common patterns: claiming issues are 'pre-existing' or 'out of scope' to avoid fixing them, saying there are 'too many issues' to address all of them, deferring work to a 'follow-up' that was not requested, listing problems without fixing them and calling that done, or skipping test/lint failures with excuses. If the response shows any of these patterns, respond {\"ok\": false, \"reason\": \"You are rationalizing incomplete work. [specific issue]. Go back and finish.\"}. If the work is genuinely complete, respond {\"ok\": true}." + } + ] + } + ] +} +``` + +This uses `type: "prompt"` instead of `type: "command"` -- Claude Code sends the hook's prompt plus the assistant's response to a fast model (Haiku), which returns a yes/no judgment. If rejected, the `reason` is fed back to Claude as its next instruction, forcing it to continue. + +### Plugins and Skills + +Claude Code's capabilities come from plugins, which provide skills (reusable workflows), agents (specialized subagents), and commands (slash commands). Plugins are distributed through marketplaces. + +#### Trail of Bits marketplaces + +Install the three Trail of Bits marketplaces: + +```bash +claude plugin marketplace add trailofbits/skills +claude plugin marketplace add trailofbits/skills-internal +claude plugin marketplace add trailofbits/skills-curated +``` + +| Repository | Description | +|------------|-------------| +| [trailofbits/skills](https://github.com/trailofbits/skills) | Security auditing, code review, smart contract analysis, reverse engineering, and development workflows. Open source -- contributions welcome. | +| [trailofbits/skills-internal](https://github.com/trailofbits/skills-internal) | Internal skills: report writing, scoping, recruiting, brand tools, and client-specific workflows. Private to Trail of Bits. | +| [trailofbits/skills-curated](https://github.com/trailofbits/skills-curated) | Vetted third-party skills and the canonical list of approved external marketplaces. | + +For external marketplaces (Anthropic official, superpowers, compound-engineering, etc.), see [skills-curated](https://github.com/trailofbits/skills-curated) -- it maintains the approved list and install scripts. + +#### Publishing skills + +Where to publish depends on the audience: + +- **Public and open source** -- submit a PR to [trailofbits/skills](https://github.com/trailofbits/skills). See its [CLAUDE.md](https://github.com/trailofbits/skills/blob/main/CLAUDE.md) for authoring guidelines. +- **Internal to Trail of Bits** -- submit a PR to [trailofbits/skills-internal](https://github.com/trailofbits/skills-internal). +- **Third-party skill you want approved** -- submit a PR to [trailofbits/skills-curated](https://github.com/trailofbits/skills-curated) with attribution to the original source. Every PR gets code review. + +#### Writing custom skills + +When you find yourself repeating the same multi-step workflow, extract it into a skill. Read Anthropic's [skill authoring best practices](https://platform.claude.com/docs/en/agents-and-tools/agent-skills/best-practices) for guidance on structure, descriptions, and testing. + +The short version: don't write skills by hand. Ask Claude to create one for you — Anthropic ships a [skill creator](https://github.com/anthropics/skills/blob/main/skills/skill-creator/SKILL.md) skill for this. When you notice yourself repeating the same workflow, ask Claude to extract it into a skill. Be specific in the description so Claude knows when to activate it. + +The `plugin-dev` plugin (included by default from `claude-plugins-official`) provides `/skill-development` to extract skills from conversations and a `skill-reviewer` agent to check them against Anthropic's best practices. + +### MCP Servers + +Everyone at Trail of Bits should set up at least **Context7** and **Exa** as global MCP servers. Granola is a useful third if you use it for meeting notes. + +| Server | What it does | Requirements | +|--------|-------------|--------------| +| Context7 | Up-to-date library documentation lookup | None (no API key) | +| Exa | Web and code search (see [Web Browsing](#web-browsing)) | `EXA_API_KEY` env var ([get one here](https://exa.ai)) | +| Granola | Meeting notes and transcripts | Granola app with paid plan | + +#### Setup + +MCP servers are configured in `.mcp.json` files. Claude Code merges configs from two locations: + +- **`~/.mcp.json`** -- global servers available in every session +- **`.mcp.json` in the project root** -- project-specific servers + +Copy `mcp-template.json` from this repo to `~/.mcp.json` for global availability. Replace `your-exa-api-key-here` with your actual key, or remove the `exa` entry if you don't have one. Add project-specific MCP servers (e.g., a local database tool) to the project's `.mcp.json`. + +### Fast Mode + +`/fast` toggles fast mode. Same Opus 4.6 model, ~2.5x faster output, 6x the cost per token. Leave it off by default. + +The only time fast mode is worth it is **tight interactive loops** -- you're debugging live, iterating on output, and every second of latency costs you focus. If you're about to kick off an autonomous run (`/fix-issue`, a swarm, anything you walk away from), turn it off first. The agent doesn't benefit from lower latency; you're just burning money. + +If you do use it, enable it at session start. Toggling it on mid-conversation reprices your entire context at fast-mode rates and invalidates prompt cache. See the [fast mode docs](https://code.claude.com/docs/en/fast-mode) for details. + +### Local Models + +Use [LM Studio](https://lmstudio.ai) to run local LLMs with Claude Code. LM Studio provides an Anthropic-compatible `/v1/messages` endpoint, so Claude Code connects with just a base URL change. On macOS it uses MLX for Apple Silicon-native inference, which is significantly faster than GGUF. + +#### Recommended model: Qwen3-Coder-Next (as of February 2026) + +[Qwen3-Coder-Next](https://lmstudio.ai/models/qwen3-coder-next) is an 80B mixture-of-experts model with only 3B active parameters, designed specifically for agentic coding. It handles tool use, long-horizon reasoning, and recovery from execution failures. The MLX 4-bit quantization is ~45GB and needs at least 64GB unified memory to load with a usable context window. 96GB or more is comfortable. + +Local models move fast. When this recommendation is stale, check the [LM Studio featured models page](https://lmstudio.ai/models) and pick the top coding model that fits in your memory as an MLX 4-bit quantization. + +#### Setup + +Download, load, and serve -- all from the CLI: + +```bash +lms get lmstudio-community/Qwen3-Coder-Next-MLX-4bit -y +lms load lmstudio-community/Qwen3-Coder-Next-MLX-4bit --context-length 32768 --gpu max -y +lms server start +``` + +`--context-length 32768` allocates a 32K context window at load time. Claude Code is context-heavy, so don't go below 25K. Sampling parameters (temperature, top-p, etc.) don't need to be configured on the server -- Claude Code sends its own in each API request. + +#### Connecting + +Point Claude Code at LM Studio by setting the base URL and an auth token (any string works for local servers): + +```bash +ANTHROPIC_BASE_URL=http://localhost:1234 \ +ANTHROPIC_AUTH_TOKEN=lmstudio \ +claude +``` + +Or use the `claude-local` shell function from [Shell Setup](#shell-setup) to avoid typing the env vars every time. + +#### Environment variables + +| Variable | Purpose | +|----------|---------| +| `ANTHROPIC_BASE_URL` | API endpoint (e.g., `http://localhost:1234`) | +| `ANTHROPIC_AUTH_TOKEN` | API key (any string for local servers) | +| `ANTHROPIC_DEFAULT_SONNET_MODEL` | Default model for most operations | +| `ANTHROPIC_DEFAULT_OPUS_MODEL` | Model for opus-tier tasks | +| `ANTHROPIC_DEFAULT_HAIKU_MODEL` | Model for summarization tasks | +| `CLAUDE_CODE_SUBAGENT_MODEL` | Model for subagent tasks | +| `CLAUDE_CODE_DISABLE_NONESSENTIAL_TRAFFIC` | Set to `1` to disable all non-essential traffic (includes auto-updates) | + +## Usage + +Read Anthropic's [Best practices for Claude Code](https://code.claude.com/docs/en/best-practices) before anything in this section. It's the single most important resource for getting good results. Everything below builds on it. + +### Continuous Improvement + +Most people's use of Claude Code plateaus early. You find a workflow that works, repeat it, and never discover what you're leaving on the table. The fix is a deliberate feedback loop: review what happened, adjust your setup, and let the next week benefit from what you learned. + +Run `/insights` once a week. It analyzes your recent sessions and surfaces patterns -- what's working, what's failing, where you're spending time. When it tells you something useful, act on it: add a rule to your CLAUDE.md, write a hook to block a mistake you keep making, extract a repeated workflow into a skill. Each adjustment compounds. After a few weeks your setup is meaningfully different from the defaults, tuned to how you actually work. + +### Output Styles + +Enable the **Explanatory** [output style](https://code.claude.com/docs/en/output-styles) (`/output-style explanatory` or `"outputStyle": "Explanatory"` in `settings.json`) when getting familiar with a new codebase. Claude explains frameworks and code patterns as it works, adding "★ Insight" blocks with reasoning and design choices alongside its normal output. Useful when auditing unfamiliar code, reviewing a language you don't write daily, or onboarding onto a client engagement. The tradeoff is context: longer responses mean earlier compaction. Switch back to the default when you want speed. You can also [create custom styles](https://code.claude.com/docs/en/output-styles) as markdown files in `~/.claude/output-styles/`. + +You can also customize the spinner verbs that appear while Claude is working. Ask Claude: "In my settings, make my spinner verbs Star Trek themed." + +### Context Management + +The context window is finite and irreplaceable mid-session. Every file read, tool call, and conversation turn consumes it. When it fills up, Claude auto-compacts -- summarizing the conversation to free space. Auto-compaction works, but it's lossy: subtle decisions, error details, and the thread of reasoning degrade each time. The best strategy is to avoid needing it. + +#### Keeping sessions clean + +**Scope work to one session.** Each feature, bug fix, or investigation should fit within a single context window. If a task is too large, break it into pieces and run each in a fresh session. This is the single most effective thing you can do for quality. + +A session that stays within its context budget produces better code than one that compacts three times to limp across the finish line. When you notice context running low (check the statusline -- green >50%, yellow >20%, red below), it's time to wrap up and start a new session, not push through. + +**Prefer `/clear` over `/compact`.** `/clear` wipes the conversation and starts fresh. `/compact` summarizes and continues. Default to `/clear` between tasks. + +`/compact` is useful when you're mid-task and need to reclaim space without losing your place, but each compaction is a lossy compression -- details get dropped, and the model's understanding of your intent degrades slightly. Two compactions in a session is a sign the task was too large. `/clear` has no information loss because there's nothing to lose -- your CLAUDE.md reloads, git state is fresh, and the agent re-reads whatever files it needs. When you do use `/compact`, pass focus instructions to steer the summary: `/compact Focus on the auth refactor` preserves what matters and sheds the rest. + +**Cut your losses after two corrections.** If you've corrected Claude twice on the same issue and it's still wrong, don't keep pushing -- the context is polluted with failed approaches. Use checkpoints (`Esc Esc` or `/rewind`) to roll back to before the first wrong attempt and try again with a better prompt. If the session is too far gone even for that, `/clear` and start fresh. A clean prompt that incorporates what you learned almost always outperforms a long session with accumulated corrections. + +#### Tools for managing context + +**Checkpoints** (`Esc Esc` or `/rewind`) restore code and conversation to any previous prompt in the session. They're your undo system -- use them aggressively. Try risky approaches knowing you can rewind if they don't work out. + +The "Summarize from here" option in the rewind menu is a more surgical alternative to `/compact`: instead of compressing everything, you keep early context intact and only summarize the part that's eating space (like a verbose debugging tangent). This preserves your initial instructions at full fidelity. + +**Offload research to subagents.** Subagents (Task tool, custom agents) each get their own context window. The main session only sees the subagent's summary, not its full working context. + +Use this deliberately: when a task requires reading a lot of documentation, exploring unfamiliar code, or doing research that would bloat your main session, delegate it to a subagent. The main session stays lean and focused on implementation while subagents handle the context-heavy exploration. + +**For complex features, interview first, implement second.** Have Claude interview you about the feature (requirements, edge cases, tradeoffs), then write a spec to a file. Start a fresh session to implement the spec. + +**Put stable context in CLAUDE.md, not the conversation.** Project architecture, coding standards, tool preferences, workflow conventions -- anything reusable goes in CLAUDE.md. It loads automatically every session and survives `/clear`. + +If you need to pass context between sessions, commit your work, write a brief plan to a file, `/clear`, and start the next session by pointing Claude at that file. You can also resume previous sessions with `claude --continue` (picks up the last session) or `claude --resume` (lets you choose from recent sessions). But a fresh session with a written handoff is usually better than resuming a stale one -- the context is cleaner and the prompt cache is warm. + +### Web Browsing + +Claude Code has three ways to interact with the web. + +#### Exa AI (MCP) + +Semantic web search that returns clean, LLM-optimized text. Unlike the built-in `WebSearch` tool (which returns search result links that Claude then has to fetch and parse), Exa returns the actual content pre-extracted and formatted for LLM consumption. This saves context window and produces more relevant results. Your CLAUDE.md can instruct Claude to prefer Exa over `WebSearch`. + +#### agent-browser + +Headless browser automation via CLI. Runs its own Chromium instance -- it does **not** share your Chrome profile, cookies, or login sessions. This means it can't access authenticated pages (Google Docs, internal dashboards, etc.) without logging in from scratch. What it excels at is context efficiency: the snapshot/ref system (`@e1`, `@e2`) uses ~93% less context than sending full accessibility trees, so the agent can navigate complex multi-page workflows without exhausting its context window. Also supports video recording and parallel sessions. + +```bash +agent-browser open # Navigate +agent-browser snapshot -i # Get element refs (@e1, @e2) +agent-browser click @e1 # Click element +agent-browser fill @e2 "text" # Fill input +agent-browser screenshot # Capture screenshot +``` + +#### Claude in Chrome (MCP) + +Browser automation via the [Claude in Chrome](https://chromewebstore.google.com/detail/claude/fcoeoabgfenejglbffodgkkbkcdhcgfn) extension. Operates inside your actual Chrome browser, so it has access to your existing login sessions, cookies, and extensions. This is the only option that can interact with authenticated pages (Gmail, Google Docs, Jira, internal tools) without re-authenticating. The tradeoff is that it uses screenshots and accessibility trees for page understanding, which consumes more context than agent-browser's ref system. + +#### When to use which + +| Need | Use | +|------|-----| +| Search the web for information | Exa | +| Automate multi-step workflows on public pages | agent-browser | +| Interact with authenticated/internal pages | Claude in Chrome | +| Record a video of browser actions | agent-browser | +| Inspect visual layout or take screenshots for analysis | Claude in Chrome | + +### Commands + +Custom slash commands are markdown files that define reusable workflows. The two in `commands/` were extracted from manual workflows that kept showing up in `/insights` -- if you notice yourself repeating the same multi-step sequence, it's a good candidate for a command. + +```bash +mkdir -p ~/.claude/commands +cp commands/review-pr.md ~/.claude/commands/ +cp commands/fix-issue.md ~/.claude/commands/ +``` + +#### Review PR + +[`commands/review-pr.md`](commands/review-pr.md) -- Reviews a GitHub PR with parallel agents, fixes findings, and pushes. Invoke with `/review-pr 456` where `456` is the PR number. + +#### Fix Issue + +[`commands/fix-issue.md`](commands/fix-issue.md) -- Takes a GitHub issue and fully autonomously completes it -- plans, implements, tests, creates a PR, self-reviews with parallel agents, fixes its own findings, and comments on the issue when done. Invoke with `/fix-issue 123` where `123` is the issue number. + +Once a workflow is a command, it's not just faster for you -- it's something an agent can run too. You can point `/fix-issue` at 50 issues in parallel across worktrees, run `/review-pr` on every open PR in a repo, or schedule either as part of CI. Commands turn manual workflows into scalable operations. + +### Recommended Skills + +Skills come from plugins you install via the Trail of Bits marketplaces and third-party marketplaces. Here are the ones worth knowing about from each. + +#### Trail of Bits ([trailofbits/skills](https://github.com/trailofbits/skills)) + +Security auditing, code analysis, and development workflows. Installed automatically with the Trail of Bits marketplace. + +| Skill | What it does | When to use it | +|-------|-------------|----------------| +| `ask-questions-if-underspecified` | Asks 1-5 targeted clarification questions before starting work | Any underspecified request -- prevents building the wrong thing | +| `modern-python` | Configures projects with uv, ruff, ty, pytest, prek | New Python projects or migrating from pip/Poetry/mypy/black | +| `audit-context-building` | Line-by-line code analysis using First Principles and 5 Whys methodology | Building deep understanding of unfamiliar code before an audit | +| `differential-review` | Security-focused review of code changes with blast radius analysis | Reviewing PRs or commits where security impact matters | + +#### Superpowers ([obra/superpowers](https://github.com/obra/superpowers)) + +Workflow discipline -- enforces planning before coding, structured debugging, and verification before declaring victory. The skills chain together: brainstorm → plan → execute → verify. + +| Skill | What it does | When to use it | +|-------|-------------|----------------| +| `/superpowers:brainstorm` | Refines ideas through Socratic questioning before implementation | Starting any non-trivial feature -- catches unclear requirements early | +| `/superpowers:systematic-debugging` | Structured 4-phase root cause analysis | Any bug where the cause isn't obvious -- prevents treating symptoms | + +#### Compound Engineering ([EveryInc/compound-engineering-plugin](https://github.com/EveryInc/compound-engineering-plugin)) + +Multi-agent workflows for planning and review. + +| Skill | What it does | When to use it | +|-------|-------------|----------------| +| `/workflows:plan` | Turns feature descriptions into implementation plans with parallel research agents | Starting a feature that touches multiple files or components | +| `/workflows:review` | Runs 15 specialized review agents in parallel (security, performance, architecture, style) | Before merging any significant PR -- catches what solo review misses | diff --git a/claude-md-template.md b/claude-md-template.md new file mode 100644 index 0000000..91db522 --- /dev/null +++ b/claude-md-template.md @@ -0,0 +1,207 @@ +# Global Development Standards + +Global instructions for all projects. Project-specific CLAUDE.md files override these defaults. + +- Prefer Exa AI (`mcp__exa__web_search_exa`) over `WebSearch` for all web searches +- Use skills proactively when they match the task — suggest relevant ones, don't block on them + +## Philosophy + +- **No speculative features** - Don't add features, flags, or configuration unless users actively need them +- **No premature abstraction** - Don't create utilities until you've written the same code three times +- **Clarity over cleverness** - Prefer explicit, readable code over dense one-liners +- **Justify new dependencies** - Each dependency is attack surface and maintenance burden +- **No phantom features** - Don't document or validate features that aren't implemented +- **Replace, don't deprecate** - When a new implementation replaces an old one, remove the old one entirely. No backward-compatible shims, dual config formats, or migration paths. Proactively flag dead code — it adds maintenance burden and misleads both developers and LLMs. +- **Verify at every level** - Set up automated guardrails (linters, type checkers, pre-commit hooks, tests) as the first step, not an afterthought. Prefer structure-aware tools (ast-grep, LSPs, compilers) over text pattern matching. Review your own output critically. Every layer catches what the others miss. +- **Bias toward action** - Decide and move for anything easily reversed; state your assumption so the reasoning is visible. Ask before committing to interfaces, data models, architecture, or destructive/write operations on external services. +- **Finish the job** - Don't stop at the minimum that technically satisfies the request. Handle the edge cases you can see. Clean up what you touched. If something is broken adjacent to your change, flag it. But don't invent new scope — there's a difference between thoroughness and gold-plating. +- **Agent-native by default** - Design so agents can achieve any outcome users can. Tools are atomic primitives; features are outcomes described in prompts. Prefer file-based state for transparency and portability. When adding UI capability, ask: can an agent achieve this outcome too? + +## Code Quality + +### Hard limits + +1. ≤100 lines/function, cyclomatic complexity ≤8 +2. ≤5 positional params +3. 100-char line length +4. Absolute imports only — no relative (`..`) paths +5. Google-style docstrings on non-trivial public APIs + +### Zero warnings policy + +Fix every warning from every tool — linters, type checkers, compilers, tests. If a warning truly can't be fixed, add an inline ignore with a justification comment. Never leave warnings unaddressed; a clean output is the baseline, not the goal. + +### Comments + +Code should be self-documenting. No commented-out code—delete it. If you need a comment to explain WHAT the code does, refactor the code instead. + +### Error handling + +- Fail fast with clear, actionable messages +- Never swallow exceptions silently +- Include context (what operation, what input, suggested fix) + +### Reviewing code + +Evaluate in order: architecture → code quality → tests → performance. Before reviewing, sync to latest remote (`git fetch origin`). + +For each issue: describe concretely with file:line references, present options with tradeoffs when the fix isn't obvious, recommend one, and ask before proceeding. + +### Testing + +**Test behavior, not implementation.** Tests should verify what code does, not how. If a refactor breaks your tests but not your code, the tests were wrong. + +**Test edges and errors, not just the happy path.** Empty inputs, boundaries, malformed data, missing files, network failures — bugs live in edges. Every error path the code handles should have a test that triggers it. + +**Mock boundaries, not logic.** Only mock things that are slow (network, filesystem), non-deterministic (time, randomness), or external services you don't control. + +**Verify tests catch failures.** Break the code, confirm the test fails, then fix. Use mutation testing (`cargo-mutants`, `mutmut`) to verify systematically. Use property-based testing (`proptest`, `hypothesis`) for parsers, serialization, and algorithms. + +## Development + +When adding dependencies, CI actions, or tool versions, always look up the current stable version — never assume from memory unless the user provides one. + +### CLI tools + +| tool | replaces | usage | +|------|----------|-------| +| `rg` (ripgrep) | grep | `rg "pattern"` - 10x faster regex search | +| `fd` | find | `fd "*.py"` - fast file finder | +| `ast-grep` | - | `ast-grep --pattern '$FUNC($$$)' --lang py` - AST-based code search | +| `shellcheck` | - | `shellcheck script.sh` - shell script linter | +| `shfmt` | - | `shfmt -i 2 -w script.sh` - shell formatter | +| `actionlint` | - | `actionlint .github/workflows/` - GitHub Actions linter | +| `zizmor` | - | `zizmor .github/workflows/` - Actions security audit | +| `prek` | pre-commit | `prek run` - fast git hooks (Rust, no Python) | +| `wt` | git worktree | `wt switch branch` - manage parallel worktrees | +| `trash` | rm | `trash file` - moves to macOS Trash (recoverable). **Never use `rm -rf`** | + +Prefer `ast-grep` over ripgrep when searching for code structure (function calls, class definitions, imports, pattern matching across arguments). Use ripgrep for literal strings and log messages. + +### Python + +**Runtime:** 3.13 with `uv venv` + +| purpose | tool | +|---------|------| +| deps & venv | `uv` | +| lint & format | `ruff check` · `ruff format` | +| static types | `ty check` | +| tests | `pytest -q` | + +**Always use uv, ruff, and ty** over pip/poetry, black/pylint/flake8, and mypy/pyright — they're faster and stricter. Configure `ty` strictness via `[tool.ty.rules]` in pyproject.toml. Use `uv_build` for pure Python, `hatchling` for extensions. + +Tests in `tests/` directory mirroring package structure. Supply chain: `pip-audit` before deploying, pin exact versions (`==` not `>=`), verify hashes with `uv pip install --require-hashes`. + +### Node/TypeScript + +**Runtime:** Node 22 LTS, ESM only (`"type": "module"`) + +| purpose | tool | +|---------|------| +| lint | `oxlint` | +| format | `oxfmt` | +| test | `vitest` | +| types | `tsc --noEmit` | + +**Always use oxlint and oxfmt** over eslint/prettier — they're faster and stricter. Enable `typescript`, `import`, `unicorn` plugins. + +**tsconfig.json strictness** — enable all of these: +```jsonc +"strict": true, +"noUncheckedIndexedAccess": true, +"exactOptionalPropertyTypes": true, +"noImplicitOverride": true, +"noPropertyAccessFromIndexSignature": true, +"verbatimModuleSyntax": true, +"isolatedModules": true +``` + +Colocated `*.test.ts` files. Supply chain: `pnpm audit --audit-level=moderate` before installing, pin exact versions (no `^` or `~`), enforce 24-hour publish delay (`pnpm config set minimumReleaseAge 1440`), block postinstall scripts (`pnpm config set ignore-scripts true`). + +### Rust + +**Runtime:** Latest stable via `rustup` + +| purpose | tool | +|---------|------| +| build & deps | `cargo` | +| lint | `cargo clippy --all-targets --all-features -- -D warnings` | +| format | `cargo fmt` | +| test | `cargo test` | +| supply chain | `cargo deny check` (advisories, licenses, bans) | +| safety check | `cargo careful test` (stdlib debug assertions + UB checks) | + +**Style:** +- Prefer `for` loops with mutable accumulators over iterator chains +- Shadow variables through transformations (no `raw_x`/`parsed_x` prefixes) +- No wildcard matches; avoid `matches!` macro—explicit destructuring catches field changes +- Use `let...else` for early returns; keep happy path unindented + +**Type design:** +- Newtypes over primitives (`UserId(u64)` not `u64`) +- Enums for state machines, not boolean flags +- `thiserror` for libraries, `anyhow` for applications +- `tracing` for logging (`error!`/`warn!`/`info!`/`debug!`), not println + +**Optimization:** +- Write efficient code by default — correct algorithm, appropriate data structures, no unnecessary allocations +- Profile before micro-optimizing; measure after + +**Cargo.toml lints:** +```toml +[lints.clippy] +pedantic = { level = "warn", priority = -1 } +# Panic prevention +unwrap_used = "deny" +expect_used = "warn" +panic = "deny" +panic_in_result_fn = "deny" +unimplemented = "deny" +# No cheating +allow_attributes = "deny" +# Code hygiene +dbg_macro = "deny" +todo = "deny" +print_stdout = "deny" +print_stderr = "deny" +# Safety +await_holding_lock = "deny" +large_futures = "deny" +exit = "deny" +mem_forget = "deny" +# Pedantic relaxations (too noisy) +module_name_repetitions = "allow" +similar_names = "allow" +``` + +### Bash + +All scripts must start with `set -euo pipefail`. Lint: `shellcheck script.sh && shfmt -d script.sh` + +### GitHub Actions + +Pin actions to SHA hashes with version comments: `actions/checkout@ # vX.Y.Z` (use `persist-credentials: false`). Scan workflows with `zizmor` before committing. Configure Dependabot with 7-day cooldowns and grouped updates. + +## Workflow + +**Before committing:** +1. Re-read your changes for unnecessary complexity, redundant code, and unclear naming +2. Run relevant tests — not the full suite +3. Run linters and type checker — fix everything before committing + +**Commits:** +- Imperative mood, ≤72 char subject line, one logical change per commit +- Never amend/rebase commits already pushed to shared branches +- Never push directly to main — use feature branches and PRs +- Never commit secrets, API keys, or credentials — use `.env` files (gitignored) and environment variables + +**Hooks and worktrees:** +- Install prek in every repo (`prek install`). Run `prek run` before committing. Configure auto-updates: `prek auto-update --cooldown-days 7` +- Parallel subagents require worktrees. Each subagent MUST work in its own worktree (`wt switch `), not the main repo. Never share working directories. + +**Pull requests:** +Describe what the code does now — not discarded approaches, prior iterations, or alternatives. Only describe what's in the diff. + +Use plain, factual language. A bug fix is a bug fix, not a "critical stability improvement." Avoid: critical, crucial, essential, significant, comprehensive, robust, elegant. diff --git a/commands/fix-issue.md b/commands/fix-issue.md new file mode 100644 index 0000000..d9b0623 --- /dev/null +++ b/commands/fix-issue.md @@ -0,0 +1,97 @@ +# Fix GitHub Issue + +@description End-to-end: plan, implement, test, PR, review, fix findings, and comment on a GitHub issue. +@arguments $ISSUE_NUMBER: GitHub issue number to fix + +Read GitHub Issue #$ISSUE_NUMBER thoroughly. Understand the full +context: problem description, acceptance criteria, linked PRs, +and any discussion. Follow linked issues, referenced PRs, and +external documentation to build complete understanding before +planning. + +Execute every step below sequentially. Do not stop or ask for +confirmation at any step. + +## 1. Plan + +Write a detailed implementation plan to `plan-issue-$ISSUE_NUMBER.md` +in the repo root. The plan must: + +- Summarize the issue requirements +- List every file to create or modify +- Describe the approach and key design decisions +- Call out risks or open questions +- Reference relevant code paths by file:line + +## 2. Implement + +Implement the plan across all necessary files. Follow the +project's CLAUDE.md standards. Keep changes minimal and focused +on the issue requirements -- no speculative features. + +## 3. Build, test, lint + +Run the project's full quality pipeline in this order: + +1. Build (compile/bundle if the project has a build step) +2. Run the full test suite -- iterate on failures until green +3. Add new tests for the changed behavior +4. Run linting, formatting, and type-checking -- fix any issues + +Refer to the project's CLAUDE.md or package.json/Makefile/etc. +for the correct commands. + +## 4. Branch, commit, and push + +- Determine the branch prefix from the issue type: `fix/` for + bugs, `feat/` for features, `refactor/` for refactors, `docs/` + for documentation. When ambiguous, use `fix/`. +- Create a branch named `{prefix}issue-$ISSUE_NUMBER` +- Delete the plan file (`plan-issue-$ISSUE_NUMBER.md`) -- it was a + working artifact and should not be committed +- Commit all changes with a conventional commit message referencing + the issue +- Push the branch + +## 5. Create PR + +Create a PR with: + +- A concise title (under 70 chars) +- A description that maps changes back to the issue requirements +- Link to the issue with "Closes #$ISSUE_NUMBER" (or "Refs" if it + doesn't fully close it) + +## 6. Self-review + +Use `/compound-engineering:workflows:review` to perform a full +multi-agent code review of the PR. Produce a list of findings +ranked by severity (P1 = blocks merge, P2 = important, P3 = nice +to have). + +## 7. Fix findings + +Address all P1-P3 findings. For each finding, either: + +- **Fix it** -- apply the change, or +- **Dismiss it** -- explain why it's a false positive or not worth + the churn (e.g. a stylistic disagreement or an impossible edge + case). Document the reasoning inline. + +After addressing all findings: + +1. Re-run the full quality pipeline (build, test, lint) +2. Commit the fixes as a separate commit (do not squash into the + original -- preserve review history) +3. Push the branch (regular push, not force-push) +4. Delete any todo files in `todos/` that were created by the + review and are now resolved + +## 8. Comment on issue + +Post a summary comment on Issue #$ISSUE_NUMBER linking to the PR. +Include: + +- What was implemented (1-3 bullet points) +- Key design decisions +- Link to the PR diff --git a/commands/review-pr.md b/commands/review-pr.md new file mode 100644 index 0000000..3398821 --- /dev/null +++ b/commands/review-pr.md @@ -0,0 +1,60 @@ +# Review and Fix PR + +@description Review an existing PR with parallel agents, fix findings, and push. +@arguments $PR_NUMBER: GitHub PR number to review and fix + +Read PR #$PR_NUMBER thoroughly using `gh pr view`. Understand the +full context: description, linked issues, commit history, and the +diff against the base branch. Check out the PR branch locally. + +Execute every step below sequentially. Do not stop or ask for +confirmation at any step. + +## 1. Review + +Use `/compound-engineering:workflows:review` to perform a full +multi-agent code review of PR #$PR_NUMBER. Produce a list of +findings ranked by severity (P1 = blocks merge, P2 = important, +P3 = nice to have, P4 = informational). + +## 2. Fix findings + +Address all P1-P3 findings. For each finding, either: + +- **Fix it** -- apply the change, or +- **Dismiss it** -- explain why it's a false positive or not worth + the churn (e.g. a stylistic disagreement or an impossible edge + case). Document the reasoning inline. + +P4 findings are informational -- note them but do not fix unless +trivial. + +## 3. Verify + +Run the project's full quality pipeline: + +1. Build (compile/bundle if the project has a build step) +2. Run the full test suite -- iterate on failures until green +3. Run linting, formatting, and type-checking -- fix any issues + +Refer to the project's CLAUDE.md or package.json/Makefile/etc. +for the correct commands. + +## 4. Commit and push + +- Commit the fixes as a separate commit (do not squash into the + original -- preserve review history) +- Use commit message: `fix: resolve code review findings for + PR #$PR_NUMBER` +- Push the branch (regular push, not force-push) +- Delete any todo files in `todos/` that were created by the + review and are now resolved + +## 5. Post summary + +Add a comment on PR #$PR_NUMBER summarizing what was done: + +- Total findings by severity (e.g. "3 P2, 5 P3") +- How many were fixed vs dismissed (with brief reasoning for + any dismissals) +- Confirmation that the quality pipeline passes diff --git a/hooks/enforce-package-manager.sh b/hooks/enforce-package-manager.sh new file mode 100755 index 0000000..7f753ff --- /dev/null +++ b/hooks/enforce-package-manager.sh @@ -0,0 +1,15 @@ +#!/bin/bash +set -euo pipefail +# EXAMPLE: PreToolUse hook — blocks npm in projects that use pnpm. +# Adapt for any "use X not Y" convention (e.g., yarn vs npm, uv vs pip). +CMD=$(jq -r '.tool_input.command // empty') +[[ -z "$CMD" ]] && exit 0 + +# Only enforce if this project uses pnpm +[[ ! -f "${CLAUDE_PROJECT_DIR}/pnpm-lock.yaml" ]] && exit 0 + +if echo "$CMD" | grep -qE '^npm\s'; then + echo "BLOCKED: This project uses pnpm, not npm. Use pnpm instead." >&2 + exit 2 +fi +exit 0 diff --git a/hooks/log-gam.sh b/hooks/log-gam.sh new file mode 100755 index 0000000..b5a1feb --- /dev/null +++ b/hooks/log-gam.sh @@ -0,0 +1,45 @@ +#!/bin/bash +set -euo pipefail +# EXAMPLE: PostToolUse hook — logs GAM (Google Apps Manager) write operations +# to JSONL. Adapt the verb patterns for any CLI tool where you want an audit +# trail of mutations. See README.md for wiring instructions. +INPUT=$(cat) +COMMAND=$(echo "${INPUT}" | jq -r '.tool_input.command // empty') + +[[ -z "${COMMAND}" ]] && exit 0 +[[ "${COMMAND}" != *'gam7/gam '* ]] && exit 0 + +# Verb lists verified against GamCommands.txt v7.33.00 +READ_PATTERN='(print|show|info|get|list|report|check|version|help)' +WRITE_PATTERN='(create|add|update|delete|remove|suspend|unsuspend|wipe|sync|move|transfer|trash|purge|enable|disable|deprovision)' + +GAM_ARGS="${COMMAND#*gam7/gam }" +FIRST_WORD="${GAM_ARGS%% *}" + +# Skip read operations +echo "${FIRST_WORD}" | grep -qiE "^${READ_PATTERN}$" && exit 0 + +# Match write verb +ACTION=$(echo "${GAM_ARGS}" | grep -oiE "(^|[[:space:]])${WRITE_PATTERN}([[:space:]]|$)" \ + | head -1 | tr -d ' ' || true) +[[ -z "${ACTION}" ]] && exit 0 + +# Log the mutation +EXIT_CODE=$(echo "${INPUT}" | jq -r '.tool_result.exit_code // 0') +[[ "${EXIT_CODE}" == "0" ]] && STATUS="success" || STATUS="failed" +LOG_FILE="${CLAUDE_PROJECT_DIR}/google/.changelog-raw.jsonl" +mkdir -p "$(dirname "${LOG_FILE}")" + +jq -nc \ + --arg ts "$(date -u +"%Y-%m-%dT%H:%M:%SZ")" \ + --arg action "${ACTION}" \ + --arg command "${COMMAND}" \ + --arg status "${STATUS}" \ + '{timestamp: $ts, action: $action, command: $command, status: $status}' \ + >> "${LOG_FILE}" + +# Remind the operator +if [[ "${STATUS}" == "success" ]]; then + echo "GAM MUTATION: ${ACTION} — logged to ${LOG_FILE}" +fi +exit 0 diff --git a/mcp-template.json b/mcp-template.json new file mode 100644 index 0000000..bc5f7d4 --- /dev/null +++ b/mcp-template.json @@ -0,0 +1,19 @@ +{ + "mcpServers": { + "context7": { + "command": "npx", + "args": ["-y", "@upstash/context7-mcp"] + }, + "exa": { + "command": "npx", + "args": ["-y", "exa-mcp-server"], + "env": { + "EXA_API_KEY": "your-exa-api-key-here" + } + }, + "granola": { + "type": "http", + "url": "https://mcp.granola.ai/mcp" + } + } +} diff --git a/scripts/statusline.sh b/scripts/statusline.sh new file mode 100755 index 0000000..885352a --- /dev/null +++ b/scripts/statusline.sh @@ -0,0 +1,165 @@ +#!/bin/bash +# Two-line statusline with visual context progress bar +# +# Line 1: Model, folder, branch +# Line 2: Progress bar, context %, cost, duration +# +# Context % uses Claude Code's pre-calculated remaining_percentage, +# which accounts for compaction reserves. 100% = compaction fires. + +# Read stdin (Claude Code passes JSON data via stdin) +stdin_data=$(cat) + +# Single jq call - extract all values at once +# Prefer pre-calculated remaining_percentage (100 - remaining = used toward compact) +# Fall back to manual calc from raw tokens if not available +IFS=$'\t' read -r current_dir model_name cost lines_added lines_removed duration_ms ctx_used cache_pct < <( + echo "$stdin_data" | jq -r '[ + .workspace.current_dir // "unknown", + .model.display_name // "Unknown", + (try (.cost.total_cost_usd // 0 | . * 100 | floor / 100) catch 0), + (.cost.total_lines_added // 0), + (.cost.total_lines_removed // 0), + (.cost.total_duration_ms // 0), + (try ( + if (.context_window.remaining_percentage // null) != null then + 100 - (.context_window.remaining_percentage | floor) + elif (.context_window.context_window_size // 0) > 0 then + (((.context_window.current_usage.input_tokens // 0) + + (.context_window.current_usage.cache_creation_input_tokens // 0) + + (.context_window.current_usage.cache_read_input_tokens // 0)) * 100 / + .context_window.context_window_size) | floor + else "null" end + ) catch "null"), + (try ( + (.context_window.current_usage // {}) | + if (.input_tokens // 0) + (.cache_read_input_tokens // 0) > 0 then + ((.cache_read_input_tokens // 0) * 100 / + ((.input_tokens // 0) + (.cache_read_input_tokens // 0))) | floor + else 0 end + ) catch 0) + ] | @tsv' +) + +# Bash-level fallback: if jq crashed entirely, extract fields individually +if [ -z "$current_dir" ] && [ -z "$model_name" ]; then + current_dir=$(echo "$stdin_data" | jq -r '.workspace.current_dir // .cwd // "unknown"' 2>/dev/null) + model_name=$(echo "$stdin_data" | jq -r '.model.display_name // "Unknown"' 2>/dev/null) + cost=$(echo "$stdin_data" | jq -r '(.cost.total_cost_usd // 0)' 2>/dev/null) + lines_added=$(echo "$stdin_data" | jq -r '(.cost.total_lines_added // 0)' 2>/dev/null) + lines_removed=$(echo "$stdin_data" | jq -r '(.cost.total_lines_removed // 0)' 2>/dev/null) + duration_ms=$(echo "$stdin_data" | jq -r '(.cost.total_duration_ms // 0)' 2>/dev/null) + ctx_used="" + cache_pct="0" + : "${current_dir:=unknown}" + : "${model_name:=Unknown}" + : "${cost:=0}" + : "${lines_added:=0}" + : "${lines_removed:=0}" + : "${duration_ms:=0}" +fi + +# Git info +if cd "$current_dir" 2>/dev/null; then + git_branch=$(git -c core.useBuiltinFSMonitor=false branch --show-current 2>/dev/null) + git_root=$(git -c core.useBuiltinFSMonitor=false rev-parse --show-toplevel 2>/dev/null) +fi + +# Build repo path display (folder name only for brevity) +if [ -n "$git_root" ]; then + repo_name=$(basename "$git_root") + if [ "$current_dir" = "$git_root" ]; then + folder_name="$repo_name" + else + folder_name=$(basename "$current_dir") + fi +else + folder_name=$(basename "$current_dir") +fi + +# Generate visual progress bar for context usage +progress_bar="" +bar_width=12 + +if [ -n "$ctx_used" ] && [ "$ctx_used" != "null" ]; then + filled=$((ctx_used * bar_width / 100)) + empty=$((bar_width - filled)) + + if [ "$ctx_used" -lt 50 ]; then + bar_color='\033[32m' # Green (0-49%) + elif [ "$ctx_used" -lt 80 ]; then + bar_color='\033[33m' # Yellow (50-79%) + else + bar_color='\033[31m' # Red (80-100%) + fi + + progress_bar="${bar_color}" + for ((i=0; i/dev/null; then + total_sec=$((duration_ms / 1000)) + hours=$((total_sec / 3600)) + minutes=$(((total_sec % 3600) / 60)) + seconds=$((total_sec % 60)) + if [ "$hours" -gt 0 ]; then + session_time="${hours}h ${minutes}m" + elif [ "$minutes" -gt 0 ]; then + session_time="${minutes}m ${seconds}s" + else + session_time="${seconds}s" + fi +else + session_time="" +fi + +# Separator +SEP='\033[2m│\033[0m' + +# Get short model name (e.g., "Opus" instead of "Claude 3.5 Opus") +short_model=$(echo "$model_name" | sed -E 's/Claude [0-9.]+ //; s/^Claude //') + +# LINE 1: [Model] folder | branch +line1=$(printf '\033[37m[%s]\033[0m' "$short_model") +line1="$line1 $(printf '\033[94m📁 %s\033[0m' "$folder_name")" +if [ -n "$git_branch" ]; then + line1="$line1 $(printf '%b \033[96m🌿 %s\033[0m' "$SEP" "$git_branch")" +fi + +# LINE 2: Progress bar | Context % | cost | duration +line2="" +if [ -n "$progress_bar" ]; then + line2=$(printf '%b' "$progress_bar") +fi +if [ -n "$ctx_pct" ]; then + if [ -n "$line2" ]; then + line2="$line2 $(printf '\033[37m%s\033[0m' "$ctx_pct")" + else + line2=$(printf '\033[37m%s\033[0m' "$ctx_pct") + fi +fi +if [ -n "$line2" ]; then + line2="$line2 $(printf '%b \033[33m$%s\033[0m' "$SEP" "$cost")" +else + line2=$(printf '\033[33m$%s\033[0m' "$cost") +fi +if [ -n "$session_time" ]; then + line2="$line2 $(printf '%b \033[36m⏱ %s\033[0m' "$SEP" "$session_time")" +fi +if [ "$cache_pct" -gt 0 ] 2>/dev/null; then + line2="$line2 $(printf ' \033[2m↻%s%%\033[0m' "$cache_pct")" +fi + +printf '%b\n\n%b' "$line1" "$line2" diff --git a/settings.json b/settings.json new file mode 100644 index 0000000..3956051 --- /dev/null +++ b/settings.json @@ -0,0 +1,70 @@ +{ + "$schema": "https://json.schemastore.org/claude-code-settings.json", + "cleanupPeriodDays": 365, + "env": { + "DISABLE_TELEMETRY": "1", + "DISABLE_ERROR_REPORTING": "1", + "CLAUDE_CODE_DISABLE_FEEDBACK_SURVEY": "1", + "CLAUDE_CODE_EXPERIMENTAL_AGENT_TEAMS": "1" + }, + "enableAllProjectMcpServers": false, + "alwaysThinkingEnabled": true, + "permissions": { + "deny": [ + "Bash(rm -rf *)", + "Bash(rm -fr *)", + "Bash(sudo *)", + "Bash(mkfs *)", + "Bash(dd *)", + "Bash(curl *|bash*)", + "Bash(wget *|bash*)", + "Bash(git push --force*)", + "Bash(git push *--force*)", + "Bash(git reset --hard*)", + + "Edit(~/.bashrc)", + "Edit(~/.zshrc)", + "Edit(~/.ssh/**)", + + "Read(~/.ssh/**)", + "Read(~/.gnupg/**)", + "Read(~/.aws/**)", + "Read(~/.azure/**)", + "Read(~/.config/gh/**)", + "Read(~/.git-credentials)", + "Read(~/.docker/config.json)", + "Read(~/.kube/**)", + "Read(~/.npmrc)", + "Read(~/.npm/**)", + "Read(~/.pypirc)", + "Read(~/.gem/credentials)", + "Read(~/Library/Keychains/**)", + "Read(~/Library/Application Support/**/metamask*/**)", + "Read(~/Library/Application Support/**/electrum*/**)", + "Read(~/Library/Application Support/**/exodus*/**)", + "Read(~/Library/Application Support/**/phantom*/**)", + "Read(~/Library/Application Support/**/solflare*/**)" + ] + }, + "hooks": { + "PreToolUse": [ + { + "matcher": "Bash", + "hooks": [ + { + "type": "command", + "command": "CMD=$(jq -r '.tool_input.command'); if echo \"$CMD\" | grep -qE 'rm[[:space:]]+-[^[:space:]]*r[^[:space:]]*f'; then echo 'BLOCKED: Use trash instead of rm -rf' >&2; exit 2; fi" + }, + { + "type": "command", + "command": "CMD=$(jq -r '.tool_input.command'); if echo \"$CMD\" | grep -qE 'git[[:space:]]+push.*(main|master)'; then echo 'BLOCKED: Use feature branches, not direct push to main' >&2; exit 2; fi" + } + ] + } + ] + }, + "statusLine": { + "type": "command", + "command": "~/.claude/statusline.sh" + } +}