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.jsonmanifest for publishing packages - Maintaining existing
prpm.jsonfiles - 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:
collectionsarray references packages bypackageId(not files)- Each collection has
id,name,description,packages - Packages can be
required: true(default) orfalse(optional) - Use version ranges (
^1.0.0) orlatest - Add
reasonto 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
packagesarray with files - Define collections in
collectionsarray 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- Requiredrepository,organization- Recommended- Note: No
format,subtype, orfilesrequired 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:
{
"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):
{
"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:
- CLI flag (
--eager/--lazy) - highest priority - File-level
eagersetting (enhanced files) - Package-level
eagersetting - 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,databaseinfrastructure,cloud,monitoringdocumentation,code-review,security
Purpose Tags:
troubleshooting,debugging,best-practicesautomation,quality-assurance,performancearchitecture,design-patterns
Meta Tags:
meta- For packages about creating packagesprpm-internal- For internal/private packagesprpm-development- For PRPM development itself
Tag Examples
Good Tags:
{
"tags": ["typescript", "type-safety", "code-quality", "best-practices", "static-analysis"]
}
Poor Tags:
{
"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:
- Privacy - Private packages first
- Format - Group by format (claude, cursor, etc.)
- Subtype - Group by subtype (agent, skill, rule)
Example organization:
{
"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-safetynotts-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:
{
"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:
- Tarball creation - Reads files directly from these paths
- Snippet extraction - Shows file preview before install
- Installation - CLI derives destination from format/subtype
Examples:
Claude agent (single file):
{
"format": "claude",
"subtype": "agent",
"files": [".claude/agents/my-agent.md"]
}
Claude skill (multiple files):
{
"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:
{
"format": "cursor",
"subtype": "rule",
"files": [".cursor/rules/my-rule.mdc"]
}
Slash command:
{
"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:
{
"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:
{
// ❌ 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:
# 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:
# 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:
{
"packages": [
{ "name": "typescript-safety", "format": "claude" },
{ "name": "typescript-safety", "format": "cursor" }
]
}
Good:
{
"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:
{
"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
{
"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
{
"conversion": {
"claude": {
"model": "sonnet|opus|haiku|inherit", // Preferred model
"tools": ["Read", "Write"], // Allowed tools
"subagentType": "format-conversion" // Subagent type if agent
}
}
}
Kiro Hints
{
"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
{
"conversion": {
"copilot": {
"applyTo": "src/**", // Path patterns
"excludeAgent": "code-review|coding-agent" // Agent to exclude
}
}
}
Continue Hints
{
"conversion": {
"continue": {
"alwaysApply": boolean, // Always apply rule
"globs": ["**/*.ts"], // File patterns
"regex": ["import.*from"] // Regex patterns
}
}
}
Windsurf Hints
{
"conversion": {
"windsurf": {
"characterLimit": 12000 // Warn if exceeding limit
}
}
}
Agents.md Hints
{
"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
{
"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)
{
"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:
{
"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:
{
"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:
{
"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:
{
"scripts": {
"prepublishOnly": "cd .claude/hooks/my-hook && npm run build"
}
}
Multiple hooks:
{
"scripts": {
"prepublishOnly": "cd .claude/hooks/hook-one && npm run build && cd ../hook-two && npm run build"
}
}
With tests:
{
"scripts": {
"prepublishOnly": "npm test && cd packages/hooks && npm run build"
}
}
What Happens During Publishing
When you run prpm publish:
- PRPM checks for
scripts.prepublishOnlyin your prpm.json - If found, runs the script from the directory containing prpm.json
- If script succeeds (exit code 0), publishing continues
- 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
prepublishOnlyfor 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:
{
"scripts": {
"prepublishOnly": "cd packages/hooks && npm run build"
}
}
Hooks in .claude/ directory:
{
"scripts": {
"prepublishOnly": "cd .claude/hooks/my-hook && npm run build"
}
}
Build multiple components:
{
"scripts": {
"prepublishOnly": "npm run build:hooks && npm run build:assets"
}
}
Debugging Script Failures
If your prepublishOnly script fails:
- Check the output - Error messages show what went wrong
- Run manually - Test the exact command in your terminal
- Verify working directory - Scripts run from prpm.json location
- Check dependencies - Ensure npm packages are installed
Example debugging:
# 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
formatandsubtype - All packages have
filesarray - Top-level has
authorandlicense
File Verification:
- All files in
filesarrays 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.locktracks installed dependencies (packages you use)prpm.jsondefines 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:
// 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"]
}
]
}
// 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:
// 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"]
}
]
}
// prpm.lock - Installed dependencies (auto-generated)
{
"packages": {
"@prpm/typescript-safety": {
// ✅ Installed from registry
"version": "1.0.0",
"format": "cursor",
"subtype": "rule"
}
}
}
Key Principles
- Lockfile is Auto-Generated - Never manually edit
prpm.lock - Separation of Concerns:
prpm.json= What you PUBLISHprpm.lock= What you INSTALL
- Check Lockfile First - Before adding to
prpm.json, check if it's already inprpm.lock - Trust the Lockfile - It's the authoritative record of installed packages
Workflow Example
# 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
# 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
# Test package installation
prpm install . --dry-run
4. Publish
# Publish all packages
prpm publish
# Or publish specific package
prpm publish --package my-skill
Common Mistakes to Avoid
❌ Missing Required Fields
{
"name": "my-skill"
// Missing: version, description, format, subtype, files
}
❌ Wrong Tag Format
{
"tags": ["TypeScript", "Code_Quality", "bestPractices"]
// Should be: ["typescript", "code-quality", "best-practices"]
}
❌ Duplicate Names
{
"packages": [
{ "name": "my-skill", "format": "claude" },
{ "name": "my-skill", "format": "cursor" }
// Second should be: "my-skill-rule" or similar
]
}
❌ Missing Files
{
"files": [".claude/skills/my-skill/SKILL.md"]
// But .claude/skills/my-skill/SKILL.md doesn't exist in the repo
}
❌ Absolute Paths
{
"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
{
"files": ["agents/my-agent.md"]
// Should be: ".claude/agents/my-agent.md" (include .claude/ prefix)
}
Remember
prpm.jsonis only for publishing YOUR packages/collections, not for installed dependencies- Never add packages from
prpm.locktoprpm.json- they serve different purposes prpm.locktracks what you INSTALL,prpm.jsondefines what you PUBLISH- Use
collectionsarray to bundle existing packages (references by packageId) - Use
packagesarray to define packages with files - Can combine both
packagesandcollectionsin 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.