-
-
Notifications
You must be signed in to change notification settings - Fork 0
Expand file tree
/
Copy pathContextCompiler.ts
More file actions
2926 lines (2717 loc) · 106 KB
/
Copy pathContextCompiler.ts
File metadata and controls
2926 lines (2717 loc) · 106 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
468
469
470
471
472
473
474
475
476
477
478
479
480
481
482
483
484
485
486
487
488
489
490
491
492
493
494
495
496
497
498
499
500
501
502
503
504
505
506
507
508
509
510
511
512
513
514
515
516
517
518
519
520
521
522
523
524
525
526
527
528
529
530
531
532
533
534
535
536
537
538
539
540
541
542
543
544
545
546
547
548
549
550
551
552
553
554
555
556
557
558
559
560
561
562
563
564
565
566
567
568
569
570
571
572
573
574
575
576
577
578
579
580
581
582
583
584
585
586
587
588
589
590
591
592
593
594
595
596
597
598
599
600
601
602
603
604
605
606
607
608
609
610
611
612
613
614
615
616
617
618
619
620
621
622
623
624
625
626
627
628
629
630
631
632
633
634
635
636
637
638
639
640
641
642
643
644
645
646
647
648
649
650
651
652
653
654
655
656
657
658
659
660
661
662
663
664
665
666
667
668
669
670
671
672
673
674
675
676
677
678
679
680
681
682
683
684
685
686
687
688
689
690
691
692
693
694
695
696
697
698
699
700
701
702
703
704
705
706
707
708
709
710
711
712
713
714
715
716
717
718
719
720
721
722
723
724
725
726
727
728
729
730
731
732
733
734
735
736
737
738
739
740
741
742
743
744
745
746
747
748
749
750
751
752
753
754
755
756
757
758
759
760
761
762
763
764
765
766
767
768
769
770
771
772
773
774
775
776
777
778
779
780
781
782
783
784
785
786
787
788
789
790
791
792
793
794
795
796
797
798
799
800
801
802
803
804
805
806
807
808
809
810
811
812
813
814
815
816
817
818
819
820
821
822
823
824
825
826
827
828
829
830
831
832
833
834
835
836
837
838
839
840
841
842
843
844
845
846
847
848
849
850
851
852
853
854
855
856
857
858
859
860
861
862
863
864
865
866
867
868
869
870
871
872
873
874
875
876
877
878
879
880
881
882
883
884
885
886
887
888
889
890
891
892
893
894
895
896
897
898
899
900
901
902
903
904
905
906
907
908
909
910
911
912
913
914
915
916
917
918
919
920
921
922
923
924
925
926
927
928
929
930
931
932
933
934
935
936
937
938
939
940
941
942
943
944
945
946
947
948
949
950
951
952
953
954
955
956
957
958
959
960
961
962
963
964
965
966
967
968
969
970
971
972
973
974
975
976
977
978
979
980
981
982
983
984
985
986
987
988
989
990
991
992
993
994
995
996
997
998
999
1000
/**
* ContextCompiler - Compile HoloScript context compositions to agent-surface formats
*
* Per "Context as a HoloScript Compile Target" memo (ai-ecosystem
* research/2026-05-06_context-as-compile-target.md, ratified 2026-05-06):
* every AI surface (Claude Code, Codex, Cursor, Copilot, Gemini, future)
* is a HoloScript compile target. Founder writes context once in `.hs`
* source; emitters produce CLAUDE.md / AGENTS.md / SKILL.md /
* .cursor/rules / system prompts / MCP configs from the same source.
*
* Architectural posture: BRIDGE compiler (W.GOLD.002 - emit-only,
* minimal). The vocabulary types below ARE the sovereign concept; the
* emitters are the bridges. Per W.GOLD.039 (Sapir-Whorf - the compiler
* as the limit of the possible), the trait vocabulary chosen here IS
* the universe of agent-context expressibility - choose primitives
* that map to founder-skill-grade rules, not to surface-specific knobs.
*
* Vocabulary v1 (ratified 2026-05-06):
*
* Top-level blocks (5):
* identity, authority_order, vision_pillar, output_shape, production_rule
*
* Per-rule traits (13):
* @refusal, @hard_dont, @default, @graduated_wisdom, @feedback,
* @escalation, @verify_token, @gap_rule, @citation_rule, @skill,
* @include, @routine, @hard_physical_gap
*
* Constraint enforcement (ratified): TIERED. BLOCK Diamond-invariant
* violations (vendor-as-substrate, refusal contradicting Diamond wisdom,
* banned-pattern defaults, hard-physical-gap claims, fake-Diamond
* declarations). WARN soft-guideline (stale citations, fluent prose
* without citation, schedule conflicts, unresolved verify-tokens).
*
* @version 1.7.0 (Phase 2(a) Iteration 3: vocabulary v3 complete.
* Adds @narrative_opening, @trigger_phrase, @prose_after, and
* section-header label alignment across all 4 emitters. Closes
* functional Losses 1-5 from docs/founder-skill-cutover-prep.md.
* Iteration 2 vocabulary v2 still valid; v3 is purely additive.)
*
* @version 1.5.0 (Phase 2(a) Iteration 2 G-3 vocabulary v2 now covers
* @invocation_mode, @date_discipline, @domain_preference,
* @embodied_projection, @editorial_default, @research_default, and
* @authority. Phase 1 emitters: claude_md + agents_md + cursor_rules +
* skill_md. Remaining Phase 1+ follow-ups: anthropic_system_prompt /
* brain_includes / mcp_context_loader.)
* @module @holoscript/core/compiler/ContextCompiler
*/
import { CompilerBase } from './CompilerBase';
import { ANSCapabilityPath, type ANSCapabilityPathValue } from '@holoscript/core-types/ans';
import type {
HoloComposition,
HoloObjectDecl,
HoloObjectTrait,
HoloValue,
} from '../parser/HoloCompositionTypes';
// =============================================================================
// VOCABULARY v1 - TYPED CONTEXT AST (the sovereign concept)
// =============================================================================
export type ContextSurface = 'claude' | 'codex' | 'cursor' | 'copilot' | 'gemini' | 'any';
/**
* Top-level block: who is this context for.
*
* `description` and `allowedTools` are optional fields used by the
* compile_to_skill_md emitter for the YAML frontmatter (`description:`
* and `allowed-tools:`) Claude Code's skill discovery reads. Other
* emitters (claude_md, agents_md, cursor_rules) ignore them. Setting
* them is required for self-hosting a Claude Code skill from a
* composition source (Phase 2(a) target).
*/
export interface ContextIdentity {
name: string;
role: string;
domain: string;
surface: ContextSurface;
noMonopoly: boolean;
description?: string; // skill_md frontmatter `description:`
allowedTools?: string[]; // skill_md frontmatter `allowed-tools:`
/**
* Vocabulary v3 (Iteration 3 first slice): the literal placeholder
* the surface substitutes with user invocation arguments. For Claude
* Code skills the canonical value is `$ARGUMENTS`; emitted as
* `**Command**: $ARGUMENTS` line right after the identity blockquote
* in skill_md output. Without this, `/founder [question]` style
* explicit invocation flows lose the `[question]` text — it's the
* functional gap that blocked Phase 2(a) cutover (per
* docs/founder-skill-cutover-prep.md Loss-1).
*/
commandTemplate?: string;
}
/** Top-level block: priority ordering of authority sources. */
export interface ContextAuthorityOrder {
tiers: string[];
}
/** Top-level block: load-bearing claim that shapes every decision. */
export interface ContextVisionPillar {
id: string;
claim: string;
citation?: string;
}
/** Top-level block: communication contract (silent-to-Joseph, etc.). */
export interface ContextOutputShape {
silentTo: string;
loudTo: string;
noMetaOutput: boolean;
surfaceHint: string;
}
/** Top-level block: environmental defaults (no dev, no mock, no localhost). */
export interface ContextProductionRule {
noDevNoMockNoLocalhost: boolean;
exception?: string;
}
/** Per-rule: stop-and-reframe pattern (Four Refusals). */
export interface ContextRefusal {
name: string;
when: string;
do: string;
doNot: string[];
reason?: string;
}
/** Per-rule: cross-provider red line. */
export interface ContextHardDont {
name: string;
reason: string;
alternative?: string;
appliesTo: string[];
}
/** Per-rule: known answer to a recurring question. */
export interface ContextDefault {
name: string;
when: string;
do: string;
reason?: string;
}
/** Per-rule: GOLD-tier wisdom reference. */
export interface ContextGraduatedWisdom {
id: string; // e.g. W.GOLD.001 or P.GOLD.007
claim: string;
tier: 'diamond' | 'platinum' | 'gold';
}
/** Per-rule: F.* feedback memory entry. */
export interface ContextFeedback {
id: string; // e.g. F.017 (feedback entry from MEMORY.md)
claim: string;
source?: string;
}
/** Per-rule: when to escalate to founder. */
export interface ContextEscalation {
trigger: string;
doAction: string;
recipient: string;
refuseToEscalateWhen: string[];
}
/** Per-rule: confidence-flagging convention. */
export interface ContextVerifyToken {
meaning: string;
example: string;
}
/** Per-rule: gap-build pattern (don't bandaid, don't descope). */
export interface ContextGapRule {
name: string;
when: string;
do: string[];
doNot: string[];
reason?: string;
}
/** Per-rule: when fluent prose needs citation. */
export interface ContextCitationRule {
fluentProseThresholdChars: number;
required: string[];
exemption?: string;
reason?: string;
}
/** Per-rule: skill registration (with output_protocol folded in per v1 ratification). */
export interface ContextSkill {
name: string;
invocableAs: string;
authority: string;
authoritativeFor: string[];
refusals?: string[]; // names of @refusal traits this skill enforces
outputProtocol?: {
invocation: string;
format: string;
surface: string;
};
}
/** Per-rule: cross-source composition. */
export interface ContextInclude {
source: string;
selector?: string;
}
/** Per-rule: A-00X recurring routine (added in v1 ratification). */
export interface ContextRoutine {
id: string; // A-001, A-019, etc.
schedule: string; // cron expression
skill: string; // /research, /scan, etc.
promptRef: string; // file path to prompt
sla: string;
outputDir?: string;
cleanExitScript?: string;
escalation?: Record<string, string[]>;
}
/**
* Per-rule: physical-presence boundary the skill never absorbs (added in v1
* ratification). Trezor signing, Quest 3 use, in-person meetings, paper
* signatures. Compiler refuses any @skill that claims `authoritativeFor`
* including one of these names - boundary enforced at compile time.
*/
export interface ContextHardPhysicalGap {
name: string;
reason: string;
appliesTo: string[];
alternative?: string;
}
/**
* Per-rule: rhetorical frame-setter that establishes the agent's posture
* before any rule applies. Vocabulary v3 (Phase 2(a) Iteration 3).
* Emits as a top-level prose block right after the identity blockquote,
* before the first ## section. Without this, agents may treat refusals
* and defaults as advisory rather than mandatory.
*/
export interface ContextNarrativeOpening {
posture: string;
reason?: string;
}
/**
* Per-rule: concrete trigger phrase that enriches the skill description.
* Vocabulary v3 (Phase 2(a) Iteration 3). Auto-fire reliability depends
* on these phrases being visible in the skill's discovery metadata.
*/
export interface ContextTriggerPhrase {
phrase: string;
context?: string;
}
/**
* Per-rule: prose paragraphs that emit AFTER a structured section.
* Vocabulary v3 (Phase 2(a) Iteration 3). Targets a canonical trait name
* (e.g. 'refusal', 'authority_order', 'date_discipline') and appends
* paragraphs after that section's structured rendering in all emitters.
*/
export interface ContextProseAfter {
trait: string;
paragraphs: string[];
}
/**
* Per-rule: a domain → execution-skill dispatch row. Vocabulary v4
* (2026-05-22). Captures the founder skill's "## Domain → execution skill
* dispatch" table — distinct from @domain_preference: this is the engine's
* delegate-to-skill map (legal/brand/capital/customer/governance/public),
* not the per-domain preference/ceiling notes. Closes a cutover parity gap
* (the live founder skill carried this section with no .hs primitive).
*/
export interface ContextDomainDispatch {
domain: string; // domain label (Legal / NDA / contract, etc.)
skills: string[]; // skills to delegate execution to
}
/**
* Per-rule: a corpus-mutability policy line. Vocabulary v4 (2026-05-22).
* Captures the founder skill's "## Corpus mutability" section — which corpus
* files are Track-B-mutable vs founder-ratification-required vs read-only.
* Closes a cutover parity gap (live founder skill carried this with no
* .hs primitive).
*/
export interface ContextCorpusMutability {
policy: string; // e.g. "Mutable via Track B", "Founder-ratification-required", "Read-only reference"
description: string; // what the policy covers
}
/**
* Per-rule: a domain → execution-skill dispatch row. Vocabulary v2
* (Phase 2(a) Iteration 2 G-3 third slice). Captures the founder skill's
* "## Domain preferences (beyond engineering)" dispatch table — each
* @domain_preference declares which existing skills handle questions
* scoped to a domain (legal, brand, capital, customer, governance,
* public-representation, etc.). Multiple per agent context (one per
* domain). The optional `ceiling` field captures spend or scope caps
* the founder skill enforces (e.g. "$5 standing spend cap" for capital).
*/
export interface ContextDomainPreference {
domain: string; // domain label (legal, brand, capital, etc.)
skills: string[]; // /skill-name dispatch targets
notes?: string; // optional context / disambiguation
ceiling?: string; // optional spend / scope ceiling for this domain
}
/**
* Per-rule: a date-surfacing refusal contract. Vocabulary v2 (Phase 2(a)
* Iteration 2 G-3 second slice). Captures `~/.claude/skills/founder/SKILL.md`
* § Date discipline (W.317): the Martinis-lesson rule that bare optimistic
* dates burn credibility, so any date surfaced for a milestone must carry
* named open blockers, matrix-row staleness signal, and engineering
* readiness color. Multiple date-discipline contracts per agent context
* are allowed (e.g. one for paper milestones, one for service deploys).
*/
export interface ContextDateDiscipline {
wisdomId: string; // "W.317" or similar
refusalContract: string; // one-line summary of the gate
requiredComponents: string[]; // ordered list (e.g. open_blockers, matrix_row_staleness, engineering_readiness)
shapeTemplate: string; // literal output template (multi-line OK)
reason?: string; // citation / context
crossReferences?: string[]; // related rules / paper-matrix columns
}
/**
* Per-rule: founder paper-program editorial default. Vocabulary v2
* (Phase 2(a) Iteration 2 G-3 fourth slice). Captures stable defaults
* from `~/.claude/skills/founder/SKILL.md` § Papers program that govern
* editor contact, byline changes, revision bundle release, GOLD citation
* verification, provenance drift fixes, and plugin-stub consumption.
* `paper_id` + `paper_phase` optionally narrow a default to one paper or
* phase; omitted values mean program-wide / all phases.
*/
export interface ContextEditorialDefault {
name: string;
paperId?: string;
paperPhase?: string;
when: string;
do: string;
reason?: string;
}
/**
* Per-rule: founder paper-program research default. Vocabulary v2
* (Phase 2(a) Iteration 2 G-3 fourth slice). Captures stable defaults
* for experiment design, ablation requirements, benchmark-claim
* verification, framing conflicts, validation sessions, and gap-build
* decisions across the 17-paper program.
*/
export interface ContextResearchDefault {
name: string;
paperId?: string;
paperPhase?: string;
when: string;
do: string;
reason?: string;
}
/**
* Per-rule: how this skill can be invoked. Vocabulary v2 (Phase 2(a)
* Iteration 2 G-3 first slice). The founder skill exposes 3 modes
* documented in `~/.claude/skills/founder/SKILL.md` § Invocation modes:
* - auto-fire (agent self-invokes when about to bandaid /
* workaround / demote / wait-for-founder)
* - explicit ("/founder [question]")
* - wrap-other-skill (embedded in another skill's flow)
*
* Other skills may declare different modes (e.g. only explicit, or
* only auto-fire); the trait is open-ended on `mode` to allow future
* skills to declare new modes without vocabulary changes — but the
* common cases stay in the union for documentation purposes.
*/
export type ContextInvocationModeKind = 'auto-fire' | 'explicit' | 'wrap-other-skill' | string;
export interface ContextInvocationMode {
mode: ContextInvocationModeKind;
when: string; // condition that triggers this mode
effect: string; // what the skill does in this mode
example?: string; // optional invocation example
// NOTE: source key is `effect:` (not `behavior:`) because `behavior` is
// a parser-reserved keyword in HoloCompositionParser. Rendered label
// in emitted markdown is "**Effect**:" for consistency. Same pattern
// as G-1's ContextEscalation.action -> doAction rename. Per W.GOLD.039
// (Sapir-Whorf), vocabulary should not adopt parser-reserved tokens.
}
/**
* Per-rule: how a back-office skill projects into an embodied review
* surface. Vocabulary v2 (Phase 2(a) Iteration 2 G-3 embodied slice).
* Captures the "embodied as projection layer" rule from NORTH_STAR §0.4:
* agent state is surfaced into Quest 3 / spatial / holographic bodies so
* the founder reviews decisive architecture-level state, not IDE-only
* chatter. Multiple projections are allowed because the same skill may
* support interactive Quest review and read-only spatial evidence.
*/
export type ContextEmbodiedProjectionSurface = 'quest-3' | 'spatial-photo' | 'hologram' | string;
export type ContextEmbodiedProjectionKind = 'read-only' | 'interactive' | string;
export interface ContextEmbodiedProjection {
surface: ContextEmbodiedProjectionSurface;
projectionKind: ContextEmbodiedProjectionKind;
trigger: string;
notes?: string;
}
/**
* Per-rule: Track-B self-edit + tier-write authority. Vocabulary v2
* (Phase 2(a) Iteration 2 G-3 authority slice). Captures the founder
* skill's "## Self-edit + tier-write authority (Track B)" mutation
* contract: which target can be mutated, what action type is logged,
* what every mutation requires, and whether a same-session founder
* ratification line is mandatory before committing the change.
*/
export interface ContextTrackBAuthority {
target: string;
actionType: string;
requires: string[];
founderRatificationRequired: boolean;
notes?: string;
}
/**
* Parsed context AST - sovereign vocabulary v1 in typed form. The
* compiler walks the HoloComposition AST, extracts known traits into
* this shape, validates per BLOCK rules, then dispatches to emitters.
*/
export interface ContextAST {
// Top-level blocks
identity?: ContextIdentity;
authorityOrder?: ContextAuthorityOrder;
visionPillars: ContextVisionPillar[];
outputShape?: ContextOutputShape;
productionRule?: ContextProductionRule;
// Per-rule traits
refusals: ContextRefusal[];
hardDonts: ContextHardDont[];
defaults: ContextDefault[];
graduatedWisdoms: ContextGraduatedWisdom[];
feedbacks: ContextFeedback[];
escalations: ContextEscalation[];
verifyTokens: ContextVerifyToken[];
gapRules: ContextGapRule[];
citationRules: ContextCitationRule[];
skills: ContextSkill[];
includes: ContextInclude[];
routines: ContextRoutine[];
hardPhysicalGaps: ContextHardPhysicalGap[];
invocationModes: ContextInvocationMode[]; // vocabulary v2 (Iteration 2 G-3 first slice)
dateDisciplines: ContextDateDiscipline[]; // vocabulary v2 (Iteration 2 G-3 second slice)
domainPreferences: ContextDomainPreference[]; // vocabulary v2 (Iteration 2 G-3 third slice)
embodiedProjections: ContextEmbodiedProjection[]; // vocabulary v2 (Iteration 2 G-3 embodied slice)
editorialDefaults: ContextEditorialDefault[]; // vocabulary v2 (Iteration 2 G-3 fourth slice)
researchDefaults: ContextResearchDefault[]; // vocabulary v2 (Iteration 2 G-3 fourth slice)
trackBAuthorities: ContextTrackBAuthority[]; // vocabulary v2 (Iteration 2 G-3 authority slice)
narrativeOpenings: ContextNarrativeOpening[]; // vocabulary v3 (Iteration 3)
triggerPhrases: ContextTriggerPhrase[]; // vocabulary v3 (Iteration 3)
proseAfters: ContextProseAfter[]; // vocabulary v3 (Iteration 3)
domainDispatches: ContextDomainDispatch[]; // vocabulary v4 (2026-05-22)
corpusMutabilities: ContextCorpusMutability[]; // vocabulary v4 (2026-05-22)
// Diagnostics surfaced from validation
warnings: ContextValidationDiagnostic[];
}
export interface ContextValidationDiagnostic {
severity: 'error' | 'warning';
rule: string;
message: string;
location?: string; // file:line if known
}
export type ContextEmitFormat =
| 'claude_md'
| 'agents_md'
| 'cursor_rules'
| 'skill_md'
| 'anthropic_system_prompt'
| 'brain_includes'
| 'mcp_context_loader';
export interface ContextCompileResult {
files: Record<string, string>; // emitted-format -> content
ast: ContextAST;
diagnostics: ContextValidationDiagnostic[];
}
export interface ContextCompilerOptions {
/** Which emit formats to produce. Defaults to ['claude_md']. */
formats?: ContextEmitFormat[];
}
// =============================================================================
// BANNED PATTERNS - Diamond-invariant BLOCK rules (ratified 2026-05-06)
// =============================================================================
/**
* Banned patterns a `@default` trait MUST NOT recommend. Source-of-truth
* per founder skill section Known founder defaults + multiple F.* feedback rules.
* Compiler BLOCKS at emit time.
*
* MIRRORED (manual sync): `~/.ai-ecosystem/scripts/skill-surface-lint.mjs` carries
* a copy of these regexes for its markdown-surface check. A direct import is
* infeasible — that linter lives in a separate repo with no @holoscript/core
* dependency, and a cross-repo import in a pre-commit hook would be brittle.
* When this array changes, update the linter's copy too (it cites this line).
*/
const BANNED_DEFAULT_PATTERNS: ReadonlyArray<{ pattern: RegExp; rule: string }> = [
{
pattern: /\bgit\s+add\s+(?:-A|--all|\.)(?=\s|$)/i,
rule: 'F.001/F.011 - git add -A leaked .env twice',
},
{
pattern: /:\s*any\b|\bas\s+any\b|<any>/i,
rule: 'global CLAUDE.md - no `any` in TypeScript, use `unknown`',
},
{
pattern: /\bregex\b.+\.(?:hs|hsplus|holo)\b/i,
rule: 'F.014 - no regex on .hs/.hsplus/.holo, use @holoscript/core',
},
{
pattern: /\bmock\s+(?:the\s+)?(?:db|database)\b/i,
rule: 'founder-default - real DB in tests, mock-vs-prod divergence',
},
];
/**
* Vendor-as-substrate phrases a `@hard_dont` MUST NOT silently endorse.
* If a hard_dont's `name` or `reason` indicates the vendor IS the
* substrate, that's a W.GOLD.002 violation - compiler BLOCKS.
*
* (The hard_dont SHOULD say "do NOT make vendor X our substrate" -
* that's correct. What we're catching is the inverse: a hard_dont
* authoring substrate-replacement as the desired state.)
*/
const VENDOR_AS_SUBSTRATE_PATTERNS: ReadonlyArray<{ pattern: RegExp; rule: string }> = [
{
pattern: /managed_agents_replaces_holomesh/i,
rule: 'W.GOLD.002 - vendor framework cannot replace HoloMesh',
},
{
pattern: /vector_store_as_source_of_truth/i,
rule: "docs/LLM_CAPABILITIES.md hard-don'ts - vendor stores never source-of-truth",
},
{
pattern: /api_keys_as_identity/i,
rule: 'W.GOLD.004 - wallets are identity, API keys are sessions',
},
];
/**
* Diamond-tier wisdom IDs that are FOUNDER-DECLARED-ONLY. A
* @graduated_wisdom claiming `tier: "diamond"` for any other ID
* (or with no ID at all) is a fake-Diamond declaration - BLOCK.
*
* Verified against D:/GOLD/INDEX.md at the time of the v1 ratification.
* If the vault grows new Diamond entries, this set must be updated
* (graduation is founder-only - Joseph or the farm pipeline).
*/
const KNOWN_DIAMOND_IDS: ReadonlySet<string> = new Set([
'W.GOLD.001', // Architecture beats alignment
'P.GOLD.001', // Failure knowledge decays slower than success knowledge
'W.GOLD.188', // Algebraic Trust (paired with W.GOLD.189)
'W.GOLD.189', // Algebraic Trust tri-layer (algebra + history + oracle)
// Add more as graduate.py promotes - verify against D:/GOLD/INDEX.md.
]);
/**
* Citation-rule fluent-prose threshold default (matches pre-commit
* F.017 hook in ai-ecosystem). Used when the source declares no
* @citation_rule of its own.
*/
const DEFAULT_FLUENT_PROSE_CHARS = 150;
// =============================================================================
// COMPILER
// =============================================================================
export class ContextCompiler extends CompilerBase {
protected readonly compilerName = 'ContextCompiler';
private options: Required<ContextCompilerOptions>;
constructor(options: ContextCompilerOptions = {}) {
super();
this.options = {
formats: options.formats ?? ['claude_md'],
};
}
protected override getRequiredCapability(): ANSCapabilityPathValue {
// Reuse the AGENT_INFERENCE capability - context compilation is in
// the same family as agent inference (both produce agent-surface
// artifacts). If a dedicated AGENT_CONTEXT capability is added
// later, swap here.
return ANSCapabilityPath.AGENT_INFERENCE;
}
/**
* Compile a HoloScript context composition to agent-surface formats.
*
* Phases:
* 1. extract - walk the HoloComposition AST, collect all v1 traits
* into the typed ContextAST shape
* 2. validate - apply BLOCK rules (Diamond-invariant violations) +
* WARN rules (soft guidelines). BLOCK rules throw; WARN rules
* accumulate in diagnostics.
* 3. emit - dispatch to per-format emitters. Phase 1 ships claude_md
* and agents_md. cursor_rules + skill_md + anthropic_system_prompt
* + brain_includes + mcp_context_loader are filed follow-ups.
*/
compile(
composition: HoloComposition,
agentToken: string,
outputPath?: string
): ContextCompileResult {
this.validateCompilerAccess(agentToken, outputPath);
// Phase 1: extract
const ast = this.extractContextAST(composition);
// Phase 2: validate (BLOCK rules throw, WARN rules accumulate)
this.validate(ast);
// Phase 3: emit
const files: Record<string, string> = {};
for (const format of this.options.formats) {
switch (format) {
case 'claude_md':
files['CLAUDE.md'] = this.emitClaudeMd(ast);
break;
case 'agents_md':
files['AGENTS.md'] = this.emitAgentsMd(ast);
break;
case 'cursor_rules': {
// One file per @refusal/@hard_dont/@default plus one index file
// for top-level blocks (identity, authority order, vision pillars,
// routines, skills registry, cross-references). Per spec:
// research/2026-05-06_cursor-mdc-spec.md.
const cursorFiles = this.emitCursorRules(ast);
for (const [path, content] of Object.entries(cursorFiles)) {
files[path] = content;
}
break;
}
case 'skill_md':
files['SKILL.md'] = this.emitSkillMd(ast);
break;
case 'anthropic_system_prompt':
case 'brain_includes':
case 'mcp_context_loader':
// Phase 1+ follow-ups - see filed board tasks.
throw new Error(
`Format "${format}" is a Phase 1+ follow-up; not yet emitted. ` +
`See ai-ecosystem research/2026-05-06_context-as-compile-target.md ` +
`section Recommended sequence for the rollout order.`
);
default: {
const exhaustive: never = format;
throw new Error(`Unknown emit format: ${String(exhaustive)}`);
}
}
}
return { files, ast, diagnostics: ast.warnings };
}
// --- Phase 1: extract -----------------------------------------------
private extractContextAST(composition: HoloComposition): ContextAST {
const ast: ContextAST = {
visionPillars: [],
refusals: [],
hardDonts: [],
defaults: [],
graduatedWisdoms: [],
feedbacks: [],
escalations: [],
verifyTokens: [],
gapRules: [],
citationRules: [],
skills: [],
includes: [],
routines: [],
hardPhysicalGaps: [],
invocationModes: [],
dateDisciplines: [],
domainPreferences: [],
embodiedProjections: [],
editorialDefaults: [],
researchDefaults: [],
trackBAuthorities: [],
narrativeOpenings: [],
triggerPhrases: [],
proseAfters: [],
domainDispatches: [],
corpusMutabilities: [],
warnings: [],
};
for (const trait of composition.traits ?? []) {
this.dispatchTrait(trait, ast);
}
for (const obj of composition.objects ?? []) {
this.extractFromObject(obj, ast);
}
return ast;
}
private extractFromObject(obj: HoloObjectDecl, ast: ContextAST): void {
const traits = obj.traits ?? [];
for (const trait of traits) {
this.dispatchTrait(trait, ast);
}
}
private dispatchTrait(trait: HoloObjectTrait, ast: ContextAST): void {
const cfg = trait.config;
switch (trait.name) {
case 'identity': {
const allowedToolsList = stringListField(cfg, 'allowed_tools');
ast.identity = {
name: stringField(cfg, 'name', ''),
role: stringField(cfg, 'role', ''),
domain: stringField(cfg, 'domain', ''),
surface: (stringField(cfg, 'surface', 'any') as ContextSurface) ?? 'any',
noMonopoly: boolField(cfg, 'no_monopoly', false),
description: stringFieldOrUndef(cfg, 'description'),
allowedTools: allowedToolsList.length > 0 ? allowedToolsList : undefined,
commandTemplate: stringFieldOrUndef(cfg, 'command_template'),
};
break;
}
case 'authority_order':
ast.authorityOrder = { tiers: stringListField(cfg, 'tiers') };
break;
case 'vision_pillar':
ast.visionPillars.push({
id: stringField(cfg, 'id', ''),
claim: stringField(cfg, 'claim', ''),
citation: stringFieldOrUndef(cfg, 'citation'),
});
break;
case 'output_shape':
ast.outputShape = {
silentTo: stringField(cfg, 'silent_to', ''),
loudTo: stringField(cfg, 'loud_to', ''),
noMetaOutput: boolField(cfg, 'no_meta_output', false),
surfaceHint: stringField(cfg, 'surface_hint', ''),
};
break;
case 'production_rule':
ast.productionRule = {
noDevNoMockNoLocalhost: boolField(cfg, 'no_dev_no_mock_no_localhost', false),
exception: stringFieldOrUndef(cfg, 'exception'),
};
break;
case 'refusal':
ast.refusals.push({
name: stringField(cfg, 'name', ''),
when: stringField(cfg, 'when', ''),
do: stringField(cfg, 'do', ''),
doNot: stringListField(cfg, 'do_not'),
reason: stringFieldOrUndef(cfg, 'reason'),
});
break;
case 'hard_dont':
ast.hardDonts.push({
name: stringField(cfg, 'name', ''),
reason: stringField(cfg, 'reason', ''),
alternative: stringFieldOrUndef(cfg, 'alternative'),
appliesTo: stringListField(cfg, 'applies_to'),
});
break;
case 'default':
ast.defaults.push({
name: stringField(cfg, 'name', ''),
when: stringField(cfg, 'when', ''),
do: stringField(cfg, 'do', ''),
reason: stringFieldOrUndef(cfg, 'reason'),
});
break;
case 'graduated_wisdom':
ast.graduatedWisdoms.push({
id: stringField(cfg, 'id', ''),
claim: stringField(cfg, 'claim', ''),
tier: stringField(cfg, 'tier', 'gold') as 'diamond' | 'platinum' | 'gold',
});
break;
case 'feedback':
ast.feedbacks.push({
id: stringField(cfg, 'id', ''),
claim: stringField(cfg, 'claim', ''),
source: stringFieldOrUndef(cfg, 'source'),
});
break;
case 'escalation':
ast.escalations.push({
trigger: stringField(cfg, 'trigger', ''),
doAction: stringField(cfg, 'do_action', ''),
recipient: stringField(cfg, 'recipient', ''),
refuseToEscalateWhen: stringListField(cfg, 'refuse_to_escalate_when'),
});
break;
case 'verify_token':
ast.verifyTokens.push({
meaning: stringField(cfg, 'meaning', ''),
example: stringField(cfg, 'example', ''),
});
break;
case 'gap_rule':
ast.gapRules.push({
name: stringField(cfg, 'name', ''),
when: stringField(cfg, 'when', ''),
do: stringListField(cfg, 'do'),
doNot: stringListField(cfg, 'do_not'),
reason: stringFieldOrUndef(cfg, 'reason'),
});
break;
case 'citation_rule':
ast.citationRules.push({
fluentProseThresholdChars: numberField(
cfg,
'fluent_prose_threshold_chars',
DEFAULT_FLUENT_PROSE_CHARS
),
required: stringListField(cfg, 'required'),
exemption: stringFieldOrUndef(cfg, 'exemption'),
reason: stringFieldOrUndef(cfg, 'reason'),
});
break;
case 'skill':
ast.skills.push({
name: stringField(cfg, 'name', ''),
invocableAs: stringField(cfg, 'invocable_as', ''),
authority: stringField(cfg, 'authority', ''),
authoritativeFor: stringListField(cfg, 'authoritative_for'),
refusals: stringListField(cfg, 'refusals'),
});
break;
case 'include':
ast.includes.push({
source: stringField(cfg, 'source', ''),
selector: stringFieldOrUndef(cfg, 'selector'),
});
break;
case 'routine':
ast.routines.push({
id: stringField(cfg, 'id', ''),
schedule: stringField(cfg, 'schedule', ''),
skill: stringField(cfg, 'skill', ''),
promptRef: stringField(cfg, 'prompt_ref', ''),
sla: stringField(cfg, 'sla', ''),
outputDir: stringFieldOrUndef(cfg, 'output_dir'),
cleanExitScript: stringFieldOrUndef(cfg, 'clean_exit_script'),
});
break;
case 'hard_physical_gap':
ast.hardPhysicalGaps.push({
name: stringField(cfg, 'name', ''),
reason: stringField(cfg, 'reason', ''),
appliesTo: stringListField(cfg, 'applies_to'),
alternative: stringFieldOrUndef(cfg, 'alternative'),
});
break;
case 'invocation_mode':
ast.invocationModes.push({
mode: stringField(cfg, 'mode', 'explicit'),
when: stringField(cfg, 'when', ''),
effect: stringField(cfg, 'effect', ''),
example: stringFieldOrUndef(cfg, 'example'),
});
break;
case 'date_discipline': {
const crossRefs = stringListField(cfg, 'cross_references');
ast.dateDisciplines.push({
wisdomId: stringField(cfg, 'wisdom_id', ''),
refusalContract: stringField(cfg, 'refusal_contract', ''),
requiredComponents: stringListField(cfg, 'required_components'),
shapeTemplate: stringField(cfg, 'shape_template', ''),
reason: stringFieldOrUndef(cfg, 'reason'),
crossReferences: crossRefs.length > 0 ? crossRefs : undefined,
});
break;
}
case 'domain_preference':
ast.domainPreferences.push({
domain: stringField(cfg, 'domain', ''),
skills: stringListField(cfg, 'skills'),
notes: stringFieldOrUndef(cfg, 'notes'),
ceiling: stringFieldOrUndef(cfg, 'ceiling'),
});
break;
case 'authority':
ast.trackBAuthorities.push({
target: stringField(cfg, 'target', ''),
actionType: stringField(cfg, 'action_type', ''),
requires: stringListField(cfg, 'requires'),
founderRatificationRequired: boolField(cfg, 'founder_ratification_required', false),
notes: stringFieldOrUndef(cfg, 'notes'),
});
break;
case 'embodied_projection':
ast.embodiedProjections.push({
surface: stringField(cfg, 'surface', ''),
projectionKind: stringField(cfg, 'projection_kind', 'read-only'),
trigger: stringField(cfg, 'trigger', ''),
notes: stringFieldOrUndef(cfg, 'notes'),
});
break;
case 'editorial_default':
ast.editorialDefaults.push({
name: stringField(cfg, 'name', ''),
paperId: stringFieldOrUndef(cfg, 'paper_id'),
paperPhase: stringFieldOrUndef(cfg, 'paper_phase'),
when: stringField(cfg, 'when', ''),
do: stringField(cfg, 'do', ''),
reason: stringFieldOrUndef(cfg, 'reason'),
});
break;
case 'research_default':
ast.researchDefaults.push({
name: stringField(cfg, 'name', ''),
paperId: stringFieldOrUndef(cfg, 'paper_id'),
paperPhase: stringFieldOrUndef(cfg, 'paper_phase'),
when: stringField(cfg, 'when', ''),
do: stringField(cfg, 'do', ''),
reason: stringFieldOrUndef(cfg, 'reason'),
});
break;
case 'narrative_opening':
ast.narrativeOpenings.push({
posture: stringField(cfg, 'posture', ''),
reason: stringFieldOrUndef(cfg, 'reason'),
});
break;
case 'trigger_phrase':
ast.triggerPhrases.push({
phrase: stringField(cfg, 'phrase', ''),
context: stringFieldOrUndef(cfg, 'context'),
});
break;
case 'prose_after':
ast.proseAfters.push({
trait: stringField(cfg, 'trait', ''),
paragraphs: stringListField(cfg, 'paragraphs'),
});
break;
case 'domain_dispatch':
ast.domainDispatches.push({
domain: stringField(cfg, 'domain', ''),
skills: stringListField(cfg, 'skills'),
});
break;
case 'corpus_mutability':
ast.corpusMutabilities.push({
policy: stringField(cfg, 'policy', ''),
description: stringField(cfg, 'description', ''),
});
break;
default:
// Unknown trait - record as warning, don't block (vocabulary
// may grow; unknown traits in source today might be valid in v2).
ast.warnings.push({
severity: 'warning',
rule: 'unknown-trait',
message: `Trait "${trait.name}" is not in vocabulary v1. Ignored. Add to vocabulary if load-bearing.`,
});
break;
}
}
// --- Phase 2: validate (BLOCK rules throw, WARN rules accumulate) --
private validate(ast: ContextAST): void {
// BLOCK: @default recommending banned patterns
for (const def of ast.defaults) {
for (const banned of BANNED_DEFAULT_PATTERNS) {
if (banned.pattern.test(def.do)) {
throw new ContextCompileError(
`@default "${def.name}" recommends a banned pattern (matches ${banned.pattern}). ` +
`Rule: ${banned.rule}.`
);
}
}
}
// BLOCK: @hard_dont with vendor-as-substrate framing
for (const dont of ast.hardDonts) {
const haystack = `${dont.name} ${dont.reason}`;
for (const vendorPat of VENDOR_AS_SUBSTRATE_PATTERNS) {
if (vendorPat.pattern.test(haystack)) {
throw new ContextCompileError(
`@hard_dont "${dont.name}" appears to author a vendor-as-substrate pattern. ` +