Skip to content

Manifest specification ​

The extension manifest is extension.json.

Example:

json
{
  "id": "hello-world",
  "name": "Hello World Extension",
  "version": "1.0.0",
  "author": "ISA Warden",
  "description": "Demo extension that validates host commands and client-server style native API calls.",
  "entry": "index.html",
  "permissions": [
    "get_app_info",
    "get_thread_list",
    "get_full_thread_object",
    "new_thread",
    "stream_chat",
    "list_extensions",
    "get_extension_info",
    "native_code"
  ],
  "native": {
    "binaries": [
      {
        "id": "hello-native-linux",
        "path": "native/linux-x86_64/hello-native-demo",
        "targets": ["linux-x86_64", "linux"],
        "functions": ["hello.native_server"],
        "protocol": "stdio-json-v1",
        "args": []
      }
    ]
  }
}

4.1 Required top-level fields ​

  • id: stable extension identifier
  • name: user-facing name
  • version: extension version string
  • entry: entry file path inside the extension package
  • author
  • description
  • icon
  • permissions

The optional modelRecommendations field is documented in section 4.7.

The optional modEntry field is valid only with the mod permission and is documented in section 4.8.

The optional minimumIsaWardenVersion field is the install-time compatibility gate and declares the oldest compatible ISA Warden host as an exact semantic version, for example "0.7.39". Discovery, validation, preview, install, and update reject a malformed value or a manifest whose minimum is newer than the running host. Dashboard packages copy this field into their distribution manifest, and the public and payload values must match exactly. This gate does not version runtime command APIs; extensions must continue detecting runtime capabilities by checking the host-advertised command arrays. Omit the field when the extension has no explicit minimum beyond the host's existing manifest contract.

4.2.1 Extension icon ​

An extension chooses its launchpad icon in its own manifest. Use a host-supported Lucide icon for normal product concepts:

json
{
  "icon": {
    "type": "lucide",
    "name": "file-search-2"
  }
}

The name uses the kebab-case Lucide icon name, such as file-search-2, tractor, or chart-no-axes-combined. The host resolves it against its installed lucide-svelte version.

Use a packaged asset for a brand or domain-specific icon:

json
{
  "icon": {
    "type": "asset",
    "path": "assets/icon.svg"
  }
}

Asset paths must be safe relative forward-slash paths inside the extension and must end in .svg, .png, .jpg, or .jpeg. The packager rejects a missing icon file. The host renders custom icons as images and does not inject their SVG markup into the app document. An absent, malformed, unavailable, or unsupported icon uses the generic Puzzle fallback.

4.3 Native block ​

If native functionality is used, native must define one or more binaries.

Binary fields:

  • id
  • path
  • targets
  • functions
  • protocol
  • args

4.4 Manifest validation rules ​

The current validator is implemented in validate_extension().

Rules:

  • manifest must parse correctly
  • minimumIsaWardenVersion, when present, must be a valid semantic version no newer than the running ISA Warden host
  • entry file must exist
  • declared icon metadata must be valid and a custom icon asset must exist
  • declared native assets must exist
  • if native exists, permissions must include native_code
  • if permissions includes native_code, native must exist
  • a native function may appear in multiple binaries only if their target sets do not overlap
  • if permissions includes mod, modEntry must name an existing safe relative classic JavaScript file
  • modEntry without the exact mod permission is invalid
  • modEntry must not be empty, absolute, drive-prefixed, backslash-separated, or contain . or .. path segments

4.4.1 Dashboard workers ​

The privileged dashboard_worker permission is valid only with a non-empty workers array. Worker IDs and function names are unique, entries are safe relative packaged .mjs paths, and the only initial runtime/protocol pair is javascript-esm-v1 with isa-extension-worker-v1. Public distribution metadata must exactly match the verified payload. Installation and every metadata or digest update require fresh administrator consent; declaration alone never grants model, file, tool, project, storage, or email access. See Dashboard extension workers.

4.5 Audio and transcription permissions ​

A typical record-and-transcribe extension declares both media permissions:

json
{
  "permissions": [
    "get_app_info",
    "audio_capture",
    "transcribe_audio"
  ]
}
  • audio_capture allows an extension to enumerate microphone inputs and manage opaque, host-owned local recordings. The host asks the user for a separate, revocable microphone grant before the first recording starts.
  • transcribe_audio allows an extension to list speech-to-text models assigned to its exact launch group and transcribe one of its own local recordings.

The permissions are independent: an extension that only manages existing recordings can request audio_capture, while the normal microphone-to-transcript flow needs both. Use capability discovery before rendering either workflow; declaring a permission does not guarantee that the current host or launch context can provide it.

Neither permission exposes audio bytes, local paths, model credentials, or dashboard credentials. An extension that persists transcript text in shared group storage must also request the relevant filesystem_read and filesystem_write permissions. Add filesystem_delete only when the extension actually deletes shared files.

4.6 Shared project permissions ​

Extensions that participate in a cross-extension project workflow can request:

json
{
  "permissions": [
    "get_app_info",
    "projects_read",
    "projects_write"
  ]
}
  • projects_read enables projects_list for the active launch group.
  • projects_write enables projects_create and projects_set_archived for that group.

The permissions are independent and appear under get_app_info().projects as canRead, canWrite, and the exact available commands. The host discards any extension-supplied workspace or group scope and injects the frozen launch context. These permissions expose project identity and metadata only; they do not grant raw filesystem access to the project registry. Store extension-owned project data in the extension group folder and key it by the returned project id.

