npm package discovery and stats viewer.

Discover Tips

  • General search

    [free text search, go nuts!]

  • Package details

    pkg:[package-name]

  • User packages

    @[username]

Sponsor

Optimize Toolset

I’ve always been into building performant and accessible sites, but lately I’ve been taking it extremely seriously. So much so that I’ve been building a tool to help me optimize and monitor the sites that I build to make sure that I’m making an attempt to offer the best experience to those who visit them. If you’re into performant, accessible and SEO friendly sites, you might like it too! You can check it out at Optimize Toolset.

About

Hi, 👋, I’m Ryan Hefner  and I built this site for me, and you! The goal of this site was to provide an easy way for me to check the stats on my npm packages, both for prioritizing issues and updates, and to give me a little kick in the pants to keep up on stuff.

As I was building it, I realized that I was actually using the tool to build the tool, and figured I might as well put this out there and hopefully others will find it to be a fast and useful way to search and browse npm packages as I have.

If you’re interested in other things I’m working on, follow me on Twitter or check out the open source projects I’ve been publishing on GitHub.

I am also working on a Twitter bot for this site to tweet the most popular, newest, random packages from npm. Please follow that account now and it will start sending out packages soon–ish.

Open Software & Tools

This site wouldn’t be possible without the immense generosity and tireless efforts from the people who make contributions to the world and share their work via open source initiatives. Thank you 🙏

© 2026 – Pkg Stats / Ryan Hefner

@reyanshrastogi/lathe

v0.0.2

Published

A protocol and reference implementation for user-customizable web app interfaces. Apps declare schemas, actions, and primitive components. Users (via an LLM agent) compose those primitives into custom views, parameterized by a theme token vocabulary. The

Readme

Lathe

A protocol and reference implementation for user-customizable web app interfaces. Apps declare schemas, actions, and primitive components. Users (via an LLM agent) compose those primitives into custom views, parameterized by a theme token vocabulary. The runtime renders user-emitted view specs against live app data with no code generation.

npm: @reyanshrastogi/lathe  |  Version: 0.0.1  |  Status: v0 — local storage, single-user, no hosted backend


Key principles

  1. The agent never emits code. All agent output is JSON validated against Zod schemas. View structure and theming are pure configuration. The runtime is deterministic React reading config.
  2. No LLM in the rendering hot path. Inference fires only on explicit customization events. Once a view spec exists, rendering is React-speed with zero AI involvement.
  3. The primitive vocabulary is fixed and small. The agent composes from a known set of primitives; it cannot invent new ones. Developers may extend the set via registerPrimitive.
  4. Theme and view are separate. Two storage keys, two prompt branches, two validation pipelines. Visual styling never bleeds into composition logic.
  5. BYOK for inference. Users provide their own provider API key. No hosted backend.
  6. Permissions live in actions, not in the agent. The agent only sees schemas and actions the current user is authorized for. Actions revalidate permissions on execution.

Quick start

npm install @reyanshrastogi/lathe
# peer deps
npm install react react-dom zod dexie
# install the provider SDK you plan to use (at least one)
npm install @google/generative-ai   # Gemini (recommended default)

1. Define your app

import { defineApp } from '@reyanshrastogi/lathe'
import type { DataSource } from '@reyanshrastogi/lathe'
import { z } from 'zod'

const TaskSchema = z.object({
  id: z.string(),
  title: z.string(),
  status: z.enum(['todo', 'in_progress', 'done']),
  priority: z.enum(['low', 'medium', 'high']),
  assignee: z.string(),
  due_date: z.string(),
})

const tasksSource: DataSource<z.infer<typeof TaskSchema>> = {
  schema: TaskSchema,
  list: async () => fetchTasks(),
  subscribe: (callback) => { /* optional live updates */ return () => {} },
}

