ark-runtime-kernel 1.2.0 → 1.4.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 +132 -8
- package/bin/ark-check.mjs +355 -48
- package/bin/ark-mcp.mjs +147 -3
- package/bin/ark-shared.mjs +53 -1
- package/dist/eslint/index.cjs +49 -1
- package/dist/eslint/index.cjs.map +1 -1
- package/dist/eslint/index.d.cts +4 -1
- package/dist/eslint/index.d.ts +4 -1
- package/dist/eslint/index.js +49 -2
- package/dist/eslint/index.js.map +1 -1
- package/dist/index.cjs +50 -2
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.cts +7 -1
- package/dist/index.d.ts +7 -1
- package/dist/index.js +50 -2
- package/dist/index.js.map +1 -1
- package/dist/nestjs/index.cjs +1 -1
- package/dist/nestjs/index.cjs.map +1 -1
- package/dist/nestjs/index.js +1 -1
- package/dist/nestjs/index.js.map +1 -1
- package/docs/agent-guide.md +9 -0
- package/docs/ai-gates.md +76 -0
- package/package.json +8 -2
- package/server.json +7 -7
- package/docs/blog/how-i-stopped-claude-from-breaking-my-architecture.md +0 -85
package/docs/agent-guide.md
CHANGED
|
@@ -277,6 +277,15 @@ createAdapter(PaymentGateway, stripeAdapter, {
|
|
|
277
277
|
|
|
278
278
|
Preset: `elevenLayerProfile` plus `defineArchitectureProfilePolicy()` forbids invalid declared dependencies across the 11-layer profile. `architecturalPolicies.cleanArchitectureMatrix()` remains available for the older four-prefix model.
|
|
279
279
|
|
|
280
|
+
Runtime support depth varies by design. Layers with dedicated kernel modules:
|
|
281
|
+
DomainModel/ApplicationOrchestration (intents, policies), WorkflowSagaEngine
|
|
282
|
+
(workflow engine), PersistenceAdapters (adapters, outbox), ReportingReadModels
|
|
283
|
+
(projections), ExtensibilityMetadata (metadata registry), SecurityAuditObservability
|
|
284
|
+
(audit trail, drift reporter), Kernel (event bus, graph, manifest).
|
|
285
|
+
PresentationAdapters, IntegrationAdapters, and BackgroundJobsScheduling are
|
|
286
|
+
**boundary-only on purpose**: Ark governs what they may import and publish, but does
|
|
287
|
+
not replace your web framework, HTTP clients, or job scheduler.
|
|
288
|
+
|
|
280
289
|
## Write-Path Gate (MCP)
|
|
281
290
|
|
|
282
291
|
The strongest place to constrain an AI agent is the moment it writes a file, not after.
|
package/docs/ai-gates.md
CHANGED
|
@@ -31,10 +31,19 @@ GitHub Actions, `AGENTS.md`, and a Codex TOML snippet under `docs/`. It skips
|
|
|
31
31
|
existing files unless you pass `--force`, so review and commit only the templates
|
|
32
32
|
that match your project.
|
|
33
33
|
|
|
34
|
+
If your project uses Codex, treat the MCP registration as part of the default setup,
|
|
35
|
+
not an optional extra. Ark works best when Codex can read `ark://manifest` before it
|
|
36
|
+
writes code; that is the fast path to avoiding architecture drift during generation.
|
|
37
|
+
|
|
34
38
|
## Claude Code — hook (recommended, hard block)
|
|
35
39
|
|
|
36
40
|
`ark-mcp --hook` is a one-shot PreToolUse gate: it reads the hook payload from stdin, computes the **post-edit** file content, validates it, and exits `2` (block, violations on stderr) or `0` (allow). The agent sees the violations and self-corrects.
|
|
37
41
|
|
|
42
|
+
Like `ark-check --baseline`, the hook ratchets: an edit is blocked only when it **adds**
|
|
43
|
+
violations relative to the file's current on-disk state, so files with pre-existing
|
|
44
|
+
(baselined) violations stay editable — they just can't get worse. New files block on
|
|
45
|
+
every violation.
|
|
46
|
+
|
|
38
47
|
Add to your project's `.claude/settings.json`:
|
|
39
48
|
|
|
40
49
|
```json
|
|
@@ -64,6 +73,47 @@ Ark architecture gate blocked this write to src/domain/order.ts (layer: DomainMo
|
|
|
64
73
|
Fix the violations and retry. The architecture contract is available as the ark://manifest MCP resource.
|
|
65
74
|
```
|
|
66
75
|
|
|
76
|
+
## Claude Code — SessionStart context injection (know the rules before the first token)
|
|
77
|
+
|
|
78
|
+
The write gate teaches by rejection; the SessionStart hook teaches up front.
|
|
79
|
+
`ark-mcp --session-context` prints a compact contract summary — layers, forbidden
|
|
80
|
+
globals, denied-edge count, baseline state, and the check command — which Claude Code
|
|
81
|
+
injects into the agent's context at session start:
|
|
82
|
+
|
|
83
|
+
```json
|
|
84
|
+
{
|
|
85
|
+
"hooks": {
|
|
86
|
+
"SessionStart": [
|
|
87
|
+
{
|
|
88
|
+
"hooks": [
|
|
89
|
+
{
|
|
90
|
+
"type": "command",
|
|
91
|
+
"command": "npx ark-mcp --session-context --root \"$CLAUDE_PROJECT_DIR\" --config ark.config.json"
|
|
92
|
+
}
|
|
93
|
+
]
|
|
94
|
+
}
|
|
95
|
+
]
|
|
96
|
+
}
|
|
97
|
+
}
|
|
98
|
+
```
|
|
99
|
+
|
|
100
|
+
What the agent sees:
|
|
101
|
+
|
|
102
|
+
```
|
|
103
|
+
Ark architecture contract governs this project (ark.config.json is authoritative).
|
|
104
|
+
Layers:
|
|
105
|
+
- DomainModel: src/domain/** — forbidden globals: fetch, process, Date.now, Math.random
|
|
106
|
+
- PersistenceAdapters: src/adapters/persistence/**
|
|
107
|
+
Rules: 10 denied layer edge(s). Full contract: ark://manifest MCP resource.
|
|
108
|
+
Baseline: 3 frozen violation(s) — only NEW violations fail; do not add to them.
|
|
109
|
+
After edits run: npx ark-check --root . --config ark.config.json --strict-config
|
|
110
|
+
```
|
|
111
|
+
|
|
112
|
+
The hook belongs in the **project's** `.claude/settings.json` (that's what
|
|
113
|
+
`--install-agent-gates` generates). It is also safe by construction if you prefer it in
|
|
114
|
+
your global settings: without an `ark.config.json` in the project, `--session-context`
|
|
115
|
+
prints nothing and exits 0, so non-Ark projects are untouched.
|
|
116
|
+
|
|
67
117
|
## Claude Code — MCP server (contract discovery + on-demand validation)
|
|
68
118
|
|
|
69
119
|
The MCP server exposes two things agents can use proactively:
|
|
@@ -124,6 +174,8 @@ Your hard backstop in Cursor is CI: `ark-check` fails the PR on anything that sl
|
|
|
124
174
|
|
|
125
175
|
## OpenAI Codex CLI
|
|
126
176
|
|
|
177
|
+
Recommended for Ark projects.
|
|
178
|
+
|
|
127
179
|
`~/.codex/config.toml`:
|
|
128
180
|
|
|
129
181
|
```toml
|
|
@@ -133,6 +185,30 @@ args = ["ark-mcp", "--root", ".", "--config", "ark.config.json"]
|
|
|
133
185
|
```
|
|
134
186
|
|
|
135
187
|
Same model as Cursor: MCP for discovery/validation, `ark-check` in CI as the hard gate.
|
|
188
|
+
For Ark projects, register the MCP server as soon as the repo is adopted so the agent
|
|
189
|
+
has the contract available from the first edit.
|
|
190
|
+
|
|
191
|
+
## Instruction-tier agents: Windsurf, Cline, GitHub Copilot, Kiro, Gemini CLI
|
|
192
|
+
|
|
193
|
+
Agents without MCP or hook support still follow the contract through an always-on
|
|
194
|
+
project rule file. `ark-check --install-agent-gates` generates them (auto-detected
|
|
195
|
+
from `.windsurf/`, `.clinerules/`, `.kiro/`; Copilot is explicit-only):
|
|
196
|
+
|
|
197
|
+
```bash
|
|
198
|
+
npx ark-check --install-agent-gates --tools windsurf,cline,copilot,kiro
|
|
199
|
+
```
|
|
200
|
+
|
|
201
|
+
| Tool | File written |
|
|
202
|
+
|------|--------------|
|
|
203
|
+
| Windsurf | `.windsurf/rules/ark.md` |
|
|
204
|
+
| Cline | `.clinerules/ark.md` |
|
|
205
|
+
| GitHub Copilot | `.github/copilot-instructions.md` |
|
|
206
|
+
| Kiro | `.kiro/steering/ark.md` |
|
|
207
|
+
| Gemini CLI | none needed — it reads the generated `AGENTS.md` |
|
|
208
|
+
|
|
209
|
+
All of them derive from the same contract as `AGENTS.md` and the Cursor rule, so the
|
|
210
|
+
steps cannot drift. These are advisory (the agent reads rules; nothing blocks the
|
|
211
|
+
write) — keep `ark-check` in CI as the hard gate.
|
|
136
212
|
|
|
137
213
|
## Any other agent runtime with shell hooks
|
|
138
214
|
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "ark-runtime-kernel",
|
|
3
|
-
"version": "1.
|
|
3
|
+
"version": "1.4.0",
|
|
4
4
|
"description": "Architectural Runtime Kernel — governance for Hexagonal + Event-Driven + DDD systems",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"main": "./dist/index.cjs",
|
|
@@ -82,7 +82,13 @@
|
|
|
82
82
|
"ai-agents",
|
|
83
83
|
"mcp",
|
|
84
84
|
"lint",
|
|
85
|
-
"architecture-fitness"
|
|
85
|
+
"architecture-fitness",
|
|
86
|
+
"architecture-enforcement",
|
|
87
|
+
"import-rules",
|
|
88
|
+
"dependency-rules",
|
|
89
|
+
"boundaries",
|
|
90
|
+
"layered-architecture",
|
|
91
|
+
"ai-code-gate"
|
|
86
92
|
],
|
|
87
93
|
"license": "MIT",
|
|
88
94
|
"repository": {
|
package/server.json
CHANGED
|
@@ -1,22 +1,22 @@
|
|
|
1
1
|
{
|
|
2
|
-
"$schema": "https://static.modelcontextprotocol.io/schemas/2025-
|
|
2
|
+
"$schema": "https://static.modelcontextprotocol.io/schemas/2025-12-11/server.schema.json",
|
|
3
3
|
"name": "io.github.pedroknigge/ark",
|
|
4
|
-
"description": "Architecture write-gate for AI agents:
|
|
4
|
+
"description": "Architecture write-gate for AI agents: blocks code that violates your Hexagonal/DDD layer rules.",
|
|
5
5
|
"repository": {
|
|
6
6
|
"url": "https://github.com/pedroknigge/ark-runtime-kernel",
|
|
7
7
|
"source": "github"
|
|
8
8
|
},
|
|
9
|
-
"version": "1.
|
|
9
|
+
"version": "1.4.0",
|
|
10
10
|
"packages": [
|
|
11
11
|
{
|
|
12
|
-
"
|
|
12
|
+
"registryType": "npm",
|
|
13
13
|
"identifier": "ark-runtime-kernel",
|
|
14
|
-
"version": "1.
|
|
14
|
+
"version": "1.4.0",
|
|
15
|
+
"runtimeHint": "npx",
|
|
15
16
|
"transport": {
|
|
16
17
|
"type": "stdio"
|
|
17
18
|
},
|
|
18
|
-
"
|
|
19
|
-
"package_arguments": [
|
|
19
|
+
"packageArguments": [
|
|
20
20
|
{ "type": "positional", "value": "ark-mcp" },
|
|
21
21
|
{ "type": "named", "name": "--root", "value": ".", "description": "Project root" },
|
|
22
22
|
{
|
|
@@ -1,85 +0,0 @@
|
|
|
1
|
-
# How I stopped Claude from breaking my hexagonal architecture
|
|
2
|
-
|
|
3
|
-
*Draft — publish on dev.to / HN / r/typescript alongside the repo going public.*
|
|
4
|
-
|
|
5
|
-
---
|
|
6
|
-
|
|
7
|
-
AI agents write most of my code now. They're fast, they're tireless, and they have absolutely no respect for my architecture.
|
|
8
|
-
|
|
9
|
-
Ask an agent to "add a findById method to Order" and there's a decent chance it imports the Postgres repository straight into the domain layer. The code compiles. The tests pass. The PR looks fine at a glance. Three months of that and your hexagonal architecture is a decorative diagram.
|
|
10
|
-
|
|
11
|
-
The usual answer is "review harder" — which doesn't scale when the agent produces 30 PRs a week — or "add a linter", which catches the violation *after* the agent already built three files on top of it.
|
|
12
|
-
|
|
13
|
-
## The insight: block at write time, not review time
|
|
14
|
-
|
|
15
|
-
Agent runtimes like Claude Code have pre-write hooks: a shell command that runs *before* a file edit lands, and can veto it. That's a fundamentally better enforcement point than CI:
|
|
16
|
-
|
|
17
|
-
1. The violation never reaches disk.
|
|
18
|
-
2. The agent sees the error **in its loop** and self-corrects immediately — it defines the port in the domain and implements it in the adapter, like you would have asked for in review.
|
|
19
|
-
|
|
20
|
-
So I built [Ark](https://github.com/pedroknigge/ark-runtime-kernel). You describe your architecture once, as data:
|
|
21
|
-
|
|
22
|
-
```json
|
|
23
|
-
{
|
|
24
|
-
"layers": [
|
|
25
|
-
{ "name": "DomainModel", "patterns": ["src/domain/**"] },
|
|
26
|
-
{ "name": "PersistenceAdapters", "patterns": ["src/adapters/persistence/**"] }
|
|
27
|
-
],
|
|
28
|
-
"rules": [
|
|
29
|
-
{ "from": "DomainModel", "to": "PersistenceAdapters", "allowed": false }
|
|
30
|
-
]
|
|
31
|
-
}
|
|
32
|
-
```
|
|
33
|
-
|
|
34
|
-
Then wire it into Claude Code as a PreToolUse hook:
|
|
35
|
-
|
|
36
|
-
```json
|
|
37
|
-
{
|
|
38
|
-
"hooks": {
|
|
39
|
-
"PreToolUse": [{
|
|
40
|
-
"matcher": "Write|Edit|MultiEdit",
|
|
41
|
-
"hooks": [{ "type": "command",
|
|
42
|
-
"command": "npx ark-mcp --hook --root \"$CLAUDE_PROJECT_DIR\" --config ark.config.json" }]
|
|
43
|
-
}]
|
|
44
|
-
}
|
|
45
|
-
}
|
|
46
|
-
```
|
|
47
|
-
|
|
48
|
-
Now the same request plays out like this:
|
|
49
|
-
|
|
50
|
-
```
|
|
51
|
-
● Write(src/domain/order.ts)
|
|
52
|
-
✗ Ark architecture gate blocked this write to src/domain/order.ts (layer: DomainModel):
|
|
53
|
-
- [FORBIDDEN_PATTERN] Forbidden pattern matched: /from ['"].*\/(infra|adapters|persistence|db)/i (line 1)
|
|
54
|
-
- [FORBIDDEN_IMPORT] Forbidden import target: "../adapters/persistence/order-repository". (line 1)
|
|
55
|
-
Fix the violations and retry. The architecture contract is available as the ark://manifest MCP resource.
|
|
56
|
-
|
|
57
|
-
● The domain layer can't import persistence adapters. I'll define the port in
|
|
58
|
-
the domain instead and implement it in src/adapters/persistence/.
|
|
59
|
-
```
|
|
60
|
-
|
|
61
|
-
The agent fixed its own architecture violation. Nobody reviewed anything.
|
|
62
|
-
|
|
63
|
-
## Details that turned out to matter
|
|
64
|
-
|
|
65
|
-
**The gate validates the post-edit file, not the diff.** An edit snippet out of context tells you nothing about imports. `ark-mcp --hook` applies the proposed edit to the current file content and validates the result.
|
|
66
|
-
|
|
67
|
-
**The same config gates CI.** Not every write goes through an agent, and not every agent runtime has hooks. `ark-check` runs the same rules in CI with TypeScript's real module resolver — path aliases and all — so nothing merges that violates the contract, whoever wrote it.
|
|
68
|
-
|
|
69
|
-
**Agents can read the contract, not just bounce off it.** The MCP server also exposes `ark://manifest` — the architecture as JSON — so agents get the rules *before* generating code instead of learning by rejection.
|
|
70
|
-
|
|
71
|
-
**Existing codebases need a ratchet.** Nobody adopts a checker that greets them with 400 errors. `ark-check --update-baseline` freezes today's violations; from then on only *new* ones fail. The count only goes down.
|
|
72
|
-
|
|
73
|
-
## What about dependency-cruiser / eslint-plugin-boundaries?
|
|
74
|
-
|
|
75
|
-
They're good tools and they cover the CI half. What they don't have is the write-time half: an MCP server and hook designed for agent runtimes, plus a machine-readable manifest for agents to consume. That's the part that changes agent behavior instead of just grading it.
|
|
76
|
-
|
|
77
|
-
## Try it
|
|
78
|
-
|
|
79
|
-
```bash
|
|
80
|
-
npm i -D ark-runtime-kernel typescript
|
|
81
|
-
npx ark-check --init # infers layers from your folder structure
|
|
82
|
-
npx ark-check # CI gate
|
|
83
|
-
```
|
|
84
|
-
|
|
85
|
-
Repo: https://github.com/pedroknigge/ark-runtime-kernel — zero dependencies, MIT.
|