# Free game hosting with the Rosebud CLI

Put a browser game online for free and get a link anyone can play. The Rosebud CLI uploads your build, and updates go to the same link.

You don't need an account to publish. To keep a game, sign in and claim it within an hour of uploading.

Using a coding agent? Give it [AGENTS.md](AGENTS.md). It has the same steps written as instructions for the agent.

## Quickstart

You need Node.js 22 or later.

**1. Install the CLI.**

```sh
npm install --global @rosebudai/cli
```

To run it without installing, use `npx @rosebudai/cli` in place of `rosebud` in the commands below, for example `npx @rosebudai/cli publish --directory ./dist`.

**2. Build your game, then publish the build folder** from your project's root:

```sh
rosebud publish --directory ./dist --title 'Moon Garden' --description 'Collect five glowing seeds.'
```

The title and description are optional, and they appear on the game's play page. Already have a ZIP? Use `--zip ./game.zip` instead of `--directory`.

No build step? Copy the files your game needs (`index.html` and everything it loads) into a folder such as `./dist` and publish that. Don't publish the project root: the CLI keeps its state in `.rosebud/` there, and hidden files such as `.gitignore` can't be uploaded.

**3. Play it.** Open the `play_url` from the result and play the game. A successful upload means the files were accepted, not that the game works.

**4. Claim it within an hour.** Open the `claim_url`, sign in and select **Claim game**, or the game is deleted.

The CLI saves the game's details in `.rosebud/project.json`, so later commands know which game to update. Add `.rosebud/` to `.gitignore`.

## Claim your game

A new upload is playable right away, but it's temporary until someone claims it. The result's `claim_expires_at` is the deadline, one hour after upload.

- **Claimed in time:** the game moves into your Rosebud account, keeps its link and opens in the Rosebud editor. It no longer expires.
- **Not claimed:** at the deadline the game, its files and its links stop working, and the game is permanently deleted. There's no late claim.

Keep the claim link private. Anyone who has it can claim the game.

If a game expires, publish the same build again as a new game. Use a new state file so the CLI doesn't confuse it with the deleted one:

```sh
rosebud publish --directory ./dist --state .rosebud/new-project.json --title 'Moon Garden'
```

The new game gets a new link. Pass the same `--state` to later commands for it.

## Publish updates

To update a game from the CLI, connect it to your account once:

```sh
rosebud connect
```

This prints a private `approval_url`. Open it, sign in and approve. If the game isn't claimed yet, approving also claims it. The link expires after 30 minutes; run `rosebud connect` again for a new one.

After approval, publish new builds to the same link:

```sh
rosebud status
rosebud update --directory ./dist
```

- `status` shows whether access is active and which version of the game is live.
- Titles, descriptions and covers you don't pass to `update` stay as they are.
- If the game was changed on Rosebud after your last update, `update` stops instead of overwriting. Bring those changes into your local project, then run `rosebud update --directory ./dist --expected-version <version from status>`.
- If an update is interrupted, run the same command again. It won't publish twice.

Access lasts 90 days and covers only this game: its files, title, description and cover. It can't reach your other games, your account or billing, or run AI generation. Revoke it any time in the editor under **Project Settings → Manage connected agents**, or run `rosebud disconnect`.

On another computer, run `rosebud connect --project <project_id>` and approve again.

## What you can upload

- `index.html` at the top level of the build folder.
- HTML, JavaScript, CSS and JSON files, anywhere in the build.
- UTF-8 plain-text notices: `.txt` files (including `.TXT`) and extensionless `LICENSE`, `LICENCE`, `NOTICE`, `COPYING`, `COPYRIGHT` and `AUTHORS`. Keep their original names, case and contents; text files do not follow the media naming rules. Do not remove required notices to make an upload pass.
- Media inside `assets/`, with lowercase names using letters, numbers, underscores and single hyphens; start and end each name with a letter or number, and use dots only for file extensions: PNG, JPEG, WebP and SVG images; MP3, WAV and OGG audio; WOFF, WOFF2, TTF and OTF fonts; WASM; GLB and glTF models with their `.bin` buffers.
- Up to 10 MiB zipped, 50 MiB unzipped, and 500 entries, including folders.

