vigiles 15.2.1 → 15.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.
@@ -1,6 +1,9 @@
1
1
  /**
2
2
  * vigiles — Skill driver: the generator (durable-imperative) form of a skill.
3
3
  *
4
+ * PARKED (2026-08-16) — see the header of `src/core/compile-generator.ts`.
5
+ * Exported from no package subpath; absent from `docs/skills.md` on purpose.
6
+ *
4
7
  * The declarative `skill({ steps })` form compiles to a *static* SKILL.md — it
5
8
  * can't express branching/looping, because that control flow depends on runtime
6
9
  * values. The generator form does: a skill is a generator that `yield`s
@@ -2,6 +2,9 @@
2
2
  /**
3
3
  * vigiles — Skill driver: the generator (durable-imperative) form of a skill.
4
4
  *
5
+ * PARKED (2026-08-16) — see the header of `src/core/compile-generator.ts`.
6
+ * Exported from no package subpath; absent from `docs/skills.md` on purpose.
7
+ *
5
8
  * The declarative `skill({ steps })` form compiles to a *static* SKILL.md — it
6
9
  * can't express branching/looping, because that control flow depends on runtime
7
10
  * values. The generator form does: a skill is a generator that `yield`s
@@ -54,5 +54,5 @@ export declare function agent<const P extends AuthoredPurity | undefined = undef
54
54
  * against the Claude Code tool catalog. Identical to the core `skill()` at
55
55
  * runtime; the typed `tools` constraint is the only difference.
56
56
  */
57
- export declare function skill<const P extends AuthoredPurity | undefined = undefined>(spec: SkillSpecInput<P, ClaudeCodeToolVocabulary>): SkillSpec;
57
+ export declare function experimental_skill<const P extends AuthoredPurity | undefined = undefined>(spec: SkillSpecInput<P, ClaudeCodeToolVocabulary>): SkillSpec;
58
58
  //# sourceMappingURL=typed-spec.d.ts.map
@@ -1,7 +1,7 @@
1
1
  "use strict";
2
2
  Object.defineProperty(exports, "__esModule", { value: true });
3
3
  exports.agent = agent;
4
- exports.skill = skill;
4
+ exports.experimental_skill = experimental_skill;
5
5
  /**
6
6
  * Typed Claude Code authoring surface — the compile-time half of the purity
7
7
  * contract, bound to the Claude Code tool vocabulary.
@@ -49,7 +49,7 @@ function agent(spec) {
49
49
  * against the Claude Code tool catalog. Identical to the core `skill()` at
50
50
  * runtime; the typed `tools` constraint is the only difference.
51
51
  */
