# Homebrew Multi Formula

> This skill should be used when the user asks to "release multiple formulas", "batch Homebrew update", "coordinate formula releases", "formula dependencies", or needs to manage releases across multiple Homebrew formulas with dependency ordering.

- Skill: `data-wise/homebrew-multi-formula` (Agent Skill)
- Install (CLI): `npx skillmds@latest add data-wise/homebrew-multi-formula`
- Raw SKILL.md: https://api.skillmd.com/api/skills/data-wise/homebrew-multi-formula/raw
- Safety review: pending
- Works with: Claude Code, Claude.ai, OpenAI Codex
- Category: Coding & Dev Tools
- Author: Data-Wise (https://skillmd.com/u/data-wise)
- Updated: 2026-09-17
- Page: https://skillmd.com/skills/data-wise/homebrew-multi-formula

---


# Multi-Formula Coordinator

Coordinate releases across multiple Homebrew formulas, respecting dependency order and handling batch updates.

> **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; see `dist-extras` and
> [`commands/dist/surfaces.md`](../../../commands/dist/surfaces.md) for the full model.

## Use Cases

1. **Monorepo Releases** - Multiple packages from one repository
2. **Ecosystem Releases** - Related packages with dependencies (e.g., rforge ecosystem)
3. **Batch Updates** - Update multiple formulas in one PR
4. **Dependency Chains** - Release in correct order when packages depend on each other

## Dependency Detection

### Formula Dependencies

```ruby
# In myapp-cli.rb
depends_on "myapp-core"  # Runtime dependency

# In myapp-plugin.rb
depends_on "myapp-cli"   # Also depends on cli
```

### Build Order

```
myapp-core    →  myapp-cli    →  myapp-plugin
    ↓              ↓
    └──────────────┴──────→ (can release in parallel after core)
```

## Workflow: Batch Release

### Input Manifest

Create `.homebrew-batch.yml`:

```yaml
# Batch release configuration
tap: data-wise/tap
auto_merge: true

formulas:
  - name: myapp-core
    version: "2.0.0"
    source: github

  - name: myapp-cli
    version: "2.0.0"
    source: github
    depends_on:
      - myapp-core

  - name: myapp-plugin
    version: "1.5.0"
    source: pypi
    depends_on:
      - myapp-cli
```

### Execution Order

```
Step 1: Build dependency graph
────────────────────────────────
  myapp-core (no deps) → Level 0
  myapp-cli (deps: core) → Level 1
  myapp-plugin (deps: cli) → Level 2

Step 2: Release in waves
────────────────────────────────
  Wave 0: myapp-core
    ✓ Updated formula
    ✓ PR created: #42
    ✓ Auto-merged

  Wave 1: myapp-cli
    ⏳ Waiting for Wave 0...
    ✓ Updated formula
    ✓ PR created: #43
    ✓ Auto-merged

  Wave 2: myapp-plugin
    ⏳ Waiting for Wave 1...
    ✓ Updated formula
    ✓ PR created: #44
    ✓ Auto-merged

Step 3: Summary
────────────────────────────────
  ✓ 3 formulas updated
  ✓ 3 PRs merged
  ⏱ Total time: 4m 23s
```

## GitHub Actions Workflow

### Reusable Batch Workflow

> **Note — illustrative pattern, not yet in the tap.** `batch-update.yml` and the
> `./.github/actions/update-formula` composite action below are a *design sketch* for
> coordinated multi-formula releases; they do **not** currently exist in
> `Data-Wise/homebrew-tap`. What the tap actually ships today is
> `.github/workflows/update-formula.yml` — a **single-formula** reusable workflow (see
> `homebrew-workflow-expert`). To release several formulas now, call that single-formula
> workflow once per formula. Build the batch workflow below only if/when true batch
> orchestration is needed.

```yaml
# homebrew-tap/.github/workflows/batch-update.yml  (illustrative — not present in tap)
name: Batch Formula Update

on:
  workflow_call:
    inputs:
      formulas:
        required: true
        type: string
        description: 'JSON array of {name, version, sha256, source_type}'
      auto_merge:
        required: false
        type: boolean
        default: true
    secrets:
      tap_token:
        required: true

jobs:
  parse:
    runs-on: ubuntu-latest
    outputs:
      matrix: ${{ steps.parse.outputs.matrix }}
      order: ${{ steps.parse.outputs.order }}
    steps:
      - name: Parse formulas and build order
        id: parse
        run: |
          echo '${{ inputs.formulas }}' | jq -r '
            # Build dependency graph
            def toposort:
              # ... topological sort implementation
            ;
            toposort | @json
          ' > order.json
          echo "order=$(cat order.json)" >> $GITHUB_OUTPUT

  update:
    needs: parse
    runs-on: ubuntu-latest
    strategy:
      max-parallel: 1  # Sequential for dependency order
      matrix:
        formula: ${{ fromJson(needs.parse.outputs.order) }}
    steps:
      - name: Wait for dependencies
        if: matrix.formula.depends_on
        run: |
          for dep in ${{ join(matrix.formula.depends_on, ' ') }}; do
            echo "Waiting for $dep to complete..."
            # Poll for PR merge status
          done

      - name: Update formula
        uses: ./.github/actions/update-formula
        with:
          formula_name: ${{ matrix.formula.name }}
          version: ${{ matrix.formula.version }}
          sha256: ${{ matrix.formula.sha256 }}
          source_type: ${{ matrix.formula.source_type }}
          auto_merge: ${{ inputs.auto_merge }}
```

### Caller Workflow

```yaml
# In project repo
name: Release Ecosystem

on:
  workflow_dispatch:
    inputs:
      core_version:
        description: 'Core version'
        required: true
      cli_version:
        description: 'CLI version'
        required: true

jobs:
  prepare:
    runs-on: ubuntu-latest
    outputs:
      formulas: ${{ steps.build.outputs.formulas }}
    steps:
      - name: Calculate SHA256s
        id: sha
        run: |
          CORE_SHA=$(curl -sL "https://github.com/.../v${{ inputs.core_version }}.tar.gz" | shasum -a 256 | cut -d' ' -f1)
          CLI_SHA=$(curl -sL "https://github.com/.../v${{ inputs.cli_version }}.tar.gz" | shasum -a 256 | cut -d' ' -f1)
          echo "core_sha=$CORE_SHA" >> $GITHUB_OUTPUT
          echo "cli_sha=$CLI_SHA" >> $GITHUB_OUTPUT

      - name: Build formula list
        id: build
        run: |
          echo 'formulas=[
            {"name":"myapp-core","version":"${{ inputs.core_version }}","sha256":"${{ steps.sha.outputs.core_sha }}","source_type":"github"},
            {"name":"myapp-cli","version":"${{ inputs.cli_version }}","sha256":"${{ steps.sha.outputs.cli_sha }}","source_type":"github","depends_on":["myapp-core"]}
          ]' >> $GITHUB_OUTPUT

  release:
    needs: prepare
    uses: data-wise/homebrew-tap/.github/workflows/batch-update.yml@main
    with:
      formulas: ${{ needs.prepare.outputs.formulas }}
      auto_merge: true
    secrets:
      # Preferred: GitHub App token (see homebrew-workflow-expert). PAT is a fallback.
      app_id: ${{ secrets.APP_ID }}
      app_private_key: ${{ secrets.APP_PRIVATE_KEY }}
```

## CLI Command

### Usage

```bash
# Multi-formula coordination workflow:
/craft:dist:homebrew deps                          # Show dependency order
/craft:dist:homebrew audit --all                   # Validate all formulas
# Then release in dependency order using /release per-project
```

### Interactive Flow

```
╔═══════════════════════════════════════════════════════════════╗
║           MULTI-FORMULA RELEASE                                ║
╠═══════════════════════════════════════════════════════════════╣
║                                                               ║
║  Detected formulas in Data-Wise/homebrew-tap:                 ║
║                                                               ║
║  [ ] aiterm (v0.3.8)                                          ║
║  [ ] atlas (v1.2.0)                                           ║
║  [x] flow-cli (v2.1.0) → v2.2.0                               ║
║  [x] nexus-cli (v0.5.0) → v0.6.0                              ║
║  [ ] mcp-bridge (v0.1.0)                                      ║
║  [ ] scribe-cli (v1.0.0)                                      ║
║                                                               ║
║  Selected: 2 formulas                                         ║
║  Dependencies: None detected                                  ║
║                                                               ║
║  Release order:                                               ║
║    1. flow-cli                                                ║
║    2. nexus-cli (parallel OK)                                 ║
║                                                               ║
║  [Continue] [Edit Selection] [Cancel]                         ║
║                                                               ║
╚═══════════════════════════════════════════════════════════════╝
```

## Dependency Graph Visualization

Generate Mermaid diagram of formula dependencies:

```bash
/craft:dist:homebrew deps --mermaid
```

Output:

```mermaid
flowchart LR
    subgraph "Data-Wise Tap"
        aiterm
        atlas
        flow-cli
        nexus-cli
        mcp-bridge
        scribe-cli
    end

    subgraph "System Dependencies"
        python@3.12
        node
        rust
    end

    aiterm --> python@3.12
    atlas --> python@3.12
    nexus-cli --> python@3.12
    mcp-bridge --> node
    scribe-cli --> rust
```

## Error Handling

### Dependency Failure

```
Error: myapp-cli release failed

Dependency chain affected:
  ✗ myapp-cli (failed)
  ⏸ myapp-plugin (skipped - depends on cli)

Options:
  1. Retry myapp-cli release
  2. Skip myapp-cli, continue with others
  3. Abort batch release

Choice: _
```

### Version Conflict

```
Warning: Version mismatch detected

myapp-cli v2.0.0 depends on myapp-core >= 2.0.0
But myapp-core in batch is v1.9.0

Options:
  1. Update myapp-core version to 2.0.0
  2. Lower myapp-cli dependency requirement
  3. Abort

Choice: _
```

## Integration

| Command | Purpose |
|---------|---------|
| `/craft:dist:homebrew deps` | Show dependency graph |
| `/craft:dist:homebrew audit --all` | Validate all formulas |

## Best Practices

1. **Test Dependencies First** - Run `brew install --build-from-source` for base packages
2. **Use Semantic Versioning** - Makes dependency resolution predictable
3. **Pin Major Versions** - `depends_on "myapp-core" => "~> 2.0"`
4. **Batch Related Releases** - Release ecosystem packages together
5. **Auto-merge for Speed** - Safe for personal taps with CI validation

