Aller au contenu principal

Foundation Extension Guide

How to customize and extend the claude-base foundation for your own projects.

Dual audience: this guide covers two distinct cases.

  • You are extending your user project (adding custom commands/rules/skills): your @imports in CLAUDE.md should point to @.claude/docs/... (since the foundation's documentation is installed under .claude/docs/ on your side).
  • You are contributing to the claude-base repo: the foundation's @imports point to @docs/... (the foundation keeps its documentation directly under docs/). See also CONTRIBUTING.md.

Overview

The foundation is designed to be extended. Four main extension points exist:

ElementLocationPurpose
Rules.claude/rules/Apply conventions based on file type
Skills.claude/skills/Encapsulate a reusable workflow
Agents.claude/agents/Orchestrate a workflow with a dedicated LLM
Hooks.claude/settings.jsonAutomate pre/post tool actions

1. Create a custom Rule

Rules are Markdown files with YAML frontmatter that define constraints and conventions. They activate automatically when Claude modifies a file matching the declared paths.

Frontmatter format

---
paths:
- "**/*.vue"
- "**/components/**"
---

# Vue Rules

## Conventions
- IMPORTANT: Use the Composition API (not Options API)
- YOU MUST declare props with defineProps<T>()

The frontmatter is optional. Without paths, the rule applies globally to all interactions.

Location

Create the file in .claude/rules/:

.claude/rules/vue.md
.claude/rules/my-framework.md

Complete example: rule for Svelte

---
paths:
- "**/*.svelte"
- "**/src/lib/**"
- "**/src/routes/**"
---

# Svelte Rules

## Component structure

| Element | Convention | Example |
|---------|-----------|---------|
| Script | `<script lang="ts">` | Always TypeScript |
| Stores | Native Svelte stores | `writable<User \| null>(null)` |
| Props | `export let prop: Type` | Explicit typing required |

## Conventions

- IMPORTANT: Prefer Svelte stores over an external state manager
- YOU MUST type all exported props
- NEVER use `any` in Svelte components
- File naming: PascalCase for components, kebab-case for routes

## Lifecycle

- Prefer `onMount` over `beforeUpdate` for side effects
- Required cleanup in `onDestroy` for subscriptions

Test the trigger

Modify a .svelte file and verify in the Claude Code session that the rule appears loaded. Rules are displayed in session information at startup (InstructionsLoaded hook).

To force reload: restart a session or use /clear.


2. Create a Skill

A skill is a SKILL.md file in a subfolder of .claude/skills/. It encapsulates a complete workflow with its instructions, examples and constraints.

Since CLI 2.1.x, slash commands and skills are unified: each skill automatically gets a /slash-command interface. Files in .claude/commands/ continue to work for compatibility, but the recommended approach for any new workflow is .claude/skills/. The foundation keeps .claude/commands/ only for namespaced shortcuts (e.g., /work:work-pr).

Folder structure

.claude/skills/my-skill/
├── SKILL.md # Required definition
├── examples/ # Concrete examples (optional)
└── references/ # Reference files (optional)

SKILL.md format

---
name: my-skill
description: What the skill does. Trigger when the user [context].
allowed-tools:
- Read
- Write
- Edit
- Bash
- Glob
- Grep
context: fork
model: sonnet
argument-hint: "[project-name] [options]"
---

# Skill Title

## Purpose
Description in 1-2 sentences.

## Instructions

1. Step 1
2. Step 2
3. Step 3

## Expected output
Output format.

## Rules
- IMPORTANT: Critical rule
- NEVER: What must never be done

Available frontmatter fields

FieldRequiredValuesDescription
nameNokebab-caseSkill name (default: folder name)
descriptionRecommendedtextTrigger context
allowed-toolsNolistTools authorized without confirmation
contextNoforkExecution in an isolated sub-agent
modelNosonnet, opus, haiku, inheritModel to use
argument-hintNotextAutocompletion in the / menu
disable-model-invocationNotrue/falseManual invocation only
user-invocableNotrue/falseVisible in the / menu

Best practices

  • Limit SKILL.md to 500 lines maximum. Move detail to examples/ or references/
  • Declare only the necessary tools (least privilege principle)
  • Always use context: fork for isolation
  • Write the description with the trigger context: Claude uses this field to automatically decide when to load the skill
  • Prefer tables over prose for quick references

Tools by skill type

Skill typeRecommended tools
Read-only (audit, review)Read, Glob, Grep
DevelopmentRead, Write, Edit, Bash, Glob, Grep
DocumentationRead, Write, Edit, Glob, Grep
AnalysisRead, Glob, Grep
InfrastructureRead, Write, Edit, Bash, Glob, Grep

Complete example: changelog generation skill

---
name: changelog-entry
description: Generates a CHANGELOG.md entry from recent commits. Trigger when the user wants to document a release or update the changelog.
allowed-tools:
- Read
- Edit
- Bash
- Glob
context: fork
model: sonnet
argument-hint: "[version] [since-tag]"
---

# Generate a Changelog Entry

## Purpose

Analyze Git commits since the last tag and generate a CHANGELOG.md entry
formatted according to Keep a Changelog.

## Instructions

1. Read the existing CHANGELOG.md to understand the format used
2. Retrieve commits: `git log <since-tag>..HEAD --oneline`
3. Group commits by type (feat, fix, refactor, docs, etc.)
4. Generate the entry in Keep a Changelog format
5. Insert at the beginning of CHANGELOG.md, after the title

## Output format

\`\`\`markdown
## [1.2.0] - 2026-04-03

### New features
- Clear description of the feature (ref: commit abc123)

### Fixes
- Description of the bug fixed (ref: commit def456)
\`\`\`

## Rules

- NEVER modify existing changelog entries
- IMPORTANT: Use the ISO date format (YYYY-MM-DD)
- Exclude style and chore commits unless significant

3. Create an Agent

An agent is a .md file in .claude/agents/. It combines a YAML frontmatter (sub-agent configuration) with Markdown instructions (behavior).

Agent format

---
name: my-agent
description: Short description. Trigger when [usage context].
tools: Read, Grep, Glob, Edit, Write, Bash
model: sonnet
permissionMode: default
skills:
- my-skill
---

# Agent MY-AGENT

Body of the agent's instructions.

Agent frontmatter fields

FieldDescription
nameAgent identifier (kebab-case)
descriptionAutomatic activation context
toolsAuthorized tools (comma-separated)
modelsonnet, opus, haiku
permissionModedefault, acceptEdits, bypassPermissions
skillsList of skills to load
hooksHooks scoped to the agent's lifecycle

When to use agent vs skill vs command

NeedSolutionReason
Reusable workflow with instructionsSkillInvokable via /name, shared between agents
Isolated execution with dedicated LLMAgentSub-agent with its own context
Sequence of bash commandsCommand .mdPrompt without additional LLM
Automation without interactionHookExecutes a script at the right moment

Complete example: dependency audit agent

---
name: deps-audit
description: Audit of obsolete or vulnerable dependencies. Trigger when the user wants to check or update project dependencies.
tools: Read, Bash, Glob, Edit
model: sonnet
permissionMode: default
---

# Agent DEPS-AUDIT

Analyzes project dependencies and produces a report classified by criticality.

## Workflow

1. Detect the package manager (npm, pnpm, yarn, pip, go mod)
2. Run the vulnerability audit (`npm audit`, `pip-audit`, etc.)
3. Identify outdated dependencies
4. Classify by criticality: CRITICAL > HIGH > MEDIUM > LOW
5. Propose an update plan

## Output

Structured report with:
- Vulnerability table by level
- Update commands to execute
- Dependencies to watch (potential breaking changes)

## Rules

- NEVER automatically update major dependencies without confirmation
- IMPORTANT: Check breaking changes before proposing a major update

Agent naming

Follow the existing domain-action convention:

DomainPrefixExamples
Developmentdev-dev-api, dev-tdd, dev-debug
Qualityqa-qa-review, qa-security
Operationsops-ops-deploy, ops-docker
Documentationdoc-doc-generate, doc-changelog
Businessbiz-biz-model, biz-mvp
Workflowwork-work-explore, work-plan

4. Create a Hook

Hooks allow automating actions at specific moments in the lifecycle of a Claude Code session. They are configured in .claude/settings.json (global hooks) or in the frontmatter of an agent/skill (scoped hooks).

Hook types

TypeDescriptionUse case
commandExecutes a bash scriptValidation, formatting, logging
promptEvaluated via a Haiku LLMSmart contextual verification
httpPOST JSON to a URLExternal webhook, CI/CD

Available events

EventTriggerTypical usage
SessionStartSession startDisplay project info, check prereqs
PreToolUseBefore tool executionValidate, block, transform
PostToolUseAfter successful executionFormat, lint, notify
StopEnd of Claude responseFinal validation, logging
PreCompactBefore context compactionSave state
SessionEndEnd of sessionCleanup, report

Hook properties

PropertyDescription
typecommand, prompt, or http
commandBash script to execute (type command)
matcherFilter on tool name (regex)
timeoutTimeout in milliseconds
onFailure"block" or "ignore"
asynctrue for background execution

When to use async

SituationasyncReason
Logging, monitoringtrueDoes not block the workflow
Blocking validationfalseMust execute before continuing
Auto formattingfalseMust finish before the next tool
External webhooktrueNon-blocking network latency

Example: PostToolUse hook to format SQL

In .claude/settings.json, hooks section:

{
"PostToolUse": [
{
"description": "Format SQL files with sqlfluff",
"matcher": "Edit|Write",
"hooks": [
{
"type": "command",
"command": "bash -c 'if command -v sqlfluff >/dev/null 2>&1; then FILE=$(echo \"$TOOL_INPUT\" | jq -r \".path // empty\"); if [[ \"$FILE\" == *.sql ]]; then sqlfluff fix --dialect ansi \"$FILE\" 2>/dev/null && echo \"[SQL] Formatted: $FILE\"; fi; fi'",
"timeout": 10000,
"onFailure": "ignore"
}
]
}
]
}

Example: PreToolUse hook for business validation

{
"PreToolUse": [
{
"description": "Prevent modification of production configuration files",
"matcher": "Edit|Write",
"hooks": [
{
"type": "command",
"command": "bash -c 'FILE=$(echo \"$TOOL_INPUT\" | jq -r \".path // empty\"); if [[ \"$FILE\" == *prod* ]] || [[ \"$FILE\" == *production* ]]; then echo \"BLOCKED: Modification of a production file detected. Use ALLOW_PROD_EDIT=1 to force.\"; if [ \"$ALLOW_PROD_EDIT\" != \"1\" ]; then exit 1; fi; fi'",
"timeout": 5000,
"onFailure": "block"
}
]
}
]
}

Hooks in settings.local.json

For hooks specific to your machine (not committed):

// .claude/settings.local.json
{
"hooks": {
"PostToolUse": [
{
"description": "Desktop notification after each modification",
"matcher": "Edit|Write",
"hooks": [
{
"type": "command",
"command": "bash -c 'notify-send \"Claude Code\" \"File modified\" 2>/dev/null || true'",
"timeout": 3000,
"async": true,
"onFailure": "ignore"
}
]
}
]
}
}

5. Customize CLAUDE.md

CLAUDE.md is the project's main configuration file. It is loaded at every session.

@import pattern

@path/to/file.md

Imported files are injected directly into the context. Use for bulky references that are not necessary for every session.

Files always loaded (imports in this project):

  • @docs/reference/best-practices.md
  • @docs/reference/project-structures.md

What belongs where

ElementLocationReason
Mandatory workflowCLAUDE.mdApplies to the whole team
Code conventionsCLAUDE.md or rulesDepending on whether contextual or global
Personal preferences~/.claude/memory/Not committed, personal
Conventions per language.claude/rules/<lang>.mdActive only on the relevant files
Architecture decisions~/.claude/memory/Memorized per session
Long referencesSeparate file with @importAvoids overloading the context
# My Project

> Short project description

## Workflow

[Adapt the mandatory workflow to the project's context]

## Conventions

[Project-specific conventions, not covered by rules]

## References

| Topic | File |
|-------|------|
| Architecture | `docs/ARCHITECTURE.md` |
| API | `docs/api/README.md` |

What must not be put in CLAUDE.md

  • Secrets, credentials, tokens (use .env)
  • Information that changes often (dependency versions, etc.)
  • Content duplicated from rules (useless, increases context)
  • History of decisions (use CHANGELOG.md or git log)

6. Contribute to the foundation

Fork and PR workflow

# 1. Fork the repository on GitHub
# 2. Clone your fork
git clone https://github.com/<you>/claude-base.git
cd claude-base

# 3. Create a feature branch
git checkout -b feature/my-python-typing-skill

# 4. Create or modify files
# 5. Test manually in a Claude Code session
# 6. Verify counter consistency
./scripts/validate-counts.sh

# 7. Commit using Conventional Commits
git commit -m "feat(skills): add python-typing skill for strict type annotations"

# 8. Push and create the PR
git push origin feature/my-python-typing-skill
gh pr create --title "feat(skills): add python-typing skill" --body "..."

Naming conventions

TypeConventionExample
Skillsdomain-actiondev-typing, qa-mutation
Agentsdomain-actiondev-typing, qa-mutation
Ruleslanguage/framework namesvelte.md, fastapi.md
Commandsdomain/action.mddev/dev-typing.md
Branchesfeature/xxx, fix/xxxfeature/svelte-rule
CommitsConventional Commitsfeat(rules): add svelte rule

Pre-PR checklist

[ ] The skill/agent has a kebab-case name following the domain-action convention
[ ] The YAML frontmatter is valid (name, description, allowed-tools)
[ ] The description contains the trigger context
[ ] Declared tools are the minimum necessary
[ ] context: fork is present for skills
[ ] The file is under 500 lines
[ ] Code examples are relevant and functional
[ ] validate-counts.sh passes without error
[ ] Reference documentation is updated if necessary

validate-counts.sh compliance

When you add a skill, an agent, a rule or a command, several documentation files must be updated to reflect the new counters:

FileCounter to update
README.mdNumber of commands
CLAUDE.mdNumber of commands, agents, skills
docs/reference/agents-catalog.mdFile header
website/src/pages/index.tsxHomepage statistics
website/docs/intro/architecture.mdArchitecture counters

Run ./scripts/validate-counts.sh --fix to identify inconsistencies. Manually correct numerical values in the flagged files.

Quality PR structure

## Description
Add a `svelte` skill for Svelte 5 development conventions.

## Motivation
The foundation did not cover Svelte. This skill activates Composition API conventions,
prop typing, and store management automatically on `.svelte` files.

## Changes
- `.claude/skills/dev-svelte/SKILL.md`: new skill
- `.claude/rules/svelte.md`: associated rule
- `docs/reference/skills-catalog.md`: entry added
- Counters updated in README.md, CLAUDE.md, website

## Tests
- Tested manually by modifying a .svelte file in a Claude Code session
- validate-counts.sh passes

## Checklist
- [x] Naming conventions respected
- [x] validate-counts.sh OK
- [x] Documentation updated

7. Native plugin migration: current state

Claude Code shipped a native plugin system between CLI 2.1.119 and 2.1.126 (April-May 2026). At first glance, porting claude-base to a native plugin (claude plugin install claude-base) would unlock distribution via the Anthropic marketplace. This is not the path the foundation has taken — yet.

Why we kept the standalone .claude/ foundation

A research pass on May 4, 2026 against the official plugin docs (code.claude.com/docs/en/plugins) surfaced three documented gaps that prevent a clean port today:

GapImpact on claude-base
Rules (.claude/rules/) are not a plugin componentThe 30 path-specific rules in this foundation cannot ship via plugin. Users would need to copy them manually post-install.
settings.json scope inside plugins is limited to agent and subagentStatusLinePlugins cannot configure permissions, env, or top-level hooks for the user's session. Foundation defaults (deny lists, env, ~15 PostToolUse hooks) cannot be auto-installed.
No first-install / setup callbackscripts/new-project.sh (the foundation orchestrator) has no equivalent. A plugin user gets skills/agents/commands immediately but no workspace setup.

For a foundation whose value sits in the integration of all four extension types plus settings + setup logic, losing two of those layers (rules + settings + setup) is a non-starter today.

When porting will make sense

Re-evaluate when at least 2 of the 3 gaps land:

  • Plugin manifests gain a rules/ contribution type
  • Plugin settings.json scope expands to include at least permissions and env
  • A documented postInstall / setup hook arrives for plugins

Track the Claude Code CHANGELOG for these features. Realistic window: 6-12 months.

For contributors who want to publish their own pack

If you've extended the foundation with a thematic pack (e.g. a stripe-pack, a rails-pack) and want it shareable today without depending on claude-base, native plugins are a solid option:

  • Manifest format: .claude-plugin/plugin.json (JSON, not YAML)
  • Repo layout: commands/, agents/, skills/, hooks/hooks.json at the plugin root
  • Installation: claude plugin install <github-org>/<repo>
  • Marketplace: list it on claudemarketplaces.com once stable
  • Reference: code.claude.com/docs/en/plugins

Note that as of May 2026 the marketplace is dominated by single-purpose plugins (1-5 skills each). Foundation-scale plugins are rare; smaller atomic packs align better with current ecosystem conventions.

What if you want both

A pragmatic interim pattern: keep claude-base as your project's .claude/ template (for the integrated foundation experience), and layer external native plugins on top for vertical-specific additions (e.g. install a community Stripe plugin alongside the foundation). The two systems coexist cleanly — they read different config namespaces.


Recap of locations

.claude/
├── rules/ # Rules per language/framework
│ ├── python.md # Activated on **/*.py
│ └── my-framework.md
├── skills/ # Reusable skills
│ └── my-skill/
│ ├── SKILL.md # Required definition
│ └── examples/
├── agents/ # Sub-agents with dedicated LLM
│ └── my-agent.md
├── commands/ # Commands invokable by /domain:name
│ └── domain/
│ └── my-command.md
└── settings.json # Project-wide hooks
settings.local.json # Local hooks not committed