Archiving is a reversible metadata change, not deletion. It preserves the project id and does not remove extension-owned files associated with that id. Only show archive or restore actions when projects_set_archived is present in the advertised project commands.

4.7 Model recommendations ​

An extension can recommend portable dashboard model records:

Use Model recommendations for the complete author workflow, host processing sequence, administrator follow-up, retry behavior, and runtime limitations. This section defines the wire format.

json
{
  "modelRecommendations": {
    "schemaVersion": 1,
    "items": [
      {
        "key": "analysis-model",
        "importance": "required",
        "name": "Local analysis model",
        "reason": "Analyses meeting content on this device.",
        "modelTypes": ["chatLlm"],
        "location": "local",
        "safetyLevel": "high",
        "modelSettings": {
          "contextLength": 8192
        },
        "source": {
          "normalHttp": {
            "url": "https://models.example/acme/analysis.gguf",
            "outputFile": "acme/analysis.gguf",
            "autoDownload": false,
            "mmprojPath": "acme/analysis-mmproj.gguf"
          }
        }
      },
      {
        "key": "summary-model",
        "importance": "recommended",
        "name": "Remote summary model",
        "reason": "Creates concise summaries.",
        "modelTypes": ["chatLlm"],
        "location": "cloud",
        "safetyLevel": "medium",
        "source": {
          "openAICompatibleAPI": {
            "baseUrl": "https://api.example/v1",
            "model": "summary-1"
          }
        }
      }
    ]
  }
}

modelRecommendations is optional. A complete version 1 example is available as examples/model-recommendations-v1.json. When present:

  • schemaVersion must be 1.
  • items must contain at least one recommendation.
  • key is unique within the extension and contains only lowercase ASCII letters, digits, _, and -.
  • importance is required or recommended. Required items cannot be deselected during installation review; this MVP does not enforce them at extension runtime.
  • name and reason are non-empty user-facing strings.
  • modelTypes is a non-empty, duplicate-free list containing chatLlm, text2Video, text2Image, textEmbedding, other, or speechToText.
  • safetyLevel is high, medium, or low.
  • modelSettings, when present, is a JSON object without credential fields.

The source is an externally tagged union with exactly one of these variants:

  • normalHttp contains url, outputFile, and optional autoDownload, mmprojPath, and mtpPath. Its location must be local. autoDownload must be omitted or false; adding the dashboard record never implicitly downloads its bytes. Output and companion paths may contain nested / segments but must be safe relative portable paths: absolute paths, drive prefixes, backslashes, empty segments, . and .. are rejected.
  • openAICompatibleAPI contains only baseUrl and the provider model identifier. Its location must be privateServer or cloud. It must never contain an API key.

Source URLs must use HTTPS. HTTP is accepted only for an explicit development endpoint on localhost or a loopback IP address. URL userinfo and credential query parameters are rejected. Portable recommendation objects are strict: unknown source fields such as apiKey, and recursively nested credential-looking fields in modelSettings, make the manifest invalid.

isa-ext package validates this contract and copies it unchanged in meaning to the public distribution extension.json. The host validates it again during preview. API keys are supplied by the administrator in the review UI and are never copied into either manifest. A recommendation key remains installation metadata and is not exposed as a runtime model ID.

4.8 Privileged host modules ​

A host mod is declared separately from the iframe entry:

json
{
  "id": "tootsy",
  "name": "Tootsy",
  "version": "1.0.0",
  "entry": "index.html",
  "permissions": ["mod"],
  "modEntry": "mod.js"
}

entry always remains the normal sandboxed iframe application. modEntry is a classic, self-registering JavaScript file that is loaded in the main application document only after the host validates the installed manifest and the user accepts the host-controlled warning for the current activation session. The warning is required because this permission can visibly change ISA Warden, add host UI such as buttons, and execute code outside the extension iframe sandbox.

The module must synchronously register exactly once while its script is evaluated:

js
window.__ISA_WARDEN_EXTENSION_MOD_HOST__.register({
  extensionId: 'my-extension',
  activate(context) {
    const style = context.appendStyle(':root { --my-accent: rebeccapurple; }');
    const root = context.appendRoot('extensionToolbar');
    const button = context.document.createElement('button');
    button.type = 'button';
    button.textContent = 'My action';
    root.append(button);

    context.addEventListener(button, 'click', () => {
      context.document.documentElement.style.setProperty('--my-accent-active', '1');
    });

    return () => {
      context.document.documentElement.style.removeProperty('--my-accent-active');
      root.remove();
      style.remove();
    };
  }
});

The registration extensionId must exactly match the installed manifest. The host rejects missing, late, wrong-ID, and duplicate registrations.

The activation context contains extensionId, document, mountPoints, minimizeExtensionView(), onDispose(callback), appendStyle(cssText), appendRoot(mountPointName = 'appShell'), and addEventListener(target, type, listener, options). The named appShell and extensionToolbar mount points are backed by host elements marked data-isa-extension-mod-mount="appShell" and data-isa-extension-mod-mount="extensionToolbar". A mod whose primary result is a host theme may call minimizeExtensionView() after activation so the themed host becomes visible while the extension and its tracked contributions remain active. appendStyle, appendRoot, and addEventListener create tracked contributions owned by the extension; activate may additionally return one cleanup function. The host runs registered and returned cleanup and removes all tracked contributions when the view reloads, closes, is uninstalled, fails activation, or is replaced.

These lifecycle helpers reduce accidental leaks; they are not a security sandbox. Once accepted, a mod runs in the host realm and can directly access the document. Request mod only when iframe theme tokens and bridge APIs cannot implement the feature.

ISA Warden extension specification