> ## Documentation Index
> Fetch the complete documentation index at: https://anvil.thatdevguy.in/llms.txt
> Use this file to discover all available pages before exploring further.

# Prompt Registry: Version, Diff, and Manage Prompts

> Store prompts as versioned, immutable artifacts with PromptRegistry. Pin routes to specific versions, diff changes, and roll back without a code deploy.

Prompts are code. When you hardcode a system prompt in a handler file, changing it means a full redeploy, you lose history, and rolling back means reverting a commit. `PromptRegistry` treats prompts as first-class, versioned artifacts backed by your existing `StateStore`. You can pin a route to a specific version, diff two versions line-by-line, and roll forward or backward entirely independently of code changes.

## Setup

Create a `PromptRegistry` backed by any `StateStore`:

```ts theme={null}
import { PromptRegistry } from 'anvil-sdk/prompt';
import { SqliteStateStore } from 'anvil-sdk/store';

const store = await SqliteStateStore.open(); // .anvil/state.db
const registry = new PromptRegistry(store);
```

<Note>
  For tests or one-off scripts, pass a `MemoryStateStore` instead — it requires no file I/O or native dependencies.
</Note>

## Registering prompts

Call `registry.register(name, template, note?)` to append a new immutable version. Version numbers start at `1` and increment automatically.

```ts theme={null}
const v1 = await registry.register(
  'support-system',
  'You are a helpful customer support agent. Answer questions concisely and accurately.',
  'Initial version',
);
// → { version: 1, template: '...', note: 'Initial version', createdAt: 1718000000000 }

// Registering again creates v2 — v1 is never modified
const v2 = await registry.register(
  'support-system',
  'You are a friendly customer support agent. Answer questions concisely, accurately, and with empathy. Always end with "Is there anything else I can help you with?"',
  'Add empathy tone and closing question',
);
// → { version: 2, ... }
```

`register` returns a `PromptVersion` object:

| Field       | Type     | Description                                                   |                                            |
| ----------- | -------- | ------------------------------------------------------------- | ------------------------------------------ |
| `version`   | `number` | Monotonically increasing version number                       |                                            |
| `template`  | `string` | The prompt template (may contain `{{placeholder}}` variables) |                                            |
| `note`      | \`string | undefined\`                                                   | Optional human-readable change description |
| `createdAt` | `number` | Unix timestamp (ms) when this version was created             |                                            |

## Retrieving prompts

### `registry.get(name, version?)`

Returns the latest version when `version` is omitted, or the specific version if provided. Returns `undefined` if the prompt or version does not exist.

```ts theme={null}
// Get the latest version
const latest = await registry.get('support-system');

// Pin to a specific version
const pinned = await registry.get('support-system', 1);
```

### `registry.list(name)`

Returns all versions for a named prompt as a `PromptVersion[]` array, oldest first.

```ts theme={null}
const versions = await registry.list('support-system');
// → [{ version: 1, ... }, { version: 2, ... }]
```

### `registry.names()`

Returns an array of all prompt names registered in the store.

```ts theme={null}
const names = await registry.names();
// → ['support-system', 'onboarding-intro', 'safety-guardrail']
```

## Diffing versions

`registry.diff(name, from, to)` returns a line-level diff between two versions. Use this in a deploy pipeline or admin UI to review prompt changes before promoting them.

```ts theme={null}
const diff = await registry.diff('support-system', 1, 2);
// diff.from    → 1
// diff.to      → 2
// diff.added   → lines present in v2 but not v1
// diff.removed → lines present in v1 but not v2
```

`PromptDiff` fields:

| Field     | Type       | Description                         |
| --------- | ---------- | ----------------------------------- |
| `from`    | `number`   | The base version number             |
| `to`      | `number`   | The target version number           |
| `added`   | `string[]` | Lines added in the target version   |
| `removed` | `string[]` | Lines removed from the base version |

## Rendering templates

`renderPrompt(template, vars)` fills `{{varName}}` placeholders in a template string with values from a plain object. Missing variables are replaced with empty strings.

```ts theme={null}
import { renderPrompt } from 'anvil-sdk/prompt';

const template = 'You are a support agent for {{company}}. Today is {{date}}.';

const rendered = renderPrompt(template, {
  company: 'Acme Corp',
  date: new Date().toDateString(),
});
// → 'You are a support agent for Acme Corp. Today is Mon Jun 10 2025.'
```

Placeholders support optional whitespace: `{{ varName }}` and `{{varName}}` are both valid.

## Using a registry in an agent

Fetch the prompt template at startup, render it with runtime variables, and pass it as the agent's `system` prompt.

<Steps>
  <Step title="Register your prompt (once, at setup time)">
    ```ts theme={null}
    import { PromptRegistry } from 'anvil-sdk/prompt';
    import { SqliteStateStore } from 'anvil-sdk/store';

    const store = await SqliteStateStore.open();
    const registry = new PromptRegistry(store);

    await registry.register(
      'support-system',
      'You are a support agent for {{company}}. Be concise and empathetic. Today\'s date is {{date}}.',
      'Initial version with date and company vars',
    );
    ```
  </Step>

  <Step title="Fetch and render the prompt in your agent definition">
    ```ts theme={null}
    import { defineAgent } from 'anvil-sdk/agent';
    import { renderPrompt } from 'anvil-sdk/prompt';

    // Fetch the latest version (or pin with a version number)
    const promptVersion = await registry.get('support-system');

    export default defineAgent({
      name: 'support-agent',
      model: 'gpt-4o-mini',

      system: renderPrompt(promptVersion!.template, {
        company: process.env.COMPANY_NAME ?? 'Acme',
        date: new Date().toDateString(),
      }),

      async run(ctx) {
        return ctx.complete();
      },
    });
    ```
  </Step>

  <Step title="Roll back without redeploying">
    Pin a different version number in `registry.get()` and restart the process — no code change required.

    ```ts theme={null}
    // Roll back to v1 by changing the version argument
    const promptVersion = await registry.get('support-system', 1);
    ```
  </Step>
</Steps>

## Reviewing changes programmatically

Run a diff in CI to surface prompt changes alongside code changes:

```ts theme={null}
const history = await registry.list('support-system');
const lastTwo = history.slice(-2);

if (lastTwo.length === 2) {
  const diff = await registry.diff(
    'support-system',
    lastTwo[0].version,
    lastTwo[1].version,
  );
  console.log('Added lines:');
  diff.added.forEach((line) => console.log(' + ' + line));
  console.log('Removed lines:');
  diff.removed.forEach((line) => console.log(' - ' + line));
}
```

<Tip>
  Store the `PromptRegistry` instance as a singleton module export so every route and agent shares the same registry and the same underlying `StateStore` connection.
</Tip>