export const myApp = defineApp({
  id: 'my-app',
  data: { tasks: tasksSource as DataSource },
  actions: {
    updateStatus: {
      fn: async ({ id, status }) => { /* mutate */ },
      argsSchema: z.object({ id: z.string(), status: z.string() }),
      description: 'Update the status of a task',
    },
  },
  defaultView: {
    type: 'Kanban',
    source: 'tasks',
    props: {
      groupBy: 'status',
      columns: ['todo', 'in_progress', 'done'],
      card: {
        type: 'Card',
        props: { title: '$item.title', subtitle: '$item.assignee', badge: '$item.priority' },
      },
      onMove: { action: 'updateStatus', args: { id: '$item.id', status: '$column' } },
    },
  },
})

2. Render the customizable region

import { CustomizableRegion } from '@reyanshrastogi/lathe'
import { myApp } from './app'

export function App() {
  return <CustomizableRegion app={myApp} userId="user_123" />
}

3. Configure API keys

Create .env.local in your project root:

VITE_DEFAULT_PROVIDER=gemini
GEMINI_API_KEY=your_key_here

The user's provider selection and key are stored locally in IndexedDB. No key leaves the browser.


Primitives reference

All 22 built-in primitives are available to the agent. The agent receives the full library spec (type, description, prop schema as JSON Schema, capabilities) on every customization call.

| Primitive | Capabilities | Description | |-----------|-------------|-------------| | List | list, sorting, filtering | Vertical list rendering each item using a nested primitive | | Table | list, sorting, grouping | Tabular data display with sortable columns | | Kanban | list, grouping, navigation | Board view grouping items by a field with drag-and-drop support | | Calendar | list, navigation | Month-grid calendar displaying items by date field | | Card | single | Compact display of one item with title, subtitle, badge, and avatar | | Detail | single, navigation | Full detail view of a single item with labeled fields and action buttons | | Form | form | Form for creating or editing an item with typed fields and a submit action | | Stats | list | Dashboard metric cards showing aggregated values (count, sum, avg, min, max) from a data source | | Grid | list, sorting, filtering | Responsive multi-column card grid; like List but arranges items in columns | | Split | — | Layout primitive splitting the region into two sections (horizontal or vertical) with a configurable ratio | | Timeline | list, sorting, filtering | Chronological event list grouped by date; use for activity feeds or history logs | | Tabs | navigation | Tabbed container showing one panel at a time; each tab has a label and a child ViewSpec | | Accordion | navigation | Collapsible sections container; use for FAQs, grouped settings, or hierarchical content | | Tree | list, navigation | Hierarchical tree view with expand/collapse; specify labelField and childrenField | | Stack | — | Flex layout container stacking children vertically or horizontally with configurable gap and alignment | | Flex | — | Flex container with wrap, justify, and alignment control for responsive card grids or toolbars | | Section | — | Titled section container wrapping a single child ViewSpec; adds headings, subtitles, optional borders | | Gallery | list | Image grid gallery; specify imageField for URLs and titleField for captions | | Gauge | single | Progress bar or ring gauge showing a numeric value from min to max | | Markdown | single | Renders markdown-formatted content as styled HTML; content can be literal or a $item.field binding | | Chart | list, filtering | SVG data visualization (bar, line, area, pie); aggregates by xField and yField | | Canvas | — | Free-layout grid canvas placing child ViewSpecs at (x, y) coordinates; the composition primitive for dashboards |

Registering custom primitives

import { registerPrimitive } from '@reyanshrastogi/lathe'
import type { PrimitiveDefinition } from '@reyanshrastogi/lathe'

registerPrimitive({
  type: 'MyPrimitive',
  component: MyPrimitiveComponent,
  propSchema: MyPropsSchema,
  description: 'What this primitive does, for the agent',
  capabilities: ['single'],
} satisfies PrimitiveDefinition<MyProps>)

The agent receives the updated library spec on the next call.


Theme system

The agent can modify visual appearance independently of view composition. Themes are stored separately from view specs and validated before application.

