Claude Code Plugins

Community-maintained marketplace

Feedback

Create or improve Makefiles with minimal complexity. Templates available: base, python-uv, python-fastapi, nodejs, go, chrome-extension.

Install Skill

1Download skill
2Enable skills in Claude

Open claude.ai/settings/capabilities and find the "Skills" section

3Upload to Claude

Click "Upload skill" and select the downloaded ZIP file

Note: Please verify skill by going through its instructions before using it.

SKILL.md


name: makefile description: Create or improve Makefiles with minimal complexity. Templates available: base, python-uv, python-fastapi, nodejs, go, chrome-extension. allowed-tools: Read, Write, Edit, Grep, Glob, Bash

Makefile Helper

Create Makefiles that are simple, discoverable, and maintainable.

Core Principles

  1. Default to rich help - Use categorized help with emoji headers unless user requests minimal
  2. Ask about structure upfront - For new Makefiles, ask: "Flat or modular? Rich help or minimal?"
  3. Follow existing conventions - Match the project's style if Makefile already exists
  4. Don't over-engineer - Solve the immediate need, not hypothetical futures
  5. Use uv run - Always run Python commands via uv run for venv context
  6. Explain decisions - If choosing flat/minimal, explain why before generating

When to Use This Skill

  • Creating a new Makefile for a project
  • Adding specific targets to an existing Makefile
  • Improving/refactoring an existing Makefile
  • Setting up CI/CD make targets

Quick Start

For new projects, use the appropriate template:

Project Type Template Complexity
Any project templates/base.mk Minimal
Python with uv templates/python-uv.mk Standard
Python FastAPI templates/python-fastapi.mk Full-featured
Node.js templates/nodejs.mk Standard
Go templates/go.mk Standard
Chrome Extension templates/chrome-extension.mk Modular

Chrome Extension Structure

The chrome extension template uses a modular structure:

Makefile                              # Main file with help + includes
makefiles/
  colors.mk                           # ANSI colors & print helpers
  common.mk                           # Shell flags, VERBOSE mode, guards
  build.mk                            # Build zip, version bump, releases
  dev.mk                              # Test, lint, clean, install

Copy from templates/chrome-extension-modules/ to your project's makefiles/ directory.

Key features:

  • build-release - Version bump menu (major/minor/patch) + zip for Chrome Web Store
  • build-beta - (Optional) GitHub releases with gh CLI
  • dev-test / dev-test-e2e - Vitest + Playwright testing
  • VERBOSE=1 make <target> - Show commands for debugging

Interaction Pattern

  1. Understand - What specific problem are we solving?
  2. Check existing - Is there already a Makefile? Read it first!
  3. Default to modular - For 5+ targets, use modular structure unless user requests flat
  4. Match preferences - Use python-fastapi.mk template style as default for rich help
  5. Explain structure - If you choose flat/minimal, explain the reasoning
  6. Iterate - Add complexity or simplify based on feedback

Naming Conventions

Use kebab-case with consistent prefix-based grouping:

# Good - consistent prefixes (hyphens, not underscores)
build-release, build-zip, build-clean    # Build tasks
dev-run, dev-test, dev-lint              # Development tasks
db-start, db-stop, db-migrate            # Database tasks
env-local, env-prod, env-show            # Environment tasks

# Internal targets - prefix with underscore to hide from help
_build-zip-internal, _prompt-version     # Not shown in make help

# Bad - inconsistent
run-dev, build, localEnv, test_net
build_release, dev_test                  # Underscores - don't use

Name targets after the action, not the tool:

# Good - describes what it does
remove-bg          # Removes background from image
format-code        # Formats code
lint-check         # Runs linting

# Bad - names the tool
rembg              # What does this do?
prettier           # Is this running prettier or configuring it?
eslint             # Unclear

Key Patterns

Always Use uv run for Python

# Good - uses uv run with ruff (modern tooling)
dev-check:
	uv run ruff check src/ tests/
	uv run ruff format --check src/ tests/
	uv run mypy src/

dev-format:
	uv run ruff check --fix src/ tests/
	uv run ruff format src/ tests/

# Bad - relies on manual venv activation
dev-format:
	ruff format .

Use uv sync (not pip install)

env-install:
	uv sync  # Uses pyproject.toml + lock file

Categorized Help (for 5+ targets)

help:
	@printf "$(BOLD)=== 🚀 API ===$(RESET)\n"
	@printf "$(CYAN)%-25s$(RESET) %s\n" "api-run" "Start server"
	@printf "%-25s $(GREEN)make api-run [--reload]$(RESET)\n" ""

