@plugdash/enrichkit

enrichkit

480 words·3min read

What it does

On every publish, enrichkit makes one LLM call and writes a summary, key topics, auto-tags, a reading level estimate, and a tweet draft to post metadata. You choose which of those five fields to generate. Content under 100 words is skipped - not worth the API call.

There is no companion component. enrichkit writes metadata, not markup - what you do with a summary or a tweet draft is up to your layout, your search index, or an agent reading the post.

Install

npm install @plugdash/enrichkit

Register

Open astro.config.mjs at the root of your Astro project. Import the plugin at the top, then add it to the pluginsarray of the emdash() integration - the one that sits inside Astro's top-level integrations array:

astro.config.mjsjs
import { defineConfig } from "astro/config"
import emdash from "emdash/astro"
import { enrichkitPlugin } from "@plugdash/enrichkit"

export default defineConfig({
  integrations: [
    emdash({
      plugins: [
        enrichkitPlugin({
          provider: "anthropic",
          apiKey: process.env.ANTHROPIC_API_KEY,
        }),
      ],
    }),
  ],
})

Set ANTHROPIC_API_KEY (or OPENAI_API_KEY if you pick OpenAI) as a secret in your build environment. You can also leave apiKey out at build time entirely and set it later from the admin at /_emdash/admin/plugins/enrichkit/settings - either way, the key is only ever read from KV at request time and is never rendered back into the UI (the settings form shows a masked hint like sk-t...1234).

allowedHosts is narrowed automatically to the configured provider's API host (api.anthropic.com orapi.openai.com). With no provider set yet, both hosts are allowed until the admin page picks one.

How it fires

publish (status: published) -> body >= 100 words -> one prompt built for the enabled fields -> provider call (20s timeout) -> parse + validate JSON -> merge into metadata

A few things worth knowing before you flip this on:

  • Only fires on content:afterSave when the content's status is published - drafts, archived, and scheduled content are never enriched.
  • The Portable Text body is flattened to plain text and capped at 12,000 characters before it goes into the prompt - the opening of a long article carries the argument, the tail rarely changes the summary.
  • If the model's reply isn't valid JSON, enrichkit retries once. Two failed parses in a row and it gives up and logs - never more than two provider calls per publish.
  • A rate limit (429) is not retried synchronously - the next publish gets a fresh attempt.
  • An over-length tweet draft is dropped, not truncated. A tweet cut mid-word is worse than no tweet.
  • Every enrichment failure - missing key, timeout, rate limit, invalid JSON, quota error - just skips and logs. It never fails the publish itself.
  • Metadata is read-merge-written, so other plugins' keys under post.data.metadata are preserved.

Examples

Config variants

Default enrichments are summary, key topics, auto-tags, and a tweet draft - reading level is off unless you turn it on. To also get the reading level and skip the tweet draft:

js
enrichkitPlugin({
  provider: "anthropic",
  apiKey: process.env.ANTHROPIC_API_KEY,
  enrichments: {
    readingLevel: true,
    tweetDraft: false,
  },
})

Or run it against OpenAI instead, with an explicit model override:

js
enrichkitPlugin({
  provider: "openai",
  apiKey: process.env.OPENAI_API_KEY,
  model: "gpt-4o",
})

Reading the metadata

Since there's no component, you read post.data.metadata.enrichkitdirectly wherever you want it - typically the post layout:

astro
---
const enrichkit = post.data.metadata?.enrichkit
---
{enrichkit?.summary && <p class="summary">{enrichkit.summary}</p>}
{enrichkit?.autoTags && (
  <ul class="tags">
    {enrichkit.autoTags.map((tag) => <li>{tag}</li>)}
  </ul>
)}

Sample output

Sample output with every enrichment on, rendered the way a theme might show it

summary

A look at how static sites evolved from plain HTML to full content platforms, and what that means for publishers choosing a stack today.

keyTopics

static site generators · content management · web performance

autoTags
  • #ssg
  • #cms
  • #performance
  • #web-dev
readingLevel

Grade 9

tweetDraft
Static sites grew up. Here's what changed and why it matters for your next project.

A published post with all default enrichments on ends up with this under post.data.metadata.enrichkit:

json
{
  "summary": "A look at how static sites evolved from plain HTML to full content platforms, and what that means for publishers choosing a stack today.",
  "keyTopics": ["static site generators", "content management", "web performance"],
  "autoTags": ["ssg", "cms", "performance", "web-dev"],
  "tweetDraft": "Static sites grew up. Here's what changed and why it matters for your next project.",
  "generatedAt": "2026-04-01T12:00:00Z",
  "model": "claude-haiku-4-5"
}

Only fields that were enabled and that passed validation get written - a field the model omitted, or returned in the wrong shape, is left out entirely rather than written as null.

No component

enrichkit ships no companion component. It writes metadata, full stop - rendering a summary or a tag list in your theme is a few lines in your layout, and an agent working against the site can read the same fields through the EmDash MCP server without any UI at all.

Props

proptypedefaultdescription
provider"anthropic" | "openai"Required - which LLM API to call
apiKeystringRequired - API key for the chosen provider
modelstringprovider defaultclaude-haiku-4-5 (Anthropic) or gpt-4o-mini (OpenAI)
enrichments.summarybooleantrue2-3 sentence summary of the main argument
enrichments.keyTopicsbooleantrue3-5 main topics as short noun phrases
enrichments.readingLevelbooleanfalseEstimated grade level (e.g. "Grade 8")
enrichments.autoTagsbooleantrue3-8 lowercase, hyphenated discovery tags
enrichments.tweetDraftbooleantrueTweet draft under 280 characters

For agents

After installing @plugdash/enrichkit and registering it in astro.config.mjs:

  1. Set an API key - either at build time via the apiKey option (read from an env var) or later from the admin settings page.
  2. Publish a test post with at least 100 words of body text.
  3. Verify post.data.metadata.enrichkit is populated: summary (string), keyTopics (string array, if enabled), readingLevel (string, if enabled - off by default), autoTags (lowercase hyphenated string array, if enabled), tweetDraft (string, under 280 chars, if enabled), generatedAt (ISO timestamp), and model (the model id used).

If no enrichkit metadata appears, check in order: the post status is "published" and not a draft; the body has at least 100 words; an API key is configured (look for "apiKey not configured" in the plugin logs); and the post was saved after the plugin was installed or reconfigured.

post.data.metadata.enrichkit.tweetDraft in particular is written specifically so an agent with access to the EmDash MCP server can read it and post to social platforms after a human publishes - no further human step required for that part of the workflow.

built with plugdash.dev