Push a build

About 15 minutesComes with StudioWindows x64

A push cuts your playtest build into chunks, uploads only the chunks the project doesn't have yet, and registers the result as an immutable build. A branch is a named channel, such as main, qa or beta, that points at one build at a time; testers on a branch get its current build.

Where a push lands

A push registers the build in a workspace's project, which you make in the web app at app.mulno.com (who can have an account). The web app can't upload a build itself: its Builds & branches page shows the push command for the project and branch, and you run it on the machine that has the build, or push from Unity. The dry run needs no account and touches no bucket and no server.

1. Projects, builds, branches and campaigns

  • A project is a game. It holds its builds, branches and campaigns, and its storage: Mulno Cloud or your own bucket, chosen per project.
  • A build is immutable once pushed: a version, a build number, a platform (Windows x64 only for now) and its size.
  • A branch points at one build. Set live moves the pointer forward and Roll back moves it back to an older build, both on the web app's Builds & branches page. The history of what was live is kept. A member can push a build; an admin creates projects, branches and campaigns and sets a branch live, so --branch needs an admin.
  • A campaign is who may play the branch and what is recorded: invite codes, consent, limits, a time window and a kill switch. Several campaigns can share a branch. A branch's default campaign is named Share.

2. Ways to push

From Unity

Tools › Mulno Playtest › Push to Branch… opens a window. Build takes the build folder, platform, version and build number. Where takes the project id, the branch (leave it empty to leave the build unassigned), the workspace id and a Since revision for the change proposal. Storage takes the Api URL for Mulno Cloud, or an endpoint, bucket and region for your own bucket. Dry run chunks and reports; Push to <branch> uploads for real. The window runs the same mulno build push as below.

  • It finds mulno.exe through the MULNO_EXE environment variable, else in a Mulno source checkout. A game project has neither, so set MULNO_EXE to %LOCALAPPDATA%\Mulno Studio\mulno.exe before you start Unity.
  • There is no key field anywhere in the window. The process inherits Unity's environment, so MULNO_S3_ACCESS_KEY_ID, MULNO_S3_SECRET_ACCESS_KEY or MULNO_API_SESSION must be set before Unity starts.
  • The window doesn't open itself after a playtest build unless you turn on Open after a playtest build.

From the command line

mulno build push <BUILD_DIR> --project <ID>, with the options in the table below. It comes with Studio (mulno CLI), and it is the same command a build machine runs (a CI sample).

From Studio

Studio 0.4.1 has no push screen: its platform screens are switched off in the desktop app for now, and the web app has them. Studio installs mulno.exe, which is what the Unity window and a build machine run. A later Studio brings the same screens into the desktop app, with a dropped folder and a dry run first.

3. See what a push would send: a dry run

A dry run needs no account. It applies the skip rules, chunks the folder and prints what a push would send. Use it to see how big a build is and how it chunks.

PowerShell
& "$env:LOCALAPPDATA\Mulno Studio\mulno.exe" build push "D:\Builds\Castle\Playtest" `
    --project prj_4M2K9Q7X --dry-run --json

The report is a mulno.build-push-report/v1 JSON object. Read files, skipped, chunks_total, bytes_total (what the chunks take after compression) and change_entries. Folders named *_DoNotShip or *_ButDontShipItWithYourGame, session-* and MulnoSessions are skipped automatically, so a tester's recordings never ride along.

4. Keep updates small

Chunks are cut with FastCDC and named by their BLAKE3 hash, so a chunk the project already holds is never sent twice. In our measurements on real Unity builds, an update pushed 0.5 to 1.6 MB for a 371 MB game. Two Unity settings decide whether you see that:

  • Compression Method: Default, not LZ4 or LZ4HC. LZ4 recompresses the whole player, so bytes move and chunks stop matching. In our test a full download was bigger (136 MB against 127 MB), and one resized asset sent about 45 MB again.
  • Scripting Backend: Mono for a branch that ships often. IL2CPP's output changes with almost any code edit, so a daily build stays large. IL2CPP is fine for a branch that ships less often.

The Push window warns about both, and about an Output Directory that would land inside the build folder. It never blocks a push.

5. The options

OptionWhat it does
--project <ID>Required. The project to push to, such as prj_4M2K9Q7X.
--branch <NAME>Moves this branch live once the build is registered. Without it the build is left unassigned.
--version, --build-number, --platformYour game's own version string, a monotonic number, and a platform such as windows-x64.
--endpoint, --bucket, --regionPush straight into your own builds bucket. Keys come from MULNO_S3_ACCESS_KEY_ID and MULNO_S3_SECRET_ACCESS_KEY, never from the command line.
--api, --workspaceRegister the build with the Mulno api. Given alone, without a bucket, the chunks go through upload links the api signs: this is how a Mulno Cloud project is pushed. Needs MULNO_API_SESSION (below).
--key-usage <FILE>, --since <REV>Propose what changed: the git commits since a revision, mapped to Catalog keys through the file the Unity window exports.
--zipAlso build the branch's web zip, after the push. Needs --branch and --api, and an admin.
--dry-run, --json, -qChunk and report only; print the report as JSON; print nothing else.

There is no CI token yet

The api reads a signed-in browser session, and MULNO_API_SESSION is that session's raw cookie value. It works for a person who signed in and copied it; it isn't a credential a build machine should hold. A workspace-scoped token for build pipelines is not built. Pushing straight into your own bucket with your own key needs no cookie, but without --api the build isn't registered, so it can't be put on a branch.

6. What changed in this build

A change entry holds a note, the areas it touches (Catalog keys such as castle/boss_room, or castle/*), issue keys and commits. A push proposes them from the git commits since --since, using the Push window's Key usage export: which scene or prefab uses which Catalog key. Sessions then filter to a build's changed areas, and an agent can ask about exactly those keys. For a Private project the entries live in your bucket beside the build, not on our servers. mulno build push prints only the count of proposed entries today, not the entries.

7. Clean up a Private bucket

mulno build gc --project <ID> --endpoint … --bucket … --api … --workspace … lists the chunks in your builds bucket, asks the api which ones your registered builds still use, and deletes the rest that are older than --grace hours (24 by default). --dry-run only lists. A build is never deleted, so every chunk a registered build names stays. Cleaning up a Mulno Cloud project's chunks isn't built yet.