/configure:claude-plugins
Configure a project to use the laurigates/claude-plugins Claude Code plugin marketplace. Sets up .claude/settings.json with permissions, marketplace enrollment, and enabledPlugins; and GitHub Actions workflows (claude.yml, claude-code-review.yml) with the marketplace pre-configured.
When to Use This Skill
| Use this skill when... | Use another approach when... |
|------------------------|------------------------------|
| Onboarding a new project to use Claude Code plugins | Configuring Claude Code settings unrelated to plugins |
| Setting up claude.yml and claude-code-review.yml workflows | Creating general GitHub Actions workflows (/configure:workflows) |
| Adding the laurigates/claude-plugins marketplace to a repo | Installing individual plugins manually |
| Merging plugin permissions into existing .claude/settings.json | Debugging Claude Code action failures (check GitHub Actions logs) |
| Selecting recommended plugins based on project type | Developing new plugins (see CLAUDE.md plugin lifecycle) |
Context
- Settings file exists: !
find . -maxdepth 3 -name 'settings.json' -path '*/.claude/*' - Workflows: !
find . -path '*/.github/workflows/*' -maxdepth 3 -name 'claude*.yml' - Git remotes: !
git remote -v - Project type indicators: !
find . -maxdepth 1 \( -name 'package.json' -o -name 'pyproject.toml' -o -name 'Cargo.toml' -o -name 'go.mod' -o -name 'Dockerfile' -o -name 'justfile' -o -name 'Justfile' \) - ESP/embedded indicators: !
find . -maxdepth 2 \( -name 'idf_component.yml' -o -name 'sdkconfig' -o -name 'CMakeLists.txt' \) - ESPHome indicators: !
find . -maxdepth 2 -name '*.yaml' -path '*/esphome/*'
Parameters
Parse from command arguments:
| Parameter | Description |
|-----------|-------------|
| --check-only | Report current configuration status without changes |
| --fix | Apply configuration automatically |
| --plugins | Comma-separated list of plugins to install (default: all recommended) |
| --exhaustive | Enumerate every marketplace plugin in enabledPlugins as an explicit true/false, so the project fully overrides the user-global enable state. Derives each boolean from repo context (see the defaults table in Step 3), preserves any value the project already set, and shows a diff before writing. Also triggered by "pin plugins" / "override global plugins for this project". |
| --workflows | Force-scaffold the claude.yml / claude-code-review.yml workflows even when no git remote is detected (default: scaffold only when a remote exists). |
| --no-workflows | Skip workflow scaffolding even when a git remote is present. Useful for local-only or vendored projects. |
Execution
Execute this Claude plugins configuration workflow:
Step 1: Detect current state and project stack
- Check for existing
.claude/settings.json - Check for existing
.github/workflows/claude.yml - Check for existing
.github/workflows/claude-code-review.yml - Detect project type (language, framework) from file indicators
- Check for a git remote with
git remote -v. Capturehas_remote = truewhen the output is non-empty,has_remote = falseotherwise. This gates workflow scaffolding in Steps 4 and 5 — workflows that cannot run (no remote → no GitHub Actions) should not be scaffolded by default.
Step 2: Select plugins
If --plugins is not specified, select recommended plugins based on detected project type:
| Project Indicator | Recommended Plugins |
|-------------------|---------------------|
| package.json | git-plugin, typescript-plugin, testing-plugin, code-quality-plugin |
| pyproject.toml / setup.py | git-plugin, python-plugin, testing-plugin, code-quality-plugin |
| Cargo.toml | git-plugin, rust-plugin, testing-plugin, code-quality-plugin |
| Dockerfile | Above + container-plugin |
| .github/workflows/ | Above + github-actions-plugin |
| idf_component.yml / sdkconfig | git-plugin, code-quality-plugin, testing-plugin, container-plugin |
| ESPHome yaml | git-plugin, python-plugin, code-quality-plugin |
| CMakeLists.txt (without Dockerfile / ESP-IDF / ESPHome indicators) | git-plugin, code-quality-plugin, testing-plugin, tools-plugin + clangd@claude-plugins-official (LSP) |
| Default (any) | git-plugin, code-quality-plugin, testing-plugin, tools-plugin |
Always include: configure-plugin, health-plugin, hooks-plugin.
Step 3: Configure .claude/settings.json
Create or merge into .claude/settings.json. The permissions baseline includes common entries plus stack-aware expansions. The stanza also enrolls the marketplace so web sessions retain plugin access.
Suffix forms — read this before copy-pasting. The two suffix forms below are not interchangeable. Using the wrong one silently breaks the config:
| Where | Suffix | Source of the suffix | |---|---|---| |
.claude/settings.json→enabledPlugins(Step 3) |<plugin>@claude-plugins| TheextraKnownMarketplaceskey in the same stanza | |.github/workflows/claude*.yml→plugins:(Steps 4–5) |<plugin>@laurigates-claude-plugins| Thenamefield inlaurigates/claude-plugins/.claude-plugin/marketplace.json|Wrong suffix in
enabledPlugins→ entry silently ignored (marketplace key does not match). Wrong suffix in the workflowplugins:block → action rejects the run.
Why enabledPlugins merge semantics matter
enabledPlugins is a per-key merging map across the settings hierarchy: a project entry overrides the matching global entry, but global entries the project does not mention still take effect. There is no enabledPluginsExclusive flag. So if a user has accidentally toggled an unwanted plugin globally (easy to do via the plugins UI), it leaks into every repo that does not explicitly set it to false.
| Mode | Project enabledPlugins contents | Behaviour vs global toggles |
|------|------------------------------------|------------------------------|
| Default (no flag) | Recommended plugins as true only | Lean. Vulnerable to global drift — any plugin the user toggled on globally is also active here. |
| --exhaustive | Every marketplace plugin enumerated as true or false | Deterministic. Project pin overrides every global toggle. Re-run when the marketplace adds plugins. |
Pick --exhaustive for repos that need a self-documenting, drift-resistant plugin set (infrastructure repos, repos shared with teammates / CI, repos sensitive to context tax from unrelated plugins). Use the default for personal scratch repos where global toggles are intentional.
Stack-aware permissions.allow baseline
Always include these common entries:
"Bash(git:*)", "Bash(gh:*)", "Bash(pre-commit:*)", "Bash(gitleaks:*)", "Bash(python3:*)"
Add stack-specific entries based on detected project type:
| Stack | Additional allow entries |
|---|---|
| Python (uv + ruff + ty) | "Bash(uv:*)", "Bash(uvx:*)", "Bash(ruff:*)", "Bash(ty:*)", "Bash(pytest:*)" |
| Node / TypeScript | "Bash(npm:*)", "Bash(pnpm:*)", "Bash(bun:*)", "Bash(tsc:*)", "Bash(eslint:*)", "Bash(prettier:*)", "Bash(vitest:*)" |
| Go | "Bash(go:*)", "Bash(gofmt:*)", "Bash(golangci-lint:*)" |
| Rust | "Bash(cargo:*)", "Bash(rustc:*)", "Bash(clippy:*)", "Bash(rustfmt:*)" |
| C / C++ (CMake) | "Bash(cmake:*)", "Bash(ctest:*)", "Bash(clang-format:*)", "Bash(clang-tidy:*)", "Bash(cppcheck:*)", "Bash(make:*)", "Bash(ninja:*)" |
| ESP-IDF / embedded | "Bash(idf.py:*)", "Bash(esptool:*)", "Bash(clang-format:*)", "Bash(cppcheck:*)", "Bash(docker:*)", "Bash(docker compose:*)", "Bash(just:*)", "Bash(make:*)" |
| ESPHome | "Bash(esphome:*)", "Bash(uv:*)", "Bash(uvx:*)" |
Use granular patterns only — do not add Bash(bash *) for CLI tools.
Exhaustive enumeration (when --exhaustive is set)
Build the full enabledPlugins map by reading every plugin name from the two relevant marketplaces, then writing each one with an explicit true/false. Every marketplace plugin is named, so the project's map fully overrides the user-global enable state — a plugin the user toggled on globally is forced off here unless it is explicitly true. This skill only ever writes <cwd>/.claude/settings.json; it never modifies ~/.claude/settings.json (user-global toggles stay as the user set them).
Deriving each plugin's boolean. Start from the Step 2 recommended set (those become true), then refine from repo context using the signals below. A plugin a value already exists for in the project's current enabledPlugins wins over the suggestion — only fill in missing entries from this logic, so a deliberate prior choice is never silently flipped.
| Signal in repo | Suggest enabling |
|---|---|
| pyproject.toml, requirements.txt, *.py | python-plugin |
| Cargo.toml, *.rs | rust-plugin (and bevy-plugin if Bevy is in deps) |
| go.mod, *.go | go-plugin (if present in the marketplace) |
| package.json, *.ts, *.tsx | typescript-plugin |
| *.tf, terraform/ | terraform-plugin |
| Dockerfile, compose.yaml | container-plugin |
| Chart.yaml, kustomization.yaml, k8s/ | kubernetes-plugin / helm-plugin |
| flake.nix, default.nix | nix-plugin |
| langchain in deps | langchain-plugin |
| home-assistant/hass configs | home-assistant-plugin |
| .github/workflows/ | github-actions-plugin |
| macOS host (uname -s = Darwin) | macos-plugin |
| Markdown-heavy docs/ or blog/ | documentation-plugin, blog-plugin |
Always-useful baseline (enable unless the user says otherwise): agents-plugin, agent-patterns-plugin, blueprint-plugin, code-quality-plugin, communication-plugin, configure-plugin, git-plugin, health-plugin, prose-plugin, taskwarrior-plugin, testing-plugin, tools-plugin, workflow-orchestration-plugin. Anything else not matched defaults to false.
-
Read the laurigates marketplace in priority order:
- If a local clone is present (e.g. inside this repo or a sibling checkout), parse
.claude-plugin/marketplace.json:jq -r '.plugins[].name' .claude-plugin/marketplace.json - Otherwise fetch over the GitHub API:
gh api repos/laurigates/claude-plugins/contents/.claude-plugin/marketplace.json --jq '.content' | base64 -d | jq -r '.plugins[].name' - Suffix each name with
@claude-pluginsto match the existing stanza format.
- If a local clone is present (e.g. inside this repo or a sibling checkout), parse
-
Add the official LSP plugins (
@claude-plugins-official). The currently shipped names are:pyright,typescript-language-server,rust-analyzer,gopls,swift-language-server,clangd. Mark the LSP that matches the detected stack astrue, the rest asfalse. If none match (no detectable stack), leave them allfalse. -
Compose the map with all entries, alphabetised within each marketplace block. Suffix
@claude-pluginsmatches theextraKnownMarketplaceskey (not the marketplacenameused in workflows):
{
"enabledPlugins": {
"accessibility-plugin@claude-plugins": false,
"agent-patterns-plugin@claude-plugins": false,
"agents-plugin@claude-plugins": false,
"...": "...",
"code-quality-plugin@claude-plugins": true,
"configure-plugin@claude-plugins": true,
"git-plugin@claude-plugins": true,
"health-plugin@claude-plugins": true,
"hooks-plugin@claude-plugins": true,
"testing-plugin@claude-plugins": true,
"typescript-plugin@claude-plugins": true,
"...": "...",
"clangd@claude-plugins-official": false,
"gopls@claude-plugins-official": false,
"pyright@claude-plugins-official": false,
"rust-analyzer@claude-plugins-official": false,
"swift-language-server@claude-plugins-official": false,
"typescript-language-server@claude-plugins-official": true
}
}
-
Drop unknown global entries. If the project's existing
enabledPlugins(or a merged-in copy of the user's global file) contains plugin names that are not in either marketplace listing, surface them in the report and ask whether to keep them. They may belong to a third marketplace the user has enrolled. Do not delete them silently — stale entries are harmless and the user may have notes about them. -
Show the diff before writing. Exhaustive mode rewrites the whole
enabledPluginsmap, so present the proposal before committing it. Group it as:- Already correct — count only, do not list each one.
- Will add — new key →
true/false, with a one-line reason for eachtrue. - Will change — existing key → flipped value, with the reason.
Render compact (a small markdown table or a
+/-list). Highlight any currently-trueentry the proposal would turn off — that is where users most often disagree. Then confirm once (accept "yes"/"go"/"apply", or let the user veto specific plugins and re-render). Skip the prompt under--check-only(report the diff only) and under--fixwhen the user already opted into non-interactive application.
Full settings.json stanza to merge
The extraKnownMarketplaces key (claude-plugins) is what each enabledPlugins entry's @claude-plugins suffix must match. The two stanzas are coupled — changing the key without also changing every suffix silently disables every plugin in enabledPlugins.
{
"permissions": {
"allow": [
"Bash(git:*)",
"Bash(gh:*)",
"Bash(pre-commit:*)",
"Bash(gitleaks:*)",
"Bash(python3:*)"
// ... plus stack-specific entries from the table above
]
},
"extraKnownMarketplaces": {
"claude-plugins": { // marketplace KEY (used by enabledPlugins suffix below)
"source": { "source": "github", "repo": "laurigates/claude-plugins" },
"autoUpdate": true
}
},
"enabledPlugins": {
"<selected-plugin-1>@claude-plugins": true, // suffix == extraKnownMarketplaces key, NOT marketplace name
"<selected-plugin-2>@claude-plugins": true
}
}
Replace <selected-plugin-N> with the plugin names selected in Step 2.
If .claude/settings.json already exists, MERGE without duplicating entries. Preserve any existing hooks, env, or other fields.
Step 4: Configure .github/workflows/claude.yml
Gate this step on a git remote being present. Decide whether to scaffold using this table:
| has_remote (from Step 1) | Flag | Behaviour |
|---|---|---|
| true | (default) or --workflows | Scaffold claude.yml |
| true | --no-workflows | Skip; record STATUS=SKIPPED (--no-workflows) |
| false | (default) | Default-skip — prompt the user via AskUserQuestion: "No git remote detected. claude.yml cannot run without GitHub Actions. Scaffold anyway (will sit dormant until a remote is added), or skip?" Default to skip on --check-only (no prompt). |
| false | --workflows | Force-scaffold anyway (e.g. the user plans to add a remote later) |
| false | --no-workflows | Skip without prompting |
When the decision is skip, do not write the file, and surface STATUS=SKIPPED (no git remote) in the Step 6 report so the omission is visible.
When the decision is scaffold, create .github/workflows/claude.yml with the Claude Code action configured to use the plugin marketplace. Workflow plugins: entries use the @laurigates-claude-plugins suffix — the marketplace name from marketplace.json, NOT the extraKnownMarketplaces key used in Step 3:
name: Claude Code
on:
issue_comment:
types: [created]
pull_request_review_comment:
types: [created]
issues:
types: [opened, assigned]
permissions:
contents: write
pull-requests: write
issues: write
id-token: write
jobs:
claude:
if: |
(github.event_name == 'issue_comment' && contains(github.event.comment.body, '@claude')) ||
(github.event_name == 'pull_request_review_comment' && contains(github.event.comment.body, '@claude')) ||
(github.event_name == 'issues' && contains(github.event.issue.body, '@claude'))
runs-on: ubuntu-latest
steps:
- name: Checkout repository
uses: actions/checkout@v6
with:
fetch-depth: 0
- name: Run Claude Code
uses: anthropics/claude-code-action@v1
with:
claude_code_oauth_token: ${{ secrets.CLAUDE_CODE_OAUTH_TOKEN }}
plugin_marketplaces: |
https://github.com/laurigates/claude-plugins.git
plugins: |
# suffix matches marketplace `name` in marketplace.json (NOT extraKnownMarketplaces key)
PLUGINS_LIST
Replace PLUGINS_LIST with the selected plugins in the format plugin-name@laurigates-claude-plugins, one per line. The suffix is the marketplace name field from laurigates/claude-plugins/.claude-plugin/marketplace.json — distinct from the @claude-plugins suffix used in .claude/settings.json (Step 3).
Step 5: Configure .github/workflows/claude-code-review.yml
Apply the same git-remote gate from Step 4. Reuse the user's answer (or the --workflows / --no-workflows flag) — do not re-prompt. If Step 4 skipped, skip Step 5 as well and record STATUS=SKIPPED (no git remote).
When the decision is scaffold, create .github/workflows/claude-code-review.yml for automatic PR reviews:
name: Claude Code Review
on:
pull_request:
types: [opened, synchronize, reopened]
permissions:
contents: read
pull-requests: write
issues: write
jobs:
review:
runs-on: ubuntu-latest
steps:
- name: Checkout repository
uses: actions/checkout@v6
with:
fetch-depth: 0
- name: Claude Code Review
uses: anthropics/claude-code-action@v1
with:
claude_code_oauth_token: ${{ secrets.CLAUDE_CODE_OAUTH_TOKEN }}
prompt: |
Review this pull request. Focus on:
- Code quality and best practices
- Potential bugs or security issues
- Test coverage gaps
- Documentation needs
claude_args: "--max-turns 5"
plugin_marketplaces: |
https://github.com/laurigates/claude-plugins.git
plugins: |
# suffix matches marketplace `name` in marketplace.json (NOT extraKnownMarketplaces key)
code-quality-plugin@laurigates-claude-plugins
testing-plugin@laurigates-claude-plugins
Step 6: Report results
Print a status report:
Claude Plugins Configuration Report
=====================================
Repository: <repo-name>
.claude/settings.json:
Status: <CREATED|UPDATED|EXISTS>
Mode: <DEFAULT|EXHAUSTIVE>
Permissions: <N> allowed patterns configured
Marketplace: laurigates/claude-plugins (extraKnownMarketplaces)
Plugins pinned: <N> total (<E> enabled, <D> disabled) # exhaustive only
Enabled plugins: <list>
Git remote: <PRESENT|MISSING>
.github/workflows/claude.yml:
Status: <CREATED|UPDATED|EXISTS|SKIPPED (no git remote)|SKIPPED (--no-workflows)>
Marketplace: laurigates/claude-plugins
Plugins: <list>
.github/workflows/claude-code-review.yml:
Status: <CREATED|UPDATED|EXISTS|SKIPPED (no git remote)|SKIPPED (--no-workflows)>
Trigger: PR opened/synchronize/reopened
Next Steps:
1. Add CLAUDE_CODE_OAUTH_TOKEN to repository secrets
Settings > Secrets and variables > Actions > New repository secret
2. Commit and push the new/updated files
3. Test by mentioning @claude in a PR comment
4. (exhaustive mode) Re-run when the marketplace adds new plugins so they
get an explicit `false` rather than inheriting the global toggle
5. (no remote) When you add a GitHub remote later, re-run with `--workflows`
to scaffold the workflows that were skipped
Agentic Optimizations
| Context | Command |
|---------|---------|
| Quick status check | /configure:claude-plugins --check-only |
| Auto-configure all | /configure:claude-plugins --fix |
| Specific plugins only | /configure:claude-plugins --fix --plugins git-plugin,testing-plugin |
| Pin against global drift | /configure:claude-plugins --fix --exhaustive |
| Settings only (local-only repo) | /configure:claude-plugins --fix --no-workflows |
| Pre-stage workflows before remote exists | /configure:claude-plugins --fix --workflows |
| List marketplace plugin names | jq -r '.plugins[].name' .claude-plugin/marketplace.json |
| Verify settings exist | find .claude -maxdepth 1 -name 'settings.json' |
| List Claude workflows | find .github/workflows -name 'claude*.yml' |
| Check for git remote | git remote -v |
Flags
| Flag | Description |
|------|-------------|
| --check-only | Report current status without making changes |
| --fix | Apply all configuration automatically |
| --plugins | Override automatic plugin selection |
| --exhaustive | Enumerate every marketplace plugin as an explicit true/false so the project fully overrides global toggles. Derives booleans from repo context, preserves existing project values, and diffs before writing. Triggered by "pin plugins" / "override global plugins for this project". |
| --workflows | Force-scaffold the claude.yml / claude-code-review.yml workflows even when no git remote is detected. By default, workflow scaffolding is skipped on remote-less repos to avoid dormant files. |
| --no-workflows | Skip workflow scaffolding even when a git remote is present. Useful for local-only or vendored projects where settings should be configured but Actions should not. |
Important Notes
- The
CLAUDE_CODE_OAUTH_TOKENsecret must be added manually to the repository extraKnownMarketplacesin.claude/settings.jsonis the key to surviving ephemeral web sessions — without it, the marketplace is only enrolled via CI- Workflow scaffolding is gated on a git remote. A repo without a remote cannot run GitHub Actions, so
claude.ymlandclaude-code-review.ymlare skipped by default — writing them would create dormant files that confuse future readers. Override with--workflowsto pre-stage them before adding a remote. - Two distinct suffix forms (see the callout at the top of Step 3 for the canonical table):
enabledPluginsentries use<plugin>@claude-plugins— theextraKnownMarketplaceskey- Workflow
plugins:blocks use<plugin>@laurigates-claude-plugins— the marketplacenamefield frommarketplace.json
- Mixing the two forms silently breaks the config —
enabledPluginsentries with the wrong suffix are ignored; workflowplugins:entries with the wrong suffix are rejected by the action
See Also
/configure:repo- Full end-to-end driver (runs this skill + web-session + health check)/configure:web-session- SessionStart hook for infrastructure tools/configure:all- Run all compliance checksclaude-security-settingsskill - Claude Code security settings