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

@moku-labs/core

v0.1.4

Published

Micro-kernel plugin framework for LLMs (TypeScript)

Downloads

2,154

Readme

Moku Core

Micro-kernel plugin framework for TypeScript. Three layers of isolation. Built for LLM-scale development.

Two runtime exports. Bundle < 8KB gzipped. Zero dependencies. The type system does the heavy lifting.

bun add @moku-labs/core

The Problem

LLMs are writing more of our code. But they generate spaghetti — they invent structure, mix concerns, bypass APIs, and scatter logic across files. The bigger the codebase, the worse it gets.

Every framework tries to solve scaling with conventions. Conventions don't work for LLMs. LLMs approximate conventions. They hallucinate when the API surface is too large to hold in context.

You need constraints, not conventions.

The Solution

Moku enforces a 3-layer architecture where each layer physically constrains the layer above it. LLM-generated code is confined to plugins, integrated only through typed public APIs, and cannot touch the core.

┌─────────────────────────────────────────────────────────┐
│  Layer 3: Consumer / LLM-generated code                 │
│  Can only: configure, compose plugins, use typed APIs   │
│  Cannot: modify the framework, bypass plugin boundaries │
├─────────────────────────────────────────────────────────┤
│  Layer 2: Framework                                     │
│  Defines: config shape, event contract, default plugins │
│  Cannot: modify the kernel                              │
├─────────────────────────────────────────────────────────┤
│  Layer 1: @moku-labs/core                               │
│  Two functions. Zero domain knowledge. Pure machinery.  │
└─────────────────────────────────────────────────────────┘

Slop doesn't spread. An LLM writing a plugin cannot break the framework. An LLM writing consumer code cannot break a plugin. The architecture is the guardrail.

Why It Works for LLMs

| Problem | How Moku solves it | |---|---| | LLMs hallucinate framework structure | Entire API learnable in ~1000 tokens | | Code drifts across files and modules | Each feature is one plugin, one boundary | | Generated code bypasses intended APIs | emit is strictly typed, no escape hatch | | Quality degrades at scale | Frozen configs, phantom types, compile-time enforcement | | Adding features breaks existing code | Horizontal scaling — add plugins, don't modify |


Quick Start

1. Define your framework (Layer 2)

// my-framework/config.ts
import { createCoreConfig } from '@moku-labs/core';

type Config = { siteName: string; mode: 'development' | 'production' };
type Events = {
  'page:render': { path: string; html: string };
  'router:navigate': { from: string; to: string };
};

export const coreConfig = createCoreConfig<Config, Events>('my-site', {
  config: { siteName: 'Untitled', mode: 'development' },
});
export const { createPlugin, createCore } = coreConfig;

2. Write plugins

// my-framework/plugins/router.ts
import { createPlugin } from '../config';

export const routerPlugin = createPlugin('router', {
  config: { basePath: '/' },
  createState: () => ({ currentPath: '/', history: [] as string[] }),
  api: ctx => ({
    navigate: (path: string) => {
      const from = ctx.state.currentPath;
      ctx.state.currentPath = path;
      ctx.emit('router:navigate', { from, to: path });
    },
    current: () => ctx.state.currentPath,
  }),
});

3. Wire the framework

// my-framework/index.ts
import { coreConfig, createCore } from './config';
import { routerPlugin } from './plugins/router';

const framework = createCore(coreConfig, {
  plugins: [routerPlugin],
});
export const { createApp, createPlugin } = framework;

4. Ship the product (Layer 3)

// my-app/main.ts
import { createApp } from 'my-framework';

const app = createApp({
  plugins: [blogPlugin],
  config: { siteName: 'My Blog', mode: 'production' },
  pluginConfigs: { router: { basePath: '/blog' } },
});

await app.start();
app.router.navigate('/about');  // fully typed
app.blog.listPosts();           // fully typed
await app.stop();

That's the entire factory chain. createCoreConfigcreateCorecreateApp. Three functions, three layers. (A second runtime export, createCorePlugin, builds self-contained infrastructure plugins — see the API reference below.)


How It Scales

Every feature is a plugin. Plugins are isolated by design:

  • Own config — declared in the plugin, resolved by the kernel
  • Own state — mutable escape hatch, invisible to other plugins
  • Own API — mounted on the app object, fully typed
  • Own events — declared via register callback, strictly typed payloads
  • Explicit dependenciesdepends: [otherPlugin], validated at init

Adding a feature = adding a plugin to the array. No framework modifications. No global state pollution. No import spaghetti.

// Team A ships auth
const authPlugin = createPlugin('auth', {
  events: register => ({
    'auth:login': register<{ userId: string }>('User logged in'),
  }),
  api: ctx => ({
    login: (id: string) => ctx.emit('auth:login', { userId: id }),
  }),
});

// Team B ships analytics, depends on auth events
const analyticsPlugin = createPlugin('analytics', {
  depends: [authPlugin],
  createState: () => ({ events: [] as string[] }),
  hooks: ctx => ({
    'auth:login': ({ userId }) => { ctx.state.events.push(`login:${userId}`); },
  }),
});

Teams work independently. Plugins compose through typed events. The kernel enforces the boundaries.


Quality Enforcement

Moku is designed for a world where LLMs write plugins and CI enforces quality. The framework provides structural guarantees, and the toolchain catches everything else.

Compile-time guarantees

  • Strict emit — only known event names compile. Wrong payloads are type errors. No any, no escape hatch.
  • Phantom types — plugin APIs, configs, and events flow through the type system without runtime cost.
  • Typed plugin configspluginConfigs overrides are checked against each plugin's declared config shape. Wrong keys or value types don't compile. Overrides are optional — plugin defaults fill anything you omit.
  • Context tierscreateState can't call emit (other plugins don't exist yet). onStop can't access other plugins (they may already be stopped). The type system prevents temporal bugs.

