> ## Documentation Index
> Fetch the complete documentation index at: https://ocx.kdco.dev/docs/llms.txt
> Use this file to discover all available pages before exploring further.

# Creating Registries

> How to build, structure, and distribute your own OCX component registry

## Overview

OCX registries are collections of components (agents, skills, plugins, commands) distributed as JSON packuments. This guide covers how to build and distribute your own registry.

<Note>
  For the HTTP API specification that registries must implement, see the [Registry Protocol](/docs/registries/protocol).
</Note>

## Quick Start (Cloudflare Workers)

The fastest path is to scaffold a registry project and deploy to Cloudflare Workers:

```bash theme={null}
# Scaffold the registry
ocx init --registry ./my-registry --namespace my-org --author "My Name"

# Build the registry (generates dist/)
cd my-registry && bun run build

# Deploy to Cloudflare Workers
bun run deploy
```

The build step runs `ocx build . --out dist` which:

1. Validates `registry.jsonc` against the schema
2. Generates `index.json` and component packuments
3. Copies component files to `dist/components/`
4. Generates `.well-known/ocx.json` (optional discovery metadata)

`ocx init --namespace` is a scaffolding input (naming/template convenience). Runtime component refs still use the registry alias chosen by the user via `ocx registry add --name <alias>`.

## Registry Philosophy

OCX follows the **Cargo + ShadCN model**:

1. **Registry Name as Identity**: Users configure registry names with `ocx registry add --name <name>` and reference components as `name/component` (e.g., `kdco/researcher`).
2. **Clean Component Names**: Components within a registry use clean names (`researcher`, not `kdco-researcher`). The registry name provides provenance.
3. **Explicit Trust**: Cross-registry dependencies require the user to have that registry configured. No auto-fetching from unknown sources.
4. **Own Your Code**: Components are copied into your project with clean filenames. The receipt file tracks provenance.

## Directory Structure

A registry source directory should look like this:

```
my-registry/
├── registry.jsonc    # Registry manifest
└── files/            # Component source files
    ├── agents/
    ├── plugins/
    ├── skills/
    └── commands/
```

## Registry Manifest (`registry.jsonc`)

OCX uses **Cargo-style union types** for a clean developer experience: use strings for simple cases, objects when you need more control.

```jsonc theme={null}
{
  "$schema": "https://ocx.kdco.dev/schemas/v2/registry.json",
  "name": "My Extensions",
  "version": "1.0.0",
  "author": "Your Name",
  "components": [
    {
      "name": "cool-plugin",
      "type": "plugin",
      "description": "Does something cool",
      "files": ["plugins/my-cool-plugin.ts"],
      "dependencies": []
    }
  ]
}
```

**Key fields:**

* `$schema`: Required for OCX v2 manifests. Use `https://ocx.kdco.dev/schemas/v2/registry.json`.
* `name`: Registry display name (human-readable metadata for the registry itself).
* **Registry alias**: Component resolution uses the alias configured by the user at install time (`ocx registry add <url> --name <alias>`). Do not add a top-level `namespace` field in v2 manifests.
* `dependencies`: Use bare names for same-registry deps (`["utils"]`), qualified names for cross-registry (`["other/utils"]`).

## Component Types

| Type      | Target Directory | Description                                               |
| --------- | ---------------- | --------------------------------------------------------- |
| `agent`   | `agents/`        | Markdown files defining specialized agents                |
| `skill`   | `skills/`        | Instruction sets (must follow `skills/<name>/SKILL.md`)   |
| `plugin`  | `plugins/`       | TypeScript/JavaScript extensions for tools and hooks      |
| `command` | `commands/`      | Markdown templates for TUI commands                       |
| `tool`    | `tools/`         | Custom tool implementations                               |
| `bundle`  | N/A              | Virtual components that install multiple other components |
| `profile` | N/A              | Shareable profile configuration                           |

## Cargo-Style Patterns

### File References

Use string shorthand when the target can be auto-inferred:

```jsonc theme={null}
// String shorthand (recommended)
"files": ["plugins/my-plugin.ts"]
// Expands to: { "path": "plugins/my-plugin.ts", "target": "plugins/my-plugin.ts" }

// Full object (when you need a custom target)
"files": [
  {
    "path": "skills/my-skill/SKILL.md",
    "target": "skills/my-skill/SKILL.md"
  }
]
```

### MCP Server Shorthand

MCP servers use URL shorthand for remote servers:

```jsonc theme={null}
"opencode": {
  "mcp": {
    "context7": "https://mcp.context7.com/mcp"
  }
}
// Expands to: { "type": "remote", "url": "https://...", "enabled": true }
```

### OpenCode Config Block

Components can specify settings to merge into the user's `opencode.jsonc`:

```jsonc theme={null}
{
  "name": "my-agent",
  "type": "agent",
  "files": ["agents/my-agent.md"],
  "opencode": {
    "plugin": ["@some-org/opencode-plugin"],
    "tools": { "webfetch": false },
    "agent": {
      "my-agent": { "temperature": 0.7 }
    }
  }
}
```

