ark-runtime-kernel 1.0.0 โ†’ 1.2.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/README.md CHANGED
@@ -2,126 +2,160 @@
2
2
 
3
3
  # ๐Ÿ›๏ธ Ark โ€” Architectural Runtime Kernel
4
4
 
5
- **Make your architecture a machine-readable, enforceable contract** โ€”<br/>
6
- respected by AI agents at write time, CI at merge time, and the runtime itself.
5
+ **Stop AI agents (and humans) from quietly breaking your architecture.**<br/>
6
+ One machine-readable contract โ€” enforced at write time, merge time, and (optionally) runtime.
7
7
 
8
- [![CI](https://github.com/pedroknigge/ark/actions/workflows/ci.yml/badge.svg)](https://github.com/pedroknigge/ark/actions/workflows/ci.yml)
8
+ [![CI](https://github.com/pedroknigge/ark-runtime-kernel/actions/workflows/ci.yml/badge.svg)](https://github.com/pedroknigge/ark-runtime-kernel/actions/workflows/ci.yml)
9
9
  [![npm](https://img.shields.io/npm/v/ark-runtime-kernel?color=cb3837&label=npm)](https://www.npmjs.com/package/ark-runtime-kernel)
10
10
  [![License: MIT](https://img.shields.io/badge/license-MIT-blue.svg)](LICENSE)
11
11
  ![Node](https://img.shields.io/badge/node-%3E%3D18-339933?logo=node.js)
12
12
  ![TypeScript](https://img.shields.io/badge/TypeScript-first-3178c6?logo=typescript&logoColor=white)
13
13
  ![Zero deps](https://img.shields.io/badge/dependencies-0-success)
14
14
 
15
- **Zero runtime dependencies** ยท TypeScript-first ยท Hexagonal + Event-Driven + DDD governance kernel
16
-
17
- [Quick Start](#60-second-setup) ยท [The Three Gates](#the-three-gates-visual) ยท [AI Write Gate](#ai-write-path-gate-ark-mcp) ยท [CI Gate](#ark-check--the-ci-gate) ยท [Docs](#documentation)
15
+ [2-Minute Setup](#2-minute-setup) ยท [Why Ark](#why-ark-and-not-just-a-linter) ยท [AI Write Gate](#the-ai-write-gate) ยท [CI Gate](#ark-check--the-ci-gate) ยท [Runtime Kernel](#the-runtime-kernel-opt-in) ยท [Docs](#documentation)
18
16
 
19
17
  </div>
20
18
 
21
19
  ---
22
20
 
23
- ## The Three Gates (Visual)
24
-
25
- ```mermaid
26
- flowchart LR
27
- A["โœ๏ธ Write Time<br/>AI Agents"] -->|ark-mcp + validate_code| B["๐Ÿšซ Blocked"]
28
- A -->|valid| C["๐Ÿ’พ Disk"]
21
+ This is what happens when an agent tries to import a persistence adapter into your domain layer with Ark's write gate active:
29
22
 
30
- D["๐Ÿ”€ Merge Time<br/>CI / PRs"] -->|ark-check| E["โŒ Fail"]
31
- D -->|valid| F["โœ… Merge"]
23
+ ![An AI agent is blocked from importing a persistence adapter into the domain layer, then self-corrects by defining a port](docs/assets/ark-write-gate.svg)
32
24
 
33
- G["โš™๏ธ Runtime<br/>In-process"] -->|createArkKernel<br/>strict defaults| H["๐Ÿ›ก๏ธ Enforce<br/>contracts + layers"]
34
- G --> I["๐Ÿ“Š Observability<br/>+ Manifest"]
35
-
36
- style A fill:#e0f2fe,color:#0c4a6e
37
- style D fill:#fef3c7,color:#92400e
38
- style G fill:#dcfce7,color:#166534
39
- ```
25
+ The agent doesn't just get blocked โ€” it gets the violation as feedback, reads the architecture contract, and **fixes its own approach**. No review round-trip.
40
26
 
41
- **One config. Three enforcement moments.**
27
+ ## 2-Minute Setup
42
28
 
43
- | Gate | Tool | When it runs | What it enforces |
44
- |--------------|---------------|-------------------------------|-----------------------------------------------|
45
- | **Write** | `ark-mcp` | Agent PreToolUse (Write/Edit) | Layer rules, unknown intents, forbidden patterns |
46
- | **Merge** | `ark-check` | CI (GitHub Actions etc.) | Cross-layer imports + intent references (real TS resolver) |
47
- | **Runtime** | `createArkKernel()` | Running process | Intent registry, event contracts, observed layer flow, policies |
48
-
49
- ---
50
-
51
- ## 60-Second Setup
29
+ No code changes. No new runtime. Just a config and a CI line.
52
30
 
53
31
  ```bash
54
32
  npm install -D ark-runtime-kernel typescript
33
+ npx ark init # asks before generating config, agent gates, and CI templates
34
+ npx ark-check # done: cross-layer imports now fail the check
55
35
  ```
56
36
 
57
- ### 1. Bootstrap your config from reality
37
+ Adopting on a codebase that already has violations? Freeze them and ratchet down:
58
38
 
59
39
  ```bash
60
- npx ark-check --init # detects your folders and writes ark.config.json
40
+ npx ark-check --update-baseline # writes .ark-baseline.json โ€” commit it
41
+ npx ark-check --baseline # only NEW violations fail from now on
61
42
  ```
62
43
 
63
- ### 2. Gate CI
44
+ Then gate your agents (Claude Code shown; [Cursor / Codex / others](docs/ai-gates.md)):
64
45
 
65
- ```bash
66
- npx ark-check --root . --config ark.config.json --strict-config
46
+ ```json
47
+ // .claude/settings.json
48
+ {
49
+ "hooks": {
50
+ "PreToolUse": [{
51
+ "matcher": "Write|Edit|MultiEdit",
52
+ "hooks": [{ "type": "command",
53
+ "command": "npx ark-mcp --hook --root \"$CLAUDE_PROJECT_DIR\" --config ark.config.json" }]
54
+ }]
55
+ }
56
+ }
67
57
  ```
68
58
 
69
- ### 3. Gate AI agents (write path)
59
+ > The same `ark.config.json` powers every gate.
60
+
61
+ Or generate the starter agent and CI gate files:
70
62
 
71
63
  ```bash
72
- npx ark-mcp --root . --config ark.config.json
64
+ npx ark-check --install-agent-gates
73
65
  ```
74
66
 
75
- Bind `--hook` mode to your agent's `PreToolUse` for Write/Edit (see full docs below).
67
+ This writes opt-in templates for MCP discovery, Claude/Cursor rules, Codex config notes,
68
+ GitHub Actions, and agent instructions. Existing files are skipped unless you pass
69
+ `--force`.
76
70
 
77
- > The same `ark.config.json` powers all three gates.
71
+ The package `postinstall` only prints the next command; it never prompts or writes files
72
+ during `npm install`. Use `npx ark init --yes` for non-interactive setup.
78
73
 
79
- ---
74
+ ## Why Ark (and not just a linter)?
80
75
 
81
- ## What Ark Actually Does
76
+ If you only need import-boundary linting in CI, [dependency-cruiser](https://github.com/sverweij/dependency-cruiser), [eslint-plugin-boundaries](https://github.com/javierbrea/eslint-plugin-boundaries), and Nx module boundaries are solid tools. Ark's reason to exist is the **write-time, agent-native half** they don't cover:
82
77
 
83
- Ark turns architecture from **diagrams + good intentions** into **executable contracts**.
78
+ | | Ark | dependency-cruiser | eslint-plugin-boundaries | Nx boundaries |
79
+ |-----------------------------------------|:---:|:---:|:---:|:---:|
80
+ | Cross-layer import checks in CI | โœ… (TS resolver) | โœ… | โœ… | โœ… |
81
+ | Blocks AI agents **before** code lands (MCP + hook) | โœ… | โŒ | โŒ | โŒ |
82
+ | Machine-readable contract for agents (`ark://manifest`) | โœ… | โŒ | โŒ | โŒ |
83
+ | Event/intent governance (who may publish what) | โœ… | โŒ | โŒ | โŒ |
84
+ | Baseline ratchet for existing codebases | โœ… | โŒ | โž– (via ESLint) | โŒ |
85
+ | Optional runtime enforcement | โœ… | โŒ | โŒ | โŒ |
86
+ | Runtime dependencies | 0 | many | many | Nx |
84
87
 
85
- ### Core Capabilities
88
+ **One config. Three enforcement moments:**
86
89
 
87
- - **Intent Registry** โ€” Semantic names (`Domain.Order.OrderPlaced`, `Application.PlaceOrder`) with declared produces/dependsOn relationships.
88
- - **Policy Engine** โ€” Hard policies (throw) + soft policies (observe). Built-in clean-architecture matrix.
89
- - **Strict Event Bus** โ€” Registered intents only, known sources, event contracts, add-only interceptors.
90
- - **Observed Layer Flow** โ€” Runtime enforcement (`'hard' | 'soft' | 'off'`) of *actual* producer โ†’ event flows against your layer rules.
91
- - **Event Contracts** โ€” Payload shape validation (including nested + enums).
92
- - **11-Layer Profile** โ€” First-class support for proper Hexagonal/Event-Driven boundaries.
93
- - **Manifest** โ€” `ark.manifest().toJSON()` โ†’ complete machine-readable contract for agents and tools.
94
- - **Observability & Drift** โ€” Declared vs observed flow reports.
95
- - **Audit / Outbox / Projections / Workflow (Saga)** โ€” Pluggable in-memory defaults + interfaces.
96
- - **Static + AI Gates** โ€” `ark-check` (deep) + `ark-mcp` + ESLint plugin.
90
+ | Gate | Tool | When it runs | What it enforces |
91
+ |--------------|---------------|-------------------------------|-----------------------------------------------|
92
+ | **Write** | `ark-mcp` | Agent PreToolUse (Write/Edit) | Layer rules, unknown intents, forbidden patterns |
93
+ | **Merge** | `ark-check` | CI (GitHub Actions etc.) | Cross-layer imports + intent references (real TS resolver) |
94
+ | **Runtime** | `createArkKernel()` | Running process (opt-in) | Intent registry, event contracts, observed layer flow, policies |
97
95
 
98
- ### Enforcement Scope (Be Honest With Yourself)
96
+ ## The AI Write Gate
99
97
 
100
- **Hard at runtime (governed paths only):**
101
- - Unregistered intents / bad names
102
- - Unknown sources
103
- - Contract violations
104
- - Hard policy violations
105
- - Observed layer flow violations (when `hard`)
98
+ `ark-mcp` is a zero-dependency MCP server + one-shot hook:
106
99
 
107
- **CI (with ark-check):**
108
- - Cross-layer imports (real module resolution)
109
- - Intent string references across boundaries
110
- - Raw `publish()` calls
111
- - Missing `source` on strict publishes
100
+ - **`ark-mcp --hook`** โ€” PreToolUse gate: computes the **post-edit** file content, validates it against your layers, exits 2 with the violations when the write must be blocked. The agent self-corrects.
101
+ - **`validate_code` tool** โ€” on-demand validation of a snippet, for runtimes without hooks.
102
+ - **`ark://manifest` resource** โ€” the architecture as JSON, so agents read the rules *before* generating code instead of learning by rejection.
112
103
 
113
- **Everything else is out of scope** unless you route it through Ark or cover it with config + CI.
104
+ Copy-paste setups for **Claude Code, Cursor, and OpenAI Codex**: [docs/ai-gates.md](docs/ai-gates.md).
114
105
 
115
- ---
106
+ ## `ark-check` โ€” The CI Gate
107
+
108
+ ```bash
109
+ npx ark-check --root . --config ark.config.json --strict-config # fail on coverage gaps too
110
+ npx ark-check --json # machine-readable
111
+ npx ark-check --baseline # ratchet mode
112
+ ```
113
+
114
+ **What it catches (via real TypeScript module resolution โ€” path aliases included):**
115
+
116
+ - Import/export violations (relative, aliases, packages, dynamic `import()`, `require`)
117
+ - String intent references across forbidden layers
118
+ - Raw `publish()` calls that bypass registered intent creators
119
+ - Missing / mismatched publish `source` metadata
120
+
121
+ Violations come with the layer edge, the resolved target, and a fix hint:
116
122
 
117
- ## Quick Start โ€” Strict Kernel (Recommended)
123
+ ```
124
+ โœ– LAYER_IMPORT_VIOLATION src/domain/order.ts:3
125
+ DomainModel โ†’ PersistenceAdapters (src/adapters/persistence/pg-order-repository.ts)
126
+ DomainModel must not import PersistenceAdapters.
127
+ fix: Depend on a port/interface owned by an inner layer instead, or move this code.
128
+ ```
129
+
130
+ ### GitHub Action
131
+
132
+ ```yaml
133
+ - uses: pedroknigge/ark-runtime-kernel@main
134
+ with:
135
+ github-token: ${{ secrets.GITHUB_TOKEN }} # comments violations on the PR
136
+ ```
137
+
138
+ Inputs: `root`, `config`, `strict-config`, `baseline`, `version`.
139
+
140
+ ### ESLint plugin (in-editor feedback)
141
+
142
+ ```js
143
+ // eslint.config.js
144
+ import ark from 'ark-runtime-kernel/eslint';
145
+ export default [ark.configs.recommended];
146
+ ```
147
+
148
+ Rules: `ark/no-domain-infra-imports`, `ark/no-raw-event-publish`, `ark/require-publish-source`.
149
+
150
+ ## The Runtime Kernel (opt-in)
151
+
152
+ The gates above need **zero changes to your code**. When you also want *runtime* guarantees โ€” registered intents only, payload contracts, observed producerโ†’event layer flows โ€” route your events through the kernel:
118
153
 
119
154
  ```ts
120
155
  import { createArkKernel } from 'ark-runtime-kernel';
121
156
 
122
- const ark = createArkKernel(); // or createStrictArkKernel()
157
+ const ark = createArkKernel(); // strict defaults
123
158
 
124
- // 1. Define intents
125
159
  const OrderPlaced = ark.registry.define<
126
160
  'Domain.Order.OrderPlaced',
127
161
  { orderId: string; amount: number }
@@ -132,7 +166,8 @@ ark.registry.define<'Application.PlaceOrder', { orderId: string }>(
132
166
  { produces: ['Domain.Order.OrderPlaced'] }
133
167
  );
134
168
 
135
- // 2. Register contracts (optional but powerful)
169
+ // Payload contracts: Ark's own schema format, or any Standard Schema
170
+ // validator (zod, valibot, arktype) via `standardSchema`.
136
171
  ark.eventContracts.register({
137
172
  intent: 'Domain.Order.OrderPlaced',
138
173
  version: '1',
@@ -143,179 +178,60 @@ ark.eventContracts.register({
143
178
  },
144
179
  });
145
180
 
146
- // 3. Projections (read models)
147
181
  ark.projections.register({
148
182
  name: 'OrderIds',
149
183
  sourceIntents: ['Domain.Order.OrderPlaced'],
150
184
  initialState: { ids: [] as string[] },
151
- project: (event, state) => ({
152
- ids: [...state.ids, event.payload.orderId as string],
153
- }),
185
+ project: (event, state) => ({ ids: [...state.ids, event.payload.orderId as string] }),
154
186
  });
155
187
 
156
- // 4. Publish through source-bound publisher (recommended)
157
188
  const publisher = ark.publisher('Application.PlaceOrder');
189
+ await publisher.publish(OrderPlaced, { orderId: 'o1', amount: 129 }, { eventVersion: '1' });
158
190
 
159
- await publisher.publish(OrderPlaced, { orderId: 'o1', amount: 129 }, {
160
- eventVersion: '1',
161
- correlationId: 'corr-xyz',
162
- });
163
-
164
- console.log(await ark.projections.getState('OrderIds'));
165
- console.log(ark.observability.report());
166
- console.log(JSON.stringify(ark.manifest().toJSON(), null, 2));
191
+ ark.manifest().toJSON(); // the complete machine-readable contract
167
192
  ```
168
193
 
169
- See `examples/basic/` for a runnable version.
170
-
171
- ---
194
+ What it gives you: intent registry with produces/dependsOn, strict event bus (registered intents only, known sources), event contracts, hard/soft policies, observed layer-flow enforcement (`'hard' | 'soft' | 'off'`), projections, observability/drift reports, and pluggable audit/outbox/workflow interfaces (in-memory defaults โ€” see [production hardening](docs/production-hardening.md)).
172
195
 
173
- ## AI Write-Path Gate (`ark-mcp`)
196
+ **Honest scope:** runtime enforcement covers governed paths only โ€” what you route through Ark. Everything else is covered by the static gates.
174
197
 
175
- **The killer feature for agentic coding.**
198
+ ### NestJS
176
199
 
177
- ### Pre-write hook (blocks bad code before disk)
200
+ ```ts
201
+ import { ArkModule, InjectArk } from 'ark-runtime-kernel/nestjs';
202
+ import type { ArkKernel } from 'ark-runtime-kernel';
178
203
 
179
- In Claude Code (`.claude/settings.json`):
204
+ @Module({ imports: [ArkModule.forRoot()] })
205
+ export class AppModule {}
180
206
 
181
- ```json
182
- {
183
- "hooks": {
184
- "PreToolUse": [{
185
- "matcher": "Write|Edit|MultiEdit",
186
- "hooks": [{
187
- "type": "command",
188
- "command": "npx ark-mcp --hook --root \"$CLAUDE_PROJECT_DIR\""
189
- }]
190
- }]
191
- }
207
+ @Injectable()
208
+ export class PlaceOrderService {
209
+ constructor(@InjectArk() private readonly ark: ArkKernel) {}
192
210
  }
193
211
  ```
194
212
 
195
- When blocked, the agent gets the violations back as feedback and can fix + retry.
196
-
197
- ### Full MCP server
198
-
199
- ```bash
200
- npx ark-mcp --root . --config ark.config.json
201
- ```
202
-
203
- Exposes:
204
- - Resource: `ark://manifest`
205
- - Tool: `validate_code(source, layer?, filePath?)`
206
-
207
- Register in `.mcp.json`.
208
-
209
- ---
210
-
211
- ## `ark-check` โ€” The CI Gate
212
-
213
- ```bash
214
- # Basic
215
- npx ark-check --root . --config ark.config.json
216
-
217
- # Fail on coverage gaps too
218
- npx ark-check --root . --config ark.config.json --strict-config
219
-
220
- # JSON for tools
221
- npx ark-check --json
222
- ```
223
-
224
- **What it catches (via real TypeScript resolution):**
225
- - Import/export violations (relative, aliases, packages, dynamic import, require)
226
- - String intent references across forbidden layers
227
- - Raw publish calls
228
- - Missing source metadata
229
- - Source-layer mismatch
230
-
231
- `--init` generates a real config from the directories that *actually exist* in your project.
232
-
233
- ---
234
-
235
- ## ESLint Plugin (dev guardrails)
236
-
237
- ```js
238
- // eslint.config.js
239
- import ark from 'ark-runtime-kernel/eslint';
240
-
241
- export default [
242
- ark.configs.recommended,
243
- ];
244
- ```
245
-
246
- Rules:
247
- - `ark/no-domain-infra-imports`
248
- - `ark/no-raw-event-publish`
249
- - `ark/require-publish-source`
250
-
251
- ---
252
-
253
- ## What Ark Is / Is Not
254
-
255
- | โœ… Ark is | โŒ Ark is not |
256
- |---------------------------------------|-------------------------------------------|
257
- | Runtime + CI + AI governance kernel | Database or queue |
258
- | Enforceable architectural contract | Full distributed workflow engine |
259
- | Machine-readable manifest for agents | Replacement for your domain logic |
260
- | Zero-dependency TypeScript library | Complete semantic / type analyzer |
261
- | Observable drift + history | OpenTelemetry implementation |
262
- | Focused, explicit, pluggable | Magic that covers code you never route |
263
-
264
- ---
265
-
266
- ## Architecture Profile (11 Layers)
267
-
268
- The built-in profile + `ark.config.json` give you a sane default taxonomy:
269
-
270
- `DomainModel โ†’ ApplicationOrchestration โ†’ PersistenceAdapters โ†’ ...` (and 8 more)
271
-
272
- You can customize freely. Rules are deny-by-default except for a few explicitly allowed flows.
273
-
274
- ---
275
-
276
- ## Production Notes
277
-
278
- All stores (`Audit`, `Outbox`, `Projections`, `Workflow`) default to in-memory.
279
-
280
- See [docs/production-hardening.md](./docs/production-hardening.md) for the interface contracts you must implement for durability.
281
-
282
- ---
213
+ `@nestjs/common` is an optional peer dependency โ€” the core stays zero-dependency.
283
214
 
284
215
  ## Documentation
285
216
 
286
- - [Agent Integration Guide](docs/agent-guide.md) โ€” wiring `ark-mcp` into Claude Code, Cursor, and other agent runtimes
287
- - [Production Hardening](docs/production-hardening.md) โ€” durable store interfaces to implement (`AuditStore`, `OutboxStore`, โ€ฆ)
288
- - [Example Config](docs/ark-check-example.json) โ€” a hand-curated `ark.config.json` starting point
289
- - [Runnable Examples](examples/) โ€” `examples/basic/` (kernel tour) and `examples/publish-smoke/` (consumer smoke test)
290
- - [Changelog](CHANGELOG.md)
291
-
292
- ---
217
+ - [AI Gates](docs/ai-gates.md) โ€” copy-paste setups for Claude Code, Cursor, Codex, and any hook-capable runtime
218
+ - [Agent Integration Guide](docs/agent-guide.md) โ€” manifest discovery and validation flows for agents
219
+ - [Production Hardening](docs/production-hardening.md) โ€” durable store interfaces (`AuditStore`, `OutboxStore`, โ€ฆ)
220
+ - [Example Config](docs/ark-check-example.json) โ€” a hand-curated `ark.config.json`
221
+ - [Runnable Examples](examples/) โ€” including `examples/hexagonal-order-api/`, a full hexagonal API you can break on purpose
222
+ - [Roadmap](ROADMAP.md) ยท [Contributing](CONTRIBUTING.md) ยท [Changelog](CHANGELOG.md)
293
223
 
294
224
  ## Development
295
225
 
296
226
  ```bash
297
- npm install
227
+ npm ci
228
+ npm run build # ark-mcp loads dist/
229
+ npx vitest run
298
230
  npm run typecheck
299
- npm run check:architecture
300
- npm test
301
- npm run build
231
+ npm run check:architecture # Ark gates itself in CI
302
232
  ```
303
233
 
304
- **Release process (already scripted):**
305
-
306
- ```bash
307
- npm run release:npm # full verify + publish
308
- npm run release:npm -- --dry # dry run
309
- ```
310
-
311
- The release script:
312
- 1. Typechecks + runs all tests + self architecture check
313
- 2. Builds
314
- 3. Temporarily swaps in the minimal publish manifest
315
- 4. Publishes
316
- 5. Restores dev manifest
317
-
318
- ---
234
+ Release: `npm run release:npm` (verifies typecheck + tests + architecture gate, then publishes; `-- --dry` for a dry run).
319
235
 
320
236
  ## License
321
237
 
@@ -324,5 +240,3 @@ MIT ยฉ Pedro Knigge
324
240
  ---
325
241
 
326
242
  **Ark doesn't generate architecture. It protects the architecture you already have โ€” at the exact moments it matters most.**
327
-
328
- Built for teams that use AI heavily and refuse to let entropy win.