arkgate 2.1.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/CHANGELOG.md +1249 -0
- package/LICENSE +21 -0
- package/README.md +218 -0
- package/SECURITY.md +39 -0
- package/bin/ark-check.mjs +5204 -0
- package/bin/ark-mcp.mjs +898 -0
- package/bin/ark-shared.mjs +1520 -0
- package/bin/ark.mjs +491 -0
- package/dist/eslint/index.cjs +222 -0
- package/dist/eslint/index.cjs.map +1 -0
- package/dist/eslint/index.d.cts +42 -0
- package/dist/eslint/index.d.ts +40 -0
- package/dist/eslint/index.js +193 -0
- package/dist/eslint/index.js.map +1 -0
- package/dist/index.cjs +3080 -0
- package/dist/index.cjs.map +1 -0
- package/dist/index.d.cts +577 -0
- package/dist/index.d.ts +577 -0
- package/dist/index.js +2998 -0
- package/dist/index.js.map +1 -0
- package/dist/nestjs/index.cjs +2332 -0
- package/dist/nestjs/index.cjs.map +1 -0
- package/dist/nestjs/index.d.cts +22 -0
- package/dist/nestjs/index.d.ts +22 -0
- package/dist/nestjs/index.js +2308 -0
- package/dist/nestjs/index.js.map +1 -0
- package/dist/types-DpdVN7Lm.d.cts +1023 -0
- package/dist/types-DpdVN7Lm.d.ts +1023 -0
- package/docs/agent-guide.md +490 -0
- package/docs/ai-gates.md +337 -0
- package/docs/ark-check-example.json +87 -0
- package/docs/assets/ark-write-gate.svg +28 -0
- package/docs/brownfield-adoption.md +87 -0
- package/docs/demos/01-write-gate-self-correction.md +74 -0
- package/docs/demos/02-brownfield-baseline-adoption.md +71 -0
- package/docs/demos/03-copilot-autopilot.md +83 -0
- package/docs/enthusiast/README.md +62 -0
- package/docs/enthusiast/explanation-application-shape.md +29 -0
- package/docs/enthusiast/how-to-agent-gates.md +36 -0
- package/docs/enthusiast/how-to-gallery-starter.md +27 -0
- package/docs/enthusiast/how-to-pick-shape.md +45 -0
- package/docs/enthusiast/how-to-policy-pack.md +37 -0
- package/docs/enthusiast/reference-archetypes.md +36 -0
- package/docs/enthusiast/reference-commands.md +50 -0
- package/docs/enthusiast/tutorial-first-project.md +86 -0
- package/docs/production-hardening.md +59 -0
- package/package.json +125 -0
- package/server.json +39 -0
- package/templates/architecture-playbook.json +339 -0
- package/templates/policy-packs/enthusiast-feature-sliced.json +20 -0
- package/templates/policy-packs/enthusiast-hexagonal.json +18 -0
- package/templates/policy-packs/enthusiast-layered.json +18 -0
- package/templates/policy-packs/enthusiast-monorepo.json +18 -0
- package/templates/skills/ark-adopt.md +103 -0
- package/templates/skills/ark-architect.md +90 -0
- package/templates/skills/ark-autopilot.md +95 -0
- package/templates/skills/ark-contract.md +98 -0
- package/templates/skills/ark-coverage.md +96 -0
- package/templates/skills/ark-explain.md +78 -0
- package/templates/skills/ark-fix.md +96 -0
- package/templates/skills/ark-loop.md +69 -0
- package/templates/skills/ark-place.md +68 -0
- package/templates/skills/ark-runtime.md +62 -0
- package/templates/skills/ark-upgrade.md +109 -0
|
@@ -0,0 +1,490 @@
|
|
|
1
|
+
# Ark — Agent Integration Guide
|
|
2
|
+
|
|
3
|
+
**Ark — Architecture Co-pilot for AI TypeScript.** This guide describes how AI agents
|
|
4
|
+
and codegen tools can safely interact with the write gate, MCP tools, and `/ark-*` skills.
|
|
5
|
+
|
|
6
|
+
## Architecture playbook and `ark-check --recommend`
|
|
7
|
+
|
|
8
|
+
Before generating project structure, agents should read the **tool-agnostic application
|
|
9
|
+
shape** that fits the repository — not a vendor stack label. Ark ships a versioned playbook
|
|
10
|
+
at `templates/architecture-playbook.json` (also in the npm package under `templates/`).
|
|
11
|
+
|
|
12
|
+
Each of the ten archetypes (`crud-product`, `api-backend`, `frontend-surface`,
|
|
13
|
+
`library-sdk`, `cli-utility`, `worker-pipeline`, `event-coordinator`,
|
|
14
|
+
`integration-bridge`, `multi-app-workspace`, `prototype-spike`) maps to:
|
|
15
|
+
|
|
16
|
+
- a named Ark preset (`hexagonal`, `layered`, `feature-sliced`, or `monorepo`),
|
|
17
|
+
- phased 11-layer adoption (phase 1–3),
|
|
18
|
+
- plain-language analogy and anti-patterns,
|
|
19
|
+
- optional book references for depth only.
|
|
20
|
+
|
|
21
|
+
Scoring is **deterministic**: repo shape signals (workspaces, UI dirs, API surface,
|
|
22
|
+
persistence, jobs, workflows, CLI `bin`, source-file count, …) are matched against the
|
|
23
|
+
playbook. Framework packages may appear as secondary `toolHints` in JSON output — never as
|
|
24
|
+
the primary archetype id.
|
|
25
|
+
|
|
26
|
+
All playbook labels, analogies, anti-patterns, and `--recommend` prose are **English**
|
|
27
|
+
(`locale: "en"` in the playbook). Agents should present them as-is unless a future locale
|
|
28
|
+
pack is explicitly loaded.
|
|
29
|
+
|
|
30
|
+
### Terminal
|
|
31
|
+
|
|
32
|
+
```bash
|
|
33
|
+
npx ark-check --recommend
|
|
34
|
+
npx ark-check --recommend --json
|
|
35
|
+
```
|
|
36
|
+
|
|
37
|
+
`--recommend` does not require `ark.config.json`. It exits `0` and prints a progressive
|
|
38
|
+
adoption plan: archetype id, preset, `confidence`, `runnerUp`, `why` (shape signals),
|
|
39
|
+
`adoptInOrder.phase1`, `firstCommand` (`ark init --archetype …`), and `checkCommand`.
|
|
40
|
+
|
|
41
|
+
Human output highlights phase-1 layers and the analogy; JSON is the stable contract for
|
|
42
|
+
MCP `ark_recommend` and the `/ark-architect` skill.
|
|
43
|
+
|
|
44
|
+
### Terminal onboarding (Phase B)
|
|
45
|
+
|
|
46
|
+
```bash
|
|
47
|
+
npx ark init --archetype crud-product --yes # non-interactive: shape → preset → gates → strict check
|
|
48
|
+
npx ark init # TTY wizard: pick application shape (1–8), not a framework
|
|
49
|
+
npx ark-check --doctor # includes "New here?" when coverage is low or config is fresh
|
|
50
|
+
npx ark-check --report beginner.html --beginner # simplified HTML for enthusiasts
|
|
51
|
+
npx ark-check --watch # debounced re-check when governed files change
|
|
52
|
+
```
|
|
53
|
+
|
|
54
|
+
`ark init --archetype <id>` maps playbook ids to named presets (`hexagonal`, `layered`,
|
|
55
|
+
`feature-sliced`, `monorepo`). With `--yes` and no archetype, Ark auto-selects from
|
|
56
|
+
`--recommend` scoring.
|
|
57
|
+
|
|
58
|
+
`ark-check --json` violations include enthusiast-oriented fields when present:
|
|
59
|
+
`fixClass` (e.g. `port-inversion`, `file-move`), `effort` (`small` | `medium`), and
|
|
60
|
+
`enthusiastHint` (plain English). `--doctor --json` exposes `doctor.newHere` with
|
|
61
|
+
`recommendCommand` and `initCommand` when the nudge applies.
|
|
62
|
+
|
|
63
|
+
### MCP `ark_recommend` and `/ark-architect` (Phase C)
|
|
64
|
+
|
|
65
|
+
The `ark-mcp` server exposes **`ark_recommend`** — same JSON as
|
|
66
|
+
`ark-check --recommend --json`. Call it (or invoke `/ark-architect`) before
|
|
67
|
+
generating project structure on greenfield or early-adoption repos.
|
|
68
|
+
|
|
69
|
+
`ark-mcp --session-context` appends a one-line enthusiast hint when governed
|
|
70
|
+
coverage is low or the config is fresh:
|
|
71
|
+
|
|
72
|
+
```
|
|
73
|
+
New to Ark? Run /ark-architect or: ark-check --recommend
|
|
74
|
+
```
|
|
75
|
+
|
|
76
|
+
The `/ark-architect` skill ships in `templates/skills/ark-architect.md` and installs
|
|
77
|
+
via `ark-check --install-agent-gates`.
|
|
78
|
+
|
|
79
|
+
### Adoption plan artifact (Phase E)
|
|
80
|
+
|
|
81
|
+
```bash
|
|
82
|
+
npx ark-check --recommend --write-plan
|
|
83
|
+
# writes ark-adoption-plan.json (optional commit; never weakens the gate)
|
|
84
|
+
```
|
|
85
|
+
|
|
86
|
+
Includes `archetype`, `preset`, `adoptInOrder`, `galleryStarter`, and suggested
|
|
87
|
+
`policyPack` (`enthusiast-<preset>`).
|
|
88
|
+
|
|
89
|
+
### Enthusiast policy packs (Phase E)
|
|
90
|
+
|
|
91
|
+
```bash
|
|
92
|
+
npx ark-check --list-policy-packs
|
|
93
|
+
npx ark-check --apply-policy-pack enthusiast-hexagonal # or layered, feature-sliced, monorepo
|
|
94
|
+
```
|
|
95
|
+
|
|
96
|
+
Packs delegate to the same preset factories as `ark init --preset`; layer
|
|
97
|
+
descriptions are shorter enthusiast copy. Metadata: `templates/policy-packs/`.
|
|
98
|
+
|
|
99
|
+
### Enthusiast documentation track
|
|
100
|
+
|
|
101
|
+
Diátaxis pages under [docs/enthusiast/](enthusiast/README.md) — tutorial, how-to,
|
|
102
|
+
reference, and explanation for the full path (recommend → init → gallery → gates → verify).
|
|
103
|
+
|
|
104
|
+
### Agent workflow (before codegen)
|
|
105
|
+
|
|
106
|
+
1. Run `ark-check --recommend --json` or MCP `ark_recommend`.
|
|
107
|
+
2. Read `archetype`, `preset`, and `adoptInOrder.phase1` — scaffold only those directories first.
|
|
108
|
+
3. Run `ark init --archetype <id> --yes`, `--apply-policy-pack enthusiast-<preset>`, or `ark init --preset <preset> --yes` when no `ark.config.json` exists.
|
|
109
|
+
4. Optional: `--write-plan` for `ark-adoption-plan.json`; copy a gallery starter from `examples/README.md`.
|
|
110
|
+
5. Use `/ark-place` or `ark_place` for individual files after the contract exists.
|
|
111
|
+
6. Verify with `ark-check --root . --config ark.config.json --strict-config`.
|
|
112
|
+
|
|
113
|
+
Do not invent layers outside the 11-layer profile or named presets. Unrecognized
|
|
114
|
+
directories (`utils/`, `lib/`) must be classified explicitly via `/ark-contract`.
|
|
115
|
+
|
|
116
|
+
**Brownfield** (existing messy repo): use `/ark-adopt` and [brownfield-adoption.md](brownfield-adoption.md), not `/ark-architect`.
|
|
117
|
+
|
|
118
|
+
## Supported agent hosts
|
|
119
|
+
|
|
120
|
+
Wire write-gate + MCP + `/ark-*` skills with:
|
|
121
|
+
|
|
122
|
+
```bash
|
|
123
|
+
npx ark-check --install-agent-gates --tools claude,cursor,codex,grok
|
|
124
|
+
```
|
|
125
|
+
|
|
126
|
+
| Host | Write gate | MCP | Skills path |
|
|
127
|
+
|------|------------|-----|-------------|
|
|
128
|
+
| Claude Code | PreToolUse hook | `.mcp.json` / `claude mcp add` | `.claude/skills/<name>/SKILL.md` |
|
|
129
|
+
| Cursor | Advisory (rules + MCP) | `.cursor/mcp.json` | `.cursor/commands/` |
|
|
130
|
+
| OpenAI Codex | MCP + CI | `~/.codex/config.toml` | `$CODEX_HOME/prompts` (`--codex-home`) |
|
|
131
|
+
| **Grok Build** | PreToolUse hook (`.grok/hooks/`) | `.grok/config.toml` + `.mcp.json` | `.grok/skills/<name>/SKILL.md` |
|
|
132
|
+
|
|
133
|
+
Full copy-paste setups: [ai-gates.md](ai-gates.md). Skill inventory: main [README](../README.md#agent-skills-ark-).
|
|
134
|
+
|
|
135
|
+
## Contract Discovery
|
|
136
|
+
|
|
137
|
+
Prefer `createStrictArkKernel()` for strict projects. It wires the registry, graph,
|
|
138
|
+
policies, event bus, audit trail, event contracts, outbox, observability,
|
|
139
|
+
projections, metadata, workflow engine, and 11-layer architecture profile:
|
|
140
|
+
|
|
141
|
+
```ts
|
|
142
|
+
import {
|
|
143
|
+
createStrictArkKernel,
|
|
144
|
+
} from 'arkgate';
|
|
145
|
+
|
|
146
|
+
const ark = createStrictArkKernel();
|
|
147
|
+
// ... define intents, event contracts, metadata, projections, and workflows through ark.*
|
|
148
|
+
|
|
149
|
+
const contract = ark.manifest().toJSON();
|
|
150
|
+
// contract.intents, policies, entities, graph, architecture, eventContracts,
|
|
151
|
+
// contract.observability, projections
|
|
152
|
+
```
|
|
153
|
+
|
|
154
|
+
Agents should read `contract` and `ark.observability.report()` before generating or modifying code.
|
|
155
|
+
|
|
156
|
+
## Naming Conventions
|
|
157
|
+
|
|
158
|
+
| Prefix | Layer | Example |
|
|
159
|
+
|--------|-------|---------|
|
|
160
|
+
| `Domain.*` | Domain events & entities | `Domain.Order.OrderPlaced` |
|
|
161
|
+
| `Application.*` | Use cases / orchestration | `Application.PlaceOrder` |
|
|
162
|
+
| `Adapter.Persistence.*` | Persistence adapters | `Adapter.Persistence.OrderRepo` |
|
|
163
|
+
| `Adapter.Integration.*` | External integrations | `Adapter.Integration.PaymentGateway.Charge` |
|
|
164
|
+
| `Workflow.*` | Sagas / long-running processes | `Workflow.OrderFulfillment` |
|
|
165
|
+
| `Job.*` | Background jobs / scheduling | `Job.InventoryRebuild` |
|
|
166
|
+
| `Presentation.*` | UI/API adapters | `Presentation.Api.PlaceOrder` |
|
|
167
|
+
| `Reporting.*` | Read models / projections | `Reporting.OrderSummary` |
|
|
168
|
+
| `Metadata.*` | Metadata and extension contracts | `Metadata.OrderSchema` |
|
|
169
|
+
| `Security.*`, `Audit.*`, `Observability.*` | Cross-cutting concerns | `Audit.OrderHistory` |
|
|
170
|
+
| `Kernel.*` | Ark-owned governance signals | `Kernel.PolicyViolation` |
|
|
171
|
+
|
|
172
|
+
Declare relationships at definition time:
|
|
173
|
+
|
|
174
|
+
```ts
|
|
175
|
+
registry.define('Application.PlaceOrder', {
|
|
176
|
+
dependsOn: ['Domain.Order.OrderPlaced'],
|
|
177
|
+
produces: ['Domain.Order.OrderPlaced'],
|
|
178
|
+
});
|
|
179
|
+
```
|
|
180
|
+
|
|
181
|
+
Strict kernels also enforce the **observed** producer→event layer flow at publish time
|
|
182
|
+
(`enforceObservedLayerFlow: 'hard'` by default). If a published event's real source and
|
|
183
|
+
intent cross a forbidden layer boundary — e.g. a `Adapter.Persistence.*` source producing
|
|
184
|
+
a `Domain.*` event — the publish throws `ObservedLayerFlowViolationError` before the event
|
|
185
|
+
reaches history, outbox, or subscribers. Use `'soft'` to record `layer.observedViolation`
|
|
186
|
+
trace/audit records without blocking, or `'off'` to disable. Agents should name the event's
|
|
187
|
+
`source` honestly: it is checked against the layer matrix, not just the intent name.
|
|
188
|
+
|
|
189
|
+
Strict kernels also require published events to have a registered source intent
|
|
190
|
+
and a matching event contract:
|
|
191
|
+
|
|
192
|
+
```ts
|
|
193
|
+
const OrderPlaced = registry.define<
|
|
194
|
+
'Domain.Order.OrderPlaced',
|
|
195
|
+
{ orderId: string; amount: number }
|
|
196
|
+
>('Domain.Order.OrderPlaced');
|
|
197
|
+
|
|
198
|
+
registry.define('Application.PlaceOrder', {
|
|
199
|
+
produces: ['Domain.Order.OrderPlaced'],
|
|
200
|
+
});
|
|
201
|
+
|
|
202
|
+
ark.eventContracts.register({
|
|
203
|
+
intent: 'Domain.Order.OrderPlaced',
|
|
204
|
+
version: '1',
|
|
205
|
+
allowAdditionalFields: false,
|
|
206
|
+
schema: {
|
|
207
|
+
orderId: { type: 'string', required: true },
|
|
208
|
+
amount: { type: 'number', required: true },
|
|
209
|
+
},
|
|
210
|
+
});
|
|
211
|
+
|
|
212
|
+
const publisher = ark.publisher('Application.PlaceOrder');
|
|
213
|
+
|
|
214
|
+
await publisher.publish(OrderPlaced, { orderId: 'o1', amount: 99 }, {
|
|
215
|
+
eventVersion: '1',
|
|
216
|
+
});
|
|
217
|
+
```
|
|
218
|
+
|
|
219
|
+
Agents should prefer `ark.publisher(sourceIntent).publish(...)` over direct
|
|
220
|
+
`eventBus.publish(...)`. Source-bound publishers stamp `metadata.source` internally and
|
|
221
|
+
reject attempts to override it with a different source.
|
|
222
|
+
|
|
223
|
+
Interceptors may enrich event payloads, but they must remain add-only:
|
|
224
|
+
|
|
225
|
+
```ts
|
|
226
|
+
ark.eventBus.registerInterceptor(OrderPlaced, ({ intercept }) => {
|
|
227
|
+
intercept({ auditTag: 'checkout' });
|
|
228
|
+
}, 'audit-tag');
|
|
229
|
+
```
|
|
230
|
+
|
|
231
|
+
If an interceptor overwrites an existing field or violates the registered event
|
|
232
|
+
contract, Ark records `interceptor.error` and keeps delivering the original event.
|
|
233
|
+
|
|
234
|
+
## Code Generation Validation
|
|
235
|
+
|
|
236
|
+
Use `createAICodeGate()` before merging agent-generated source snippets:
|
|
237
|
+
|
|
238
|
+
```ts
|
|
239
|
+
import * as ts from 'typescript';
|
|
240
|
+
|
|
241
|
+
const gate = createAICodeGate({
|
|
242
|
+
intents: registry.list(),
|
|
243
|
+
enforceIntentAllowlist: true,
|
|
244
|
+
architectureProfile: elevenLayerProfile,
|
|
245
|
+
typescript: ts,
|
|
246
|
+
extensions: [/* optional external AST analyzers implementing AIGateExtension */],
|
|
247
|
+
});
|
|
248
|
+
|
|
249
|
+
const result = gate.validate(generatedSource, {
|
|
250
|
+
filePath: 'src/domain/order.ts',
|
|
251
|
+
agentId: 'agent-1',
|
|
252
|
+
layer: 'DomainModel',
|
|
253
|
+
});
|
|
254
|
+
if (!result.valid) {
|
|
255
|
+
for (const v of result.violations) {
|
|
256
|
+
console.log(v.code, v.message, v.suggestion);
|
|
257
|
+
}
|
|
258
|
+
}
|
|
259
|
+
```
|
|
260
|
+
|
|
261
|
+
Passing the `typescript` module enables built-in AST checks for raw publish calls, missing
|
|
262
|
+
`metadata.source`, and source-layer mismatches. `ark-mcp` enables these checks
|
|
263
|
+
automatically when TypeScript is available.
|
|
264
|
+
|
|
265
|
+
Violation codes (from `createAICodeGate`): `RAW_EVENT_PUBLISH`, `PUBLISH_MISSING_SOURCE`, `PUBLISH_SOURCE_LAYER_MISMATCH`, `FORBIDDEN_PATTERN`, `FORBIDDEN_SUBSTRING`, `FORBIDDEN_IMPORT`, `POLICY_VIOLATION`, `UNKNOWN_INTENT`, `LAYER_REFERENCE_VIOLATION`, `EXTENSION_ERROR`, `AST_ANALYZER_ERROR`.
|
|
266
|
+
|
|
267
|
+
Use `ark-check` in CI for repository-level checks that need real file paths:
|
|
268
|
+
|
|
269
|
+
```bash
|
|
270
|
+
npx ark-check --root . --config ark.config.json
|
|
271
|
+
```
|
|
272
|
+
|
|
273
|
+
Agents can generate a config from the project's actual directory layout instead of inventing layer mappings:
|
|
274
|
+
|
|
275
|
+
```bash
|
|
276
|
+
npx ark-check --init
|
|
277
|
+
```
|
|
278
|
+
|
|
279
|
+
Or print the full 11-layer template to adapt manually:
|
|
280
|
+
|
|
281
|
+
```bash
|
|
282
|
+
npx ark-check --print-config eleven-layer
|
|
283
|
+
```
|
|
284
|
+
|
|
285
|
+
Example config:
|
|
286
|
+
|
|
287
|
+
```json
|
|
288
|
+
{
|
|
289
|
+
"include": ["src"],
|
|
290
|
+
"layers": [
|
|
291
|
+
{
|
|
292
|
+
"name": "DomainModel",
|
|
293
|
+
"patterns": ["src/domain/**"],
|
|
294
|
+
"intentPrefixes": ["Domain."]
|
|
295
|
+
},
|
|
296
|
+
{
|
|
297
|
+
"name": "PersistenceAdapters",
|
|
298
|
+
"patterns": ["src/adapters/persistence/**"],
|
|
299
|
+
"intentPrefixes": ["Adapter.Persistence."]
|
|
300
|
+
},
|
|
301
|
+
{
|
|
302
|
+
"name": "ApplicationOrchestration",
|
|
303
|
+
"patterns": ["src/application/**"],
|
|
304
|
+
"intentPrefixes": ["Application."]
|
|
305
|
+
}
|
|
306
|
+
],
|
|
307
|
+
"rules": [
|
|
308
|
+
{
|
|
309
|
+
"from": "DomainModel",
|
|
310
|
+
"to": "PersistenceAdapters",
|
|
311
|
+
"allowed": false
|
|
312
|
+
}
|
|
313
|
+
]
|
|
314
|
+
}
|
|
315
|
+
```
|
|
316
|
+
|
|
317
|
+
`ark-check` resolves imports through the TypeScript module resolver against your
|
|
318
|
+
`tsconfig.json` — relative, path-alias (e.g. `@infra/db`), package imports, dynamic
|
|
319
|
+
`import()`, and `require()` — plus string intent references. It also flags raw
|
|
320
|
+
`publish()` calls, publish calls without `metadata.source`, and source intent literals
|
|
321
|
+
whose resolved layer differs from the publishing file layer. Pass `--tsconfig <path>` to force one config
|
|
322
|
+
for every file; otherwise each source file uses the nearest `tsconfig.json` above it (like
|
|
323
|
+
`tsc`), so monorepos with per-package alias maps work under a single `--root`. It resolves
|
|
324
|
+
modules the way your build does, but is intentionally not yet a full type-graph analyzer
|
|
325
|
+
(cross-layer type-only references beyond the import specifier are out of scope).
|
|
326
|
+
|
|
327
|
+
Repeat runs are cached in `node_modules/.cache/ark-check.json` — unchanged files skip the
|
|
328
|
+
parse, while import edges always re-resolve against the live filesystem so the cache can
|
|
329
|
+
never hide a new violation. `--no-cache` disables it.
|
|
330
|
+
|
|
331
|
+
`ark-check --json` also reports `warnings` for incomplete governance coverage: missing
|
|
332
|
+
layers, unclassified included files, unmatched layer patterns, duplicate layers, and rules
|
|
333
|
+
that reference unknown layers. These are advisory by default. Use `--strict-config` once a
|
|
334
|
+
project is ready to fail CI on coverage gaps.
|
|
335
|
+
|
|
336
|
+
Use the optional ESLint plugin for fast local feedback:
|
|
337
|
+
|
|
338
|
+
```js
|
|
339
|
+
import ark from 'arkgate/eslint';
|
|
340
|
+
|
|
341
|
+
export default [
|
|
342
|
+
ark.configs.recommended,
|
|
343
|
+
];
|
|
344
|
+
```
|
|
345
|
+
|
|
346
|
+
Rules: `ark/no-domain-infra-imports`, `ark/no-raw-event-publish`, and
|
|
347
|
+
`ark/require-publish-source`.
|
|
348
|
+
|
|
349
|
+
## Runtime Observability
|
|
350
|
+
|
|
351
|
+
The event bus exposes a standard trace format:
|
|
352
|
+
|
|
353
|
+
```ts
|
|
354
|
+
const bus = createEventBus({
|
|
355
|
+
maxHistorySize: 1000,
|
|
356
|
+
auditTrail,
|
|
357
|
+
traceSinks: [(record) => otelBridge(record)],
|
|
358
|
+
onSoftViolation: (result, event) => { /* advisory policies */ },
|
|
359
|
+
onHandlerError: (err, event, intent) => { /* subscriber failures */ },
|
|
360
|
+
});
|
|
361
|
+
|
|
362
|
+
await bus.publish(intent, payload);
|
|
363
|
+
const trace = bus.getTrace();
|
|
364
|
+
// trace[].type includes 'event.published', 'event.rawPublish', 'event.intercepted',
|
|
365
|
+
// 'interceptor.error', 'policy.hardViolation', 'policy.softViolation', 'handler.error'
|
|
366
|
+
```
|
|
367
|
+
|
|
368
|
+
Native audit records are available through `auditTrail.query()`. Projection
|
|
369
|
+
state and checkpoints are available through `ProjectionRegistry`.
|
|
370
|
+
|
|
371
|
+
`ark.observability.report()` compares declared productions with observed runtime
|
|
372
|
+
flows. Use `observedButUndeclared` as a high-signal review queue for hidden coupling.
|
|
373
|
+
|
|
374
|
+
For tests, use `createArkTestHarness(ark)` to inspect events, traces, audit,
|
|
375
|
+
outbox, and observability snapshots without reaching into private internals.
|
|
376
|
+
|
|
377
|
+
## Extension Points (External Layers)
|
|
378
|
+
|
|
379
|
+
Implement these interfaces in **external** packages — not inside the Ark core:
|
|
380
|
+
|
|
381
|
+
| Interface | Purpose |
|
|
382
|
+
|-----------|---------|
|
|
383
|
+
| `AIGateExtension` | Plug in AST/semantic analyzers for codegen validation |
|
|
384
|
+
| `Policy` | Custom architectural rules via `definePolicy()` |
|
|
385
|
+
| `LayerFlowRule` | Layer isolation via `defineLayerPolicy()` |
|
|
386
|
+
| `WorkflowStore` | Persist workflow snapshots outside memory |
|
|
387
|
+
| `ReadModelStore` | Persist projection/read-model state outside memory |
|
|
388
|
+
| `AuditStore` | Persist audit records outside memory |
|
|
389
|
+
| `OutboxStore` | Persist event outbox records outside memory |
|
|
390
|
+
| `EventInterceptor` | Add-only event enrichment before delivery |
|
|
391
|
+
|
|
392
|
+
## Ports and Adapters
|
|
393
|
+
|
|
394
|
+
When generating adapter code, prefer ports with explicit ownership and allowlists:
|
|
395
|
+
|
|
396
|
+
```ts
|
|
397
|
+
const PaymentGateway = definePort<PaymentGatewayPort>('PaymentGateway', {
|
|
398
|
+
ownerLayer: 'ApplicationOrchestration',
|
|
399
|
+
intent: 'Application.Port.PaymentGateway',
|
|
400
|
+
allowedAdapters: ['Adapter.Integration.StripePaymentGateway'],
|
|
401
|
+
});
|
|
402
|
+
|
|
403
|
+
createAdapter(PaymentGateway, stripeAdapter, {
|
|
404
|
+
name: 'Adapter.Integration.StripePaymentGateway',
|
|
405
|
+
layer: 'IntegrationAdapters',
|
|
406
|
+
requiredKeys: ['charge'],
|
|
407
|
+
});
|
|
408
|
+
```
|
|
409
|
+
|
|
410
|
+
`createAdapter` rejects adapter names/intents not listed in `allowedAdapters`; use
|
|
411
|
+
`checkAdapterGovernance(adapter)` when a tool needs a non-throwing result.
|
|
412
|
+
|
|
413
|
+
Preset: `elevenLayerProfile` plus `defineArchitectureProfilePolicy()` forbids invalid declared dependencies across the 11-layer profile. `architecturalPolicies.cleanArchitectureMatrix()` remains available for the older four-prefix model.
|
|
414
|
+
|
|
415
|
+
Runtime support depth varies by design. Layers with dedicated kernel modules:
|
|
416
|
+
DomainModel/ApplicationOrchestration (intents, policies), WorkflowSagaEngine
|
|
417
|
+
(workflow engine), PersistenceAdapters (adapters, outbox), ReportingReadModels
|
|
418
|
+
(projections), ExtensibilityMetadata (metadata registry), SecurityAuditObservability
|
|
419
|
+
(audit trail, drift reporter), Kernel (event bus, graph, manifest).
|
|
420
|
+
PresentationAdapters, IntegrationAdapters, and BackgroundJobsScheduling are
|
|
421
|
+
**boundary-only on purpose**: Ark governs what they may import and publish, but does
|
|
422
|
+
not replace your web framework, HTTP clients, or job scheduler.
|
|
423
|
+
|
|
424
|
+
## Write-Path Gate (MCP)
|
|
425
|
+
|
|
426
|
+
The strongest place to constrain an AI agent is the moment it writes a file, not after.
|
|
427
|
+
`ark-mcp` exposes Ark over MCP (zero dependencies, JSON-RPC over stdio) so a host can gate
|
|
428
|
+
the write path:
|
|
429
|
+
|
|
430
|
+
```bash
|
|
431
|
+
npx ark-mcp --root . --config ark.config.json [--manifest ark.manifest.json]
|
|
432
|
+
```
|
|
433
|
+
|
|
434
|
+
- **Resource `ark://manifest`** — contract discovery. Serve your exported
|
|
435
|
+
`ark.manifest().toJSON()` via `--manifest`, or omit it to get the 11-layer profile
|
|
436
|
+
(layers + rules) as the default contract.
|
|
437
|
+
- **Tool `ark_recommend`** — no args. Returns the deterministic application-shape plan
|
|
438
|
+
(archetype, preset, phased adoption, analogy). Same as `ark-check --recommend --json`.
|
|
439
|
+
- **Tool `validate_code`** — args `{ source, layer?, filePath? }`. Runs `createAICodeGate`
|
|
440
|
+
against the profile and (when a manifest is provided) the registered intent allowlist.
|
|
441
|
+
Returns `{ valid, violations, layer }`; `isError` is `true` when invalid. If `layer` is
|
|
442
|
+
omitted it is inferred from `filePath` via the config's layer patterns.
|
|
443
|
+
|
|
444
|
+
For hook-based enforcement, `ark-mcp --hook` runs one-shot: it reads a PreToolUse payload
|
|
445
|
+
from stdin, validates the post-edit file content, and exits `2` with violations on stderr
|
|
446
|
+
to block the write (`0` to allow). Working Claude Code configuration
|
|
447
|
+
(`.claude/settings.json`):
|
|
448
|
+
|
|
449
|
+
```json
|
|
450
|
+
{
|
|
451
|
+
"hooks": {
|
|
452
|
+
"PreToolUse": [
|
|
453
|
+
{
|
|
454
|
+
"matcher": "Write|Edit|MultiEdit",
|
|
455
|
+
"hooks": [
|
|
456
|
+
{
|
|
457
|
+
"type": "command",
|
|
458
|
+
"command": "npx ark-mcp --hook --root \"$CLAUDE_PROJECT_DIR\""
|
|
459
|
+
}
|
|
460
|
+
]
|
|
461
|
+
}
|
|
462
|
+
]
|
|
463
|
+
}
|
|
464
|
+
}
|
|
465
|
+
```
|
|
466
|
+
|
|
467
|
+
Register the server itself in `.mcp.json` so the agent can read `ark://manifest` and call
|
|
468
|
+
`validate_code` on demand:
|
|
469
|
+
|
|
470
|
+
```json
|
|
471
|
+
{
|
|
472
|
+
"mcpServers": {
|
|
473
|
+
"ark": { "command": "npx", "args": ["ark-mcp", "--root", ".", "--config", "ark.config.json"] }
|
|
474
|
+
}
|
|
475
|
+
}
|
|
476
|
+
```
|
|
477
|
+
|
|
478
|
+
This makes the manifest + AI gate an enforced checkpoint rather than a library the agent
|
|
479
|
+
must remember to call.
|
|
480
|
+
|
|
481
|
+
## Recommended Agent Workflow
|
|
482
|
+
|
|
483
|
+
1. **Read** manifest via `ark.manifest().toJSON()`
|
|
484
|
+
2. **Generate** code using registered intents, profiles, metadata, projections, and workflow definitions
|
|
485
|
+
3. **Validate snippets** with `createAICodeGate().validate(source, { layer })`
|
|
486
|
+
4. **Validate repository** with `ark-check --root . --config ark.config.json`
|
|
487
|
+
5. **Lint** with `arkgate/eslint` recommended rules
|
|
488
|
+
6. **Wire** relationships via `registry.define(..., { dependsOn, produces })`
|
|
489
|
+
7. **Register** event contracts before publishing in strict mode
|
|
490
|
+
8. **Observe** runtime via `bus.getTrace()`, `auditTrail.query()`, outbox records, projection checkpoints, and `ark.observability.report()`
|