Publish community firmware

List firmware you wrote for a music device on Maru: what to prepare, how to publish a listing, and how to keep it accurate.

The Maru framework lets you describe firmware or an on-device app for a piece of music hardware in a small project folder, and publish it as a listing in the firmware catalog. People find it, read your instructions and go to your release files. You keep your source and your files, and the listing points to them.

In the Help Center: Controllers, pedals and hardware for more on controllers and devices.

Prepare your release

Before adding a binary release, gather these in your repository and README. People will rely on them when deciding whether to risk their device.

  • Hardware: the exact product and board revision, what you tested on, and what you know doesn't work. A shared chip doesn't mean shared compatibility.
  • Files: a permanent HTTPS link, size and SHA-256 for each file. Say which is the application, loader, data or recovery file.
  • Rights: your licence, where the source is, and permission to distribute anything you didn't write.
  • Installing: the tool and operating systems you support, what mode the device needs, and how to confirm it worked.
  • Data: what gets erased, how to back up and restore, and whether going back to an older version keeps user data.
  • Recovery: how to get the device back after a failed update, including back to the maker's firmware. Write this for your firmware. Don't copy another project's key combination.
  • Testing: what you tested on a physical unit, and what you only tried in an emulator.

Start without a binary

Use a new or empty directory and an exact device ID from the hardware directory:

bash
maru init my-firmware --kind firmware --device fm-1
cd my-firmware

This creates only maru.config.json and README.md. It does not install dependencies, choose a toolchain or overwrite existing work. The starter uses kind: "source-release" and omits release, binaries, checksums and tested revisions. Selecting fm-1 declares which device the project concerns; it does not establish compatibility.

Replace the summary and complete the README before publishing. Keep your existing source repository and build tools. Publication snapshots the README and metadata, not your source tree. Installation and recovery can remain explicitly unknown for a source-only project.

Create the listing

A listing needs two files in one folder: maru.config.json and README.md. Your account also needs a public profile handle. A source-only listing can be this small:

json
{
  "type": "firmware",
  "slug": "your-device-your-firmware",
  "name": "Your Firmware",
  "summary": "What this firmware lets a musician do.",
  "kind": "source-release",
  "devices": [{ "deviceId": "fm-1", "supportLevel": "author-declared" }],
  "repositoryUrl": "https://github.com/your-account/your-firmware",
  "licenseSpdx": "MIT"
}

Use kind to say what it is: firmware, on-device-app, controller-app, editor, daw-integration, source-release or sound-content. Only list a revision and licence you actually support.

deviceId must be the canonical ID of a device already in the hardware directory, not its display name, URL, chip family or an alias. The dry run checks it with the service; an alias rejection names the canonical ID to use. If the directory does not make the ID clear, contact us with the device page, maker, model and revision. Hardware submission is handled through review; this firmware command does not create hardware records. For an unlisted device, ask for that review before publishing.

Slugs are unique across the whole catalog, not per author. You can't take a slug that's in use, and firmware Maru already lists can't be replaced by publishing over it. If an existing listing describes your work and you want it corrected, ask us and name the listing.

To add downloadable files, add a release object to the manifest. This example shows the field names and types, not a real installable release:

json
{
  "release": {
    "version": "1.0.0",
    "assets": [
      {
        "name": "your-firmware-1.0.0.bin",
        "url": "https://example.com/your-firmware-1.0.0.bin",
        "bytes": 524288,
        "sha256": "0123456789abcdef0123456789abcdef0123456789abcdef0123456789abcdef"
      }
    ],
    "installation": {
      "protocol": "external-tool",
      "instructions": "What to run, on which systems, and how to confirm it worked.",
      "recoveryInstructions": "How to get the device back if the update fails."
    }
  }
}

Replace the example URL, byte count and digest with facts from your actual immutable file. The digest must contain exactly 64 lowercase hexadecimal characters; do not publish this example value. Record the exact source tag/commit, tested revisions and required starting firmware/loader in your README and, where applicable, devices[].revision and devices[].requiredStockVersion.

protocol is one of midi-sysex, usb-dfu, usb-hid, usb-vendor, serial, mass-storage or external-tool. It describes your procedure for readers. A source-only listing can leave release out, so don't add placeholder hashes.

The README should explain features, pinned build tools and commands, source and licensing, exact compatible and excluded hardware, installation prerequisites, backup/data loss, post-install identity checks and recovery. Distinguish physical tests from emulator or protocol tests; label anything unknown.

In your README, raw HTML doesn't run, external images aren't shown and relative files aren't fetched, so keep it to text and links.

Publish

From the folder:

bash
maru login
maru publish . --dry-run
maru publish .

