Aller au contenu principal

Customization Guide

How to adapt claude-base to your specific needs.


1. Customize CLAUDE.md​

# Project [Name]

## Essential Commands
[npm/yarn/make commands specific to your project]

## Project Structure
[Tree with description of each folder]

## Code Conventions
[Rules specific to your team]

## Git & Commits
[Commit format, branches, workflow]

## Points of attention
[Common pitfalls, technical debt, sensitive areas]

Emphasis keywords​

Claude pays more attention to certain keywords:

KeywordUsage
IMPORTANT:Critical rule to follow
YOU MUSTAbsolute obligation
NEVERProhibition
ALWAYSAlways do it this way
WARNING:Point of attention

Example:

## Security
- IMPORTANT: Always validate user inputs
- YOU MUST use parameterized queries
- NEVER log passwords or tokens

Business context​

Add business context so Claude understands better:

## Business context
This project is a B2B e-commerce application.
- "Customers" are companies, not individuals
- A "cart" can contain thousands of items
- "Orders" go through a validation workflow

2. Create custom commands​

Location​

  • Project: .claude/commands/ (shared via git)
  • Personal: ~/.claude/commands/ (global)

Note: The foundation's commands are organized into subdirectories by category. A default install is core-only (work/, dev/, qa/, ops/, doc/, data/); the horizontal domains biz/, growth/, legal/ and platform/stack tooling are opt-in modules — add them with claude-base add <module> . (list with claude-base modules). Your custom commands can be at the root of .claude/commands/ or in a subdirectory of your choice.

Vendor skills: if you also opt into recommended vendor skills, the global rule .claude/rules/vendor-precedence.md defines precedence when their advice and the foundation's conflict (foundation owns security/workflow; vendor owns tool-specific API).

Structure of a command​

# Command name

Short description of what the command does.

## Context
$ARGUMENTS

## Instructions
1. Step 1
2. Step 2
...

## Expected output
[Output format]

---

[Additional instructions with IMPORTANT/YOU MUST]

Example: Deployment command​

.claude/commands/deploy.md:

# DEPLOY Agent

Deploys the application to the specified environment.

## Environment
$ARGUMENTS

## Prerequisites
- [ ] Tests pass
- [ ] Build OK
- [ ] Changelog up to date

## Workflow

### Staging
```bash
npm run build
npm run deploy:staging

Production​

IMPORTANT: Requires manual approval

npm run build:prod
npm run deploy:prod

Post-deployment​

  • Check healthchecks
  • Monitor errors
  • Notify the team

NEVER deploy to production without review.


Usage: `/deploy staging` or `/deploy production`

### Available variables

| Variable | Description |
|----------|-------------|
| `$ARGUMENTS` | Arguments passed to the command |

---

## 3. Configure permissions

### `.claude/settings.json` file

```json
{
"permissions": {
"allow": [
"Edit",
"Write",
"Bash(npm test:*)",
"Bash(npm run lint:*)",
"Bash(git status:*)",
"Bash(git diff:*)",
"Bash(git add:*)",
"Bash(git commit:*)"
],
"deny": [
"Bash(rm -rf:*)",
"Bash(git push --force:*)",
"Bash(DROP TABLE:*)"
]
}
}

Permission patterns​

PatternDescription
Bash(cmd:*)Allows cmd with all arguments
Bash(cmd arg:*)Allows cmd arg with free continuation
EditFile modification
WriteFile creation

Permissions per environment​

Create .claude/settings.local.json (gitignored) for more permissive local permissions:

{
"permissions": {
"allow": [
"Bash(docker:*)",
"Bash(kubectl:*)"
]
}
}

4. Configure hooks​

In .claude/settings.json​

Hooks are configured directly in the settings.json file:

{
"hooks": {
"PreToolUse": [
{
"description": "Protect main branch",
"matcher": "Edit|Write",
"hooks": [
{
"type": "command",
"command": "bash -c 'branch=$(git rev-parse --abbrev-ref HEAD 2>/dev/null); if [ \"$branch\" = \"main\" ] || [ \"$branch\" = \"master\" ]; then echo \"Modification blocked on $branch\" >&2; exit 2; fi'"
}
]
}
],
"PostToolUse": [
{
"description": "Auto-format after edit",
"matcher": "Edit|Write",
"hooks": [
{
"type": "command",
"command": "bash -c 'FILE=$(jq -r \".tool_input.file_path // empty\"); [ -n \"$FILE\" ] && npx prettier --write \"$FILE\"'"
}
]
}
]
}
}

Hook types​

