---
url: https://docs.sunlicense.com/guide/releases.md
---
# Publish releases from the CLI or CI

A release is a version of your product that buyers [download](/guide/downloads) from SunLicense, with their license
(and a mark naming them) written into the file. Besides the dashboard's **Downloads** tab, you can publish releases
from the command line, from your CI workflow, or from an AI assistant over [MCP](/cli/mcp). Product downloads are on
the **Standard** [plan](/guide/plans).

## From the command line

```bash
sunlicense releases create build/libs/acme-1.4.0.jar --product acme-editor --version 1.4.0 --notes @CHANGELOG.md
```

It creates release `1.4.0`, uploads the file straight to SunLicense storage, waits for SunLicense to check it and
publishes it: buyers can download it from their download links and the customer portal at once. For each file it says
whether every download carries the buyer's key and mark (see [Download watermark](#download-watermark)).

| Flag | What it does |
|---|---|
| `--product <code\|name\|id>` | The product |
| `--version <version>` | The release's version, like `1.4.0` or `2.0.0-beta.1` (required) |
| `--notes <text\|@file>` | Release notes in Markdown, or `@file` to read them from a file |
| `--title <text>` | A short title buyers see |
| `--draft` | Upload without publishing: buyers don't see it until you publish it under **Downloads** |
| `--obfuscate` | Obfuscate the files on SunLicense before they go live (Lite and Standard, uses obfuscation runs) |
| `--wait <duration>` | How long to wait for the file check (default `5m`, `15m` with `--obfuscate`) |
| `--json` | Print the result as JSON |

Several files (one per platform, a jar and a resource pack): pass them all to the one command. A **draft** of the same
version gets the files instead of a new release, so you can create the draft in the dashboard or with an assistant and
upload from CI; a file that is already in the draft with the same content isn't uploaded again. A **published** version
is refused: give each build its own version.

```bash
sunlicense releases list acme-editor                                     # versions, status, files, storage used
sunlicense releases delete --product acme-editor --version 1.4.0-setup   # a draft only
```

Published releases are deleted or unpublished under **Downloads**, since buyers may be downloading them.

The CLI checks your plan before uploading: no product downloads in the plan, a file over the plan's file size, or not
enough storage left stops it with the reason and how to upgrade.

## In CI

Run `releases create` only where real releases are made: a workflow for version tags, or your release task. Never in
the everyday build or in pull requests, since each run publishes a version buyers can download. The CLI signs in with a
[personal access token](/api/overview#personal-access-tokens) in the `SUNLICENSE_TOKEN` secret.

```yaml
# .github/workflows/release.yml
on:
  push:
    tags: ["v*"]
jobs:
  release:
    runs-on: ubuntu-latest
    steps:
      - uses: actions/checkout@v4
      - run: ./gradlew build
      - run: curl -fsSL https://sunlicense.com/install.sh | sh
      - run: sunlicense releases create build/libs/acme-${GITHUB_REF_NAME#v}.jar --product acme-editor --version ${GITHUB_REF_NAME#v} --notes @CHANGELOG.md
        env:
          SUNLICENSE_TOKEN: ${{ secrets.SUNLICENSE_TOKEN }}
```

Obfuscating too? Run `sunlicense obfuscate` first and upload its output, or pass `--obfuscate`.

## With an AI assistant (MCP)

* **`list_releases`**: a product's releases, their files and whether each carries the watermark.
* **`create_release`** in `sunlicense mcp` (the CLI's local server) takes the paths of your built files, reads them from
  disk and uploads them straight to SunLicense (never through the model), then publishes the release. It's marked
  destructive, and assistants that support it ask you before publishing; with `draft` it only uploads.
* **Connected apps** ([remote MCP](/guide/remote-mcp)) and **SunLicense AI** run on our side and can't read files from
  your computer. There, `create_release` creates a **draft** with the version and notes and returns the
  `sunlicense releases create` command that uploads your files into it and publishes it, plus a link to the
  **Downloads** tab to upload them by hand.

## The setup prompt

The product's **Setup** tab has a **Publish releases** part, off by default. Switch it on and the setup prompt adds a
release step to your project's release script or CI, after the build (and after obfuscation, when that part is on). The
part ticks once SunLicense sees the product's first release.

## Download watermark

The **Download watermark** part ticks as soon as you upload a release file (dashboard, CLI or API) that SunLicense can
see writes each buyer's details in: a `.jar`, `.zip`, `.mcpack`, `.mcaddon` or `.mrpack` whose code or text files carry
`%%__SUNLICENSE_KEY__%%` or `%%__SUNLICENSE_DOWNLOAD__%%` in a place SunLicense rewrites (see
[How the license gets into the file](/guide/downloads#how-the-license-gets-into-the-file)). It also ticks on the first
download that wrote a buyer's license in. `sunlicense releases list --json` shows `"watermark": true` for such files.
