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

# Custom Registries

> Host and distribute custom agent skills and context bundles with custom registries

BRV Hub supports custom registries beyond the official `hub.byterover.dev`.
Create your own custom private registry to distribute internal skills and bundles across your team,
then register it with the BRV CLI to browse and install entries alongside the official catalog.

All registries are fetched in parallel with graceful degradation — if a private registry is unreachable, others continue to work normally.

<Note>
  The official registry is always included and cannot be removed.
</Note>

## Hosting Your Own Registry

The [BRV Hub repository](https://github.com/campfirein/brv-hub) is an open-source, zero-backend registry template.
Clone it to host your own private registry of agent skills and context bundles, using GitHub Actions for validation and automatic `registry.json` generation.

<Note>
  The BRV Hub template is MIT-licensed. You can clone it into a private repository for internal use.
</Note>

### Step-by-Step Setup

<Steps>
  <Step title="Clone the BRV Hub template">
    For a **public** registry, fork the repo directly on GitHub and clone it:

    ```bash theme={null}
    gh repo fork campfirein/brv-hub --clone --remote
    cd brv-hub
    npm install
    ```

    For a **private** registry, clone the template and push to a new private repo
    (GitHub does not allow forking a public repo into a private repo):

    ```bash theme={null}
    git clone https://github.com/campfirein/brv-hub.git my-hub
    cd my-hub
    rm -rf .git
    git init
    gh repo create your-org/my-hub --private --source . --push
    npm install
    ```

    <Tip>
      Alternatively, use GitHub's [Import repository](https://github.com/new/import) feature to import `https://github.com/campfirein/brv-hub` into a new private repo.
    </Tip>
  </Step>

  <Step title="Configure your registry URLs">
    Open `scripts/update-registry.js`. The official hub uses proxy routes (`/r/` for downloads, `/v/` for viewing) that don't exist on GitHub, GitLab, or self-hosted platforms. You need to update the base URL **and** the URL patterns to match your hosting platform.

    **Line 5** — change the base URL constant:

    ```javascript theme={null}
    // Before (official hub)
    const HUB_BASE_URL = "https://hub.byterover.dev";

    // After — GitHub
    const HUB_BASE_URL = "https://github.com/your-org/your-hub/tree/main";

    // After — GitLab
    const HUB_BASE_URL = "https://gitlab.com/your-org/your-hub/-/tree/main";

    // After — self-hosted
    const HUB_BASE_URL = "https://registry.yourcompany.com";
    ```

    For GitHub and GitLab, add a second constant for raw content URLs right after `HUB_BASE_URL`:

    ```javascript theme={null}
    // GitHub:
    const CONTENT_BASE_URL = "https://raw.githubusercontent.com/your-org/your-hub/main";

    // GitLab:
    const CONTENT_BASE_URL = "https://gitlab.com/your-org/your-hub/-/raw/main";
    ```

    Then update the 4 URL constructions to remove the `/r/` and `/v/` route prefixes:

    ```javascript theme={null}
    // Line 77 — file_tree URLs (downloads)
    // Before:
    url: `${HUB_BASE_URL}/r/${entryPath}/${f}`
    // After:
    url: `${CONTENT_BASE_URL}/${entryPath}/${f}`

    // Line 94 — path_url (browsable link to the entry)
    // Before:
    path_url: `${HUB_BASE_URL}/${entryId}`
    // After:
    path_url: `${HUB_BASE_URL}/${entryPath}`

    // Line 95 — manifest_url
    // Before:
    manifest_url: `${HUB_BASE_URL}/v/${entryPath}/manifest.json`
    // After:
    manifest_url: `${CONTENT_BASE_URL}/${entryPath}/manifest.json`

    // Line 96 — readme_url
    // Before:
    readme_url: `${HUB_BASE_URL}/v/${entryPath}/README.md`
    // After:
    readme_url: `${CONTENT_BASE_URL}/${entryPath}/README.md`
    ```

    <Note>
      For self-hosted registries that serve files directly (no separate raw content domain), set both `HUB_BASE_URL` and `CONTENT_BASE_URL` to the same value, or use `HUB_BASE_URL` everywhere and skip the second constant.
    </Note>

    <Warning>
      The `file_tree`, `manifest_url`, and `readme_url` values must point to URLs that return **raw file content**, not HTML pages. The BRV CLI uses these URLs to download files directly.
    </Warning>
  </Step>

  <Step title="Remove example entries">
    ```bash theme={null}
    rm -rf skills/*
    rm -rf bundles/*
    ```
  </Step>

  <Step title="Add your own skills or bundles">
    Create a directory for each entry with the required files:

    ```
    skills/my-internal-skill/
    ├── manifest.json    # Entry metadata
    ├── README.md        # Usage instructions
    └── SKILL.md         # Skill workflow content
    ```

    ```
    bundles/my-context-pack/
    ├── manifest.json    # Entry metadata
    ├── README.md        # Usage instructions
    └── context.md       # Context content
    ```

    Create a `manifest.json` for each entry:

    ```json theme={null}
    {
      "id": "my-internal-skill",
      "name": "My Internal Skill",
      "version": "1.0.0",
      "description": "An internal skill for our team's code review workflow",
      "type": "agent-skill",
      "author": { "name": "Your Team" },
      "tags": ["internal", "review"],
      "category": "code-quality"
    }
    ```

    <Tip>
      See the [manifest specification](https://github.com/campfirein/brv-hub/blob/main/docs/manifest-spec.md) for all available fields including `long_description`, `dependencies`, and `metadata`.
    </Tip>
  </Step>

  <Step title="Validate locally">
    ```bash theme={null}
    npm run validate
    ```

    Validation checks:

    * JSON Schema compliance for all manifests
    * Directory name matches the `id` field
    * Entry `type` matches parent directory (`agent-skill` → `skills/`, `bundle` → `bundles/`)
    * Required files are present (`README.md`, `SKILL.md` or `context.md`)
    * `id` and `name` are globally unique across all entries
  </Step>

  <Step title="Generate and push the registry">
    The template includes two GitHub Actions workflows:

    * **validate-pr.yml** — validates every PR that touches `skills/` or `bundles/`
    * **update-registry.yml** — regenerates `registry.json` automatically on push to `main`

    Once your changes are merged to `main`, the registry updates automatically.

    To generate the registry manually instead:

    ```bash theme={null}
    npm run update-registry
    git add registry.json
    git commit -m "chore: update registry"
    git push
    ```

    See [GitHub Actions Setup](#github-actions-setup) below for configuring the automated workflows.
  </Step>

  <Step title="Register with BRV CLI">
    Connect your private registry to the BRV CLI so you can browse and install entries.

    <Note>
      For GitHub private repos, you need a **Personal Access Token** with `repo` scope (classic) or **Contents: Read-only** permission (fine-grained). See [Creating a personal access token](https://docs.github.com/en/authentication/keeping-your-account-and-data-secure/managing-your-personal-access-tokens) on GitHub Docs.
    </Note>

    ```bash theme={null}
    # GitHub private repo (using Personal Access Token)
    brv hub registry add my-team \
      --url https://raw.githubusercontent.com/your-org/your-hub/main/registry.json \
      --auth-scheme token \
      --token ghp_your_personal_access_token
    ```

    ```bash theme={null}
    # Self-hosted (no authentication)
    brv hub registry add my-team \
      --url https://registry.yourcompany.com/registry.json
    ```

    ```bash theme={null}
    # GitLab private repo
    brv hub registry add my-team \
      --url https://gitlab.com/your-org/your-hub/-/raw/main/registry.json \
      --auth-scheme custom-header \
      --header-name PRIVATE-TOKEN \
      --token glpat-your_token
    ```

    Or use the TUI equivalent:

    ```
    /hub registry add my-team --url <url> --token <token>
    ```

    <Tip>
      See [Authentication Schemes](#authentication-schemes) for all supported auth methods and [CLI Commands](#cli-commands) for the full `registry add` reference.
    </Tip>
  </Step>

  <Step title="Verify and install">
    ```bash theme={null}
    # Verify your registry appears and is reachable
    brv hub registry list

    # List entries — your private entries appear alongside official ones
    brv hub list

    # Install a skill from your private registry
    brv hub install my-internal-skill --registry my-team --agent "Claude Code"
    ```
  </Step>
</Steps>

### Entry File Requirements

| Type          | Directory       | Required Files                             |
| ------------- | --------------- | ------------------------------------------ |
| `agent-skill` | `skills/<id>/`  | `manifest.json`, `README.md`, `SKILL.md`   |
| `bundle`      | `bundles/<id>/` | `manifest.json`, `README.md`, `context.md` |

<Note>
  The directory name must match the `id` field in `manifest.json` exactly. Use kebab-case, 3–64 characters, no consecutive hyphens.
</Note>

### Manifest Reference

| Field         | Type   | Description                                                    |
| ------------- | ------ | -------------------------------------------------------------- |
| `id`          | string | Kebab-case identifier matching the directory name (3–64 chars) |
| `name`        | string | Human-readable name (3–100 chars, globally unique)             |
| `version`     | string | Semantic version (e.g., `1.0.0`)                               |
| `description` | string | What the entry does and when to use it (max 1024 chars)        |
| `type`        | string | `agent-skill` or `bundle`                                      |
| `author`      | object | `{ "name": "..." }` (required); optional `email`, `url`        |
| `tags`        | array  | 1–10 search tags                                               |
| `category`    | string | One of the valid categories below                              |

**Valid categories:** `productivity`, `code-quality`, `testing`, `documentation`, `refactoring`, `debugging`, `deployment`, `analysis`, `security`, `learning`

<Tip>
  See the full [manifest specification](https://github.com/campfirein/brv-hub/blob/main/docs/manifest-spec.md) for optional fields like `long_description`, `license`, `dependencies`, and `metadata`.
</Tip>

### Hosting Options

| Platform         | Base URL Pattern                                  | Auth Scheme        | `registry add` Flags                                                        |
| ---------------- | ------------------------------------------------- | ------------------ | --------------------------------------------------------------------------- |
| GitHub (private) | `https://raw.githubusercontent.com/org/repo/main` | `token`            | `--auth-scheme token --token ghp_xxx`                                       |
| GitLab (private) | `https://gitlab.com/org/repo/-/raw/main`          | `custom-header`    | `--auth-scheme custom-header --header-name PRIVATE-TOKEN --token glpat-xxx` |
| Self-hosted      | `https://registry.yourcompany.com`                | `bearer` or `none` | `--token secret` or no auth flags                                           |
| GitHub Pages     | `https://org.github.io/repo`                      | `none`             | No auth flags (public only; private Pages requires GitHub Enterprise)       |

### GitHub Actions Setup

The template ships with two workflows that automate validation and registry generation. To enable them:

<Steps>
  <Step title="Create a Personal Access Token">
    Go to **GitHub > Settings > Developer settings > Personal access tokens > Fine-grained tokens**. Grant **Contents: Read and write** permission scoped to your registry repository.
  </Step>

  <Step title="Add as repository secret">
    In your registry repo, go to **Settings > Secrets and variables > Actions** and create a secret named `PAT_TOKEN` with your token value.
  </Step>
</Steps>

<Warning>
  The `PAT_TOKEN` secret is required because the default `GITHUB_TOKEN` cannot trigger subsequent workflows. Without it, the `update-registry.yml` workflow will fail to push the generated `registry.json`.
</Warning>

## CLI Commands

### `brv hub registry list`

List all configured registries with their connection status and entry counts.

```bash theme={null}
brv hub registry list [OPTIONS]
```

| Flag                    | Description                     | Default |
| ----------------------- | ------------------------------- | ------- |
| `-f, --format <format>` | Output format: `text` or `json` | `text`  |

The output includes each registry's name, URL, authentication status, and entry count (or error message if unreachable).

### `brv hub registry add <name>`

Add a new custom registry.

```bash theme={null}
brv hub registry add <name> [OPTIONS]
```

| Argument / Flag              | Description                                     | Required |
| ---------------------------- | ----------------------------------------------- | -------- |
| `name`                       | Registry name (used in `--registry` flag)       | Yes      |
| `-u, --url <url>`            | Registry URL                                    | Yes      |
| `-t, --token <token>`        | Auth token for private registry                 | No       |
| `-s, --auth-scheme <scheme>` | Authentication scheme                           | No       |
| `--header-name <name>`       | Custom header name (for `custom-header` scheme) | No       |
| `-f, --format <format>`      | Output format: `text` or `json`                 | No       |

```bash theme={null}
# Public registry (no auth)
brv hub registry add myco --url https://example.com/registry.json

# Bearer token (default when --token is provided)
brv hub registry add myco --url https://example.com/registry.json --token secret123

# GitHub personal access token
brv hub registry add ghrepo \
  --url https://raw.githubusercontent.com/org/repo/main/registry.json \
  --auth-scheme token \
  --token ghp_xxx

# GitLab private token
brv hub registry add gitlab \
  --url https://gitlab.com/org/repo/-/raw/main/registry.json \
  --auth-scheme custom-header \
  --header-name PRIVATE-TOKEN \
  --token glpat-xxx

# Basic auth
brv hub registry add internal \
  --url https://internal.example.com/registry.json \
  --auth-scheme basic \
  --token user:password
```

<Warning>
  The following registry names are reserved and cannot be used: `brv`, `byterover`, `campfire`, `campfirein`, `official`.
</Warning>

### `brv hub registry remove <name>`

Remove a custom registry and its stored credentials (if private).

```bash theme={null}
brv hub registry remove <name>
```

```bash theme={null}
brv hub registry remove myco
```

Both the registry configuration and any stored authentication token are removed.

## Authentication Schemes

| Scheme          | HTTP Header Sent                | Use Case                                       |
| --------------- | ------------------------------- | ---------------------------------------------- |
| `bearer`        | `Authorization: Bearer <token>` | Most APIs (default when `--token` is provided) |
| `token`         | `Authorization: token <token>`  | GitHub personal access tokens                  |
| `basic`         | `Authorization: Basic <base64>` | HTTP basic auth                                |
| `custom-header` | `<header-name>: <token>`        | GitLab, custom APIs                            |
| `none`          | *(no header)*                   | Public registries                              |

## Token Storage

Authentication tokens are stored using file-based AES-256-GCM encryption with the following storage locations:

* **macOS** — `~/Library/Application Support/brv/`
* **Linux** — `$XDG_DATA_HOME/brv/` (defaults to `~/.local/share/brv/`)
* **Windows** — `%LOCALAPPDATA%/brv/`

Encryption keys and credential files are created with `0600` permissions (owner read/write only).
The encryption key is regenerated on every write operation.

Registry configurations (name, URL, auth scheme — but **not** tokens) are stored in `hub-registries.json` within the same data directory.

## Registry Format

A registry is a JSON file containing a `version` string and an `entries` array. Each entry describes a skill or bundle with its metadata and downloadable files.

```json theme={null}
{
  "version": "1.0.0",
  "entries": [
    {
      "id": "my-skill",
      "name": "My Custom Skill",
      "version": "1.0.0",
      "description": "A custom agent skill for your team",
      "type": "agent-skill",
      "author": { "name": "Your Team" },
      "tags": ["custom"],
      "category": "productivity",
      "file_tree": [
        { "name": "SKILL.md", "url": "https://example.com/skills/my-skill/SKILL.md" }
      ],
      "readme_url": "https://example.com/skills/my-skill/README.md",
      "manifest_url": "https://example.com/skills/my-skill/manifest.json",
      "path_url": "https://example.com/skills/my-skill"
    }
  ]
}
```

<Tip>
  See the [BRV Hub repository](https://github.com/campfirein/brv-hub) for the full manifest specification, validation schema, and contribution guide.
</Tip>

## Multi-Registry Behavior

When multiple registries are configured:

* Entries from all registries are **merged** and displayed together in `brv hub list` and the `/hub` TUI.
* If the same entry ID exists in multiple registries, the `install` command requires the `--registry <name>` flag to disambiguate.
* Failed registries are **silently skipped** — one unreachable registry does not block access to others.
* Registry data is **cached for 5 minutes** per registry to reduce network requests.

## Troubleshooting

<AccordionGroup>
  <Accordion title="Registry validation fails when adding">
    The registry URL must be reachable and return valid JSON during `brv hub registry add`. Verify that:

    * The URL points to a valid registry JSON file
    * Authentication credentials are correct (if the registry is private)
    * The server is reachable from your network
  </Accordion>

  <Accordion title="Entry exists in multiple registries">
    When an entry ID appears in more than one registry, use the `--registry` flag to specify which one to install from:

    ```bash theme={null}
    brv hub install my-skill --registry myco --agent "Claude Code"
    ```
  </Accordion>

  <Accordion title="Authentication failed (HTTP 401/403)">
    Verify that:

    * The token is correct and not expired
    * The `--auth-scheme` matches what the server expects
    * For `custom-header`, the `--header-name` is correct (e.g., `PRIVATE-TOKEN` for GitLab)

    Re-add the registry with updated credentials:

    ```bash theme={null}
    brv hub registry remove myco
    brv hub registry add myco --url https://example.com/registry.json --token new-token
    ```
  </Accordion>

  <Accordion title="Cannot use reserved registry name">
    The names `brv`, `byterover`, `campfire`, `campfirein`, and `official` are reserved. Choose a different name for your registry.
  </Accordion>

  <Accordion title="Registry generation fails in GitHub Actions">
    Verify that:

    * The `PAT_TOKEN` repository secret exists under **Settings > Secrets and variables > Actions**
    * The token has **Contents: Read and write** permission scoped to the repository
    * The token has not expired

    Check the **Actions** tab in your repository for workflow run logs.
  </Accordion>

  <Accordion title="Private registry returns 404 for file downloads">
    Verify that:

    * The `HUB_BASE_URL` in `scripts/update-registry.js` matches the actual URL where your files are served
    * The branch name in the URL is correct (e.g., `main` vs `master`)
    * The auth token used with `brv hub registry add` has read access to the repository

    Re-generate the registry after fixing the base URL:

    ```bash theme={null}
    npm run update-registry
    ```
  </Accordion>
</AccordionGroup>

## Next Steps

<CardGroup cols={2}>
  <Card title="BRV Hub Overview" icon="store" href="/brv-hub/overview">
    Browse and install skills and bundles from the hub
  </Card>

  <Card title="Contributing" icon="github" href="https://github.com/campfirein/brv-hub">
    Submit your own skills and bundles to the community hub
  </Card>
</CardGroup>
