Skip to content

Commit 1904604

Browse files
aRustyDevclaude
andauthored
feat(skills): add pkgmgr-homebrew-formula-dev skill (#819)
* feat(skills): add pkgmgr-homebrew-formula-dev skill scaffold SKILL.md with research, formula structure, and template pipeline docs. Includes .gitignore, package.json for mustache/ajv deps, and settings. Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com> * feat(skills): add JSON schema and preprocessing helper formula.schema.ts defines draft-2020-12 schema for formula validation. formula.helper.ts exports pascalCase, renderLicense, preprocessFormulas, loadPartials, and parseInput for the rendering pipeline. Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com> * feat(skills): add Mustache templates with language partials main.mustache renders shared formula fields and dispatches install blocks to language-specific partials (go, rust, python, zig, cmake, autotools, meson) via {{#is_<lang>}} sections. Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com> * feat(skills): add justfile with javascript-recipe and test recipes javascript-recipe validates JSON input against schema via AJV, preprocesses formulas, and renders through Mustache with auto-loaded language partials. test recipe runs all shell-based test cases. Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com> * test(skills): add test data fixtures and test cases 7 JSON fixtures covering go, rust, python, head-only, service, and 2 invalid schemas. 6 shell test cases assert rendered output and validation rejection. run-all.sh delegates to just test. Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com> * feat(skills): add pipeline-generated formula examples Reference formulas for go, rust, python, head-only, and service scenarios, generated from the JSON→Mustache pipeline. Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com> * docs(skills): add language-specific research guides and reference docs Go, Rust, and Python lang docs with research tables, quick-check commands, install patterns, schema fields, and common issues. Includes checklists, FAQ, testing patterns, and Brewfile. Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com> * docs(skills): add bottle attestation and build provenance reference Covers Sigstore-based attestation, SLSA Build L2 provenance, GitHub Actions setup with actions/attest-build-provenance, and Homebrew::Attestation API for custom tap verification. Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com> --------- Co-authored-by: Claude Opus 4.5 <noreply@anthropic.com>
1 parent 3875eeb commit 1904604

48 files changed

Lines changed: 2787 additions & 0 deletions

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

.beads/issues.jsonl

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,4 @@
1+
{"id":"ai-959","title":"analyze fit of spec-workflow-mcp","description":"https://github.com/Pimzino/spec-workflow-mcp\nalso 'claude-code-spec-workflow'\n","status":"open","priority":2,"issue_type":"task","owner":"36318507+aRustyDev@users.noreply.github.com","created_at":"2026-01-30T02:53:07.086543-05:00","created_by":"aRustyDev","updated_at":"2026-01-30T02:53:46.93047-05:00"}
2+
{"id":"ai-aem","title":"add frontmatter scopes","description":"add scopes (user/project/component/etc) to each context file","status":"open","priority":2,"issue_type":"task","owner":"36318507+aRustyDev@users.noreply.github.com","created_at":"2026-01-30T02:16:52.824174-05:00","created_by":"aRustyDev","updated_at":"2026-01-30T02:16:52.824174-05:00"}
3+
{"id":"ai-bt2","title":"add command namespacing in frontmatter","description":"use build time logic to remove illegal frontmatter keys\n\nOrganize commands in subdirectories. The subdirectories are used for organization and appear in the command description, but they do not affect the command name itself. The description will show whether the command comes from the project directory (`.claude/commands`) or the user-level directory (`~/.claude/commands`), along with the subdirectory name.\n\nConflicts between user and project level commands are not supported. Otherwise, multiple commands with the same base file name can coexist.\n\nFor example, a file at `.claude/commands/frontend/component.md` creates the command `/component` with description showing \"(project:frontend)\".\nMeanwhile, a file at `~/.claude/commands/component.md` creates the command `/component` with description showing \"(user)\".\n\n```yaml\n---\nallowed-tools: Bash(git add:*), Bash(git status:*), Bash(git commit:*)\nargument-hint: [message]\ndescription: Create a git commit\nmodel: claude-3-5-haiku-20241022\n---\n```\n","status":"open","priority":2,"issue_type":"task","owner":"36318507+aRustyDev@users.noreply.github.com","created_at":"2026-01-30T02:18:13.280099-05:00","created_by":"aRustyDev","updated_at":"2026-01-30T02:24:12.262077-05:00"}
4+
{"id":"ai-exp","title":"question: is it a good pattern to use progressive disclosure in sub-agents?","status":"open","priority":2,"issue_type":"task","owner":"36318507+aRustyDev@users.noreply.github.com","created_at":"2026-01-30T02:31:30.657878-05:00","created_by":"aRustyDev","updated_at":"2026-01-30T02:31:30.657878-05:00"}
Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
node_modules
Lines changed: 18 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,18 @@
1+
<!--https://github.com/GongRzhe/JSON-MCP-Server-->
2+
<!--https://lobehub.com/mcp/kehvinbehvin-json-mcp-filter-->
3+
<!--https://lobehub.com/mcp/kehvinbehvin-json-mcp-->
4+
<!--https://lobehub.com/mcp/buzdolapci-json-validate-->
5+
<!--https://lobehub.com/mcp/gage-russell-jsonresume-mcp-->
6+
<!--https://lobehub.com/mcp/buzdolapci-json-validate-->
7+
<!--https://lobehub.com/mcp/gszecsenyi-schemavault-->
8+
<!--https://lobehub.com/mcp/bablu-singh-json-mapping-and-context-mcp-server-->
9+
<!--https://lobehub.com/mcp/semanticintent-semantic-context-mcp-->
10+
<!--https://lobehub.com/mcp/5queezer-mcp-json-->
11+
<!--https://lobehub.com/mcp/berrydev-ai-json-mcp-server-->
12+
<!--https://lobehub.com/mcp/berrydev-ai-jq-mcp-server-->
13+
<!--https://github.com/mgraczyk/json-query-mcp-->
14+
<!--https://github.com/vadimnastoyashchy/json-mcp-->
15+
<!--https://github.com/gongrzhe/json-mcp-server-->
16+
<!--https://www.pulsemcp.com/servers/jeannier-homebrew-->
17+
<!--https://www.pulsemcp.com/servers/tatn-unified-diff-generator-->
18+
<!--https://www.pulsemcp.com/servers/benjamine-jsondiffpatch-->
Lines changed: 172 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,172 @@
1+
---
2+
name: pkgmgr-homebrew-formula-dev
3+
description: Create, test, and maintain Homebrew formulas. Use when adding packages to a Homebrew tap, debugging formula issues, running brew audit/test, or automating version updates with livecheck. Use when creating a new Homebrew formula for a project.
4+
---
5+
6+
# Homebrew Formula Development
7+
8+
Guide for researching, creating, testing, and maintaining Homebrew formulas in a custom tap.
9+
10+
## When to Use This Skill
11+
12+
- Creating a new Homebrew formula for a project
13+
- Debugging formula build or test failures
14+
- Running local validation before CI
15+
- Understanding Homebrew's Ruby DSL
16+
- Setting up livecheck for automatic version detection
17+
18+
## Template Pipeline
19+
20+
This skill includes a **JSON Schema → Mustache template** pipeline for generating formulas from structured data.
21+
22+
### Workflow
23+
24+
1. Create a JSON file conforming to `scripts/formula.schema.ts`
25+
2. Run `just javascript-recipe <path-to-json>` to validate and render
26+
3. The pipeline validates with AJV, preprocesses (PascalCase, language dispatch, license rendering), then renders via Mustache
27+
28+
### Key Files
29+
30+
| File | Purpose |
31+
|------|---------|
32+
| `scripts/formula.schema.ts` | JSON Schema (draft-2020-12) defining formula structure |
33+
| `scripts/formula.helper.ts` | Preprocessing: PascalCase, license rendering, install flattening, partials loading |
34+
| `reference/templates/main.mustache` | Main template — renders all shared fields, dispatches to language partials |
35+
| `reference/templates/langs/*.mustache` | Language-specific install partials (go, rust, python, zig, cmake, autotools, meson) |
36+
| `test/data/*.json` | Test fixtures covering each scenario |
37+
| `test/cases/*.sh` | Test cases that validate rendered output |
38+
39+
### Running
40+
41+
```bash
42+
# Render a formula from JSON
43+
just javascript-recipe path/to/formula.json
44+
45+
# Run all tests
46+
just test
47+
```
48+
49+
### Adding a New Language
50+
51+
1. Add `install-<lang>` definition to `scripts/formula.schema.ts`
52+
2. Add language dispatch `allOf` entry in the `formula` definition
53+
3. Create `reference/templates/langs/<lang>.mustache` partial
54+
4. Add `"<lang>"` to the `language` enum
55+
5. Add a test fixture in `test/data/` and test case in `test/cases/`
56+
57+
## Research Phase
58+
59+
Before creating a formula, gather this information:
60+
61+
| Field | How to Find |
62+
|-------|-------------|
63+
| Latest version | `gh api repos/owner/repo/releases/latest --jq '.tag_name'` (404 → HEAD-only) |
64+
| License | Check LICENSE file or repo metadata (use SPDX identifier) |
65+
| Build system | Look at Makefile, go.mod, Cargo.toml, pyproject.toml, etc. |
66+
| Dependencies | Check build docs, CI files, or dependency manifests |
67+
| Default branch | Check repo settings — may be `main` or `master` |
68+
| Binary name | May differ from formula name — check Cargo.toml `[[bin]]`, Go `cmd/`, or pyproject.toml `[project.scripts]` |
69+
70+
### Determine Formula Type
71+
72+
| Scenario | Type | Has `url`/`sha256`? | Has `livecheck`? |
73+
|----------|------|---------------------|------------------|
74+
| Tagged releases | Standard | Yes | Yes |
75+
| No releases | HEAD-only | No | No |
76+
| Monorepo subdirectory | Standard | Yes | Yes |
77+
78+
### Calculate SHA256
79+
80+
```bash
81+
curl -sL "https://github.com/owner/repo/archive/refs/tags/vX.Y.Z.tar.gz" | shasum -a 256
82+
```
83+
84+
### Formula Naming
85+
86+
- Formula name: **kebab-case** (`hex-patch`, `jwt-ui`)
87+
- Class name: **PascalCase** (`HexPatch`, `JwtUi`)
88+
89+
## Formula Structure
90+
91+
### File Location
92+
93+
Formulas are organized alphabetically: `Formula/<first-letter>/<name>.rb`
94+
95+
### Key Elements
96+
97+
| Element | Purpose |
98+
|---------|---------|
99+
| `desc` | Short description (~80 chars) for `brew info` |
100+
| `homepage` | Project homepage URL |
101+
| `url` | Source tarball URL (omit for HEAD-only) |
102+
| `sha256` | Checksum (omit for HEAD-only) |
103+
| `license` | SPDX identifier |
104+
| `head` | Git URL for `--HEAD` installs |
105+
| `livecheck` | Auto-detect new versions (omit for HEAD-only) |
106+
| `depends_on` | Build or runtime dependencies |
107+
| `test` | Verification block |
108+
109+
### SPDX License Identifiers
110+
111+
| License | SPDX |
112+
|---------|------|
113+
| MIT | `"MIT"` |
114+
| Apache 2.0 | `"Apache-2.0"` |
115+
| GPL 3.0 (only) | `"GPL-3.0-only"` |
116+
| GPL 3.0 (or later) | `"GPL-3.0-or-later"` |
117+
| BSD 2-Clause | `"BSD-2-Clause"` |
118+
| BSD 3-Clause | `"BSD-3-Clause"` |
119+
120+
Always specify `-only` or `-or-later` for GPL/LGPL/AGPL.
121+
122+
## Language-Specific Patterns
123+
124+
Each language has a reference doc with install patterns, schema fields, and common issues:
125+
126+
- **Go:** `reference/langs/go.md`
127+
- **Rust:** `reference/langs/rust.md`
128+
- **Python:** `reference/langs/python.md`
129+
130+
Additional languages supported by the template pipeline (cmake, autotools, meson, zig) — see their Mustache partials in `reference/templates/langs/`.
131+
132+
## Reference Materials
133+
134+
| Topic | Location |
135+
|-------|----------|
136+
| Local validation steps | `reference/checklists/local-validation.md` |
137+
| Common issues & FAQ | `reference/faq/common.md` |
138+
| Test block patterns | `reference/testing/patterns.md` |
139+
| Generated formula examples | `reference/templates/formulas/*.rb` |
140+
| JSON Schema definition | `scripts/formula.schema.ts` |
141+
| Bottle attestation & provenance | `reference/security/attestation.md` |
142+
143+
## Batch Formula Creation
144+
145+
When creating many formulas at once:
146+
147+
1. **Compute SHA256 hashes in parallel** — launch multiple `curl | shasum` calls concurrently
148+
2. **Research build details in parallel** — check build manifests concurrently
149+
3. **Write all formula files** — no dependencies between them
150+
4. **Create branches/PRs sequentially** — one branch per formula, each from main
151+
5. **Use `ruby -c *.rb`** to syntax-check all formulas before pushing
152+
153+
## Checklist
154+
155+
- [ ] Research complete (version, license, build system, deps, binary name, default branch)
156+
- [ ] Formula type determined (standard vs HEAD-only)
157+
- [ ] SHA256 calculated (if not HEAD-only)
158+
- [ ] Formula file created at `Formula/<letter>/<name>.rb`
159+
- [ ] `ruby -c` passes
160+
- [ ] `brew audit --new` passes
161+
- [ ] `brew style arustydev/tap` passes
162+
- [ ] `brew install --build-from-source` succeeds
163+
- [ ] `brew test` passes
164+
- [ ] Binary executes correctly
165+
- [ ] PR created with CI passing
166+
167+
## References
168+
169+
- [Homebrew Formula Cookbook](https://docs.brew.sh/Formula-Cookbook)
170+
- [SPDX License List](https://spdx.org/licenses/)
171+
- [Homebrew Ruby Style Guide](https://docs.brew.sh/Ruby-Style-Guide)
172+
- [Homebrew Python Guidelines](https://docs.brew.sh/Python-for-Formula-Authors)
Lines changed: 33 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,33 @@
1+
- [ ] Zig support
2+
- [ ] C/C++ support
3+
- [ ] Java support
4+
- [ ] Roc support
5+
- [ ] Rust support
6+
- [ ] Go support
7+
- [ ] Python support
8+
- [ ] TypeScript support
9+
- [ ] Swift support
10+
- [ ] Kotlin support
11+
- [ ] Scala support
12+
- [ ] Haskell support
13+
- [ ] Lua support
14+
- [ ] JavaScript support
15+
- [ ] PHP support
16+
- [ ] Ruby support
17+
- [ ] Erlang support
18+
- [ ] Elixir support
19+
- [ ] Clojure support
20+
- [ ] CSharp support
21+
- [ ] Objective-C support
22+
- [ ] FSharp support
23+
- [ ] Fortran support
24+
- [ ] Dart support
25+
- [ ] Erlang support
26+
- [ ] Gleam support
27+
- [ ] Groovy support
28+
- [ ] Scheme support
29+
- [ ] OCaml support
30+
- [ ] Perl support
31+
- [ ] Nim support
32+
- [ ] Julia support
33+
- [ ] R support
Lines changed: 58 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,58 @@
1+
data := '{"formulas":[{"name":"Chris","role":"Developer"},{"name":"Anna","role":"Designer"}]}'
2+
3+
add-formula name:
4+
echo "{{ kebabcase(name) }}"
5+
echo "{{ uppercamelcase(name) }}"
6+
7+
[macos]
8+
_deps:
9+
brew bundle -f "{{ justfile_directory() }}/reference/Brewfile"
10+
npm install
11+
12+
13+
export PATH := "./node_modules/.bin:" + env('PATH')
14+
export NODE_PATH := justfile_directory() + "/node_modules"
15+
16+
javascript-recipe json=data:
17+
#!/usr/bin/env node
18+
const Mustache = require('mustache');
19+
const fs = require('fs');
20+
const path = require('path');
21+
const Ajv = require('ajv/dist/2020');
22+
23+
Mustache.escape = (text) => text;
24+
const { SCHEMA } = require('{{ justfile_directory() }}/scripts/formula.schema.ts');
25+
const { preprocessFormulas, loadPartials, parseInput } = require('{{ justfile_directory() }}/scripts/formula.helper.ts');
26+
const baseDir = '{{ justfile_directory() }}/reference/templates';
27+
28+
const jsObject = JSON.parse(parseInput(`{{json}}`));
29+
const ajv = new Ajv();
30+
const validate = ajv.compile(SCHEMA);
31+
if (!validate(jsObject)) {
32+
console.error(JSON.stringify(validate.errors, null, 2));
33+
process.exit(1);
34+
}
35+
36+
const partials = loadPartials(path.join(baseDir, 'langs'));
37+
preprocessFormulas(jsObject.formulas);
38+
39+
const main = fs.readFileSync(path.join(baseDir, 'main.mustache'), 'utf8');
40+
console.log(Mustache.render(main, jsObject, partials));
41+
42+
test:
43+
#!/usr/bin/env bash
44+
set -euo pipefail
45+
cd "{{ justfile_directory() }}"
46+
passed=0
47+
failed=0
48+
for t in test/cases/test-*.sh; do
49+
echo "--- Running $(basename "$t") ---"
50+
if bash "$t"; then
51+
passed=$((passed + 1))
52+
else
53+
failed=$((failed + 1))
54+
fi
55+
done
56+
echo ""
57+
echo "Results: $passed passed, $failed failed"
58+
[ "$failed" -eq 0 ]

context/skills/pkgmgr-homebrew-formula-dev/package-lock.json

Lines changed: 99 additions & 0 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

0 commit comments

Comments
 (0)