Skip to content
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
127 changes: 127 additions & 0 deletions .github/workflows/homebrew-dev-cask.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,127 @@
# SPDX-FileCopyrightText: Copyright (c) 2025-2026 NVIDIA CORPORATION & AFFILIATES. All rights reserved.
# SPDX-License-Identifier: Apache-2.0

name: Publish Homebrew Dev Cask Bundle

on:
workflow_dispatch:
workflow_run:
workflows:
- Release Dev
- Release VM Dev
types:
- completed

permissions:
contents: write

concurrency:
group: homebrew-dev-cask
cancel-in-progress: false

defaults:
run:
shell: bash

jobs:
publish:
name: Publish Dev Cask Bundle
if: github.repository == 'NVIDIA/OpenShell' && (github.event_name == 'workflow_dispatch' || github.event.workflow_run.conclusion == 'success')
runs-on: ubuntu-latest
timeout-minutes: 10
env:
GH_TOKEN: ${{ secrets.GITHUB_TOKEN }}
BUNDLE_ASSET: openshell-homebrew-dev-aarch64-apple-darwin.tar.gz
steps:
- name: Download release assets
run: |
set -euo pipefail
mkdir -p downloads

gh release download dev \
--repo "${GITHUB_REPOSITORY}" \
--pattern openshell-aarch64-apple-darwin.tar.gz \
--pattern openshell-gateway-aarch64-apple-darwin.tar.gz \
--dir downloads \
--clobber

gh release download vm-dev \
--repo "${GITHUB_REPOSITORY}" \
--pattern openshell-driver-vm-aarch64-apple-darwin.tar.gz \
--dir downloads \
--clobber

test -f downloads/openshell-aarch64-apple-darwin.tar.gz
test -f downloads/openshell-gateway-aarch64-apple-darwin.tar.gz
test -f downloads/openshell-driver-vm-aarch64-apple-darwin.tar.gz

- name: Build cask bundle
run: |
set -euo pipefail
mkdir -p bundle/libexec/openshell artifacts

tar -xzf downloads/openshell-aarch64-apple-darwin.tar.gz \
-C bundle openshell
tar -xzf downloads/openshell-gateway-aarch64-apple-darwin.tar.gz \
-C bundle/libexec openshell-gateway
tar -xzf downloads/openshell-driver-vm-aarch64-apple-darwin.tar.gz \
-C bundle/libexec/openshell openshell-driver-vm

cat > bundle/openshell-gateway <<'SH'
#!/bin/sh
set -e

