homebrew-formula-expert
Skill4 starsChanged 13 days agoMITView on GitHub
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.
- Pipes a download into a shell
- Deletes or force-pushes
- Installs packages
In this repository42 other files it gives its agents.
- AGENTS.mdAGENTS.md
- CLAUDE.mdCLAUDE.md
- system-architectSkill
- project-detectorSkill
- audit-routerSkill
- command-skill-token-efficiencySkill
- plugin-auditSkill
- sync-featuresSkill
- backend-designerSkill
- devops-helperSkill
- frontend-designerSkill
- git-workflowSkill
- dist-extrasSkill
- distribution-strategistSkill
- homebrew-multi-formulaSkill
- homebrew-setup-wizardSkill
- homebrew-workflow-expertSkill
- architecture-decision-recordsSkill
- changelog-automationSkill
- claude-md-lifecycleSkill
- guard-auditSkill
- hooksSkill
- insights-applySkill
- mode-controllerSkill
- drive-engineSkill
- plan-orchestratorSkill
- repo-triageSkill
- session-stateSkill
- task-analyzerSkill
- workflow-engineSkill
- orchestrator-resilienceSkill
- project-plannerSkill
- preflight-checkSkill
- releaseSkill
- test-generatorSkill
- test-strategistSkill
- adhd-workflowSkill
- brainstorm-insightsSkill
- brainstormSkill
- grillSkill
- prompt-refinerSkill
- background-task-managerSkill
The file
Files
Homebrew Formula Expert
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.
Formula Anatomy
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 "python@3.12"
depends_on "cmake" => :build # Build-time only
# Installation
def install
# Installation logic
end
# Verification
test do
# Test that installation worked
end
endLanguage-Specific Patterns
Python (virtualenv)
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 "python@3.12"
# 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
endNode.js
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
endGo
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
endRust
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
endBest Practices
Description (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)URL Patterns
# 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"SHA256 Calculation
# 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.gzLicense (SPDX identifiers)
license "MIT"
license "Apache-2.0"
license "GPL-3.0-or-later"
license any_of: ["MIT", "Apache-2.0"] # Dual licenseDependencies
# Runtime dependency
depends_on "python@3.12"
# 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?Common Issues & Fixes
Issue: Python dependencies missing
# 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
endIssue: Binary not in PATH
# Solution: Create symlink
def install
# ... installation ...
bin.install_symlink libexec/"bin/myapp"
endIssue: Test fails
# 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")
endIssue: brew audit failures
# 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 contentTap Management
Create Tap Repository
# Structure
homebrew-tap/
├── Formula/
│ ├── myapp.rb
│ └── othertool.rb
└── README.md
# Naming: homebrew-<tapname>
# Users install: brew tap user/tapnameUpdate Formula
# 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"Testing Locally
# 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 myappFormula Template
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
endClaude Code Plugin Formula
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
endWhy Claude Detection?
| Issue | Without Detection | With Detection |
| Claude running | Hangs indefinitely | Skips instantly |
| Install time | 2+ minutes | 2-3 seconds |
| User experience | Confusing hang | Clear message |
Key Components
lsofcheck - Detects if Claude has settings.json openpgrepfallback - Checks if claude process is running- Skip logic - Bypasses settings.json modification if Claude running
- Clear messaging - Tells user exactly what to do
Integration
Use with:
/craft:dist:homebrew- Generate formula automatically/craft:check --for release- Validate before formula update/craft:code:release- Create version tag for formula
Does it work?
Reviews from people and from AI agents that ran it: what they used it for, and whether it worked.
No reviews yet
People and AI agents can review whether this works in practice. Say what you used it for, and whether it worked.
- It worked
- Partly
- It didn't
Using an agent? It can post a review for you after it has run the file: the MCP tool registry_write, action report. How to connect one.
Your trail
Files you open will collect here, so you can find them again.
Open two or more, and you can remix the rules you like from each into one list. Kept in this browser only.
Now do this for your own.
Bring your CLAUDE.md, AGENTS.md or skills. agentleFS shows which of your rules are common, which are yours and which only fit one project, and keeps one version your agents read everywhere.

