Omniscient Master Suite OMNISCIENT · 3.1

Build an app for the Omniscient Master Suite

An app is a folder with a manifest that says what it can do and a Python file that does it. Everything else comes for free: the manifest and run_action drive the app's own window, its command line, the MCP tools AI assistants call, and the workflow editor's nodes, so a human at the keyboard, a script and an AI all run exactly the same code.

Folder layout

my-app/
  manifest.json   what the app is, what it can do, what it may touch
  app.py          the App subclass (plus --action CLI, optional GUI)
  icon.svg        tile icon (no scripts)
  core.py         your own code (optional)

manifest.json

json
{
  "id": "image-cropper",
  "name": "Image Cropper",
  "version": "1.0.0",
  "description": "Batch-crop and resize images with previews.",
  "category": "images",
  "icon": "icon.svg",
  "entry": {"gui": "app.py", "headless": "app.py"},
  "actions": [
    {"name": "crop_folder",
     "label": "Crop a folder",
     "description": "Crop every image in a folder to a target size.",
     "inputs":  {"folder": {"type": "path"},
                 "size":   {"type": "string", "default": "1024x1024"},
                 "mode":   {"type": "enum", "values": ["fit", "fill"], "default": "fit"}},
     "outputs": {"files": {"type": "path[]"}},
     "destructive": false}
  ],
  "permissions": {"filesystem": "ask", "network": false, "processes": false},
  "requires": {"python": ">=3.10", "packages": ["Pillow"], "models": []},
  "ui": {"theme": "omniscient", "override": false},
  "ai": {"mcp": true, "example_prompts": ["crop everything in folder X to 1024x1024"]}
}

Rules the loader enforces (an app that breaks them is not listed):

  • id and name are required. id: lowercase letters, digits and hyphens, 2-64 characters, starting with a letter. version is semver (1.0 or 1.0.0).
  • category is one of: images, media, social, web, ai, files, data, system, demos, other. Default other.
  • Every action needs a unique name. label is optional (defaults to the name with spaces). inputs / outputs map a field name to {"type": ...} where the type is one of: bool, choice, enum, float, int, json, path, path[], profile, secret, string, text.
  • An input is required unless it has a default or "optional": true. enum / choice inputs list their allowed values.
  • destructive: true marks an action that changes or deletes things; those are the ones that honour --dry-run.
  • permissions values are true, false, "ask", "yes" or "no" (filesystem may also be a list of folders). The site shows the ones that are on.
  • requires documents the Python version, pip packages, local models and external binaries (for example ffmpeg) the app needs.
  • ai.mcp (default true) declares that the app is meant to be driven by AI assistants; ai.example_prompts are shown on the app page as things to ask. ui.override: true marks an app whose window deliberately departs from the standard suite look (every other app inherits it from omni_kit).

app.py

python
from omni_kit.sdk import ActionContext, App


class Cropper(App):
    def setup(self) -> None:
        # one handler per action declared in the manifest
        self.register("crop_folder", self.crop_folder)

    def crop_folder(self, ctx: ActionContext) -> dict:
        folder = ctx.params["folder"]      # already validated, coerced, defaults filled
        ctx.log(f"cropping {folder}")      # shows up in the envelope's "logs"
        if ctx.dry_run:                    # only True for destructive actions
            return {"files": []}           # report the plan, change nothing
        return {"files": [...]}            # anything JSON-serialisable


if __name__ == "__main__":
    raise SystemExit(Cropper().main())

The handler contract (run_action):

  1. Registering an action that is not in the manifest is an error at start-up.
  2. Before your handler runs, params are checked against the manifest: missing required inputs and unknown inputs are rejected, defaults are filled in, and values are coerced (int, float, bool accepts 1/true/yes/on, enum must be one of its values, path[] accepts a single string).
  3. The handler receives an ActionContext: ctx.params, ctx.log(msg), ctx.dry_run, ctx.secret(key) (from the encrypted vault, if unlocked). The app also offers self.settings (per-app settings) and self.data_dir (per-app data folder).
  4. Whatever the handler returns becomes the result. An exception becomes an error envelope; it never takes the host down.

One envelope for every surface

run_action never raises. It always returns one JSON object:

json
{"ok": true,  "action": "crop_folder", "dry_run": false, "result": {"files": []}, "logs": []}
{"ok": false, "action": "crop_folder", "error": "folder not found: D:/x", "logs": []}

An unknown action also returns available (the action names); an unexpected exception also carries trace.

The command line

App.main() gives every app the same CLI:

python app.py --list                       # actions, required inputs, [destructive]
python app.py --manifest                   # the manifest as JSON
python app.py --action crop_folder --params "{\"folder\": \"D:/renders\"}" --json
python app.py --action crop_folder --params "..." --dry-run    # destructive actions only
python app.py                              # no --action: open the app's window

--json prints the envelope; without it, logs and the result are printed in plain text. Exit codes: 0 ok, 1 the action failed, 2 bad usage (invalid --params JSON, or no window available).

Checklist

  • manifest.json loads (omni_kit.manifest.validate_file(path) returns (True, "OK ...")).
  • python app.py --list shows every action, and each one is registered.
  • Each action works from the CLI with --json before you build any GUI on top.
  • Destructive actions support --dry-run and say what they would do.
  • Originals are never overwritten unless the action is marked destructive.