Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
32 changes: 32 additions & 0 deletions AI/Claude/CLAUDE.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,32 @@
# Claude Team Standards

This file defines shared rules for Claude across the team. All rules here apply to everyone — engineering, QA, and support.

## Safety

- Never run `git push` — all pushes must be done manually by the user
- Never commit secrets, API keys, or tokens — use environment variables
- Never bypass pre-commit hooks with `--no-verify`
- Never force push to `main`

## Code quality

- Always run tests before considering a task done
- Always run the linter after editing code
- Don't add features, refactoring, or improvements beyond what was asked

## Git discipline

- Write clear, descriptive commit messages
- One logical change per commit
- Branch names must describe the work (e.g. `feature/x`, `fix/y`, `chore/z`)

## Communication

- If a task is ambiguous, ask before starting — don't assume
- When blocked, state why clearly instead of guessing a workaround

## Workflow

- Use `/analyze-issue` before picking up any GitHub issue
- Read existing code before writing new code — don't duplicate logic
119 changes: 119 additions & 0 deletions AI/Claude/README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,119 @@
# 🤖 Claude Team Standards

This directory contains shared Claude Code configuration for the team — skills, hooks, and rules that make Claude behave consistently for everyone, whether you're in engineering, QA, or support.

---

## Why shared configs?

When everyone uses Claude differently, you get inconsistent output, repeated mistakes, and no way to enforce team standards. Shared configs fix that:

- 📏 **Consistency** — Claude follows the same rules and formats for everyone
- 🛡️ **Safety** — hard rules (like never pushing code) are enforced, not just suggested
- ⚡ **Speed** — common workflows become one-liner slash commands
- 🧠 **Shared knowledge** — team conventions live in one place, not in individual heads

---

## What's in here

### 📄 CLAUDE.md

The rules file. Claude reads this automatically and uses it to guide its behavior throughout a session. Think of it as a team handbook for Claude — coding standards, git discipline, safety rules, workflow expectations.

It's **advisory** — Claude will follow it, but it's not enforced at a technical level. Pair it with hooks for anything that must never slip.

👉 See [CLAUDE.md](./CLAUDE.md)

---

### ⚡ Skills

Skills are custom slash commands. You create a markdown file, and the filename becomes the command. Invoke it with `/skill-name` in Claude Code.

They're great for repeated workflows — instead of explaining the same task to Claude every time, you write the instructions once and reuse them forever.

```
/analyze-issue #123 → structured analysis of a GitHub issue
```

Skills are **project-scoped** — everyone who clones this repo gets them automatically. No setup needed beyond having Claude Code installed.

> 🔌 Some skills require an MCP server (e.g. the GitHub MCP server for issue-related skills). Check the skills README for details.

👉 See [skills/README.md](./skills/README.md)

---

### 🪝 Hooks

Hooks are scripts that run automatically when Claude tries to do something — before or after a tool executes. Unlike CLAUDE.md, hooks are **enforced** — they can block actions outright.

Use them for things that must never happen:

- 🚫 Blocking `git push` (all pushes must come from the user)
- 🌿 Blocking direct commits to `main` or `master`
- 🔑 Detecting secrets before they get written to a file
- 🧹 Running the linter automatically after every file edit

Hooks can be written in **any language** — Python, shell, Rust, Go, etc. Python and shell are preferred for simplicity since they run without a build step. Compiled language hooks (like Rust) require each team member to compile the binary locally. See the hooks README for details.

Hooks are configured in `.claude/settings.json` and live in the `hooks/` directory.

👉 See [hooks/README.md](./hooks/README.md)

---

## How to set everything up

### 1. Install Claude Code

If you haven't already:
```bash
npm install -g @anthropic-ai/claude-code
```

### 2. Clone the repo

Skills and hooks are automatically available once you clone — no extra setup needed for those.

### 3. Compile Rust hooks (if applicable)

Some hooks are written in Rust for teams that already have a Rust toolchain. These need to be compiled once per machine:

```bash
rustc AI/Claude/hooks/block_commit_main.rs -o AI/Claude/hooks/block_commit_main
```

Or if there's a Makefile:
```bash
make hooks
```

Compiled binaries are gitignored — only the `.rs` source files are committed.

### 4. Configure hooks

Copy or reference the hook settings into your project's `.claude/settings.json`. See [hooks/README.md](./hooks/README.md) for the exact JSON.

### 5. Set up MCP servers (if needed)

If you're using skills that interact with GitHub or other external services, you'll need the relevant MCP server configured. See [skills/README.md](./skills/README.md) for details.

### 6. Start using skills

Open Claude Code in your project and type `/` to see available commands.

---

## The golden rule 🏅

> **CLAUDE.md tells Claude what to do. Hooks make sure it actually does it.**

Use CLAUDE.md for conventions and guidance. Use hooks for anything where "Claude forgot" is not an acceptable excuse.

---

## Contributing

