Prismic
The @yak-io/prismic package adapts your Prismic content into Yak primitives. It produces standard RouteSource, ToolSource, and ToolAdapter values that compose with the existing framework SDKs — most commonly @yak-io/nextjs or @yak-io/nuxt.
What you get
createPrismicRouteAdapter— turn published Prismic documents into the route manifest the LLM uses for navigation.createPrismicToolAdapter— exposeprismic.getByUID,prismic.getAllByType, andprismic.searchas tools the assistant can invoke.createPrismicGraphQLToolAdapter— introspect your repo's GraphQL schema and return a browser-executedToolAdapter(agraphql_prismictool) so the assistant can query your content model directly.
Installation
npm install @yak-io/prismic @yak-io/javascript @prismicio/clientpnpm add @yak-io/prismic @yak-io/javascript @prismicio/clientyarn add @yak-io/prismic @yak-io/javascript @prismicio/clientbun add @yak-io/prismic @yak-io/javascript @prismicio/client@prismicio/client (v7+) is a peer dependency. If you want to use the GraphQL adapter, also install graphql.
Quick Start
Create a Prismic client
Wherever you would normally configure Prismic — usually a shared prismicio.ts:
import * as prismic from "@prismicio/client";
export const prismicClient = prismic.createClient("your-repo-name", {
accessToken: process.env.PRISMIC_ACCESS_TOKEN,
});Build the adapters
Each factory takes the client plus a small config. Routes need a resolveRoute mapper from document → RouteInfo. Tools need an allowedTypes list — this is the security boundary for what the LLM can read.
import {
createPrismicRouteAdapter,
createPrismicToolAdapter,
} from "@yak-io/prismic";
import { prismicClient } from "./prismicio";
export const prismicRoutes = createPrismicRouteAdapter({
client: prismicClient,
documentTypes: ["page", "blog_post"],
resolveRoute: (doc) => ({
path: `/${doc.uid}`,
title: doc.data.meta_title ?? doc.data.title,
description: doc.data.meta_description,
}),
});
export const prismicTools = createPrismicToolAdapter({
client: prismicClient,
allowedTypes: ["page", "blog_post"],
});Plug them into your Yak handler
See the framework sections below — the exact wiring differs between Next.js and Nuxt, but in both cases you pass the adapters straight into the standard handler config.
Using with Next.js
Pair @yak-io/prismic with @yak-io/nextjs. The Next.js handler accepts route and tool sources as arrays, so you can combine Prismic-sourced routes with the filesystem auto-scan or with other tool adapters in the same handler.
import { createNextYakHandler } from "@yak-io/nextjs/server";
import {
createPrismicRouteAdapter,
createPrismicToolAdapter,
} from "@yak-io/prismic";
import { prismicClient } from "@/prismicio";
const prismicRoutes = createPrismicRouteAdapter({
client: prismicClient,
documentTypes: ["page", "blog_post"],
resolveRoute: (doc) => ({
path: `/${doc.uid}`,
title: doc.data.meta_title ?? doc.data.title,
description: doc.data.meta_description,
}),
});
const prismicTools = createPrismicToolAdapter({
client: prismicClient,
allowedTypes: ["page", "blog_post"],
});
export const { GET, POST } = createNextYakHandler({
appDir: "./src/app",
routes: [prismicRoutes],
tools: [prismicTools],
});If you want filesystem routes and Prismic routes, just include both in the array — the handler merges and deduplicates by path:
import { scanRoutes } from "@yak-io/nextjs/server";
export const { GET, POST } = createNextYakHandler({
routes: [
() => scanRoutes("./src/app"),
prismicRoutes,
],
tools: [prismicTools],
});GraphQL adapter on the client
The GraphQL adapter runs in the browser. Compose it with any server-relayed tools using
createYakToolset, then wire the toolset's getConfig / onToolCall into your YakProvider:
"use client";
import { createYakServerAdapter, createYakToolset, YakProvider, YakWidget } from "@yak-io/nextjs/client";
import { createPrismicGraphQLToolAdapter } from "@yak-io/prismic";
import { prismicClient } from "@/prismicio";
let toolset: ReturnType<typeof createYakToolset> | null = null;
async function getToolset() {
if (!toolset) {
const prismicGraphQL = await createPrismicGraphQLToolAdapter({
client: prismicClient,
headers: async () => ({ "Prismic-ref": await prismicClient.getMasterRef().then((r) => r.ref) }),
});
toolset = createYakToolset([createYakServerAdapter({ endpoint: "/api/yak" }), prismicGraphQL]);
}
return toolset;
}
export function Providers({ children }: { children: React.ReactNode }) {
return (
<YakProvider
appId={process.env.NEXT_PUBLIC_YAK_APP_ID!}
getConfig={async () => ({ routes, ...(await (await getToolset()).getConfig()) })}
onToolCall={async (name, args) => (await getToolset()).onToolCall(name, args)}
>
{children}
<YakWidget />
</YakProvider>
);
}Cache the introspection result. The GraphQL schema rarely changes between sessions, and you don't want to re-introspect on every chat open.
Using with Nuxt
Pair @yak-io/prismic with @yak-io/nuxt. Nuxt's server side uses Nitro routes; you call the underlying createYakHandler from @yak-io/javascript/server and pass the adapters into it the same way.
import { createYakHandler } from "@yak-io/javascript/server";
import {
createPrismicRouteAdapter,
createPrismicToolAdapter,
} from "@yak-io/prismic";
import { prismicClient } from "~/prismicio";
const prismicRoutes = createPrismicRouteAdapter({
client: prismicClient,
documentTypes: ["page", "blog_post"],
resolveRoute: (doc) => ({
path: `/${doc.uid}`,
title: doc.data.meta_title ?? doc.data.title,
description: doc.data.meta_description,
}),
});
const prismicTools = createPrismicToolAdapter({
client: prismicClient,
allowedTypes: ["page", "blog_post"],
});
const { GET } = createYakHandler({
routes: [prismicRoutes],
tools: [prismicTools],
});
export default defineEventHandler(async (event) => {
const request = toWebRequest(event);
const response = await GET(request);
return response.json();
});import { createYakHandler } from "@yak-io/javascript/server";
import { createPrismicToolAdapter } from "@yak-io/prismic";
import { prismicClient } from "~/prismicio";
const { POST } = createYakHandler({
routes: [],
tools: [
createPrismicToolAdapter({
client: prismicClient,
allowedTypes: ["page", "blog_post"],
}),
],
});
export default defineEventHandler(async (event) => {
const request = toWebRequest(event);
const response = await POST(request);
return response.json();
});GraphQL adapter on the client
In your .client.ts Nuxt plugin, compose the Prismic GraphQL adapter with the server adapter:
import { createYakProvider, createYakServerAdapter, createYakToolset } from "@yak-io/nuxt";
import { createPrismicGraphQLToolAdapter } from "@yak-io/prismic";
import { prismicClient } from "~/prismicio";
let toolset: ReturnType<typeof createYakToolset> | null = null;
export default defineNuxtPlugin((nuxtApp) => {
const yak = createYakProvider({
appId: useRuntimeConfig().public.yakAppId,
getConfig: async () => {
toolset ??= createYakToolset([
createYakServerAdapter({ endpoint: "/api/yak" }),
await createPrismicGraphQLToolAdapter({ client: prismicClient }),
]);
return { routes, ...(await toolset.getConfig()) };
},
onToolCall: async (name, args) => toolset!.onToolCall(name, args),
});
nuxtApp.hook("app:mounted", () => yak.mount());
return { provide: { yak } };
});API Reference
createPrismicRouteAdapter
const routes = createPrismicRouteAdapter({
client: prismicClient,
documentTypes: ["page", "blog_post"],
resolveRoute: (doc) => ({ path: `/${doc.uid}` }),
});| Option | Type | Description |
|---|---|---|
client | Client | A @prismicio/client instance |
documentTypes | string[] | Which Prismic custom types to include in the route manifest |
resolveRoute | (doc) => RouteInfo | null | Map each document to a RouteInfo entry. Return null to skip a document (drafts, hidden pages, etc.) |
filters | string[] | Optional additional Prismic filter expressions, appended after the type filter |
id | string | Optional source identifier (default: "prismic") |
createPrismicToolAdapter
const tools = createPrismicToolAdapter({
client: prismicClient,
allowedTypes: ["page", "blog_post"],
});| Option | Type | Description |
|---|---|---|
client | Client | A @prismicio/client instance |
allowedTypes | string[] | Document types the LLM is allowed to query. Required — this is the security boundary |
fields | Record<string, string[]> | Optional per-type field projection. Translated to Prismic's GraphQuery DSL on the wire |
id | string | Optional source identifier (default: "prismic") |
The adapter exposes three tools:
| Tool name | Purpose |
|---|---|
prismic.getByUID | Fetch one document by (type, uid) |
prismic.getAllByType | List all documents of a given type (default limit: 20) |
prismic.search | Full-text search across allowed types |
createPrismicGraphQLToolAdapter
const prismicGraphQL = await createPrismicGraphQLToolAdapter({
client: prismicClient,
});Introspects your Prismic repo's /graphql endpoint once and returns a browser-executed
ToolAdapter exposing a graphql_prismic tool.
| Option | Type | Description |
|---|---|---|
client | Client | A @prismicio/client instance |
name | string | Tool name suffix — exposed as graphql_<name> (default: "prismic") |
endpoint | string | Override the GraphQL endpoint (defaults to the repo's derived /graphql URL) |
headers | HeadersInit | (() => HeadersInit | Promise<HeadersInit>) | Execution headers, e.g. Prismic-ref. May be async to fetch the master ref per call |
fetchFn | typeof fetch | Optional fetch override for the one-time introspection (testing) |
GraphQL mode requires the graphql package to be installed alongside this adapter.
Composing with other sources
Route and tool sources merge cleanly. You can pair Prismic with anything else in the same handler:
import { createNextYakHandler } from "@yak-io/nextjs/server";
import { createTRPCToolAdapter } from "@yak-io/trpc";
import { createPrismicToolAdapter } from "@yak-io/prismic";
import { appRouter, createContext } from "@/server/trpc";
import { prismicClient } from "@/prismicio";
export const { GET, POST } = createNextYakHandler({
appDir: "./src/app",
tools: [
createPrismicToolAdapter({
client: prismicClient,
allowedTypes: ["page", "blog_post"],
}),
createTRPCToolAdapter({
router: appRouter,
createContext: async ({ req }) => createContext({ req }),
allowedProcedures: ["orders.list", "orders.getById"],
}),
],
});The route manifest merger dedupes by path, so a Prismic-sourced /about route won't conflict with a filesystem-sourced one.
Security
allowedTypes defines the read surface the LLM has into your Prismic repository. Without it, anyone using the assistant could ask it to fetch internal document types (settings, feature_flags, etc.). Always set this to the minimal list of public content types.
- Restrict
documentTypes(routes) andallowedTypes(tools) to the document types that are genuinely public. - Use
resolveRoutereturningnullto filter unpublished drafts out of the route manifest. - Tool calls execute server-side via
createYakHandler/createNextYakHandler— your Prismic access token never reaches the browser.