Skip to content

how to contribute tooling

Nik Anand edited this page Jun 15, 2026 · 3 revisions

Tooling

The build system, packaging script, and CI workflows behind DroidProxy.

Build system: Swift Package Manager

The package manifest is /Users/nikhilanand/droidproxy/src/Package.swift (swift-tools-version: 5.9, platform macOS(.v13)):

  • CLIProxyMenuBar — an executableTarget at Sources/, depending on Sparkle (https://github.com/sparkle-project/Sparkle, from 2.5.0). Bundled resources are copied via .copy("Resources"), so everything under src/Sources/Resources/ (the cli-proxy-api binary, config.yaml, icons) ships in the build.
  • CLIProxyMenuBarTests — a testTarget at Tests/CLIProxyMenuBarTests/, depending on the executable target. See Testing.

Run swift commands from /Users/nikhilanand/droidproxy/src.

Packaging: create-app-bundle.sh

/Users/nikhilanand/droidproxy/create-app-bundle.sh builds and signs DroidProxy.app at the repo root. Steps:

  1. Buildswift build -c release (honors TARGET_ARCH when set, e.g. arm64).
  2. Assemble — creates the .app structure, copies the CLIProxyMenuBar executable, adds an @loader_path/../Frameworks rpath for Sparkle, copies the contents of src/Sources/Resources/ into Contents/Resources/ (skipping *.swift), and copies Sparkle.framework into Contents/Frameworks/. It fails hard if cli-proxy-api is missing.
  3. Version — injects CFBundleShortVersionString from APP_VERSION (or the latest git tag, v-prefix stripped) and CFBundleVersion from git rev-list --count HEAD.
  4. Sign — uses a Developer ID Application identity (CODESIGN_IDENTITY, or auto-detected from the keychain) with hardened runtime (--options runtime --timestamp). It signs the cli-proxy-api binary (with entitlements.plist), Sparkle.framework and its nested XPC services / Autoupdate / Updater.app (with sparkle-entitlements.plist), the main executable, then the whole bundle, and verifies with codesign --verify --deep --strict. With no identity it falls back to an ad-hoc signature (codesign --force --deep --sign -), which is fine for local dev but not for distribution.
# Local release bundle, auto-detecting signing identity
./create-app-bundle.sh

# Explicit version + identity
APP_VERSION=1.9.0 CODESIGN_IDENTITY="Developer ID Application: ..." TARGET_ARCH=arm64 ./create-app-bundle.sh

CI workflows (.github/workflows/)

Workflow Trigger What it does
pr-build.yml PRs to main touching src/**, create-app-bundle.sh, or the workflow Compile check: swift build -c release --arch arm64 on macos-26. No signing/notarization.
release.yml Push to main touching src/**, create-app-bundle.sh, entitlements.plist, sparkle-entitlements.plist; or manual dispatch Build, sign, notarize, Sparkle-sign, update appcast.xml, tag, and publish a GitHub release on macos-26. See Deployment.
update-cliproxyapi.yml Every 12 hours (cron) + manual dispatch Checks router-for-me/CLIProxyAPI for a newer release; if found, downloads the arm64 binary into src/Sources/Resources/cli-proxy-api and opens a bump-cliproxyapi-<version> PR (closing superseded bump PRs). Merging that PR triggers a release.
droid.yml @droid mention in a comment, review, issue, or PR body Runs the Factory Droid agent (Factory-AI/droid-action).
droid-review.yml PR to main opened / synchronize / labeled, gated on the droid-review label Runs Droid Auto Review and comments findings (review_model: gpt-5.2).
junie-review.yml, junie-tag.yml PR / mention events A second automated review/agent path.

Notarization and update signing

These run inside release.yml but can be done locally for a hand-built bundle:

# Notarize
ditto -c -k --sequesterRsrc --keepParent "DroidProxy.app" "DroidProxy-notarize.zip"
xcrun notarytool submit "DroidProxy-notarize.zip" --keychain-profile "notarytool" --wait
xcrun stapler staple "DroidProxy.app"

# Sparkle update signature for the release zip
src/.build/artifacts/sparkle/Sparkle/bin/sign_update DroidProxy-arm64.zip

notarytool submits the zipped app to Apple and stapler attaches the ticket; Sparkle's sign_update produces the edSignature that goes into appcast.xml. The full build → sign → notarize → Sparkle → appcast → GitHub release pipeline is documented in Deployment. The app ships as a single arm64 build — there is no Intel/x86_64 release path.

Conventions

See Patterns and conventions for codebase rules (NSLog, surgical JSON editing, source-of-truth locations) that affect anything you build or package.

Clone this wiki locally