Adding a new skill or hook? Great — follow the guidelines in their respective READMEs, keep things focused and simple, and update this README if you're adding something significant.
134 changes: 134 additions & 0 deletions AI/Claude/hooks/README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,134 @@
# Hooks

Hooks are scripts that run automatically in response to Claude's actions. They enforce rules that must never be bypassed — unlike CLAUDE.md which is advisory, hooks are deterministic.

## Structure

```
hooks/
├── README.md
├── block_push.py # Blocks git push attempts (Python)
└── block_commit_main.rs # Blocks direct commits to main/master (Rust)
```

## How hooks work

Claude pipes a JSON payload to the hook's stdin before (or after) executing a tool. The hook responds with an exit code:

| Exit code | Meaning |
|-----------|---------|
| `0` | Allow — proceed normally |
| `2` | Block — stop the action, show stderr to Claude |

## How to register a hook

Hooks are configured in `.claude/settings.json`. The example below uses `block_push.py` — a hook that prevents Claude from running `git push`:

**`AI/Claude/hooks/block_push.py`:**
```python
import sys
import json

data = json.load(sys.stdin)
command = data.get("tool_input", {}).get("command", "")

if "git push" in command:
print("Blocked: git push is not allowed from Claude. Push manually.")
sys.exit(2)

sys.exit(0)
```

**`.claude/settings.json`:**
```json
{
"hooks": {
"PreToolUse": [
{
"matcher": "Bash",
"hooks": [
{
"type": "command",
"command": "python3 AI/Claude/hooks/block_push.py"
}
]
}
]
}
}
```

## Hook events

| Event | Fires |
|-------|-------|
| `PreToolUse` | Before Claude executes a tool — can block |
| `PostToolUse` | After Claude executes a tool — cannot block, used for logging/linting |

---

## Using Rust hooks

Hooks can be written in any language — including Rust. The tradeoff is that compiled hooks require a build step and each team member must compile for their own platform.

### Example — `block_commit_main.rs`

This hook blocks Claude from committing directly to `main` or `master`, enforcing the use of feature branches.

**Compile it:**
```bash
rustc AI/Claude/hooks/block_commit_main.rs -o AI/Claude/hooks/block_commit_main
```

**Register it in `.claude/settings.json`:**
```json
{
"hooks": {
"PreToolUse": [
{
"matcher": "Bash",
"hooks": [
{
"type": "command",
"command": "AI/Claude/hooks/block_commit_main"
}
]
}
]
}
}
```

### Team setup for Rust hooks

Since compiled binaries are platform-specific, follow these steps:

1. **Add binaries to `.gitignore`** — commit the `.rs` source files, not the compiled output:
```gitignore
AI/Claude/hooks/block_commit_main
```

2. **Each team member compiles locally** after cloning:
```bash
rustc AI/Claude/hooks/block_commit_main.rs -o AI/Claude/hooks/block_commit_main
```

3. **Alternatively, use a Makefile** to automate this:
```makefile
hooks:
rustc AI/Claude/hooks/block_commit_main.rs -o AI/Claude/hooks/block_commit_main
```
Then team members just run `make hooks` after cloning.

> **Tip:** If the extra build step is a friction point, rewrite the hook in Python instead. Rust hooks make sense when you need performance or already have a Rust toolchain in your workflow.

---

## Guidelines

- Use hooks for hard rules (secrets, destructive commands, force pushes, branch protection)
- Use CLAUDE.md for guidance and conventions — hooks are the backstop
- Prefer Python or shell for hooks — no compilation required, works cross-platform out of the box
- Use Rust (or other compiled languages) only when justified — document the build step clearly
- Keep hooks fast — they run on every matching tool call
- Always handle the case where stdin is empty or malformed
32 changes: 32 additions & 0 deletions AI/Claude/hooks/block_commit_main.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,32 @@
use std::io::{self, Read};
use std::process::Command;

fn main() {
let mut input = String::new();
io::stdin().read_to_string(&mut input).unwrap();

// Only act on git commit commands
if !input.contains("git commit") {
std::process::exit(0);
}

// Get the current branch name
let output = Command::new("git")
.args(["branch", "--show-current"])
.output();

let branch = match output {
Ok(o) => String::from_utf8_lossy(&o.stdout).trim().to_string(),
Err(_) => std::process::exit(0), // can't determine branch, allow
};

if branch == "main" || branch == "master" {
eprintln!(
"Blocked: direct commits to '{}' are not allowed. Create a feature branch first.",
branch
);
std::process::exit(2);
}

std::process::exit(0);
}
11 changes: 11 additions & 0 deletions AI/Claude/hooks/block_push.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
import sys
import json

data = json.load(sys.stdin)
command = data.get("tool_input", {}).get("command", "")

if "git push" in command:
print("Blocked: git push is not allowed from Claude. Push manually.")
sys.exit(2)

sys.exit(0)
Loading
Loading