Host services
Fixed, validated media operations Chataway runs with its own code on files your app was handed — every op, its parameters and limits, and why there's no raw ffmpeg.
Lots of apps need the same few things done to a file before it's useful: resize an image, convert a format, trim a clip, grab a frame. Chataway does these on the user's Mac, with its own code, on files your app was handed. You describe what you want; Chataway builds and runs every command.
Host services need the host:media grant.
#Why not just run ffmpeg?
Because then every app would be running arbitrary command lines on the user's computer. ffmpeg and image libraries take hundreds of options, some of which read or write arbitrary files, open network connections or run filters with their own mini-languages. A single "pass these arguments through" feature would undo the whole trust model.
So there are no arguments to pass through. Each operation has a small set of typed parameters, they're checked against a schema, and Chataway's own code turns them into a safe invocation. Results are new files — the source is never modified.
#Where you can use them
Declaratively, on a tool's file param — the common case:
"files": {
"images": { "accept": ["image/*"], "prepare": { "op": "resize", "width": 512, "height": 512, "fit": "cover", "format": "png" } }
}From your panel, on a file the user picked:
const [photo] = await app.pickFiles({ accept: ['image/*'] });
const square = await app.host.media('crop', photo.ref, { aspect: '1:1', gravity: 'center' });
// square = { ref, url } — show it with <img src={square.url}>, or get the bytes:
const bytes = await (await fetch(square.url)).blob();#Operations
Available operations:
resize · crop · convert · compress · trim · frame · extract_audio · concat · probe
#resize
| Param | Type | |
|---|---|---|
width | integer 1–8192 | Target width |
height | integer 1–8192 | Target height |
fit | cover · contain · fill | cover crops to fill, contain letterboxes inside the box (transparent for PNG/WebP), fill stretches |
format | see below | Output format (default: keep) |
At least one of width / height. With only one, the other follows the aspect ratio.
{ "op": "resize", "width": 1024, "fit": "contain", "format": "webp" }#crop
| Param | Type | |
|---|---|---|
x, y | integer 0–16384 | Top-left of the box |
width, height | integer 1–8192 | Box size |
aspect | "W:H", e.g. "1:1", "9:16" | Crop to an aspect ratio instead of a box |
gravity | center · north · south · east · west | Which part to keep with aspect (default center) |
Either width + height (with x/y), or aspect. Works on images and videos.
#convert
| Param | Type | |
|---|---|---|
format | png jpg webp avif gif mp4 webm mp3 wav | Required |
quality | integer 1–100 | For lossy formats |
Image → image, video → video, audio → audio, and video → gif.
#compress
| Param | Type | |
|---|---|---|
quality | integer 1–100 | Re-encode at this quality |
targetKb | integer 10–50000 | Aim for this size; quality is chosen for you |
One of the two is required. Keeps the format.
#trim
| Param | Type | |
|---|---|---|
start | seconds, 0–600 | Start of the kept part |
end | seconds, 0–600 | End of the kept part (after start) |
At least one of start / end. Video and audio.
#frame
| Param | Type | |
|---|---|---|
at | seconds, 0–600 | Which moment |
format | png · jpg · webp | Output (default png) |
Video → image.
#extract_audio
| Param | Type | |
|---|---|---|
format | mp3 · wav | Output format |
Video → audio.
#concat
Joins several files of the same kind (all video or all audio) in order. In the panel, pass the other refs as refs:
await app.host.media('concat', intro.ref, { refs: [main.ref, outro.ref] });Not available as prepare (a tool param's files are processed one by one).
#probe
Reads a file's facts without changing it:
const { info } = await app.host.media('probe', clip.ref);
// info = { width: 1920, height: 1080, duration: 12.4, codecs: ['h264', 'aac'] }#Limits
| Media length | 10 minutes (times are 0–600 s) |
| Dimensions | 8192 px on either side (8K) |
| Concurrent jobs | 2 per app; more are queued |
| Queue | Shared with Chataway's own media jobs, with progress shown to the user |
A job that fails (unsupported codec, corrupt file, over a limit) fails the tool call with a clear error for the agent, or rejects the host.media promise in your panel.
#Validation errors
A bad prepare in your manifest fails validation with a media.* code — for example media.resize (resize needs width and/or height) or media.time (start must be 0..600 seconds). The full list is in the manifest reference.
#Need something else?
If your app needs an operation that isn't here, tell us at the developer dashboard — new operations are added when several apps need them. Until then, do the work on your server: receive the file and process it there.