Makefile ordering rule - help targets go LAST, just before catch-all:

  1. Configuration (?= variables)
  2. HELP_PATTERNS definition
  3. Imports (include ./makefiles/*.mk)
  4. Main targets (grouped by function)
  5. help: and help-unclassified: targets
  6. Catch-all %: rule (absolute last)

Preflight Checks

_check-docker:
	@docker info >/dev/null 2>&1 || { echo "Docker not running"; exit 1; }

db-start: _check-docker  # Runs check first
	docker compose up -d

External Tool Dependencies

When a target requires an external tool (not a system service):

  • Don't create public install targets (no make install-foo)
  • Use internal check as dependency (prefix with _, no ## comment)
  • Show install command on failure - tell user what to run, don't do it for them
# Internal check - hidden from help (no ##)
_check-rembg:
	@command -v rembg >/dev/null 2>&1 || { \
		printf "$(RED)$(CROSS) rembg not installed$(RESET)\n"; \
		printf "$(YELLOW)Run: uv tool install \"rembg[cli]\"$(RESET)\n"; \
		exit 1; \
	}

# Public target - uses check as dependency
.PHONY: remove-bg
remove-bg: _check-rembg ## Remove background from image
	rembg i "$(IN)" "$(OUT)"

Key points:

  • Name target after the action (remove-bg), not the tool (rembg)
  • Check runs automatically - user just runs make remove-bg
  • If tool missing, user sees exactly what command to run

Env File Loading

Load .env and export to child processes:

# At top of Makefile, after .DEFAULT_GOAL
-include .env
.EXPORT_ALL_VARIABLES:

For per-target env override:

# Allow: E2E_ENV=.test.env make test-e2e
test-e2e:
	@set -a && . "$${E2E_ENV:-.env}" && set +a && uv run pytest tests/e2e/

FIX Variable for Check/Format Targets

Use a FIX variable to toggle between check-only and auto-fix modes:

FIX ?= false

dev-check: ## Run linting and type checks (FIX=false: check only)
	$(call print_section,Running checks)
ifeq ($(FIX),true)
	uv run ruff check --fix src/ tests/
	uv run ruff format src/ tests/
else
	uv run ruff check src/ tests/
	uv run ruff format --check src/ tests/
endif
	uv run mypy src/
	$(call print_success,All checks passed)

In help output, show usage:

@printf "$(CYAN)%-25s$(RESET) %s\n" "dev-check" "Run linting (FIX=false: check only)"
@printf "%-25s $(GREEN)make dev-check FIX=true$(RESET)  <- auto-fix issues\n" ""

When to Modularize

Default to modular for any new Makefile with 5+ targets.

Use flat file only when:

  • Simple scripts or single-purpose tools
  • User explicitly requests it
  • < 5 targets with no expected growth

Standard modular structure:

Makefile              # Config, imports, help, catch-all
makefiles/
  colors.mk          # ANSI colors & print helpers
  common.mk          # Shell flags, VERBOSE, guards
  <domain>.mk        # Actual targets (build.mk, dev.mk, etc.)

Legacy Compatibility

Default: NO legacy aliases. Only add when:

  • User explicitly requests backwards compatibility
  • Existing CI/scripts depend on old names (verify with rg "make old-name")

When legacy IS needed, put them in a clearly marked section AFTER main targets but BEFORE help:

############################
### Legacy Target Aliases ##
############################

.PHONY: old-name
old-name: new_name ## (Legacy) Description

Key Rules

  • Always read existing Makefile before changes
  • Search codebase before renaming targets (rg "make old-target")
  • Test with make help and make -n target
  • Update docs after Makefile changes
  • Never add targets without clear purpose
  • No line-specific references - Avoid patterns like "Makefile:44" in docs/comments; use target names instead
  • Single source of truth - Config vars defined once in root Makefile, not duplicated in modules
  • Help coverage audit - All targets with ## must appear in either make help or make help-unclassified

Help System

ASCII box title for visibility:

help:
	@printf "\n"
	@printf "$(BOLD)$(CYAN)╔═══════════════════════════╗$(RESET)\n"
	@printf "$(BOLD)$(CYAN)║     Project Name          ║$(RESET)\n"
	@printf "$(BOLD)$(CYAN)╚═══════════════════════════╝$(RESET)\n\n"

Categorized help with sections:

	@printf "$(BOLD)=== 🏗️  Build ===$(RESET)\n"
	@grep -h -E '^build-[a-zA-Z_-]+:.*?## .*$$' ... | awk ...
	@printf "$(BOLD)=== 🔧 Development ===$(RESET)\n"
	@grep -h -E '^dev-[a-zA-Z_-]+:.*?## .*$$' ... | awk ...

Key help patterns:

  • help - Main categorized help
  • help-unclassified - Show targets not in any category (useful for auditing)
  • help-all - Show everything including internal targets
  • Hidden targets: prefix with _ (e.g., _build-internal)
  • Legacy targets: label with ## (Legacy) and filter from main help

Always include a Help section in make help output:

	@printf "$(BOLD)=== ❓ Help ===$(RESET)\n"
	@printf "$(CYAN)%-25s$(RESET) %s\n" "help" "Show this help"
	@printf "$(CYAN)%-25s$(RESET) %s\n" "help-unclassified" "Show targets not in categorized help"
	@printf "\n"

help-unclassified pattern (note the sed to strip filename prefix):

help-unclassified: ## Show targets not in categorized help
	@printf "$(BOLD)Targets not in main help:$(RESET)\n"
	@grep -E '^[a-zA-Z_-]+:.*?## .*$$' $(MAKEFILE_LIST) | \
		sed 's/^[^:]*://' | \
		grep -v -E '^(env-|dev-|clean|help)' | \
		awk 'BEGIN {FS = ":.*?## "}; {printf "$(CYAN)%-25s$(RESET) %s\n", $$1, $$2}' || \
		printf "  (none)\n"

Usage examples on second line in green:

# Target description on first line
@printf "$(CYAN)%-40s$(RESET) %s\n" "remove-bg" "Remove background from image"
# Usage example on second line - use GREEN (not DIM, which appears grey)
@printf "%-40s $(GREEN)make remove-bg IN=logo.png [OUT=logo_nobg.png]$(RESET)\n" ""

Usage line format:

  • Show on a separate second line (not inline with description)
  • Use $(GREEN) for visibility (avoid $(DIM) - appears grey/unreadable)
  • Include full command with realistic example values
  • Show optional params in brackets with sensible defaults

Catch-all redirects to help:

%:
	@printf "$(RED)Unknown target '$@'$(RESET)\n"
	@$(MAKE) help

Common Pitfalls

Issue Fix
$var in shell loops Use $$var to escape for make
Catch-all %: shows error Redirect to @$(MAKE) help instead
Config vars scattered Put all ?= overridable defaults at TOP of root Makefile
HELP_PATTERNS mismatch Must match grep patterns in help target exactly
Duplicate defs in modules Define once in root, reference in modules
Trailing whitespace in vars Causes path splitting bugs - trim all variable definitions
.PHONY on file targets Only use .PHONY for non-file targets
Too many public targets Don't expose install-X or check-X - use internal _check-X dependencies
$(DIM) for usage text Appears grey/unreadable - use $(GREEN) instead
Target named after tool Name after the action: remove-bg not rembg
help-unclassified shows filename Use sed 's/^[^:]*://' to strip Makefile: prefix
No .env export Add -include .env and .EXPORT_ALL_VARIABLES: at top

Cleanup Makefile Workflow

When user says "cleanup my makefiles":

IMPORTANT: Build a plan first and explain it to the user before implementing anything.

Phase 1: Audit (no changes yet)

make help                    # See categorized targets
make help-unclassified       # Find orphaned targets
cat Makefile                 # Read structure
ls makefiles/*.mk 2>/dev/null # Check if modular
rg "make " --type md         # Find external dependencies
grep -E '\s+$' Makefile makefiles/*.mk  # Trailing whitespace

Phase 2: Build & Present Plan

Create a checklist of proposed changes:

  • Structure - Convert flat → modular (if 5+ targets) or vice versa
  • Legacy removal - List specific targets to delete (with dependency check)
  • Duplicates - List targets to consolidate
  • Renames - List old_namenew-name changes
  • Description rewrites - List vague descriptions to improve
  • Missing targets - Suggest targets that should exist (e.g., help-unclassified)
  • Ordering fixes - Config → imports → targets → help → catch-all

Ask user to approve the plan before proceeding.

Phase 3: Implement (after approval)

  1. Restructure (if needed) - Create makefiles/ directory, split into modules
  2. Remove legacy - Delete approved targets
  3. Consolidate duplicates - Merge into single targets
  4. Rename targets - Apply hyphen convention, add _ prefix for internal
  5. Rewrite descriptions - Make each ## explain the purpose
  6. Fix formatting
    • Usage examples in yellow: $(YELLOW)make foo$(RESET)
    • Remove trailing whitespace
    • .PHONY only on non-file targets
  7. Add missing pieces - help-unclassified, catch-all %:, etc.

Phase 4: Verify

make help          # Clean output?
make help-unclassified  # Should be empty or minimal
make -n <target>   # Dry-run key targets

What NOT to do without asking:

  • Rename targets that CI/scripts depend on
  • Remove targets that look unused
  • Change structure (flat ↔ modular) without approval

Files in This Skill

  • reference.md - Detailed patterns, categorized help, error handling
  • templates/ - Full copy-paste Makefiles for each stack
  • modules/ - Reusable pieces for complex projects

Example: Adding a Target

User: "Add a target to run my tests"

.PHONY: test
test: ## Run tests
	$(call print_section,Running tests)
	uv run pytest tests/ -v
	$(call print_success,Tests passed)

User: "Add database targets"

.PHONY: db-start db-stop db-migrate

db-start: _check-docker ## Start database
	docker compose up -d postgres

db-stop: ## Stop database
	docker compose down

db-migrate: _check-postgres ## Run migrations
	uv run alembic upgrade head