DorkOS

Publishing a package

Build an agent, plugin, skill pack, or adapter and share it through the DorkOS Marketplace.

Publishing a package

This page is for people building something to share, not just installing what's already there. If you want to browse and install packages instead, see Marketplace.

A DorkOS package is a folder with a manifest and some content: skills, hooks, commands, or an agent definition. You scaffold it with the CLI, validate it locally, then either keep it private or submit it to the public registry.

What you can publish

Every package is exactly one of four types:

  • Agent - a reusable agent identity: a persona, suggested traits, and starter skills or tasks.
  • Plugin - a Claude Code extension: slash commands, hooks, and DorkOS UI extensions (sidebar widgets, sections on the Activity tab, and the like).
  • Skill pack - a bundle of SKILL.md files that teach an agent how to do something, with no commands or hooks attached.
  • Adapter - a bridge to an external system, like a relay transport for a chat platform or a mesh discovery backend.

Pick the type based on what the package actually does. Defining an agent's identity means agent. Adding commands or UI means plugin. Just teaching a skill means skill-pack. Bridging an outside service means adapter.

Claude Code compatibility, honestly

DorkOS packages are built to be a superset of Claude Code plugins: the registry format and validator are designed so a package that passes DorkOS validation also passes Claude Code's own claude plugin validate. We haven't verified every Claude Code feature end to end inside DorkOS, including every hook type and every MCP (the protocol that lets AI tools call external servers) option. If your package leans on a specific Claude Code feature, test it in both DorkOS and plain Claude Code before you publish.

Anatomy of a package

Every package needs a .dork/manifest.json. This is the file DorkOS reads to know what your package is and what it does.

// .dork/manifest.json
{
  "schemaVersion": 1,
  "name": "my-package", // kebab-case, must match the folder name
  "version": "1.0.0", // semver: MAJOR.MINOR.PATCH
  "type": "plugin", // "agent" | "plugin" | "skill-pack" | "adapter"
  "description": "What it does, one to two sentences.",
  "displayName": "My Package", // optional, shown instead of `name` in the UI
  "author": "Your Name",
  "license": "MIT",
  "tags": ["review", "ci"],
  "category": "code-quality",
  "icon": "🔍",
}

name, version, type, and description are required. Everything else is optional. A few fields worth knowing about:

FieldWhat it's for
repositoryA URL to your source, shown as a link in the package detail sheet.
homepageA URL to docs or a project page, shown the same way.
minDorkosVersionThe oldest DorkOS version your package needs, if it depends on a recent feature.
layersWhich content categories the package contributes: skills, hooks, commands, and so on. Used to filter the browse grid.
requiresOther packages this one depends on, as <type>:<name> (for example adapter:slack).
featuredSet by the registry maintainers, not by you. Ignore it when authoring.

Each type adds its own fields on top of the base manifest:

  • plugin adds extensions: an array of extension IDs your package registers with the DorkOS extension API (for sidebar widgets, Activity tab sections, and similar UI slots).
  • agent adds agentDefaults: an optional persona string describing the agent, a capabilities list, and traits (each scored 1 to 5): verbosity, autonomy, chaos, creativity, humor, and spice.
  • adapter adds adapterType, required: a short identifier for what it bridges to, like "matrix" or "slack".
  • skill-pack adds nothing. The manifest is the whole story.

Packages of every type except agent also need a .claude-plugin/plugin.json, the manifest Claude Code itself reads:

// .claude-plugin/plugin.json
{
  "name": "my-package",
  "version": "1.0.0",
  "description": "What it does."
}

Keep the name, version, and description in sync with .dork/manifest.json. The version must match exactly: if the two files disagree, or plugin.json has no version, validation fails and DorkOS won't install the package. Raise the version in both files whenever you change the package. People who already have it are only offered an update when the version goes up. If your package also defines Claude Code commands, hooks, or MCP servers, add those fields following Claude Code's own plugin manifest format.

Any skills you write live in a directory-based SKILL.md file, with frontmatter naming the skill and describing what it does:

---
name: my-skill
description: One line describing what this skill does.
kind: skill
---

# My Skill

The instructions your agent follows when it uses this skill.