Rosebud serves your files as they are and doesn't run a build. Hidden files, symbolic links, dependency folders and unsupported file types are rejected. Everything you upload is public, so keep credentials and `.env` files out of the build.

Hosted games are unlisted: anyone with the link can play, but they don't appear in Rosebud's game listings.

## Game details

All of these are optional, for both `publish` and `update`:

| Option          | Details                                                                  |
| --------------- | ------------------------------------------------------------------------ |
| `--title`       | Up to 255 characters. Changing it later keeps the same play link.        |
| `--description` | Up to 4,000 characters.                                                  |
| `--thumbnail`   | A PNG or JPEG gameplay screenshot, at most 2 MiB and 4096 pixels a side. |

Agents can also pass `--agent-client` (`claude-code`, `codex`, `cursor`, `gemini-cli` or `other`) to say which tool published the game.

## Command reference

| Command                              | What it does                                                       |
| ------------------------------------ | ------------------------------------------------------------------ |
| `rosebud publish --directory ./dist` | Creates a new game from a build folder and saves its details.      |
| `rosebud connect`                    | Prints a private link that lets you approve updates from this CLI. |
| `rosebud connect --project <id>`     | Connects to an existing game, for example from another computer.   |
| `rosebud status`                     | Shows whether access is pending, active, revoked or expired.       |
| `rosebud update --directory ./dist`  | Replaces the game's files and publishes them to the same link.     |
| `rosebud disconnect`                 | Revokes this CLI's access. The game stays online.                  |
| `rosebud --help`                     | Lists commands and options.                                        |

Every upload takes exactly one of `--directory` or `--zip`. Other options:

- `--state <file>`: where the game's details are saved. The default is `.rosebud/project.json`.
- `--timeout-ms <ms>`: how long to wait for Rosebud. The default is 120000.

Credentials are stored separately in `~/.config/rosebud/credentials` with private file permissions. Set `ROSEBUD_CREDENTIALS_DIR` to use another folder.

## Troubleshooting

Commands print JSON (except `--help` and `--version`): results on stdout, errors on stderr. Errors include a `code` and a `message` that says what to fix. When Rosebud rejects a specific file, `filename` names it.

| Exit code | Meaning                                                                             |
| --------- | ----------------------------------------------------------------------------------- |
| 0         | Success.                                                                            |
| 2         | The command or build has a problem. Fix it and run the command again.               |
| 3         | Rosebud rejected the request. Read `error.code` and `error.message`.                |
| 4         | The result is unknown, for example after a dropped connection. See the notes below. |

- After an unknown `publish` result, the game may already exist. Don't publish again right away; a new publish creates a second game.
- After an unknown `update` result, run the same command again.
- `state_in_build` or a hidden-file `unsafe_path` error means you published the project root. Publish the build folder, or a copy of the game in `./dist`.
- Media errors (`media_path`, `noncanonical_path`) usually come from bundler output. Vite, for example, adds mixed-case hashes to image names. Keep media names lowercase and inside `assets/`.
- The CLI locks its state file while it runs. If a command crashed, make sure it has stopped before deleting the `.lock` file next to the state file.

The [HTTP reference](http-reference.md) lists every error code.

## HTTP reference

The CLI calls a small HTTP API. The [HTTP reference](http-reference.md) documents its endpoints, fields, errors and retry rules.

## Coming soon

We're working on an in-game SDK for gameplay events and error reports, and dashboards for sessions and returning players. We're also exploring ways to earn from hosted games. None of these are available yet, and hosting doesn't need an SDK in your game.

## Source and releases

The CLI is open source under Apache-2.0.

- Source code and issues: [rosebudai/rosebud-cli](https://github.com/rosebudai/rosebud-cli) on GitHub.
- Package: [@rosebudai/cli](https://www.npmjs.com/package/@rosebudai/cli) on npm. Each release is built by GitHub Actions and published with npm provenance, which links it to the source it was built from.
- Changes: the [changelog](https://github.com/rosebudai/rosebud-cli/blob/main/CHANGELOG.md).
- Security problems: report them privately through the repository's [Security tab](https://github.com/rosebudai/rosebud-cli/security), not in a public issue.

The [starter ZIP](source.zip) has these guides and a sample game to try publishing with.
