Publishing to the Addon Registry
The phpVMS addon registry is the central index of community addons. Once your addon is registered, operators can discover and install it directly from their phpVMS admin UI — they never need to clone repos or run composer commands.
This guide is the short reference. The full plugin authors guide in the registry repo is the authoritative source.
Prerequisites
Before submitting:
- A public GitHub repository for your addon.
- At least one published GitHub release with a zip asset attached.
- The zip contains
module.jsonat its root (not inside a subdirectory). - The zip's
module.jsondeclares aregistry_idequal to your registry name (for example,acme/reports). See Addingregistry_idto module.json below. - All migrations under
database/migrations/follow the migration rules.
Adding registry_id to module.json
The alias field in module.json is restricted to lowercase identifiers
(letters, digits, underscores) because Laravel uses it as the namespace
for views, configs, and translations — for example view('reports::index').
Registry names use the {author}/{package} form, which is not a legal
alias.
Add a separate registry_id field to module.json so the registry can
match your addon to its YAML entry:
{
"name": "Reports",
"alias": "reports",
"registry_id": "acme/reports",
"description": "KPIs, route performance, scheduled exports.",
"keywords": ["reports", "analytics"],
"priority": 0,
"providers": [
"Modules\\Reports\\Providers\\ReportsServiceProvider"
],
"files": []
}
name— display name. Free-form.alias— Laravel namespace. Lowercase, no slashes.registry_id— must equal thename:value in yourpackages/{author}/{name}.yml.
What you submit
A single YAML file at packages/{author}/{name}.yml describing your
addon. You do not submit a release: block — the registry's bot
queries your GitHub releases and adds it after merge.
If your namespace doesn't exist yet, also submit
packages/{author}/meta.yml in the same PR.
Naming rules
Registry names use the form {author}/{package}:
- Lowercase letters, digits, and hyphens only.
- Each segment is at least two characters.
- No underscores, no uppercase, no periods.
- The slug
metais reserved (it denotes namespace metadata).
Conventions (recommended, not enforced):
- The
{author}segment should match your GitHub username or organisation. This keeps ownership unambiguous and makes the source repo easy to find. - The
{package}segment should match the GitHub repository name of the addon source. So an addon hosted athttps://github.com/acme/reports-addonis best registered asacme/reports-addon.
Examples that follow the convention: acme/reports,
phpvms/core-tools, crew-tools/dispatch.
Minimal package YAML
# packages/acme/reports.yml
name: acme/reports
description: Reports addon for phpVMS — KPIs, route performance, scheduled exports.
category: reporting
license: MIT
keywords:
- reports
- analytics
- dashboard
source:
type: github-release
repository: acme/reports-addon
requirements:
php: '>=8.3'
phpvms: '>=7.0.0'
That's the entire submission. The bot resolves the release: block after
merge.
Allowed category values
Pick exactly one. The current list lives in
schema/categories.yml:
accountingcommunicationscrewdev-toolsintegrationoperationspirepsreportingschedulingtemplatesuiwidgetother
To request a new category, open a separate PR adding it to that file before submitting your package YAML.
meta.yml (first-time author)
If your namespace is new (no other addons under packages/{author}/),
include packages/{author}/meta.yml in the same PR:
# packages/acme/meta.yml
name: Acme Corp
url: https://acme.example.com
maintainers:
- acme-dev
- jdoe
maintainers is a list of GitHub usernames. The first listed is treated
as the primary contact.
What CI checks at PR time
- Schema — required fields, valid
nameregex, allowed category, requirements present. - Filename matches name —
acme/reportslives atpackages/acme/reports.yml, no exceptions. - Source repo exists and is public.
- Latest release — at least one published release with a zip asset.
- Zip integrity — downloadable, contains
module.jsonat the root, no forbidden paths (.git/,.github/,tests/,node_modules/,.idea/,.vscode/,.DS_Store,Tests/). - module.json — schema-valid;
registry_idequals the registry name. - Migration lint — see Migration rules.
The validator posts a single comment summarising results. If everything
passes, the comment includes the proposed release: block.
What happens after merge
- The
release-blockworkflow opens an auto-merging bot PR appending the resolvedrelease:block to your YAML. - The
publishworkflow buildsraw/packages.jsonandraw/keywords.json, uploads them to R2, and refreshes the worker's edge cache. - Hosts polling the read API see your addon within a few minutes.
- Subsequent releases on your repo are picked up by the discovery sweep (cron every 6h, plus push triggers from the worker).
Updating your addon
Tag a new release on your GitHub repo. The discovery sweep opens an
auto-merging bot/bump-{author}-{name}-{version} PR within hours.
You do not interact with the registry repository for routine updates.
Marking an addon revoked or archived
Revocation and archival are maintainer actions, not author actions. See
revocation.md
in the registry repo for the process.