From craft
This skill should be used when the user asks to "create a Homebrew formula", "fix brew audit errors", "write a formula", "Homebrew best practices", or needs help with Homebrew formula syntax, dependencies, and troubleshooting. Expert knowledge of Homebrew formula creation and maintenance.
How this skill is triggered — by the user, by Claude, or both
Slash command
/craft:homebrew-formula-expertThe summary Claude sees in its skill listing — used to decide when to auto-load this skill
Deep expertise in Homebrew formula creation, maintenance, and best practices.
Deep expertise in Homebrew formula creation, maintenance, and best practices.
Surface scope: Homebrew installs plugins to the Claude Code CLI surface (
~/.claude/). Claude Desktop (DXT/MCPB extensions — a different, MCP-server format) and Cowork are separate surfaces; seedist-extrasandcommands/dist/surfaces.mdfor the full model.
class MyApp < Formula
# Metadata
desc "Short description (< 80 chars, no 'A' or 'An' prefix)"
homepage "https://github.com/user/repo"
url "https://github.com/user/repo/archive/v1.0.0.tar.gz"
sha256 "64-char-hex-string"
license "MIT" # SPDX identifier
head "https://github.com/user/repo.git", branch: "main"
# Dependencies
depends_on "[email protected]"
depends_on "cmake" => :build # Build-time only
# Installation
def install
# Installation logic
end
# Verification
test do
# Test that installation worked
end
end
class MyPythonApp < Formula
include Language::Python::Virtualenv
desc "My Python application"
homepage "https://github.com/user/repo"
url "https://github.com/user/repo/archive/v1.0.0.tar.gz"
sha256 "..."
license "MIT"
depends_on "[email protected]"
# For packages with many deps, list resources
resource "requests" do
url "https://files.pythonhosted.org/..."
sha256 "..."
end
def install
virtualenv_install_with_resources
# Or manual:
# venv = virtualenv_create(libexec, "python3.12")
# venv.pip_install resources
# venv.pip_install buildpath
# bin.install_symlink libexec/"bin/myapp"
end
test do
assert_match version.to_s, shell_output("#{bin}/myapp --version")
end
end
class MyNodeApp < Formula
desc "My Node.js application"
homepage "https://github.com/user/repo"
url "https://registry.npmjs.org/myapp/-/myapp-1.0.0.tgz"
sha256 "..."
license "MIT"
depends_on "node"
def install
system "npm", "install", *std_npm_args
bin.install_symlink Dir["#{libexec}/bin/*"]
end
test do
assert_match version.to_s, shell_output("#{bin}/myapp --version")
end
end
class MyGoApp < Formula
desc "My Go application"
homepage "https://github.com/user/repo"
url "https://github.com/user/repo/archive/v1.0.0.tar.gz"
sha256 "..."
license "MIT"
depends_on "go" => :build
def install
system "go", "build", *std_go_args(ldflags: "-s -w -X main.version=#{version}")
end
test do
assert_match version.to_s, shell_output("#{bin}/myapp --version")
end
end
class MyRustApp < Formula
desc "My Rust application"
homepage "https://github.com/user/repo"
url "https://github.com/user/repo/archive/v1.0.0.tar.gz"
sha256 "..."
license "MIT"
depends_on "rust" => :build
def install
system "cargo", "install", *std_cargo_args
end
test do
assert_match version.to_s, shell_output("#{bin}/myapp --version")
end
end
desc)# Good
desc "Terminal optimizer for AI-assisted development"
# Bad
desc "A terminal optimizer for AI-assisted development" # No 'A'
desc "aiterm is a terminal optimizer..." # No app name
desc "..." # Too long (> 80 chars)
# GitHub release (preferred)
url "https://github.com/user/repo/archive/v1.0.0.tar.gz"
# GitHub release with refs/tags (more explicit)
url "https://github.com/user/repo/archive/refs/tags/v1.0.0.tar.gz"
# PyPI
url "https://files.pythonhosted.org/packages/.../myapp-1.0.0.tar.gz"
# npm
url "https://registry.npmjs.org/myapp/-/myapp-1.0.0.tgz"
# From URL
curl -sL https://github.com/user/repo/archive/v1.0.0.tar.gz | shasum -a 256
# From file
shasum -a 256 myapp-1.0.0.tar.gz
license "MIT"
license "Apache-2.0"
license "GPL-3.0-or-later"
license any_of: ["MIT", "Apache-2.0"] # Dual license
# Runtime dependency
depends_on "[email protected]"
# Build-time only
depends_on "cmake" => :build
# Optional
depends_on "imagemagick" => :optional
# Recommended
depends_on "jq" => :recommended
# Platform-specific
depends_on "linux-headers" => :build if OS.linux?
# Problem: pip install fails due to missing deps
# Solution: Include as resources
resource "click" do
url "https://files.pythonhosted.org/packages/.../click-8.0.0.tar.gz"
sha256 "..."
end
# Or install individually
def install
venv = virtualenv_create(libexec, "python3.12")
venv.pip_install "click>=8.0"
venv.pip_install "rich>=13.0"
venv.pip_install buildpath
end
# Solution: Create symlink
def install
# ... installation ...
bin.install_symlink libexec/"bin/myapp"
end
# Problem: Command requires config file
# Solution: Create minimal config in test
test do
(testpath/".config/myapp").mkpath
(testpath/".config/myapp/config.json").write("{}")
assert_match version.to_s, shell_output("#{bin}/myapp --version")
end
# Run audit
brew audit --strict --online Formula/myapp.rb
# Common fixes:
# - desc: Remove 'A/An' prefix, keep < 80 chars
# - license: Use SPDX identifier
# - test: Must have test block
# - sha256: Must match URL content
# Structure
homebrew-tap/
├── Formula/
│ ├── myapp.rb
│ └── othertool.rb
└── README.md
# Naming: homebrew-<tapname>
# Users install: brew tap user/tapname
# Old
url "https://github.com/user/repo/archive/v1.0.0.tar.gz"
sha256 "old-sha256"
# New
url "https://github.com/user/repo/archive/v1.0.1.tar.gz"
sha256 "new-sha256"
# Install from local formula
brew install --build-from-source ./Formula/myapp.rb
# Reinstall after changes
brew reinstall --build-from-source ./Formula/myapp.rb
# Uninstall
brew uninstall myapp
class {{ClassName}} < Formula
{{#if python}}
include Language::Python::Virtualenv
{{/if}}
desc "{{description}}"
homepage "{{homepage}}"
url "{{url}}"
sha256 "{{sha256}}"
license "{{license}}"
{{#each dependencies}}
depends_on "{{this}}"
{{/each}}
def install
{{install_commands}}
end
test do
assert_match version.to_s, shell_output("#{bin}/{{binary}} --version")
end
end
For Claude Code plugins, use this special pattern with Claude detection:
class MyPlugin < Formula
desc "My plugin - Claude Code plugin"
homepage "https://github.com/user/my-plugin"
url "https://github.com/user/my-plugin/archive/refs/tags/v1.0.0.tar.gz"
sha256 "..."
license "MIT"
depends_on "jq" => :optional
def install
libexec.install Dir["*", ".*"].reject { |f| %w[. .. .git].include?(f) }
(bin/"my-plugin-install").write <<~EOS
#!/bin/bash
PLUGIN_NAME="my-plugin"
TARGET_DIR="$HOME/.claude/plugins/$PLUGIN_NAME"
SOURCE_DIR="$(brew --prefix)/opt/my-plugin/libexec"
echo "Installing plugin to Claude Code..."
mkdir -p "$HOME/.claude/plugins" 2>/dev/null || true
if [ -L "$TARGET_DIR" ] || [ -d "$TARGET_DIR" ]; then
rm -rf "$TARGET_DIR" 2>/dev/null || true
fi
ln -sf "$SOURCE_DIR" "$TARGET_DIR"
# Claude detection - skip auto-enable if Claude is running
SETTINGS_FILE="$HOME/.claude/settings.json"
AUTO_ENABLED=false
CLAUDE_RUNNING=false
if command -v lsof &>/dev/null; then
if lsof "$SETTINGS_FILE" 2>/dev/null | grep -q "claude"; then
CLAUDE_RUNNING=true
fi
elif pgrep -x "claude" >/dev/null 2>&1; then
CLAUDE_RUNNING=true
fi
if [ "$CLAUDE_RUNNING" = false ] && command -v jq &>/dev/null && [ -f "$SETTINGS_FILE" ]; then
TEMP_FILE=$(mktemp)
if jq --arg plugin "${PLUGIN_NAME}@local-plugins" '.enabledPlugins[$plugin] = true' "$SETTINGS_FILE" > "$TEMP_FILE" 2>/dev/null; then
mv "$TEMP_FILE" "$SETTINGS_FILE" 2>/dev/null && AUTO_ENABLED=true
fi
[ -f "$TEMP_FILE" ] && rm -f "$TEMP_FILE" 2>/dev/null
fi
echo "✅ Plugin installed!"
if [ "$AUTO_ENABLED" = true ]; then
echo "Plugin auto-enabled."
elif [ "$CLAUDE_RUNNING" = true ]; then
echo "Claude running - skipped auto-enable."
echo "Run: claude plugin install ${PLUGIN_NAME}@local-plugins"
else
echo "Run: claude plugin install ${PLUGIN_NAME}@local-plugins"
fi
EOS
chmod "+x", bin/"my-plugin-install"
end
def post_install
system bin/"my-plugin-install"
system "claude", "plugin", "update", "my-plugin@local-plugins" if which("claude")
rescue
nil
end
test do
assert_predicate libexec/".claude-plugin/plugin.json", :exist?
end
end
| Issue | Without Detection | With Detection |
|---|---|---|
| Claude running | Hangs indefinitely | Skips instantly |
| Install time | 2+ minutes | 2-3 seconds |
| User experience | Confusing hang | Clear message |
lsof check - Detects if Claude has settings.json openpgrep fallback - Checks if claude process is runningUse with:
/craft:dist:homebrew - Generate formula automatically/craft:check --for release - Validate before formula update/craft:git:tag - Create version for formulanpx claudepluginhub data-wise/craft --plugin craftCreates, edits, and verifies skills using a test-driven development approach with pressure scenarios and subagents.