@veil-runtime/core 0.1.2 → 0.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
@@ -1,522 +1,58 @@
1
- # Veil
2
-
3
- Veil is a capability-driven execution platform for AI and software systems.
4
-
5
- It separates **reasoning** from **execution**, allowing planners, language models, agents, humans and applications to safely interact with external systems through reusable capabilities while keeping execution governed, observable, auditable and independent of any specific AI provider.
6
-
7
- The goal is simple:
8
-
9
- > **Allow any planner to decide _what_ should happen, while Veil reliably decides _how_ it happens.**
10
-
11
- Or, more simply:
12
-
13
- > **Veil treats AI as a planning problem and execution as an engineering problem.**
14
-
15
- ---
16
-
17
- # Vision
18
-
19
- Modern language models are exceptional at reasoning.
20
-
21
- They should not be responsible for safely interacting with production systems.
22
-
23
- Veil provides the governed execution layer between reasoning and the outside world.
24
-
25
- Instead of allowing planners to directly manipulate browsers, files, databases, infrastructure or external services, Veil executes structured plans through governed capabilities, applying validation, permissions, policies, memory, logging and runtime services before any action is performed.
26
-
27
- The result is a reusable execution platform capable of powering automation, operational intelligence, developer tooling and enterprise integrations without coupling execution to any specific reasoning system or AI provider.
28
-
29
- ---
30
-
31
- # Architectural Principles
32
-
33
- Veil owns **the contract between reasoning and execution**.
34
-
35
- It does not prescribe how reasoning is performed or how capabilities are implemented.
36
-
37
- Instead, it defines stable interfaces that allow both sides to evolve independently.
38
-
39
- ```text
40
- Reasoning
41
-
42
- Planner Providers
43
- Planner Strategies
44
- Planner Routing
45
-
46
- ExecutionPlan
47
- ══════════════════════
48
- OperatorRuntime
49
- ══════════════════════
50
- Capability Registry
51
- Capability Modules
52
- Providers
53
-
54
- Execution
55
- ```
56
-
57
- This separation allows new planners, routing strategies, capability modules and providers to be introduced without changing Veil Core.
58
-
59
- ---
60
-
61
- # Architecture
62
-
63
- ```text
64
- Goal
65
-
66
-
67
- Planner Router
68
-
69
- selects strategy
70
-
71
-
72
- Planner Strategy
73
-
74
- ┌────────────┼────────────┐
75
- │ │ │
76
- ▼ ▼ ▼
77
- Planner Registry Runtime State Eligibility
78
-
79
- └────────────┬────────────┘
80
-
81
-
82
- Planner Provider(s)
83
-
84
-
85
- ExecutionPlan
86
-
87
- ══════════════════════════════════════════════
88
- VEIL
89
- ══════════════════════════════════════════════
90
-
91
-
92
-
93
- OperatorRuntime
94
-
95
- ┌───────────────┼───────────────┐
96
- ▼ ▼ ▼
97
- Policy Job Manager Event Bus
98
-
99
-
100
- Execution Engine
101
-
102
-
103
- Capability Registry
104
-
105
-
106
- Capability Modules
107
-
108
-
109
- Providers
110
-
111
- ┌──────────────┬──────────────┬──────────────┬──────────────┐
112
- ▼ ▼ ▼ ▼
113
- Browser Filesystem Shell HTTP
114
- ```
115
-
116
- ---
117
-
118
- # Current Features
119
-
120
- ## Runtime
121
-
122
- - Generic execution engine
123
- - OperatorRuntime façade
124
- - Planner router registry
125
- - Planner registry
126
- - Strategy registry
127
- - Capability registry
128
- - ExecutionPlan contract
129
- - Execution context
130
- - Event bus
131
- - Runtime events
132
- - Structured execution logging
133
- - Job lifecycle management
134
- - Persistent SQLite job store
135
- - Human-reviewed outcomes
136
-
137
- ---
138
-
139
- ## Planning
140
-
141
- - Planner router
142
- - Planner registry
143
- - Planner strategies
144
- - Deterministic planner
145
- - OpenAI-compatible planner support
146
- - Example local and distributed planner configurations
147
- - Planner health monitoring
148
- - Planner runtime state
149
- - Planner eligibility
150
- - Historical context retrieval
151
- - ExecutionPlan v1
152
-
153
- ---
154
-
155
- ## SDK
156
-
157
- - Capability SDK
158
- - Declarative capability authoring
159
- - Middleware pipeline
160
- - Lifecycle middleware
161
- - Timeout middleware
162
- - Runtime execution options
163
- - Capability module support
164
-
165
- ---
166
-
167
- ## Memory
168
-
169
- - Persistent job history
170
- - Planner context retrieval
171
- - Historical capability recall
172
- - Outcome recording
173
- - Human review workflow
174
-
175
- ---
176
-
177
- ## Capabilities
178
-
179
- - LinkedIn authentication
180
- - LinkedIn profile reader
181
- - Generic web page reader
182
- - HTTP request execution
183
- - Filesystem reader
184
- - Shell command execution
185
-
186
- ---
187
-
188
- ## Providers
189
-
190
- - Browser provider
191
- - Browser session manager
192
- - HTTP provider
193
- - Filesystem provider
194
- - Shell provider
195
- - SQLite provider
196
- - OpenAI-compatible AI providers
197
-
198
- ---
199
-
200
- # Design Principles
201
-
202
- - Planner agnostic
203
- - Strategy agnostic
204
- - Provider agnostic
205
- - Capability driven
206
- - Runtime governed
207
- - Explicit permissions
208
- - Structured observability
209
- - Human review before learning
210
- - Small composable services
211
- - Extension through composition
212
- - Reusable by design
213
-
214
- ---
215
-
216
- # What Makes Veil Different
217
-
218
- Veil does not attempt to replace language models.
219
-
220
- Instead, it provides the governed execution environment around them.
221
-
222
- Reasoning remains completely replaceable.
223
-
224
- Execution remains governed and deterministic at the capability boundary.
225
-
226
- Applications can embed Veil without coupling themselves to specific planners, capability implementations or infrastructure providers.
227
-
228
- Because these responsibilities remain independent:
229
-
230
- - Routers choose strategies.
231
- - Strategies orchestrate planners.
232
- - Planners produce execution plans.
233
- - OperatorRuntime governs execution.
234
- - Capabilities perform the work.
235
- - Providers interact with external systems.
236
- - Runtime services remain independent of planners and capabilities.
237
-
238
- This separation allows Veil to remain reusable across domains while ensuring execution remains governed, observable and consistent.
239
-
240
- ---
241
-
242
- # Roadmap
243
-
244
- ## Runtime
245
-
246
- - Dependency graph execution
247
- - Parallel capability execution
248
- - Live progress reporting
249
- - Cancellation
250
- - Retry policies
251
- - Secrets service
252
- - Metrics
253
- - Audit services
254
- - Resource management
255
-
256
- ---
257
-
258
- ## SDK
259
-
260
- - Provider SDK
261
- - Capability testing framework
262
- - Middleware library
263
- - Validation helpers
264
- - Retry middleware
265
- - Metrics middleware
266
- - Audit middleware
267
- - Execution decorators
268
-
269
- ---
270
-
271
- ## Intelligence
272
-
273
- - Planner routing policies
274
- - Planner evaluation
275
- - Cost-aware routing
276
- - Latency-aware routing
277
- - Capability recommendations
278
- - Historical plan optimisation
279
- - Outcome-aware learning
280
- - Runtime analytics
281
- - Multi-agent planning pipelines
282
-
283
- ---
284
-
285
- ## Capabilities
286
-
287
- - LinkedIn posting
288
- - GitHub
289
- - Docker
290
- - SSH
291
- - SQL
292
- - Jira
293
- - Confluence
294
- - Kubernetes
295
- - Cloud providers
296
- - Generic REST integrations
297
-
298
- ---
299
-
300
- # Long-Term Direction
301
-
302
- Veil is evolving into a reusable execution platform capable of powering:
303
-
304
- - AI assistants
305
- - Operational intelligence platforms
306
- - Enterprise automation
307
- - Developer tooling
308
- - Agentic systems
309
- - Workflow orchestration
310
- - Multi-agent collaboration
311
-
312
- Reasoning remains modular through planners, strategies and routing.
313
-
314
- Execution remains governed and deterministic at the capability boundary.
315
-
316
- Veil defines the contract between them.
317
-
318
- ---
319
-
320
- # Status
321
-
322
- Veil has evolved beyond a proof of concept into a reusable execution platform.
323
-
324
- The execution runtime, capability system, reasoning architecture, planner routing, planner strategies, provider model, event bus, persistent memory, module architecture and SDK foundation are now in place.
325
-
326
- The current focus is strengthening the platform itself—its SDKs, runtime services, provider ecosystem, reasoning architecture and execution model—so that new planners, strategies, capabilities and integrations become progressively simpler to build while preserving governed, observable and reliable execution.
327
-
328
- Every architectural improvement compounds across the platform, allowing Veil to grow in capability while keeping complexity contained behind stable contracts.
329
-
330
- The guiding principles remain simple:
331
-
332
- > **Veil owns the contract between reasoning and execution.**
333
-
334
- > **Planners reason. Strategies orchestrate. OperatorRuntime governs execution. Veil owns the contract between them.**
335
-
336
- > **Architecture evolves only when existing contracts can no longer express a real-world use case. Otherwise, Veil grows through extensions rather than changes to its core.**
337
-
338
- ---
339
- ---
340
-
341
- # Getting Started
342
-
343
- ## Requirements
344
-
345
- - Node.js 24+
346
- - npm
347
- - Git
348
-
349
- Optional:
350
-
351
- - Docker Model Runner or another OpenAI-compatible endpoint
352
- - Playwright (for browser capabilities)
353
-
354
- ---
355
-
356
- ## Installation
357
-
358
- Install the public runtime package in an application:
359
-
360
- ```bash
361
- npm install @veil-runtime/core
362
- ```
363
-
364
- Create and execute a capability through the public API:
365
-
366
- ```ts
367
- import {
368
- createCapability,
369
- OperatorRuntime,
370
- type CapabilityModule,
371
- type ExecutionPlan,
372
- } from '@veil-runtime/core';
373
-
374
- const echo = createCapability<{ value: string }, string>({
375
- name: 'example.echo',
376
- version: '1.0.0',
377
- description: 'Return the provided value',
378
- risk: 'read',
379
- async execute({ input }) {
380
- return input.value;
381
- },
382
- });
383
-
384
- const module: CapabilityModule = {
385
- manifest: {
386
- name: 'example',
387
- version: '1.0.0',
388
- capabilities: [echo.name],
389
- },
390
- capabilities: [echo],
391
- };
392
-
393
- const plan: ExecutionPlan = {
394
- version: '1.0',
395
- steps: [{
396
- id: 'echo',
397
- capability: echo.name,
398
- capabilityVersion: echo.version,
399
- input: { value: 'Hello from Veil' },
400
- }],
401
- };
402
-
403
- const runtime = new OperatorRuntime();
404
- runtime.use(module);
405
-
406
- const job = await runtime.executePlan(plan);
407
- console.log(job.status, job.result);
408
- ```
409
-
410
- This public-package usage is compile- and execution-verified by the release
411
- consumer fixture. Internal `src`, `dist`, registry, provider, and storage
412
- subpaths are intentionally unavailable.
413
-
414
- ### Contextual execution authorization
415
-
416
- An application may supply a runtime-scoped authorizer. Veil resolves and
417
- validates the step input before invoking it, and does not start a denied
418
- capability:
419
-
420
- ```ts
421
- import {
422
- OperatorRuntime,
423
- type ExecutionAuthorizer,
424
- } from '@veil-runtime/core';
425
-
426
- const authorizer: ExecutionAuthorizer = {
427
- async authorize({ capability, input }) {
428
- if (
429
- capability.name === 'deploy.trigger' &&
430
- typeof input === 'object' &&
431
- input !== null &&
432
- 'environment' in input &&
433
- input.environment === 'production'
434
- ) {
435
- return {
436
- decision: 'deny',
437
- reason: 'Production deployment is not allowed.',
438
- };
439
- }
440
-
441
- return { decision: 'allow' };
442
- },
443
- };
444
-
445
- const runtime = new OperatorRuntime({ authorizer });
446
- ```
447
-
448
- ## Repository development
449
-
450
- Clone the repository:
451
-
452
- ```bash
453
- git clone git@github.com:veil-runtime/veil.git
454
- cd veil
455
- ```
456
-
457
- Install dependencies:
458
-
459
- ```bash
460
- npm install
461
- ```
462
-
463
- ---
464
-
465
- ## Running Veil
466
-
467
- Start the runtime:
468
-
469
- ```bash
470
- JOB_STORE=sqlite npm run dev
471
- ```
472
-
473
- The runtime will start on:
474
-
475
- ```
476
- http://127.0.0.1:3333
477
- ```
478
-
479
- Verify it's running:
480
-
481
- ```bash
482
- curl http://127.0.0.1:3333/health
483
- ```
484
-
485
- Expected response:
486
-
487
- ```json
488
- {
489
- "status": "ok",
490
- "service": "operator-runtime"
491
- }
492
- ```
493
-
494
- ---
495
-
496
- ## Running Your First Job
497
-
498
- Submit a goal:
499
-
500
- ```bash
501
- curl -X POST http://127.0.0.1:3333/api/jobs/run \
502
- -H "Content-Type: application/json" \
503
- -d '{
504
- "goal": "Read README.md"
505
- }'
506
- ```
507
-
508
- Veil will:
509
-
510
- 1. Route the request through a `PlannerRouter`.
511
- 2. Select a `PlannerStrategy`.
512
- 3. Generate an `ExecutionPlan`.
513
- 4. Execute the plan through `OperatorRuntime`.
514
- 5. Return the completed job.
515
-
516
- ---
517
-
518
- # License and branding
519
-
520
- Veil Core is licensed under Apache-2.0. Copyright 2026 Mustapha Keraan.
521
- Veil names, logos, and branding are governed separately; see
522
- [TRADEMARKS.md](TRADEMARKS.md) for the brand policy.
1
+ # Veil
2
+
3
+ Veil is a governed, capability-driven execution runtime for AI and software systems.
4
+
5
+ **Developer documentation:** [GitHub Pages portal](https://veil-runtime.github.io/veil/developer.html) | [repository docs](docs/developer.md)
6
+
7
+ ## The idea
8
+
9
+ Veil separates reasoning from execution. A human, application, deterministic planner, or AI system produces an ExecutionPlan; OperatorRuntime validates and executes it through registered capabilities.
10
+
11
+ Reasoning / application -> ExecutionPlan -> OperatorRuntime
12
+ -> validation -> reference resolution -> authorization
13
+ -> capability -> provider -> external system
14
+ -> job history and events
15
+
16
+ Planners reason. Strategies orchestrate. Routers select strategies. Capabilities define work. Providers interact with external systems.
17
+
18
+ ## Install
19
+
20
+ Requires Node.js 24+.
21
+
22
+ npm install @veil-runtime/core
23
+
24
+ This installs the published package. To verify v0.2.0 before publication, see [candidate installation](docs/getting-started/installation.md).
25
+
26
+ ## Smallest working example
27
+
28
+ import { createCapability, OperatorRuntime } from '@veil-runtime/core';
29
+
30
+ const echo = createCapability<{ value: string }, string>({
31
+ name: 'example.echo', version: '1.0.0', description: 'Return a value', risk: 'read',
32
+ inputSchema: { value: { type: 'string', required: true, description: 'Text' } },
33
+ async execute({ input }) { return input.value; },
34
+ });
35
+ const module = {
36
+ manifest: { name: 'example', version: '1.0.0', capabilities: [echo.name] },
37
+ capabilities: [echo],
38
+ };
39
+ const runtime = new OperatorRuntime();
40
+ runtime.use(module);
41
+ const job = await runtime.executePlan({ version: '1.0', steps: [{
42
+ id: 'echo', capability: echo.name, capabilityVersion: echo.version,
43
+ input: { value: 'Hello from Veil' },
44
+ }] });
45
+
46
+ The default authorizer permits reads and denies write/destructive capabilities. Supply a runtime-scoped authorizer to allow selected writes. See [authorization](docs/concepts/authorization.md).
47
+
48
+ ## Status and roadmap
49
+
50
+ Release candidate: **v0.2.0**. See [release notes](docs/getting-started/v0.2.0.md). The latest published package remains **v0.1.3** until publication. ExecutionPlan v1 is linear. DAGs, parallel execution, conditionals, cancellation, and retry policies are roadmap work, not current behavior.
51
+
52
+ ## Contributing
53
+
54
+ See [development setup](docs/contributing/development-setup.md), [testing](docs/contributing/testing.md), and the [architecture rules](docs/contributing/architecture-rules.md).
55
+
56
+ ## License and branding
57
+
58
+ Veil Core is licensed under Apache-2.0. See [LICENSE](LICENSE), [NOTICE](NOTICE), and [TRADEMARKS.md](TRADEMARKS.md).
package/dist/index.d.ts CHANGED
@@ -4,7 +4,7 @@ export type { OperatorRuntimeOptions } from './runtime/operator-runtime.js';
4
4
  export type { CapabilityAuthorizationContext, CapabilityAuthorizationDecision, ExecutionAuthorizer, } from './runtime/permissions/execution-authorizer.js';
5
5
  export type { ExecutionPlan, ExecutionStep, Planner, PlannerContext, ResultReference, } from './runtime/planner/planner.js';
6
6
  export type { ExecutionCaller, ExecutionContext } from './runtime/execution/execution-context.js';
7
- export type { Capability, CapabilityInputField, CapabilityRisk, } from './runtime/registry/capability.js';
7
+ export type { Capability, CapabilityDescriptor, CapabilityInputField, CapabilityRisk, } from './runtime/registry/capability.js';
8
8
  export type { CapabilityModule } from './runtime/modules/capability-module.js';
9
9
  export type { CapabilityModuleManifest } from './runtime/modules/capability-module-manifest.js';
10
10
  export type { Job, JobOutcome } from './runtime/jobs/job.js';
@@ -24,7 +24,14 @@ class MemoryEventBus {
24
24
  ...specific,
25
25
  ...wildcard,
26
26
  ];
27
- await Promise.all(handlers.map((handler) => Promise.resolve(handler(event))));
27
+ await Promise.all(handlers.map(async (handler) => {
28
+ try {
29
+ await handler(event);
30
+ }
31
+ catch {
32
+ // Subscriber failures are contained observer failures.
33
+ }
34
+ }));
28
35
  }
