---
summary: "Signing steps for macOS debug builds generated by packaging scripts"
read_when:
  - Building or signing mac debug builds
title: "macOS Signing"
---

# mac signing (debug builds)

This app is usually built from
[`scripts/package-mac-app.sh`](https://github.com/fased-ai/fased/blob/main/scripts/package-mac-app.sh),
which now:

- sets a stable debug bundle identifier: `ai.fased.mac.debug`
- writes the Info.plist with that bundle id (override via `BUNDLE_ID=...`)
- calls
  [`scripts/codesign-mac-app.sh`](https://github.com/fased-ai/fased/blob/main/scripts/codesign-mac-app.sh)
  to sign the main binary and app bundle so macOS keeps TCC permissions stable.
  For stable permissions, use a real signing certificate.
- uses `CODESIGN_TIMESTAMP=auto` by default for Developer ID signatures. Set
  `CODESIGN_TIMESTAMP=off` to skip timestamping for offline debug builds.
- injects build metadata into Info.plist: `FasedAgentBuildTimestamp` (UTC) and
  `FasedAgentGitCommit` (short hash).
- **Packaging requires Node 24 recommended, or Node 22.14+ with `node:sqlite`**:
  the script runs TS builds and the Control UI build.
- reads `SIGN_IDENTITY` from the environment. Add
  `export SIGN_IDENTITY="Apple Development: Your Name (TEAMID)"` to your shell
  rc to always sign with your cert.
- requires explicit opt-in for ad-hoc signing via `ALLOW_ADHOC_SIGNING=1` or
  `SIGN_IDENTITY="-"`. This is not recommended for permission testing.
- runs a Team ID audit after signing and fails if any Mach-O inside the app
  bundle is signed by a different Team ID. Set `SKIP_TEAM_ID_CHECK=1` to bypass.

## Usage

```bash
# from repo root
scripts/package-mac-app.sh
SIGN_IDENTITY="Developer ID Application: Your Name" scripts/package-mac-app.sh
ALLOW_ADHOC_SIGNING=1 scripts/package-mac-app.sh
SIGN_IDENTITY="-" scripts/package-mac-app.sh
DISABLE_LIBRARY_VALIDATION=1 scripts/package-mac-app.sh
```

### Ad-hoc Signing Note

When signing with `SIGN_IDENTITY="-"` (ad-hoc), the script automatically
disables the **Hardened Runtime** (`--options runtime`). This prevents crashes
when the app loads embedded frameworks that do not share the same Team ID.
Ad-hoc signatures also break TCC permission persistence; see
[macOS permissions](/platforms/mac/permissions) for recovery steps.

## Build metadata for About

`package-mac-app.sh` stamps the bundle with:

- `FasedAgentBuildTimestamp`: ISO8601 UTC at package time
- `FasedAgentGitCommit`: short git hash (or `unknown` if unavailable)

The About tab reads these keys to show version, build date, git commit, and
whether it is a debug build via `#if DEBUG`. Run the packager to refresh these
values after code changes.

## Why

TCC permissions are tied to the bundle identifier and code signature. Unsigned
debug builds with changing UUIDs can cause macOS to forget grants after each
rebuild. Signing the binaries and keeping a fixed bundle id/path
(`dist/FasedAgent.app`) preserves grants between builds.
