Agent skill

Afm Build Promote Nightly

by scouzi1966 in scouzi1966/maclocal-api

A skill your agent uses when promoting afm to a stable release — builds from main HEAD or a nightly commit, verifies patches, updates Homebrew stable tap (afm.rb), builds a PyPI wheel, updates…

MITAuto-check: warningsMobile

Install Afm Build Promote Nightly

The automated check flagged lines worth reading first. See the safety section below.

skills CLI
$ npx skills add scouzi1966/maclocal-api --skill afm-build-promote-nightly -a claude-code

Project install by default; add -g for ~/.claude/skills/.

GitHub CLI
$ gh skill install scouzi1966/maclocal-api afm-build-promote-nightly --agent claude-code

Project scope by default; add --scope user for a personal install. Needs GitHub CLI 2.90.0 or later (public preview).

Manual copy
$ git clone --depth 1 https://github.com/scouzi1966/maclocal-api.git skills-src && mkdir -p .claude/skills && cp -r skills-src/.claude/skills/afm-build-promote-nightly .claude/skills/afm-build-promote-nightly && rm -rf skills-src

Use ~/.claude/skills/ instead of .claude/skills for a personal install. The folder must contain SKILL.md.

Claude Code skills documentation · loads skills from .claude/skills/

Facts

Skill name
afm-build-promote-nightly
GitHub stars
346
Token cost
~8.9k tokens
SKILL.md length
1,963 words
Files
1
Skills in repo
12
Repo updated
First seen
Licence
MIT

At a glance

A skill your agent uses when promoting afm to a stable release — builds from main HEAD or a nightly commit, verifies patches, updates Homebrew stable tap (afm.rb), builds a PyPI wheel, updates…

  • Works in 12 steps: Verify Admin Access → Choose Build Source → Determine Stable Version → …
  • Promoting afm to a stable release — builds from main HEAD
  • SKILL.md covers Usage and Instructions
  • Calls git, brew and gh; reaches test.pypi.org; needs UV_PUBLISH_TOKEN

What it does

Afm Build Promote Nightly is an agent skill from scouzi1966/maclocal-api. Use when promoting afm to a stable release — builds from main HEAD or a nightly commit, verifies patches, updates Homebrew stable tap (afm.rb), builds a PyPI wheel, updates README and version files, and verifies both brew install and pip install work. Repo admin only.

Its SKILL.md is about 8.9k tokens, which your agent loads only when the skill is triggered. It is a single SKILL.md file with no bundled scripts.

It sits in Mobile, covering App store release. It works with Homebrew and macOS. The repository describes itself as: 'afm' command cli: macOS server and single prompt mode that exposes Apple's Foundation and MLX Models and other APIs running on your Mac through a single aggregated…. The licence is MIT.

When your agent uses it

  • Promoting afm to a stable release — builds from main HEAD
  • A nightly commit
  • Verifies patches
  • Updates Homebrew stable tap (afm.rb)

Example prompts

  • “/afm-build-promote-nightly”

Requirements

  • Python 3
  • Node.js

Workflow steps

12 steps, taken from the step headings in SKILL.md.

  1. Verify Admin Access
  2. Choose Build Source
  3. Determine Stable Version
  4. Checkout Nightly Commit and Update Version
  5. Verify Patches and Rebuild
  6. Package Stable Tarball
  7. Return to Original Branch
  8. Create Stable GitHub Release
  9. Update Homebrew Stable Tap (afm.rb)
  10. Update Version Files on Working Branch
  11. Update README.md
  12. Build Python Wheel

What it can do on your machine

Read from SKILL.md and the folder at commit 138ca5d. It shows what the files ask for, not the result of running them.

  • Tool permissions

    Pre-approves nothing: there is no allowed-tools line, so your agent's usual permission prompts apply.

    From allowed-tools in the SKILL.md frontmatter.

  • Runs code

    Shell commands in SKILL.md call:

    • git
    • brew
    • gh
    • pip
    • swift
    • uv
    • npm
    • ruby
    • curl
    • python3

    From the folder's file list and the shell code blocks in SKILL.md.

  • Network

    Hosts in commands or code, which the agent is likely to contact:

    • test.pypi.org

    From URLs in SKILL.md, links to its own repository left out.

  • Credentials

    Names these keys or tokens, usually read from environment variables:

    • UV_PUBLISH_TOKEN

    From names ending in _API_KEY, _TOKEN, _SECRET, _KEY or _PASSWORD in SKILL.md.

Context cost

Afm Build Promote Nightly loads about 8.9k tokens when it runs. Until then it costs about 74 tokens; SKILL.md has 1,963 words of instructions outside code blocks.

Always · name and description, kept in context so the agent knows when to use it
~74
When it runs · the whole SKILL.md, loaded when a task matches
~8.9k

Estimates: characters ÷ 4, the usual rule of thumb; real counts depend on the model's tokenizer. Scripts and assets cost tokens only if the agent reads them.

Safety

Auto-check: warnings

The automated check found patterns that need a careful read before installing.

  • WarningMentions a credentials file (SSH keys, cloud or package-manager tokens)SKILL.md:762
    me (`--token` / `UV_PUBLISH_TOKEN` / `~/.pypirc`) — never assume it's stored in the repo.

Automated static check — not a guarantee. Review scripts before installing. It scans the text of SKILL.md for risky patterns (piping downloads into a shell, reading credential files, hidden Unicode, destructive commands); files beside SKILL.md are not scanned.

SKILL.md

The full file from scouzi1966/maclocal-api at commit 138ca5d, republished under its MIT licence (© scouzi1966). 1,963 words, ~8,866 tokens.

