The official registry and submission hub for Dot X plugins.
This repository serves as the official plugin marketplace for Dot X.
-
Source Register (
plugins-source.json)- The single source of truth for developer submissions
- Developers submit PRs to modify this file
- Contains plugin metadata: id, name, author, description, repo, tags
-
Final Register (
dist/marketplace-registry.json)- The read-only registry consumed by Dot X
- Generated automatically by GitHub Actions
- Hosted via GitHub Pages
- Includes integrity hashes and verified permissions
-
GitHub Actions Workflows
- PR Validation: Validates submissions before merge
- Registry Generation: Automatically builds and deploys the registry
- SHA-256 hash calculated at approval time
- Hash covers the raw
plugin.zipbytes - App verifies hash before installation
- Any byte change invalidates the hash and blocks installation
- Tracks approved permissions for each plugin version
- If permissions expand during scheduled updates, creates a security review PR
- Requires human approval for permission changes
- Your plugin must be published as a GitHub Release
- The latest release must include:
plugin.zip- A self-contained plugin package zip
- The
idfield in yourmanifest.jsonmust match theidyou specify inplugins-source.json
The Dot X marketplace installer downloads exactly one package asset per release:
plugin.zip
If plugin.zip is not present, registry validation falls back to the only .zip asset in the release, but only when there is exactly one zip asset total. If there are multiple zip assets and none is named plugin.zip, validation fails.
The archive root must contain:
manifest.jsonmain.js
The archive may also contain additional files and directories, such as:
bin/windows-x64/...bin/windows-arm64/...bin/macos-x64/...bin/macos-arm64/...bin/linux-x64/...assets/...data/...
-
Fork this repository
-
Add your plugin to
plugins-source.json:{ "$schema": "./schemas/plugins-source.schema.json", "plugins": [ { "id": "my-awesome-plugin", "name": "My Awesome Plugin", "author": "Your Name", "description": "A plugin that does awesome things", "repo": "https://github.com/username/my-awesome-plugin", "tags": ["productivity", "ui"], "funding_url": "https://github.com/sponsors/username" } ] } -
Create a Pull Request
- The PR validation workflow will automatically:
- Validate JSON schema
- Verify the GitHub repo and latest release exist
- Select
plugin.zip, or fall back to the only zip asset in the release if exactly one exists - Open the package and verify root
manifest.jsonandmain.js - Verify the
idinmanifest.jsonmatches your submission - Post a comment listing detected permissions
- The PR validation workflow will automatically:
-
Wait for Review
- Maintainers will review your submission
- Once approved and merged, the registry will be automatically updated
Your manifest.json must be included inside plugin.zip and should follow this structure:
{
"id": "my-awesome-plugin",
"name": "My Awesome Plugin",
"version": "1.0.0",
"description": "Plugin description",
"author": "Your Name",
"dotxVersion": ">=1.0.0",
"main": "main.js",
"permissions": [
"env"
],
"license": "MIT"
}Required Fields:
id- Must match theidinplugins-source.jsonname- Display name for your pluginversion- Plugin version (semver)description- Short descriptionauthor- Author namedotxVersion- Minimum Dot X version requirement (e.g., ">=1.0.0")permissions- Array of permission strings
Common Permissions:
env- Environment variable accessnet- Network accessread- File system read accesswrite- File system write accessrun- Subprocess executionffi- Foreign function interface access
Note: The registry automatically uses the latest release from your repository. Make sure the latest release includes plugin.zip, or exactly one zip asset that contains root manifest.json and main.js.
Before you publish a GitHub Release, make sure:
- Your plugin is built to a single
main.jsbundle. manifest.jsonreferences the compiled entrypoint with"main": "main.js".- Place
manifest.json,main.js, and any required binaries/assets into a staging directory. - Create
plugin.zipfrom that staging directory, withmanifest.jsonandmain.jsat the archive root. - The
idinmanifest.jsonmatches theidinplugins-source.json. - The latest release is the one you want Dot X to install from.
If you currently publish from GitHub Releases, you do not need a different hosting setup. You only need to make sure the release contains a self-contained zip package.
{
plugins: Array<{
id: string; // Unique plugin ID (must match manifest.json)
name: string; // Display name
author: string; // Author name
description: string; // Plugin description
repo: string; // GitHub repository URL
tags: string[]; // Array of tags
funding_url?: string; // Optional funding/sponsorship URL
}>
}{
generated_at: string;
plugins: Array<{
id: string; // Plugin ID
name: string; // Display name
description: string; // Description
repo: string; // Repository URL
version: string; // Plugin version from packaged manifest.json
dotxVersion: string | null; // Minimum Dot X version from manifest
tags: string[]; // Tags
author: string; // Author
funding_url?: string; // Optional funding URL
package_url: string; // URL to plugin.zip asset
package_format: "zip"; // Package format
package_integrity_hash: string; // SHA-256 hash of plugin.zip bytes
package_size?: number; // Package size in bytes
approved_permissions: string[]; // Approved permissions
likes: number; // Like count
downloads: number; // Download count
}>
}Trigger: Pull requests targeting plugins-source.json
Actions:
- Validates JSON schema
- Verifies GitHub repo and latest release exist
- Selects
plugin.zip, or falls back to the only zip asset in the release if exactly one exists - Opens the package and verifies root
manifest.jsonandmain.js - Verifies
manifest.jsonid matches the submission - Extracts permissions from the packaged manifest
- Posts PR comment with permission summary
Triggers:
- Scheduled: Every 4 hours
- Push to main branch (when
plugins-source.jsonchanges) - Manual dispatch
Actions:
- Loads source and existing registry
- For each plugin:
- Fetches the latest GitHub release
- Selects
plugin.zipor the only zip asset, downloads it, hashes the raw archive, opens the package, and extractsversion, permissions, anddotxVersion - If packaged version unchanged: updates mutable fields (name, description, tags, etc.) only
- If packaged version changed: updates the registry entry to the new package metadata
- Creates security review PR if permissions expanded during scheduled update
- Fetches the latest
likesanddownloadsfrom Supabase and merges them intodist/marketplace-registry.json - Deploys to GitHub Pages
- Commits changes to repository
The registry is available at:
https://<user>.github.io/dot-x-plugins/marketplace-registry.json
The registry prevents "Trojanning" attacks through immutable hashes, hash verification, and permission tracking. Permission expansions detected during scheduled updates automatically trigger a security review PR requiring human approval.
-
Install dependencies:
npm install
-
Validate schema:
node .github/scripts/validate-schema.js
-
Test registry generation (requires GITHUB_TOKEN):
GITHUB_TOKEN=your_token node .github/scripts/generate-registry.js
-
Apply the stats schema and deploy the functions with the Supabase CLI:
npx supabase db push npx supabase functions deploy set-plugin-like npx supabase functions deploy record-plugin-download
Contributions are welcome! Please:
- Follow the existing code style
- Ensure all workflows pass
- Update documentation as needed
- Test your changes locally when possible
MIT. See LICENSE.