# Placeholders

A placeholder is the file your game uses until a request is fulfilled: a grey box where the lantern keeper will stand, a beep where the door creak will go, a labelled card where the potion icon will sit. Attach one to a request and everyone working on it sees what the real file has to fit. Every plan includes placeholders.

A placeholder isn't a reference. A reference is art to match; a placeholder shows the size, framing and timing the real file must fit, and makers are told not to copy it.

## Three ways to get one

- **Upload a file**: the stand-in you already use, of any kind agh previews.
- **Use the file at its path**: the file already at the request's path on the project's repository branch. agh copies it as it is.
- **Make a quick stand-in**: agh makes one in the format the request's path names, with no AI and nothing to pay for:

| Request | Stand-in | Formats |
| --- | --- | --- |
| Image | A dark hatched card at the spec's `size` (256×256 without one), labelled with the asset's id and size | PNG, JPEG, WebP, SVG |
| Audio | A soft beep at the start of every second, for the spec's `duration` (1 second without one) | WAV, Ogg Opus |
| Model | A plain grey box, sphere, capsule or cylinder of the width, depth and height you give in metres, with its origin at the base so it stands on the floor | .glb, .gltf, .obj |
| Text | One line naming the request and its brief | .txt, .md |

agh can't make stand-ins for other formats, such as `.fbx`, `.rbxm` or `.mp3`; upload a placeholder for those.

## From the command line

```sh
agh request ui.icon.potion --kind image --path ui/icons/potion.png --brief "Red health potion" \
  --spec size=128x128 --stand-in --save-placeholder
agh request char.npc.keeper --kind model --path characters/keeper.glb --brief "Lantern keeper" \
  --stand-in capsule --size 0.6x0.6x1.8 --save-placeholder
agh placeholder ui.banner.title ./banner_temp.png     # attach a file to an existing request
agh placeholder ui.banner.title --placeholder-from-repo
agh placeholder ui.banner.title --remove
agh get ui.icon.potion --which placeholder            # download it
```

`--save-placeholder` writes the placeholder at the request's path under the current folder, so the game can load it at once. A file already there is left alone. In a `--from` file, give an entry `placeholder: {source: stand-in, shape: capsule, size: 0.6x0.6x1.8}` or `placeholder: {source: repository}`.

## For coding agents

Over MCP, give a request in `request_assets` a `placeholder` (`{source: "stand-in"}`, with `shape` and `size` for a model, or `{source: "repository"}`). The result's `placeholders` holds a one-hour download link for each, so the agent can save the file at the request's path and keep coding; `placeholderProblems` says why one couldn't be made. `set_placeholder` attaches one later, or a file uploaded with `start_upload` (`placeholder: true`).

Over HTTP, `PUT /projects/{project}/assets/{id}/placeholder` takes `source` (`upload`, `repository` or `stand-in`), with `uploadId`, `fileName` and `contentType` from `POST .../placeholder/uploads` for an upload, or `shape` and `size` for a stand-in model. `DELETE` takes it off, and `GET .../file?which=placeholder` downloads it.

## In the web app

Admins and developers attach a placeholder from **Add placeholder…** on each request in **Approve**, or from the request's page in the **Library**. Open requests, claims, Library tiles and guest links show it with a dashed **Placeholder** badge, and review shows it beside the delivery in the place of the file it replaces.

## What happens to it

- Only admins, developers and agents attach, replace or remove one. Anyone who can see the request can download it, and so can a guest whose link reaches the request.
- agh never publishes a placeholder and never lists it in `.agh/provenance.yaml`.
- It counts toward the project's storage until a delivery is accepted. Then agh drops it, and it stops counting. A request that already has an accepted file doesn't take one.
- When storage is full, attaching one is refused like any upload; the request itself is still saved.
