@moku-labs/core 0.1.0-alpha.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/LICENSE ADDED
@@ -0,0 +1,21 @@
1
+ MIT License
2
+
3
+ Copyright (c) 2026 moku-labs
4
+
5
+ Permission is hereby granted, free of charge, to any person obtaining a copy
6
+ of this software and associated documentation files (the "Software"), to deal
7
+ in the Software without restriction, including without limitation the rights
8
+ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9
+ copies of the Software, and to permit persons to whom the Software is
10
+ furnished to do so, subject to the following conditions:
11
+
12
+ The above copyright notice and this permission notice shall be included in all
13
+ copies or substantial portions of the Software.
14
+
15
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21
+ SOFTWARE.
package/README.md ADDED
@@ -0,0 +1,315 @@
1
+ # Moku Core
2
+
3
+ **Micro-kernel plugin framework for TypeScript. Three layers of isolation. Built for LLM-scale development.**
4
+
5
+ One runtime export. Bundle < 5KB. Zero dependencies. The type system does the heavy lifting.
6
+
7
+ ```
8
+ bun add @moku-labs/core
9
+ ```
10
+
11
+ ---
12
+
13
+ ## The Problem
14
+
15
+ 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.
16
+
17
+ 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.
18
+
19
+ **You need constraints, not conventions.**
20
+
21
+ ## The Solution
22
+
23
+ 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.
24
+
25
+ ```
26
+ ┌─────────────────────────────────────────────────────────┐
27
+ │ Layer 3: Consumer / LLM-generated code │
28
+ │ Can only: configure, compose plugins, use typed APIs │
29
+ │ Cannot: modify the framework, bypass plugin boundaries │
30
+ ├─────────────────────────────────────────────────────────┤
31
+ │ Layer 2: Framework │
32
+ │ Defines: config shape, event contract, default plugins │
33
+ │ Cannot: modify the kernel │
34
+ ├─────────────────────────────────────────────────────────┤
35
+ │ Layer 1: @moku-labs/core │
36
+ │ One function. Zero domain knowledge. Pure machinery. │
37
+ └─────────────────────────────────────────────────────────┘
38
+ ```
39
+
40
+ **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.
41
+
42
+ ## Why It Works for LLMs
43
+
44
+ | Problem | How Moku solves it |
45
+ |---|---|
46
+ | LLMs hallucinate framework structure | Entire API learnable in ~1000 tokens |
47
+ | Code drifts across files and modules | Each feature is one plugin, one boundary |
48
+ | Generated code bypasses intended APIs | `emit` is strictly typed, no escape hatch |
49
+ | Quality degrades at scale | Frozen configs, phantom types, compile-time enforcement |
50
+ | Adding features breaks existing code | Horizontal scaling — add plugins, don't modify |
51
+
52
+ ---
53
+
54
+ ## Quick Start
55
+
56
+ ### 1. Define your framework (Layer 2)
57
+
58
+ ```typescript
59
+ // my-framework/config.ts
60
+ import { createCoreConfig } from '@moku-labs/core';
61
+
62
+ type Config = { siteName: string; mode: 'development' | 'production' };
63
+ type Events = {
64
+ 'page:render': { path: string; html: string };
65
+ 'router:navigate': { from: string; to: string };
66
+ };
67
+
68
+ export const coreConfig = createCoreConfig<Config, Events>('my-site', {
69
+ config: { siteName: 'Untitled', mode: 'development' },
70
+ });
71
+ export const { createPlugin, createCore } = coreConfig;
72
+ ```
73
+
74
+ ### 2. Write plugins
75
+
76
+ ```typescript
77
+ // my-framework/plugins/router.ts
78
+ import { createPlugin } from '../config';
79
+
80
+ export const routerPlugin = createPlugin('router', {
81
+ config: { basePath: '/' },
82
+ createState: () => ({ currentPath: '/', history: [] as string[] }),
83
+ api: ctx => ({
84
+ navigate: (path: string) => {
85
+ const from = ctx.state.currentPath;
86
+ ctx.state.currentPath = path;
87
+ ctx.emit('router:navigate', { from, to: path });
88
+ },
89
+ current: () => ctx.state.currentPath,
90
+ }),
91
+ });
92
+ ```
93
+
94
+ ### 3. Wire the framework
95
+
96
+ ```typescript
97
+ // my-framework/index.ts
98
+ import { coreConfig, createCore } from './config';
99
+ import { routerPlugin } from './plugins/router';
100
+
101
+ const framework = createCore(coreConfig, {
102
+ plugins: [routerPlugin],
103
+ });
104
+ export const { createApp, createPlugin } = framework;
105
+ ```
106
+
107
+ ### 4. Ship the product (Layer 3)
108
+
109
+ ```typescript
110
+ // my-app/main.ts
111
+ import { createApp } from 'my-framework';
112
+
113
+ const app = await createApp({
114
+ plugins: [blogPlugin],
115
+ config: { siteName: 'My Blog', mode: 'production' },
116
+ pluginConfigs: { router: { basePath: '/blog' } },
117
+ });
118
+
119
+ await app.start();
120
+ app.router.navigate('/about'); // fully typed
121
+ app.blog.listPosts(); // fully typed
122
+ await app.stop();
123
+ ```
124
+
125
+ **That's the entire API.** `createCoreConfig` → `createCore` → `createApp`. Three functions, three layers.
126
+
127
+ ---
128
+
129
+ ## How It Scales
130
+
131
+ Every feature is a plugin. Plugins are isolated by design:
132
+
133
+ - **Own config** — declared in the plugin, resolved by the kernel
134
+ - **Own state** — mutable escape hatch, invisible to other plugins
135
+ - **Own API** — mounted on the app object, fully typed
136
+ - **Own events** — declared via register callback, strictly typed payloads
137
+ - **Explicit dependencies** — `depends: [otherPlugin]`, validated at init
138
+
139
+ Adding a feature = adding a plugin to the array. No framework modifications. No global state pollution. No import spaghetti.
140
+
141
+ ```typescript
142
+ // Team A ships auth
143
+ const authPlugin = createPlugin('auth', {
144
+ events: register => ({
145
+ 'auth:login': register<{ userId: string }>('User logged in'),
146
+ }),
147
+ api: ctx => ({
148
+ login: (id: string) => ctx.emit('auth:login', { userId: id }),
149
+ }),
150
+ });
151
+
152
+ // Team B ships analytics, depends on auth events
153
+ const analyticsPlugin = createPlugin('analytics', {
154
+ depends: [authPlugin],
155
+ createState: () => ({ events: [] as string[] }),
156
+ hooks: ctx => ({
157
+ 'auth:login': ({ userId }) => { ctx.state.events.push(`login:${userId}`); },
158
+ }),
159
+ });
160
+ ```
161
+
162
+ Teams work independently. Plugins compose through typed events. The kernel enforces the boundaries.
163
+
164
+ ---
165
+
166
+ ## Quality Enforcement
167
+
168
+ 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.
169
+
170
+ ### Compile-time guarantees
171
+
172
+ - **Strict emit** — only known event names compile. Wrong payloads are type errors. No `any`, no escape hatch.
173
+ - **Phantom types** — plugin APIs, configs, and events flow through the type system without runtime cost.
174
+ - **Required configs** — if a plugin needs config and you don't provide it, TypeScript tells you.
175
+ - **Context tiers** — `createState` 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.
176
+
177
+ ### Runtime guarantees
178
+
179
+ - **Frozen configs** — `Object.freeze` on all configs and the app object. No accidental mutation.
180
+ - **No duplicate plugins** — caught at init with an actionable error message.
181
+ - **Dependency validation** — dependencies must appear before dependents. No implicit reordering.
182
+ - **Sequential execution** — lifecycle phases run one plugin at a time. No race conditions.
183
+ - **Single start/stop** — calling `start()` twice throws. Calling `stop()` before `start()` throws.
184
+
185
+ ### Recommended toolchain
186
+
187
+ The kernel provides structure. Pair it with:
188
+
189
+ - **[Biome](https://biomejs.dev/)** — fast formatting + linting, zero-config
190
+ - **[ESLint](https://eslint.org/)** — JSDoc enforcement, code quality rules
191
+ - **[Vitest](https://vitest.dev/)** — test coverage thresholds per plugin
192
+ - **TypeScript strict mode** — `exactOptionalPropertyTypes`, `noUncheckedIndexedAccess`
193
+
194
+ LLMs generate the code. The toolchain gates it. The kernel contains it.
195
+
196
+ ---
197
+
198
+ ## The Kernel
199
+
200
+ Six responsibilities. Nothing else.
201
+
202
+ | # | Responsibility | Mechanism |
203
+ |---|---|---|
204
+ | 1 | Collect plugins | Ordered array, framework defaults + consumer extras |
205
+ | 2 | Validate | Reserved names, duplicates, dependency order |
206
+ | 3 | Resolve config | Shallow merge: plugin defaults → framework → consumer |
207
+ | 4 | Lifecycle | 3 phases: `onInit` → `onStart` → `onStop` (reverse) |
208
+ | 5 | Events | `emit` dispatches to typed hooks. Fire-and-forget. |
209
+ | 6 | Freeze | `Object.freeze` on app and configs. State stays mutable. |
210
+
211
+ ### Plugin spec shape
212
+
213
+ ```typescript
214
+ createPlugin('name', {
215
+ config: { /* defaults */ },
216
+ events: register => ({ 'name:event': register<Payload>('description') }),
217
+ depends: [otherPlugin],
218
+ createState: ctx => ({ /* mutable state */ }),
219
+ api: ctx => ({ /* public methods, mounted on app.name */ }),
220
+ hooks: ctx => ({ 'event:name': handler }),
221
+ onInit: async ctx => { /* all plugins exist */ },
222
+ onStart: async ctx => { /* app is running */ },
223
+ onStop: async ctx => { /* teardown, reverse order */ },
224
+ });
225
+ ```
226
+
227
+ Every field is optional. A plugin with only `api` works. A plugin with only `hooks` works.
228
+
229
+ ---
230
+
231
+ ## Design Principles
232
+
233
+ **Brutal simplicity.** No classes. No decorators. No dependency injection. No inheritance. Every function is a pure factory: input → output.
234
+
235
+ **Types over runtime.** Most of the codebase is type definitions and JSDoc. The type system provides autocomplete, compile-time validation, and documentation simultaneously.
236
+
237
+ **Explicit over implicit.** Plugin order is the array order. No topological sort. No magic reordering. If B depends on A, A comes first.
238
+
239
+ **Functional composition.** Plugins are plain objects. Dependencies use `ctx.require(plugin)`. APIs are closures over state. No `this`, no prototypes.
240
+
241
+ **Minimum description length.** Define parts (plugins), compose them (createApp), let them communicate (events + APIs), manage lifecycle (init/start/stop). Nothing else.
242
+
243
+ ---
244
+
245
+ ## API Reference
246
+
247
+ ### Exports
248
+
249
+ ```typescript
250
+ // Runtime
251
+ import { createCoreConfig } from '@moku-labs/core';
252
+
253
+ // Type utilities for plugin authors
254
+ import type { PluginCtx, EmitFn } from '@moku-labs/core';
255
+ ```
256
+
257
+ ### createCoreConfig\<Config, Events\>(id, options)
258
+
259
+ Creates a bound factory chain for a framework. Returns `{ createPlugin, createCore }`, both locked to `Config` and `Events`.
260
+
261
+ ### createCore(coreConfig, options)
262
+
263
+ Captures framework defaults: plugins, plugin configs, `onReady`, `onError`. Returns `{ createApp, createPlugin }`.
264
+
265
+ ### createPlugin(name, spec)
266
+
267
+ Creates a plugin instance. Zero explicit generics — everything inferred from the spec. Returns `PluginInstance` with phantom types.
268
+
269
+ ### createApp(options?)
270
+
271
+ Merges framework defaults with consumer options. Validates, resolves config, runs `onInit`. Returns `Promise<App>` — a frozen object with plugin APIs mounted as properties.
272
+
273
+ ### App
274
+
275
+ ```typescript
276
+ await app.start(); // onStart (forward order)
277
+ await app.stop(); // onStop (reverse order)
278
+ app.emit('event', payload); // strictly typed, fire-and-forget
279
+ app.require(plugin); // returns typed API or throws
280
+ app.has('name'); // boolean, never throws
281
+ app.pluginName.method(); // fully typed API access
282
+ ```
283
+
284
+ ---
285
+
286
+ ## Specification
287
+
288
+ The full specification lives in [`specification/`](specification/):
289
+
290
+ | Document | Covers |
291
+ |---|---|
292
+ | [01 Architecture](specification/01-ARCHITECTURE.md) | Three-layer model, design philosophy, LLM motivation |
293
+ | [02 Core API](specification/02-CORE-API.md) | All function signatures |
294
+ | [03 Plugin System](specification/03-PLUGIN-SYSTEM.md) | PluginSpec, PluginInstance, depends |
295
+ | [04 Factory Chain](specification/04-FACTORY-CHAIN.md) | 3-step factory chain: why and how |
296
+ | [05 Config System](specification/05-CONFIG-SYSTEM.md) | Config resolution, shallow merge rules |
297
+ | [06 Lifecycle](specification/06-LIFECYCLE.md) | init → start → stop phases |
298
+ | [07 Communication](specification/07-COMMUNICATION.md) | emit, hooks, event dispatch |
299
+ | [08 Context](specification/08-CONTEXT.md) | Three context tiers |
300
+ | [09 Type System](specification/09-TYPE-SYSTEM.md) | Phantom types, type flow, BuildPluginApis |
301
+ | [11 Invariants](specification/11-INVARIANTS.md) | Guarantees, error format, anti-patterns |
302
+ | [12 Plugin Patterns](specification/12-PLUGIN-PATTERNS.md) | File structure conventions |
303
+ | [13 Kernel Pseudocode](specification/13-KERNEL-PSEUDOCODE.md) | Reference implementation with rationale |
304
+ | [14 Event Registration](specification/14-EVENT-REGISTRATION.md) | Register callback pattern |
305
+ | [15 Plugin Structure](specification/15-PLUGIN-STRUCTURE.md) | Plugin file organization |
306
+
307
+ ---
308
+
309
+ ## Status
310
+
311
+ Alpha. API is stabilizing. Not yet published to npm.
312
+
313
+ ## License
314
+
315
+ MIT