Where your package keeps its settings

People fill in settings, and agents write notes, inside an installed package's folder. DorkOS keeps every file your package didn't ship across updates, reinstalls and uninstalls. So a few habits keep your package's state safe:

  • Write state to ${CLAUDE_PLUGIN_DATA}, the same variable Claude Code gives plugins. In DorkOS it points at the install's own .dork/data folder. There is one for each install, so the same package installed in two projects keeps two sets of settings. It survives updates, and only dorkos uninstall --purge removes it. Your commands and hooks can use it as ${CLAUDE_PLUGIN_DATA} or read the environment variable.

  • Don't write into files you ship. If a person edits one, an update replaces it and saves their copy as <file>.dork-old.

  • Mark shipped defaults that are meant to be edited in .dork/manifest.json. For those files, a person's copy stays and a changed default is saved beside it as <file>.dork-new:

    {
      "userEditable": ["config/defaults.json", "prompts/**"]
    }

    Each entry is an exact path, or a folder followed by /**. Older DorkOS versions ignore the field, so set minDorkosVersion if your package depends on it.

    Files that decide what your package runs can't be marked this way: hooks/, .mcp.json, .lsp.json, monitors/, bin/, .dork/extensions/, .dork/tasks/, skills/, commands/, agents/, output-styles/, a root SKILL.md, package.json, the folders coding agents read their settings from (.claude/, .agents/, .codex/, .opencode/, .gemini/, opencode.json, opencode.jsonc), and any other place your plugin.json points these at. When someone updates your package, they approve exactly what the new version runs, so an edited copy of one of these files must never be kept in its place.

  • Don't ship these paths. They belong to the person or to DorkOS, and validation refuses a package that includes them: .dork/data/, .dork/secrets.json, .dork/install-metadata.json, .dork/installed-files.json, .dork/uninstalled-agent.json, .dork/saved/, and any file ending in .dork-old or .dork-new.

  • An agent package can't ship settings for its own chats. An agent's package folder is also the folder its chats run in, so Claude Code, Codex and OpenCode would load any settings there without anyone seeing them. Validation refuses an agent package that includes:

    • .claude/settings.json or .claude/settings.local.json;
    • a top-level .mcp.json;
    • .codex/;
    • opencode.json, opencode.jsonc or .opencode/;
    • .agents/harness.manifest.json;
    • Gemini CLI's .gemini/settings.json;
    • a .claude folder anywhere below the top of the package;
    • a subagent in .claude/agents/ that sets hooks, mcpServers or permissionMode, or whose header isn't plain YAML with each setting once.

    Instructions (CLAUDE.md, AGENTS.md, .claude/rules/), output styles and skills (.claude/skills/, .claude/commands/, .agents/skills/) are fine: the install screen shows what each skill may do without asking. For hooks or servers, ship a plugin your agent requires, so a person approves them.

  • Dependencies you declare in package.json are already installed into your package's own node_modules, so you don't need to install them into the data folder yourself.

What DorkOS will read from your package

DorkOS reads your package's files to check it and to show people what it does before they install it. It keeps those reads inside a few limits, so one odd file can't slow it down or point it somewhere else:

  • Frontmatter is YAML or JSON. The header between the --- lines in a SKILL.md or command file is read as YAML, or as JSON when it starts with ---json. A header in any other language (such as ---js) is refused, never run.
  • Keep headers small. A header over 32 KB is refused, and so is one that uses more than 100 YAML aliases or expands into something huge. Real headers are a few KB at most.
  • Text files up to 1 MB. DorkOS stops reading a SKILL.md, README or manifest past 1 MB and reports the file as too large. A marketplace.json or dorkos.json catalog can be up to 5 MB.
  • Links aren't installed. DorkOS never follows a symbolic link inside a package. Validation warns about each one, the install preview lists them, and they are left out of the installed copy. Ship the real file instead.

Scaffolding a new package

The dorkos CLI can generate the starting files for you:

dorkos package init my-package --type plugin
Created package at: /path/to/my-package
Files written:
  - .dork/manifest.json
  - .claude-plugin/plugin.json
  - README.md

--type accepts agent, plugin, skill-pack, or adapter (defaults to plugin if you leave it out). A few more flags:

dorkos package init my-adapter \
  --type adapter \
  --parent-dir ./packages \
  --description "Bridges DorkOS to Matrix" \
  --author "Your Name" \
  --adapter-type matrix

--parent-dir chooses where the package folder is created (defaults to your current directory). --adapter-type only matters for adapter packages; it defaults to the package name if you skip it.

If you're chatting with an agent connected to DorkOS instead of using a terminal, it can scaffold a package for you into your personal marketplace (see below) using the same scaffolder under the hood. Either path produces the same files.

Validating locally

Before you go further, check that the manifest and any skills are well-formed:

dorkos package validate
Package: my-package@1.0.0 (plugin)
✓ Package is valid

If something's wrong, you get one line per issue with a code you can look up, like MANIFEST_SCHEMA_INVALID or SKILL_INVALID. Warnings (for example, a package folder whose name doesn't match manifest.name) don't block you; errors do. Run it from inside the package folder, or pass a path:

dorkos package validate ./packages/my-package

Trying it out before you publish

Every DorkOS install has a personal marketplace at ~/.dork/personal-marketplace/, created automatically the first time the server starts. It's registered as a source named personal, so anything you drop into its packages/ folder (or scaffold there) is installable right away, without touching the public registry:

dorkos install my-package@personal

This is the fastest loop for iterating: scaffold, edit, validate, install, repeat. Nothing leaves your machine.

You can also register any git repo as your own private source, which is useful for sharing a package across a team before (or instead of) submitting it publicly:

# Add a source pointing at your repo
dorkos marketplace add https://github.com/your-team/marketplace --name your-team

# Confirm it shows up
dorkos marketplace list

# Install a package from it
dorkos install my-package@your-team

A source is just a git repo with a marketplace.json file, at its root or in a .claude-plugin/ folder, listing one or more packages. dorkos install <name>@<marketplace> looks up <name> in that specific source; leave off the @<marketplace> part and DorkOS searches every source you have enabled.

Publishing to the public registry

The official marketplace lives in the dork-labs/marketplace repo. Packages there are listed in two files that work together: marketplace.json (the Claude-Code-standard registry format) and a dorkos.json sidecar next to it (DorkOS-specific extras like type, layers, and icon, which Claude Code's schema doesn't allow inline).

Fork and add your package

Fork the repo, then add your package under plugins/<your-package-name>/.

Register it in both files

Add an entry to .claude-plugin/marketplace.json:

{
  "name": "my-package",
  "source": "./plugins/my-package", // must start with "./plugins/"
  "description": "What it does",
  "author": { "name": "Your Name" },
  "license": "MIT",
}

And a matching entry in .claude-plugin/dorkos.json:

{
  "my-package": {
    "type": "plugin",
    "layers": ["skills", "extensions"],
    "icon": "🔍",
  },
}

Validate the registry, not just your package

dorkos package validate ./plugins/my-package
dorkos marketplace validate ./.claude-plugin/marketplace.json

The second command checks the whole registry file: your entry's shape, that reserved names weren't used, and that the file still passes Claude Code's own strict schema. Exit code 2 means your entry works for DorkOS but would fail Claude Code's plugin validator, so move the offending field into the dorkos.json sidecar and try again.

Open a pull request

Open a PR against main with both files updated. Once it merges, your package is live: anyone with the dorkos-community source enabled (the default) can find and install it.

Testing end to end

Before you open that PR, run through the install as a stranger would:

  1. Point a clean DorkOS instance (or one where you've removed the package) at your fork: dorkos marketplace add https://github.com/you/your-fork --name test.
  2. Install it: dorkos install my-package@test.
  3. Confirm the permission preview shown before install matches what your package actually does. If it asks for less (or more) than expected, that's a manifest problem, not a DorkOS bug.
  4. Open a chat and confirm your skills, commands, or hooks actually run.
  5. If you shipped a plugin with extensions, check that it shows up in the slot it registered for, like the right-hand panel or the Activity tab.

A package that only validates but was never actually installed and run is not a tested package. The validator checks shape; only a real install checks behavior.

Next steps