29
36
  }
30
37
  exports.MemoryEventBus = MemoryEventBus;
@@ -79,6 +79,13 @@ function validatePlan(steps) {
79
79
  const errors = [];
80
80
  const seenStepIds = new Set();
81
81
  for (const step of steps) {
82
+ if (seenStepIds.has(step.id)) {
83
+ errors.push({
84
+ stepId: step.id,
85
+ capability: step.capability,
86
+ message: `Duplicate step ID: ${step.id}`,
87
+ });
88
+ }
82
89
  const capability = registry_js_1.capabilityRegistry.get(step.capability);
83
90
  if (!capability) {
84
91
  errors.push({
@@ -89,7 +96,7 @@ function validatePlan(steps) {
89
96
  seenStepIds.add(step.id);
90
97
  continue;
91
98
  }
92
- if (step.capabilityVersion && step.capabilityVersion !== capability.version) {
99
+ if (step.capabilityVersion !== undefined && step.capabilityVersion !== capability.version) {
93
100
  errors.push({
94
101
  stepId: step.id,
95
102
  capability: step.capability,
@@ -39,7 +39,7 @@ function resolveResultReferences(value, completedSteps) {
39
39
  }
40
40
  let resolved = step.result;
41
41
  for (const segment of path) {
42
- if (!resolved || typeof resolved !== 'object' || !(segment in resolved)) {
42
+ if (!resolved || typeof resolved !== 'object' || !Object.hasOwn(resolved, segment)) {
43
43
  throw new Error(`Result reference path not found: ${value.$ref}`);
44
44
  }
45
45
  resolved = resolved[segment];
@@ -14,20 +14,38 @@ const composite_log_sink_js_1 = require("../logging/composite-log-sink.js");
14
14
  const sqlite_log_sink_js_1 = require("../logging/sqlite-log-sink.js");
15
15
  class JobManager {
16
16
  async executePlan(plan, caller, authorizer = execution_authorizer_js_1.defaultExecutionAuthorizer) {
17
- if (!plan.steps.length) {
17
+ // Own the structural envelope before admission; nested input remains shared.
18
+ const capturedGoal = plan.goal;
19
+ const idempotencyKey = plan.idempotencyKey;
20
+ const submittedSteps = plan.steps;
21
+ const steps = new Array(submittedSteps.length);
22
+ for (let index = 0; index < steps.length; index += 1) {
23
+ if (!(index in submittedSteps))
24
+ continue;
25
+ const step = submittedSteps[index];
26
+ steps[index] = {
27
+ id: step.id,
28
+ capability: step.capability,
29
+ capabilityVersion: step.capabilityVersion,
30
+ input: step.input,
31
+ reason: step.reason,
32
+ idempotencyKey: step.idempotencyKey,
33
+ };
34
+ }
35
+ if (!steps.length) {
18
36
  throw new Error('Execution plan contains no steps');
19
37
  }
20
- const validation = (0, plan_validator_js_1.validatePlan)(plan.steps);
38
+ const validation = (0, plan_validator_js_1.validatePlan)(steps);
21
39
  if (!validation.valid) {
22
40
  throw new Error(`Execution plan failed validation: ${validation.errors
23
41
  .map((error) => error.message)
24
42
  .join('; ')}`);
25
43
  }
26
- const goal = plan.goal?.trim() ||
44
+ const goal = capturedGoal?.trim() ||
27
45
  'External execution plan';
28
46
  const job = await this.create(goal);
29
- job.idempotencyKey = plan.idempotencyKey;
30
- job.steps = plan.steps.map((step) => ({
47
+ job.idempotencyKey = idempotencyKey;
48
+ job.steps = steps.map((step) => ({
31
49
  ...step,
32
50
  status: 'pending',
33
51
  createdAt: new Date().toISOString(),
@@ -112,8 +130,22 @@ class JobManager {
112
130
  input: resolvedInput,
113
131
  caller,
114
132
  });
115
- if (authorization.decision === 'deny') {
116
- const message = authorization.reason ??
133
+ if (typeof authorization !== 'object' ||
134
+ authorization === null ||
135
+ Array.isArray(authorization) ||
136
+ !Object.hasOwn(authorization, 'decision')) {
137
+ throw new Error('Invalid authorization decision');
138
+ }
139
+ const decision = authorization.decision;
140
+ if (decision !== 'allow' && decision !== 'deny') {
141
+ throw new Error('Invalid authorization decision');
142
+ }
143
+ if (decision === 'deny') {
144
+ const reason = authorization.reason;
145
+ if (reason !== undefined && typeof reason !== 'string') {
146
+ throw new Error('Invalid authorization decision');
147
+ }
148
+ const message = reason ??
117
149
  `Capability not permitted: ${step.capability}`;
118
150
  step.status = 'failed';
119
151
  step.error = message;
@@ -122,7 +154,7 @@ class JobManager {
122
154
  stepId: step.id,
123
155
  capability: capability.name,
124
156
  risk: capability.risk,
125
- reason: authorization.reason,
157
+ reason,
126
158
  });
127
159
  throw new AuthorizationDeniedError(message);
128
160
  }
@@ -1,3 +1,4 @@
1
+ import type { CapabilityDescriptor } from './registry/capability.js';
1
2
  import { Job } from './jobs/job.js';
2
3
  import { JobListFilter } from './jobs/job-store.js';
3
4
  import { ExecutionCaller } from './execution/execution-context.js';
@@ -23,13 +24,8 @@ export declare class OperatorRuntime {
23
24
  run(goal: string, options?: RunJobOptions): Promise<Job>;
24
25
  getJob(id: string): Promise<Job | undefined>;
25
26
  listJobs(filter?: JobListFilter): Promise<Job[]>;
26
- listCapabilities(): {
27
- name: string;
28
- version: string;
29
- description: string;
30
- risk: import("./registry/capability.js").CapabilityRisk;
31
- inputSchema: Record<string, import("./registry/capability.js").CapabilityInputField>;
32
- }[];
27
+ listCapabilities(): CapabilityDescriptor[];
28
+ describeCapability(name: string, version?: string): CapabilityDescriptor | undefined;
33
29
  listPlanners(): {
34
30
  name: string;
35
31
  }[];
@@ -70,6 +70,9 @@ class OperatorRuntime {
70
70
  listCapabilities() {
71
71
  return registry_js_1.capabilityRegistry.list();
72
72
  }
73
+ describeCapability(name, version) {
74
+ return registry_js_1.capabilityRegistry.describe(name, version);
75
+ }
73
76
  listPlanners() {
74
77
  return planner_registry_js_1.plannerRegistry.list();
75
78
  }
@@ -13,3 +13,12 @@ export interface Capability<TInput = unknown, TResult = unknown> {
13
13
  inputSchema?: Record<string, CapabilityInputField>;
14
14
  execute(input: TInput, context?: ExecutionContext): Promise<TResult>;
15
15
  }
16
+ /** Detached execution metadata. Introspection is not authorization. */
17
+ export interface CapabilityDescriptor {
18
+ name: string;
19
+ version: string;
20
+ description: string;
21
+ risk: CapabilityRisk;
22
+ /** Limited Veil field contract, not full JSON Schema. */
23
+ inputSchema: Record<string, CapabilityInputField>;
24
+ }
@@ -1,15 +1,10 @@
1
- import { Capability } from './capability.js';
1
+ import { Capability, CapabilityDescriptor } from './capability.js';
2
2
  declare class CapabilityRegistry {
3
3
  private capabilities;
4
4
  register(capability: Capability): void;
5
5
  get(name: string): Capability | undefined;
6
- list(): {
7
- name: string;
8
- version: string;
9
- description: string;
10
- risk: import("./capability.js").CapabilityRisk;
11
- inputSchema: Record<string, import("./capability.js").CapabilityInputField>;
12
- }[];
6
+ describe(name: string, version?: string): CapabilityDescriptor | undefined;
7
+ list(): CapabilityDescriptor[];
13
8
  }
14
9
  export declare const capabilityRegistry: CapabilityRegistry;
15
10
  export {};
@@ -12,14 +12,29 @@ class CapabilityRegistry {
12
12
  get(name) {
13
13
  return this.capabilities.get(name);
14
14
  }
15
+ describe(name, version) {
16
+ const capability = this.get(name);
17
+ if (!capability || (version !== undefined && version !== capability.version)) {
18
+ return undefined;
19
+ }
20
+ return describeCapability(capability);
21
+ }
15
22
  list() {
16
- return Array.from(this.capabilities.values()).map((capability) => ({
17
- name: capability.name,
18
- version: capability.version,
19
- description: capability.description,
20
- risk: capability.risk,
21
- inputSchema: capability.inputSchema ?? {},
22
- }));
23
+ return Array.from(this.capabilities.values(), describeCapability);
23
24
  }
24
25
  }
25
26
  exports.capabilityRegistry = new CapabilityRegistry();
27
+ // Explicitly project passive metadata; never copy implementation properties.
28
+ function describeCapability(capability) {
29
+ return {
30
+ name: capability.name,
31
+ version: capability.version,
32
+ description: capability.description,
33
+ risk: capability.risk,
34
+ inputSchema: Object.fromEntries(Object.entries(capability.inputSchema ?? {}).map(([name, field]) => [name, {
35
+ type: field.type,
36
+ required: field.required,
37
+ description: field.description,
38
+ }])),
39
+ };
40
+ }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@veil-runtime/core",
3
- "version": "0.1.2",
3
+ "version": "0.2.0",
4
4
  "description": "A governed, capability-driven execution runtime",
5
5
  "license": "Apache-2.0",
6
6
  "repository": {
@@ -43,6 +43,8 @@
43
43
  "test": "tsc --project tsconfig.test.json && node --test .tmp/test-build/test/*.test.js",
44
44
  "verify:package": "npm run build && node tools/verify-package.mjs",
45
45
  "check": "npm run typecheck && npm test && npm run verify:package",
46
+ "quality": "node tools/quality.mjs",
47
+ "test:quality": "node --test tools/quality.test.mjs tools/quality-governance.test.mjs",
46
48
  "mcp:stdio": "tsx src/integrations/mcp/stdio-server.ts",
47
49
  "mcp:test": "tsx src/integrations/mcp/test-client.ts",
48
50
  "mcp:test:outbound": "tsx src/integrations/mcp/test-outbound.ts"
@@ -61,6 +63,7 @@
61
63
  "better-sqlite3": "^13.0.3"
62
64
  },
63
65
  "devDependencies": {
66
+ "@babel/parser": "8.0.5",
64
67
  "@types/better-sqlite3": "^9.6.0",
65
68
  "@types/node": "^26.2.0",
66
69
  "fastify": "^5.11.3",