# Package Spec <Badge type="warning" text="Not yet released" />

The rules a Mini App package must meet for Micromeet to sign it and Cowork to open it: what each rule is, who checks it, and what happens when it is not met. How to make the package is in [Build and Sign](https://docs.micromeet.ai/miniapp-sdk/build.md); `micromeet-miniapp verify` runs these checks on your computer first. This page is about the signed Mini App package, not the Cowork packages of the [Package](https://docs.micromeet.ai/miniapp-sdk/package.md) module.

| Checked by | When |
|---|---|
| **Tool** | `micromeet-miniapp` (`pack`, `verify`, `zip`) and the Vite plugin, on your computer |
| **Micromeet** | When Micromeet registers and signs a version |
| **Install** | When Cowork installs the package |
| **Open** | Every time Cowork opens the Mini App, and every time the page reads a file |

## Files

```text
ai.example.app-1.0.0.zip
  manifest.json
  app.asar
  app.asar.unpacked/    optional: large media
  INSTALL.md            optional: steps for the agent that installs it
```

| Rule | Checked by | If not met |
|---|---|---|
| The four entries sit at the root of the zip (or folder); Cowork keeps only these | Install | Anything else is not installed |
| Zip: at most 100,000 entries and 8 GB unpacked; no encryption, absolute path, `..`, backslash or symbolic link | Tool, Install | Not installed |
| No file or folder named `.DS_Store`, `__MACOSX`, `.git` or `node_modules` | Tool | `pack` leaves them out; `verify` refuses one in `app.asar.unpacked/` |

## manifest.json

| Field | Rule | Checked by | If not met |
|---|---|---|---|
| `appId` | The AppID Micromeet registered: lower-case reverse domain such as `ai.example.app`, at most 128 characters | Tool, Micromeet, Install | Refused |
| `name` | A string, or `{ zh, en }` with at least one of them; 1–60 characters. Not signed: the sign-in card shows the name Micromeet registered | Tool, Install | Refused |
| `version` | Starts with a letter or digit; letters, digits, `.`, `+`, `-`; at most 32 | Tool, Micromeet | Refused |
| `version_code` | A string of 12 digits, the build time `YYMMDDHHmmss` | Tool, Install | Refused |
| `entry` | A file packed inside `app.asar`, not unpacked; relative path, at most 256 characters, no `..`, backslash or control character. Default `index.html` | Tool, Micromeet, Install | Refused |
| `asar` | The archive's file name: letters, digits, `.`, `_`, `-`, ending in `.asar`. Default `app.asar` | Tool, Install | Refused |
| `domains` | Optional; only for a Mini App that signs people in with Micromeet ([Server domains](https://docs.micromeet.ai/miniapp-sdk/build.md#server-domains)). `https://host[:port]` written lower-case, no path or IP address; or `http(s)://localhost[:port]` / `127.0.0.1[:port]`. No duplicate, at most 20 | Tool, Micromeet, Install | Refused. Micromeet registers a version only when each of its domains is verified for the AppID |
| `asarHeaderSha256` | SHA-256 of `app.asar`'s first 8 + header-size bytes; written by the tools | Tool, Micromeet, Open | Not signed: Cowork does not open it |
| `signature` | `{ kid, alg: "Ed25519", value }`, written from Micromeet's answer | Tool, Open | Not signed: Cowork does not open it |
| `extension` | Not allowed in a signed package | Tool, Install | Refused |

## app.asar

| Rule | Checked by | If not met |
|---|---|---|
| Made by `@electron/asar` 3.x; the header exactly as it writes it, at most 64 MB | Tool, Micromeet, Install | Refused |
| Every file, packed or unpacked, has `integrity`: SHA-256 in 4 MB blocks | Tool, Micromeet, Open | Refused; Cowork treats it as not signed |
| No symbolic link, inside `app.asar` or in `app.asar.unpacked/` | Tool, Micromeet, Install | Refused |
| File and folder names are not empty, `.` or `..`, and hold no `/`, backslash or NUL | Tool, Micromeet | Refused |
| `app.asar` at most 512 MB; put video and audio in `app.asar.unpacked/` | Tool, Micromeet | Refused |
| `app.asar.unpacked/` at most 100,000 files and 8 GB; each file is the size its header records | Tool, Install | Refused |
| Every file's bytes match its digest | Tool, Micromeet, Open | Micromeet refuses to sign; Cowork closes the Mini App and says its files were changed |
| No inline `<script>` in HTML: pages are served with the content policy `script-src 'self'` | Tool (`pack`) | Refused by `pack`; in the browser the script would not run |

Cowork serves the files from `miniapp://<appId>/`, so absolute paths such as `/assets/app.js` work. Requests to other services are not limited.

## Signature

Micromeet signs these bytes with Ed25519. `domains` are sorted and joined by one space; the last line is empty without them. `name` and icons are not signed.

```text
miniapp-sig-v2
<appId>
<version>
<entry>
<asarHeaderSha256>
<domains>
```

Versions registered before 2026-11-10 carry `miniapp-sig-v1` (the first five lines, no domains) and stay valid for a manifest without `domains`.

| Cowork | Treats as signed |
|---|---|
| Released Cowork | `cowork-prod-1`: versions signed by Micromeet production |
| Cowork Preview | `cowork-preview-1` |
| A development run (not packaged) | Its own key, `cowork-preview-1` and `cowork-test-1` |

## Versions and delivery

| Rule | Checked by | If not met |
|---|---|---|
| A version is registered once: change `version` for every build you hand over | Micromeet | Refused |
| Changing any file, `entry` or `domains` needs a new version and signature | Open | Not signed: Cowork does not open it |
| Installed on its own from the zip or folder (`miniapp_install`): each `version_code` in its own folder, the older one removed when its tabs close | Install | — |
| Or inside a Cowork package, copied or linked; a copied package holds at most 2,000 files and 50 MB, `app.asar` included | Install | The package is refused |

## When Cowork opens it

- Not signed, signed with a key this Cowork does not trust, or unreadable: Cowork does not open it and tells the person the Mini App is not certified.
- A file that differs from its digest when the page reads it: Cowork closes the Mini App and says its files were changed.
- Each Cowork account keeps its own storage for the Mini App; one person never sees another's.
- The page stays on `miniapp://<appId>/`; `http(s)` links open in the system browser.
- Signing a person in also needs the AppID and version active on Micromeet and at least one verified server domain in `domains` (see [Sign-in](https://docs.micromeet.ai/miniapp-sdk/auth.md)).

## Related

- [Build and Sign](https://docs.micromeet.ai/miniapp-sdk/build.md): Make the package and have Micromeet sign it
- [Sign-in](https://docs.micromeet.ai/miniapp-sdk/auth.md): Sign a person in from the Mini App
- [Overview](https://docs.micromeet.ai/miniapp-sdk/overview.md): All modules of the Mini App SDK
