Skip to content

App Configuration

Every Lombok app is defined by a single config.json manifest at the root of its package. The manifest is not a loose plugin descriptor — it is validated against a strict schema (AppConfig) at install time, and unknown top-level keys are rejected.

This page documents that manifest field by field. It is derived directly from the schema rather than hand-maintained prose, so it is meant to be read as a reference.

The manifest shape is defined in the main Lombok repository:

  • packages/types/src/apps.types.tsappConfigSchema (AppConfig), the authoritative top-level schema, plus icon, contributions, settings, and containerProfiles definitions.
  • packages/types/src/task.types.tstaskConfigSchema and taskTriggerConfigSchema (triggers, schedules, completion handlers).
  • packages/demo-apps/simple-demo/config.json — a complete, valid example.

When this page and the schema disagree, the schema wins.

AppConfig is a strict object: only the keys below are allowed.

FieldRequiredTypeSummary
slugyesstringStable app identifier. [a-z0-9]+, lowercase; cannot be platform or core.
labelyesstringHuman-readable name. 1–128 characters.
descriptionyesstringShort description. 1–1024 characters.
iconyesobjectApp icon. Builtin or custom (see Icon).
requiresStoragenobooleanDeclares the app needs storage access.
permissionsnoobjectPlatform permissions the app requests (see Permissions).
subscribedCoreEventsnostring[]Platform events the app subscribes to (core:<event>).
triggersnoarrayBind events, schedules, or user actions to tasks (see Triggers).
tasksnoarrayNamed units of work (see Tasks).
runtimeWorkersnoobjectJS worker definitions, keyed by worker id (see Runtime workers).
containerProfilesnoobjectDocker-backed execution profiles, keyed by profile id (see Container profiles).
systemRequestRuntimeWorkersnoobjectMaps platform system requests (e.g. search) to workers.
uinoobjectDeclares an embedded UI bundle. { enabled: true, csp? }.
databasenoobjectDeclares Lombok-managed database support. { enabled: true }.
contributionsnoobjectUI/navigation surfaces and mobile views (see Contributions).
settingsnoobjectUser/folder settings schemas (see Settings).

A stable, lowercase identifier matching ^[a-z0-9]+$. It is cosmetic and may be renamed; the canonical app identifier the platform uses internally is <slug>-<id>, where id is an immutable 8-hex-character suffix. The values platform and core are reserved.

The display name shown in the Lombok UI (1–128 characters).

A short explanation of the app (1–1024 characters).

The app icon is a discriminated union on source. There are two sources: builtin (a name from the platform catalog) and custom (assets shipped in your UI bundle).

Builtin — references a catalog icon by name:

{ "source": "builtin", "name": "box", "label": "My App" }

Catalog v1 names: app, box, code, file, folder, settings, sparkles, terminal. Each rendering client maps these to its own assets.

Custom (SVG) — tintable or original-color vector assets:

{
"source": "custom",
"format": "svg",
"rendering": "template",
"assets": [{ "path": "assets/icon.svg", "appearance": "any" }]
}

rendering is template (tintable) or original.

Custom (PNG) — raster assets at one or more scales:

{
"source": "custom",
"format": "png",
"rendering": "original",
"assets": [
{ "path": "assets/logo-light@2x.png", "scale": 2, "appearance": "light" },
{ "path": "assets/logo-dark@2x.png", "scale": 2, "appearance": "dark" }
]
}

Asset rules:

  • appearance is light, dark, or any. An asset set may use either a single any asset or up to one light and one dark — the two cannot be mixed.
  • PNG scale is 1, 2, or 3, and at least one asset must be scale 2 or 3. PNG only supports rendering: "original".
  • Custom icons require ui.enabled: true — their assets are resolved from the app’s UI bundle at /ui/<path> and validated against the bundle manifest.

permissions requests platform capabilities, grouped by scope. Each group is an array drawn from a fixed enum.

{
"permissions": {
"core": ["READ_FOLDER_ACL"],
"user": ["READ_USER", "READ_FOLDERS"],
"folder": ["READ_OBJECTS", "WRITE_OBJECTS"]
}
}
ScopeAllowed values
coreREAD_FOLDER_ACL
userCREATE_FOLDERS, READ_FOLDERS, UPDATE_FOLDERS, DELETE_FOLDERS, READ_USER
folderREAD_OBJECTS, WRITE_OBJECTS, WRITE_OBJECTS_METADATA, WRITE_FOLDER_METADATA, REINDEX_FOLDER

An array of platform event identifiers the app listens for, each prefixed with core:. Known core events:

  • core:object_added
  • core:object_removed
  • core:object_updated
  • core:folder_scanned
  • core:serverless_task_enqueued
  • core:docker_task_enqueued
  • core:new_user_registered

An app must subscribe here to any core: event it references from an event trigger.

