Services
A service is background JavaScript that runs commands on demand. and your own UI call into it for work that should not block the interface.
Declare a service
service names the runtime, the entry file, when it starts, and every command it exposes. It needs process.invoke, and your UI calls it through atlas.process.invoke. runtime is atlas-js; start is on-demand or app-start.
"service": {
"runtime": "atlas-js", "entry": "service.js", "start": "on-demand",
"commands": [{ "id": "render-preview", "title": "Render preview", "timeoutMs": 15000 }]
}A command that is not declared here throws when invoked, even if your module exports a handler for it. timeoutMs is per call and defaults to 30000 when omitted.
The module shape
Export a commands object keyed by command id. Atlas falls back to a single invoke(command, payload, context) export when commands has no matching entry, so you can use either style.
export const commands = {
"render-preview": async (payload, context) => { /* … */ }
};
// optional fallback for anything not in commands
export async function invoke(command, payload, context) { /* … */ }context is { pluginId, manifest, command }. Your return value must be JSON-serialisable — it crosses a boundary back to the host.
What a format provider handler receives
When your service backs a format provider, the payload carries the job's paths, the item row, and the file's own contents.
sourcePath / srcAbsolute path of the file being indexed. Both keys carry the same value.destPath / destWhere Atlas will write what you return. Do not write it yourself.previewDestPathPreview output path for this job.metadataDestPathMetadata output path for this job.itemThe item row: id, projectId, folderPath, fullPath, filename, extension, mediaKind, providerId, sourceModifiedAt.providerid, pluginId, and formatId of the provider this job belongs to.sourceTextThe file decoded as UTF-8. Absent when the file is over the inline limit or could not be read.sourceBytesBase64The same bytes as base64, for binary formats. Absent under the same conditions.sourceSizeBytesThe file's size on disk. Present even when the contents are not.sourcePayloadTruncatedfalse when the contents are inline, true when they were left out, absent when the file could not be read at all.sourceText and sourceBytesBase64 omitted entirely — not shortened. Read from sourcePath yourself in that case. Treat sourcePayloadTruncated === false as the only guarantee the contents are present; checking for !== true will also match the read-failure case, where nothing is there.