Docs

Build with Lexem.

Lexem is version control + evals + safe deploys for the prompts that drive your AI. This page covers everything from signup to shipping a prompt change in production.

1

Quick start

From zero to a prompt fetched in your code — about five minutes.

  1. 1

    Sign up and create a project

    Hit signup with email or Google. A “Personal” team is created automatically; rename it from Settings if you'll be inviting teammates. Then create a project from the dashboard.

  2. 2

    Add a prompt and commit a version

    Open the project, click New prompt, name it, and write the prompt body in the editor. Add typed variables with {{name: string}} syntax. When you're happy, hitCommit — that snapshot is now an immutable version with an author, timestamp, and commit message.

  3. 3

    (Optional) Promote to an environment

    Every project ships with dev, staging, and production environments. Click Environments on the project page, then Promote to deploy a specific version to dev. Promotion follows dev → staging → production; you can toggle approval-required on any environment column.

  4. 4

    Generate an API key

    From the project page, click API keys New API key. Save the lxm_... token shown — this is the only time you'll see it. Admins and Owners only.

  5. 5

    Fetch it from your code

    TypeScript
    import { createClient } from "lexem-sdk";
    
    const lexem = createClient({ apiKey: process.env.LEXEM_API_KEY! });
    
    const p = await lexem.get("your-prompt-slug", { env: "production" });
    console.log(p.content);   // the prompt text
    console.log(p.versionId); // log this with your LLM call
    Pro tip
    Log versionId alongside every LLM call. When a regression appears in production, you'll know exactly which version of which prompt produced the output.
2

Concepts

A handful of nouns power the entire product. Once these click, the UI navigates itself.

Project

A collection of prompts owned by a team. Permissions, environments, and API keys are scoped to a project.

Prompt & Version

A prompt is a named slot (e.g. summarizer). A version is an immutable snapshot of that prompt's content at a point in time, with a commit message and an author. You never overwrite a version — you commit a new one.

Branches & tags

Branches let you commit experimental variants without touching main. Merge a branch back to main when its eval score beats the incumbent. Tags (v1.0, stable,pre-launch) attach human-readable labels to specific versions.

Evals

An eval is a suite of test cases — each with input variables and an expected output — run against a prompt version. Three scorers are built in: exact match, regex, and LLM-as-judge. Lexem auto-flags regressions when a new version's score drops more than 5 points from the previous one.

Environments

Every project has three environments — dev, staging, production — seeded automatically. Each environment holds an active version per prompt. Promotion is strictly chained: a version must be live in dev before it can be promoted to staging, and live in staging before it can reach production. The order is enforced server-side.

Approvals

Toggle approval required on any environment column. With approval on, a promote click creates a pending Deployment that doesn't flip the active version until a teammate approves it from the Pending approvals panel at the top of the environments page.

API keys

Project-scoped bearer tokens (lxm_...) used by the SDK and REST API to fetch prompts. Generated by Admins, hashed at rest, shown once on creation, and revocable any time. lastUsedAt ticks with every successful auth so you can audit usage.

Team roles

Four tiers. Permissions stack — every tier inherits everything below it:

CapabilityViewerEditorAdminOwner
View prompts, versions, evals, environments
Commit, branch, merge, tag, rollback·
Create / edit / run evals·
Promote to envs · approve / reject··
Manage provider keys + API keys··
Manage members & invites··
Promote Admins / rename team···
3

TypeScript SDK

The official JavaScript / TypeScript SDK wraps the REST API with a small, typed surface, an in-memory cache, and a render() helper for variable interpolation. Requires Node 18+ (uses globalfetch).

Beta
lexem-sdk is published on npm at 0.1.x — beta while the wire format stabilizes. Pin a specific version in production.

Install

bash
npm install lexem-sdk
# or
pnpm add lexem-sdk
# or
yarn add lexem-sdk

Create a client

TypeScript
import { createClient } from "lexem-sdk";

const lexem = createClient({
  apiKey: process.env.LEXEM_API_KEY!,
  baseUrl: "https://api.lexem.site",  // optional; default shown
  cacheTtlMs: 30_000,                  // optional; default 30s, 0 to disable
});

