How Skills and Plugins Operate in the OpenWork Marketplace Ecosystem
In the OpenWork marketplace ecosystem, skills and plugins are stored as encrypted, versioned config objects that agents discover via the unified capability rail and execute entirely within the database—no external network calls required.
OpenWork is an open-source AI-workspace platform that treats skills, plugins, and related resources as extensions published to an organization marketplace. This marketplace functions as the fourth capability source on the OpenWork rail—the set of tools search_capabilities and execute_capability available to agents—supplementing the REST catalog, external MCP connections, and native provider capabilities. Understanding how skills and plugins operate in the OpenWork marketplace ecosystem is essential for admins who want to distribute internal tools and for developers building on the different-ai/openwork source code.
The OpenWork Marketplace as a Capability Source for Skills and Plugins
The OpenWork capability rail exposes exactly two tools—search_capabilities and execute_capability—that consume four underlying sources. The marketplace sits alongside the REST catalog, external MCP connections, and native provider routes, as detailed in docs/marketplace-capabilities-architecture.md and grounded in the generic extension abstraction from docs/extensions-manifest-foundation.md.
When a user queries search_capabilities, the search engine interleaves marketplace matches with the other sources and scores them on title, description, and full-text fields. Each result is identified by a canonical name that follows the pattern plugin:<pluginId>:<configObjectId>.
For example, plugin:12345:skill-abc maps to a specific config object inside a plugin record. Under the hood, these objects are indexed from the database tables defined in den-db/src/schema/sharables/plugin-arch.ts. The marketplace surfaces DB-only config object types such as skill, command, agent, mcp, tool, hook, context, and custom.
Execution Flow for Marketplace Skills and Plugins
When an agent calls execute_capability with a marketplace name, the server runs a deterministic, database-local pipeline. Because the path never makes outbound network requests, it remains fast and isolated. The flow is implemented across the plugin-system store and agent execution layers in ee/apps/den-api/src/routes/org/plugin-system/store.ts and related handlers.
Parse the Capability Identifier
The handler first extracts pluginId and configObjectId from the plugin:<pluginId>:<configObjectId> string using a strict regex. If the name does not match, the request is rejected before any access checks occur.
function parseMarketplaceCapabilityName(name: string) {
const m = /^plugin:([^:]+):([^:]+)$/.exec(name);
if (!m) throw new Error("Invalid marketplace capability");
return { pluginId: m[1], configObjectId: m[2] };
}
Verify Grants and Visibility
Access is enforced through three grant tables: ConfigObjectAccessGrantTable, PluginAccessGrantTable, and MarketplaceAccessGrantTable. A member with viewer rights on the matching grant can both search and execute the object, while organization admins see every marketplace item without restriction.
Load and Decrypt the Latest Version
After access is confirmed, the server pulls the latestVersion record from the ConfigObjectVersion table. It then decrypts the stored rawSourceText or normalizedPayloadJson using the existing encryptedTextColumn logic, keeping skill definitions secure at rest.
Return an Instructional Payload
The final response is an instructional payload that agents consume directly. It carries the kind, plugin and marketplace provenance, name, description, and the full content—such as the complete Markdown body of a skill. Optional status flags like needs_install or content_not_synced and a corresponding hint surface degraded states.
{
"kind": "skill",
"plugin": "Support Operations",
"marketplace": "Acme Marketplace",
"name": "Create shift handoff",
"description": "Creates a handoff report for unresolved tickets.",
"content": "...full skill markdown body...",
"provenance": "Content from marketplace plugin Support Operations in your organization."
}
Because this payload is returned through the standard execute_capability handler, no new tools are added to the agent rail. This preserves the existing API contract while still surfacing rich marketplace content.
Local Installation of Marketplace Skills and Plugins
The desktop client can materialize a marketplace plugin locally by copying its files into the workspace .opencode/ folder. The orchestration logic lives in apps/server/src/cloud-plugins.ts and handles namespace allocation, path mapping, content rendering, and MCP registration.
Namespace and Path Mapping
During installation, the routine derives a pluginNamespace from the plugin’s name or id. It then maps each config object type to a concrete disk path. Skills are written to .opencode/skills/<namespace>/<skill>/SKILL.md, while MCP objects become .opencode/mcps/<namespace>/<name>.json.
function getPluginObjectInstallPath(obj: CloudPluginConfigObject, namespace: string) {
// Returns paths like `.opencode/skills/<namespace>/<skill>/SKILL.md`
// or `.opencode/mcps/<namespace>/<name>.json` for MCP objects.
// (Full implementation in installCloudPlugin)
}
Content Rendering and MCP Registration
For skill objects, the installer calls buildCloudSkillContent to assemble the final Markdown body before writing it to disk. If the plugin defines MCP servers, the client invokes addMcp to register them in the local workspace. Uninstalling a plugin triggers removeMcp and removePluginWorkspaceFile to keep the workspace clean.
Access Control and Kill Switches for Marketplace Skills and Plugins
Marketplace visibility uses the same Connect gating that governs external MCP connections. Organization metadata can disable the entire marketplace capability source by setting a top-level kill-switch flag.
{
"capabilities": {
"mcpConnections": false
}
}
When this flag is active, search_capabilities omits all plugin: matches and execute_capability returns unknown_capability. This guarantees byte-identical behavior for organizations that have opted out and is documented in docs/marketplace-capabilities-architecture.md.
Extending the OpenWork Ecosystem with OpenCode Plugins
OpenWork also supports OpenCode plugins, which are custom tool bundles that live in a workspace’s .opencode/plugins/ directory. These plugins export an async factory that returns a hooks object containing tools, experiment transforms, and other extensions, as shown in .opencode/skills/create-plugin/SKILL.md.
Although OpenCode plugins are distinct from Anthropic plugins, they can be adapted into standard marketplace plugin resources. Once published, they flow through the same discovery and execution pipeline as any other skill or config object in the OpenWork marketplace ecosystem.
Summary
- Config Object Storage: Skills and plugins are stored as versioned config objects inside a plugin record, with schemas defined in
den-db/src/schema/sharables/plugin-arch.ts. - Unified Rail: The marketplace is a fourth capability source on the OpenWork rail, interleaving results from
search_capabilitiesand executing viaexecute_capabilitywithout adding new tools. - Access Control: Visibility is enforced through
ConfigObjectAccessGrantTable,PluginAccessGrantTable, andMarketplaceAccessGrantTable, plus an organization-wide kill switch. - Local Installation: The desktop client installs marketplace plugins into
.opencode/usingapps/server/src/cloud-plugins.ts, rendering skills and registering MCP connections locally. - Zero Network Execution: Marketplace capability execution is database-only, decrypting content on the fly and returning instructional payloads without outbound calls.
Frequently Asked Questions
How are skills and plugins stored in the OpenWork marketplace?
They are stored as config objects within a plugin record inside the organization database. The schema is defined in den-db/src/schema/sharables/plugin-arch.ts, and each object is versioned through the ConfigObjectVersion table. At rest, sensitive fields such as rawSourceText are encrypted using the encryptedTextColumn abstraction.
What happens when an agent executes a marketplace skill?
The agent calls execute_capability with a name like plugin:12345:skill-abc. The server parses the identifier, validates grants against three access tables, loads the latest version, decrypts the source, and returns an instructional payload containing the full skill content and provenance. No external network calls are required because the path is entirely database-local.
Can an organization disable marketplace access entirely?
Yes. An admin can set the organization metadata flag "capabilities": { "mcpConnections": false }, which acts as a kill switch. When disabled, search_capabilities filters out all plugin: results and execute_capability responds with unknown_capability, ensuring opted-out orgs experience identical behavior.
How does local installation work for marketplace plugins?
The desktop client runs the installCloudPlugin routine in apps/server/src/cloud-plugins.ts, which copies config objects into the workspace .opencode/ folder under a derived namespace. Skills become Markdown files, MCP objects trigger addMcp, and removal cleans up via removeMcp and removePluginWorkspaceFile.
Have a question about this repo?
These articles cover the highlights, but your codebase questions are specific. Give your agent direct access to the source. Share this with your agent to get started:
curl -s "https://instagit.com/install.md" Maintain an open-source project? Get it listed too →