DocsExtensionsmanifest.json reference

manifest.json reference

Every extension must include a manifest.json file in the repository root. The manifest is how Bulwark knows what the extension is, what capabilities it needs, and where its entry point lives.

Example

{
  "name": "my-extension",
  "displayName": "My Extension",
  "version": "1.0.0",
  "type": "plugin",
  "pluginType": "sidebar-app",
  "description": "A short description.",
  "author": "githubUsername",
  "license": "MIT",
  "permissions": ["email:read"],
  "tags": ["productivity"],
  "minAppVersion": "1.0.0",
  "entryPoint": "index.js",
  "icon": "icon.png"
}

Required fields

FieldDescription
nameUnique slug - lowercase, numbers, and dashes only. Used in URLs and install paths.
displayNameHuman-readable name shown in the directory and admin UI.
versionSemantic version (for example 1.0.0). Must match a git tag in the source repo.
typeEither plugin or theme.
descriptionShort summary of what the extension does. Max 200 characters.
licenseSPDX identifier of an OSI-approved license (for example MIT, Apache-2.0, GPL-3.0-or-later).
permissionsArray of permission strings the extension needs. Requesting more than necessary will be rejected.

Plugin-only fields

FieldDescription
pluginTypeOne of hook, ui-extension, or sidebar-app.
entryPointRelative path to the JavaScript entry module (for example index.js).
minAppVersionMinimum Bulwark version the plugin supports. Used for compatibility checks.

Theme-only fields

FieldDescription
entryPointRelative path to the theme stylesheet (typically theme.css).

Optional metadata

FieldDescription
authorGitHub username of the author. Defaults to the submitter.
tagsArray of category tags. Allowed: productivity, security, automation, appearance, integration, communication, developer-tools, accessibility.
iconRelative path to a square icon (128×128 PNG or SVG).
screenshotsArray of relative paths to screenshot images.
homepageURL to the extension's website or documentation.
frameOriginsArray of strict https://host origins the plugin needs to embed (merged into the host CSP frame-src only while the plugin is enabled).
httpOriginsArray of https://host origins the plugin is allowed to call through the sandboxed HTTP proxy (requires the http:fetch permission).

Source assets When the directory ingests a submission, it pulls icon, banner, and screenshots straight from the source repo at the tag you submitted. There's no separate upload flow - keep these files inside your repository alongside manifest.json.

Permissions

Bulwark uses a declarative permission model. Each permission string takes the form resource:action. The directory shows these on the extension's listing so users can audit what an extension can do before installing.

CategoryPermissions
Emailemail:read, email:write, email:send
Calendarcalendar:read, calendar:write
Contactscontacts:read, contacts:write
Filesfiles:read, files:write
Identityidentity:read, identity:write
Filtersfilters:read, filters:write
Taskstasks:read, tasks:write
Templatestemplates:read, templates:write
S/MIMEsmime:read
Vacationvacation:read, vacation:write
Settingssettings:read, settings:write
Securitysecurity:read
UIui:toolbar, ui:app-top-banner, ui:email-banner, ui:email-footer, ui:email-details, ui:composer-toolbar, ui:composer-sidebar, ui:sidebar-widget, ui:settings-section, ui:context-menu, ui:navigation-rail, ui:calendar-action, ui:admin-page, ui:keyboard, ui:download-file, ui:message-list-tabs
Authauth:observe
Adminadmin:config
HTTPhttp:fetch, http:post (paired with the httpOrigins manifest field to declare the allowlist)

ui:observe and app:lifecycle are granted to every plugin automatically. Listing them does nothing.

Privileged permissions

crypto:full, email:raw-send, email:blob-read, email:blob-write, and email:render-takeover require "tier": "privileged", a signed bundle, and an explicit high-risk consent step from the admin installing it. They exist for plugins that perform their own message cryptography. Requesting one without that justification will fail review.

Validation

When you submit, the directory checks that:

  1. The manifest is valid JSON with all required fields.
  2. name is a valid slug and not already taken.
  3. version matches an existing git tag on the referenced repository.
  4. license is an OSI-approved SPDX identifier and a LICENSE file is present.
  5. permissions contains only known permission strings.

If any of these fail, the submission is rejected with a machine-readable error.