plugin.json, decided in order, then every field from Kanboombo's own schema, every limit, and what changed in contract 1. Unknown keys are refused.
plugin.json is the first thing a reviewer reads and the only thing the Server trusts: your fetcher cannot reach a host you did not declare, nor write a series you did not name. Add "$schema": "https://kanboombo.com/developers/plugins/plugin.schema.json" and your editor completes and checks it as you type. Unknown keys are refused at every level, except $schema: a misspelt fieldnames fails with PLG-MANIFEST-UNKNOWN-KEY instead of being quietly dropped.
Decide it in this order
Who it is. id is 2 to 48 lowercase letters, digits and hyphens, starting with a letter: your folder's name, part of lasting addresses (kanboombo://plugins/<id>), never reused, so make it plain and lasting. name is per language; version is major.minor.patch.
When it runs. timezone, a named IANA zone, never an offset (Dates); schedule, a five-field cron in it, at most 24 runs a day; backfill, how far back the first run fills: all, or a span such as 90d.
Who may read it. audience is public, private or local: Audiences.
What it downloads. At most 16 sources, each a lowercase name used once and an https url with a lowercase host. Set maxBytes, at most 20 MB, close to what you see: a far larger file is more likely an error page than news.
What it writes. 1 to 64 series, each one kind of record:
Choose
value, numbers about a date; event, something that happens on a date, maybe scheduled ahead (a rate decision, with the new rate as its value); item, a dated document to open
Choose
observation, the day described, where a changed number is a revision; publication, the day published, with period and revises (most monthly statistics)
Choose
fields, 1 to 16 in the order shown; fieldNames per language; unit, at most 16 characters (% shows changes in basis points); change, the field whose change readers see, never coloured good or bad
Choose
A window, { "back": "30d", "ahead": "0d" }, inside which every run prints the whole truth: for a source that corrects or removes what it published, not for notices that stand; kept inside what the source shows
cadence tells readers what to expect and schedules nothing. links.hosts lists hosts items may link to besides your sources'; limits may lower seconds and megabytes, never raise them. licence says whose data it is: Data rights.
Mistakes the check catches
check reports the first problem of each part, with its code, so most are fixed in one pass. An offset is not a time zone:
{
"contract": 1, "id": "my-plugin", "name": { "en": "Mine" }, "version": "1.0.0",
"timezone": "-04:00", "audience": "private", "schedule": "0 7 * * *", "backfill": "all",
"sources": [{ "name": "data", "url": "https://example.com/data.csv" }],
"series": [{ "key": "main", "kind": "value", "cadence": "daily", "dates": "observation", "name": { "en": "Main" }, "fields": ["value"] }],
"licence": { "holder": "Someone", "terms": null, "retain": "unknown" }
}
An http source fails with PLG-MANIFEST-SOURCE-URL; an id with capitals or an underscore with PLG-MANIFEST-ID.
Every field
PluginManifest
plugin.json: what your plug-in downloads, what it writes, when it runs and who may read it. Unknown keys are refused.
Field
Type
Required
Description
Type
string; at most 500 characters
Description
Your editor's schema for plugin.json, such as https://kanboombo.com/developers/plugins/plugin.schema.json. Ignored by Kanboombo.
Description
The contract this plug-in follows: 1.
Description
The plug-in's id, the same as its folder's name.
Description
Its name per language, 80 characters or fewer each.
Description
major.minor.patch. Raise it with every change you publish.
Type
string; 1 to 100 characters
Description
A named IANA zone. It decides today, how schedule is read, and how source URLs are filled.
Description
Who may read it: public, private or local.
Type
string; at most 100 characters
Description
Five-field cron, read in the manifest's time zone.
Description
How far back the first run fills: all, or a span such as 5y.
Description
The files Kanboombo downloads for each run. At most 16.
Description
What it writes. 1 to 64.
Description
Where an item's link may point besides your sources' own hosts.
Description
Lower time and memory limits, if you want them.
Description
Who holds the data, how it is credited, and whether it may be kept.
PluginSource
One file Kanboombo downloads before each run and hands to your fetcher. https only; the host refuses private addresses and redirects to hosts no source names. {today}, {year} and {month} are filled in the manifest's time zone.
Field
Type
Required
Description
Description
The source's name: the key your fetcher finds it under in the run context's sources.
Type
string; at most 500 characters
Description
Where to download it: https, with a lowercase host.
Type
integer; 1 to 20,971,520
Description
The largest download you expect, at most 20 MB (the default). A larger file fails the run.
PluginSeries
One kind of record your plug-in writes, and how readers see it.
Field
Type
Required
Description
Description
The series key every record of it names.
Description
value, event or item.
Description
How often it has a new record.
Description
Whether a record is dated by what it describes (observation) or by when it was published (publication).
Description
Its name per language, shown as the row's label.
Type
string; at most 16 characters
Description
What its numbers are in, such as DOP, m or %. Up to 16 characters. Screen readers say it after the figures; with % a change is shown in basis points and an event's value as a percentage.
Description
A value series' numbers, by key, in the order they are shown. 1 to 16.
Description
A label for each field, per language, for example compra: { es: Compra, en: Buy }.
Description
The field whose change from the previous record is shown, never coloured as good or bad.
Description
A window each run fully restates: a stored record missing from it for three runs is withdrawn.
PluginSnapshot
Each run's batch is the whole truth for this window. A stored record inside it that is missing from three runs in a row is withdrawn.
Field
Type
Required
Description
Description
How far before today the window reaches.
Description
How far after today it reaches, for scheduled events.
PluginLinks
The hosts an item record may link to, besides every source's host.
Field
Type
Required
Description
Description
Lowercase host names, such as www.bancentral.gov.do. At most 16.
PluginLimits
Lower limits than the defaults, if your fetcher needs less. They can never be raised.
Field
Type
Required
Description
Description
How long a run may take, 1 to 120. Default 120.
Description
How much memory a run may use, 16 to 256. Default 256.
PluginLicence
Who holds the data and what you may do with it. Readers see the attribution beside every record.
Field
Type
Required
Description
Type
string; 1 to 200 characters
Description
Who publishes the data, such as Banco Central de la República Dominicana.
Type
string; 1 to 40 characters
Description
The short name shown beside its records, such as Banco Central.
Type
string or null; at most 500 characters
Description
A link to the terms the data is published under, or null when there are none to link.
Type
"yes", "no", "unknown"
Description
Whether Kanboombo may keep the records: yes, no (they can be purged) or unknown.
PluginId
A plug-in's id: lowercase letters, digits and hyphens, starting with a letter, 2 to 48 characters. It is also its folder's name, and it is never reused.
•
•
Pattern: ^[a-z][a-z0-9-]{1,47}$
•
PluginKey
A key for a source, a series or a field: lowercase letters, digits, hyphens and underscores, starting with a letter.
•
•
Pattern: ^[a-z][a-z0-9_-]{0,47}$
•
PluginNames
A name in each language the plug-in speaks, keyed by language code. A reader sees their own language, then en, then the first listed.
PluginAudience
public: anyone signed in, and a Mac's proxy. private: the readers set at host.kanboombo.com (people and organizations). local: runs on your Mac only; refused by the Server until its slice ships.
•
Type: "public", "private", "local"
PluginCadence
How often the series has a new record. It tells readers what to expect; it does not schedule anything.
•
Type: "business-day", "daily", "weekly", "monthly", "quarterly", "irregular"
PluginRecordKind
value: numbers on a date. event: something scheduled, happened or cancelled. item: a dated link with a title.
•
Type: "value", "event", "item"
PluginDates
observation: a record's date is the day it describes. publication: the day it was published, with period naming what it describes.
•
Type: "observation", "publication"
PluginWindow
A span relative to the run's today: a number and a unit, d for days or y for years.
•
•
Pattern: ^[0-9]{1,4}[dy]$
•
Limits
The checker's numbers, the same in check and on the Server:
What it holds
Sources one manifest may declare
What it holds
The largest download one source may be (maxBytes), in bytes
What it holds
Characters in a source's url
What it holds
Series one manifest may declare
What it holds
Fields in a value series, and in one value record
What it holds
Hosts in links.hosts
What it holds
Characters in a name, in each language
What it holds
Characters in a series' unit
What it holds
Characters in licence.attribution
What it holds
Characters in licence.holder
What it holds
Characters in licence.terms
What it holds
Records one run may print
What it holds
Characters in a record's period
What it holds
Characters in an event's or an item's id
What it holds
Characters in a title
What it holds
Characters in an item's url
Value
1 to 120; 120 if you set nothing
What it holds
How long one run may take, in seconds (limits.seconds)
Value
16 to 256; 256 if you set nothing
What it holds
How much memory one run may use, in megabytes (limits.megabytes)
What the Server holds a run to
Number
120 seconds and 256 MB. A lower limits.seconds is kept; a lower limits.megabytes is not yet enforced on the Server, though check enforces both
Number
At most 24 (PLG-SCHEDULE-TOO-FREQUENT at upload)
Number
A stored record missing from its snapshot window for 3 runs in a row
What
Withdrawals that wait for a person
Number
More than 10 at once, or more than 1% of a window of 100 or more
What
Days a reader asks for at once
What
Records one run may print
Number
A named IANA zone, up to 100 characters
Contract 1 and its changes
Contract 1 only grows: a field, a stated limit or a check with its own code may be added, and nothing a plug-in relies on is taken away or changes meaning. A change that would break a working plug-in is contract 2, run beside contract 1. A check code is never renamed or reused; a retired one stays in Submission errors.
October 2026. Contract 1, with DOP Economy on readers' days. Added the same week, changing nothing DOP Economy writes nor its digest: $schema (plugin.schema.json); links.hosts; backfillFrom in the run context; fixtures/context.json and fixtures/runs/<case>/; the digest leaving out listing.json, listing/, review.json, .git/, .DS_Store, AGENTS.md and CLAUDE.md; and a code from one catalog, with its fix and page, on every problem. The tool's versions are in the CLI.