HookTrigger
SessionStartSession start (matchers: startup, resume, clear, compact)
SessionEndSession end
UserPromptSubmitWhen the user submits a prompt (can inject context)
PreToolUseBefore using a tool (Edit, Write, Bash, Read…)
PostToolUseAfter using a tool
StopWhen Claude finishes a response
NotificationSystem notifications (permissions, idle…)

Available matchers​

MatcherTargeted tools
EditFile modifications
WriteFile creation
BashShell commands
ReadFile reading
Glob, GrepSearch
Edit|WriteMultiple tools (regex)
*All tools

Environment variables​

VariableDescription
$CLAUDE_PROJECT_DIRProject root (equivalent to pwd at startup)
$CLAUDE_SESSION_IDUnique session identifier

Per-invocation data (the edited file, the tool name, the command) is not exposed as env vars — hooks receive the full JSON payload on stdin and parse it with jq:

Field (stdin JSON)Description
.tool_nameName of the tool used (Edit, Write, Bash…)
.tool_input.file_pathPath of the edited/written file (Edit/Write)
.tool_input.commandThe shell command (Bash)
.tool_input.content / .new_stringThe written/edited content
# Read the payload once, then extract what you need
FILE=$(jq -r '.tool_input.file_path // empty')

Behavior on failure​

exit 2 on a PreToolUse hook refuses the action. By default, a hook that crashes, exits otherwise, or outlives its timeout (in seconds) does not block — the action proceeds (measured 2026-09-25). Since Claude Code 2.1.295, "onFailure": "block" on the hook turns those failures into a block; every foundation PreToolUse guard carries it, so a guard that crashes, is cut or is missing fails closed (measured 2026-10-17), bar the zsh PIPESTATUS guard, a correctness check that carries "continue" on purpose; its deliberate fail-open paths (no jq, a missing policy core) exit 0 and still let the call through. The only values are "block" and "continue": any other one silently disables every PreToolUse guard. Keep guards fast and give them a wide timeout, since under "block" a cut guard refuses a legitimate call.


5. Create custom skills​

Skills are triggered automatically by Claude based on context (keywords in the conversation). Ideal for recurring patterns you don't want to invoke manually.

Location​

.claude/skills/
└── my-skill/
├── SKILL.md # Frontmatter + main instructions
├── examples/ # (optional) Detailed examples
└── references/ # (optional) Large references

SKILL.md format​

---
name: my-skill
description: When to trigger this skill (keywords or context)
---

# My Skill

## Trigger

Activated when the user mentions:
- "pattern X"
- "approach Y"

## Instructions

[The full skill prompt — can be up to 500 lines]

## Examples

For large examples, move to `examples/` and include via link.

Best practices​

  • context: omit it (default) and the skill runs inline, in the conversation. fork is the only value: it runs the skill in a sub-agent that sees none of the conversation, so keep it for a self-contained job (a report, a batch over the repo) and pair it with background: false, or the result arrives asynchronously.
  • allowed-tools: the foundation declares none — see Pre-approving tools below.
  • Precise description: Claude uses the description to decide when to trigger, be specific.
  • Skills ≠ Agents: a skill complements Claude; an agent is an isolated subprocess.

Pre-approving tools (allowed-tools)​

allowed-tools pre-approves tools — no permission prompt — for the skill's turn. It grants, it never restricts: a skill can use every tool whatever the field says (measured on a forked skill).

The foundation's skills and commands declare none, and tests/skills-frontmatter.bats refuses the key. The reason is honest rather than dramatic: the shipped .claude/settings.json already allows Read, Bash, Edit, Write, WebFetch and WebSearch on every turn (deny rules and hooks are the safety net), so in an installed project a grant adds nothing. It only matters in a project that narrowed its allow list, or for a skill copied elsewhere — and there it silently widens what runs unprompted; even a bare Read then reaches outside the project (~/.ssh, ~/.aws), since reads inside it never prompt anyway. (With the shipped settings, bare Read is already allowed on every turn, outside the project included: that is a property of the settings, not of any skill.)

If your own skill truly needs an unattended command, give it one precise rule such as Bash(npm test:*) and review it; never a bare tool or a wildcard-only scope like Edit(**).

Example: TypeScript code review skill​

---
name: review-typescript-strict
description: Activate when the user wants a strict TypeScript review (any, implicit types, null safety)
context: fork # a self-contained review of the code, not of the conversation
background: false # wait for the result in the same turn
---

# Strict TypeScript Review

When the user requests a TypeScript review:

1. Detect explicit `any` (other than those justified in a comment).
2. Detect implicit types (parameters without type).
3. Check null safety (optional chaining, nullish coalescing).
4. Produce a report with line:column for each issue.

6. Integrate MCP servers​

.mcp.json file​

Security important: the foundation ships .mcp.json empty ("mcpServers": {}) — no MCP server runs by default. A server is active only if listed in .mcp.json (the format has no per-server enabled flag). A curated catalogue ships as .mcp.json.example (a reference file Claude does not load); copy the server blocks you need into .mcp.json, provide their env vars, and review their permissions. Project-scoped servers prompt for approval on first use.

{
"mcpServers": {
"filesystem": {
"command": "npx",
"args": ["-y", "@modelcontextprotocol/server-filesystem", "."]
},
"postgres": {
"command": "npx",
"args": ["-y", "@modelcontextprotocol/server-postgres"],
"env": {
"DATABASE_URL": "${DATABASE_URL}"
}
}
}
}
ServerPackageUsage
Filesystem@modelcontextprotocol/server-filesystemControlled file access
Postgres@modelcontextprotocol/server-postgresPostgreSQL queries
GitHub@modelcontextprotocol/server-githubGitHub API (issues, PRs)
Puppeteer@modelcontextprotocol/server-puppeteerBrowser automation
Fetch@modelcontextprotocol/server-fetchHTTP requests
Memory@modelcontextprotocol/server-memoryKnowledge graph memory

Full list: <https://github.com/modelcontextprotocol/servers>.


7. Adapt for your team​

Team conventions​

Add to CLAUDE.md:

## Team conventions

### Code review
- Minimum 1 approval required
- Author does not merge their own PR
- Squash merge preferred

### Communication
- Jira tickets format: PROJ-123
- Commits reference the ticket: "feat(PROJ-123): ..."

### Deployments
- Staging: automatic on develop
- Production: manual, Wednesdays only

Onboarding​

Create a specific onboarding command:

.claude/commands/team-onboard.md:

# Team Onboarding

Guides the new developer through the project.

## Steps

1. **Architecture**: Explain the structure
2. **Setup**: Guide local installation
3. **Workflow**: Explain the dev process
4. **Conventions**: Present team rules
5. **Resources**: List important documentation

## Useful links
- Wiki: [link]
- Jira: [link]
- Slack: #channel-dev

Sharing configurations​

  1. Version .claude/ and CLAUDE.md in git
  2. Gitignore CLAUDE.local.md and .claude/settings.local.json
  3. Document custom commands in the README

Best practices​

  1. Start simple - Add commands as needs arise
  2. Document commands - Future you will thank you
  3. Test permissions - Verify nothing dangerous is allowed
  4. Iterate - Improve CLAUDE.md based on experience
  5. Share - Good configurations benefit the whole team

Troubleshooting​

Claude doesn't find my commands​

  • Check the path: .claude/commands/name.md
  • Check that the file has the .md extension
  • Restart Claude Code after adding

Permissions don't work​

  • Check the JSON syntax
  • Patterns are case-sensitive
  • Use :* wildcards for arguments

Hooks don't trigger​

  • Check the matcher matches the tool (e.g. Edit|Write, Bash)
  • Check that the hook script path exists and is executable
  • Consult the Claude logs

Stack templates for CLAUDE.md​

TemplateLanguage / Framework
CLAUDE.react.mdReact
CLAUDE.vue.mdVue.js 3
CLAUDE.node-api.mdNode.js API
CLAUDE.python.mdPython
CLAUDE.go.mdGo
CLAUDE.rust.mdRust
CLAUDE.java.mdJava / Spring Boot
CLAUDE.fullstack.mdFullstack monorepo
CLAUDE.flutter.mdFlutter / Dart (Mobile)
CLAUDE.neovim.mdNeovim / Lua config
# Recommended: scaffold via the dispatcher (works post-install, any cwd)
claude-base init --type react ./my-app

# Or copy the template manually (from a foundation clone)
cp templates/CLAUDE.react.md CLAUDE.md

The dispatcher path additionally wires hooks, settings, and preset-specific filtering ; the raw cp only installs the project-instructions file.

IDE Integration​

./scripts/ide.sh setup <vscode|idea|vim|all> # configure
./scripts/ide.sh check <vscode|idea|vim> # verify
./scripts/ide.sh remove <vscode|idea|vim> # uninstall

Sets up Settings/Tasks/Extensions/Snippets (VSCode/Cursor), Run Configurations/Code Style/Templates (IntelliJ), or Abbreviations/Mappings/Autocmds (Vim/Neovim). Run ./scripts/ide.sh --help for the full surface.