---
title: Build Your Registry - PromptScript
description: Learn how to create and manage PromptScript registries for your organization, with self-service registry commands and decentralized architecture.
---

# Build Your Registry

PromptScript supports registries - collections of reusable configurations that can be inherited across projects. Each organization creates and manages their own registry, giving full control over AI instruction standards.

## Quick Start

### 1. Create a Registry

```bash
prs registry init my-company-registry
```

This scaffolds a complete registry with starter configurations. See [Creating a Registry](#creating-a-registry) for details.

### 2. Configure Your Project

Add to your `promptscript.yaml`:

```yaml
registry:
  git:
    url: https://github.com/your-org/your-registry.git
    ref: main # Or pin to version: v1.0.0
```

### 2. Inherit Configurations

```promptscript
@meta {
  id: "my-project"
  syntax: "1.0.0"
}

@inherit @stacks/react
@use @fragments/testing
```

<!-- playground-link-start -->
<a href="https://getpromptscript.dev/playground/?s=N4IgZglgNgpgziAXAbVABwIYBcAWSQwAeGAtmrAHRoBOCANCAMYD2AdljO-gAIkxYYABMAA6rQYIgATRIJEgSATwC0NZgCsYjLPLES4i9hkKz5ARgoAGK7tYBfMWIDEg7hFY4Y1CFldwBjADWcAD01DAY2hIuABThAOYQ-tSKgsqCUkkYAEawUoJgzNSC5BiK8dTMAK6sUgCUzq5VcDCuYNQY8XzsoRz+7vHRgnEwicmp6ZlwOXkFRSVQZRXVtXUgdgC6DJxYKfhEpOQwVLQgDABuXnAQbPhm60A" target="_blank" rel="noopener noreferrer">
  <img src="https://img.shields.io/badge/Try_in-Playground-blue?style=flat-square" alt="Try in Playground" />
</a>
<!-- playground-link-end -->

### 3. Compile

```bash
prs compile  # Automatically fetches registry and generates output
```

**Note:** When using a Git registry, the CLI automatically clones and caches the repository. You don't need to run `prs pull` separately - the `compile` and `validate` commands handle this automatically.

The registry is cached at `~/.promptscript/.cache/git/` with a default TTL of 1 hour. Use `prs pull --refresh` to force an update.

## Using `prs init`

The `prs init` command can connect to your registry and suggest configurations:

```bash
prs init
```

It will:

1. Detect your tech stack (React, Node, Python, etc.)
2. Offer to connect to a Git or local registry
3. Suggest relevant configurations from your registry's catalog
4. Generate your `promptscript.yaml` and `.promptscript/project.prs`

You can also set a default registry via [user-level config](./user-config.md) so `prs init --yes` automatically uses it.

### How Overlay-Aware Suggestions Work

When your registry catalogs Layer 2 / Layer 3 [skill overlays](./skill-overlays.md), `prs init` collapses overlay relationships before showing the picker so you don't see both the base skill and its overlay as separate choices.

Detection works two ways:

1. **Manifest `extends` field** — when a skill entry in `registry-manifest.yaml` declares `extends: <base-skill-id>`, the suggestion engine treats it as an overlay of that base.
2. **Inline `@extend` scan** — when no manifest hint exists, the engine scans the suggested skill's `.prs` source for `@use … as <alias>` plus `@extend <alias>.skills.<name>` and resolves the base skill via the alias map.

When an overlay is detected and **both** the overlay and its base were suggested, the base is removed from the choices. The overlay choice is annotated inline:

```text
? Select skills to add: (Use space to select, enter to confirm)
  ◉ @stacks/react (use)
  ◉ @skills/code-review (extends @skills/code-review-base) (skill)
  ◉ @skills/security-review (skill)
```

The `(extends …)` annotation makes it explicit which base the overlay is layering on top of, so reviewers can audit the chain at a glance. If your registry doesn't yet declare `extends`, populate the field in `registry-manifest.yaml` to get the cleanest experience:

```yaml
catalog:
  - id: '@skills/code-review-base'
    description: 'Generic code-review base skill'
  - id: '@skills/code-review'
    description: 'Org-specific code-review overlay (banking compliance)'
    extends: '@skills/code-review-base'
```

See [Skill Overlays](./skill-overlays.md) for the overlay model itself, and the [Registry Manifest](#registry-manifest) section below for the full schema.

## Usage Patterns

### Pattern 1: Inherit a Tech Stack

```promptscript
@meta { id: "react-app" syntax: "1.0.0" }

@inherit @stacks/react
```

<!-- playground-link-start -->
<a href="https://getpromptscript.dev/playground/?s=N4IgZglgNgpgziAXAbVABwIYBcAWSQwAeGAtmrAHRoBOCANCAMYD2AdljO-gAIkxYYABMEEQAJokEAdENRgZGWALQY0aGYLgBPdhkKSZARgoAGUxoC+U1tYDEg7hFY4Y1CFgdwBjANZwA9HIKHoL2ABRyAOYQXtRagkqCYjEYAEawYoJgzNSC5BhakdTMAK6sYgCUIBYAugycWHH4RKTkMFS0IAwAbq5wEGz4htVAA" target="_blank" rel="noopener noreferrer">
  <img src="https://img.shields.io/badge/Try_in-Playground-blue?style=flat-square" alt="Try in Playground" />
</a>
<!-- playground-link-end -->

### Pattern 2: Mix in Fragments

```promptscript
@meta { id: "secure-app" syntax: "1.0.0" }

@inherit @stacks/node
@use @fragments/testing
@use @fragments/security/owasp-security-review
```

<!-- playground-link-start -->
<a href="https://getpromptscript.dev/playground/?s=N4IgZglgNgpgziAXAbVABwIYBcAWSQwAeGAtmrAHRoBOCANCAMYD2AdljO-gAIkxYYABMEEQAJokEAdEHBiMArtRgBaDGjQzBcAJ7sMhSTICMFAAzmtAXymtbAYkHcIrHDGoQsTuAMYBrOAB6VmYxGEFBRwAKZQBzCB9qHUEVQTEEjAAjWDFBMGZqQXIMHVjqZgVWMQBKBycFOScwagxYvnYgjh8XWIjouISsJJS0jOyYXPzC4tLyypq67gbw7mbW9qwguUUPLB1A5gB3DDg0FW2lTx0VZQA3CBhDvsEYmHjE5NT0uCycvIKilASmUKlVqiArABdBicIY6fBEUjkGBUWggBi3dxwCBsfDGCFAA" target="_blank" rel="noopener noreferrer">
  <img src="https://img.shields.io/badge/Try_in-Playground-blue?style=flat-square" alt="Try in Playground" />
</a>
<!-- playground-link-end -->

### Pattern 3: Use Prompts Directly

```promptscript
@meta { id: "terminal" syntax: "1.0.0" }

@inherit @prompts/coding/linux-terminal
```

<!-- playground-link-start -->
<a href="https://getpromptscript.dev/playground/?s=N4IgZglgNgpgziAXAbVABwIYBcAWSQwAeGAtmrAHRoBOCANCAMYD2AdljO-gAIkxYYABMEEQAJokEAdEB2okIrDFBmC4AT3YZCkmQEYKABiOqAvlNYWAxIO6KcMahCy2azMljgB6FmMUBzLyhFAFdCAFo5BSUoQUEbAApqGH8IOCxqdUFwwT84DAAjWDFBMGZqQXIMdX9qZhDWMQBKEFMAXQZODPV8IlJyGCpaEAYAN0c4CDZ8PVagA" target="_blank" rel="noopener noreferrer">
  <img src="https://img.shields.io/badge/Try_in-Playground-blue?style=flat-square" alt="Try in Playground" />
</a>
<!-- playground-link-end -->

## How Git Registry Resolution Works

When you configure a Git registry, the CLI handles everything automatically:

1. **On first use:** The registry is cloned to `~/.promptscript/.cache/git/<hash>/`
2. **On subsequent uses:** The cached version is used if not stale (default: 1 hour TTL)
3. **On cache expiry:** The registry is updated with `git fetch`

```
prs init --yes
    ↓
Creates config with registry.git.url

prs compile
    ↓
resolveRegistryPath() → checks cache validity
    ↓
If stale/missing: GitRegistry.fetch() → clone/update
    ↓
Compiler uses cached registry path
```

### Cache Configuration

Control caching behavior in `promptscript.yaml`:

```yaml
registry:
  git:
    url: https://github.com/your-org/your-registry.git
    ref: main
  cache:
    enabled: true # Set to false to always fetch
    ttl: 3600000 # Cache TTL in ms (default: 1 hour)
```

### Force Refresh

```bash
prs pull --refresh  # Force re-clone the registry
```

## Version Pinning

Pin to a specific version for stability:

```yaml
registry:
  git:
    ref: v1.0.0
```

Or in `.prs` files:

```promptscript
@inherit @stacks/react@1.0.0
```

<!-- playground-link-start -->
<a href="https://getpromptscript.dev/playground/?s=N4IgZglgNgpgziAXAbVABwIYBcAWSQwAeGAtmrAHRoBOCANCAMYD2AdljO-gMQAEAAhFY4Y1CFgFwsGRgGs4AemowZWfgEYKABm29efABTKA5hCnUAnrwC0vACZmMAI1h3eYZtV7kMF49WYAV1Y7AEoQAF8AXQZOLEt8IlJyGCpaEAYAN1E4CDZ8dUigA" target="_blank" rel="noopener noreferrer">
  <img src="https://img.shields.io/badge/Try_in-Playground-blue?style=flat-square" alt="Try in Playground" />
</a>
<!-- playground-link-end -->

---

## Creating a Registry

Use the `prs registry init` command to scaffold a new registry:

```bash
prs registry init my-registry
```

This creates the full directory structure, manifest, and optional seed configurations.

### Interactive Mode

```bash
prs registry init my-registry
# Prompts for: name, description, namespaces, seed configs
```

### Non-Interactive Mode

```bash
prs registry init my-registry --yes --name "My Company Registry" --namespaces @core @stacks @fragments
```

### Skip Seed Configs

```bash
prs registry init my-registry --no-seed
```

### Registry Structure

```
my-registry/
├── registry-manifest.yaml    # Catalog of all configurations
├── @core/
│   └── base.prs
├── @roles/
│   └── developer/
│       └── fullstack.prs
├── @stacks/
│   └── react.prs
└── @fragments/
    └── testing.prs
```

### Registry Manifest

The `registry-manifest.yaml` file catalogs all configurations and enables `prs init` suggestions:

```yaml
version: '1'

meta:
  name: 'My Company Registry'
  description: 'Internal AI instruction configurations'
  lastUpdated: '2025-01-28'

namespaces:
  '@core':
    description: 'Universal foundations'
    priority: 100
  '@roles':
    description: 'AI personas'
    priority: 90
  '@stacks':
    description: 'Tech stack configurations'
    priority: 80
  '@fragments':
    description: 'Reusable mixins'
    priority: 70

catalog:
  - id: '@core/base'
    path: '@core/base.prs'
    name: 'Base Foundation'
    description: 'Universal AI assistant foundation'
    tags: [core, foundation]
    targets: [github, claude, cursor]
    dependencies: []
    detectionHints:
      always: true

  - id: '@stacks/react'
    path: '@stacks/react.prs'
    name: 'React Stack'
    description: 'React + TypeScript configuration'
    tags: [react, typescript, frontend]
    targets: [github, claude, cursor]
    dependencies: ['@core/base']
    detectionHints:
      dependencies: ['react', 'react-dom']
      frameworks: ['react', 'nextjs']

suggestionRules:
  - condition: { always: true }
    suggest: { inherit: '@core/base' }
  - condition: { frameworks: ['react'] }
    suggest: { inherit: '@stacks/react', use: ['@fragments/testing'] }
```

### Manifest Fields

#### `catalog` Entry Fields

| Field            | Required | Description                              |
| ---------------- | -------- | ---------------------------------------- |
| `id`             | Yes      | Unique ID matching file path             |
| `path`           | Yes      | Path to the `.prs` file                  |
| `name`           | Yes      | Human-readable name                      |
| `description`    | Yes      | Brief description                        |
| `tags`           | Yes      | Searchable tags                          |
| `targets`        | No       | Supported targets (github, claude, etc.) |
| `dependencies`   | No       | Required configurations                  |
| `detectionHints` | No       | Auto-suggestion hints (see below)        |

#### `detectionHints` Fields

| Field          | Description                                    |
| -------------- | ---------------------------------------------- |
| `always`       | Always suggest this configuration              |
| `files`        | Suggest if these files exist                   |
| `dependencies` | Suggest if package.json has these dependencies |
| `languages`    | Suggest for these languages                    |
| `frameworks`   | Suggest for these frameworks                   |

### Using Your Registry

#### Git Registry

Host on GitHub, GitLab, or any Git provider:

```yaml
registry:
  git:
    url: https://github.com/your-org/your-registry.git
    ref: main
```

#### Local Registry

For development or air-gapped environments:

```yaml
registry:
  path: ./path/to/registry
```

### Validating a Registry

Use `prs registry validate` to check your registry structure:

```bash
prs registry validate ./my-registry
```

Validation checks:

- `registry-manifest.yaml` exists and parses correctly
- Manifest schema is valid (version, meta, namespaces, catalog)
- All catalog entry `.prs` files exist
- Catalog IDs match declared namespaces
- No circular dependencies
- Warns about orphaned `.prs` files not in catalog

Use `--strict` to treat warnings as errors:

```bash
prs registry validate ./my-registry --strict
```

Use `--format json` for machine-readable output:

```bash
prs registry validate ./my-registry --format json
```

### Publishing a Registry

Use `prs registry publish` to commit and push registry updates:

```bash
prs registry publish ./my-registry
```

This will:

1. Validate the registry (use `--force` to skip)
2. Update `meta.lastUpdated` in the manifest
3. Stage, commit, and push changes

Options:

```bash
prs registry publish ./my-registry --dry-run              # Preview without publishing
prs registry publish ./my-registry -m "Add React stack"    # Custom commit message
prs registry publish ./my-registry --tag v1.0.0            # Tag the release
prs registry publish ./my-registry --force                 # Skip validation
```

### CI/CD Integration

Add registry validation to your CI pipeline:

```yaml
# .github/workflows/registry.yml
name: Registry CI
on: [push, pull_request]
jobs:
  validate:
    runs-on: ubuntu-latest
    steps:
      - uses: actions/checkout@v4
      - uses: actions/setup-node@v4
        with:
          node-version: '20'
      - run: npm install -g @promptscript/cli
      - run: prs registry validate --strict
```

---

## Next Steps

- [Enterprise Setup](enterprise.md) - Scale PromptScript across your organization
- [CI/CD Integration](ci.md) - Automate validation and compilation in your pipeline

---

## Registry Aliases

Registry aliases let you define short names for Git repository URLs so that imports stay readable and organization-wide base URLs are configured in one place.

### Configuring Aliases

Aliases are defined in the `registries` field of `promptscript.yaml` (project scope) or `~/.promptscript/config.yaml` (user scope):

```yaml
# promptscript.yaml
registries:
  '@company': github.com/acme/promptscript-base
  '@team': github.com/acme/team-frontend
```

Use any scoped name as the key. The value is a bare Git host path - no `https://` prefix required.

### Three-Level Merge

Aliases are merged from three sources in priority order (highest first):

1. **Project** - `promptscript.yaml` in the repo (team-specific overrides)
2. **User** - `~/.promptscript/config.yaml` (developer preferences)
3. **System** - `/etc/promptscript/config.yaml` (IT-provisioned defaults)

Project aliases win over user aliases, which win over system aliases. This lets IT provision company-wide aliases while still allowing projects to override specific ones.

### Using Aliases in .prs Files

Once configured, use the alias as the scope prefix in any import:

```promptscript
@meta { id: "my-project" syntax: "1.0.0" }

# Resolves to github.com/acme/promptscript-base/@org/base.prs
@inherit @company/@org/base

# Resolves to github.com/acme/team-frontend/@stacks/react.prs
@use @team/@stacks/react
```

<!-- playground-link-start -->
<a href="https://getpromptscript.dev/playground/?s=N4IgZglgNgpgziAXAbVABwIYBcAWSQwAeGAtmrAHRoBOCANCAMYD2AdljO-gAIkxYYABMEEQAJokEAdECQCeAWhrMAVjEZYZguHPYZCkmQEYKABjNaAvlNY2AxIIBK8ZlABu8QVmaCA5hFwAVwAjChYSAHoMRj4I5TIsOEZqCDQsBWCMOBgI7mZqXwjM7KpaG24IVhwYFKxBbnDMVjlc-MLimBt7Jxd3T28-AJwQsOZI6NiOUgUwajYOVjFcuAFGAGs4COoYaKxSuHLA7PqpyO4V6I2tnY0QSwBdBk4sajl8IlJyGH2QBg9aCBsfBGO5AA" target="_blank" rel="noopener noreferrer">
  <img src="https://img.shields.io/badge/Try_in-Playground-blue?style=flat-square" alt="Try in Playground" />
</a>
<!-- playground-link-end -->

---

## Go-Style URL Imports

Beyond registry aliases, PromptScript supports Go-module-style bare URL imports. You can reference any Git repository directly by its host path - no alias required.

### Basic URL Import

```promptscript
@meta { id: "my-project" syntax: "1.0.0" }

# Import directly from a public GitHub repo
@use github.com/acme/shared-standards/@fragments/security

# Import from any Git host
@use gitlab.com/myorg/prompts/@stacks/python
```

<!-- playground-link-start -->
<a href="https://getpromptscript.dev/playground/?s=N4IgZglgNgpgziAXAbVABwIYBcAWSQwAeGAtmrAHRoBOCANCAMYD2AdljO-gAIkxYYABMEEQAJokEAdECQCeAWhrMAVjEZYZguHPYZCkmQEYKABjNaAvlNY2AxIICSZZtSyCxEauqxQ5gsGpmEkEhNABXACMoCEZBAHEILAAJKMFvNGYbbnC4GEEAcyScKIoWEgB6DEY+CrgcDG8xBTgBVjFGsTgK7kCMAr52brzGcOokuRt7Jxc3AKCQjFZ-RPccZlbs3Pyi3wxIsuCK+VcCiuUyLG7uVuqAa260OVw2EEsAXQZOLGo5fCJSOQYFRaCAGAA3GC0CCvRAgIxvIA" target="_blank" rel="noopener noreferrer">
  <img src="https://img.shields.io/badge/Try_in-Playground-blue?style=flat-square" alt="Try in Playground" />
</a>
<!-- playground-link-end -->

### Version Pinning in URL Imports

Append a version specifier with `@`:

```promptscript
# Pin to an exact tag
@use github.com/acme/shared-standards/@org/base@1.2.0

# Pin to a semver range (latest patch in 1.x)
@use github.com/acme/shared-standards/@org/base@^1.0.0

# Pin to a branch
@use github.com/acme/shared-standards/@org/base@main
```

<!-- playground-link-start -->
<a href="https://getpromptscript.dev/playground/?s=N4IgZglgNgpgziAXAbVABwIYBcAWSQwAeGAtmrAHRoBOCANCAMYD2AdljO-gMQAEAChFa8szXhmFEMjLCIwBzADqsAAgFc4MXvIi41AIwosSAemkkYJuDgzUYAEwC0cLBPu37cEyubV5J-QxNFQBGCgAmCgAGZWU+QWFRcV5NEgA3GGpeagl5LQAKKGx4WUwsRhxeIV4wwgBKZXVNbV0cAyNmU3NLa1sHZ1dWd2pPb19-QOCAPTCo6NjWeOqkjF59HNYKxo0tHT1DYzNGCysbOycXNw8vHz8AoJgVEgwhEABfAF0GTixqAE98FIyJQaPQQBlaBA2PgQu8gA" target="_blank" rel="noopener noreferrer">
  <img src="https://img.shields.io/badge/Try_in-Playground-blue?style=flat-square" alt="Try in Playground" />
</a>
<!-- playground-link-end -->

| Specifier | Meaning                               |
| --------- | ------------------------------------- |
| `@1.2.0`  | Exact tag `v1.2.0` or `1.2.0`         |
| `@^1.0.0` | Latest tag matching `^1.0.0` (semver) |
| `@main`   | Tip of branch `main`                  |
| (none)    | Default branch as configured          |

### Alias vs URL Import

| Style         | Example                                | When to Use                        |
| ------------- | -------------------------------------- | ---------------------------------- |
| Alias         | `@use @company/security`               | Frequently-used internal packages  |
| Full URL      | `@use github.com/acme/security`        | One-off external imports           |
| Versioned URL | `@use github.com/acme/security@^1.0.0` | Reproducible external dependencies |

---

## Auto-Discovery

When you import a repository that does not contain `.prs` files, PromptScript looks for native AI plugin files and converts them automatically. This means you can `@use` any GitHub repository that contains `SKILL.md`, agent definitions, or command files - even if it was not authored with PromptScript.

### What Gets Auto-Discovered

| Source File Pattern                       | Imported As        |
| ----------------------------------------- | ------------------ |
| `SKILL.md` in root or `skills/` directory | `@skills` block    |
| `.claude/agents/*.md`                     | `@agents` block    |
| `.claude/commands/*.md`                   | `@shortcuts` block |
| `.github/skills/*/SKILL.md`               | `@skills` block    |

### Example: Importing an Open-Source Skill Library

```promptscript
@meta { id: "my-project" syntax: "1.0.0" }

# This repo has a SKILL.md but no .prs files - auto-discovered
@use github.com/some-org/claude-skills/skills/tdd-workflow
```

<!-- playground-link-start -->
<a href="https://getpromptscript.dev/playground/?s=N4IgZglgNgpgziAXAbVABwIYBcAWSQwAeGAtmrAHRoBOCANCAMYD2AdljO-gAIkxYYABMEEQAJokEAdECQCeAWhrMAVjEZYZguHPYZCkmQEYKABjNaAvlNY2AxIIAqOCHEHUYaZoJwY3QgGUAaQBJABkwihIxQQAjAFcsQVZvKlpBSFg3BUEMROYFMVcWADcYDzEbbni4GEEAcwhceNiKFhIAejhmPgVmanqOxig8sRgFOABraCg4LumoWY6sMTEFAHd+ybAoZnWQSwBdBk4sajl8IlJyGDT6EDLaCDZ8IwOgA" target="_blank" rel="noopener noreferrer">
  <img src="https://img.shields.io/badge/Try_in-Playground-blue?style=flat-square" alt="Try in Playground" />
</a>
<!-- playground-link-end -->

PromptScript fetches the repository, detects the `SKILL.md`, and synthesizes a virtual `.prs` fragment that you can merge into your project just like any other import.

!!! tip "Zero Config Required"
Auto-discovery works without any setup in the remote repo. The remote maintainer does not need to know about PromptScript.

---

## Lockfile

PromptScript generates a `promptscript.lock` file to record the exact resolved commit for every remote import. This gives you reproducible builds - the same source always produces the same output, regardless of when you compile.

### Generating the Lockfile

```bash
prs lock            # Create or update promptscript.lock
prs lock --dry-run  # Show what would change without writing
```

The lockfile is also written automatically during `prs compile` when remote imports are present.

### Lockfile Format

```yaml
# promptscript.lock
version: 1
packages:
  github.com/acme/promptscript-base:
    url: https://github.com/acme/promptscript-base.git
    ref: main
    commit: a3f8c2d91b4e6f7890123456789abcdef0123456
    resolved: '2026-03-23T10:00:00Z'
    references:
      '@stacks/react.prs':
        hash: sha256:a1b2c3d4e5f6...
      '@fragments/testing.prs':
        hash: sha256:f6e5d4c3b2a1...
  github.com/some-org/claude-skills:
    url: https://github.com/some-org/claude-skills.git
    ref: v1.2.0
    commit: deadbeef12345678901234567890abcdef012345
    resolved: '2026-03-22T08:30:00Z'
    references:
      'skills/tdd-workflow/SKILL.md':
        hash: sha256:1234abcd5678...
```

### Integrity Hashes

Each lockfile entry includes SHA-256 hashes for the individual files resolved from that package. During compilation and validation, these hashes are verified against the actual file contents. If a file has been modified since it was locked, a reference integrity error is raised.

This protects against:

- **Tampered dependencies** - changes to registry files after locking
- **Cache corruption** - stale or corrupted cached copies
- **Supply chain attacks** - unauthorized modifications to shared skills

To skip hash verification (e.g., during local development), use:

```bash
prs compile --ignore-hashes
prs validate --ignore-hashes
```

!!! warning
Never use `--ignore-hashes` in CI pipelines. Hash verification is a critical security check for production builds.

### Committing the Lockfile

Commit `promptscript.lock` to version control. This ensures:

- **Reproducible builds** - CI always compiles against the same commits
- **Auditable deps** - diffs show exactly when a dependency was updated
- **Offline support** - works with `prs vendor sync` (see below)

### Updating Dependencies

```bash
# Update a specific package to its latest allowed version
prs update github.com/acme/promptscript-base

# Update all packages
prs update

# Preview updates without writing
prs update --dry-run
```

---

## Vendor Mode

Vendor mode copies all remote dependencies into a local `.promptscript/vendor/` directory. This enables fully offline builds - useful in air-gapped CI environments or when you want to audit third-party content before it runs.

### Syncing the Vendor Directory

```bash
# Download all lockfile-resolved packages to vendor/
prs vendor sync

# Check that vendor/ is in sync with the lockfile
prs vendor check
```

After running `prs vendor sync`, compilation never performs network requests. The vendor directory is used as-is.

### Vendor Directory Structure

```
.promptscript/
└── vendor/
    ├── github.com/
    │   ├── acme/
    │   │   └── promptscript-base/
    │   │       ├── @org/base.prs
    │   │       └── @org/security.prs
    │   └── some-org/
    │       └── claude-skills/
    │           └── skills/
    │               └── tdd-workflow/
    │                   └── SKILL.md
    └── .vendor-manifest.yaml
```

### CI Pipeline with Vendor

```yaml
# .github/workflows/promptscript.yml
- name: Sync vendor
  run: prs vendor sync

- name: Validate
  run: prs vendor check && prs validate --strict

- name: Compile
  run: prs compile
```

Commit the vendor directory to your repository if you want fully self-contained, network-free builds. Otherwise, regenerate it in CI from the lockfile.

---

## Private Repositories

### SSH Authentication

PromptScript uses your existing SSH keys automatically for `git@` URLs:

```yaml
registries:
  '@company': git@github.com:acme/promptscript-base
```

Or in URL imports:

```promptscript
@use git@github.com:acme/private-skills/@fragments/security
```

<!-- playground-link-start -->
<a href="https://getpromptscript.dev/playground/?s=N4IgZglgNgpgziAXAbVABwIYBcAWSQwAeGAtmrAHRoBOCANCAMYD2AdljO-gAICucMAAQBzCFm6jcvAEYUWJRBkYkYAehoQAbthgBaOAGtoUOKu5hqGYSvamBjXtTEBPEAF8Aug05ZqrxATEZJQ09CCaMLQQbPgAjO5AA" target="_blank" rel="noopener noreferrer">
  <img src="https://img.shields.io/badge/Try_in-Playground-blue?style=flat-square" alt="Try in Playground" />
</a>
<!-- playground-link-end -->

Ensure your SSH key is added to `ssh-agent` or configured in `~/.ssh/config`.

### Token Authentication (GITHUB_TOKEN)

For HTTPS URLs, configure a token in your registry entry:

```yaml
# promptscript.yaml
registry:
  git:
    url: https://github.com/acme/promptscript-base.git
    ref: main
    auth:
      type: token
      tokenEnvVar: GITHUB_TOKEN
```

The `tokenEnvVar` field names the environment variable that holds the token - it is never stored in plain text.

### User-Level Token Configuration

Set up credentials once in `~/.promptscript/config.yaml` and they apply to all projects:

```yaml
# ~/.promptscript/config.yaml
registries:
  '@company': github.com/acme/promptscript-base

auth:
  github.com:
    type: token
    tokenEnvVar: GITHUB_TOKEN
  gitlab.com:
    type: token
    tokenEnvVar: GITLAB_TOKEN
```

### CI Configuration

```yaml
# .github/workflows/promptscript.yml
- name: Compile
  run: prs compile
  env:
    GITHUB_TOKEN: ${{ secrets.REGISTRY_TOKEN }}
```
