Agent Skills: Plugin Settings Pattern

|

UncategorizedID: laurigates/claude-plugins/plugin-settings

Install this agent skill to your local

pnpm dlx add-skill https://github.com/laurigates/claude-plugins/tree/HEAD/agent-patterns-plugin/skills/plugin-settings

Skill Files

Browse the full folder contents for plugin-settings.

Download Skill

Loading file tree…

agent-patterns-plugin/skills/plugin-settings/SKILL.md

Skill Metadata

Name
plugin-settings
Description
|

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.

When to Use This Skill

| Use plugin settings when... | Use alternatives when... | |-----------------------------|--------------------------| | Plugin needs per-project configuration | Settings are global (use ~/.claude/settings.json) | | Hooks need runtime enable/disable control | Hook behavior is always-on | | Agent state persists between sessions | State is ephemeral within a session | | Users customize plugin behavior per-project | Plugin has no configurable behavior | | Configuration includes prose/prompts alongside structured data | All config is purely structured (use .json) |

File Structure

Location

project-root/
└── .claude/
    └── plugin-name.local.md    # Per-project, user-local settings

Format

---
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:

.claude/*.local.md

Reading Settings

From Shell Scripts (Hooks)

Use the standard frontmatter extraction pattern from .claude/rules/shell-scripting.md:

#!/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

# 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:

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:

#!/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:

---
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

---
validation_level: strict
max_file_size: 1000000
allowed_extensions: [".js", ".ts", ".tsx"]
---
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 |

Agentic Optimizations

| Context | Command | |---------|---------| | Check settings exist | [[ -f ".claude/plugin.local.md" ]] | | Extract single field | head -50 file \| grep -m1 "^field:" \| sed 's/^[^:]*:[[:space:]]*//' | | Extract body | awk '/^---$/{i++; next} i>=2' file | | Quick enable check | [[ "$(extract_field file enabled)" == "true" ]] |