52
- function skill(spec) {
53
- return (0, spec_js_1.skill)(spec);
52
+ function experimental_skill(spec) {
53
+ return (0, spec_js_1.experimental_skill)(spec);
54
54
  }
55
55
  //# sourceMappingURL=typed-spec.js.map
@@ -9,7 +9,7 @@ export * from "./adapters/claude-code/plugin-loader.js";
9
9
  export * from "./mock-model.js";
10
10
  export { claudeCodeDriver, buildClaudeArgs, parseClaudeRun, claudeAvailable, } from "./harness-test.js";
11
11
  export * from "./adapters/claude-code/dialect.js";
12
- export { agent, skill, type ClaudeCodeToolVocabulary, } from "./adapters/claude-code/typed-spec.js";
12
+ export { agent, experimental_skill, type ClaudeCodeToolVocabulary, } from "./adapters/claude-code/typed-spec.js";
13
13
  export { measureSelectionMatrix, assertNoCollision, formatSelectionReport, } from "./scan-behavioral.js";
14
14
  export type { SelectionReport, SkillSelectionStat, SelectionOptions, SelectionMatrixOptions, } from "./scan-behavioral.js";
15
15
  export * from "./adapters/claude-code/layout.js";
@@ -14,7 +14,7 @@ var __exportStar = (this && this.__exportStar) || function(m, exports) {
14
14
  for (var p in m) if (p !== "default" && !Object.prototype.hasOwnProperty.call(exports, p)) __createBinding(exports, m, p);
15
15
  };
16
16
  Object.defineProperty(exports, "__esModule", { value: true });
17
- exports.formatSelectionReport = exports.assertNoCollision = exports.measureSelectionMatrix = exports.skill = exports.agent = exports.claudeAvailable = exports.parseClaudeRun = exports.buildClaudeArgs = exports.claudeCodeDriver = void 0;
17
+ exports.formatSelectionReport = exports.assertNoCollision = exports.measureSelectionMatrix = exports.experimental_skill = exports.agent = exports.claudeAvailable = exports.parseClaudeRun = exports.buildClaudeArgs = exports.claudeCodeDriver = void 0;
18
18
  /**
19
19
  * `vigiles/claude-code` — the Claude Code-specific harness pieces a *different*
20
20
  * harness would swap out: the plugin/repo loader (reads real Claude Code plugin
@@ -35,13 +35,19 @@ Object.defineProperty(exports, "buildClaudeArgs", { enumerable: true, get: funct
35
35
  Object.defineProperty(exports, "parseClaudeRun", { enumerable: true, get: function () { return harness_test_js_1.parseClaudeRun; } });
36
36
  Object.defineProperty(exports, "claudeAvailable", { enumerable: true, get: function () { return harness_test_js_1.claudeAvailable; } });
37
37
  __exportStar(require("./adapters/claude-code/dialect.js"), exports);
38
- // The typed Claude Code authoring surface: `agent` / `skill` with the `purity`
39
- // floor enforced AT COMPILE TIME against the CC tool catalog (a `tsc` error for
40
- // e.g. `purity: "pure"` + `"Bash"`). A strict addition to the runtime/compile
41
- // purity checks; the bare core `agent()`/`skill()` (`vigiles/spec`) stay open.
38
+ // The typed Claude Code authoring surface: `agent` / `experimental_skill` with
39
+ // the `purity` floor enforced AT COMPILE TIME against the CC tool catalog (a
40
+ // `tsc` error for e.g. `purity: "pure"` + `"Bash"`). A strict addition to the
41
+ // runtime/compile purity checks; the bare core `agent()`/`experimental_skill()`
42
+ // (`vigiles/spec`) stay open.
43
+ //
44
+ // NOTE the collision this rename also resolves: `vigiles/testing` exports a
45
+ // `skill()` too, and it is a DIFFERENT function — a `Check<Trace>` asking "did
46
+ // this skill fire?", taking an id string. One word, two concepts, told apart
47
+ // only by which door you imported from. Only the authoring builder is prefixed.
42
48
  var typed_spec_js_1 = require("./adapters/claude-code/typed-spec.js");
43
49
  Object.defineProperty(exports, "agent", { enumerable: true, get: function () { return typed_spec_js_1.agent; } });
44
- Object.defineProperty(exports, "skill", { enumerable: true, get: function () { return typed_spec_js_1.skill; } });
50
+ Object.defineProperty(exports, "experimental_skill", { enumerable: true, get: function () { return typed_spec_js_1.experimental_skill; } });
45
51
  // Selection-collision — a Claude-Code-ONLY behavioral measurement (Codex has no
46
52
  // skill-selection event to read), so it lives on this surface, not the agnostic
47
53
  // `vigiles/testing`. `measureSelectionMatrix` builds the N×N "which skill fired?"
@@ -80,7 +80,7 @@ export interface AdoptSurfaceResult {
80
80
  unmappedKeys: string[];
81
81
  }
82
82
  /**
83
- * Adopt an existing SKILL.md into a `skill()` spec. The body is carried verbatim
83
+ * Adopt an existing SKILL.md into an `experimental_skill()` spec. The body is carried verbatim
84
84
  * (skills are freeform markdown — `##` headings stay in the body), so a clean
85
85
  * skill round-trips below the integrity header.
86
86
  *
@@ -289,7 +289,7 @@ function unmappedNote(kind, keys) {
289
289
  const SURFACE_HEADER = (from) => `// Adopted from ${from} by \`vigiles init\` — body verbatim, standard\n` +
290
290
  `// frontmatter mapped; no rules inferred. Review the diff, then \`compile\`.\n`;
291
291
  /**
292
- * Adopt an existing SKILL.md into a `skill()` spec. The body is carried verbatim
292
+ * Adopt an existing SKILL.md into an `experimental_skill()` spec. The body is carried verbatim
293
293
  * (skills are freeform markdown — `##` headings stay in the body), so a clean
294
294
  * skill round-trips below the integrity header.
295
295
  *
@@ -325,7 +325,7 @@ function adoptSkill(markdown, dirName) {
325
325
  const trimmedBody = body.trim();
326
326
  if (trimmedBody)
327
327
  lines.push(` body: ${tsTemplate(trimmedBody)},`);
328
- const spec = (0, spec_js_1.skill)({
328
+ const spec = (0, spec_js_1.experimental_skill)({
329
329
  name,
330
330
  description,
331
331
  ...(argumentHint ? { argumentHint } : {}),
@@ -336,8 +336,8 @@ function adoptSkill(markdown, dirName) {
336
336
  });
337
337
  const source = SURFACE_HEADER(`${dirName}/SKILL.md`) +
338
338
  unmappedNote("skill", unmappedKeys) +
339
- `import { skill } from "vigiles/spec";\n\n` +
340
- `export default skill({\n${lines.join("\n")}\n});\n`;
339
+ `import { experimental_skill } from "vigiles/spec";\n\n` +
340
+ `export default experimental_skill({\n${lines.join("\n")}\n});\n`;
341
341
  return { source, kind: "skill", spec, unmappedKeys };
342
342
  }
343
343
  /**
@@ -1,6 +1,15 @@
1
1
  /**
2
2
  * vigiles — Generator → SKILL.md compiler.
3
3
  *
4
+ * PARKED (2026-08-16). Not part of the public API and not in `docs/skills.md`.
5
+ * It works — `vigiles compile` detects `genSkill(` and routes here (`cli.ts`),
6
+ * verified end-to-end — but `genSkill` / `act` / `checkpoint` / `finish` /
7
+ * `runSkill` are reachable from NO package subpath, so nobody outside this repo
8
+ * can author one. Parked rather than deleted because the code is sound and its
9
+ * tests pass; there is simply nothing to evaluate its usefulness against.
10
+ * Do not re-document it or give it an entry point without settling that first —
11
+ * see `docs/skills.md` §Status and the adoption-ladder work.
12
+ *
4
13
  * A generator skill (`function* () { … yield act/gate/result … }`) has dynamic
5
14
  * control flow, so it can't be rendered by *executing* it. Instead we parse its
6
15
  * SOURCE with the TypeScript compiler API and render the structure to markdown:
@@ -2,6 +2,15 @@
2
2
  /**
3
3
  * vigiles — Generator → SKILL.md compiler.
4
4
  *
5
+ * PARKED (2026-08-16). Not part of the public API and not in `docs/skills.md`.
6
+ * It works — `vigiles compile` detects `genSkill(` and routes here (`cli.ts`),
7
+ * verified end-to-end — but `genSkill` / `act` / `checkpoint` / `finish` /
8
+ * `runSkill` are reachable from NO package subpath, so nobody outside this repo
9
+ * can author one. Parked rather than deleted because the code is sound and its
10
+ * tests pass; there is simply nothing to evaluate its usefulness against.
11
+ * Do not re-document it or give it an entry point without settling that first —
12
+ * see `docs/skills.md` §Status and the adoption-ladder work.
13
+ *
5
14
  * A generator skill (`function* () { … yield act/gate/result … }`) has dynamic
6
15
  * control flow, so it can't be rendered by *executing* it. Instead we parse its
7
16
  * SOURCE with the TypeScript compiler API and render the structure to markdown:
@@ -281,10 +281,10 @@ export declare function instructions(strings: TemplateStringsArray, ...values: I
281
281
  * `<!-- vigiles:effect -->` markers. Independent of the `doc()` authoring
282
282
  * surface — it does not block on it.
283
283
  *
284
- * @internal Experimental (parked P3) — NOT part of the frozen public surface;
284
+ * @experimental Experimental (parked P3) — NOT part of the frozen public surface;
285
285
  * may change or be removed without a major bump pre-1.0.
286
286
  */
287
- export declare function effect(strings: TemplateStringsArray, ...values: InstructionFragment[]): EffectRegion;
287
+ export declare function experimental_effect(strings: TemplateStringsArray, ...values: InstructionFragment[]): EffectRegion;
288
288
  /**
289
289
  * The purity an author DECLARES for a skill/agent — the floor `compile`
290
290
  * enforces against the tool contract (see `purityViolations` in
@@ -493,14 +493,20 @@ export type SkillSpecInput<P extends AuthoredPurity | undefined, V extends ToolV
493
493
  * Define a SKILL.md specification.
494
494
  *
495
495
  * // skills/my-skill/SKILL.md.spec.ts
496
- * export default skill({ name: "my-skill", description: "...", body: "..." });
496
+ * export default experimental_skill({ name: "my-skill", description: "" });
497
497
  *
498
498
  * Generic over a tool `Vocabulary` (default `OpenToolVocabulary` — no
499
- * constraint), exactly like `agent()`: a vocabulary-bound `skill` (e.g.
500
- * `vigiles/claude-code`) makes `purity: "pure"` + a side-effecting tool a `tsc`
501
- * error; the bare core `skill()` accepts any tools, as before.
499
+ * constraint), exactly like `agent()`: a vocabulary-bound `experimental_skill`
500
+ * (e.g. `vigiles/claude-code`) makes `purity: "pure"` + a side-effecting tool a
501
+ * `tsc` error; the bare core one accepts any tools, as before.
502
+ *
503
+ * The name also disambiguates: `vigiles/testing` exports a `skill()` that is a
504
+ * DIFFERENT function — a `Check<Trace>` taking an id string, asking whether a
505
+ * skill fired. This one authors a skill; that one observes one.
506
+ *
507
+ * @experimental
502
508
  */
503
- export declare function skill<const P extends AuthoredPurity | undefined = undefined, V extends ToolVocabulary = OpenToolVocabulary>(spec: SkillSpecInput<P, V>): SkillSpec;
509
+ export declare function experimental_skill<const P extends AuthoredPurity | undefined = undefined, V extends ToolVocabulary = OpenToolVocabulary>(spec: SkillSpecInput<P, V>): SkillSpec;
504
510
  /**
505
511
  * A subagent definition (compiles to `agents/<name>.md`). Unlike a skill —
506
512
  * reference material the model reads on activation — a subagent is a *delegated
@@ -758,10 +764,10 @@ export type NeedsContract<N extends Shape> = N;
758
764
  *
759
765
  * needs({ plan: "string", files: "string[]" })
760
766
  *
761
- * @internal Experimental typed-composition surface — NOT part of the frozen
767
+ * @experimental Experimental typed-composition surface — NOT part of the frozen
762
768
  * public API (pre-1.0); may change without a major bump.
763
769
  */
764
- export declare function needs<const N extends Shape>(shape: N): NeedsContract<N>;
770
+ export declare function experimental_needs<const N extends Shape>(shape: N): NeedsContract<N>;
765
771
  /**
766
772
  * A typed pipeline step: a `TypedAgentSpec` paired with the input `needs` it
767
773
  * reads from the prior step's `ok`. `step()` builds one; `pipe` checks that the
@@ -782,10 +788,10 @@ export interface PipeStep<Needs extends Shape, Ok extends Shape, Err extends Sha
782
788
  *
783
789
  * pipeStep(implementer, needs({ plan: "string", files: "string[]" }))
784
790
  *
785
- * @internal Experimental typed-composition surface — NOT part of the frozen
791
+ * @experimental Experimental typed-composition surface — NOT part of the frozen
786
792
  * public API (pre-1.0); may change without a major bump.
787
793
  */
788
- export declare function pipeStep<Needs extends Shape, Ok extends Shape, Err extends Shape>(a: TypedAgentSpec<Ok, Err>, needsContract?: Needs): PipeStep<Needs, Ok, Err>;
794
+ export declare function experimental_pipeStep<Needs extends Shape, Ok extends Shape, Err extends Shape>(a: TypedAgentSpec<Ok, Err>, needsContract?: Needs): PipeStep<Needs, Ok, Err>;
789
795
  /**
790
796
  * True iff `Producer` provides EVERY field `Consumer` needs, with matching
791
797
  * field types. When satisfiable it is `true`; otherwise it collapses to a
@@ -844,10 +850,10 @@ export interface Pipeline<Ok extends Shape, Err extends Shape> {
844
850
  * its `needs` must be empty (`needs({})` or omitted). Returns a `Pipeline`
845
851
  * carrying that step's `ok`/`err` forward.
846
852
  *
847
- * @internal Experimental typed-composition surface — NOT part of the frozen
853
+ * @experimental Experimental typed-composition surface — NOT part of the frozen
848
854
  * public API (pre-1.0); may change without a major bump.
849
855
  */
850
- export declare function start<Ok extends Shape, Err extends Shape>(first: PipeStep<Record<string, never>, Ok, Err> | TypedAgentSpec<Ok, Err>): Pipeline<Ok, Err>;
856
+ export declare function experimental_start<Ok extends Shape, Err extends Shape>(first: PipeStep<Record<string, never>, Ok, Err> | TypedAgentSpec<Ok, Err>): Pipeline<Ok, Err>;
851
857
  /**
852
858
  * Append a step to a typed pipeline. The handoff is CHECKED: the constraint
853
859
  * `Supplies<PriorOk, Needs>` must be `true`, else the `next` parameter's type
@@ -859,10 +865,10 @@ export declare function start<Ok extends Shape, Err extends Shape>(first: PipeSt
859
865
  * exporting a function called `then` becomes a thenable, so `await import()` of
860
866
  * any barrel re-exporting it would invoke it — a footgun the rename avoids.
861
867
  *
862
- * @internal Experimental typed-composition surface — NOT part of the frozen
868
+ * @experimental Experimental typed-composition surface — NOT part of the frozen
863
869
  * public API (pre-1.0); may change without a major bump.
864
870
  */
865
- export declare function andThen<PriorOk extends Shape, PriorErr extends Shape, Needs extends Shape, Ok extends Shape, Err extends Shape>(prior: Pipeline<PriorOk, PriorErr>, next: Supplies<PriorOk, Needs> extends true ? PipeStep<Needs, Ok, Err> : {
871
+ export declare function experimental_andThen<PriorOk extends Shape, PriorErr extends Shape, Needs extends Shape, Ok extends Shape, Err extends Shape>(prior: Pipeline<PriorOk, PriorErr>, next: Supplies<PriorOk, Needs> extends true ? PipeStep<Needs, Ok, Err> : {
866
872
  readonly __HANDOFF_ERROR: Supplies<PriorOk, Needs>;
867
873
  }): Pipeline<Ok, PriorErr | Err>;
868
874
  /**
@@ -882,19 +888,19 @@ export declare function andThen<PriorOk extends Shape, PriorErr extends Shape, N
882
888
  * pipeStep(reviewer, needs({ diff: "string" })),
883
889
  * ) // ← won't compile if a handoff doesn't line up
884
890
  *
885
- * @internal Experimental typed-composition surface — NOT part of the frozen
891
+ * @experimental Experimental typed-composition surface — NOT part of the frozen
886
892
  * public API (pre-1.0); may change without a major bump.
887
893
  */
888
- export declare function pipe<A extends Shape, AE extends Shape>(a: TypedAgentSpec<A, AE>): Pipeline<A, AE>;
889
- export declare function pipe<A extends Shape, AE extends Shape, BN extends Shape, B extends Shape, BE extends Shape>(a: TypedAgentSpec<A, AE>, b: Supplies<A, BN> extends true ? PipeStep<BN, B, BE> : {
894
+ export declare function experimental_pipe<A extends Shape, AE extends Shape>(a: TypedAgentSpec<A, AE>): Pipeline<A, AE>;
895
+ export declare function experimental_pipe<A extends Shape, AE extends Shape, BN extends Shape, B extends Shape, BE extends Shape>(a: TypedAgentSpec<A, AE>, b: Supplies<A, BN> extends true ? PipeStep<BN, B, BE> : {
890
896
  readonly __HANDOFF_ERROR: Supplies<A, BN>;
891
897
  }): Pipeline<B, AE | BE>;
892
- export declare function pipe<A extends Shape, AE extends Shape, BN extends Shape, B extends Shape, BE extends Shape, CN extends Shape, C extends Shape, CE extends Shape>(a: TypedAgentSpec<A, AE>, b: Supplies<A, BN> extends true ? PipeStep<BN, B, BE> : {
898
+ export declare function experimental_pipe<A extends Shape, AE extends Shape, BN extends Shape, B extends Shape, BE extends Shape, CN extends Shape, C extends Shape, CE extends Shape>(a: TypedAgentSpec<A, AE>, b: Supplies<A, BN> extends true ? PipeStep<BN, B, BE> : {
893
899
  readonly __HANDOFF_ERROR: Supplies<A, BN>;
894
900
  }, c: Supplies<B, CN> extends true ? PipeStep<CN, C, CE> : {
895
901
  readonly __HANDOFF_ERROR: Supplies<B, CN>;
896
902
  }): Pipeline<C, AE | BE | CE>;
897
- export declare function pipe<A extends Shape, AE extends Shape, BN extends Shape, B extends Shape, BE extends Shape, CN extends Shape, C extends Shape, CE extends Shape, DN extends Shape, D extends Shape, DE extends Shape>(a: TypedAgentSpec<A, AE>, b: Supplies<A, BN> extends true ? PipeStep<BN, B, BE> : {
903
+ export declare function experimental_pipe<A extends Shape, AE extends Shape, BN extends Shape, B extends Shape, BE extends Shape, CN extends Shape, C extends Shape, CE extends Shape, DN extends Shape, D extends Shape, DE extends Shape>(a: TypedAgentSpec<A, AE>, b: Supplies<A, BN> extends true ? PipeStep<BN, B, BE> : {
898
904
  readonly __HANDOFF_ERROR: Supplies<A, BN>;
899
905
  }, c: Supplies<B, CN> extends true ? PipeStep<CN, C, CE> : {
900
906
  readonly __HANDOFF_ERROR: Supplies<B, CN>;
package/dist/core/spec.js CHANGED
@@ -21,21 +21,21 @@ exports.ref = ref;
21
21
  exports.dir = dir;
22
22
  exports.glob = glob;
23
23
  exports.instructions = instructions;
24
- exports.effect = effect;
24
+ exports.experimental_effect = experimental_effect;
25
25
  exports.claude = claude;
26
26
  exports.project = project;
27
27
  exports.input = input;
28
28
  exports.step = step;
29
- exports.skill = skill;
29
+ exports.experimental_skill = experimental_skill;
30
30
  exports.agent = agent;
31
31
  exports.result = result;
32
32
  exports.delegate = delegate;
33
33
  exports.railway = railway;
34
- exports.needs = needs;
35
- exports.pipeStep = pipeStep;
36
- exports.start = start;
37
- exports.andThen = andThen;
38
- exports.pipe = pipe;
34
+ exports.experimental_needs = experimental_needs;
35
+ exports.experimental_pipeStep = experimental_pipeStep;
36
+ exports.experimental_start = experimental_start;
37
+ exports.experimental_andThen = experimental_andThen;
38
+ exports.experimental_pipe = experimental_pipe;
39
39
  exports.defineConfig = defineConfig;
40
40
  // ---------------------------------------------------------------------------
41
41
  // Template literal types for type-safe linter references
@@ -192,10 +192,10 @@ function instructions(strings, ...values) {
192
192
  * `<!-- vigiles:effect -->` markers. Independent of the `doc()` authoring
193
193
  * surface — it does not block on it.
194
194
  *
195
- * @internal Experimental (parked P3) — NOT part of the frozen public surface;
195
+ * @experimental Experimental (parked P3) — NOT part of the frozen public surface;
196
196
  * may change or be removed without a major bump pre-1.0.
197
197
  */
198
- function effect(strings, ...values) {
198
+ function experimental_effect(strings, ...values) {
199
199
  const body = [];
200
200
  for (let i = 0; i < strings.length; i++) {
201
201
  if (strings[i])
@@ -234,14 +234,20 @@ function step(instr, opts = {}) {
234
234
  * Define a SKILL.md specification.
235
235
  *
236
236
  * // skills/my-skill/SKILL.md.spec.ts
237
- * export default skill({ name: "my-skill", description: "...", body: "..." });
237
+ * export default experimental_skill({ name: "my-skill", description: "" });
238
238
  *
239
239
  * Generic over a tool `Vocabulary` (default `OpenToolVocabulary` — no
240
- * constraint), exactly like `agent()`: a vocabulary-bound `skill` (e.g.
241
- * `vigiles/claude-code`) makes `purity: "pure"` + a side-effecting tool a `tsc`
242
- * error; the bare core `skill()` accepts any tools, as before.
240
+ * constraint), exactly like `agent()`: a vocabulary-bound `experimental_skill`
241
+ * (e.g. `vigiles/claude-code`) makes `purity: "pure"` + a side-effecting tool a
242
+ * `tsc` error; the bare core one accepts any tools, as before.
243
+ *
244
+ * The name also disambiguates: `vigiles/testing` exports a `skill()` that is a
245
+ * DIFFERENT function — a `Check<Trace>` taking an id string, asking whether a
246
+ * skill fired. This one authors a skill; that one observes one.
247
+ *
248
+ * @experimental
243
249
  */
244
- function skill(spec) {
250
+ function experimental_skill(spec) {
245
251
  return { _specType: "skill", ...spec };
246
252
  }
247
253
  /**
@@ -333,10 +339,10 @@ function railway(spec) {
333
339
  *
334
340
  * needs({ plan: "string", files: "string[]" })
335
341
  *
336
- * @internal Experimental typed-composition surface — NOT part of the frozen
342
+ * @experimental Experimental typed-composition surface — NOT part of the frozen
337
343
  * public API (pre-1.0); may change without a major bump.
338
344
  */
339
- function needs(shape) {
345
+ function experimental_needs(shape) {
340
346
  return shape;
341
347
  }
342
348
  /**
@@ -346,10 +352,10 @@ function needs(shape) {
346
352
  *
347
353
  * pipeStep(implementer, needs({ plan: "string", files: "string[]" }))
348
354
  *
349
- * @internal Experimental typed-composition surface — NOT part of the frozen
355
+ * @experimental Experimental typed-composition surface — NOT part of the frozen
350
356
  * public API (pre-1.0); may change without a major bump.
351
357
  */
352
- function pipeStep(a, needsContract = {}) {
358
+ function experimental_pipeStep(a, needsContract = {}) {
353
359
  return { _step: "typed-delegate", agent: a, needs: needsContract };
354
360
  }
355
361
  /**
@@ -357,11 +363,13 @@ function pipeStep(a, needsContract = {}) {
357
363
  * its `needs` must be empty (`needs({})` or omitted). Returns a `Pipeline`
358
364
  * carrying that step's `ok`/`err` forward.
359
365
  *
360
- * @internal Experimental typed-composition surface — NOT part of the frozen
366
+ * @experimental Experimental typed-composition surface — NOT part of the frozen
361
367
  * public API (pre-1.0); may change without a major bump.
362
368
  */
363
- function start(first) {
364
- const step = "_step" in first ? first : pipeStep(first, {});
369
+ function experimental_start(first) {
370
+ const step = "_step" in first
371
+ ? first
372
+ : experimental_pipeStep(first, {});
365
373
  const out = step.agent.output;
366
374
  return {
367
375
  _specType: "pipeline",
@@ -385,10 +393,10 @@ function start(first) {
385
393
  * exporting a function called `then` becomes a thenable, so `await import()` of
386
394
  * any barrel re-exporting it would invoke it — a footgun the rename avoids.
387
395
  *
388
- * @internal Experimental typed-composition surface — NOT part of the frozen
396
+ * @experimental Experimental typed-composition surface — NOT part of the frozen
389
397
  * public API (pre-1.0); may change without a major bump.
390
398
  */
391
- function andThen(prior, next) {
399
+ function experimental_andThen(prior, next) {
392
400
  const real = next;
393
401
  const out = real.agent.output;
394
402
  const rw = railway({
@@ -403,12 +411,12 @@ function andThen(prior, next) {
403
411
  railway: rw,
404
412
  };
405
413
  }
406
- function pipe(first, ...rest) {
414
+ function experimental_pipe(first, ...rest) {
407
415
  // The overloads above enforce each handoff at the type level; the runtime body
408
416
  // is the same left fold of start/andThen, untyped (the checks already happened).
409
- let pipeline = start(first);
417
+ let pipeline = experimental_start(first);
410
418
  for (const s of rest) {
411
- pipeline = andThen(pipeline, s);
419
+ pipeline = experimental_andThen(pipeline, s);
412
420
  }
413
421
  return pipeline;
414
422
  }
package/dist/e2e.d.ts CHANGED
@@ -10,7 +10,9 @@
10
10
  * four tiers). Prefer `vigiles/integration`.
11
11
  *
12
12
  * NOT here: **evals** (`runEval` / `measure` / `measureTriggerRate` / `judge`) —
13
- * those are non-deterministic measurement (`vigiles/eval`), a different axis.
13
+ * those are non-deterministic measurement, a different axis. (They live on
14
+ * `vigiles/testing`; `vigiles/eval` is named here in the original comment and does
15
+ * not exist as an entry point.)
14
16
  */
15
17
  export * from "./integration.js";
16
18
  //# sourceMappingURL=e2e.d.ts.map
package/dist/e2e.js CHANGED
@@ -26,7 +26,9 @@ Object.defineProperty(exports, "__esModule", { value: true });
26
26
  * four tiers). Prefer `vigiles/integration`.
27
27
  *
28
28
  * NOT here: **evals** (`runEval` / `measure` / `measureTriggerRate` / `judge`) —
29
- * those are non-deterministic measurement (`vigiles/eval`), a different axis.
29
+ * those are non-deterministic measurement, a different axis. (They live on
30
+ * `vigiles/testing`; `vigiles/eval` is named here in the original comment and does
31
+ * not exist as an entry point.)
30
32
  */
31
33
  __exportStar(require("./integration.js"), exports);
32
34
  //# sourceMappingURL=e2e.js.map
@@ -71,6 +71,23 @@ function fieldSchema(type) {
71
71
  return { type: "boolean" };
72
72
  case "string[]":
73
73
  return { type: "array", items: { type: "string" } };
74
+ default:
75
+ // 🔴 Unreachable from TypeScript, reachable from JavaScript — and the one
76
+ // shipped example of this API (examples/experimental-emit/run-emit.mjs) is
77
+ // .mjs, so this is the path a real author takes.
78
+ //
79
+ // Without this arm the switch fell through to `undefined`, and every later
80
+ // step read that as a field: `"actions" in properties` is TRUE for an
81
+ // undefined value, so nothing noticed; `JSON.stringify` then DROPPED the
82
+ // key while `required` kept it and `additionalProperties: false` forbade
83
+ // it. The served schema demanded a property it also banned — unsatisfiable,
84
+ // silent, and contradicted by `.instruction`, which still asked the model
85
+ // to send it. Throwing here makes the contradiction impossible to construct
86
+ // instead of merely unlikely.
87
+ throw new TypeError(`experimental_emitTool: unsupported field type ${JSON.stringify(type)}. ` +
88
+ `Supported: "string", "number", "boolean", "string[]". ` +
89
+ `Nested objects and enums are outside this surface's ceiling — flatten the field, ` +
90
+ `or use the fenced fork rail if the shape cannot be flattened.`);
74
91
  }
75
92
  }
76
93
  function trackSchema(shape) {
@@ -29,6 +29,6 @@
29
29
  * @module vigiles/experimental
30
30
  */
31
31
  export { experimental_startServices, experimental_withServices, type ServiceSpec, type ServiceReady, type ServiceReset, type ServiceHandle, type ServiceSession, type ContainerRuntime, } from "./services.js";
32
- export { experimental_dockerRuntime, makeDockerRuntime, type DockerExec, type NetProbe, } from "./services-docker.js";
32
+ export { experimental_dockerRuntime, experimental_makeDockerRuntime, type DockerExec, type NetProbe, } from "./services-docker.js";
33
33
  export { experimental_emitTool, experimental_parseEmitted, experimental_assertEmittedOk, type EmitFieldSchema, type EmitObjectSchema, type EmitPropertySchema, type EmitTrackSchema, type EmitToolDefinition, type ExperimentalEmitTool, } from "./experimental-emit.js";
34
34
  //# sourceMappingURL=experimental.d.ts.map
@@ -1,6 +1,6 @@
1
1
  "use strict";
2
2
  Object.defineProperty(exports, "__esModule", { value: true });
3
- exports.experimental_assertEmittedOk = exports.experimental_parseEmitted = exports.experimental_emitTool = exports.makeDockerRuntime = exports.experimental_dockerRuntime = exports.experimental_withServices = exports.experimental_startServices = void 0;
3
+ exports.experimental_assertEmittedOk = exports.experimental_parseEmitted = exports.experimental_emitTool = exports.experimental_makeDockerRuntime = exports.experimental_dockerRuntime = exports.experimental_withServices = exports.experimental_startServices = void 0;
4
4
  /**
5
5
  * `vigiles/experimental` — ⚠️ EXPERIMENTAL, UNSTABLE public surface.
6
6
  *
@@ -36,7 +36,7 @@ Object.defineProperty(exports, "experimental_startServices", { enumerable: true,
36
36
  Object.defineProperty(exports, "experimental_withServices", { enumerable: true, get: function () { return services_js_1.experimental_withServices; } });
37
37
  var services_docker_js_1 = require("./services-docker.js");
38
38
  Object.defineProperty(exports, "experimental_dockerRuntime", { enumerable: true, get: function () { return services_docker_js_1.experimental_dockerRuntime; } });
39
- Object.defineProperty(exports, "makeDockerRuntime", { enumerable: true, get: function () { return services_docker_js_1.makeDockerRuntime; } });
39
+ Object.defineProperty(exports, "experimental_makeDockerRuntime", { enumerable: true, get: function () { return services_docker_js_1.experimental_makeDockerRuntime; } });
40
40
  var experimental_emit_js_1 = require("./experimental-emit.js");
41
41
  Object.defineProperty(exports, "experimental_emitTool", { enumerable: true, get: function () { return experimental_emit_js_1.experimental_emitTool; } });
42
42
  Object.defineProperty(exports, "experimental_parseEmitted", { enumerable: true, get: function () { return experimental_emit_js_1.experimental_parseEmitted; } });
@@ -309,7 +309,7 @@ interface MatcherOutput {
309
309
  * Custom matchers compatible with both vitest and jest. Register once:
310
310
  *
311
311
  * import { expect } from "vitest"; // or "@jest/globals"
312
- * import { vigilesMatchers } from "vigiles/harness-assert";
312
+ * import { vigilesMatchers } from "vigiles/testing";
313
313
  * expect.extend(vigilesMatchers);
314
314
  *
315
315
  * expect(result).toHaveCreated("RESULT");
@@ -69,7 +69,8 @@ const agent_result_js_1 = require("./adapters/claude-code/agent-result.js");
69
69
  const stats_js_1 = require("./stats.js");
70
70
  const eval_baseline_js_1 = require("./eval-baseline.js");
71
71
  // Re-export the significance primitives so the whole eval-analysis surface lives
72
- // behind `vigiles/harness-assert` (no separate entry point).
72
+ // re-exported from `vigiles/testing` (there is no `vigiles/harness-assert` entry
73
+ // point — it was advertised in this very comment and never existed).
73
74
  var stats_js_2 = require("./stats.js");
74
75
  Object.defineProperty(exports, "compareArms", { enumerable: true, get: function () { return stats_js_2.compareArms; } });
75
76
  var eval_baseline_js_2 = require("./eval-baseline.js");
@@ -689,7 +690,7 @@ function assertTriggerRate(report, opts) {
689
690
  * Custom matchers compatible with both vitest and jest. Register once:
690
691
  *
691
692
  * import { expect } from "vitest"; // or "@jest/globals"
692
- * import { vigilesMatchers } from "vigiles/harness-assert";
693
+ * import { vigilesMatchers } from "vigiles/testing";
693
694
  * expect.extend(vigilesMatchers);
694
695
  *
695
696
  * expect(result).toHaveCreated("RESULT");
@@ -34,7 +34,7 @@ export declare function parseDockerPort(output: string): number | undefined;
34
34
  *
35
35
  * @experimental
36
36
  */
37
- export declare function makeDockerRuntime(deps?: {
37
+ export declare function experimental_makeDockerRuntime(deps?: {
38
38
  exec?: DockerExec;
39
39
  netProbe?: NetProbe;
40
40
  sleep?: (ms: number) => Promise<void>;
@@ -6,7 +6,7 @@ exports.dockerRunArgs = dockerRunArgs;
6
6
  exports.dockerExecArgs = dockerExecArgs;
7
7
  exports.publishedPorts = publishedPorts;
8
8
  exports.parseDockerPort = parseDockerPort;
9
- exports.makeDockerRuntime = makeDockerRuntime;
9
+ exports.experimental_makeDockerRuntime = experimental_makeDockerRuntime;
10
10
  /**
11
11
  * vigiles — a Docker-backed {@link ContainerRuntime} for the R3 disposable-service
12
12
  * tier (⚠️ EXPERIMENTAL / UNSTABLE — see src/services.ts and `vigiles/experimental`).
@@ -166,7 +166,7 @@ function numericNow() {
166
166
  *
167
167
  * @experimental
168
168
  */
169
- function makeDockerRuntime(deps = {}) {
169
+ function experimental_makeDockerRuntime(deps = {}) {
170
170
  const exec = deps.exec ?? realDockerExec;
171
171
  const netProbe = deps.netProbe ?? realNetProbe;
172
172
  const sleep = deps.sleep ?? delay;
@@ -230,5 +230,5 @@ const containerNames = new WeakMap();
230
230
  *
231
231
  * @experimental
232
232
  */
233
- exports.experimental_dockerRuntime = makeDockerRuntime();
233
+ exports.experimental_dockerRuntime = experimental_makeDockerRuntime();
234
234
  //# sourceMappingURL=services-docker.js.map
@@ -1,6 +1,11 @@
1
1
  /**
2
2
  * vigiles — Skill testing: deterministic tests for a skill's action sequence.
3
3
  *
4
+ * PARKED (2026-08-16) — this drives the generator form, so it is parked with it;
5
+ * see the header of `src/core/compile-generator.ts`. `runSkill` is reachable
6
+ * from no package subpath. `scriptModel` is NOT parked: it is public from
7
+ * `vigiles/claude-code` and serves the harness testing API independently.
8
+ *
4
9
  * A thin wrapper over the generator driver (`driveSkill`) for use inside an
5
10
  * ordinary `node:test` / Vitest `test()` — no custom runner, no DSL. You script
6
11
  * the *model* (the non-deterministic part) and assert the deterministic spine:
@@ -2,6 +2,11 @@
2
2
  /**
3
3
  * vigiles — Skill testing: deterministic tests for a skill's action sequence.
4
4
  *
5
+ * PARKED (2026-08-16) — this drives the generator form, so it is parked with it;
6
+ * see the header of `src/core/compile-generator.ts`. `runSkill` is reachable
7
+ * from no package subpath. `scriptModel` is NOT parked: it is public from
8
+ * `vigiles/claude-code` and serves the harness testing API independently.
9
+ *
5
10
  * A thin wrapper over the generator driver (`driveSkill`) for use inside an
6
11
  * ordinary `node:test` / Vitest `test()` — no custom runner, no DSL. You script
7
12
  * the *model* (the non-deterministic part) and assert the deterministic spine:
package/dist/testing.d.ts CHANGED
@@ -3,7 +3,14 @@
3
3
  * the three tiers — `runHook` (unit), `runHarnessTest` (deterministic), `runEval`
4
4
  * (eval) — plus the runner-agnostic predicates/assertions. Kept deliberately
5
5
  * separate from `vigiles/claude-code` so this surface can stay harness-agnostic as
6
- * more harnesses are added. Granular paths (`vigiles/run-hook`, etc.) still work.
6
+ * more harnesses are added.
7
+ *
8
+ * 🔴 THIS LINE USED TO SAY the granular paths (`vigiles/run-hook`, etc.) «still
9
+ * work». MEASURED 2026-08-16: they do not. `vigiles/run-hook`, `vigiles/eval`,
10
+ * `vigiles/harness-test`, `vigiles/harness-assert`, `vigiles/skill` and
11
+ * `vigiles/skill-test` all raise ERR_PACKAGE_PATH_NOT_EXPORTED — six paths this
12
+ * package advertised to its own readers and does not serve. A promise that an
13
+ * import keeps working is exactly the kind a reader has no reason to re-check.
7
14
  *
8
15
  * It re-exports the composition-root runner modules (which do the Claude-Code
9
16
  * default-wiring), never an adapter directly — the `agnostic-surface` eslint
package/dist/testing.js CHANGED
@@ -4,7 +4,14 @@
4
4
  * the three tiers — `runHook` (unit), `runHarnessTest` (deterministic), `runEval`
5
5
  * (eval) — plus the runner-agnostic predicates/assertions. Kept deliberately
6
6
  * separate from `vigiles/claude-code` so this surface can stay harness-agnostic as
7
- * more harnesses are added. Granular paths (`vigiles/run-hook`, etc.) still work.
7
+ * more harnesses are added.
8
+ *
9
+ * 🔴 THIS LINE USED TO SAY the granular paths (`vigiles/run-hook`, etc.) «still
10
+ * work». MEASURED 2026-08-16: they do not. `vigiles/run-hook`, `vigiles/eval`,
11
+ * `vigiles/harness-test`, `vigiles/harness-assert`, `vigiles/skill` and
12
+ * `vigiles/skill-test` all raise ERR_PACKAGE_PATH_NOT_EXPORTED — six paths this
13
+ * package advertised to its own readers and does not serve. A promise that an
14
+ * import keeps working is exactly the kind a reader has no reason to re-check.
8
15
  *
9
16
  * It re-exports the composition-root runner modules (which do the Claude-Code
10
17
  * default-wiring), never an adapter directly — the `agnostic-surface` eslint
package/dist/unit.d.ts CHANGED
@@ -1,8 +1,23 @@
1
1
  /**
2
2
  * `vigiles/unit` — the **no-capability** harness-testing surface.
3
3
  *
4
- * Importing from here is a contract: this test needs **no `claude`, no model, no
5
- * bubblewrap, no network** — only a process. It is the cheap base of the pyramid:
4
+ * Importing from here is MOSTLY a contract: this test needs no `claude`, no
5
+ * bubblewrap and no network — only a process. It is the cheap base of the pyramid:
6
+ *
7
+ * 🔴 «NO MODEL» IS NOT TRUE TODAY, AND SAYING SO WAS THE WORST OF THE FOUR
8
+ * MISSTATEMENTS ON THIS SURFACE, because it reads as a guarantee rather than a
9
+ * description. `judged` is re-exported here and its default judge is a REAL model
10
+ * call — `check.ts` resolves `opts.judge ?? ((o) => runJudge(o))`. So a test that
11
+ * imports only from this barrel can still spend money, and the one line a reader
12
+ * would rely on to know it cannot is this one.
13
+ *
14
+ * The honest fix is to MOVE `judged` off this barrel, not to reword the sentence —
15
+ * but that changes the public surface, and the surface is being reorganised
16
+ * separately (the measured proposal splits by COST: everything free on one path,
17
+ * everything that spends money on another, where this defect becomes unexpressible
18
+ * rather than merely documented). Until that lands, the claim is corrected here
19
+ * rather than left standing.
20
+ *
6
21
  * `runHook` (pipe a synthesized event to a hook and read the block/allow
7
22
  * decision), the bare `Trace` predicates, the `assert*` helpers, and the pure
8
23
  * parsers. A `*.test.ts` should import **only** from here (enforced by lint).
package/dist/unit.js CHANGED
@@ -18,8 +18,23 @@ exports.formatGuardrailReport = exports.assertBlocksDisasters = exports.unblocke
18
18
  /**
19
19
  * `vigiles/unit` — the **no-capability** harness-testing surface.
20
20
  *
21
- * Importing from here is a contract: this test needs **no `claude`, no model, no
22
- * bubblewrap, no network** — only a process. It is the cheap base of the pyramid:
21
+ * Importing from here is MOSTLY a contract: this test needs no `claude`, no
22
+ * bubblewrap and no network — only a process. It is the cheap base of the pyramid:
23
+ *
24
+ * 🔴 «NO MODEL» IS NOT TRUE TODAY, AND SAYING SO WAS THE WORST OF THE FOUR
25
+ * MISSTATEMENTS ON THIS SURFACE, because it reads as a guarantee rather than a
26
+ * description. `judged` is re-exported here and its default judge is a REAL model
27
+ * call — `check.ts` resolves `opts.judge ?? ((o) => runJudge(o))`. So a test that
28
+ * imports only from this barrel can still spend money, and the one line a reader
29
+ * would rely on to know it cannot is this one.
30
+ *
31
+ * The honest fix is to MOVE `judged` off this barrel, not to reword the sentence —
32
+ * but that changes the public surface, and the surface is being reorganised
33
+ * separately (the measured proposal splits by COST: everything free on one path,
34
+ * everything that spends money on another, where this defect becomes unexpressible
35
+ * rather than merely documented). Until that lands, the claim is corrected here
36
+ * rather than left standing.
37
+ *
23
38
  * `runHook` (pipe a synthesized event to a hook and read the block/allow
24
39
  * decision), the bare `Trace` predicates, the `assert*` helpers, and the pure
25
40
  * parsers. A `*.test.ts` should import **only** from here (enforced by lint).
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "vigiles",
3
- "version": "15.2.1",
3
+ "version": "15.4.0",
4
4
  "description": "Audit, test and measure the harness your AI agent runs on — grade your CLAUDE.md / AGENTS.md, skills, subagents and hooks, run them against a scripted model, and measure whether they actually fire.",
5
5
  "keywords": [
6
6
  "claude-code",
@@ -92,6 +92,8 @@
92
92
  "test:types": "npm run build && tsc --noEmit -p test/types/tsconfig.json",
93
93
  "api:report": "npm run build && node scripts/api-extractor.mjs --local",
94
94
  "api:check": "npm run build && node scripts/api-extractor.mjs",
95
+ "docs:check": "npm run build && node scripts/check-doc-imports.mjs . docs README.md",
96
+ "experimental:check": "npm run api:check && node scripts/check-experimental-naming.mjs",
95
97
  "docs:api": "typedoc"
96
98
  },
97
99
  "devDependencies": {