This skill should be used when the user asks about "plugin settings", "store plugin configuration", "user-configurable plugin", ".local.md files", "plugin state files", "read YAML frontmatter", "per-project plugin settings", or wants to make plugin behavior configurable. Documents the .claude/plugin-name.local.md pattern for storing plugin-specific configuration with YAML frontmatter and markdown content.
This skill should be used when the user asks about "plugin settings", "store plugin configuration", "user-configurable plugin", ".local.md files", "plugin state files", "read YAML frontmatter", "per-project plugin settings", or wants to make plugin behavior configurable. Documents the .claude/plugin-name.local.md pattern for storing plugin-specific configuration with YAML frontmatter and markdown content.
version
0.1.0
Plugin Settings Pattern for Claude Code Plugins
Overview
Plugins can store user-configurable settings and state in .claude/plugin-name.local.md files within the project directory. This pattern uses YAML frontmatter for structured configuration and markdown content for prompts or additional context.
Key characteristics:
File location: .claude/plugin-name.local.md in project root
Structure: YAML frontmatter + markdown body
Purpose: Per-project plugin configuration and state
Usage: Read from hooks, commands, and agents
Lifecycle: User-managed (not in git, should be in .gitignore)
File Structure
Basic Template
---
enabled: true
setting1: value1
setting2: value2
numeric_setting: 42
list_setting: ["item1", "item2"]
---
# Additional Context
This markdown body can contain:
- Task descriptions
- Additional instructions
- Prompts to feed back to Claude
- Documentation or notes
Example: Plugin State File
.claude/my-plugin.local.md:
---
enabled: true
strict_mode: false
max_retries: 3
notification_level: info
coordinator_session: team-leader
---
# Plugin Configuration
This plugin is configured for standard validation mode.
Contact @team-lead with questions.
Reading Settings Files
From Hooks (Bash Scripts)
Pattern: Check existence and parse frontmatter
#!/bin/bashset -euo pipefail
# Define state file path
STATE_FILE=".claude/my-plugin.local.md"# Quick exit if file doesn't existif [[ ! -f "$STATE_FILE" ]]; thenexit 0 # Plugin not configured, skipfi# Parse YAML frontmatter (between --- markers)
FRONTMATTER=$(sed -n '/^---$/,/^---$/{ /^---$/d; p; }'"$STATE_FILE")
# Extract individual fields
ENABLED=$(echo"$FRONTMATTER" | grep '^enabled:' | sed 's/enabled: *//' | sed 's/^"\(.*\)"$/\1/')
STRICT_MODE=$(echo"$FRONTMATTER" | grep '^strict_mode:' | sed 's/strict_mode: *//' | sed 's/^"\(.*\)"$/\1/')
# Check if enabledif [[ "$ENABLED" != "true" ]]; thenexit 0 # Disabledfi# Use configuration in hook logicif [[ "$STRICT_MODE" == "true" ]]; then# Apply strict validation# ...fi
See examples/read-settings-hook.sh for complete working example.
From Commands
Commands can read settings files to customize behavior:
---
description: Process data with plugin
allowed-tools: ["Read", "Bash"]
---# Process Command
Steps:
1. Check if settings exist at `.claude/my-plugin.local.md`2. Read configuration using Read tool
3. Parse YAML frontmatter to extract settings
4. Apply settings to processing logic
5. Execute with configured behavior
From Agents
Agents can reference settings in their instructions:
---
name: configured-agent
description: Agent that adapts to project settings
---
Check for plugin settings at `.claude/my-plugin.local.md`.
If present, parse YAML frontmatter and adapt behavior according to:
- enabled: Whether plugin is active
- mode: Processing mode (strict, standard, lenient)
- Additional configuration fields
# Setup Command
Steps:
1. Ask user for configuration preferences
2. Create `.claude/my-plugin.local.md` with YAML frontmatter
3. Set appropriate values based on user input
4. Inform user that settings are saved
5. Remind user to restart Claude Code for hooks to recognize changes
Template Generation
Provide template in plugin README:
## Configuration
Create `.claude/my-plugin.local.md` in your project:
\`\`\`markdown
---
enabled: true
mode: standard
max_retries: 3
---
# Plugin Configuration
Your settings are active.
\`\`\`
After creating or editing, restart Claude Code for changes to take effect.
Best Practices
File Naming
✅ DO:
Use .claude/plugin-name.local.md format
Match plugin name exactly
Use .local.md suffix for user-local files
❌ DON'T:
Use different directory (not .claude/)
Use inconsistent naming
Use .md without .local (might be committed)
Gitignore
Always add to .gitignore:
.claude/*.local.md
.claude/*.local.json
Document this in plugin README.
Defaults
Provide sensible defaults when settings file doesn't exist:
if [[ ! -f "$STATE_FILE" ]]; then# Use defaults
ENABLED=true
MODE=standard
else# Read from file# ...fi
Important: Settings changes require Claude Code restart.
Document in your README:
## Changing Settings
After editing `.claude/my-plugin.local.md`:
1. Save the file
2. Exit Claude Code
3. Restart: `claude` or `cc`4. New settings will be loaded
Hooks cannot be hot-swapped within a session.
Security Considerations
Sanitize User Input
When writing settings files from user input:
# Escape quotes in user input
SAFE_VALUE=$(echo"$USER_INPUT" | sed 's/"/\\"/g')
# Write to filecat > "$STATE_FILE" <<EOF
---
user_setting: "$SAFE_VALUE"
---
EOF
Validate File Paths
If settings contain file paths:
FILE_PATH=$(echo"$FRONTMATTER" | grep '^data_file:' | sed 's/data_file: *//')
# Check for path traversalif [[ "$FILE_PATH" == *".."* ]]; thenecho"⚠️ Invalid path in settings (path traversal)" >&2
exit 2
fi
Permissions
Settings files should be:
Readable by user only (chmod 600)
Not committed to git
Not shared between users
Real-World Examples
multi-agent-swarm Plugin
.claude/multi-agent-swarm.local.md:
---
agent_name: auth-implementation
task_number: 3.5
pr_number: 1234
coordinator_session: team-leader
enabled: true
dependencies: ["Task 3.4"]
additional_instructions: Use JWT tokens, not sessions
---
# Task: Implement Authentication
Build JWT-based authentication for the REST API.
Coordinate with auth-agent on shared types.
Hook usage (agent-stop-notification.sh):
Checks if file exists (line 15-18: quick exit if not)
Parses frontmatter to get coordinator_session, agent_name, enabled
Sends notifications to coordinator if enabled
Allows quick activation/deactivation via enabled: true/false
ralph-loop Plugin
.claude/ralph-loop.local.md:
---
iteration: 1
max_iterations: 10
completion_promise: "All tests passing and build successful"
---
Fix all the linting errors in the project.
Make sure tests pass after each fix.
Hook usage (stop-hook.sh):
Checks if file exists (line 15-18: quick exit if not active)