The dry run contacts the service and requires login, just like publishing; it validates without saving. Your account needs publishing access and a public profile handle. Publishing prints the listing's page. Add --json to see the listing version.

The CLI first reads the local files and validates their shape. There is no offline firmware dry-run command: passing those local checks alone does not mean the service accepted the metadata. A successful remote dry run does not reserve a slug or listing version, so a later publish can still conflict. Neither result uploads or checks the release bytes, proves physical compatibility or admits a browser or desktop installer. Declaring a protocol describes your procedure; installer availability is decided separately for the exact device, revision, release and supported transport.

Resolve a rejected publication

Use --json for structured results and errors. Local validation names invalid field paths; remote refusals retain the service message. Keep that message when asking for help, along with the slug and command, without credentials.

Message or stateNext step
Not signed in, rejected credentials or missing publishing scopeRun maru login again with publishing access, then retry. Status and withdrawal also need modules:publish.
public_handle_requiredSet a public handle in your Maru profile, then retry with the same account.
Hardware not publicly listed or canonical ID requiredUse the canonical hardware ID named by the service, or request hardware review as described above.
Invalid JSON, manifest fields or READMEFix the named file or field. Both files must be regular files of at most 65,536 UTF-8 bytes; README must contain text. Unknown manifest fields are rejected. Use HTTPS URLs, a valid slug and actual release facts.
Slug already owned, firmware_owner_required or curated record conflictSign in as the owner for a correction. Choose an unused slug for a different project; ask for review of an existing curated listing instead of replacing it.
firmware_expected_version_required or firmware_version_conflictRun maru firmware-status my-firmware --json, review the current content and retry with its listing version. Do not blindly increase the number.
firmware_release_immutable or firmware_release_already_existsPreserve the old release facts and use a new release.version for changed release content.
firmware_moderated, hidden or lockedInspect status and contact us about moderation. Locked listings can remain readable; hidden listings are unavailable publicly. Publishing a correction does not override either restriction.
firmware_not_listed or withdrawnInspect status. Withdrawal is terminal; publishing again does not restore it. Ask for help if the state is unexpected.
firmware_publication_not_foundCheck the slug and signed-in account. Status intentionally does not distinguish another person's listing from a missing one.

If malformed JSON prevents automatic firmware detection, use maru publish . --kind firmware --dry-run to get the firmware file diagnostic.

Inspect and correct a listing

On your firmware page, sign in as its current owner and choose Manage publication from the action menu. It shows the listing version, publication status, moderation and public visibility, with a CLI command for publishing a correction. Other readers do not get this owner action.

You can also read your current publication from the CLI before editing it:

bash
maru firmware-status my-firmware --json

The result includes its publication state, listing version and content digest. Edit the same project folder and pass the version you just read as a concurrency guard:

bash
maru publish . --expected-version 1 --dry-run
maru publish . --expected-version 1

Replace 1 with the current listing version. A stale guard refuses the write; inspect again and review the newer content before retrying. Repeating identical content changes nothing, but an explicitly supplied version still must match.

The listing version is separate from release.version. You can correct the name, summary or README, but an existing firmware release's files, instructions, targets and prerequisites are immutable. Publish a new release version when those facts change; do not reuse a version with different contents.

For a new release, change release.version and fill in that release's actual assets, installation and recovery facts. Keep the same listing slug. Read status again and run the same guarded dry-run and publish commands above with the current listing version. A new listing version records the publication; it is not a firmware version.

Withdraw a listing

Withdrawal removes the listing from public reads and is terminal for that firmware identity: publishing it again is refused. On the website, open Manage publication, type the listing slug in Unpublish listing, then choose Unpublish firmware. After you leave the unpublished page, use maru firmware-status to inspect its current state; publication history is preserved.

For CLI withdrawal, inspect its current version first, then preview and apply the guarded request:

bash
maru unpublish my-firmware --kind firmware --expected-version 1 --dry-run
maru unpublish my-firmware --kind firmware --expected-version 1

With --kind firmware, the bare slug selects your remote listing; you do not need the original folder. Use ./my-folder to select a local project instead. Replace 1 with the current listing version. Repeating the same withdrawal guard reports already-withdrawn; a stale guard conflicts. Owner status and withdrawal require login with publishing access (modules:publish). A missing listing and a listing you do not own both report not found.

What a listing tells people

Your compatibility claims appear as declared by the author, and your hashes are your own statement. A listing isn't a test on a device, so give readers what they need to judge the risk themselves.

Read the hardware listing and takedown policy for what Maru lists and how to ask for a correction or removal. To build your own instrument for a device with Maru rather than list independent firmware, start with hardware platforms.