Manifest
manifest.json lives in the package root. The host validates it strictly: unknown top-level keys and unknown permissions are errors.
Required
Section titled “Required”| Field | Description |
|---|---|
schema |
always 1 |
id |
unique identifier, for example com.example.hello |
name |
name; can be an object with translations by language |
version |
semver, for example 1.0.0 |
compat |
compatibility, see below (compat.freshgram is required) |
runtime |
how to run the code |
files |
the package file list |
description, author, license and permissions are optional but recommended. Unknown top-level keys are errors, except keys that start with x- (these are not accepted as language keys inside a localized name/description map, though). Every key is listed in the full manifest reference.
Optional descriptive keys
Section titled “Optional descriptive keys”| Key | Meaning |
|---|---|
description |
text for the install dialog; a string or a language map (up to 1000 characters) |
author |
an object with name (up to 100), url (https) and contact (up to 200) |
license |
licence name, up to 64 characters |
homepage, repository, support |
https links, up to 500 characters each |
icon |
path of a PNG in the package, at most 256 KiB; checked when the package is opened, not by the manifest parser |
changelog |
path of a file in the package |
categories |
up to 8 tokens (a-z, 0-9, -, up to 32 characters each) |
keywords |
up to 16 tokens of the same kind |
locales |
up to 64 language codes the plugin is translated to (ru, pt-BR) |
icon and changelog must also be listed in files. Empty strings are rejected for every one of these keys (and for author.name, author.contact, updates.feed): omit a key instead of writing "". Length limits of the other strings are in the full reference.
compat
Section titled “compat”"compat": { "freshgram": ">=7.0.0 <8.0.0", "api": 7 }freshgram— range of client versions.api— the API level the plugin requires: a single integern(meaning “levelnor higher”, must be 1–1000) or an object{ "min": 3, "max": 7 }(both 1–1000,maxnot belowmin). The host currently declares level 7.accounts— account restrictions (thecompat.accountsfield).- If the plugin requires Premium, set
compat.accounts.premium.compat.requireslists host features andcompat.testedWiththe client version you tested with (a semantic version, up to 64 characters).
runtime
Section titled “runtime”"runtime": { "kind": "python", "entry": "main.py" }"runtime": { "kind": "wasm", "module": "plugin.wasm", "language": "rust", "abi": 1, "limits": { "memoryMb": 64, "eventTimeoutMs": 500, "storageMb": 10 }}| Key | Value |
|---|---|
kind |
python or wasm (up to 16 characters) |
entry |
entry file (Python) |
module |
path to the .wasm (Wasm) |
language |
language hint, for example rust, c |
pythonVersion |
optional, informational: a Python version hint (up to 32 characters). The host does not compare it with the interpreter, and ignores it for wasm plugins |
abi |
Wasm ABI version, currently only 1 |
limits.memoryMb |
memory, 1–1024, default 64 |
limits.eventTimeoutMs |
event handling timeout, 10–60000, default 500 |
limits.storageMb |
storage quota, 0–1024, default 10 |
permissions
Section titled “permissions”"permissions": { "required": [ { "id": "messages.read", "reason": "Counts the messages it sees." } ]}Each permission has an id and a reason (up to 500 characters; can be localized). The reason is shown to the user. Extra fields:
scope— only formessages.read:selectedorall.mode— forfs.folder:readorwrite.ports— fornet.local: port ranges on this computer.
The full list is in the permission reference.
contributes
Section titled “contributes”What the plugin adds to the app:
| Key | Purpose |
|---|---|
events |
events the plugin subscribes to (see Events) |
commands |
/name commands with a description |
menus |
menu items on surfaces (surface, id, title, icon, when) |
icons |
the plugin’s own icons |
outgoing / incoming |
message hooks |
translator |
the plugin as a translation provider (name, languages, maxChars) |
aiProvider |
the plugin as an AI provider (name, maxChars) |
messages |
an object with a from array: { "from": ["com.example.other", "*"] } lists the plugins whose plugin.message is accepted ("*" — any); up to 64 entries; needs the plugins.message permission. The key is contributes.messages.from, not contributes.messages as a list |
settingsPage |
the plugin has a settings page |
Menu surfaces: message, chat, profile, composer, main_menu, tray, selection, shared_media. The when condition can limit an item with chat_type, out, has_media, has_text, media and forwarded. A menu item id may contain only a-z, 0-9 and -.
activation.on limits what can wake the plugin: startup, event, command, menu, settings, message, timer, translate, ai, toast. activation.background together with the background permission allows background work. dependencies and conflicts list other plugins by id with a version range. storage.export.prefixes and storage.export.exclude set which keys are exported on transfer, and storage.schema is the storage schema version. updates.feed is accepted by the parser but is not used by the app yet. signature is the manifest signature (the algorithm is set in signature.alg).