path=$0
while [ -L "$path" ]; do
link=$(readlink "$path")
case "$link" in
/*) path=$link ;;
*) path=$(dirname "$path")/$link ;;
esac
done

dir=$(CDPATH= cd -- "$(dirname -- "$path")" && pwd)
export OPENSHELL_DRIVER_DIR="${dir}/libexec/openshell"
exec "${dir}/libexec/openshell-gateway" "$@"
SH

cat > bundle/openshell-driver-vm <<'SH'
#!/bin/sh
set -e

path=$0
while [ -L "$path" ]; do
link=$(readlink "$path")
case "$link" in
/*) path=$link ;;
*) path=$(dirname "$path")/$link ;;
esac
done

dir=$(CDPATH= cd -- "$(dirname -- "$path")" && pwd)
exec "${dir}/libexec/openshell/openshell-driver-vm" "$@"
SH

cat > bundle/libexec/openshell/openshell-driver-vm-entitlements.plist <<'XML'
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
<plist version="1.0">
<dict>
<key>com.apple.security.hypervisor</key>
<true/>
</dict>
</plist>
XML

chmod 0555 bundle/openshell bundle/openshell-gateway bundle/openshell-driver-vm
chmod 0555 bundle/libexec/openshell-gateway bundle/libexec/openshell/openshell-driver-vm

tar -czf "artifacts/${BUNDLE_ASSET}" -C bundle .
tar -tzf "artifacts/${BUNDLE_ASSET}"

- name: Upload cask bundle to dev release
run: |
set -euo pipefail
gh release upload dev "artifacts/${BUNDLE_ASSET}" \
--repo "${GITHUB_REPOSITORY}" \
--clobber
4 changes: 2 additions & 2 deletions .github/workflows/release-vm-dev.yml
Original file line number Diff line number Diff line change
Expand Up @@ -689,8 +689,8 @@ jobs:
done
vm_count=$(ls release-final/openshell-vm-*.tar.gz 2>/dev/null | wc -l)
driver_count=$(ls release-final/openshell-driver-vm-*.tar.gz 2>/dev/null | wc -l)
if [ "$vm_count" -eq 0 ] || [ "$driver_count" -eq 0 ]; then
echo "ERROR: Missing binary tarballs (openshell-vm=${vm_count}, openshell-driver-vm=${driver_count})" >&2
if [ "$vm_count" -ne 3 ] || [ "$driver_count" -ne 3 ]; then
echo "ERROR: Expected 3 openshell-vm and 3 openshell-driver-vm binary tarballs (openshell-vm=${vm_count}, openshell-driver-vm=${driver_count})" >&2
ls -la release/ || true
exit 1
fi
Expand Down
28 changes: 28 additions & 0 deletions Casks/openshell-dev.rb
Original file line number Diff line number Diff line change
@@ -0,0 +1,28 @@
cask "openshell-dev" do
version :latest
sha256 :no_check

url "https://github.com/NVIDIA/OpenShell/releases/download/dev/openshell-homebrew-dev-aarch64-apple-darwin.tar.gz"
name "OpenShell Dev"
desc "Development build of the safe private runtime for autonomous AI agents"
homepage "https://github.com/NVIDIA/OpenShell"

depends_on arch: :arm64
depends_on macos: ">= :big_sur"

binary "openshell"
binary "openshell-gateway"
binary "openshell-driver-vm"

postflight do
system_command "/usr/bin/codesign",
args: [
"--entitlements",
"#{staged_path}/libexec/openshell/openshell-driver-vm-entitlements.plist",
"--force",
"-s",
"-",
"#{staged_path}/libexec/openshell/openshell-driver-vm",
]
end
end
13 changes: 13 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -26,6 +26,19 @@ OpenShell is built agent-first. The project ships with agent skills for everythi
curl -LsSf https://raw.githubusercontent.com/NVIDIA/OpenShell/main/install.sh | sh
```

**Homebrew dev cask (macOS Apple Silicon):**

```bash
curl -LsSf https://raw.githubusercontent.com/NVIDIA/OpenShell/main/install-dev.sh | sh
```

Or install the cask directly:

```bash
brew tap nvidia/openshell https://github.com/NVIDIA/OpenShell.git
Comment thread
pimlock marked this conversation as resolved.
brew install --cask nvidia/openshell/openshell-dev
```

**From PyPI (requires [uv](https://docs.astral.sh/uv/)):**

```bash
Expand Down
17 changes: 16 additions & 1 deletion architecture/build-containers.md
Original file line number Diff line number Diff line change
Expand Up @@ -35,10 +35,25 @@ OpenShell also publishes a standalone `openshell-gateway` binary as a GitHub rel
- **Artifact name**: `openshell-gateway-<target>.tar.gz`
- **Targets**: `x86_64-unknown-linux-gnu`, `aarch64-unknown-linux-gnu`, `aarch64-apple-darwin`
- **Release workflows**: `.github/workflows/release-dev.yml`, `.github/workflows/release-tag.yml`
- **Installer**: None yet. The binary is a manual-download asset.
- **Installers**: `install-vm.sh` for the rolling development gateway, and the Homebrew dev cask under `Casks/`.

Both the standalone artifact and the deployed container image use the `openshell-gateway` binary.

## Homebrew Dev Cask

This repository also acts as the Homebrew tap for the rolling macOS Apple Silicon dev build. Users must tap it with the full Git URL because the repository is not named `homebrew-*`:

```bash
brew tap nvidia/openshell https://github.com/NVIDIA/OpenShell.git
brew install --cask nvidia/openshell/openshell-dev
```

`Casks/openshell-dev.rb` uses `version :latest` and `sha256 :no_check` because it installs a rolling development archive from the `dev` GitHub release. `.github/workflows/homebrew-dev-cask.yml` runs after the dev CLI/gateway release or VM dev driver release completes. It downloads the macOS ARM64 CLI, gateway, and VM driver assets, repacks them into `openshell-homebrew-dev-aarch64-apple-darwin.tar.gz`, and uploads that archive back to the `dev` release.

The archive exposes `openshell`, `openshell-gateway`, and `openshell-driver-vm` through cask `binary` stanzas. The gateway entrypoint is a wrapper that sets `OPENSHELL_DRIVER_DIR` to the bundled driver directory before executing the real gateway binary. The cask signs the VM driver with the Hypervisor entitlement during `postflight`.

`install-dev.sh` installs the same dev cask automatically on macOS Apple Silicon. On Linux amd64 and arm64, it installs the rolling development Debian package.

## Python Wheels

OpenShell also publishes Python wheels for `linux/amd64`, `linux/arm64`, and macOS ARM64.
Expand Down
73 changes: 66 additions & 7 deletions install-dev.sh
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,8 @@
# Install the OpenShell development build from the rolling GitHub `dev` release.
#
# This script is intended as a convenient installer for development builds. It
# currently supports Debian packages on Linux amd64 and arm64 only.
# supports Debian packages on Linux amd64/arm64 and the Homebrew dev cask on
# macOS Apple Silicon.
#
set -e

Expand All @@ -14,6 +15,9 @@ REPO="NVIDIA/OpenShell"
GITHUB_URL="https://github.com/${REPO}"
RELEASE_TAG="dev"
CHECKSUMS_NAME="openshell-checksums-sha256.txt"
HOMEBREW_TAP="nvidia/openshell"
HOMEBREW_TAP_URL="${GITHUB_URL}.git"
HOMEBREW_CASK="${HOMEBREW_TAP}/openshell-dev"

info() {
printf '%s: %s\n' "$APP_NAME" "$*" >&2
Expand All @@ -26,7 +30,7 @@ error() {

usage() {
cat <<EOF
install-dev.sh - Install the OpenShell development Debian package
install-dev.sh - Install the OpenShell development build

USAGE:
curl -fsSL https://raw.githubusercontent.com/NVIDIA/OpenShell/main/install-dev.sh -o install-dev.sh
Expand All @@ -41,7 +45,8 @@ NOTES:
This installs the rolling development release from:
${GITHUB_URL}/releases/tag/${RELEASE_TAG}

Only Linux amd64 and arm64 Debian packages are supported right now.
Linux amd64 and arm64 install the development Debian package.
macOS Apple Silicon installs the Homebrew dev cask.
EOF
}

Expand Down Expand Up @@ -142,6 +147,26 @@ check_platform() {
require_cmd dpkg
}

check_homebrew_platform() {
if [ "$(uname -s)" != "Darwin" ]; then
error "unsupported OS: $(uname -s); Homebrew dev cask requires macOS"
fi

case "$(uname -m)" in
arm64|aarch64)
;;
*)
error "unsupported architecture: $(uname -m); Homebrew dev cask requires Apple Silicon"
;;
esac

if [ "$(id -u)" -eq 0 ]; then
error "Homebrew must not be run as root; rerun this installer as your user"
fi

require_cmd brew
}

get_deb_arch() {
_arch="$(dpkg --print-architecture)"

Expand Down Expand Up @@ -228,6 +253,7 @@ remove_local_gateway_registration() {

# The install-dev gateway is a user service. Replace the CLI registration
# directly instead of asking `gateway destroy` to tear down Docker resources.
# shellcheck disable=SC2016
as_target_user sh -c '
config_dir=$1
rm -rf "${config_dir}/gateways/local"
Expand Down Expand Up @@ -259,21 +285,54 @@ register_local_gateway() {
esac
}

install_homebrew_cask() {
check_homebrew_platform

info "tapping ${HOMEBREW_TAP}..."
brew tap "${HOMEBREW_TAP}" "${HOMEBREW_TAP_URL}"

if brew list --cask openshell-dev >/dev/null 2>&1; then
info "reinstalling ${HOMEBREW_CASK}..."
brew reinstall --cask "${HOMEBREW_CASK}"
else
info "installing ${HOMEBREW_CASK}..."
brew install --cask "${HOMEBREW_CASK}"
fi

_brew_prefix="$(brew --prefix)"
_openshell_bin="${_brew_prefix}/bin/openshell"
if [ -x "$_openshell_bin" ]; then
_installed_version="$("$_openshell_bin" --version 2>/dev/null || true)"
if [ -n "$_installed_version" ]; then
info "installed ${_installed_version} via Homebrew"
else
info "installed OpenShell development cask via Homebrew"
fi
else
info "installed OpenShell development cask via Homebrew"
fi
}

main() {
while [ "$#" -gt 0 ]; do
case "$1" in
for arg in "$@"; do
case "$arg" in
--help)
usage
exit 0
;;
*)
error "unknown option: $1"
error "unknown option: $arg"
;;
esac
shift
done

require_cmd curl

if [ "$(uname -s)" = "Darwin" ]; then
install_homebrew_cask
return 0
fi

check_platform

TARGET_USER="$(target_user)"
Expand Down
Loading