--- name: prpm-json-best-practices description: Best practices for structuring prpm.json package manifests with required fields, tags, organization, multi-package management, enhanced file format, eager/lazy activation, and conversion hints --- # 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 "globs": ["**/*.ts"] // File patterns to auto-attach } } } ``` ### Claude Hints ```json { "conversion": { "claude": { "model": "sonnet|opus|haiku|inherit", // Preferred model "tools": ["Read", "Write"], // Allowed tools "subagentType": "format-conversion" // Subagent type if agent } } } ``` ### Kiro Hints ```json { "conversion": { "kiro": { "inclusion": "always|fileMatch|manual", // When to include "fileMatchPattern": "**/*.ts", // Pattern for fileMatch mode "domain": "typescript", // Domain category "tools": ["fs_read", "fs_write"], // Available tools "mcpServers": { // MCP server configs "database": { "command": "mcp-server-postgres", "args": [], "env": { "DATABASE_URL": "${DATABASE_URL}" } } } } } } ``` ### Copilot Hints ```json { "conversion": { "copilot": { "applyTo": "src/**", // Path patterns "excludeAgent": "code-review|coding-agent" // Agent to exclude } } } ``` ### Continue Hints ```json { "conversion": { "continue": { "alwaysApply": boolean, // Always apply rule "globs": ["**/*.ts"], // File patterns "regex": ["import.*from"] // Regex patterns } } } ``` ### Windsurf Hints ```json { "conversion": { "windsurf": { "characterLimit": 12000 // Warn if exceeding limit } } } ``` ### Agents.md Hints ```json { "conversion": { "agentsMd": { "project": "my-project", // Project name "scope": "backend" // Scope/domain } } } ``` **When to use conversion hints:** - Publishing cross-format packages that need specific settings per format - Format conversion tools need guidance on how to transform content - Package behavior should change based on target format - Want to preserve format-specific metadata during conversions ## Common Patterns ### Private Internal Packages ```json { "name": "internal-tool", "version": "1.0.0", "description": "Internal development tool", "private": true, "format": "claude", "subtype": "skill", "tags": ["prpm-internal", "development"], "files": [".claude/skills/internal-tool/SKILL.md"] } ``` ### Meta Packages (Creating Other Packages) ```json { "name": "creating-skills", "version": "1.0.0", "description": "Guide for creating effective Claude Code skills", "format": "claude", "subtype": "skill", "tags": ["meta", "claude-code", "skills", "documentation", "best-practices"], "files": [".claude/skills/creating-skills/SKILL.md"] } ``` ### Cross-Format Packages When you have the same content for multiple formats: ```json { "packages": [ { "name": "format-conversion-agent", "format": "claude", "subtype": "agent", "description": "Agent for converting between AI prompt formats", "files": [".claude/agents/format-conversion.md"] }, { "name": "format-conversion", "format": "cursor", "subtype": "rule", "description": "Rule for converting between AI prompt formats", "files": [".cursor/rules/format-conversion.mdc"] } ] } ``` ### Collections in prpm.json Collections CAN be defined in prpm.json alongside packages using the `collections` array. Collections bundle multiple packages together for easier installation. **Example with both packages and collections:** ```json { "name": "my-prompts-repo", "author": "Your Name", "license": "MIT", "packages": [ { "name": "typescript-rules", "version": "1.0.0", "description": "TypeScript best practices", "format": "cursor", "subtype": "rule", "tags": ["typescript"], "files": [".cursor/rules/typescript.mdc"] } ], "collections": [ { "id": "my-dev-setup", "name": "My Development Setup", "description": "Complete development setup with TypeScript and React", "version": "1.0.0", "category": "development", "tags": ["typescript", "react"], "packages": [ { "packageId": "typescript-strict", "version": "^1.0.0", "required": true, "reason": "Enforces strict TypeScript type safety" }, { "packageId": "react-best-practices", "version": "^2.0.0", "required": true } ] } ] } ``` For more details on creating collections, see the PRPM documentation at https://docs.prpm.dev or run `prpm help collections`. **Summary:** `prpm.json` can contain both packages (skills, agents, rules, slash-commands, etc.) and collections. ## Lifecycle Scripts **IMPORTANT:** The `scripts` field only applies to **multi-package manifests** (prpm.json with a `packages` array). It does NOT work in single-package manifests. Use the `scripts` field to run commands automatically during package operations, particularly for building TypeScript hooks before publishing. ### When to Use Scripts **Primary use case: Building TypeScript Hooks** If your packages include Claude Code hooks written in TypeScript, you MUST build them to JavaScript before publishing: ```json { "name": "my-packages", "license": "MIT", "scripts": { "prepublishOnly": "cd packages/hooks && npm run build" }, "packages": [ { "name": "my-hook", "version": "1.0.0", "format": "claude", "subtype": "hook", "files": [ ".claude/hooks/my-hook/hook.ts", ".claude/hooks/my-hook/hook.json", ".claude/hooks/my-hook/dist/hook.js" ] } ] } ``` ### Available Script Types | Script | When it Runs | Use Case | |--------|--------------|----------| | `prepublishOnly` | Before `prpm publish` only | **Recommended** - Build hooks, compile assets | | `prepublish` | Before publish AND on npm install | **Not recommended** - causes unexpected builds | **Always use `prepublishOnly` instead of `prepublish`** to avoid running builds when users install your packages. ### prepublishOnly Examples **Single hook:** ```json { "scripts": { "prepublishOnly": "cd .claude/hooks/my-hook && npm run build" } } ``` **Multiple hooks:** ```json { "scripts": { "prepublishOnly": "cd .claude/hooks/hook-one && npm run build && cd ../hook-two && npm run build" } } ``` **With tests:** ```json { "scripts": { "prepublishOnly": "npm test && cd packages/hooks && npm run build" } } ``` ### What Happens During Publishing When you run `prpm publish`: 1. PRPM checks for `scripts.prepublishOnly` in your prpm.json 2. If found, runs the script from the directory containing prpm.json 3. If script succeeds (exit code 0), publishing continues 4. If script fails (non-zero exit code), publishing is aborted **Script execution details:** - Working directory: Same directory as prpm.json - Timeout: 5 minutes (300,000ms) default - Environment: Inherits your shell's environment variables - Output: Shown in real-time ### Best Practices for Scripts **DO:** - ✅ Use `prepublishOnly` for building hooks - ✅ Chain commands with `&&` for dependencies: `npm test && npm run build` - ✅ Keep scripts fast (under 1 minute if possible) - ✅ Test scripts locally before publishing **DON'T:** - ❌ Use `prepublish` (runs on install too) - ❌ Forget to build hooks before publishing - ❌ Use scripts in single-package manifests (not supported) - ❌ Put long-running operations in scripts ### Common Patterns **Hooks in packages/ directory:** ```json { "scripts": { "prepublishOnly": "cd packages/hooks && npm run build" } } ``` **Hooks in .claude/ directory:** ```json { "scripts": { "prepublishOnly": "cd .claude/hooks/my-hook && npm run build" } } ``` **Build multiple components:** ```json { "scripts": { "prepublishOnly": "npm run build:hooks && npm run build:assets" } } ``` ### Debugging Script Failures If your prepublishOnly script fails: 1. **Check the output** - Error messages show what went wrong 2. **Run manually** - Test the exact command in your terminal 3. **Verify working directory** - Scripts run from prpm.json location 4. **Check dependencies** - Ensure npm packages are installed **Example debugging:** ```bash # Test your prepublishOnly script manually cd /path/to/prpm.json/directory cd packages/hooks && npm run build # If it works manually but fails in PRPM, check: # - Working directory assumptions # - Environment variables # - Installed dependencies ``` ### Why This Matters **Without prepublishOnly:** - You might forget to build hooks before publishing - Published packages contain stale/outdated JavaScript - Users install broken hooks - Manual builds are error-prone **With prepublishOnly:** - Hooks automatically build before every publish - JavaScript always matches TypeScript source - Prevents publishing broken code - Consistent, reliable publishing workflow ## Validation Checklist Before publishing, verify: **Required Fields:** - [ ] All packages have `name`, `version`, `description` - [ ] All packages have `format` and `subtype` - [ ] All packages have `files` array - [ ] Top-level has `author` and `license` **File Verification:** - [ ] All files in `files` arrays exist - [ ] File paths are relative to repo root - [ ] No missing or broken file references **No Duplicates:** - [ ] No duplicate package names - [ ] Package names are unique across entire manifest **Tags:** - [ ] Tags use kebab-case - [ ] 3-8 relevant tags per package - [ ] Tags include technology, domain, and purpose **Organization:** - [ ] Private packages listed first - [ ] Packages grouped by format and subtype - [ ] Consistent versioning across related packages ## Lockfile Management ### Understanding prpm.lock The `prpm.lock` file is **auto-generated** and tracks installed packages. It serves as the source of truth for what's installed in your project. **IMPORTANT:** Do NOT add packages to `prpm.json` if they already exist in `prpm.lock`: - `prpm.lock` tracks **installed dependencies** (packages you use) - `prpm.json` defines **published packages** (packages you create and share) ### When to Use prpm.json vs prpm.lock **Use `prpm.json` when:** - You're creating a package to publish to the registry - You want to define metadata for YOUR packages - You're setting up a multi-package repository **Use `prpm.lock` (auto-generated) when:** - You install packages with `prpm install` - You want to track which packages are installed - You want reproducible installations across environments ### Common Mistake: Duplicating Dependencies **❌ WRONG - Don't add installed packages to prpm.json:** ```json // prpm.json { "name": "my-project", "packages": [ { "name": "typescript-safety", // ❌ This is an INSTALLED package "version": "1.0.0", "format": "cursor", "subtype": "rule", "files": [".cursor/rules/typescript-safety.mdc"] } ] } ``` ```json // prpm.lock (auto-generated) { "packages": { "@prpm/typescript-safety": { // ✅ Already tracked here "version": "1.0.0", "format": "cursor", "subtype": "rule" } } } ``` **✅ CORRECT - prpm.json only for YOUR packages:** ```json // prpm.json - Only YOUR packages you're publishing { "name": "my-project", "packages": [ { "name": "my-custom-rule", // ✅ This is YOUR package "version": "1.0.0", "format": "cursor", "subtype": "rule", "files": [".cursor/rules/my-custom-rule.mdc"] } ] } ``` ```json // prpm.lock - Installed dependencies (auto-generated) { "packages": { "@prpm/typescript-safety": { // ✅ Installed from registry "version": "1.0.0", "format": "cursor", "subtype": "rule" } } } ``` ### Key Principles 1. **Lockfile is Auto-Generated** - Never manually edit `prpm.lock` 2. **Separation of Concerns**: - `prpm.json` = What you PUBLISH - `prpm.lock` = What you INSTALL 3. **Check Lockfile First** - Before adding to `prpm.json`, check if it's already in `prpm.lock` 4. **Trust the Lockfile** - It's the authoritative record of installed packages ### Workflow Example ```bash # Install a package (updates prpm.lock automatically) prpm install @prpm/typescript-safety # This creates/updates prpm.lock - DO NOT add to prpm.json! # Only create prpm.json entries for packages YOU create: # 1. Create your custom rule/skill/agent # 2. Add entry to prpm.json # 3. Publish with: prpm publish ``` ## Publishing Workflow ### 1. Validate Manifest ```bash # Validate JSON syntax cat prpm.json | jq . > /dev/null # Check for duplicates cat prpm.json | jq -r '.packages[].name' | sort | uniq -d # Verify files exist # (see File Verification section) ``` ### 2. Bump Versions Update version numbers for changed packages. ### 3. Test Locally ```bash # Test package installation prpm install . --dry-run ``` ### 4. Publish ```bash # Publish all packages prpm publish # Or publish specific package prpm publish --package my-skill ``` ## Common Mistakes to Avoid ### ❌ Missing Required Fields ```json { "name": "my-skill", // Missing: version, description, format, subtype, files } ``` ### ❌ Wrong Tag Format ```json { "tags": ["TypeScript", "Code_Quality", "bestPractices"] // Should be: ["typescript", "code-quality", "best-practices"] } ``` ### ❌ Duplicate Names ```json { "packages": [ { "name": "my-skill", "format": "claude" }, { "name": "my-skill", "format": "cursor" } // Second should be: "my-skill-rule" or similar ] } ``` ### ❌ Missing Files ```json { "files": [".claude/skills/my-skill/SKILL.md"] // But .claude/skills/my-skill/SKILL.md doesn't exist in the repo } ``` ### ❌ Absolute Paths ```json { "files": ["/Users/me/project/.claude/skills/my-skill/SKILL.md"] // Should be: ".claude/skills/my-skill/SKILL.md" (relative to project root) } ``` ### ❌ Missing Directory Prefix ```json { "files": ["agents/my-agent.md"] // Should be: ".claude/agents/my-agent.md" (include .claude/ prefix) } ``` ## Remember - `prpm.json` is **only for publishing YOUR packages/collections**, not for installed dependencies - **Never add packages from `prpm.lock` to `prpm.json`** - they serve different purposes - `prpm.lock` tracks what you INSTALL, `prpm.json` defines what you PUBLISH - Use `collections` array to bundle existing packages (references by packageId) - Use `packages` array to define packages with files - Can combine both `packages` and `collections` in same repo - Always validate before committing - Keep versions in sync for related packages - Use consistent, searchable tags - Verify all file paths exist - Check for duplicate names - Follow semver for version management **Goal:** Create maintainable, well-organized package manifests and curated collections that are easy to publish and discover in the PRPM registry.