Submitting to the Store
The Store lists add-ons from LedgeAddOns, a public GitHub repository. You submit an add-on as a pull request; once it's reviewed and merged, it's built, published and listed in everyone's Store.
From your Mac to the Store
- Fork LedgeAddOns and clone your fork.
- Create a branch, and add your add-on as its own Swift package in
add-ons/<id>/. The folder name must be the add-on'sid. - Run its tests and build the catalogue locally, then load the package into Ledge and try it.
- Open a pull request against
mainand fill in the template. - A maintainer reviews the source and what it asks for, and merges it.
- The merged commit is built again from scratch and published as a new catalogue release.
- The next time someone opens the Store, your add-on is listed.
What goes in the folder
add-ons/my-addon/
├── Package.swift LedgeKit pinned to a release by its HTTPS URL
├── addon.json id must match the folder name
├── listing.json how the add-on's Store page looks
├── Assets/Icon.png
├── Store/ screenshots and a motion demo
├── Sources/
├── Tests/
└── README.md what it does, what it needs, how to set it upThe package must build on its own, without the Ledge repository. Don't include credentials, build output, binaries or .build folders.
listing.json
addon.json says what the add-on is and what it needs. listing.json says how its page in the Store looks. Every new submission needs one.
{
"developer": "Your display name",
"category": "System",
"availability": "Free · macOS 14 or later",
"description": "What it does, how to set it up, and what it can't do.",
"feedbackURL": "https://github.com/your-account/your-addon/issues/new",
"screenshots": ["Store/Screenshot.png"],
"motionDemo": "Store/Demo.mp4"
}| Field | Rules |
|---|---|
developer | Up to 120 characters. Shown as Developer on the add-on's page |
category | Up to 60 characters. Media and System have their own filters in the Store |
availability | Up to 120 characters, such as the price and the macOS it needs |
description | Up to 10,000 characters. Describe what it really does, including its limits |
feedbackURL | An HTTPS address. Send feedback opens it in the browser and never sends anything itself |
screenshots | 1 to 8 PNGs inside your folder, each at most 8 MB and 4096 pixels a side |
motionDemo | One MP4 inside your folder, at most 32 MB. It plays only when someone chooses to |
Use real captures of your add-on, or clearly labelled demos, with nothing private in them. When the catalogue is published, each file gets its own release address and hash, and Ledge checks them before showing them.
Don't add an install count. installs is kept for a future service that counts verified installs, and a listing that includes it is rejected.
Check it before you open the pull request
swift test --package-path add-ons/my-addon
python3 scripts/build.pybuild.py runs the same checks as CI. It validates every manifest, runs each add-on's tests, builds for Apple silicon and Intel, and writes the files and catalog.json to dist/.
The pull request
The template asks you to explain:
- The add-on's name, permanent ID, version and purpose
- Every capability, every server it talks to, and how it uses credentials
- What you tested by hand, and what you couldn't
and to confirm that:
- LedgeKit is pinned to a published version
- Tests pass and the package loads in Ledge
- No credentials or generated binaries are included
- You have the rights to the icon and any other assets
- You checked what happens when it fails and when it's removed
Review
CI builds every pull request with read-only permissions and no secrets, so a pull request can never publish anything. A passing build doesn't mean the add-on is accepted. A maintainer reads the source, the capabilities, the dependencies, the assets and how it behaves when things go wrong.
After it's merged
A separate job rebuilds the merged commit for arm64 and x86_64, signs it for development, and publishes the files with a new catalog.json as a release tagged with that commit. Only that job can publish. If the build fails, the previous release stays in place. The catalogue describes what gets published.
Updates and removal
To release a new version, raise version in addon.json and open another pull request. To take an add-on out of the Store, its folder is removed and a new catalogue is published.