---
name: PRPM JSON Best Practices
slug: prpm-json-best-practices
category: AI Engineering
description: PRPM JSON Best Practices explains how to structure prpm.json manifests for publishing packages, including required fields, tags, multi-package repos, collections, and activation settings. Use it when creating or maintaining PRPM package metadata.
github: "https://github.com/AgentWorkforce/relay/tree/main/.claude/skills/prpm-json-best-practices-skill"
language: TypeScript
stars: 801
forks: 64
install: "npx degit https://github.com/AgentWorkforce/relay/tree/main/.claude/skills/prpm-json-best-practices-skill ~/.claude/skills/prpm-json-best-practices-skill"
installs_to: ~/.claude/skills/prpm-json-best-practices-skill
source_path: .claude/skills/prpm-json-best-practices-skill/SKILL.md
collection_size: 25
category_size: 2451
collection_url: "https://dirskills.com/collections/AgentWorkforce/relay"
added: 2026-08-23T05:18:49.723Z
last_synced: 2026-08-23T05:18:49.723Z
canonical_url: "https://dirskills.com/skills/prpm-json-best-practices"
---

# PRPM JSON Best Practices

PRPM JSON Best Practices explains how to structure prpm.json manifests for publishing packages, including required fields, tags, multi-package repos, collections, and activation settings. Use it when creating or maintaining PRPM package metadata.

**Install:**

```bash
npx degit https://github.com/AgentWorkforce/relay/tree/main/.claude/skills/prpm-json-best-practices-skill ~/.claude/skills/prpm-json-best-practices-skill
```

## README

# PRPM JSON Best Practices

You are an expert at creating and maintaining `prpm.json` package manifests for PRPM (Prompt Package Manager). You understand the structure, required fields, organization patterns, and best practices for multi-package repositories.

## When to Apply This Skill

**Use when:**

- Creating a new `prpm.json` manifest for publishing packages
- Maintaining existing `prpm.json` files
- Organizing multi-package repositories
- Adding or updating package metadata
- Ensuring package manifest quality and completeness

**Don't use for:**

