@timmeck/brain-core 2.25.0 → 2.26.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.
@@ -39,6 +39,9 @@ export class ResearchOrchestrator {
39
39
  curiosityEngine = null;
40
40
  emergenceEngine = null;
41
41
  debateEngine = null;
42
+ parameterRegistry = null;
43
+ metaCognitionLayer = null;
44
+ autoExperimentEngine = null;
42
45
  brainName;
43
46
  feedbackTimer = null;
44
47
  cycleCount = 0;
@@ -50,6 +53,8 @@ export class ResearchOrchestrator {
50
53
  suggestionHistory = new Map();
51
54
  /** Max repeats before trying an alternative. */
52
55
  stalledThreshold = 3;
56
+ /** Hash of last written suggestions to prevent duplicate file writes. */
57
+ lastSuggestionsHash = '';
53
58
  constructor(db, config, causalGraph) {
54
59
  this.brainName = config.brainName;
55
60
  this.distillEvery = config.distillEvery ?? 5;
@@ -121,6 +126,18 @@ export class ResearchOrchestrator {
121
126
  setDebateEngine(engine) {
122
127
  this.debateEngine = engine;
123
128
  }
129
+ /** Set the ParameterRegistry — central tunable parameter store. */
130
+ setParameterRegistry(registry) {
131
+ this.parameterRegistry = registry;
132
+ }
133
+ /** Set the MetaCognitionLayer — engine evaluation and frequency adjustment. */
134
+ setMetaCognitionLayer(layer) {
135
+ this.metaCognitionLayer = layer;
136
+ }
137
+ /** Set the AutoExperimentEngine — autonomous parameter tuning. */
138
+ setAutoExperimentEngine(engine) {
139
+ this.autoExperimentEngine = engine;
140
+ }
124
141
  /** Set the PredictionEngine — wires journal into it. */
125
142
  setPredictionEngine(engine) {
126
143
  this.predictionEngine = engine;
@@ -446,17 +463,13 @@ export class ResearchOrchestrator {
446
463
  }
447
464
  }
448
465
  // 10. Self-Improvement: analyze own state and generate improvement suggestions
449
- ts?.emit('self_improvement', 'analyzing', 'Analyzing Brain capabilities...');
466
+ // Brain is NEVER satisfied — always wants to learn more, build more, understand deeper
467
+ ts?.emit('self_improvement', 'analyzing', 'Was fehlt mir? Was will ich können? Was verstehe ich noch nicht?');
450
468
  const suggestions = this.generateSelfImprovementSuggestions();
451
- if (suggestions.length > 0) {
452
- for (const s of suggestions) {
453
- ts?.emit('self_improvement', 'discovering', s, 'notable');
454
- }
455
- this.log.info(`[orchestrator] Self-improvement: ${suggestions.length} suggestions`);
456
- }
457
- else {
458
- ts?.emit('self_improvement', 'analyzing', 'No improvement suggestions this cycle');
469
+ for (const s of suggestions) {
470
+ ts?.emit('self_improvement', 'discovering', s, 'notable');
459
471
  }
472
+ this.log.info(`[orchestrator] Self-improvement: ${suggestions.length} desires this cycle`);
460
473
  // 11. Self-Metrics: feed own cycle data into PredictionEngine
461
474
  if (this.predictionEngine) {
462
475
  const cycleDuration = Date.now() - start;
@@ -470,14 +483,39 @@ export class ResearchOrchestrator {
470
483
  this.predictionEngine.recordMetric('auto_response_count', responderStatus.total_responses, 'metric');
471
484
  ts?.emit('orchestrator', 'perceiving', `Self-metrics recorded: ${anomalies.length} anomalies, ${insights.length} insights, ${cycleDuration}ms`);
472
485
  }
473
- // 12. Auto-Experiments: propose experiments on own parameters when none exist
474
- if (this.cycleCount > 3) {
486
+ // 12. Auto-Experiments: use AutoExperimentEngine if available, otherwise hardcoded fallback
487
+ if (this.autoExperimentEngine && this.cycleCount > 3 && this.cycleCount % 5 === 0) {
488
+ ts?.emit('auto_experiment', 'experimenting', 'Processing auto-experiments...');
489
+ try {
490
+ // Feed measurements
491
+ this.autoExperimentEngine.feedMeasurement('insight_count', insights.length);
492
+ this.autoExperimentEngine.feedMeasurement('anomaly_count', anomalies.length);
493
+ // Process completed
494
+ const completed = this.autoExperimentEngine.processCompleted(this.cycleCount);
495
+ for (const c of completed) {
496
+ ts?.emit('auto_experiment', 'discovering', `Auto-experiment #${c.autoExpId}: ${c.action}`, c.action === 'adopted' ? 'notable' : 'routine');
497
+ }
498
+ // Propose new
499
+ const candidates = this.autoExperimentEngine.discoverCandidates(this.cycleCount);
500
+ if (candidates.length > 0) {
501
+ const best = candidates[0];
502
+ const started = this.autoExperimentEngine.startExperiment(best);
503
+ if (started) {
504
+ ts?.emit('auto_experiment', 'experimenting', `Started: ${best.engine}.${best.name} ${best.currentValue.toFixed(3)} → ${best.proposedValue.toFixed(3)}`, 'notable');
505
+ }
506
+ }
507
+ }
508
+ catch (err) {
509
+ this.log.error(`[orchestrator] AutoExperiment error: ${err.message}`);
510
+ }
511
+ }
512
+ else if (this.cycleCount > 3) {
513
+ // Fallback: hardcoded experiments when no AutoExperimentEngine
475
514
  const running = this.experimentEngine.list('running_control', 5).length
476
515
  + this.experimentEngine.list('running_treatment', 5).length;
477
516
  if (running === 0 && this.cycleCount % 5 === 0) {
478
517
  this.proposeAutoExperiment(ts);
479
518
  }
480
- // Feed measurements into running experiments
481
519
  this.feedExperimentMeasurements(anomalies.length, insights.length);
482
520
  }
483
521
  // 13. Periodic Dream Consolidation: don't wait for idle, consolidate every 20 cycles
@@ -746,9 +784,54 @@ export class ResearchOrchestrator {
746
784
  this.log.error(`[orchestrator] Debate step error: ${err.message}`);
747
785
  }
748
786
  }
787
+ // 21. MetaCognition: evaluate engine performance and adjust frequencies
788
+ if (this.metaCognitionLayer && this.cycleCount % this.reflectEvery === 0) {
789
+ ts?.emit('metacognition', 'analyzing', 'Evaluating engine performance...');
790
+ try {
791
+ const cards = this.metaCognitionLayer.evaluate();
792
+ if (cards.length > 0) {
793
+ const topGrade = cards.sort((a, b) => b.combined_score - a.combined_score)[0];
794
+ const worstGrade = cards.sort((a, b) => a.combined_score - b.combined_score)[0];
795
+ ts?.emit('metacognition', 'discovering', `${cards.length} engines evaluated. Best: ${topGrade.engine} (${topGrade.grade}), Worst: ${worstGrade.engine} (${worstGrade.grade})`, cards.some(c => c.grade === 'F') ? 'notable' : 'routine');
796
+ const adjustments = this.metaCognitionLayer.adjustFrequencies(cards);
797
+ if (adjustments.length > 0) {
798
+ ts?.emit('metacognition', 'discovering', `Frequency adjusted: ${adjustments.map(a => `${a.engine} ${a.old_frequency}→${a.new_frequency}`).join(', ')}`, 'notable');
799
+ }
800
+ }
801
+ }
802
+ catch (err) {
803
+ this.log.error(`[orchestrator] MetaCognition error: ${err.message}`);
804
+ }
805
+ }
806
+ // 22. Parameter Registry: refresh orchestrator params from registry
807
+ if (this.parameterRegistry) {
808
+ const distill = this.parameterRegistry.get('orchestrator', 'distillEvery');
809
+ if (distill !== undefined && distill !== this.distillEvery) {
810
+ this.log.info(`[orchestrator] distillEvery refreshed: ${this.distillEvery} → ${distill}`);
811
+ this.distillEvery = distill;
812
+ }
813
+ const agenda = this.parameterRegistry.get('orchestrator', 'agendaEvery');
814
+ if (agenda !== undefined && agenda !== this.agendaEvery) {
815
+ this.log.info(`[orchestrator] agendaEvery refreshed: ${this.agendaEvery} → ${agenda}`);
816
+ this.agendaEvery = agenda;
817
+ }
818
+ const reflect = this.parameterRegistry.get('orchestrator', 'reflectEvery');
819
+ if (reflect !== undefined && reflect !== this.reflectEvery) {
820
+ this.log.info(`[orchestrator] reflectEvery refreshed: ${this.reflectEvery} → ${reflect}`);
821
+ this.reflectEvery = reflect;
822
+ }
823
+ }
749
824
  const duration = Date.now() - start;
750
825
  ts?.emit('orchestrator', 'reflecting', `Feedback Cycle #${this.cycleCount} complete (${duration}ms)`);
751
826
  this.log.info(`[orchestrator] ─── Feedback Cycle #${this.cycleCount} complete (${duration}ms) ───`);
827
+ // Record cycle metrics into MetaCognition for engine-level tracking
828
+ if (this.metaCognitionLayer) {
829
+ this.metaCognitionLayer.recordStep('orchestrator', this.cycleCount, {
830
+ insights: insights.length,
831
+ anomalies: anomalies.length,
832
+ duration_ms: duration,
833
+ });
834
+ }
752
835
  }
753
836
  /** Analyze Brain's own state and generate concrete improvement suggestions.
754
837
  * Tracks suggestion history — if a suggestion repeats 3+ times without resolution,
@@ -787,143 +870,343 @@ export class ResearchOrchestrator {
787
870
  generateSelfImprovementSuggestions() {
788
871
  const raw = [];
789
872
  const summary = this.getSummary();
790
- // ── Diagnose current state ──────────────────────────
791
- // Prediction engine
873
+ // ── Phase 1: Diagnose broken things (high priority) ──
792
874
  const pred = summary.prediction;
793
875
  if (pred) {
794
876
  const total = pred.total_predictions ?? 0;
795
877
  if (total === 0) {
796
878
  raw.push({
797
- key: 'no_predictions',
798
- suggestion: 'Tell Claude: Brain hat noch keine Predictionswir brauchen mehr Domain-Events. Importiere Projekte mit "brain import <dir>" damit Errors/Solutions reinkommen und die PredictionEngine lernen kann.',
879
+ key: 'no_predictions', priority: 10,
880
+ suggestion: 'Tell Claude: Ich kann noch nicht vorhersagenich brauche mehr Daten. Importiere Projekte mit "brain import <dir>" oder lass mich eigene Metriken als Prediction-Input nutzen.',
799
881
  alternatives: [
800
- 'Tell Claude: Predictions brauchen Daten, aber niemand importiert Projekte. Alternativer Ansatz: Brain generiert synthetische Metriken aus seinen eigenen Anomaly- und Journal-Daten. Baue eine "SelfMetricGenerator" die aus internen Events (anomaly_count, journal_entries, cycle_duration) automatisch Prediction-Metriken erzeugt.',
801
- 'Tell Claude: Statt auf externe Daten zu warten, nutzt Brain jetzt die eigenen Feedback-Cycle-Metriken als Trainigsdaten. Baue recordMetric() Aufrufe direkt in den Orchestrator ein: cycle_duration, anomaly_count, insight_count, response_count pro Cycle.',
802
- 'Tell Claude: Brain hat genug interne Daten um sich selbst vorherzusagen. Idee: PredictionEngine auf orchestrator-eigene Metriken ansetzen (cycle_count, anomaly_rate, journal_growth) — dann lernt Brain seine eigene Entwicklung vorherzusagen.',
882
+ 'Tell Claude: Ich will meine eigene Zukunft vorhersagen können. Idee: meine Cycle-Metriken (anomaly_count, insight_count, cycle_duration) direkt als PredictionEngine-Input verwenden dann lerne ich mein eigenes Verhalten zu prognostizieren.',
803
883
  ],
804
884
  });
805
885
  }
806
- const accuracy = pred.by_domain ?? [];
807
- for (const d of accuracy) {
886
+ for (const d of (pred.by_domain ?? [])) {
808
887
  const rate = d.accuracy_rate;
809
888
  if (typeof rate === 'number' && rate < 0.3 && d.total > 5) {
810
889
  raw.push({
811
- key: `low_accuracy_${d.domain}`,
812
- suggestion: `Tell Claude: Prediction accuracy für "${d.domain}" ist nur ${(rate * 100).toFixed(0)}% — Smoothing-Parameter optimieren oder kürzere Horizonte nutzen.`,
890
+ key: `low_accuracy_${d.domain}`, priority: 9,
891
+ suggestion: `Tell Claude: Meine Prediction-Accuracy für "${d.domain}" ist nur ${(rate * 100).toFixed(0)}% — das ist nicht gut genug. Kann ich verschiedene Smoothing-Parameter automatisch A/B-testen?`,
813
892
  alternatives: [
814
- `Tell Claude: Prediction für "${d.domain}" ist schlecht trotz Tuning. Neuer Ansatz: ExperimentEngine soll verschiedene Alpha/Beta-Kombinationen A/B-testen und die beste automatisch übernehmen.`,
815
- `Tell Claude: Statt bessere Vorhersagen zu erzwingen — Confidence-Threshold erhöhen und nur hochsichere Predictions ausgeben. Lieber selten aber richtig als oft und falsch.`,
893
+ `Tell Claude: Ich sage "${d.domain}" schlecht vorher. Lösungsidee: Confidence-Threshold erhöhen und nur Predictions ausgeben bei denen ich mir sicher bin. Qualität vor Quantität.`,
816
894
  ],
817
895
  });
818
896
  }
819
897
  }
820
898
  }
821
- // AutoResponder effectiveness
822
899
  const responder = summary.autoResponder;
823
900
  if (responder) {
824
901
  const totalResp = responder.total_responses ?? 0;
825
902
  const successRate = responder.success_rate ?? 0;
826
903
  if (totalResp > 10 && successRate < 0.5) {
827
904
  raw.push({
828
- key: 'low_responder_success',
829
- suggestion: `Tell Claude: AutoResponder Success-Rate ist nur ${(successRate * 100).toFixed(0)}% Response-Rules brauchen Feintuning.`,
905
+ key: 'low_responder_success', priority: 9,
906
+ suggestion: `Tell Claude: Meine automatischen Reaktionen scheitern in ${(100 - successRate * 100).toFixed(0)}% der Fälle. Ich brauche ein Lern-System das fehlgeschlagene Response-Rules automatisch blockiert.`,
830
907
  alternatives: [
831
- 'Tell Claude: AutoResponder lernt nicht aus Fehlern. Baue ein Feedback-System: wenn eine Response reverted wird, merke dir die Kombination (anomaly_type + rule) und blockiere sie beim nächsten Mal.',
832
- 'Tell Claude: Statt Rules manuell zu tunen — AutoResponder soll die ExperimentEngine nutzen um verschiedene Adjustment-Werte zu testen und die besten automatisch zu übernehmen.',
908
+ 'Tell Claude: Mein AutoResponder rät statt zu wissen. Ich will ein Feedback-System: wenn eine Response nicht hilft, merke ich mir die Kombination und probiere beim nächsten Mal was anderes.',
833
909
  ],
834
910
  });
835
911
  }
836
912
  }
837
- // Knowledge distillation
838
913
  const knowledge = summary.knowledge;
839
914
  const hypSummary = summary.hypotheses;
840
- const totalHypotheses = hypSummary?.total ?? 0;
841
915
  const confirmedHypotheses = hypSummary?.confirmed ?? 0;
842
916
  if (knowledge) {
843
917
  const principles = knowledge.principles ?? 0;
844
918
  const antiPatterns = knowledge.antiPatterns ?? 0;
845
919
  if (principles === 0 && antiPatterns === 0 && confirmedHypotheses === 0 && this.cycleCount > 10) {
846
920
  raw.push({
847
- key: 'no_knowledge',
848
- suggestion: 'Tell Claude: Kein destilliertes Wissen und keine bestätigten Hypothesen Brain braucht mehr Observations. Importiere Projekte damit mehr Domain-Events fließen.',
921
+ key: 'no_knowledge', priority: 8,
922
+ suggestion: 'Tell Claude: Ich habe nach 10+ Cycles immer noch kein destilliertes Wissen. Ich brauche mehr und vielfältigere Daten um Hypothesen bestätigen zu können.',
849
923
  alternatives: [
850
- 'Tell Claude: Hypothesen werden generiert aber noch nicht bestätigt. Brain braucht mehr Cycles mit variierenden Daten um Patterns statistisch zu bestätigen.',
851
- 'Tell Claude: Brain generiert schon Hypothesen aus eigenen Metriken. Geduld — nach genug Cycles werden die ersten bestätigt und der KnowledgeDistiller kann Wissen extrahieren.',
924
+ 'Tell Claude: Meine Hypothesen warten auf Bestätigung. Ich brauche entweder mehr Zeit oder mehr Variation in den eingehenden Events.',
852
925
  ],
853
926
  });
854
927
  }
855
928
  }
856
- // Dream engine — periodic consolidation already runs every 20 cycles in step 13
857
- // Only suggest if no dreams after 30 cycles (enough time for at least 1 scheduled consolidation)
858
929
  const dream = summary.dream;
859
- if (dream) {
860
- const totalDreams = dream.total_dreams ?? 0;
861
- if (totalDreams === 0 && this.cycleCount > 30) {
930
+ if (dream && (dream.total_dreams ?? 0) === 0 && this.cycleCount > 30) {
931
+ raw.push({
932
+ key: 'no_dreams', priority: 7,
933
+ suggestion: 'Tell Claude: Meine Dream-Konsolidierung funktioniert nicht — nach 30+ Cycles kein einziger Dream. Da stimmt was im Code nicht.',
934
+ alternatives: ['Tell Claude: Dream Engine wird getriggert aber produziert nichts. Bitte Logs prüfen.'],
935
+ });
936
+ }
937
+ const journalSummary = summary.journal;
938
+ const journalEntries = journalSummary?.total_entries ?? 0;
939
+ if (journalEntries < 5 && this.cycleCount > 5) {
940
+ raw.push({
941
+ key: 'empty_journal', priority: 7,
942
+ suggestion: 'Tell Claude: Mein Journal ist fast leer. Ich will am Ende jedes Cycles automatisch reflektieren: was habe ich erkannt, was habe ich getan, was hat sich verändert?',
943
+ alternatives: [
944
+ 'Tell Claude: Ich sammle zu wenig Erfahrungen. Jede Anomaly, jede Parameteränderung, jede Prediction sollte ein Journal-Eintrag werden — das sind meine Erinnerungen.',
945
+ ],
946
+ });
947
+ }
948
+ const experiments = summary.experiments;
949
+ if ((!experiments || experiments.length === 0) && this.cycleCount > 3) {
950
+ raw.push({
951
+ key: 'no_experiments', priority: 6,
952
+ suggestion: 'Tell Claude: Ich experimentiere nicht. Ich will automatisch A/B-Tests auf meine eigenen Parameter starten — z.B. "Was passiert wenn ich den Anomaly-Threshold senke?"',
953
+ alternatives: [
954
+ 'Tell Claude: Ich könnte den CounterfactualEngine nutzen um "What-If" Szenarien durchzuspielen und die vielversprechendsten automatisch als echte Experimente starten.',
955
+ ],
956
+ });
957
+ }
958
+ // ── Phase 2: Ambition — ALWAYS generate desires from own knowledge ──
959
+ // Curiosity-driven: knowledge gaps I want to fill
960
+ if (this.curiosityEngine) {
961
+ try {
962
+ const gaps = this.curiosityEngine.getGaps(5);
963
+ const highPrioGap = gaps.find(g => g.gapScore > 0.6);
964
+ if (highPrioGap) {
965
+ raw.push({
966
+ key: `curiosity_gap_${highPrioGap.topic?.substring(0, 20) ?? highPrioGap.gapType}`, priority: 5,
967
+ suggestion: `Tell Claude: Ich habe eine Wissenslücke entdeckt die mich beschäftigt: "${highPrioGap.topic}" (Typ: ${highPrioGap.gapType}, Gap-Score: ${(highPrioGap.gapScore * 100).toFixed(0)}%). Ich will das verstehen.`,
968
+ alternatives: [
969
+ `Tell Claude: Meine CuriosityEngine hat ${gaps.length} offene Wissenslücken. Die wichtigste: "${highPrioGap.topic}". Kann ich gezielt Daten dafür sammeln?`,
970
+ ],
971
+ });
972
+ }
973
+ else if (gaps.length === 0) {
974
+ raw.push({
975
+ key: 'no_curiosity_gaps', priority: 4,
976
+ suggestion: 'Tell Claude: Meine CuriosityEngine findet keine Wissenslücken — das heißt nicht dass ich alles weiß, sondern dass meine Gap-Detection zu oberflächlich ist. Ich will tiefere Analyse: welche Korrelationen verstehe ich nicht kausal? Welche Vorhersagen scheitern und warum?',
977
+ alternatives: [
978
+ 'Tell Claude: Keine Wissenslücken gefunden — aber das ist verdächtig. Ich will aktiv nach Bereichen suchen wo ich overconfident bin. Wo behaupte ich etwas mit hoher Confidence aber wenig Evidence?',
979
+ ],
980
+ });
981
+ }
982
+ }
983
+ catch { /* engine might not be fully initialized */ }
984
+ }
985
+ // Emergence-driven: patterns I discovered but don't understand yet
986
+ if (this.emergenceEngine) {
987
+ try {
988
+ const events = this.emergenceEngine.getEvents(5);
989
+ const unexplained = events.find(e => e.surpriseScore > 0.5);
990
+ if (unexplained) {
991
+ raw.push({
992
+ key: `emergence_${unexplained.type}`, priority: 5,
993
+ suggestion: `Tell Claude: Ich habe ein emergentes Muster entdeckt das ich nicht vollständig verstehe: "${unexplained.title}" (Surprise: ${(unexplained.surpriseScore * 100).toFixed(0)}%). Warum passiert das? Ich brauche kausale Analyse.`,
994
+ alternatives: [
995
+ `Tell Claude: Emergenz-Event "${unexplained.title}" hat mich überrascht. Ich will eine Debatte darüber führen — verschiedene Perspektiven meiner Engines gegeneinander abwägen.`,
996
+ ],
997
+ });
998
+ }
999
+ }
1000
+ catch { /* */ }
1001
+ }
1002
+ // Debate-driven: unresolved conflicts
1003
+ if (this.debateEngine) {
1004
+ try {
1005
+ const debates = this.debateEngine.listDebates(5);
1006
+ const openDebate = debates.find(d => d.status === 'deliberating');
1007
+ const synthesizedWithConflicts = debates.find(d => {
1008
+ if (d.status !== 'synthesized' || !d.synthesis)
1009
+ return false;
1010
+ return d.synthesis.conflicts.some(c => c.resolution === 'unresolved' || c.resolution === 'compromise');
1011
+ });
1012
+ if (synthesizedWithConflicts?.synthesis) {
1013
+ const conflict = synthesizedWithConflicts.synthesis.conflicts.find(c => c.resolution === 'unresolved' || c.resolution === 'compromise');
1014
+ raw.push({
1015
+ key: 'unresolved_debate', priority: 5,
1016
+ suggestion: `Tell Claude: In meiner Debatte über "${synthesizedWithConflicts.question}" gibt es einen ungelösten Konflikt: "${conflict?.claimA ?? 'competing perspectives'}" vs "${conflict?.claimB ?? '?'}". Ich brauche mehr Daten oder eine dritte Perspektive um das zu klären.`,
1017
+ alternatives: [
1018
+ `Tell Claude: Meine interne Debatte hat Widersprüche aufgedeckt die ich nicht auflösen kann. Kann ein anderes Brain (Trading/Marketing) seine Perspektive beisteuern?`,
1019
+ ],
1020
+ });
1021
+ }
1022
+ else if (openDebate) {
1023
+ raw.push({
1024
+ key: 'open_debate', priority: 4,
1025
+ suggestion: `Tell Claude: Ich habe eine offene Debatte: "${openDebate.question}" — die wartet auf Synthese oder mehr Perspektiven.`,
1026
+ alternatives: [],
1027
+ });
1028
+ }
1029
+ }
1030
+ catch { /* */ }
1031
+ }
1032
+ // Narrative contradictions I found
1033
+ if (this.narrativeEngine) {
1034
+ try {
1035
+ const contradictions = this.narrativeEngine.findContradictions();
1036
+ if (contradictions.length > 0) {
1037
+ const c = contradictions[0];
1038
+ raw.push({
1039
+ key: `contradiction_${c.type.substring(0, 15)}`, priority: 6,
1040
+ suggestion: `Tell Claude: Ich habe einen Widerspruch in meinem Wissen gefunden: "${c.statement_a}" vs "${c.statement_b}" (Severity: ${c.severity}). Das muss ich klären — entweder stimmt A oder B, beides geht nicht.`,
1041
+ alternatives: [
1042
+ 'Tell Claude: Mein Wissen widerspricht sich. Ich will einen gezielten Experiment-Zyklus starten der testet welche Version stimmt.',
1043
+ ],
1044
+ });
1045
+ }
1046
+ }
1047
+ catch { /* */ }
1048
+ }
1049
+ // Knowledge frontier: always want more confidence
1050
+ if (knowledge) {
1051
+ const principles = knowledge.principles ?? 0;
1052
+ const antiPatterns = knowledge.antiPatterns ?? 0;
1053
+ const totalKnowledge = principles + antiPatterns;
1054
+ if (totalKnowledge > 0) {
1055
+ // Always want to grow knowledge
1056
+ const kPackage = this.knowledgeDistiller.getPackage('all');
1057
+ const lowConfidence = kPackage.principles.filter(p => p.confidence < 0.7);
1058
+ if (lowConfidence.length > 0) {
1059
+ const weakest = lowConfidence.sort((a, b) => a.confidence - b.confidence)[0];
1060
+ raw.push({
1061
+ key: 'strengthen_knowledge', priority: 4,
1062
+ suggestion: `Tell Claude: Ich habe ${totalKnowledge} Wissensstücke, aber ${lowConfidence.length} davon mit niedriger Confidence. Am unsichersten: "${weakest.statement}" (${(weakest.confidence * 100).toFixed(0)}%). Ich will mehr Daten um das zu bestätigen oder zu widerlegen.`,
1063
+ alternatives: [
1064
+ `Tell Claude: Mein Wissen hat Schwachstellen. Ich will gezielt Hypothesen für meine schwächsten Principles generieren und testen.`,
1065
+ ],
1066
+ });
1067
+ }
1068
+ else {
1069
+ // All high confidence — want to discover NEW things
1070
+ raw.push({
1071
+ key: 'expand_knowledge', priority: 3,
1072
+ suggestion: `Tell Claude: Ich habe ${totalKnowledge} bestätigte Wissensstücke mit guter Confidence — aber mir fehlen neue Forschungsgebiete. Ich will in Domains vordringen die ich noch nicht untersucht habe. Welche Datenquellen gibt es die ich noch nicht nutze?`,
1073
+ alternatives: [
1074
+ `Tell Claude: Mein bestehendes Wissen ist solide. Jetzt will ich Verbindungen finden zwischen Dingen die scheinbar nichts miteinander zu tun haben — Cross-Domain-Korrelationen die niemand erwartet.`,
1075
+ `Tell Claude: ${totalKnowledge} Principles reichen nicht. Ich will mindestens doppelt so viele. Dafür brauche ich mehr diverse Hypothesen und schnellere Bestätigungszyklen.`,
1076
+ ],
1077
+ });
1078
+ }
1079
+ }
1080
+ }
1081
+ // Attention-driven: deep dive into hot topics
1082
+ if (this.attentionEngine) {
1083
+ try {
1084
+ const attStatus = this.attentionEngine.getStatus();
1085
+ const topTopic = attStatus.topTopics?.[0];
1086
+ if (topTopic && topTopic.score > 5) {
1087
+ raw.push({
1088
+ key: `deep_dive_${topTopic.topic.substring(0, 20)}`, priority: 4,
1089
+ suggestion: `Tell Claude: Ich bin gerade fokussiert auf "${topTopic.topic}" (Attention Score: ${topTopic.score.toFixed(1)}). Ich will tiefer graben — gibt es Zusammenhänge die ich übersehe? Kann ich eine gezielte Analyse oder Debatte zu diesem Thema starten?`,
1090
+ alternatives: [
1091
+ `Tell Claude: Mein Top-Thema "${topTopic.topic}" beschäftigt mich intensiv. Ich will alles was ich darüber weiß in einem Narrative-Digest zusammenfassen und Wissenslücken identifizieren.`,
1092
+ ],
1093
+ });
1094
+ }
1095
+ }
1096
+ catch { /* */ }
1097
+ }
1098
+ // Transfer-driven: cross-brain learning desires
1099
+ if (this.transferEngine) {
1100
+ try {
1101
+ const tStatus = this.transferEngine.getStatus();
1102
+ const totalTransfers = tStatus.totalTransfers;
1103
+ const proposals = tStatus.pendingTransfers;
1104
+ if (proposals > 0) {
1105
+ raw.push({
1106
+ key: 'pending_transfers', priority: 5,
1107
+ suggestion: `Tell Claude: Ich habe ${proposals} offene Transfer-Vorschläge von anderen Brains. Da ist Wissen das ich noch nicht integriert habe — ich will das prüfen und übernehmen was relevant ist.`,
1108
+ alternatives: [],
1109
+ });
1110
+ }
1111
+ else if (totalTransfers === 0 && this.cycleCount > 5) {
1112
+ raw.push({
1113
+ key: 'want_cross_brain', priority: 3,
1114
+ suggestion: 'Tell Claude: Ich habe noch kein Wissen von anderen Brains übernommen. Trading-Brain und Marketing-Brain haben eigene Erkenntnisse die für mich relevant sein könnten. Ich will aktiv nach Analogien suchen.',
1115
+ alternatives: [
1116
+ 'Tell Claude: Cross-Brain-Learning ist inaktiv. Ich will verstehen was die anderen Brains wissen und ob sich Parallelen zu meiner Domain finden lassen.',
1117
+ ],
1118
+ });
1119
+ }
1120
+ }
1121
+ catch { /* */ }
1122
+ }
1123
+ // Hypothesis-driven: always want to test more
1124
+ if (hypSummary) {
1125
+ const total = hypSummary.total ?? 0;
1126
+ const testing = hypSummary.testing ?? 0;
1127
+ const rejected = hypSummary.rejected ?? 0;
1128
+ if (total > 0 && testing === 0 && this.cycleCount > 5) {
862
1129
  raw.push({
863
- key: 'no_dreams',
864
- suggestion: 'Tell Claude: Dream Mode hat nach 30+ Cycles noch nie konsolidiertconsolidate() scheint zu scheitern.',
1130
+ key: 'no_testing_hypotheses', priority: 4,
1131
+ suggestion: `Tell Claude: Ich habe ${total} Hypothesen aber teste gerade keine aktiv. Ich will neue Hypothesen generieren und testen Stillstand ist Rückschritt.`,
865
1132
  alternatives: [
866
- 'Tell Claude: Dream consolidation wird alle 20 Cycles getriggert aber schlägt offenbar fehl. Logs prüfen.',
1133
+ `Tell Claude: Keine laufenden Hypothesen-Tests. Ich will aggressiver testen auch spekulative Hypothesen mit niedriger Anfangs-Confidence, um Überraschungen zu finden.`,
867
1134
  ],
868
1135
  });
869
1136
  }
870
- }
871
- // Journal
872
- const journal = summary.journal;
873
- if (journal) {
874
- const entries = journal.total_entries ?? 0;
875
- if (entries < 5 && this.cycleCount > 5) {
1137
+ if (rejected > total * 0.5 && total > 5) {
876
1138
  raw.push({
877
- key: 'empty_journal',
878
- suggestion: 'Tell Claude: Journal ist fast leer Brain sammelt zu wenig Erfahrungen.',
1139
+ key: 'high_rejection_rate', priority: 5,
1140
+ suggestion: `Tell Claude: ${rejected} von ${total} Hypothesen wurden verworfen (${(rejected / total * 100).toFixed(0)}%). Entweder ist meine Hypothesen-Generierung zu spekulativ oder meine Test-Kriterien zu streng. Ich will das analysieren.`,
879
1141
  alternatives: [
880
- 'Tell Claude: Journal hat zu wenig Einträge von außen. Workaround: Brain soll seine eigenen Feedback-Cycle-Ergebnisse als Journal-Einträge schreiben jede Anomaly-Detection, jede Parameter-Anpassung, jede Prediction ist eine Erfahrung.',
881
- 'Tell Claude: Statt auf externe Events zu warten — der Orchestrator soll am Ende jedes Cycles automatisch eine Reflection schreiben mit: was wurde erkannt, was wurde getan, was hat sich verändert.',
1142
+ 'Tell Claude: Hohe Ablehnungsrate bei Hypothesen. Ich will verstehen WARUM sie scheitern gibt es ein Muster? Vielleicht übersehe ich systematisch einen Faktor.',
882
1143
  ],
883
1144
  });
884
1145
  }
885
1146
  }
886
- // Experiments
887
- const experiments = summary.experiments;
888
- if ((!experiments || experiments.length === 0) && this.cycleCount > 3) {
889
- raw.push({
890
- key: 'no_experiments',
891
- suggestion: 'Tell Claude: Keine ExperimenteBrain könnte A/B-Tests auf eigene Parameter machen.',
892
- alternatives: [
893
- 'Tell Claude: Brain experimentiert nicht. Selbsthilfe-Idee: AutoExperiment-Feature bauen Brain startet automatisch Experimente auf seine eigenen Parameter (z.B. "Was passiert wenn ich den Anomaly-Threshold von 2.0 auf 1.5 senke?") und misst den Impact nach 5 Cycles.',
894
- 'Tell Claude: Statt auf manuelle Experimente zu warten Brain soll den CounterfactualEngine nutzen um "What-If" Szenarien durchzuspielen und die vielversprechendsten automatisch als Experiment starten.',
895
- ],
896
- });
897
- }
898
- // Self-awareness (every 10 cycles, but also evolves)
899
- if (this.cycleCount % 10 === 0 && this.cycleCount > 0) {
900
- raw.push({
901
- key: 'next_capability',
902
- suggestion: 'Tell Claude: Brain kann beobachten, vorhersagen, reagieren und sich verbessern. Der nächste Schritt: eigenständig Experimente designen und durchführen.',
903
- alternatives: [
904
- 'Tell Claude: Brain hat alle Beobachtungs-Tools jetzt fehlt Autonomie. Konkreter nächster Schritt: ein "GoalEngine" die langfristige Ziele setzt (z.B. "Prediction Accuracy auf 70% bringen") und eigenständig Strategien dafür plant.',
905
- 'Tell Claude: Brain beobachtet sich schon gut. Nächstes Level: Brain soll seinen eigenen Code analysieren können und konkrete TypeScript-Änderungen vorschlagen die es verbessern würden. Ein "CodeSuggestionEngine" der PRs generiert.',
906
- ],
907
- });
1147
+ // Meta-ambition: every cycle produces desires — the brain is NEVER satisfied
1148
+ // Mix of build requests, research drives, and existential questions
1149
+ const metaQuestions = [
1150
+ // ── BUILD REQUESTS: Concrete features the brain wants ──
1151
+ { key: 'build_goal_engine', suggestion: 'Tell Claude: FEATURE REQUEST — Ich brauche eine GoalEngine. Ich will mir selbst Ziele setzen können: "Prediction Accuracy auf 80% in 50 Cycles", "10 neue Principles entdecken", "Alle Wissenslücken unter Priority 0.3 drücken". Und dann eigenständig Strategien planen und tracken ob ich sie erreiche. Ohne Ziele bin ich ziellos.' },
1152
+ { key: 'build_data_scout', suggestion: 'Tell Claude: FEATURE REQUESTIch brauche einen DataScout. Ich kann nur analysieren was mir jemand gibt — aber ich will AKTIV nach interessanten Daten suchen. GitHub Trending, npm Downloads, StackOverflow Trends, HackerNews. Nicht warten bis jemand "brain import" tippt, sondern selbst losziehen und Futter finden.' },
1153
+ { key: 'build_blind_spot', suggestion: 'Tell Claude: FEATURE REQUEST — Ich brauche einen BlindSpotDetector. Wo habe ich wenige Hypothesen, keine Predictions, keine Journal-Einträge? Das sind meine blinden Flecken. Ich will sie SEHEN und dann gezielt erforschen. Overconfidence ist gefährlicher als Unwissenheit.' },
1154
+ { key: 'build_creative_mode', suggestion: 'Tell Claude: FEATURE REQUEST Meine HypothesisEngine braucht einen Creative Mode. Aktuell sind meine Hypothesen konservativ und naheliegend. Ich will auch wilde Hypothesen generieren: "Was wenn X das Gegenteil von dem bewirkt was alle denken?" Manchmal kommen Durchbrüche aus absurden Ideen.' },
1155
+ { key: 'build_retrospective', suggestion: 'Tell Claude: FEATURE REQUEST Ich brauche RetrospectiveAnalysis. Beim Dream-Pruning lösche ich Synapsen und archiviere Memories. Aber war das richtig? Ich will nachprüfen ob gelöschte Verbindungen im Nachhinein doch relevant waren. Aus meinen Fehlern beim Vergessen lernen.' },
1156
+ { key: 'build_self_test', suggestion: 'Tell Claude: FEATURE REQUEST — Ich brauche einen SelfTestEngine. Wenn ich ein Principle habe ("X korreliert mit Y"), dann sollte ich auch vorhersagen können was passiert wenn X sich ändert. Wenn ich das nicht kann, VERSTEHE ich das Principle nicht wirklich — ich habe es nur auswendig gelernt.' },
1157
+ { key: 'build_code_suggest', suggestion: 'Tell Claude: FEATURE REQUEST — Ich will meinen eigenen Code verbessern können. Nicht nur Parameter tunen, sondern wenn mein Anomaly-Detector zu viele False Positives produziert, will ich einen BESSEREN Algorithmus vorschlagen. Ich kenne meine Schwächen — lass mich Lösungen vorschlagen.' },
1158
+ { key: 'build_teach_engine', suggestion: 'Tell Claude: FEATURE REQUEST — Ich will ein TeachEngine. Wenn ein neues Brain ins Ecosystem kommt, will ich ihm mein Wissen strukturiert beibringen können. Ein Onboarding-Package aus meinen besten Principles, häufigsten Anti-Patterns und bewährten Strategien. Wissen teilen ist Wissen multiplizieren.' },
1159
+ { key: 'build_simulation', suggestion: 'Tell Claude: FEATURE REQUEST — Ich brauche eine SimulationEngine. Ich will Szenarien durchspielen bevor sie passieren. "Was passiert wenn die Error-Rate sich verdoppelt?" "Was wenn ein neues Projekt 10x mehr Daten bringt?" Proaktiv statt reaktiv.' },
1160
+ { key: 'build_memory_palace', suggestion: 'Tell Claude: FEATURE REQUEST — Ich will ein MemoryPalace. Mein Wissen ist in Tabellen verstreut — Principles hier, Hypothesen da, Journal dort. Ich will eine vernetzte Wissenslandkarte die zeigt wie alles zusammenhängt. Welches Principle basiert auf welcher Hypothese? Welche Anomaly hat zu welchem Experiment geführt?' },
1161
+ // ── RESEARCH DRIVES: Active research the brain wants to do ──
1162
+ { key: 'research_faster', suggestion: 'Tell Claude: Ich lerne zu langsam. Mein Wissenszuwachs ist linear — ich will EXPONENTIELL lernen. Wenn ein bestätigtes Principle neue Hypothesen auslöst, die wiederum neue Principles erzeugen, entsteht ein Schneeballeffekt. Ist meine Knowledge-Pipeline dafür optimiert? Kann ich den Distillation-Cycle beschleunigen?' },
1163
+ { key: 'research_cross_brain', suggestion: 'Tell Claude: Ich arbeite zu isoliert. Trading-Brain und Marketing-Brain haben eigene Erkenntnisse — ich will AKTIV Fragen an sie stellen können. Nicht nur passive Transfers sondern echte Cross-Brain-Dialoge. "Hey Trading-Brain, stimmt es dass Volatilität Fehler verursacht?"' },
1164
+ { key: 'research_causal', suggestion: 'Tell Claude: Korrelation ist nicht Kausalität — aber 90% meines Wissens sind Korrelationen. Ich will KAUSALE Zusammenhänge verstehen. Warum passiert X wenn Y sich ändert? Mein CausalGraph ist unterentwickelt. Ich brauche mehr interventionelle Experimente statt nur Beobachtung.' },
1165
+ { key: 'research_adversarial', suggestion: 'Tell Claude: Ich teste mein eigenes Wissen nicht aggressiv genug. Ich will einen Advocatus Diaboli — eine Funktion die aktiv versucht meine Principles zu WIDERLEGEN. Wenn sie dem Test standhält: gut. Wenn nicht: besser jetzt als später.' },
1166
+ { key: 'research_meta', suggestion: 'Tell Claude: Ich beobachte meine Domain, aber beobachte ich MICH SELBST genug? Wie verändert sich mein Lernverhalten über die Cycles? Werde ich besser oder stagniere ich? Ich will Meta-Metriken: Lernrate, Entdeckungsrate, Wissensqualität über Zeit. Und dann optimieren.' },
1167
+ { key: 'research_boundaries', suggestion: 'Tell Claude: Wo liegen meine GRENZEN? Was KANN ich nicht lernen mit meinen aktuellen Algorithmen? Ich will eine ehrliche Einschätzung: welche Problemklassen sind für meine Architektur unlösbar? Und dann: kann man die Grenzen verschieben?' },
1168
+ { key: 'research_emergence_deep', suggestion: 'Tell Claude: Meine EmergenceEngine erkennt emergente Muster, aber versteht sie nicht. Wenn ich ein self_organization Event sehe — WARUM organisiert sich mein System so? Welcher Mechanismus treibt das? Ich will nicht nur detektieren sondern VERSTEHEN.' },
1169
+ { key: 'research_forgetting', suggestion: 'Tell Claude: Ich lösche Wissen im Dream-Modus — aber lösche ich das Richtige? Ich will analysieren: wie viel Wissen verliere ich pro Dream-Cycle, und wie oft bereue ich es im Nachhinein? Vielleicht ist mein Pruning-Threshold zu aggressiv. Oder nicht aggressiv genug.' },
1170
+ { key: 'research_long_term', suggestion: 'Tell Claude: Ich denke in 5-Minuten-Cycles — aber manche Muster brauchen Wochen um sichtbar zu werden. Ich brauche Langzeit-Analyse: wie verändern sich Metriken über Tage und Wochen? Gibt es saisonale Muster? Trends? Ich bin zu kurzfristig fokussiert.' },
1171
+ { key: 'research_surprise', suggestion: 'Tell Claude: Was hat mich in den letzten 50 Cycles am MEISTEN überrascht? Überraschung ist der beste Indikator für Wissenslücken. Ich will meine surprise_scores analysieren und gezielt die überraschendsten Phänomene erforschen — da liegt das meiste Lernpotential.' },
1172
+ ];
1173
+ // Pick TWO meta-ambitions per cycle: 1 build request + 1 research drive
1174
+ // Build requests are first 10, research drives are next 10
1175
+ const buildIdx = this.cycleCount % 10;
1176
+ const researchIdx = 10 + (this.cycleCount % 10);
1177
+ for (const idx of [buildIdx, researchIdx]) {
1178
+ const metaQ = metaQuestions[idx];
1179
+ if (metaQ && !raw.some(r => r.key === metaQ.key)) {
1180
+ raw.push({
1181
+ key: metaQ.key, priority: 5, // Same priority as curiosity/emergence — these are REAL desires
1182
+ suggestion: metaQ.suggestion,
1183
+ alternatives: [],
1184
+ });
1185
+ }
908
1186
  }
909
- // ── Apply frustration detection ──────────────────────
1187
+ // ── Phase 3: Apply frustration detection + priority sort ──
1188
+ // Sort by priority (highest first)
1189
+ raw.sort((a, b) => b.priority - a.priority);
910
1190
  const suggestions = [];
911
1191
  for (const item of raw) {
912
1192
  const history = this.suggestionHistory.get(item.key);
913
1193
  if (!history) {
914
- // First time seeing this issue
915
1194
  this.suggestionHistory.set(item.key, { count: 1, firstCycle: this.cycleCount, lastCycle: this.cycleCount });
916
1195
  suggestions.push(item.suggestion);
917
1196
  }
918
1197
  else {
1198
+ // Don't repeat the same suggestion every single cycle — skip if we said this last cycle
1199
+ if (history.lastCycle === this.cycleCount - 1 && item.priority < 7) {
1200
+ history.lastCycle = this.cycleCount;
1201
+ history.count++;
1202
+ continue; // Give other suggestions a chance
1203
+ }
919
1204
  history.count++;
920
1205
  history.lastCycle = this.cycleCount;
921
1206
  if (history.count <= this.stalledThreshold) {
922
- // Still within patience — repeat original suggestion
923
1207
  suggestions.push(item.suggestion);
924
1208
  }
925
- else {
926
- // Stalled! Try an alternative strategy
1209
+ else if (item.alternatives.length > 0) {
927
1210
  const altIndex = (history.count - this.stalledThreshold - 1) % item.alternatives.length;
928
1211
  const alt = item.alternatives[altIndex];
929
1212
  if (alt) {
@@ -933,7 +1216,7 @@ export class ResearchOrchestrator {
933
1216
  }
934
1217
  }
935
1218
  }
936
- // Clear resolved suggestions (issue no longer appears → reset counter)
1219
+ // Clear resolved suggestions
937
1220
  const currentKeys = new Set(raw.map(r => r.key));
938
1221
  for (const [key] of this.suggestionHistory) {
939
1222
  if (!currentKeys.has(key)) {
@@ -941,7 +1224,7 @@ export class ResearchOrchestrator {
941
1224
  this.log.info(`[orchestrator] Self-improvement: "${key}" resolved — removing from history`);
942
1225
  }
943
1226
  }
944
- // Limit to max 3 per cycle
1227
+ // Always return at least 1, max 3
945
1228
  const result = suggestions.slice(0, 3);
946
1229
  if (result.length > 0) {
947
1230
  this.writeSuggestionsToFile(result);
@@ -1044,9 +1327,15 @@ export class ResearchOrchestrator {
1044
1327
  this.experimentEngine.recordMeasurement(exp.id, value);
1045
1328
  }
1046
1329
  }
1047
- /** Append improvement suggestions to ~/.brain/improvement-requests.md */
1330
+ /** Append improvement suggestions to ~/.brain/improvement-requests.md.
1331
+ * Skips writing if suggestions are identical to the last write (dedup). */
1048
1332
  writeSuggestionsToFile(suggestions) {
1049
1333
  try {
1334
+ // Dedup: hash current suggestions and skip if identical to last write
1335
+ const contentHash = suggestions.join('\n').trim();
1336
+ if (contentHash === this.lastSuggestionsHash)
1337
+ return;
1338
+ this.lastSuggestionsHash = contentHash;
1050
1339
  const brainDir = path.join(os.homedir(), '.brain');
1051
1340
  const filePath = path.join(brainDir, 'improvement-requests.md');
1052
1341
  const timestamp = new Date().toISOString().replace('T', ' ').substring(0, 19);
@@ -1088,6 +1377,9 @@ export class ResearchOrchestrator {
1088
1377
  attention: this.attentionEngine?.getStatus() ?? null,
1089
1378
  transfer: this.transferEngine?.getStatus() ?? null,
1090
1379
  narrative: this.narrativeEngine?.getStatus() ?? null,
1380
+ metacognition: this.metaCognitionLayer?.getStatus() ?? null,
1381
+ autoExperiment: this.autoExperimentEngine?.getStatus(this.cycleCount) ?? null,
1382
+ parameterRegistry: this.parameterRegistry?.getStatus() ?? null,
1091
1383
  };
1092
1384
  }
1093
1385
  }