npm package discovery and stats viewer.

Discover Tips

  • General search

    [free text search, go nuts!]

  • Package details

    pkg:[package-name]

  • User packages

    @[username]

Sponsor

Optimize Toolset

I’ve always been into building performant and accessible sites, but lately I’ve been taking it extremely seriously. So much so that I’ve been building a tool to help me optimize and monitor the sites that I build to make sure that I’m making an attempt to offer the best experience to those who visit them. If you’re into performant, accessible and SEO friendly sites, you might like it too! You can check it out at Optimize Toolset.

About

Hi, 👋, I’m Ryan Hefner  and I built this site for me, and you! The goal of this site was to provide an easy way for me to check the stats on my npm packages, both for prioritizing issues and updates, and to give me a little kick in the pants to keep up on stuff.

As I was building it, I realized that I was actually using the tool to build the tool, and figured I might as well put this out there and hopefully others will find it to be a fast and useful way to search and browse npm packages as I have.

If you’re interested in other things I’m working on, follow me on Twitter or check out the open source projects I’ve been publishing on GitHub.

I am also working on a Twitter bot for this site to tweet the most popular, newest, random packages from npm. Please follow that account now and it will start sending out packages soon–ish.

Open Software & Tools

This site wouldn’t be possible without the immense generosity and tireless efforts from the people who make contributions to the world and share their work via open source initiatives. Thank you 🙏

© 2026 – Pkg Stats / Ryan Hefner

prompt-kit-js

v1.0.0

Published

Lightweight, versioned prompt template manager for LLM apps — variable injection, template registry, and a rough token-count estimator. Framework/provider agnostic (OpenAI, Groq, Anthropic, anything).

Readme

prompt-kit-js


⚡ Why prompt-kit-js?

In most production AI applications, prompts start as messy string literals scattered across multiple backend files. When you want to iterate, A/B test a wording change, rollback a regression, or track which model a prompt was tuned for, things quickly get out of hand.

prompt-kit-js provides a centralized in-memory registry for your prompts:

  • 🎯 Centralized Registry: Keep all your system prompts and few-shot templates organized in one place.
  • 🗂️ Semantic Versioning: Store multiple versions (1.0.0, 1.1.0, 2.0.0) of the same prompt and pin specific versions for specific models.
  • 🛡️ Variable Validation: Strict mode catches missing {{placeholders}} at render time before wasting LLM API credits.
  • 📊 Token Estimation: Built-in zero-dependency heuristic to estimate token budgets before dispatching requests.
  • 🤖 Provider Agnostic: Works seamlessly with OpenAI, Anthropic Claude, Google Gemini, Groq, Mistral, Ollama, or custom pipelines.
  • 🪶 Zero Dependencies: Weighs less than ~2 KB minified with dual ESM & CJS support.

📦 Installation

# npm
npm install prompt-kit-js

# pnpm
pnpm add prompt-kit-js

# yarn
yarn add prompt-kit-js

# bun
bun add prompt-kit-js

🚀 Quick Start

import { PromptRegistry } from "prompt-kit-js";

// 1. Create a prompt registry
const prompts = new PromptRegistry();

// 2. Register your templates
prompts.register({
  id: "customer-support-summary",
  version: "1.0.0",
  description: "Summarizes user support ticket into bullet points",
  template: `You are an AI assistant for {{companyName}}.
Summarize the following support conversation with priority level {{priority}}:

Ticket ID: {{ticketId}}
Conversation:
{{transcript}}

Output format: JSON { summary: string, actionItems: string[] }`,
  variables: ["companyName", "priority", "ticketId", "transcript"],
  tags: ["support", "summary", "gpt-4o"],
});

// 3. Render the prompt with inputs
const promptText = prompts.render("customer-support-summary", {
  companyName: "Acme Corp",
  priority: "HIGH",
  ticketId: "TCK-8941",
  transcript: "Customer: I cannot log in after password reset...",
});

console.log(promptText);

🔄 Prompt Versioning & A/B Testing

You can register multiple iterations of a prompt under the same id. By default, render() always uses the most recently registered version, but you can explicitly pin an older version:

