Appearance
Recipes API (Recipe Handles)
Recipes are the front door to llm-core. Everything is a recipe handle: some recipes are leaf steps, some are composite, but the public surface is the same.
> **Recipes are the public story.** Packs/flows are internal composition tools; most users never need them.
Related:
Recipe handles (the public surface)
Every recipe exposes the same handle methods:
configure(config)— recipe-specific behavior (prompts, retrieval knobs, tool options).defaults(defaults)— wiring and infra (adapters, plugins, retry defaults).use(otherRecipe)— composition (pluggable sub-recipes).plan()— returns the step graph (no side effects).build()— returns a reusable runnable.run(input, runtime?)— one-shot execution.
Use defaults({ retryDefaults }) when you want per-recipe retry policy defaults; per-run overrides live in runtime.retry.
ts
import { recipes } from "@geekist/llm-core/recipes";
import type { AgentRecipeConfig } from "@geekist/llm-core/recipes";
// Configure once, reuse across requests.
const agent = recipes["agent"]()
.configure({
planning: { modelInstructions: "Plan before acting." },
tools: { toolChoice: "auto" },
} satisfies AgentRecipeConfig)
.defaults({ adapters: { model, tools, memory } }); // Wire adapters once.
const result = await agent.run({ input: "Help me debug this RAG flow." });Recipe-specific config (no global junk drawer)
Each recipe exports its own config type. configure() only accepts that type. There is no global RecipeConfig bag.
ts
import type { RagRecipeConfig } from "@geekist/llm-core/recipes";
const rag = recipes["rag"]().configure({
retrieval: { topK: 8 },
synthesis: { system: "Cite your sources." },
} satisfies RagRecipeConfig);plan(): see the graph
plan() gives you a stable, inspectable view of the recipe DAG.
ts
type PlanView = { steps: Array<{ id: string }> };
const plan: PlanView = recipes["rag"]().plan();
// Inspect the resolved step graph.
console.log(plan.steps.map((step) => step.id));build(): reusable runnables
build() is optional, but useful when you want to cache a configured recipe.
ts
const runnable = recipes["rag"]()
.configure({ retrieval: { topK: 5 } })
.defaults({ adapters: { model, retriever } }) // Keep wiring separate.
.build();
type RagRunnable = typeof runnable;
const outcome = await(runnable as RagRunnable)({ input: "Explain DSP." });