AGENTS.md defines the project map, change boundaries, mail privacy safeguards and verification requirements for agents. CONTRIBUTING.md provides setup, focused-change and pull-request steps for people and AI contributors. Read these before changing the repository.
Aggregate Mail shares its React renderer, Electron main process and bundled mail service across Windows and macOS. npm run package builds Windows NSIS; npm run package:mac builds macOS DMG and ZIP files on a Mac. Package names include the macOS architecture. See installation and storage, product scope and ADR 0001.
The macOS target disables app and DMG signing and notarization. The release workflow calls cross-platform CI and publishes installers for version tags. Building a package does not publish it or prove Gatekeeper acceptance.
Run npm test and npm run build before packaging. The desktop startup check opens the encrypted database, loads the renderer, requires the desktop token for API access and checks native menu roles on macOS. Use a temporary user-data directory so checks cannot open a maintainer's accounts:
| 1 | check_dir=$(mktemp -d) |
| 2 | npm run check:desktop -- --user-data-dir="$check_dir" |
For a packaged Apple silicon build, use the logged-in macOS desktop session. Quit any running copy first, since the mail service uses a fixed port:
| 1 | check_dir=$(mktemp -d) |
| 2 | open -n -W "release/mac-arm64/Aggregate Mail.app" \ |
| 3 | --stdout "$check_dir/stdout.log" --stderr "$check_dir/stderr.log" \ |
| 4 | --args --check-startup --user-data-dir="$check_dir/profile" |
| 5 | cat "$check_dir/stdout.log" "$check_dir/stderr.log" |
Require a startup: passed JSON result and process exit, then remove only the temporary directory created for that check. An open exit alone is insufficient. Intel builds use release/mac/. These checks do not drive the UI, authenticate real accounts or send mail. A direct SSH executable launch can lack Keychain access even when desktop launch works. Keychain availability is required; an access failure is a blocker, not a reason to replace encryption.
The repository has no scripts/documentation.py; documentation checks currently require link and diff review.
Keep credentials, personal contact details, absolute machine paths, private hostnames, session records and mailbox contents out of source, commits, PRs and release attachments. Use synthetic test data and portable commands. Preserve the project's existing identity. Review commit author and committer metadata before pushing. Ignore rules and package exclusions are preventive controls; scan the final source diff and package contents too. A pattern scan cannot prove the absence of all sensitive information.
The CI workflow runs on pull requests, pushes to main and manual dispatch. The tag-release workflow calls the same build jobs. Each matrix job uses Node 24, installs the lockfile with npm ci, runs npm test, runs the TypeScript and production build, runs an isolated production-startup check on Windows and macOS, then packages an installer without publishing. Linux runtime behavior needs separate proof.
| Platform | Architecture | Installer | Standard runner |
|---|---|---|---|
| Windows | x64 | NSIS .exe | windows-latest |
| macOS | Apple silicon arm64 | .dmg | macos-15 |
| macOS | Intel x64 | .dmg | macos-15-intel |
| Linux | x64 | .AppImage | ubuntu-24.04 |
Download installer-<platform> from the workflow run's Artifacts section. Each artifact expires after one day. Reruns replace artifacts for rebuilt platforms; successful platform jobs that are not rerun retain their earlier artifacts. Missing installer files fail the job. Superseded runs are canceled, and each job has a 20-minute limit.
The build-version step gives non-tag runs the version <release>-ci.<GITHUB_RUN_ID>.<GITHUB_RUN_ATTEMPT>. It updates package.json and both root lockfile versions only in the runner checkout. Each new run or rerun has a distinct application version and installer filename. The macOS bundle build version and Windows file version use the workflow run number and attempt. Tagged builds keep the exact release version and reject a mismatched tag. Bump and commit the source release version before each new release tag. See ADR 0004.
The repository is public. Standard GitHub-hosted runner execution is free under GitHub's Actions billing policy. Artifact storage shares the owner's plan allowance with GitHub Packages; excess artifact storage is billed at $0.25 USD per GB-month. npm cache storage has a separate 10 GB included allowance per repository. One-day artifact retention limits storage use but does not set an account spending cap. Recheck billing before making the repository private or selecting larger runners.
CI has read-only repository permissions, disables signing-certificate discovery, and passes --publish never to packaging. It needs no mail-provider keys or signing credentials. Installer creation proves packaging; it does not prove native launch, account sign-in, OS trust acceptance or mail delivery. Windows installers are unsigned; macOS installers are unsigned and not notarized. The release workflow publishes all four installers and SHA-256 checksums only after every build job passes. The version tag must match package.json. Only its publishing job has repository write permission.