Runtime guarantees

  • Frozen configsObject.freeze on all configs and the app object. No accidental mutation.
  • No duplicate plugins — caught at init with an actionable error message.
  • Dependency validation — dependencies must appear before dependents. No implicit reordering.
  • Sequential execution — lifecycle phases run one plugin at a time. No race conditions.
  • Single start/stop — calling start() twice throws. Calling stop() before start() throws.

Recommended toolchain

The kernel provides structure. Pair it with:

  • Biome — fast formatting + linting, zero-config
  • ESLint — JSDoc enforcement, code quality rules
  • Vitest — test coverage thresholds per plugin
  • TypeScript strict modeexactOptionalPropertyTypes, noUncheckedIndexedAccess

LLMs generate the code. The toolchain gates it. The kernel contains it.


The Kernel

Six responsibilities. Nothing else.

| # | Responsibility | Mechanism | |---|---|---| | 1 | Collect plugins | Ordered array, framework defaults + consumer extras | | 2 | Validate | Reserved names, duplicates, dependency order | | 3 | Resolve config | Shallow merge: plugin defaults → framework → consumer | | 4 | Lifecycle | 3 phases: onInitonStartonStop (reverse) | | 5 | Events | emit dispatches to typed hooks. Fire-and-forget. | | 6 | Freeze | Object.freeze on app and configs. State stays mutable. |

Plugin spec shape

createPlugin('name', {
  config:      { /* defaults */ },
  events:      register => ({ 'name:event': register<Payload>('description') }),
  depends:     [otherPlugin],
  createState: ctx => ({ /* mutable state */ }),
  api:         ctx => ({ /* public methods, mounted on app.name */ }),
  hooks:       ctx => ({ 'event:name': handler }),
  onInit:      ctx => { /* all plugins exist, sync only */ },
  onStart:     async ctx => { /* app is running */ },
  onStop:      async ctx => { /* teardown, reverse order */ },
});

Every field is optional. A plugin with only api works. A plugin with only hooks works.


Design Principles

Brutal simplicity. No classes. No decorators. No dependency injection. No inheritance. createCoreConfig, createCore, and createPlugin are pure factories. createApp() performs synchronous init. app.start() / app.stop() run the runtime lifecycle.

Types over runtime. Most of the codebase is type definitions and JSDoc. The type system provides autocomplete, compile-time validation, and documentation simultaneously.

Explicit over implicit. Plugin order is the array order. No topological sort. No magic reordering. If B depends on A, A comes first.

Functional composition. Plugins are plain objects. Dependencies use ctx.require(plugin). APIs are closures over state. No this, no prototypes.

Minimum description length. Define parts (plugins), compose them (createApp), let them communicate (events + APIs), manage lifecycle (init/start/stop). Nothing else.


API Reference

Exports

// Runtime
import { createCoreConfig, createCorePlugin } from '@moku-labs/core';

// Type utilities for plugin authors
import type { PluginCtx, EmitFn } from '@moku-labs/core';

createCoreConfig<Config, Events>(id, options)

Creates a bound factory chain for a framework. Returns { createPlugin, createCore }, both locked to Config and Events.

createCorePlugin(name, spec)

Creates a self-contained infrastructure plugin (logging, env, storage). Core plugins are passed to createCoreConfig via plugins, and their APIs are injected onto every regular plugin's context (ctx.log.info(...)). No depends, no events, no hooks — a minimal { config, state } context only.

createCore(coreConfig, options)

Captures framework defaults: plugins, plugin configs, onReady, onError. Returns { createApp, createPlugin }.

createPlugin(name, spec)

Creates a plugin instance. Zero explicit generics — everything inferred from the spec. Returns PluginInstance with phantom types.

createApp(options?)

Merges framework defaults with consumer options. Validates, resolves config, runs onInit, and returns App — a frozen object with plugin APIs mounted as properties. createApp() is synchronous and side-effectful within the init phase; it is not a lazy builder. start() / stop() are optional and mainly useful for apps with a distinct runtime phase. Lifecycle execution is non-transactional: start/stop errors propagate, they are not rolled back by the kernel.

App

await app.start();            // optional: onStart (forward order)
await app.stop();             // optional: onStop (reverse order)
app.emit('event', payload);   // strictly typed, fire-and-forget
app.require(plugin);          // returns typed API or throws
app.has('name');              // boolean, never throws
app.pluginName.method();      // fully typed API access

Specification

The full specification lives in specification/:

| Document | Covers | |---|---| | 01 Architecture | Three-layer model, design philosophy, LLM motivation | | 02 Core API | All function signatures | | 03 Plugin System | PluginSpec, PluginInstance, depends | | 04 Factory Chain | 3-step factory chain: why and how | | 05 Config System | Config resolution, shallow merge rules | | 06 Lifecycle | init → start → stop phases | | 07 Communication | emit, hooks, event dispatch | | 08 Context | Three context tiers | | 09 Type System | Phantom types, type flow, BuildPluginApis | | 11 Invariants | Guarantees, error format, anti-patterns | | 12 Plugin Patterns | File structure conventions | | 13 Kernel Pseudocode | Reference implementation with rationale | | 14 Event Registration | Register callback pattern | | 15 Plugin Structure | Plugin file organization |


Status

Early release (0.1.x). The public API — createCoreConfigcreateCorecreateApp — is stable; pre-1.0 means internals may still be refined. Published to npm: bun add @moku-labs/core.

License

MIT