Plugins & Extensions

Zync has a decentralized extension system. Plugins run in sandboxed Web Workers or iframe panels and communicate with the app through a clean zync API — no native code required.

How It Works

Every plugin is a .zip archive containing at minimum:

  • manifest.json — declares the plugin's identity, version, and capabilities.
  • main.js — your plugin logic, executed inside a Web Worker with access to the zync global API.

Plugins come in two flavours:

  • Background plugins — run in a Web Worker, no visible UI. Good for commands, status bar widgets, SSH automation.
  • Panel plugins — register a full HTML/CSS/JS interface rendered in a sandboxed iframe inside Zync's tab bar. Good for dashboards, monitoring tools, custom file managers.

manifest.json

Every plugin must have a manifest.json at the root of its .zip. The id must follow reverse-DNS format and be globally unique.

json·manifest.json
{  "id": "com.yourname.plugin.my-plugin",  "name": "My Plugin",  "version": "1.0.0",  "description": "A short description shown in the marketplace.",  "author": "Your Name",  "main": "main.js",  "permissions": ["terminal", "statusBar", "ui", "panel", "ssh"]}

For themes, add the theme-specific fields instead of main:

json·manifest.json (theme)
{  "id": "com.yourname.theme.my-theme",  "name": "My Theme",  "version": "1.0.0",  "description": "A beautiful dark theme.",  "author": "Your Name",  "style": "theme.css",  "mode": "dark",  "preview_bg": "#0f111a",  "preview_accent": "#6366f1"}

The zync API

When your main.js runs, the global zync object is available. All async methods return Promises.

Lifecycle

bash·main.js
zync.on('ready', function() {  // Called once when the plugin is fully initialized.  // Register commands and panels here.  zync.logger.log('[my-plugin] ready');});

Command Palette

Register commands that appear in Zync's command palette (Cmd+K / Ctrl+K).

bash·main.js
zync.commands.register('my-plugin.ping', 'My Plugin: Ping Server', async function() {  const output = await zync.ssh.exec('ping -c 4 8.8.8.8');  zync.ui.notify({ type: 'info', body: output });});

Terminal

bash·main.js
// Write text to the active terminalzync.terminal.send('ls -la');// Open a new terminal tab and run a commandzync.terminal.newTab({ command: 'htop' });

SSH Exec

Run commands on the active SSH connection and get back the output as a string.

bash·main.js
const uptime = await zync.ssh.exec('uptime -p');zync.ui.notify({ type: 'success', body: uptime });

Status Bar

bash·main.js
// Set a persistent status bar widgetzync.statusBar.set('my-plugin', '⚡ 12% CPU');// Update it on an intervalsetInterval(async () => {  const stat = await zync.ssh.exec("top -bn1 | grep 'Cpu' | awk '{print $2}'");  zync.statusBar.set('my-plugin', stat.trim() + '% CPU');}, 5000);

Notifications & Dialogs

bash·main.js
// Toast notifications: success | error | info | warningzync.ui.notify({ type: 'success', body: 'Deployment complete!' });// Confirm dialog  returns Promise<boolean>const ok = await zync.ui.confirm({  title: 'Restart Nginx?',  message: 'This will briefly interrupt traffic.',  variant: 'danger',});if (ok) await zync.ssh.exec('sudo systemctl restart nginx');

Panel Plugins (Full UI)

Call zync.panel.register to mount a full HTML interface as a tab inside Zync. The panel runs in a sandboxed iframe with a postMessage bridge back to the zync API.

bash·main.js
zync.on('ready', function() {  const html = `<!DOCTYPE html><html>  <head>    <style>      body { font-family: sans-serif; background: #09090b; color: #fff; padding: 16px; }      button { background: #6366f1; color: #fff; border: none; padding: 8px 16px; border-radius: 6px; cursor: pointer; }    </style>  </head>  <body>    <h2>My Panel</h2>    <button onclick="runCommand()">Run uptime</button>    <pre id="out"></pre>    <script>      async function runCommand() {        const result = await window.zync.ssh.exec('uptime');        document.getElementById('out').textContent = result;      }    </script>  </body></html>`;  zync.panel.register('my-plugin.panel', 'My Panel', html);});

For complex panels, compile a full React or Vue app to a single HTML string (e.g. with Webpack html-webpack-plugin + inline-source). See the open-source pm2-monitor plugin in the zync-extensions repo for a complete example.

Packaging Your Plugin

Zip the plugin directory so that manifest.json is at the root of the archive (not inside a subfolder):

bash·Terminal
 # From inside your plugin directory:$zip -r my-plugin.zip manifest.json main.js  # Or if you have extra assets:$zip -r my-plugin.zip manifest.json main.js assets/

The zip must be hosted at a publicly accessible URL so Zync can download and install it.

Publishing to the Official Marketplace

The official marketplace is the zync-extensions GitHub repository. To list your plugin:

  1. Fork github.com/gajendraxdev/zync-extensions.
  2. Add your plugin files under plugins/your-plugin-id/.
  3. Upload the .zip to a permanent public URL (GitHub Releases on your own repo works well).
  4. Add your entry to marketplace.json:
json·marketplace.json entry
{  "id": "com.yourname.plugin.my-plugin",  "name": "My Plugin",  "version": "1.0.0",  "description": "What it does in one sentence.",  "author": "Your Name",  "type": "plugin",  "downloadUrl": "https://github.com/yourname/my-plugin/releases/latest/download/my-plugin.zip"}
  1. Open a Pull Request. Once merged your plugin appears in the in-app marketplace for all users.

Self-Hosted Registry

You don't have to use the official repository. Anyone can host their own plugin registry — a plain JSON file served over HTTPS — and users can point Zync at it from Settings. This is useful for private company plugins, beta channels, or curated plugin sets.

1. Create your marketplace.json

Your registry file must be a JSON array (or an object with a plugins key). Host it anywhere that returns the raw JSON over HTTPS — a GitHub repo, a CDN, or your own server.

json·marketplace.json
[  {    "id": "com.yourcompany.plugin.deploy",    "name": "One-Click Deploy",    "version": "2.1.0",    "description": "Deploy to staging with a single command.",    "author": "Acme Corp",    "type": "plugin",    "downloadUrl": "https://cdn.yourcompany.com/plugins/deploy-2.1.0.zip"  }]

2. Host it at a public URL

The simplest approach is a public GitHub repository — your raw URL will look like:

bash
https://raw.githubusercontent.com/yourname/your-repo/main/marketplace.json

3. Add the registry URL in Zync

In Zync, open Settings → Extensions and paste your registry URL. Zync will fetch it alongside the official marketplace and merge the results. Users on your team only need to add the URL once.

Format requirements

Zync accepts two formats for the registry file:

  • Flat array[ { ...plugin }, ... ]
  • Object with keys{ "plugins": [...], "themes": [...] }

Each entry must have at minimum: id, name, version, and downloadUrl.