Get a prompt

TypeScript
const p = await lexem.get("summarizer", { env: "production" });
// {
//   content: "You are a helpful summarizer...",
//   versionId: "clxa...",
//   variables: [{ name: "article", type: "string", default: null }],
//   env: "production",
//   fetchedAt: "2026-05-17T08:00:00Z"
// }

Omit env to fetch the prompt's current main-branch head — useful in early development before you start promoting.

Render variables

TypeScript
const filled = await lexem.render(
  "summarizer",
  { article: "Q4 results showed..." },
  { env: "production" },
);
// returns the prompt string with {{article}} substituted

Missing variables throw by default. Pass { missing: "leave" } to keep placeholders, or { missing: "empty" } to substitute an empty string.

Caching

Results are cached in memory for 30 seconds per (slug, env) pair by default. Disable globally with cacheTtlMs: 0 in createClient, or bypass for a single call with fresh: true:

TypeScript
await lexem.get("summarizer", { env: "production", fresh: true });

// Or drop all entries (useful in tests):
lexem.clearCache();

Errors

TypeScript
import { LexemError } from "lexem-sdk";

try {
  await lexem.get("does-not-exist");
} catch (e) {
  if (e instanceof LexemError) {
    console.error(e.status, e.message);
    // 404, 'Prompt "does-not-exist" not found in this project.'
  }
}
4

REST API

If you're not on Node/TypeScript, hit the REST API directly. One public endpoint today — the same one the SDK calls.

Base URL

text
https://api.lexem.site

Authentication

Bearer token in the Authorization header. The key is the full lxm_... string from API keys.

bash
curl https://api.lexem.site/v1/prompts/summarizer?env=production \
  -H "Authorization: Bearer lxm_your_key_here"

For quick debugging only, ?api_key= is also accepted as a query parameter. Don't use this in production — it ends up in access logs and browser history.

GET /v1/prompts/:slug

Fetches the active version of a prompt.

text
Query params:
  env   (optional)  Environment name: "dev", "staging", "production",
                    or any custom env. Omit to fetch the current
                    main-branch head.

Returns 200:
  {
    "content":    "You are a helpful summarizer...",
    "versionId":  "clxa...",
    "variables":  [{ "name": "article", "type": "string", "default": null }] | null,
    "env":        "production" | "current",
    "fetchedAt":  "2026-05-17T08:00:00Z"
  }

Errors:
  401  Missing or invalid API key (or key revoked).
  404  Prompt not found in this project, or no active version
       in the requested environment.
5

Self-hosting

Lexem is open-source under MIT. Full setup instructions live in the repository README. The short version:

bash
git clone https://github.com/rudra016/lexem
cd lexem
pnpm install
pnpm --filter @lexem/db migrate
pnpm dev

You'll need:

  • Node 20.6+ and pnpm 9+
  • A PostgreSQL database
  • At least one provider API key (OpenAI / Anthropic / Google) to run evals or generate AI change summaries

When self-hosting, point the SDK at your deployment with baseUrl: "https://lexem.your-domain.com".

6

FAQ

How is this different from LangSmith or PromptLayer?

Both observe LLM calls; neither treats prompts as versioned source code. Lexem focuses on the artifact: real diff/branch/merge/rollback, eval-gated promotions, and an SDK that returns the active version per environment.

Are my prompts and provider keys safe?

Provider API keys are encrypted at rest with AES-256-GCM, scoped per team, and never returned to the client in plaintext. Lexem API keys are stored as SHA-256 hashes, prefixed in the UI for identification, and revocable.

Can I run evals against my own model deployment?

Today the runner supports OpenAI, Anthropic, and Google. A custom base-URL / endpoint shim is on the roadmap.

Does the SDK work in the browser / Edge runtime?

Anywhere global fetch is available — Node 18+, modern browsers, Cloudflare Workers, Vercel Edge. That said, putting an API key in browser JS exposes it; prefer fetching prompts server-side and shipping the rendered text to the client.

Where do I report bugs or request features?

GitHub Issues. Security disclosures: email rudra619kumar@gmail.com directly.