catalog — independently scanned and version-tracked by SaferSkills.
SaferSkills independently audited catalog (Agent Skill) and scored it 100/100 (green). The audit ran 55 deterministic rules across Security, Supply Chain, Maintenance, Transparency, and Community; it found 0 high-severity and 0 lower-severity findings. The full rule-by-rule trace and per-finding evidence are below. Free, methodology-open.
Findings & checks · 0 flagged
Every scanned point with the score it earned and what moved between them.
First recorded scan — no prior version to compare against.
The primary manifest — the file an agent reads to learn what this artifact does.
System for letting an LLM render custom React components by emitting fenced code blocks with JSON specs. The catalog ships a remark plugin, a <pre> override, and a system-prompt generator — all wired through <Chat components={catalog} />.
import {
componentCatalog,
ComponentRenderer,
ComponentError,
createComponentPre,
createChartComponentDef,
validateSpec,
generatePrompt,
type ComponentCatalog,
type ComponentDefinition,
type ComponentDefinitions,
type ComponentSpec,
type ComponentCatalogOptions,
type ComponentCatalogError,
type ComponentErrorProps
} from 'reachat';
import { z } from 'zod';Main factory. Takes a map of component definitions and returns a catalog object ready for <Chat>.
function componentCatalog(
definitions: ComponentDefinitions,
options?: ComponentCatalogOptions
): ComponentCatalog;
interface ComponentCatalogOptions {
/** Fenced-code language tag (default: 'component') */
language?: string;
/** Custom error renderer — return ReactNode or undefined for default */
onError?: (error: ComponentCatalogError) => ReactNode | undefined;
}
interface ComponentCatalog {
remarkPlugin: Plugin; // Pass-through plugin (rendering happens in <pre>)
components: Components; // { pre: ComponentPre } for react-markdown
systemPrompt: () => string; // LLM instructions
definitions: ComponentDefinitions;
}Chat accepts a catalog directly via the components prop and wires everything in:
<Chat sessions={sessions} components={catalog}>...</Chat>For advanced control, splice the pieces yourself:
<Chat
sessions={sessions}
remarkPlugins={[remarkGfm, catalog.remarkPlugin]}
markdownComponents={{ ...catalog.components, pre: MyCustomPre }}
>...</Chat>interface ComponentDefinition<TProps = Record<string, any>> {
description: string; // Used by systemPrompt
props: z.ZodType<TProps>; // Runtime validation + prompt schema
component: FC<TProps & {
children?: ReactNode;
sendMessage?: (message: string) => void;
}>;
}
type ComponentDefinitions = Record<string, ComponentDefinition>;The component receives validated props plus:
children — rendered nested specssendMessage — pulled from ChatContext so the rendered UI can dispatch a follow-up messageconst catalog = componentCatalog({
WeatherCard: {
description: 'Displays weather for a city',
props: z.object({
city: z.string().describe('City name'),
temperature: z.number().describe('Temp in Fahrenheit')
}),
component: ({ city, temperature, sendMessage }) => (
<div className="rounded-xl border p-4">
<h3>{city}</h3>
<p>{temperature}°F</p>
<button onClick={() => sendMessage?.(`Tell me more about ${city}`)}>
Tell me more
</button>
</div>
)
}
});
<Chat sessions={sessions} components={catalog}>
<SessionMessages />
<ChatInput />
</Chat>The LLM emits:
{ "type": "WeatherCard", "props": { "city": "SF", "temperature": 68 } }
interface ComponentSpec {
type: string; // Must match a key in the catalog
props: Record<string, any>; // Validated against the Zod schema
children?: ComponentSpec[]; // Optional nested specs
}{ "type": "Card", "props": {...} }[ {...}, {...} ] — multiple top-level components in one block{ "type": "Row", "props": {}, "children": [ {...}, {...} ] }Validation produces ComponentCatalogError with one of four types:
| type | When |
|---|---|
invalid_json | The fenced block is not valid JSON |
unknown_component | spec.type is not in the catalog |
invalid_props | Zod validation failed (issues passed through) |
render_error | The component threw during render |
Each component is wrapped in a React error boundary so a single failure doesn't break the markdown stream. Provide a custom UI via options.onError:
componentCatalog(defs, {
onError: error =>
error.type === 'invalid_props' ? (
<pre>{JSON.stringify(error.issues, null, 2)}</pre>
) : undefined
});Generates LLM instructions describing the available components, their descriptions, and Zod-derived prop schemas. Useful as a system message when calling your model.
const prompt: string = catalog.systemPrompt();Pre-built definition that wraps ChartRenderer, allowing the LLM to render charts.
import { componentCatalog, createChartComponentDef } from 'reachat';
const catalog = componentCatalog({
Chart: createChartComponentDef()
});LLM output:
{ "type": "Chart", "props": { "type": "bar", "title": "Active users", "data": [{ "key": "Mon", "data": 12 }, { "key": "Tue", "data": 18 }] } }
Supported types: bar, line, area, pie, radialBar, radialArea, sparkline. Requires reaviz as a peer dependency.
<pre> override component used in catalog.components (for advanced custom wiring)ComponentSpec directly (for custom dispatch outside of markdown)ComponentErrorPropszod — required, used for runtime prop validationreaviz — peer-optional, only needed for createChartComponentDef()theme.component.base~30 seconds. Free. No account. Every finding cites a rule and a line of evidence.