Getting a file into Herald
Where the files live#
Herald keeps an app's animations in one folder per app, so every template of that app can use them. This section tells you where that folder is and what Herald puts in it, which matters when you copy a file in by hand or clean up.
~/Library/Application Support/Herald/assets/<app>/<asset id>.riv
<app> and <asset id> are each reduced to one safe path component:
- A character outside
A-Z a-z 0-9 . _ -becomes_and a short hash is appended, soa/banda_bstay different. - A leading dot cannot reach a parent folder.
- For ordinary ids such as
webwatcher.emailandbellthe folder and the file are exactly those names.
Two kinds of file live in an app's folder:
| Kind | Made by | Referenced with |
|---|---|---|
A copy of a file the app's manifest declares, named <asset id>.riv. | Herald, when the manifest is saved. | asset |
| A file you or an upload put there. | You, the Designer's Add... button, or an upload. | path with the file name |
Copies keep a banner playing after the issuing app moves or deletes its own files. Nothing else is cached on disk. Deleting a manifest removes the copies of the assets it declared and leaves the other files.
The folder holds at most 32 .riv files, whichever way they arrived.
Getting a file into Herald#
There are four ways to store an animation. Pick the one that matches who owns the file: an app ships its animation in its manifest, a person uses the Designer, and an agent or script uploads. All of them end with the file in the app's folder.
| Way | Best for | Referenced with |
|---|---|---|
| Upload | Agents, scripts and the CLI. | path with the file name |
| Manifest asset | An app that ships its own animation. | asset with the asset id |
| Designer | Someone designing a template by hand. | asset or path, chosen for you |
| Copy by hand | Quick experiments. | path with the file name |
Upload from a script or an agent#
Uploading copies a .riv file into the app's folder and returns the component to use. Send the path of a file on
this Mac, or the file's bytes encoded as base64 (the request body is limited to 1 MB, so use a path for anything
larger). Herald checks the name, the size and the 32-file limit, and it replaces a file of the same name.
herald assets add --app example.bidbot --file ~/Animations/bell.riv
{"ok": true, "kind": "rive", "app": "example.bidbot", "id": "bell", "file": "bell.riv",
"path": "/Users/you/Library/Application Support/Herald/assets/example.bidbot/bell.riv",
"bytes": 18432, "replaced": false, "component": {"type": "rive", "path": "bell.riv"}}
The component value in the reply is ready to paste into a template cell. Storing and managing files has one
command, route and tool for each job:
| Job | CLI | HTTP | MCP tool |
|---|---|---|---|
| Store a file. | herald assets add | POST /v1/assets | upload_asset |
| List the stored files, the templates that use each and whether the manifest declares it. | herald assets list -- | GET /v1/assets | list_assets |
| Remove a file. The reply names the templates that still reference it. | herald assets rm -- | DELETE /v1/assets | delete_asset |
Declare it in the manifest#
An app that ships its own animation lists it in its manifest as an asset. Herald copies each asset
into the app's folder as <asset id>.riv when the manifest is saved, and templates refer to it by id. One bad asset
is reported and never blocks the manifest: the banner shows the reason where the animation would be.
{"app": "example.bidbot", "appName": "BidBot", "version": 1,
"fields": [{"key": "title", "type": "text", "sample": "Bid accepted"},
{"key": "count", "type": "number", "sample": 2},
{"key": "url", "type": "url"}],
"assets": [{"id": "bell", "type": "rive", "path": "~/Animations/bell.riv",
"stateMachine": "Main", "inputs": ["count", "hover"]}]}
curl -s -X PUT "$HERALD/v1/manifest" \
-H "Authorization: Bearer $TOKEN" -H "Content-Type: application/json" \
--data @manifest.json
This is PUT /v1/manifest, also available as the MCP tool
put_manifest. An asset has these rules:
| Part | Rule |
|---|---|
id | Letters, digits, _, . and -, unique in the manifest. A component's asset names it. |
type | Must be rive. Any other value is refused with asset type "x" is not supported (only rive). |
path | An absolute path, a ~/ path, a file:// URL, or a name relative to the app's folder. At most 2048 bytes. A remote URL is refused. |
stateMachine | Optional. The state machine a component plays when it names none. |
inputs | Optional. The input names the file has. The validator warns when a component binds a name that is not listed. |
Saving the manifest again refreshes the copy only when the file's content changed. If the source file later disappears, the earlier valid copy keeps playing.
Add it in the Designer#
In the Designer, the Assets palette lists the app's .riv files, each with a live preview.
- Add... opens a file panel and copies the chosen file into the app's folder, taking the id from the file name and making it unique.
- Remove... deletes a file after asking you to confirm.
- Drag a file onto the canvas, or click it, to place a
rivecomponent in the selected slot.
A file the manifest declares is placed by asset, with its state machine. A file you added is placed by path, with its file name.
Select a rive cell to open its inspector, which has these controls:
| Control | What it sets |
|---|---|
| Asset | A manifest asset, or A file... to name a file. |
| File | The path, with a menu of the stored files. Shown for A file.... |
| Summary line | What the Rive runtime read: artboards, state machines and inputs with their kinds. |
| Artboard and state machine pickers | artboard and stateMachine. The first choice is the file's default. |
| Inputs | inputBindings, with the file's inputs suggested and hover and pressed offered. |
| Loop | loop: Loop, Once or Animation's own. |
| Ratio | aspectRatio. The placeholder shows the artboard's own ratio. |
| Height | height. |
| Action | The click action: none, one from the list, or one of its own. |
Import... and Export... at the top of the Designer move a template with its animations as a bundle.
Copy it by hand#
Copy the file into ~/Library/Application Support/Herald/assets/<app>/ and reference it with a relative path:
{"type": "rive", "path": "spinner.riv", "height": 24}