triggers is an array binding an event, schedule, or user action to a task. Each entry is discriminated by kind. All trigger kinds share these fields:

  • taskIdentifier (required) — the tasks[].identifier to run. Must exist.
  • condition (optional) — a guard expression evaluated before the task runs.
  • onComplete (optional) — completion handlers (see below).
  • onProgress (optional) — progress handlers.
{
"kind": "event",
"eventIdentifier": "core:object_added",
"taskIdentifier": "demo_object_added_worker_task",
"dataTemplate": { "key": "{{event.data.key}}" },
"triggerKey": "on_upload"
}
  • eventIdentifier — a plain identifier or a core:-prefixed platform event. If it is a core: event, it must also appear in subscribedCoreEvents.
  • dataTemplate (optional) — shapes the data passed to the task using {{...}} references.
  • triggerKey (optional) — a stable handle; when set it must be unique per app.
{
"kind": "schedule",
"triggerKey": "hourly_job",
"config": { "kind": "interval", "interval": 1, "unit": "hours" },
"taskIdentifier": "demo_scheduled_worker_task"
}
  • triggerKey is required on schedules.
  • config is one of two forms:
    • interval{ "kind": "interval", "interval": <int > 0>, "unit": "minutes" | "hours" | "days" }
    • cron{ "kind": "cron", "expression": "<5-field cron>", "timezone": "<IANA tz>" }. Sub-minute cron is rejected; timezone defaults to UTC.

User-action triggers (kind: "user_action")

Section titled “User-action triggers (kind: "user_action")”
{
"kind": "user_action",
"taskIdentifier": "demo_user_action_task",
"scope": { "folder": { "folderId": "<uuid>" } }
}

scope optionally narrows the action to a user permission or a specific folder. User-action triggers are config-only.

onComplete chains another task when one finishes. It is recursive — a handler can itself declare onComplete.

onProgress works similarly but fires on progress reports. Every taskIdentifier referenced by a handler must resolve to a declared task.

tasks declares named units of work. Each task is a strict object:

{
"identifier": "demo_object_added_worker_task",
"label": "Demo Object Added Worker",
"description": "A task that runs for every newly added object.",
"handler": { "type": "runtime", "identifier": "demo_object_added_worker" }
}
FieldRequiredNotes
identifieryes[a-z_]+. Referenced by triggers and handlers.
labelyes1–128 characters.
descriptionyesFree text.
handler.typeyesruntime or docker.
handler.identifieryesTarget of the handler.

Handler resolution is validated against the rest of the manifest:

  • type: "runtime"identifier must be a key in runtimeWorkers.
  • type: "docker"identifier is <profile>:<job>, where <profile> is a key in containerProfiles and <job> is a job defined within that profile.

runtimeWorkers is a map of worker id ([a-z0-9_]+) to a worker definition. These are JavaScript entrypoints that execute tasks and service requests.

"runtimeWorkers": {
"demo_object_added_worker": {
"entrypoint": "demo_object_added_worker/index.js",
"description": "Runs for every newly added object.",
"environmentVariables": { "MY_CUSTOM_ENV_VAR": "value" }
}
}
FieldRequiredNotes
entrypointyesRelative path within the workers bundle. No leading / or ./, no .., no backslashes. Must exist in the bundle manifest at /workers/<entrypoint>.
descriptionyesFree text.
labelnoDisplay label.
environmentVariablesnoMap of string → string (non-secret values).

Maps built-in platform system requests to runtime workers. Currently:

"systemRequestRuntimeWorkers": { "performSearch": ["demo_search_worker"] }

Each named worker must exist in runtimeWorkers.

containerProfiles declares Docker-backed execution, keyed by profile id ([a-z_]+). Use this for work that needs a container image rather than a JS worker. Each profile is a strict object.

FieldRequiredNotes
imageyesContainer image reference.
workersyesArray of worker definitions.
resourcesnoResource hints: gpu, memoryMB, cpuCores.
containerTargetnoDefault targeting strategy for the profile.

A workers entry is discriminated by kind:

  • exec{ "kind": "exec", "command": string[], "jobIdentifier": "...", "containerTarget"? }
  • http{ "kind": "http", "command": string[], "port": 1–65535, "jobs": [{ "identifier": "...", "containerTarget"? }] }

Declares that the app ships an embedded UI bundle:

"ui": { "enabled": true, "csp": "default-src 'self'" }

enabled must be the literal true. csp (optional) overrides the Content-Security-Policy for the embedded UI.

Declares Lombok-managed database support:

"database": { "enabled": true }

enabled must be the literal true. See App Database Access for usage.

contributions declares the surfaces an app injects into the Lombok UI. It is a strict object. The five link arrays are all required when contributions is present (use [] for those you do not contribute); mobile is optional.

The link arrays are:

  • sidebarMenuLinks
  • folderSidebarViews
  • objectSidebarViews
  • objectDetailViews
  • folderDetailViews

Each link entry is { path, label, icon? }, where path must start with / and label is non-empty. mobile declares server-driven mobile views and is substantial enough to document separately.

settings defines structured, user- and folder-scoped configuration that operators fill in after install. At least one of user or folder must be present.

  • user / folder are JSON-Schema-07-style objects.
  • secretKeyPattern (optional) marks keys whose values are sensitive so Lombok can treat them as secrets.

For the full settings property model and secret handling, see App Settings & Secrets.

Beyond per-field rules, the manifest is checked for internal consistency at install time. The most important rules:

  • every trigger taskIdentifier must resolve to a declared task
  • a core: event trigger requires the matching entry in subscribedCoreEvents
  • runtime handlers must name existing runtime workers
  • docker handlers must name existing container profiles and jobs
  • custom icons require ui.enabled: true
  • runtime worker entrypoints must exist in the workers bundle manifest