Chataway Developers
Concepts

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:

json
"files": {
  "images": { "accept": ["image/*"], "prepare": { "op": "resize", "width": 512, "height": 512, "fit": "cover", "format": "png" } }
}

From your panel, on a file the user picked:

ts
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

ParamType
widthinteger 1–8192Target width
heightinteger 1–8192Target height
fitcover · contain · fillcover crops to fill, contain letterboxes inside the box (transparent for PNG/WebP), fill stretches
formatsee belowOutput format (default: keep)

At least one of width / height. With only one, the other follows the aspect ratio.

json
{ "op": "resize", "width": 1024, "fit": "contain", "format": "webp" }

#crop

ParamType
x, yinteger 0–16384Top-left of the box
width, heightinteger 1–8192Box size
aspect"W:H", e.g. "1:1", "9:16"Crop to an aspect ratio instead of a box
gravitycenter · north · south · east · westWhich part to keep with aspect (default center)

Either width + height (with x/y), or aspect. Works on images and videos.

#convert

ParamType
formatpng jpg webp avif gif mp4 webm mp3 wavRequired
qualityinteger 1–100For lossy formats

Image → image, video → video, audio → audio, and video → gif.

#compress

ParamType
qualityinteger 1–100Re-encode at this quality
targetKbinteger 10–50000Aim for this size; quality is chosen for you

One of the two is required. Keeps the format.

#trim

ParamType
startseconds, 0–600Start of the kept part
endseconds, 0–600End of the kept part (after start)

At least one of start / end. Video and audio.

#frame

ParamType
atseconds, 0–600Which moment
formatpng · jpg · webpOutput (default png)

Video → image.

#extract_audio

ParamType
formatmp3 · wavOutput 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:

ts
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:

ts
const { info } = await app.host.media('probe', clip.ref);
// info = { width: 1920, height: 1080, duration: 12.4, codecs: ['h264', 'aac'] }

#Limits

Media length10 minutes (times are 0–600 s)
Dimensions8192 px on either side (8K)
Concurrent jobs2 per app; more are queued
QueueShared 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.