Installation

Alchemy is distributed as scoped npm packages. Install the core and Node.js packages:

bash
# Core + Node runtime
pnpm add @edv4h/alchemy-core @edv4h/alchemy-node

# Add a transmuter plugin for your LLM provider
pnpm add @edv4h/alchemy-plugin-transmuter-openai    # OpenAI
# pnpm add @edv4h/alchemy-plugin-transmuter-anthropic  # Anthropic
# pnpm add @edv4h/alchemy-plugin-transmuter-google     # Google Gemini

If you plan to use structured output with JSON schemas, also install Zod:

bash
pnpm add zod
Prerequisites

Node.js 18+ and an OpenAI API key. Set your key as the OPENAI_API_KEY environment variable or pass it directly to the transmuter.

Your First Recipe

A Recipe defines what Alchemy should do — the prompt (Spell), the output format (Refiner), and optional settings like roleDefinition and temperature.

ts
import { Alchemist } from "@edv4h/alchemy-node";
import { OpenAITransmuter } from "@edv4h/alchemy-plugin-transmuter-openai";

// 1. Create an Alchemist with an OpenAI transmuter
const alchemist = new Alchemist({
  transmuter: new OpenAITransmuter({
    apiKey: process.env.OPENAI_API_KEY,
  }),
});

// 2. Run a simple text recipe
const result = await alchemist.transmute({
  recipe: {
    spell: { output: "Translate this to French" },
  },
  materials: [{ type: "text", text: "Hello, world!" }],
});

console.log(result.output);
// → "Bonjour, le monde !"

That's it! The Alchemist takes your materials (inputs), applies the spell (prompt), sends it through the transmuter (OpenAI), and returns the result.

Structured Output with Zod

The real power of Alchemy is type-safe structured output. Use JsonRefiner with a Zod schema to get validated, typed responses:

ts
import { JsonRefiner } from "@edv4h/alchemy-core";
import { z } from "zod";

// Define your output schema
const SentimentSchema = z.object({
  sentiment: z.enum(["positive", "negative", "neutral"]),
  confidence: z.number().min(0).max(1),
  keywords: z.array(z.string()),
});

const result = await alchemist.transmute({
  recipe: {
    spell: { output: "Analyze the sentiment of this text" },
    refiner: new JsonRefiner(SentimentSchema),
  },
  materials: [{ type: "text", text: "I absolutely love this product!" }],
});

// result.output is fully typed as:
// { sentiment: "positive" | "negative" | "neutral";
//   confidence: number;
//   keywords: string[] }
console.log(result.output.sentiment);   // "positive"
console.log(result.output.confidence);  // 0.95
console.log(result.output.keywords);    // ["love", "product"]
Tip

The JsonRefiner automatically adds format instructions to the prompt, strips markdown code fences from the response, and validates the output against your Zod schema.

Streaming

For long responses, use the stream method to get results as they arrive:

ts
const stream = alchemist.stream({
  recipe: {
    spell: { output: "Write a short story about an alchemist" },
  },
  materials: [{ type: "text", text: "A mysterious laboratory..." }],
});

for await (const chunk of stream) {
  process.stdout.write(chunk);
}
// Outputs text progressively as it's generated

Next Steps

  • Concepts — Learn about Materials, Transforms, Spells, Transmuters, and Refiners in depth.
  • API Reference — Full API documentation for all three packages.
  • Examples — Real-world code examples and patterns.