| Field                   | Description                                                      |
| ----------------------- | ---------------------------------------------------------------- |
| `opencode.mcp`          | MCP servers (URL shorthand or full config)                       |
| `opencode.plugin`       | npm packages added to `opencode.jsonc` plugin array              |
| `opencode.tools`        | Global tool enable/disable settings                              |
| `opencode.agent`        | Per-agent configuration (tools, temperature, permission, prompt) |
| `opencode.permission`   | Permission settings for bash/edit/mcp                            |
| `opencode.instructions` | Global instructions appended to config                           |

## Plugin Discovery vs Registration

OpenCode handles plugins in two ways:

### File-Based Plugins (Auto-Discovered)

Registry components with `type: "plugin"` install files to the `plugins/` directory. OpenCode **automatically discovers** them — no configuration needed.

```bash theme={null}
ocx add kdco/workspace-plugin
# Installs to: plugins/workspace-plugin.ts
# OpenCode auto-discovers it
```

### npm Plugins (Explicitly Registered)

npm plugins installed via `ocx add npm:package-name` require registration in `opencode.jsonc`:

```bash theme={null}
ocx add npm:@franlol/opencode-md-table-formatter
# Adds to opencode.jsonc: {"plugin": ["@franlol/opencode-md-table-formatter"]}
```

## Instruction Files for Components

### Config-Based Instructions (Recommended)

Use custom paths with the `instructions` config field:

```jsonc theme={null}
{
  "name": "my-component",
  "type": "bundle",
  "files": ["instructions/my-guidelines.md"],
  "opencode": {
    "instructions": ["instructions/my-guidelines.md"]
  }
}
```

**Path Resolution for Registry Components:**

* Paths are **install-root-relative** (not cwd-relative)
* OCX resolves them to absolute paths at runtime
* **Absolute paths are NOT allowed**

When installed, `instructions/style-guide.md` resolves to:

* **Project**: `.opencode/instructions/style-guide.md`
* **Profile**: `~/.config/opencode/profiles/myprofile/instructions/style-guide.md`
* **Global**: `~/.config/opencode/instructions/style-guide.md`

<Warning>
  Do **not** install instruction files to `AGENTS.md`, `CLAUDE.md`, or `CONTEXT.md` in standard locations. These are reserved for user project-specific instructions and can cause conflicts.
</Warning>

## Dependencies

### Same-Registry Dependencies

Use bare component names:

```jsonc theme={null}
{
  "name": "researcher",
  "dependencies": ["background-agents", "utils"]
}
```

### Cross-Registry Dependencies

Use qualified names:

```jsonc theme={null}
{
  "name": "researcher",
  "dependencies": ["background-agents", "acme/shared-utils"]
}
```

The user must have the `acme` registry configured in their `ocx.jsonc` for cross-registry deps to resolve.

## Building

Use the OCX CLI to validate and build your registry:

```bash theme={null}
ocx build ./my-registry --out dist
```

This validates your `registry.jsonc`, verifies dependencies, and generates `index.json` plus individual packument files.

## Distribution

OCX registries are static JSON files that can be hosted anywhere:

### Cloudflare Workers (Recommended)

```jsonc theme={null}
// wrangler.jsonc
{
  "name": "my-registry",
  "assets": { "directory": "./dist" }
}
```

Deploy with `wrangler deploy` after building.

### Other Hosting Options

* **GitHub Pages**, **Vercel**, **Netlify** — Pre-build with `ocx build`
* **Any HTTP server** — Serve the `dist/` directory as static files

### Registry Discovery (Optional)

Add a `/.well-known/ocx.json` endpoint to enable automatic discovery:

```jsonc theme={null}
{
  "registry": "/index.json"
}
```

OCX currently validates registries by requesting `<url>/index.json` directly during `ocx registry add`; it does not resolve `/.well-known/ocx.json` automatically in that path.

Use a URL whose `/index.json` is directly available:

```bash theme={null}
ocx registry add https://example.com --name my
```

### Adding and Using Registries

```bash theme={null}
# Add the registry
ocx registry add https://example.com/registry --name my

# Install components
ocx add my/cool-plugin
```

## Conflict Handling

If installing a component would overwrite an existing file from a different component:

```bash theme={null}
$ ocx add acme/researcher
Error: File conflict detected
  agents/researcher.md already exists (installed from kdco/researcher)

To resolve:
  1. Remove existing file and update receipt
  2. Or rename existing file manually
  3. Then retry: ocx add acme/researcher
```

## See Also

* [Registry Protocol](/docs/registries/protocol) — HTTP API specification for OCX registries.
* [ocx build](/docs/cli/build) — CLI command reference for building registries.
* [ocx init](/docs/cli/init) — Scaffold a new registry project with `--registry`.
