Browse API 1 documentation
GroveAPI 1preview

Package and manifest

Package layout, manifest fields, validation, and network allow-lists.

Mango 3.1+View Markdown

A Grove extension is a directory of static assets with manifest.json at its root. A distributable .grove file is a zip archive of that directory. Mango accepts a manifest at the archive root or inside one wrapping directory.

Manifest example

json
{
  "grove": 1,
  "id": "com.example.grove.poll",
  "name": "Poll",
  "version": "1.0.0",
  "description": "Run quick polls in a channel.",
  "author": { "name": "Example Developer", "url": "https://example.com" },
  "icon": "icon.png",
  "readme": "README.md",
  "screenshots": [
    { "path": "screenshots/results.webp", "caption": "Poll results in a channel pane." }
  ],
  "entry": "index.html",
  "settings": "settings.html",
  "presentation": {
    "surfaces": ["channelPane", "window"],
    "defaultSurface": "channelPane",
    "minSize": { "width": 280, "height": 200 },
    "defaultSize": { "width": 340, "height": 420 }
  },
  "capabilities": ["channel.read", "channel.send", "storage"],
  "hostPermissions": ["https://api.example.com"]
}

Top-level fields

Field Required Contract
grove Yes Integer API version. Mango 3.1 supports 1.
id Yes Immutable, globally unique reverse-DNS identifier. It must contain a dot and cannot start or end with one.
name Yes Human-readable extension name shown by Mango.
version Yes Release version string. Semantic versions are required for catalogue update ordering.
description No Short store and consent description.
author No Object with required name and optional url.
icon No Package-relative image path.
readme No Package-relative .md or .markdown file used as the long store description.
screenshots No Up to eight package images with optional captions of at most 240 characters.
entry Yes Package-relative HTML entry document.
settings No Package-relative configuration page opened from Grove Manager.
presentation No Allowed surfaces, default surface, scope, and sizing hints. Omission defaults to a channel pane.
contributions No Static metadata for host integrations such as on-demand composer commands and upload providers.
capabilities No Permission names requested from the user. Unknown names make the manifest invalid.
hostPermissions No TLS network destinations available to the extension runtime.

Optional arrays default to empty. Optional presentation defaults to a visible channelPane extension.

Package resource validation

entry, settings, icon, readme, and screenshot paths must name files inside the package. Mango resolves symlinks and rejects:

  • absolute or empty resource paths;
  • .. traversal or a symlink that escapes the package;
  • missing resources or directories where a file is expected;
  • a README without a Markdown extension;
  • screenshots outside PNG, JPEG, or WebP;
  • duplicate screenshot paths;
  • more than eight screenshots or an overlong caption.

The package installer also bounds compressed size, expanded size, and entry count. Keep dependencies bundled, remove source maps or test fixtures that the runtime does not need, and do not fetch executable code from a remote host.

Presentation

API 1 manifest surfaces are channelPane, window, tab, composer, and headless. tab, composer, and headless are exclusive contracts. A tab must be the only declared surface and must declare "scope": "server"; Mango rejects a mixed-surface or non-server tab manifest. The valid form creates one visible network-wide instance, and starting it again selects that existing tab. See Surfaces and scopes.

Network destinations

hostPermissions is a network allow-list, separate from native capabilities. Declare the scheme and host:

json
"hostPermissions": [
  "https://api.example.com",
  "wss://events.example.com"
]

An https:// entry permits TLS web requests to that host; it does not grant WebSocket access. A wss:// entry permits secure WebSockets and does not grant ordinary HTTPS requests. Cleartext http:// and ws:// entries do not become reachable.

Entries are origin-scoped and may include a port. Exact origins are preferred. A complete leftmost-label wildcard such as https://*.example.com matches one direct subdomain (alice.example.com), but not the apex (example.com), a deeper name (www.alice.example.com), another scheme, or an undeclared port. No other partial wildcard form is supported.

The broad forms https://* and wss://* are reserved for extensions whose destination is genuinely chosen by the user, such as a configurable upload provider. Broad access is displayed prominently during consent and should not be used when the service host is known in advance.

An empty allow-list means no external network access. The extension’s own packaged assets, data:, blob:, and inert browser URLs remain available.

Composer-command contributions

An exclusive composer utility may declare slash commands under contributions.commands. This makes the commands available while the utility is closed; Mango starts the utility only after the user invokes one and then delivers the ordinary command event:

json
{
  "presentation": { "surfaces": ["composer"] },
  "contributions": {
    "commands": [
      {
        "name": "gif",
        "summary": "Find a GIF and add it to the draft",
        "usage": "[search|first] [keywords]",
        "subcommands": [
          { "name": "search", "summary": "Open the picker", "usage": "<keywords>" },
          { "name": "first", "summary": "Use the first result", "usage": "<keywords>" }
        ]
      }
    ]
  },
  "capabilities": ["commands.register"]
}

The manifest may declare at most 32 commands and 16 subcommands per command. Names are normalized to lowercase, cannot contain whitespace, must be unique inside the package, and cannot shadow a built-in Mango command. summary, usage, and subcommands are optional.

This form is only for the exclusive composer surface. A persistent visible Sprig or headless Root registers commands at runtime with grove.commands.register(...). A composer utility must not call that registration method; its manifest remains the authoritative command list. Command invocation does not grant an IRC send route, and grove.composer.complete(...) still returns text to the draft without sending it.

Upload-provider contributions

Only a headless Root may contribute an upload provider, and it must request uploads.provide:

json
{
  "presentation": { "surfaces": ["headless"], "scope": "application" },
  "contributions": {
    "uploadProviders": [
      {
        "id": "primary",
        "name": "Private files",
        "kind": "userConfigured",
        "acceptsImagesOnly": false,
        "maxFileSize": 1073741824
      }
    ]
  },
  "capabilities": ["uploads.provide"]
}

A manifest may declare at most eight providers. A provider identifier is 1–64 lowercase letters, digits, ., _, or -; it must be unique inside the package. kind is userConfigured or thirdParty. maxFileSize is an optional positive byte count.

Application scope is recommended for one destination configured once and available on every network. Use server scope only when the extension deliberately keeps a separate uploader configuration for each IRC session.

See Upload providers for runtime registration.