Token groups:

  • colors — 13 required semantic tokens (background, foreground, primary, primaryForeground, card, cardForeground, accent, accentForeground, muted, mutedForeground, destructive, destructiveForeground, border) plus optional gradientBackground and gradientCard CSS gradient overrides
  • typographyfontFamily (sans | serif | mono | custom string), baseSize (12–20 px), scaleRatio (1.05–1.5), baseWeight (400 | 500), optional fontUrl for Google Fonts
  • spacingbaseUnit (2–8 px), density (compact | comfortable | spacious)
  • shaperadius (0–2 rem), borderWidth (1 | 2)
  • effectsshadowDepth (flat | soft | elevated), optional animation (none | subtle | energetic), optional shadowColor

Token values are written as CSS variables on the CustomizableRegion root. WCAG AA contrast (4.5:1) is validated for every foreground/background pair before a theme patch is accepted.

Setting a default theme:

defineApp({
  // ...
  defaultTheme: {
    colors: { primary: '#6d28d9', primaryForeground: '#ffffff' },
    shape: { radius: 0.5 },
    effects: { shadowDepth: 'soft', animation: 'subtle' },
  },
})

Agent / BYOK

Lathe ships four provider implementations. Install the SDK for the provider you want to use.

| Provider | Package | Model | |----------|---------|-------| | gemini | @google/generative-ai | gemini-2.5-flash | | groq | groq-sdk | llama-3.3-70b-versatile | | openai | openai | gpt-4o-mini | | anthropic | @anthropic-ai/sdk | claude-sonnet-4-7 |

The provider and API key are stored locally by the user (IndexedDB ConfigRecord). The CustomizableRegion sidebar handles provider selection UI.

Using a provider programmatically:

import { generatePatch, GeminiProvider } from '@reyanshrastogi/lathe'

const provider = new GeminiProvider(process.env.GEMINI_API_KEY)
const patch = await generatePatch(agentInput, provider)

Implementing a custom provider:

import type { ModelProvider } from '@reyanshrastogi/lathe'

const myProvider: ModelProvider = {
  id: 'custom',
  generate: async ({ system, user, schema }) => { /* ... */ },
}

defineApp API

defineApp({
  id: string,                          // unique app ID; used as IndexedDB key prefix
  data: Record<string, DataSource>,    // named data sources
  actions: Record<string, Action>,     // named actions (mutation endpoints)
  defaultView: ViewSpec,               // rendered before any customization
  defaultTheme?: Partial<Theme>,       // overrides for the built-in defaults
  customPrimitives?: PrimitiveDefinition[], // optional extensions
})

DataSource:

interface DataSource<T> {
  schema: z.ZodType<T>
  list: (params: ListParams) => Promise<T[]>
  get?: (id: string) => Promise<T>
  subscribe?: (callback: (items: T[]) => void) => () => void
  relations?: Record<string, { source: string; on: string }>
}

Action:

interface Action<TArgs> {
  fn: (args: TArgs) => Promise<unknown>
  argsSchema: z.ZodType<TArgs>
  description: string           // shipped to the agent; be descriptive
  requires?: string[]           // permission identifiers checked at execution time
}

Development

The repo is a Yarn/npm workspace. The example/ directory is a working task tracker demo.

# Run the example app
cd example
npm run dev

Set your API key and provider in example/.env.local:

VITE_DEFAULT_PROVIDER=gemini
GEMINI_API_KEY=your_key_here

Building the library:

npm run build       # outputs to dist/
npm run test        # vitest
npm run tsc         # type-check only

Status

v0. Single-user. No hosted backend. Storage is local IndexedDB (Dexie). Inference is BYOK. The primitive vocabulary is intentionally fixed at 22 entries for v0; composition over invention is the design constraint.

See SPEC.md for the full protocol reference (type contracts, view-spec grammar, theme token vocabulary, agent I/O schemas) and BUILDPLAN.md for the phased implementation plan.