// Version 1.0.0
prompts.register({
  id: "codegen-assistant",
  version: "1.0.0",
  template: "Write a {{language}} function that does: {{task}}",
});

// Version 2.0.0 (improved few-shot prompt tuned for newer models)
prompts.register({
  id: "codegen-assistant",
  version: "2.0.0",
  template: "You are an expert {{language}} developer. Follow clean code and SOLID principles.\nTask: {{task}}\nProvide typed code with unit tests.",
});

// Uses latest version (2.0.0)
const latestPrompt = prompts.render("codegen-assistant", {
  language: "TypeScript",
  task: "parse ISO timestamp",
});

// Pin to older version (1.0.0) for legacy systems
const legacyPrompt = prompts.render("codegen-assistant", {
  language: "TypeScript",
  task: "parse ISO timestamp",
}, { version: "1.0.0" });

📊 Token Estimation & Budget Hints

Estimate token counts before making expensive API calls:

const { prompt, estimatedTokens } = prompts.renderWithStats("codegen-assistant", {
  language: "Python",
  task: "implement a distributed priority queue with Redis",
});

console.log(`Estimated prompt size: ~${estimatedTokens} tokens`);

// Or use the standalone estimator directly:
import { estimateTokens } from "prompt-kit-js";

const tokens = estimateTokens("Analyze the following 50 pages of financial logs...");

Note: This is a fast, zero-dependency heuristic (~4 characters per token + word-weight blending). It is ideal for rate-limit protection, context-window budgeting, and UI warnings.


🛡️ Strict vs Lenient Rendering

Strict Mode (Default)

Throws a MissingVariableError if any {{variable}} found in the template is omitted from the input:

try {
  prompts.render("customer-support-summary", {
    companyName: "Acme Corp",
    // Missing ticketId, priority, transcript
  });
} catch (err) {
  if (err instanceof MissingVariableError) {
    console.error(err.message);
    // => prompt-kit: template "customer-support-summary" is missing required variable "priority"
  }
}

Lenient Mode

If you prefer missing variables to evaluate to empty strings "":

const result = prompts.render(
  "customer-support-summary",
  { companyName: "Acme Corp" },
  { strict: false }
);

🔍 Auto-Detecting Template Placeholders

Extract all placeholders dynamically from a registered template:

const vars = prompts.detectVariables("customer-support-summary");
console.log(vars);
// Output: ["companyName", "priority", "ticketId", "transcript"]

🤖 Real-World LLM Example (OpenAI / Anthropic / Groq)

import OpenAI from "openai";
import { PromptRegistry } from "prompt-kit-js";

const openai = new OpenAI();
const prompts = new PromptRegistry();

prompts.register({
  id: "sentiment-analyzer",
  version: "1.0.0",
  template: "Analyze the sentiment of the following customer feedback as positive, neutral, or negative.\nFeedback: {{feedback}}",
});

async function analyzeReview(reviewText: string) {
  const prompt = prompts.render("sentiment-analyzer", { feedback: reviewText });

  const completion = await openai.chat.completions.create({
    model: "gpt-4o-mini",
    messages: [{ role: "user", content: prompt }],
    temperature: 0,
  });

  return completion.choices[0].message.content;
}

📚 API Reference

PromptRegistry

| Method | Return Type | Description | |---|---|---| | register(template) | void | Adds a template version to the registry. | | registerAll(templates[]) | void | Bulk registers multiple templates. | | get(id, version?) | PromptTemplate | Retrieves raw template object (defaults to latest). | | list() | string[] | Returns an array of all registered template IDs. | | listVersions(id) | string[] | Returns all version strings registered for a template ID. | | render(id, vars, options?) | string | Fills template placeholders. Supports { version, strict }. | | renderWithStats(id, vars, options?) | { prompt, estimatedTokens } | Returns rendered prompt with token estimate. | | detectVariables(id, version?) | string[] | Inspects template string and extracts all placeholder names. |

Standalone Helpers

| Function / Class | Description | |---|---| | estimateTokens(text: string) | Heuristic token estimator (~4 chars per token). | | MissingVariableError | Thrown when a variable is absent during strict rendering. | | TemplateNotFoundError | Thrown when an ID or specified version does not exist. |


📄 License

MIT © Tushar