Download SKILL.mdSave it as .claude/skills/afm-build-promote-nightly/SKILL.md (or your agent's skills folder).
name
afm-build-promote-nightly
description
Use when promoting afm to a stable release — builds from main HEAD or a nightly commit, verifies patches, updates Homebrew stable tap (afm.rb), builds a PyPI wheel, updates README and version files, and verifies both brew install and pip install work. Repo admin only.

Promote AFM to Stable Release

Build a stable release from either the current main branch HEAD or a specific nightly commit. Updates BuildInfo.swift with the stable version, rebuilds with verified patches, then publishes to GitHub, Homebrew (afm.rb), and PyPI.

Repo admin only (scouzi1966).

Usage

  • /afm-build-promote-nightly — build stable release (choose source interactively)
  • /afm-build-promote-nightly 0.9.7 — build stable with explicit version

Instructions

Step 1: Verify Admin Access
bash
gh auth status
GH_USER=$(gh api user -q .login)
echo "GitHub user: $GH_USER"

gh api repos/scouzi1966/maclocal-api -q '.permissions.push'
gh api repos/scouzi1966/homebrew-afm -q '.permissions.push'

# Tap repo — auto-clone if missing
TAP_DIR="${TAP_DIR:-$(cd "$(git rev-parse --show-toplevel)/.." && pwd)/homebrew-afm}"
if [ ! -d "$TAP_DIR/.git" ]; then
  echo "Tap repo missing — cloning..."
  gh repo clone scouzi1966/homebrew-afm "$TAP_DIR"
fi
test -f "$TAP_DIR/afm.rb" && echo "Tap OK" || echo "FAILED"

If GH_USER is not scouzi1966 or push access is false for either repo, STOP immediately:

This skill publishes stable releases for scouzi1966/maclocal-api.
Only the repository owner (scouzi1966) can run it. You are authenticated as: <username>
Step 2: Choose Build Source

List recent nightly releases for reference:

bash
# Show current main HEAD
echo "main HEAD: $(git rev-parse --short HEAD) — $(git log -1 --format='%s')"

# List recent nightlies
gh release list --repo scouzi1966/maclocal-api --limit 10 --json tagName,name,publishedAt,isPrerelease \
  -q '.[] | select(.isPrerelease) | "\(.tagName)\t\(.name)\t\(.publishedAt)"'

Use AskUserQuestion:

Question: "Build stable release from which source?"

Options:

  1. "main HEAD" — build from the current tip of main (most common)
  2. "A nightly release" — build from a specific nightly tag's commit
  3. "A specific commit" — enter a commit SHA

If "main HEAD": Set BUILD_SHA=$(git rev-parse HEAD)

If "A nightly release": Show the nightly list and ask user to pick one, then:

bash
NIGHTLY_TAG="<selected tag>"
BUILD_SHA=$(git rev-list -n 1 "$NIGHTLY_TAG" 2>/dev/null || \
  gh release view "$NIGHTLY_TAG" --repo scouzi1966/maclocal-api --json targetCommitish -q '.targetCommitish')

If "A specific commit": User provides the SHA, set BUILD_SHA=<user input>

bash
echo "Build source commit: $BUILD_SHA"
echo "Commit message: $(git log -1 --format='%s' $BUILD_SHA)"
Step 3: Determine Stable Version

If version was provided as argument, use it. Otherwise derive from BuildInfo.swift:

bash
BASE_VERSION=$(grep 'static let version' Sources/AFMKit/BuildInfo.swift \
  | sed 's/.*"\(.*\)".*/\1/' | sed 's/^v//')

Use AskUserQuestion:

Question: "Stable version? Derived base version is X.Y.Z."

Options:

  1. "X.Y.Z (derived)" — use as-is
  2. "Custom version" — enter a different version

Save as VERSION. Set TAG="v${VERSION}".

Check stable tag doesn't already exist:

bash
if gh release view "v${VERSION}" --repo scouzi1966/maclocal-api >/dev/null 2>&1; then
  echo "ERROR: Release v${VERSION} already exists!"
fi

If it exists, STOP and ask the user to choose a different version.

Step 3b: Capture Rollback State

Before any mutations, snapshot the current state so the entire promotion can be reverted (except PyPI, which is immutable).

bash
cd "$(git rev-parse --show-toplevel)"

# Previous stable version (for tap rollback)
PREV_STABLE_VERSION=$(grep 'version "' "$TAP_DIR/afm.rb" | head -1 | sed 's/.*"\(.*\)".*/\1/')
PREV_STABLE_URL=$(grep 'url "' "$TAP_DIR/afm.rb" | head -1 | sed 's/.*"\(.*\)".*/\1/')
PREV_STABLE_SHA256=$(grep 'sha256 "' "$TAP_DIR/afm.rb" | head -1 | sed 's/.*"\(.*\)".*/\1/')

# Previous version file values
PREV_BUILDINFO_VERSION=$(grep 'static let version' Sources/AFMKit/BuildInfo.swift | sed 's/.*"\(.*\)".*/\1/')
PREV_PYPROJECT_VERSION=$(grep '^version = ' pyproject.toml | sed 's/.*"\(.*\)".*/\1/')
PREV_INIT_VERSION=$(grep '^__version__' macafm/__init__.py | sed 's/.*"\(.*\)".*/\1/')

# Previous README version
PREV_README_STABLE=$(grep -o 'Stable (v[^)]*)' README.md | head -1)

# Tap commit before our changes (production)
PREV_TAP_COMMIT=$(cd "$TAP_DIR" && git rev-parse HEAD)

# Staging tap commit before our changes (used in Step 8b)
STAGING_DIR="${STAGING_TAP_DIR:-$(cd "$(git rev-parse --show-toplevel)/.." && pwd)/homebrew-afm-staging}"
if [ -d "$STAGING_DIR/.git" ]; then
  PREV_STAGING_COMMIT=$(cd "$STAGING_DIR" && git rev-parse HEAD)
else
  PREV_STAGING_COMMIT="(repo not yet cloned — will be created in Step 8b)"
fi

echo "=== Rollback snapshot ==="
echo "Tap version: $PREV_STABLE_VERSION"
echo "Tap commit: $PREV_TAP_COMMIT"
echo "Staging commit: $PREV_STAGING_COMMIT"
echo "BuildInfo: $PREV_BUILDINFO_VERSION"
echo "pyproject: $PREV_PYPROJECT_VERSION"
echo "__init__: $PREV_INIT_VERSION"
echo "README: $PREV_README_STABLE"

Report the rollback snapshot to the user so they have it on record.

Step 4: Checkout Nightly Commit and Update Version

CRITICAL: The stable build must use the chosen commit (BUILD_SHA), with only BuildInfo.swift changed to carry the stable version.

bash
cd "$(git rev-parse --show-toplevel)"

# Save current branch to return later
ORIGINAL_BRANCH=$(git branch --show-current)

# Stash any uncommitted changes
git stash --include-untracked 2>/dev/null || true

# Checkout the chosen commit
git checkout "$BUILD_SHA"

# Update ONLY BuildInfo.swift with stable version
sed -i '' "s/static let version: String? = \".*\"/static let version: String? = \"v${VERSION}\"/" \
  Sources/AFMKit/BuildInfo.swift

# Verify the change
grep 'static let version' Sources/AFMKit/BuildInfo.swift
# Must show: static let version: String? = "vX.Y.Z"
Step 5: Verify Patches and Rebuild

CRITICAL FAIL-SAFE: Before building, verify that ALL vendor patches are correctly applied. The build MUST use our patched files, not upstream originals.

bash
cd "$(git rev-parse --show-toplevel)"

# Step 5a: Initialize submodules at the exact state for this commit
git submodule update --init --recursive

# Step 5b: Apply patches
./Scripts/apply-mlx-patches.sh

# Step 5c: FAIL-SAFE — Verify every patch file matches its vendor target
./Scripts/apply-mlx-patches.sh --check
PATCH_CHECK=$?

if [ $PATCH_CHECK -ne 0 ]; then
  echo "FATAL: Patch verification FAILED. Aborting build."
  echo "One or more vendor files do not match Scripts/patches/."
  echo "This means the build would use unpatched vendor code."
fi

If --check exits non-zero, STOP IMMEDIATELY. Do NOT proceed with the build. Report the failing patches to the user and investigate.

Additional per-file verification — confirm critical patched files byte-for-byte:

bash
# Verify the most critical patches individually
PATCHES_DIR="$(git rev-parse --show-toplevel)/Scripts/patches"
VENDOR_DIR="$(git rev-parse --show-toplevel)/vendor/mlx-swift-lm"

CRITICAL_PATCHES=(
  "Evaluate.swift:Libraries/MLXLMCommon/Evaluate.swift"
  "LLMModelFactory.swift:Libraries/MLXLLM/LLMModelFactory.swift"
  "ToolCallFormat.swift:Libraries/MLXLMCommon/Tool/ToolCallFormat.swift"
  "Load.swift:Libraries/MLXLMCommon/Load.swift"
  "KVCache.swift:Libraries/MLXLMCommon/KVCache.swift"
)

ALL_OK=true
for entry in "${CRITICAL_PATCHES[@]}"; do
  PATCH_NAME="${entry%%:*}"
  TARGET_REL="${entry##*:}"
  if ! diff -q "$PATCHES_DIR/$PATCH_NAME" "$VENDOR_DIR/$TARGET_REL" >/dev/null 2>&1; then
    echo "MISMATCH: $PATCH_NAME != $TARGET_REL"
    ALL_OK=false
  else
    echo "OK: $PATCH_NAME"
  fi
done

if [ "$ALL_OK" = false ]; then
  echo "FATAL: Critical patch mismatch detected. Aborting."
fi

If any critical patch fails diff, STOP. Do not build.

Step 5d: Build WebUI assets (MANDATORY):

The WebUI (-w flag) is a core feature. Every release MUST include Resources/webui/index.html.gz. This asset comes from the llama.cpp submodule and must be built or copied before packaging.

bash
cd "$(git rev-parse --show-toplevel)"

# Build webui from llama.cpp submodule
WEBUI_DIR="vendor/llama.cpp/tools/server/webui"
WEBUI_PREBUILT="vendor/llama.cpp/tools/server/public/index.html.gz"

if [ -f "$WEBUI_PREBUILT" ]; then
  # Pre-built webui exists in submodule — copy it
  mkdir -p Resources/webui
  cp "$WEBUI_PREBUILT" Resources/webui/index.html.gz
  echo "WebUI: copied pre-built from llama.cpp submodule"
elif [ -d "$WEBUI_DIR" ] && command -v node >/dev/null 2>&1; then
  # Build from source
  cd "$WEBUI_DIR" && npm install && npm run build && cd "$(git rev-parse --show-toplevel)"
  mkdir -p Resources/webui
  cp vendor/llama.cpp/tools/server/public/index.html.gz Resources/webui/index.html.gz
  echo "WebUI: built from source"
else
  echo "FATAL: Cannot build or find WebUI assets."
  echo "Neither $WEBUI_PREBUILT nor $WEBUI_DIR with Node.js available."
fi

# MANDATORY CHECK — release MUST have webui
if [ ! -f "Resources/webui/index.html.gz" ]; then
  echo "FATAL: Resources/webui/index.html.gz is MISSING. Cannot release without WebUI."
else
  echo "WebUI OK: $(ls -lh Resources/webui/index.html.gz | awk '{print $5}')"
fi

If Resources/webui/index.html.gz does not exist, STOP IMMEDIATELY. Do NOT proceed with the build. The WebUI is a core feature and every release must include it.

Step 5e: Build for release:

bash
# Clean and build release
swift package clean
swift build -c release

Step 5f: Post-build version verification:

bash
BIN=".build/arm64-apple-macosx/release/afm"
[ -x "$BIN" ] || BIN=".build/release/afm"

# The binary MUST report the stable version
REPORTED_VERSION=$($BIN --version 2>&1)
echo "Binary reports: $REPORTED_VERSION"

if ! echo "$REPORTED_VERSION" | grep -qF "v${VERSION}"; then
  echo "FATAL: Binary reports '$REPORTED_VERSION' but expected 'v${VERSION}'"
  echo "BuildInfo.swift was not picked up by the build."
fi

If the binary version doesn't match v${VERSION}, STOP. The build did not incorporate the version change.

Step 5g: Relocated binary check (MANDATORY — blocks pip/Homebrew install crash):

SPM auto-generates resource_bundle_accessor.swift with a hardcoded absolute build path. If any code calls Bundle.module, the binary will fatalError when relocated (pip install, Homebrew). This has shipped broken releases before. This check is non-negotiable.

bash
# 1. Source code audit — Bundle.module must NEVER appear in non-comment source
HITS=$(grep -r 'Bundle\.module' Sources/ --include='*.swift' | grep -v '^\s*//' | grep -v '// ' | wc -l | tr -d ' ')
if [ "$HITS" -gt 0 ]; then
  echo "FATAL: Found $HITS Bundle.module call(s) — will crash on pip/Homebrew install"
  grep -rn 'Bundle\.module' Sources/ --include='*.swift' | grep -v '//'
  echo "STOP. Remove all Bundle.module calls before proceeding."
  exit 1
fi
echo "PASS: No Bundle.module calls in source"

# 2. Runtime simulation — copy binary + loose metallib to temp dir (NO SPM bundle)
TMPDIR=$(mktemp -d)
cp "$BIN" "$TMPDIR/"
cp "$(dirname "$BIN")/AFMKit_AFMKitMLX.bundle/default.metallib" "$TMPDIR/"

MACAFM_MLX_MODEL_CACHE=/Volumes/edata/models/vesta-test-cache \
  "$TMPDIR/afm" mlx -m mlx-community/Qwen3.5-35B-A3B-4bit -s "hello" --max-tokens 5 2>&1 | head -3
EXIT_CODE=${PIPESTATUS[0]}
rm -rf "$TMPDIR"

if [ "$EXIT_CODE" -ne 0 ]; then
  echo "FATAL: Relocated binary crashed (exit $EXIT_CODE)"
  echo "This means pip install and Homebrew install will crash on first run."
  echo "STOP. Fix MLXMetalLibrary.swift before proceeding."
  exit 1
fi
echo "PASS: Relocated binary runs without crash"

If either check fails, STOP IMMEDIATELY. Do NOT package, publish, or release. Every pip and Homebrew user will get a crash on first run.

Step 5h: Info.plist embedding check (MANDATORY — blocks Speech Recognition SIGABRT):

macOS 26 SIGABRTs any process that requests privacy-sensitive APIs (Speech Recognition, microphone, camera, etc.) without the matching *UsageDescription key in its embedded Info.plist. Required for afm speech, POST /v1/audio/transcriptions, and chat input_audio content parts. Any future privacy-API integration needs its *UsageDescription key added here too.

bash
# 1. Verify __TEXT,__info_plist section is present in the binary
if ! otool -l "$BIN" | grep -q '__info_plist'; then
  echo "FATAL: Missing __TEXT,__info_plist section in binary"
  echo "Check Package.swift linker flags (-Xlinker -sectcreate ...) and Sources/AFMCLI/Info.plist"
  exit 1
fi

# 2. Verify NSSpeechRecognitionUsageDescription key is embedded
if ! strings "$BIN" | grep -q 'NSSpeechRecognitionUsageDescription'; then
  echo "FATAL: NSSpeechRecognitionUsageDescription missing from embedded plist"
  echo "afm speech / /v1/audio/transcriptions will SIGABRT on macOS 26"
  exit 1
fi

# 3. Verify Info.plist source file is well-formed
plutil -lint Sources/AFMCLI/Info.plist || { echo "FATAL: Info.plist is malformed"; exit 1; }

# 4. Verify Apple frameworks that require the embedded plist are actually linked.
#    PR #104 (Vision OCR) and PR #107 (Speech transcription) depend on these — if they
#    drop out of Package.swift the plist is pointless because the APIs can't be called.
REQUIRED_FRAMEWORKS=(Speech Vision PDFKit ImageIO)
FW_MISSING=()
for FW in "${REQUIRED_FRAMEWORKS[@]}"; do
  if ! otool -L "$BIN" | grep -q "/${FW}.framework/"; then
    FW_MISSING+=("$FW")
  fi
done
if [ ${#FW_MISSING[@]} -gt 0 ]; then
  echo "FATAL: Binary missing required framework links: ${FW_MISSING[*]}"
  echo "Check Package.swift .linkedFramework(...) entries — PR #104/#107 features will not work."
  exit 1
fi

# 5. Verify CFBundleIdentifier (TCC identity) is embedded. Changing this bundle id
#    forces every user to re-grant Speech/mic/camera permission — treat as a contract.
if ! strings "$BIN" | grep -q 'com.scouzi1966.afm'; then
  echo "FATAL: Embedded plist missing CFBundleIdentifier=com.scouzi1966.afm (TCC identity broken)"
  exit 1
fi

echo "PASS: Info.plist embedded with NSSpeechRecognitionUsageDescription"
echo "PASS: Required frameworks linked: ${REQUIRED_FRAMEWORKS[*]}"
echo "PASS: CFBundleIdentifier present in embedded plist"

If this fails, STOP. Shipping a stable release with broken Speech Recognition is worse than shipping a nightly — stable users have higher expectations.

Note on CFBundleIdentifier in Info.plist: The CFBundleIdentifier (com.scouzi1966.afm) establishes the TCC identity. Changing it later forces every user to re-grant Speech Recognition / microphone / camera permission. Treat it as a stable contract across releases.

Step 6: Package Stable Tarball
bash
cd "$(git rev-parse --show-toplevel)"

BIN=".build/arm64-apple-macosx/release/afm"
[ -x "$BIN" ] || BIN=".build/release/afm"

STAGING=".build/release-package-stable"
rm -rf "$STAGING"
mkdir -p "$STAGING"

cp "$BIN" "$STAGING/"

# Provider resource bundles
for BUNDLE_NAME in AFMKit_AFMKitMLX.bundle AFMKit_AFMKitDwarfStar.bundle; do
  BUNDLE_DIR="$(dirname "$BIN")/$BUNDLE_NAME"
  test -d "$BUNDLE_DIR"
  cp -r "$BUNDLE_DIR" "$STAGING/"
done

# WebUI (MANDATORY — verified in Step 5d)
mkdir -p "$STAGING/Resources/webui"
cp "Resources/webui/index.html.gz" "$STAGING/Resources/webui/"

cp README.md "$STAGING/" 2>/dev/null || true
cp LICENSE "$STAGING/" 2>/dev/null || true

STABLE_TARBALL="afm-v${VERSION}-arm64.tar.gz"
tar -czf "$STABLE_TARBALL" -C "$STAGING" .
SHA256=$(shasum -a 256 "$STABLE_TARBALL" | cut -d' ' -f1)

echo "Tarball: $STABLE_TARBALL ($(du -h "$STABLE_TARBALL" | cut -f1 | xargs))"
echo "SHA256: $SHA256"

# MANDATORY: Verify tarball contains webui
if ! tar tzf "$STABLE_TARBALL" | grep -q "index.html.gz"; then
  echo "FATAL: Tarball does NOT contain WebUI! Aborting."
fi
Step 7: Return to Original Branch
bash
cd "$(git rev-parse --show-toplevel)"

# Return to original branch
git checkout "$ORIGINAL_BRANCH"
git stash pop 2>/dev/null || true

Now apply version changes to the working branch (Steps 8-9 operate on the current branch, not the detached HEAD).

Step 8: Create Stable GitHub Release
bash
cd "$(git rev-parse --show-toplevel)"

PREV_TAG=$(gh release list --repo scouzi1966/maclocal-api --limit 20 --json tagName -q '.[].tagName' \
  | grep '^v[0-9]' | head -1) || true

if [ -n "$PREV_TAG" ] && git cat-file -e "${PREV_TAG}^{commit}" 2>/dev/null; then
  CHANGELOG=$(git log --pretty=format:"- %s (\`%h\`)" "${PREV_TAG}..${BUILD_SHA}" -- . ':!vendor' 2>/dev/null)
else
  CHANGELOG=$(git log --pretty=format:"- %s (\`%h\`)" -20 -- . ':!vendor' 2>/dev/null)
fi

gh release create "v${VERSION}" \
  --title "afm ${VERSION}" \
  --notes "$(cat <<EOF
## afm ${VERSION}

Apple Foundation Models + MLX local models — OpenAI-compatible API, WebUI, all Swift.

### Changes since ${PREV_TAG:-first release}
${CHANGELOG}

### Install / Upgrade via Homebrew

**Fresh install:**
\`\`\`
brew tap scouzi1966/afm
brew install scouzi1966/afm/afm
\`\`\`

**Upgrade:**
\`\`\`
brew upgrade afm
\`\`\`

### Install via PyPI

\`\`\`
pip install macafm==${VERSION}
\`\`\`
EOF
)" \
  --target "$BUILD_SHA" \
  --repo scouzi1966/maclocal-api \
  "$STABLE_TARBALL"

Note: --target "$BUILD_SHA" ensures the release points to the exact commit used for the build.

IMPORTANT: Do NOT delete, edit, or modify any existing nightly releases. Nightly releases and their nightly-* tags must remain intact on GitHub. This skill creates a NEW stable release — it does not replace any existing release.

Step 8b: Publish to Staging Tap and Validate on a Clean Machine (MANDATORY)

DO NOT update the production tap (scouzi1966/afm) until the staging validation completes. The production tap is what every brew install scouzi1966/afm/afm user downloads. Shipping a broken build to it forces a revert — and any user who ran brew update in the broken window already has the bad bottle. Validate on the staging tap first so the real install path is tested against the real published artifact.

The staging tap repo is scouzi1966/homebrew-afm-staging. If it does not exist, create it (public, visible only via explicit tap):

bash
if ! gh repo view scouzi1966/homebrew-afm-staging >/dev/null 2>&1; then
  gh repo create scouzi1966/homebrew-afm-staging --public \
    --description "Staging Homebrew tap for afm — candidate builds under test, not for production"
fi

STAGING_DIR="${STAGING_TAP_DIR:-$(cd "$(git rev-parse --show-toplevel)/.." && pwd)/homebrew-afm-staging}"
if [ ! -d "$STAGING_DIR/.git" ]; then
  gh repo clone scouzi1966/homebrew-afm-staging "$STAGING_DIR"
fi

Write the candidate formula into the staging tap. Use the same URL / version / sha256 as the GitHub release created in Step 8 so the download path matches what the production tap will later serve.

bash
DOWNLOAD_URL="https://github.com/scouzi1966/maclocal-api/releases/download/v${VERSION}/afm-v${VERSION}-arm64.tar.gz"

cd "$STAGING_DIR"
git pull --ff-only 2>/dev/null || true

cat > afm.rb <<RUBY
class Afm < Formula
  desc "Apple Foundation Models + MLX local models — OpenAI-compatible API, WebUI, all Swift (STAGING)"
  homepage "https://github.com/scouzi1966/maclocal-api"
  url "${DOWNLOAD_URL}"
  version "${VERSION}"
  sha256 "${SHA256}"

  depends_on arch: :arm64
  depends_on :macos

  def install
    bin.install "afm"

    ["AFMKit_AFMKitMLX.bundle", "AFMKit_AFMKitDwarfStar.bundle"].each do |bundle_dir|
      (libexec/bundle_dir).mkpath
      (libexec/bundle_dir).install Dir["#{bundle_dir}/*"]
      bin.install_symlink libexec/bundle_dir
    end

    if Dir.exist?("Resources/webui")
      (share/"afm/webui").mkpath
      (share/"afm/webui").install Dir["Resources/webui/*"]
    end
  end

  def caveats
    <<~EOS
      ⚠️  STAGING BUILD — not for production use.
      This is v${VERSION} served from a staging tap for validation before
      promotion to the main scouzi1966/afm tap. Switch to the main tap
      for stable use:
        brew untap scouzi1966/afm-staging
        brew install scouzi1966/afm/afm
    EOS
  end

  test do
    assert_match "v${VERSION}", shell_output("#{bin}/afm --version")
  end
end
RUBY

git add afm.rb
git commit -m "Stage candidate v${VERSION}"
git push 2>&1 | tail -3

Now provide the user with a machine-portable install-and-verify recipe for a clean host. It MUST be a host that is not the one where the build was produced — the binary has been code-signed ad-hoc and has no special access on the build machine; only a fresh install via the staging tap exercises the same download and TCC path real end users will see.

Use AskUserQuestion:

Question: "Staged v${VERSION} is live at scouzi1966/afm-staging. Please install on a clean machine (ideally not the build host) and run the regression test matrix. Confirm results below."

Install instructions to give the user (absolute brew install form, not the cached tap form):

bash
# On the clean machine — no prior afm install of any kind
brew untap scouzi1966/afm 2>/dev/null  # optional: avoid any tap collision during test
brew tap scouzi1966/afm-staging
brew install scouzi1966/afm-staging/afm
afm --version                           # must show vVERSION

Regression matrix the user should run — at minimum:

  1. afm --version reports v${VERSION}.
  2. Plain text-only Foundation chat (tests the core code path; missing from earlier runs catches this class of regression):
    bash
    afm -p 9999 &
    sleep 3
    curl -s -X POST http://127.0.0.1:9999/v1/chat/completions \
      -H 'Content-Type: application/json' \
      -d '{"model":"foundation","stream":false,"messages":[{"role":"user","content":"Say hi"}]}'
    kill %1
  3. Any per-release PR-specific smoke tests (e.g. Vision OCR, Speech, MLX generation) relevant to what this promotion ships.

Options:

  1. "Staging validation PASSED — promote to production tap" — proceed to Step 9.
  2. "Staging validation FAILED" — STOP. The production tap must not be touched. Investigate, re-build, re-publish the GitHub release (or cut a new version), re-stage, re-test. Return here only after a clean pass.
  3. "Skip staging validation (not recommended)" — continue to Step 9 at your own risk. Only choose this for emergency hotfixes where the staging machine is unavailable and you accept the rollback cost.

If the user selects option 2, do NOT proceed to Step 9. The production tap remains on the previous stable. Offer the rollback procedure (below) if the GitHub release needs to be withdrawn.

Step 9: Update Homebrew Stable Tap (afm.rb)
bash
TAP_DIR="${TAP_DIR:-$(cd "$(git rev-parse --show-toplevel)/.." && pwd)/homebrew-afm}"
cd "$TAP_DIR"
git pull --ff-only

DOWNLOAD_URL="https://github.com/scouzi1966/maclocal-api/releases/download/v${VERSION}/afm-v${VERSION}-arm64.tar.gz"
sed -i '' "s|url \".*\"|url \"${DOWNLOAD_URL}\"|" afm.rb
sed -i '' "s/version \".*\"/version \"${VERSION}\"/" afm.rb
sed -i '' "s/sha256 \".*\"/sha256 \"${SHA256}\"/" afm.rb
sed -i '' "s/assert_match \"v[0-9][^\"]*\"/assert_match \"v${VERSION}\"/" afm.rb
sed -i '' "s/MLX Local Models (v[0-9][^)]*)/MLX Local Models (v${VERSION}+)/" afm.rb

git add afm.rb
git commit -m "afm ${VERSION}"
git push
Step 10: Update Version Files on Working Branch
bash
cd "$(git rev-parse --show-toplevel)"

# BuildInfo.swift
sed -i '' "s/static let version: String? = \".*\"/static let version: String? = \"v${VERSION}\"/" \
  Sources/AFMKit/BuildInfo.swift

# pyproject.toml
sed -i '' "s/^version = \".*\"/version = \"${VERSION}\"/" pyproject.toml

# macafm/__init__.py
sed -i '' "s/^__version__ = \".*\"/__version__ = \"${VERSION}\"/" macafm/__init__.py
Step 11: Update README.md
bash
# Install table version
sed -i '' "s/Stable (v[0-9][^)]*)/Stable (v${VERSION})/" README.md

# Release notes link
sed -i '' "s|\[v[0-9][^]]*\](https://github.com/scouzi1966/maclocal-api/releases/tag/v[^)]*)|[v${VERSION}](https://github.com/scouzi1966/maclocal-api/releases/tag/v${VERSION})|" README.md

# "What's new in afm-next" section — reset to show no new features since this stable release.
# All previous nightly features are now IN the stable release, so the list must be cleared.
# Future nightlies will add items back as new features land.
sed -i '' "s/everything in v[0-9][^ ]* plus/everything in v${VERSION} plus/" README.md

IMPORTANT: After updating the version reference, replace the bullet list under "What's new in afm-next" with:

> - No new features yet — nightly is currently in sync with the stable release

Remove all previous bullet points — they are now part of the stable release and no longer "new in afm-next". Future nightly builds will add new items to this section as features land after the stable cut.

Show full SKILL.md (784 more words)Show less
Step 12: Build Python Wheel

Stage the freshly built binary (from the stable build in Step 5) into the Python package:

bash
cd "$(git rev-parse --show-toplevel)"

BIN=".build/arm64-apple-macosx/release/afm"
[ -x "$BIN" ] || BIN=".build/release/afm"

mkdir -p macafm/bin macafm/share/webui
cp "$BIN" macafm/bin/

# Metallib
METALLIB="$(dirname "$BIN")/AFMKit_AFMKitMLX.bundle/default.metallib"
if [ -f "$METALLIB" ]; then
  cp "$METALLIB" macafm/bin/
fi

# WebUI (MANDATORY — verified in Step 5d)
cp "Resources/webui/index.html.gz" macafm/share/webui/

# Build wheel
uv build

# Clean staged assets (never commit binaries)
rm -rf macafm/bin macafm/share

# Verify wheel size (must be >1MB — contains binary)
WHEEL=$(ls -1 dist/macafm-${VERSION}*.whl 2>/dev/null | head -1)
WHEEL_SIZE=$(stat -f%z "$WHEEL" 2>/dev/null || stat -c%s "$WHEEL" 2>/dev/null)
echo "Wheel: $WHEEL (${WHEEL_SIZE} bytes)"
if [ "$WHEEL_SIZE" -lt 1000000 ]; then
  echo "ERROR: Wheel is only ${WHEEL_SIZE} bytes — assets were not staged correctly!"
fi

# MANDATORY: Verify wheel contains webui
if ! unzip -l "$WHEEL" | grep -q "index.html.gz"; then
  echo "FATAL: Wheel does NOT contain WebUI!"
fi

If wheel is under 1 MB or missing WebUI, STOP. Do not provide the publish command.

Step 12b: User Clean-Slate Installation Testing (MANDATORY)

Before publishing to PyPI, the user MUST verify both installation methods work from a completely clean slate. Each method must be tested independently with full uninstall in between to avoid conflicts.

First, uninstall ALL existing afm installations:

bash
# Remove all traces
brew uninstall afm 2>/dev/null || true
brew uninstall afm-next 2>/dev/null || true
pip uninstall macafm -y 2>/dev/null || true
uv pip uninstall macafm 2>/dev/null || true

# Verify clean slate
echo "=== Verify clean slate ==="
brew list --formula 2>&1 | grep -E "^afm" || echo "Homebrew: clean"
pip show macafm 2>&1 | grep -i version || echo "pip: clean"
which afm 2>&1 || echo "PATH: clean"

Use AskUserQuestion:

Question: "Clean-slate testing required. Please test Homebrew install first, then uninstall before testing pip. Ready to start?"

Provide the user with these commands:

Test 1 — Homebrew (test, then fully uninstall before Test 2):

brew update
brew tap scouzi1966/afm
brew install scouzi1966/afm/afm
afm --version          # must show vVERSION
afm mlx -w -m <model>  # must launch WebUI in browser
brew uninstall afm      # MUST uninstall before Test 2

Test 2 — pip from local wheel (after brew is fully removed):

pip install FULL_PATH_TO_WHEEL
afm --version          # must show vVERSION
afm mlx -w -m <model>  # must launch WebUI in browser
pip uninstall macafm    # clean up after testing

IMPORTANT: Always provide the full absolute path to the wheel file. The user may run the command from any directory.

Options:

  1. "Both passed" — continue to PyPI publish
  2. "Homebrew failed" — investigate and fix before continuing
  3. "pip failed" — investigate and fix before continuing

If either test fails, STOP. Investigate the failure, fix the issue, and re-run the failed test before proceeding. Do NOT publish to PyPI until both methods pass.

Step 13: Provide PyPI Publish Command

The maintainer has a TestPyPI account (separate login from production PyPI, 2FA + API token), so the wheel can be validated on TestPyPI before the production push. For a release that feels risky (new packaging, big version jump), offer the TestPyPI dry-run first; otherwise production is fine. The token is supplied at publish time (--token / UV_PUBLISH_TOKEN / ~/.pypirc) — never assume it's stored in the repo.

Present the exact command with the absolute path to the wheel and a placeholder token (production):

bash
ROOT="$(git rev-parse --show-toplevel)"
echo "uv publish --token <YOUR_PYPI_TOKEN> ${ROOT}/dist/macafm-${VERSION}*"

TestPyPI dry-run variant (validate first, then verify with pip install --index-url https://test.pypi.org/simple/ macafm==${VERSION}):

bash
echo "uv publish --publish-url https://test.pypi.org/legacy/ --token <YOUR_TEST_PYPI_TOKEN> ${ROOT}/dist/macafm-${VERSION}*"

IMPORTANT: Always provide the full absolute path to the dist files — the user may run the command from a different directory.

Use AskUserQuestion:

Question: "The wheel is ready. Validate on TestPyPI first, publish straight to production PyPI, or skip? (Replace the token placeholder with your own.)"

Options:

  1. "TestPyPI first" — run the TestPyPI dry-run, verify, then production
  2. "Done — published to PyPI"
  3. "Skip PyPI"
Step 14: Verify Deployment

Homebrew verification:

bash
brew update
brew tap scouzi1966/afm
brew install scouzi1966/afm/afm || brew upgrade afm
# If afm-next is linked, unlink it first: brew unlink afm-next && brew link afm
BREW_VERSION=$(afm --version 2>&1)
echo "Homebrew afm version: $BREW_VERSION"
echo "$BREW_VERSION" | grep -qF "v${VERSION}" && echo "VERSION: PASS" || echo "VERSION: FAIL: expected v${VERSION}"

# Smoke test — run a simple prompt to verify the binary actually works
afm -s "why is the sky blue" 2>&1 | head -20
echo "BREW SMOKE TEST: PASS (if output above contains a response)"

PyPI verification (only if user published in Step 13):

bash
VENV_DIR=$(mktemp -d)
python3 -m venv "$VENV_DIR"
"$VENV_DIR/bin/pip" install macafm==${VERSION}
PIP_VERSION=$("$VENV_DIR/bin/afm" --version 2>&1)
echo "PyPI afm version: $PIP_VERSION"
echo "$PIP_VERSION" | grep -qF "v${VERSION}" && echo "VERSION: PASS" || echo "VERSION: FAIL: expected v${VERSION}"

# Smoke test — run a simple prompt to verify the pip-installed binary works
$VENV_DIR/bin/afm -s "why is the sky blue" 2>&1 | head -20
echo "PIP SMOKE TEST: PASS (if output above contains a response)"
rm -rf "$VENV_DIR"

Report PASS/FAIL for each (version check + smoke test). If either fails, investigate and report the issue before proceeding.

Step 15: Commit and Report
bash
cd "$(git rev-parse --show-toplevel)"
git add Sources/AFMKit/BuildInfo.swift pyproject.toml macafm/__init__.py README.md
git commit -m "Release v${VERSION}: promote nightly to stable"

Use AskUserQuestion before pushing:

Question: "Version files committed. Push to origin/main?"

Options:

  1. "Push" — git push origin main
  2. "Don't push"

Cleanup:

bash
rm -rf ".build/release-package-stable"
rm -f "afm-v${VERSION}-arm64.tar.gz"

Final report:

  • Stable version: VERSION
  • Built from commit: BUILD_SHA
  • GitHub release URL
  • Homebrew: brew install scouzi1966/afm/afm / brew upgrade afm
  • PyPI: pip install macafm==VERSION (if published)
  • Wheel file: path and size
  • Verification results (Homebrew ✓/✗, PyPI ✓/✗)
Error Handling
  • Patch verification fails (Step 5): STOP. Do not build. Show which patches failed diff -q. Likely cause: submodule is at wrong commit or patches were not applied. Re-run git submodule update --init --recursive then ./Scripts/apply-mlx-patches.sh.
  • Binary version mismatch (Step 5e): STOP. BuildInfo.swift change was not compiled. Run swift package clean and rebuild.
  • Stable tag already exists: User must choose a different version or delete existing release first.
  • Tap push fails: Check $TAP_DIR is on right branch with no uncommitted changes.
  • Wheel too small (<1 MB): Assets not staged — verify binary, metallib, and webui exist in staging dirs.
  • uv build fails: Check uv is installed; check pyproject.toml syntax.
  • Homebrew install fails after publish: Run brew update; check formula with brew audit afm.
  • PyPI install fails: Check version was actually published; try pip install macafm==VERSION --no-cache-dir.
  • Detached HEAD issues: Step 7 returns to original branch. If git checkout fails, check for uncommitted changes with git status.
Rollback Procedure

If something goes wrong after publishing, use the rollback snapshot from Step 3b to revert. PyPI is immutable — a published version cannot be deleted or replaced. All other channels can be fully reverted.

Use AskUserQuestion before executing rollback:

Question: "Are you sure you want to rollback the v${VERSION} stable release? This will delete the GitHub release, revert the Homebrew tap, and undo version file changes. PyPI cannot be reverted."

Options:

  1. "Rollback" — proceed
  2. "Cancel" — abort rollback

1. Delete GitHub release and tag:

bash
gh release delete "v${VERSION}" --repo scouzi1966/maclocal-api --yes
git tag -d "v${VERSION}" 2>/dev/null || true
git push origin --delete "v${VERSION}" 2>/dev/null || true

2. Revert Homebrew tap:

bash
cd "$TAP_DIR"
git revert HEAD --no-edit
git push
# Verify it matches the previous state
grep 'version "' afm.rb
# Should show: PREV_STABLE_VERSION

3. Revert version files on working branch:

bash
cd "$(git rev-parse --show-toplevel)"

# Restore previous values
sed -i '' "s/static let version: String? = \".*\"/static let version: String? = \"${PREV_BUILDINFO_VERSION}\"/" \
  Sources/AFMKit/BuildInfo.swift
sed -i '' "s/^version = \".*\"/version = \"${PREV_PYPROJECT_VERSION}\"/" pyproject.toml
sed -i '' "s/^__version__ = \".*\"/__version__ = \"${PREV_INIT_VERSION}\"/" macafm/__init__.py

# Restore README
sed -i '' "s/Stable (v[0-9][^)]*)/Stable (v${PREV_PYPROJECT_VERSION})/" README.md
sed -i '' "s|\[v${VERSION}\](https://github.com/scouzi1966/maclocal-api/releases/tag/v${VERSION})|[v${PREV_PYPROJECT_VERSION}](https://github.com/scouzi1966/maclocal-api/releases/tag/v${PREV_PYPROJECT_VERSION})|" README.md

git add Sources/AFMKit/BuildInfo.swift pyproject.toml macafm/__init__.py README.md
git commit -m "Rollback: revert v${VERSION} promotion"

Use AskUserQuestion before pushing the rollback commit.

4. PyPI (immutable — cannot rollback):

If the wheel was published to PyPI, it cannot be deleted. Options:

  • Publish a new patch version (e.g., X.Y.Z+1) with the fix
  • Yank the version (marks it as not recommended but doesn't delete it): pip install twine && twine yank macafm ${VERSION} --repository pypi

After rollback, report:

  • GitHub release: deleted ✓
  • Git tag v${VERSION}: deleted ✓
  • Homebrew tap: reverted to PREV_STABLE_VERSION ✓
  • Version files: reverted ✓
  • PyPI: immutable (not reverted)

© scouzi1966, MIT. Rendered from Markdown: HTML in the file is shown as text, images as links, and headings moved down two levels. Raw file

Files

Just SKILL.md in .claude/skills/afm-build-promote-nightly of scouzi1966/maclocal-api.

Open the folder on GitHubat commit 138ca5d

Compare with similar skills

Afm Build Promote Nightly next to the 5 skills that share the most tags, products or categories with it. Stars are the repository's; “used in” counts other GitHub owners with a copy.

Afm Build Promote Nightly compared with similar skills
SkillStarsUsed inTokensAuto-checkLicenceRepo updated
Afm Build Promote Nightly this skillscouzi1966/maclocal-api346—~8.9kAutomated safety check: WarnMIT
App Store Deployromankurnovskii/BrewMate300—~813Automated safety check: NotesMIT
Releasevaayne/mori303—~1.2kAutomated safety check: PassMIT
Ffmpeg Kit macOS Codesign Crashdivinevideo/divine-mobile266—~1.1kAutomated safety check: PassMPL-2.0
App Store Screenshots GeneratorParthJadhav/app-store-screenshots7.2k—~16kAutomated safety check: PassMIT
Release Asc CLIrorkai/App-Store-Connect-CLI7.7k—~2.4kAutomated safety check: PassMIT

Similar skills

  • App Store Deploy

    romankurnovskii/BrewMate

    Automates the build and deployment of the Electron app to the Mac App Store and TestFlight.

    300 GitHub stars~813 tokensUpdated 13 days ago
    MobileAuto-check: notes
  • Release

    vaayne/mori

    Release workflow for Mori macOS workspace terminal and MoriRemote iOS app.

    303 GitHub stars~1.2k tokensUpdated 2 mo ago
    MobileAuto-check passed
  • Ffmpeg Kit macOS Codesign Crash

    divinevideo/divine-mobile

    Fix Flutter macOS app crash at launch due to FFmpeg Kit library loading failure.

    266 GitHub stars~1.1k tokensUpdated yesterday
    Media & CreativeAuto-check passed
  • App Store Screenshots Generator

    ParthJadhav/app-store-screenshots

    Scaffolds a Next.js editor for designing App Store and Google Play screenshots as ads and exporting them at every required size, for iOS, Mac and Android.

    7.2k GitHub stars~16k tokensUpdated yesterday
    MobileAuto-check passed
  • Release Asc CLI

    rorkai/App-Store-Connect-CLI

    Publish and verify a new release of the App-Store-Connect-CLI repository.

    7.7k GitHub stars~2.4k tokensUpdated today
    MobileAuto-check passed
  • App Store Preflight Skills

    truongduy2611/app-store-preflight-skills

    Scan an iOS/macOS Xcode project for common App Store rejection patterns before submission.

    1.4k GitHub stars~1.4k tokensUpdated 4 mo ago
    MobileAuto-check passed

More from scouzi1966/maclocal-api

All 12 skills in this repo
  • Afm

    scouzi1966/maclocal-api

    Maintain and extend AFM (maclocal-api), a Swift OpenAI-compatible local LLM server and CLI for Apple Foundation Models, MLX models, API gateway proxying, and Vision OCR.

    346 GitHub stars~1.2k tokensUpdated yesterday
    Auto-check passed
  • Build Afm

    scouzi1966/maclocal-api

    Build AFM from scratch — submodules, patches, webui, and Swift build.

    346 GitHub stars~1.8k tokensUpdated yesterday
    Auto-check: notes
  • Codex Promptfoo Agentic Eval

    scouzi1966/maclocal-api

    Run and review the Promptfoo-based AFM agentic evaluation suite.

    346 GitHub stars~1.8k tokensUpdated yesterday
    Auto-check passed
  • Test Afm Binary

    scouzi1966/maclocal-api

    Test a pre-built afm binary at any path — runs pre-flight safety checks, then any combination of unit tests, assertions, smart analysis, promptfoo evals, batch validation, OpenAI compat, GPU…

    346 GitHub stars~3.8k tokensUpdated yesterday
    Auto-check passed
  • Afm Release Wheel

    scouzi1966/maclocal-api

    A skill your agent uses when user wants to build a PyPI wheel from an existing compiled afm binary and publish to PyPI.

    346 GitHub stars~1.5k tokensUpdated yesterday
    Auto-check: warnings
  • Test Macafm

    scouzi1966/maclocal-api

    Run the maclocal-api (AFM/MLX) test suite — automated assertions and smart analysis.

    346 GitHub stars~7k tokensUpdated yesterday
    Auto-check passed

Works with

Questions about Afm Build Promote Nightly

What does Afm Build Promote Nightly do?

A skill your agent uses when promoting afm to a stable release — builds from main HEAD or a nightly commit, verifies patches, updates Homebrew stable tap (afm.rb), builds a PyPI wheel, updates…. Afm Build Promote Nightly is an agent skill from scouzi1966/maclocal-api.rb), builds a PyPI wheel, updates README and version files, and verifies both brew install and pip install work.

When should I use Afm Build Promote Nightly?

Afm Build Promote Nightly fits situations like: promoting afm to a stable release — builds from main HEAD; A nightly commit; verifies patches; updates Homebrew stable tap (afm.rb).

How do I install Afm Build Promote Nightly in Claude Code?

Run `npx skills add scouzi1966/maclocal-api --skill afm-build-promote-nightly -a claude-code`. Or copy the skill folder (.claude/skills/afm-build-promote-nightly in scouzi1966/maclocal-api) into .claude/skills/afm-build-promote-nightly in your project. Claude Code loads it when a task matches its description.

How do I install Afm Build Promote Nightly in Codex?

Run `npx skills add scouzi1966/maclocal-api --skill afm-build-promote-nightly -a codex`. Or copy the skill folder (.claude/skills/afm-build-promote-nightly in scouzi1966/maclocal-api) into .agents/skills/afm-build-promote-nightly in your project. Codex loads it when a task matches its description.

Can I use Afm Build Promote Nightly in Cursor, Gemini CLI or GitHub Copilot?

Cursor, Gemini CLI, GitHub Copilot and OpenCode also load SKILL.md folders. With the skills CLI, run `npx skills add scouzi1966/maclocal-api --skill afm-build-promote-nightly -a cursor` (or -a gemini-cli, github-copilot or opencode for the others). To copy it by hand, put the folder in .cursor/skills/afm-build-promote-nightly, .gemini/skills/afm-build-promote-nightly, .github/skills/afm-build-promote-nightly and .opencode/skills/afm-build-promote-nightly in your project.

What does Afm Build Promote Nightly need to run?

Going by SKILL.md and its folder, Afm Build Promote Nightly needs the command-line tools its instructions call (git, brew, gh, pip, swift and uv) and credentials named UV_PUBLISH_TOKEN. Our summary lists: Python 3; Node.js.

Does Afm Build Promote Nightly access the network?

SKILL.md names 1 domain. In commands or code: test.pypi.org; the agent is likely to contact it when it follows the instructions. This is read from the text; nothing was executed.

Is Afm Build Promote Nightly safe to install?

Our automated static check of SKILL.md flagged 1 warning(s): mentions a credentials file (ssh keys, cloud or package-manager tokens). Read the flagged lines before installing; the check is not a guarantee either way.

What licence does Afm Build Promote Nightly use?

Afm Build Promote Nightly is published under the MIT licence (the repository's licence). It allows redistribution, so the full SKILL.md is shown on this page.

How many tokens does Afm Build Promote Nightly use?

About 8.9k tokens (SKILL.md is roughly 35k characters). Agents keep only the skill's name and description in context until a task matches; then they load SKILL.md in full.

What are the alternatives to Afm Build Promote Nightly?

Skills that share tags, products or a category with Afm Build Promote Nightly: App Store Deploy (romankurnovskii/BrewMate, 300 stars), Release (vaayne/mori, 303 stars), Ffmpeg Kit macOS Codesign Crash (divinevideo/divine-mobile, 266 stars) and App Store Screenshots Generator (ParthJadhav/app-store-screenshots, 7.2k stars). The comparison table on this page puts their stars, adoption, token cost, safety result and licence side by side.

Who maintains Afm Build Promote Nightly?

scouzi1966 (a GitHub user) maintains it in scouzi1966/maclocal-api, which has 346 GitHub stars. The repository holds 12 skills in this directory. The repository was last updated on October 10, 2026.

Source: scouzi1966/maclocal-api on GitHub. Facts on this page come from the repository at the commit we read; the author's words are quoted as theirs.