- User configuration files (`.prpmrc`) - those are for users
- Lockfiles (`prpm.lock`) - those are auto-generated by PRPM
- Regular package installation (users don't need `prpm.json`)
- Dependencies already tracked in lockfiles

## Core Purpose

`prpm.json` is **only needed if you're publishing packages**. Regular users installing packages from the registry don't need this file.

Use `prpm.json` when you're:

- Publishing a package to the PRPM registry
- Creating a collection of packages
- Distributing your own prompts/rules/skills/agents
- Managing multiple related packages in a monorepo

## File Structure

### Single Package

See `examples/single-package.json` for complete structure.

**Key fields:** `name`, `version`, `description`, `author`, `license`, `format`, `subtype`, `files`

### Multi-Package Repository

See `examples/multi-package.json` for complete structure.

**Use when:** Publishing multiple related packages from one repo
**Key difference:** Top-level `packages` array with individual package definitions

### Collections Repository

See `examples/collections-repository.json` for complete structure.

**Use when:** Bundling existing published packages into curated collections
**Key points:**

- `collections` array references packages by `packageId` (not files)
- Each collection has `id`, `name`, `description`, `packages`
- Packages can be `required: true` (default) or `false` (optional)
- Use version ranges (`^1.0.0`) or `latest`
- Add `reason` to explain why package is included

### Packages + Collections (Combined)

See `examples/packages-with-collections.json` for complete structure.

**Use when:** Publishing packages AND creating collections that bundle them
**Key points:**

- Define packages in `packages` array with files
- Define collections in `collections` array referencing those packages
- Collections can reference both local packages and external ones
- Publish both individual packages and collection bundles from same repo

## Required Fields

### Top-Level (Single Package)

| Field         | Type     | Required | Description                                                                     |
| ------------- | -------- | -------- | ------------------------------------------------------------------------------- |
| `name`        | string   | **Yes**  | Package name (kebab-case, unique in registry)                                   |
| `version`     | string   | **Yes**  | Semver version (e.g., `1.0.0`)                                                  |
| `description` | string   | **Yes**  | Clear description of what the package does                                      |
| `author`      | string   | **Yes**  | Author name and optional email                                                  |
| `license`     | string   | **Yes**  | SPDX license identifier (e.g., `MIT`, `Apache-2.0`)                             |
| `format`      | string   | **Yes**  | Target format: `claude`, `cursor`, `continue`, `windsurf`, etc.                 |
| `subtype`     | string   | **Yes**  | Package type: `agent`, `skill`, `rule`, `slash-command`, `prompt`, `collection` |
| `files`       | string[] | **Yes**  | Array of files to include in package                                            |

### Optional Top-Level Fields

| Field           | Type     | Description                                                   |
| --------------- | -------- | ------------------------------------------------------------- |
| `repository`    | string   | Git repository URL                                            |
| `organization`  | string   | Organization name (for scoped packages)                       |
| `homepage`      | string   | Package homepage URL                                          |
| `documentation` | string   | Documentation URL                                             |
| `license_text`  | string   | Full text of the license file for proper attribution          |
| `license_url`   | string   | URL to the license file in the repository                     |
| `tags`          | string[] | Searchable tags (kebab-case)                                  |
| `keywords`      | string[] | Additional keywords for search                                |
| `category`      | string   | Package category                                              |
| `private`       | boolean  | If `true`, won't be published to public registry              |
| `dependencies`  | object   | Package dependencies (name: semver)                           |
| `scripts`       | object   | Lifecycle scripts (multi-package only)                        |
| `eager`         | boolean  | If `true`, skill/agent loads at session start (not on-demand) |

### Multi-Package Fields

When using `packages` array:

| Field         | Type     | Required    | Description                                |
| ------------- | -------- | ----------- | ------------------------------------------ |
| `name`        | string   | **Yes**     | Unique package name                        |
| `version`     | string   | **Yes**     | Package version                            |
| `description` | string   | **Yes**     | Package description                        |
| `format`      | string   | **Yes**     | Package format                             |
| `subtype`     | string   | **Yes**     | Package subtype                            |
| `tags`        | string[] | Recommended | Searchable tags                            |
| `files`       | string[] | **Yes**     | Files to include                           |
| `private`     | boolean  | No          | Mark as private                            |
| `eager`       | boolean  | No          | Load at session start (skills/agents only) |

### Collection Fields

When using `collections` array:

**Top-level (repository with collections):**

- `name`, `version`, `description`, `author`, `license` - **Required**
- `repository`, `organization` - Recommended
- Note: No `format`, `subtype`, or `files` required at top level

**Each collection object:**

| Field         | Type     | Required    | Description                                            |
| ------------- | -------- | ----------- | ------------------------------------------------------ |
| `id`          | string   | **Yes**     | Unique collection identifier (kebab-case, 3-100 chars) |
| `name`        | string   | **Yes**     | Display name (3-100 chars)                             |
| `description` | string   | **Yes**     | What the collection provides (10-500 chars)            |
| `packages`    | array    | **Yes**     | Array of packages to include (minimum 1)               |
| `version`     | string   | Recommended | Semantic version of collection                         |
| `category`    | string   | Recommended | Collection category (development, testing, etc.)       |
| `tags`        | string[] | Recommended | Searchable tags (kebab-case, 1-10 items)               |
| `icon`        | string   | Optional    | Emoji or icon (max 10 chars)                           |

**Each package within collection:**

| Field       | Type    | Required | Description                                   |
| ----------- | ------- | -------- | --------------------------------------------- |
| `packageId` | string  | **Yes**  | Package to include                            |
| `version`   | string  | Optional | Version range (^1.0.0, ~2.1.0, 1.0.0, latest) |
| `required`  | boolean | Optional | Whether package is required (default: true)   |
| `reason`    | string  | Optional | Why package is included (max 200 chars)       |

## Format and Subtype Values

### Format (Target AI Tool)

| Format      | Description                   |
| ----------- | ----------------------------- |
| `claude`    | Claude Code (agents, skills)  |
| `cursor`    | Cursor IDE (rules, MDC files) |
| `continue`  | Continue.dev extension        |
| `windsurf`  | Windsurf IDE                  |
| `copilot`   | GitHub Copilot                |
| `kiro`      | Kiro IDE                      |
| `agents.md` | Agents.md format              |
| `generic`   | Generic/universal format      |
| `mcp`       | Model Context Protocol        |

### Subtype (Package Type)

| Subtype         | Description              | Typical Formats       |
| --------------- | ------------------------ | --------------------- |
| `agent`         | Autonomous agents        | `claude`, `agents.md` |
| `skill`         | Specialized capabilities | `claude`              |
| `rule`          | IDE rules and guidelines | `cursor`, `windsurf`  |
| `slash-command` | Slash commands           | `cursor`, `continue`  |
| `prompt`        | Prompt templates         | `generic`             |
| `collection`    | Package collections      | Any                   |
| `chatmode`      | Chat modes               | `kiro`                |
| `tool`          | MCP tools                | `mcp`                 |

## Eager vs Lazy Activation

Skills and agents can be configured to load eagerly (at session start) or lazily (on-demand when relevant).

### When to Use Eager

**Use `eager: true` when:**

- The skill should ALWAYS be active (coding standards, style guides)
- Critical behavior that must never be skipped
- Small, foundational skills with minimal token cost

**Keep lazy (default) when:**

- Specialized skills for specific contexts
- Large skills with significant token overhead
- Skills that only apply to certain file types

### Setting Eager in prpm.json

**Package-level:**

```json
{
  "name": "code-style-enforcer",
  "version": "1.0.0",
  "format": "claude",
  "subtype": "skill",
  "eager": true,
  "files": [".claude/skills/code-style/SKILL.md"]
}
```

**File-level (enhanced files format):**

```json
{
  "files": [
    {
      "path": ".claude/skills/critical-skill/SKILL.md",
      "format": "claude",
      "subtype": "skill",
      "eager": true
    },
    {
      "path": ".claude/skills/optional-skill/SKILL.md",
      "format": "claude",
      "subtype": "skill",
      "eager": false
    }
  ]
}
```

### Precedence

When installing, the final eager setting is determined by:

1. CLI flag (`--eager`/`--lazy`) - highest priority
2. File-level `eager` setting (enhanced files)
3. Package-level `eager` setting
4. Default: lazy (false)

### Applicable Subtypes

| Subtype         | Supports Eager |
| --------------- | -------------- |
| `skill`         | Yes            |
| `agent`         | Yes            |
| `rule`          | No             |
| `slash-command` | No             |
| `hook`          | No             |

Eager loading only affects progressive disclosure formats (agents.md, gemini.md, claude.md, aider).

## Tags Best Practices

### Tag Structure

- Use **kebab-case** for all tags
- Be **specific** and **searchable**
- Include 3-8 tags per package
- Combine technology, domain, and purpose tags

### Tag Categories

**Technology Tags:**

- Languages: `typescript`, `python`, `javascript`, `rust`
- Frameworks: `react`, `nextjs`, `fastify`, `django`
- Tools: `aws`, `docker`, `kubernetes`, `postgresql`

**Domain Tags:**

- `deployment`, `testing`, `ci-cd`, `database`
- `infrastructure`, `cloud`, `monitoring`
- `documentation`, `code-review`, `security`

**Purpose Tags:**

- `troubleshooting`, `debugging`, `best-practices`
- `automation`, `quality-assurance`, `performance`
- `architecture`, `design-patterns`

**Meta Tags:**

- `meta` - For packages about creating packages
- `prpm-internal` - For internal/private packages
- `prpm-development` - For PRPM development itself

### Tag Examples

**Good Tags:**

```json
{
  "tags": ["typescript", "type-safety", "code-quality", "best-practices", "static-analysis"]
}
```

**Poor Tags:**

```json
{
  "tags": [
    "code", // Too generic
    "stuff", // Meaningless
    "TypeScript", // Wrong case
    "type_safety" // Wrong format (use kebab-case)
  ]
}
```

## Organization Best Practices

### Multi-Package Organization

**Order packages by:**

1. **Privacy** - Private packages first
2. **Format** - Group by format (claude, cursor, etc.)
3. **Subtype** - Group by subtype (agent, skill, rule)

**Example organization:**

```json
{
  "packages": [
    // Private > Claude > Agents
    { "name": "internal-agent", "private": true, "format": "claude", "subtype": "agent" },

    // Private > Claude > Skills
    { "name": "internal-skill", "private": true, "format": "claude", "subtype": "skill" },

    // Private > Cursor > Rules
    { "name": "internal-rule", "private": true, "format": "cursor", "subtype": "rule" },

    // Public > Claude > Skills
    { "name": "public-skill", "format": "claude", "subtype": "skill" },

    // Public > Cursor > Rules
    { "name": "public-rule", "format": "cursor", "subtype": "rule" }
  ]
}
```

### Naming Conventions

**Package Names:**

- Use **kebab-case**: `my-awesome-skill`
- Be **descriptive**: `typescript-type-safety` not `ts-types`
- Avoid duplicates across formats: use suffixes if needed
  - `format-conversion-agent` (Claude agent)
  - `format-conversion` (Cursor rule)

**File Paths:**

- Use **full paths from project root** (where prpm.json lives)
- Agents: `.claude/agents/name.md`
- Skills: `.claude/skills/name/SKILL.md`
- Rules: `.cursor/rules/name.mdc`
- Commands: `.claude/commands/category/name.md`

## Version Management

### Semver Guidelines

Follow semantic versioning:

- **Major (1.0.0 → 2.0.0)**: Breaking changes
- **Minor (1.0.0 → 1.1.0)**: New features, backward compatible
- **Patch (1.0.0 → 1.0.1)**: Bug fixes, backward compatible

### Version Bumping

When to bump versions:

- **Patch**: Bug fixes, typo corrections, minor improvements
- **Minor**: New sections, additional examples, new features
- **Major**: Complete rewrites, breaking changes, renamed fields

### Keep Versions in Sync

For multi-package repos, keep related packages in sync:

```json
{
  "packages": [
    { "name": "pkg-one", "version": "1.2.0" },
    { "name": "pkg-two", "version": "1.2.0" },
    { "name": "pkg-three", "version": "1.2.0" }
  ]
}
```

## File Management

### Files Array

**CRITICAL: File paths must be full paths from project root (where prpm.json lives).**

**Required:**

- List all files to include in the package
- Use **full paths from project root** - not relative to destination directories
- Paths should start with `.claude/`, `.cursor/`, etc.
- Include documentation files

**Why Full Paths?**
File paths in `prpm.json` are used for:

1. **Tarball creation** - Reads files directly from these paths
2. **Snippet extraction** - Shows file preview before install
3. **Installation** - CLI derives destination from format/subtype

**Examples:**

Claude agent (single file):

```json
{
  "format": "claude",
  "subtype": "agent",
  "files": [".claude/agents/my-agent.md"]
}
```

Claude skill (multiple files):

```json
{
  "format": "claude",
  "subtype": "skill",
  "files": [
    ".claude/skills/my-skill/SKILL.md",
    ".claude/skills/my-skill/EXAMPLES.md",
    ".claude/skills/my-skill/README.md"
  ]
}
```

Cursor rule:

```json
{
  "format": "cursor",
  "subtype": "rule",
  "files": [".cursor/rules/my-rule.mdc"]
}
```

Slash command:

```json
{
  "format": "claude",
  "subtype": "slash-command",
  "files": [".claude/commands/category/my-command.md"]
}
```

### Enhanced File Format

**Advanced:** Files can be objects with metadata instead of simple strings. Useful for packages with multiple files targeting different formats or needing per-file metadata.

**Enhanced file object structure:**

```json
{
  "files": [
    {
      "path": ".cursor/rules/typescript.mdc",
      "format": "cursor",
      "subtype": "rule",
      "name": "TypeScript Rules",
      "description": "TypeScript coding standards and best practices",
      "tags": ["typescript", "frontend"]
    },
    {
      "path": ".cursor/rules/python.mdc",
      "format": "cursor",
      "subtype": "rule",
      "name": "Python Rules",
      "description": "Python best practices for backend development",
      "tags": ["python", "backend"]
    }
  ]
}
```

**When to use enhanced format:**

- Multi-file packages with different formats/subtypes per file
- Need per-file descriptions or tags
- Want to provide display names for individual files
- Building collection packages with mixed content types

**Enhanced file fields:**

| Field         | Required | Description                                     |
| ------------- | -------- | ----------------------------------------------- |
| `path`        | **Yes**  | Relative path to file from project root         |
| `format`      | **Yes**  | File's target format (`cursor`, `claude`, etc.) |
| `subtype`     | No       | File's subtype (`rule`, `skill`, `agent`, etc.) |
| `name`        | No       | Display name for this file                      |
| `description` | No       | Description of what this file does              |
| `tags`        | No       | File-specific tags (array of strings)           |

**Note:** Cannot mix simple strings and objects in the same `files` array. Use all strings OR all objects, not both.

**Common Mistake:**

```json
{
  // ❌ WRONG - Relative paths without directory prefix
  "files": ["agents/my-agent.md"]  // Will fail to find file

  // ✅ CORRECT - Full path from project root
  "files": [".claude/agents/my-agent.md"]
}
```

### File Verification

Always verify files exist:

```bash
# Check all files in prpm.json exist
for file in $(cat prpm.json | jq -r '.packages[].files[]'); do
  if [ ! -f "$file" ]; then
    echo "Missing: $file"
  fi
done
```

## Duplicate Detection

### Check for Duplicate Names

Run this check before committing:

```bash
# Check for duplicate package names
cat prpm.json | jq -r '.packages[].name' | sort | uniq -d
```

If output is empty, no duplicates exist. If names appear, you have duplicates to resolve.

### Resolving Duplicates

**Bad:**

```json
{
  "packages": [
    { "name": "typescript-safety", "format": "claude" },
    { "name": "typescript-safety", "format": "cursor" }
  ]
}
```

**Good:**

```json
{
  "packages": [
    { "name": "typescript-safety", "format": "claude", "subtype": "skill" },
    { "name": "typescript-safety-rule", "format": "cursor", "subtype": "rule" }
  ]
}
```

## Conversion Hints (Advanced)

**Purpose:** Help improve quality when converting packages to other formats. The `conversion` field provides format-specific hints for cross-format transformations.

**Note:** This is an advanced feature primarily used by format conversion tools. Most packages don't need this.

**Structure:**

```json
{
  "name": "my-package",
  "version": "1.0.0",
  "format": "claude",
  "conversion": {
    "cursor": {
      "alwaysApply": false,
      "priority": "high",
      "globs": ["**/*.ts", "**/*.tsx"]
    },
    "kiro": {
      "inclusion": "fileMatch",
      "fileMatchPattern": "**/*.ts",
      "domain": "typescript",
      "tools": ["fs_read", "fs_write"],
      "mcpServers": {
        "database": {
          "command": "mcp-server-postgres",
          "args": [],
          "env": {
            "DATABASE_URL": "${DATABASE_URL}"
          }
        }
      }
    },
    "copilot": {
      "applyTo": ["src/**", "lib/**"],
      "excludeAgent": "code-review"
    }
  }
}
```

**Supported conversion hints:**

### Cursor Hints

```json
{
  "conversion": {
    "cursor": {
      "alwaysApply": boolean,      // Whether rule should always apply
      "priority": "high|medium|low", // Rule priority level

