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
.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..claude/plugin-name.local.md in project root.gitignore)--- 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
--- 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.
#!/bin/bash set -euo pipefail # Define state file path STATE_FILE=".claude/my-plugin.local.md" # Quick exit if file doesn't exist if [[ ! -f "$STATE_FILE" ]]; then exit 0 # Plugin not configured, skip fi # 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 enabled if [[ "$ENABLED" != "true" ]]; then exit 0 # Disabled fi # Use configuration in hook logic if [[ "$STRICT_MODE" == "true" ]]; then # Apply strict validation # ... fi
examples/read-settings-hook.sh for complete working example.--- 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
--- 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
# Extract everything between --- markers FRONTMATTER=$(sed -n '/^---$/,/^---$/{ /^---$/d; p; }' "$FILE")
VALUE=$(echo "$FRONTMATTER" | grep '^field_name:' | sed 's/field_name: *//' | sed 's/^"\(.*\)"$/\1/')ENABLED=$(echo "$FRONTMATTER" | grep '^enabled:' | sed 's/enabled: *//') # Compare: if [[ "$ENABLED" == "true" ]]; then `**Numeric fields:**` MAX=$(echo "$FRONTMATTER" | grep '^max_value:' | sed 's/max_value: *//') # Use: if [[ $MAX -gt 100 ]]; then
---:# Get everything after closing --- BODY=$(awk '/^---$/{i++; next} i>=2' "$FILE")
#!/bin/bash STATE_FILE=".claude/security-scan.local.md" # Quick exit if not configured if [[ ! -f "$STATE_FILE" ]]; then exit 0 fi # Read enabled flag FRONTMATTER=$(sed -n '/^---$/,/^---$/{ /^---$/d; p; }' "$STATE_FILE") ENABLED=$(echo "$FRONTMATTER" | grep '^enabled:' | sed 's/enabled: *//') if [[ "$ENABLED" != "true" ]]; then exit 0 # Disabled fi # Run hook logic # ...
--- agent_name: auth-agent task_number: 3.5 pr_number: 1234 coordinator_session: team-leader enabled: true dependencies: ["Task 3.4"] --- # Task Assignment Implement JWT authentication for the API. **Success Criteria:** - Authentication endpoints created - Tests passing - PR created and CI green `Read from hooks to coordinate agents:` AGENT_NAME=$(echo "$FRONTMATTER" | grep '^agent_name:' | sed 's/agent_name: *//') COORDINATOR=$(echo "$FRONTMATTER" | grep '^coordinator_session:' | sed 's/coordinator_session: *//') # Send notification to coordinator tmux send-keys -t "$COORDINATOR" "Agent $AGENT_NAME completed task" Enter
--- validation_level: strict max_file_size: 1000000 allowed_extensions: [".js", ".ts", ".tsx"] enable_logging: true --- # Validation Configuration Strict mode enabled for this project. All writes validated against security policies. `Use in hooks or commands:` LEVEL=$(echo "$FRONTMATTER" | grep '^validation_level:' | sed 's/validation_level: *//') case "$LEVEL" in strict) # Apply strict validation ;; standard) # Apply standard validation ;; lenient) # Apply lenient validation ;; esac
# 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
## 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.
.claude/plugin-name.local.md format.local.md suffix for user-local files.claude/).md without .local (might be committed).gitignore:.claude/*.local.md .claude/*.local.json
if [[ ! -f "$STATE_FILE" ]]; then # Use defaults ENABLED=true MODE=standard else # Read from file # ... fi
MAX=$(echo "$FRONTMATTER" | grep '^max_value:' | sed 's/max_value: *//') # Validate numeric range if ! [[ "$MAX" =~ ^[0-9]+$ ]] || [[ $MAX -lt 1 ]] || [[ $MAX -gt 100 ]]; then echo "⚠️ Invalid max_value in settings (must be 1-100)" >&2 MAX=10 # Use default fi
## 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
# Escape quotes in user input SAFE_VALUE=$(echo "$USER_INPUT" | sed 's/"/\\"/g') # Write to file cat > "$STATE_FILE" <<EOF --- user_setting: "$SAFE_VALUE" --- EOF
FILE_PATH=$(echo "$FRONTMATTER" | grep '^data_file:' | sed 's/data_file: *//') # Check for path traversal if [[ "$FILE_PATH" == *".."* ]]; then echo "⚠️ Invalid path in settings (path traversal)" >&2 exit 2 fi
chmod 600)--- 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.
enabled: true/false--- 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.
project-root/ └── .claude/ └── plugin-name.local.md `### Frontmatter Parsing` # Extract frontmatter FRONTMATTER=$(sed -n '/^---$/,/^---$/{ /^---$/d; p; }' "$FILE") # Read field VALUE=$(echo "$FRONTMATTER" | grep '^field:' | sed 's/field: *//' | sed 's/^"\(.*\)"$/\1/') `### Body Parsing` # Extract body (after second ---) BODY=$(awk '/^---$/{i++; next} i>=2' "$FILE") `### Quick Exit Pattern` if [[ ! -f ".claude/my-plugin.local.md" ]]; then exit 0 # Not configured fi
references/parsing-techniques.md - Complete guide to parsing YAML frontmatter and markdown bodiesreferences/real-world-examples.md - Deep dive into multi-agent-swarm and ralph-wiggum implementationsexamples/:read-settings-hook.sh - Hook that reads and uses settingscreate-settings-command.md - Command that creates settings fileexample-settings.md - Template settings filescripts/:validate-settings.sh - Validate settings file structureparse-frontmatter.sh - Extract frontmatter fields.claude/*.local.md