Configure per-project plugin settings via .claude/plugin-name.local.md files. Use when building plugins with user-configurable behavior, storing agent state, or controlling hooks.
Installs into .claude/skills of the current project.
Are you the author of Plugin Settings?
Add the live security badge to your README. It updates with every re-scan.
[](https://www.skillsdirectory.com/skills/laurigates-plugin-settings)
---
name: plugin-settings
description: Configure per-project plugin settings via .claude/plugin-name.local.md files. Use when building plugins with user-configurable behavior, storing agent state, or controlling hooks.
user-invocable: false
allowed-tools: Bash, Read, Write, Edit, Grep, Glob, TodoWrite
created: 2026-03-06
modified: 2026-07-28
compatibility: claude-code
reviewed: 2026-03-06
---
# Plugin Settings Pattern
Per-project plugin configuration using `.claude/plugin-name.local.md` files with YAML frontmatter for structured settings and markdown body for additional context.
Reach for a different mechanism when the settings are **global** (`~/.claude/settings.json`) or **purely structured** with no prose/prompt content (a plain `.json` file). The `.local.md` form earns its keep when config must carry prompts or instructions alongside structured fields.
## File Structure
### Location
```
project-root/
└── .claude/
└── plugin-name.local.md # Per-project, user-local settings
```
### Format
```markdown
---
enabled: true
mode: standard
max_retries: 3
allowed_extensions: [".js", ".ts", ".tsx"]
---
# Additional Context
Markdown body for prompts, instructions, or documentation
that hooks and agents can read and use.
```
### Naming Convention
- Use `.claude/plugin-name.local.md` format
- Match the plugin name exactly from `plugin.json`
- The `.local.md` suffix signals user-local (not committed to git)
### Gitignore
Add to project `.gitignore`:
```gitignore
.claude/*.local.md
```
## Reading Settings
### From Shell Scripts (Hooks)
Use the standard frontmatter extraction pattern from `.claude/rules/shell-scripting.md`:
```bash
#!/bin/bash
set -euo pipefail
STATE_FILE=".claude/my-plugin.local.md"
# Quick exit if not configured
[[ -f "$STATE_FILE" ]] || exit 0
# Extract field using standard pattern
extract_field() {
local file="$1" field="$2"
head -50 "$file" | grep -m1 "^${field}:" | sed 's/^[^:]*:[[:space:]]*//' | tr -d '\r'
}
plugin_enabled=$(extract_field "$STATE_FILE" "enabled")
[[ "$plugin_enabled" == "true" ]] || exit 0
plugin_mode=$(extract_field "$STATE_FILE" "mode")
```
### Extract Markdown Body
```bash
# Get content after the closing --- frontmatter delimiter
BODY=$(awk '/^---$/{i++; next} i>=2' "$STATE_FILE")
```
### From Skills and Agents
Skills and agents read settings with the Read tool:
```markdown
1. Check if `.claude/my-plugin.local.md` exists
2. Read the file and parse YAML frontmatter
3. Apply settings to current behavior
4. Use markdown body as additional context/prompt
```
## Common Patterns
### Pattern 1: Toggle-Based Hook Activation
Control hook activation without editing `hooks.json`:
```bash
#!/bin/bash
set -euo pipefail
STATE_FILE=".claude/security-scan.local.md"
[[ -f "$STATE_FILE" ]] || exit 0
extract_field() {
local file="$1" field="$2"
head -50 "$file" | grep -m1 "^${field}:" | sed 's/^[^:]*:[[:space:]]*//' | tr -d '\r'
}
scan_enabled=$(extract_field "$STATE_FILE" "enabled")
[[ "$scan_enabled" == "true" ]] || exit 0
# Hook logic runs only when enabled
```
### Pattern 2: Agent State Between Sessions
Store agent task state for multi-session work:
```markdown
---
agent_name: auth-implementation
task_number: 3.5
pr_number: 1234
enabled: true
---
# Current Task
Implement JWT authentication for the REST API.
Coordinate with auth-agent on shared types.
```
### Pattern 3: Configuration-Driven Validation
```markdown
---
validation_level: strict
max_file_size: 1000000
allowed_extensions: [".js", ".ts", ".tsx"]
---
```
```bash
validation_level=$(extract_field "$STATE_FILE" "validation_level")
case "$validation_level" in
strict) run_strict_checks ;;
standard) run_standard_checks ;;
*) run_standard_checks ;; # Default
esac
```
## Implementation Checklist
When adding settings to a plugin:
1. Design settings schema (fields, types, defaults)
2. Create template in plugin README
3. Add `.claude/*.local.md` to `.gitignore`
4. Implement parsing using `extract_field` pattern
5. Use quick-exit pattern (`[[ -f "$STATE_FILE" ]] || exit 0`)
6. Provide sensible defaults when file is missing
7. Document that changes require Claude Code restart (hooks only)
## Best Practices
| Practice | Details |
|----------|---------|
| Quick exit | Check file existence first, exit 0 if absent |
| Sensible defaults | Provide fallback values when settings file is missing |
| Use `extract_field` | Standard frontmatter extraction from `shell-scripting.md` |
| Validate values | Check numeric ranges, enum membership |
| File permissions | Settings files should be user-readable only (`chmod 600`) |
| Restart notice | Document that hook-related changes need a Claude Code restart |