rlhf-feedback-loop 0.6.11 → 0.6.13

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.
Files changed (43) hide show
  1. package/CHANGELOG.md +10 -0
  2. package/README.md +116 -74
  3. package/adapters/README.md +3 -3
  4. package/adapters/amp/skills/rlhf-feedback/SKILL.md +2 -0
  5. package/adapters/chatgpt/INSTALL.md +7 -4
  6. package/adapters/chatgpt/openapi.yaml +6 -3
  7. package/adapters/claude/.mcp.json +3 -3
  8. package/adapters/codex/config.toml +3 -3
  9. package/adapters/gemini/function-declarations.json +2 -2
  10. package/adapters/mcp/server-stdio.js +19 -5
  11. package/bin/cli.js +302 -32
  12. package/openapi/openapi.yaml +6 -3
  13. package/package.json +22 -9
  14. package/scripts/a2ui-engine.js +73 -0
  15. package/scripts/adk-consolidator.js +126 -32
  16. package/scripts/billing.js +192 -685
  17. package/scripts/context-engine.js +81 -0
  18. package/scripts/export-kto-pairs.js +310 -0
  19. package/scripts/feedback-ingest-watcher.js +290 -0
  20. package/scripts/feedback-loop.js +154 -9
  21. package/scripts/feedback-quality.js +139 -0
  22. package/scripts/feedback-schema.js +31 -5
  23. package/scripts/feedback-to-memory.js +13 -1
  24. package/scripts/generate-paperbanana-diagrams.sh +1 -1
  25. package/scripts/hook-auto-capture.sh +6 -0
  26. package/scripts/hook-stop-self-score.sh +51 -0
  27. package/scripts/install-mcp.js +168 -0
  28. package/scripts/jsonl-watcher.js +155 -0
  29. package/scripts/local-model-profile.js +207 -0
  30. package/scripts/pr-manager.js +112 -0
  31. package/scripts/prove-adapters.js +137 -15
  32. package/scripts/prove-automation.js +41 -8
  33. package/scripts/prove-lancedb.js +1 -1
  34. package/scripts/prove-local-intelligence.js +244 -0
  35. package/scripts/prove-workflow-contract.js +116 -0
  36. package/scripts/reminder-engine.js +132 -0
  37. package/scripts/risk-scorer.js +458 -0
  38. package/scripts/rlaif-self-audit.js +7 -1
  39. package/scripts/status-dashboard.js +155 -0
  40. package/scripts/test-coverage.js +1 -1
  41. package/scripts/validate-workflow-contract.js +287 -0
  42. package/scripts/vector-store.js +115 -17
  43. package/src/api/server.js +372 -25
package/bin/cli.js CHANGED
@@ -7,7 +7,7 @@
7
7
  * npx rlhf-feedback-loop capture # capture feedback
8
8
  * npx rlhf-feedback-loop export-dpo # export DPO training pairs
9
9
  * npx rlhf-feedback-loop stats # feedback analytics + Revenue-at-Risk
10
- * npx rlhf-feedback-loop pro # upgrade to Cloud Pro
10
+ * npx rlhf-feedback-loop pro # upgrade to Context Gateway
11
11
  */
12
12
 
13
13
  'use strict';
@@ -39,23 +39,146 @@ function pkgVersion() {
39
39
  // --- Platform auto-detection helpers ---
40
40
 
41
41
  const HOME = process.env.HOME || process.env.USERPROFILE || '';
42
- const MCP_SERVER_ENTRY = {
43
- command: 'node',
44
- args: [path.relative(CWD, path.join(PKG_ROOT, 'adapters', 'mcp', 'server-stdio.js'))],
45
- };
42
+ const MCP_SERVER_NAME = 'rlhf';
43
+ const LEGACY_MCP_SERVER_NAMES = ['rlhf', 'rlhf-feedback-loop', 'rlhf_feedback_loop'];
44
+ const PORTABLE_MCP_COMMAND = 'npx';
45
+ const LOCAL_MCP_COMMAND = 'node';
46
+
47
+ function portableMcpArgs() {
48
+ return ['-y', `rlhf-feedback-loop@${pkgVersion()}`, 'serve'];
49
+ }
50
+
51
+ function localServerEntryPath() {
52
+ return path.join(PKG_ROOT, 'adapters', 'mcp', 'server-stdio.js');
53
+ }
54
+
55
+ function shouldUseLocalServerEntry() {
56
+ return fs.existsSync(path.join(PKG_ROOT, '.git'));
57
+ }
58
+
59
+ function portableMcpEntry() {
60
+ return {
61
+ command: PORTABLE_MCP_COMMAND,
62
+ args: portableMcpArgs(),
63
+ };
64
+ }
65
+
66
+ function localMcpEntry() {
67
+ return {
68
+ command: LOCAL_MCP_COMMAND,
69
+ args: [localServerEntryPath()],
70
+ };
71
+ }
72
+
73
+ function mcpEntriesMatch(entry, expectedEntry) {
74
+ return Boolean(
75
+ entry &&
76
+ expectedEntry &&
77
+ entry.command === expectedEntry.command &&
78
+ Array.isArray(entry.args) &&
79
+ Array.isArray(expectedEntry.args) &&
80
+ entry.args.length === expectedEntry.args.length &&
81
+ entry.args.every((arg, index) => arg === expectedEntry.args[index])
82
+ );
83
+ }
84
+
85
+ function escapeRegExp(value) {
86
+ return String(value).replace(/[.*+?^${}()|[\]\\]/g, '\\$&');
87
+ }
88
+
89
+ function formatTomlStringArray(values) {
90
+ return `[${values.map((value) => JSON.stringify(value)).join(', ')}]`;
91
+ }
92
+
93
+ function canonicalMcpEntry() {
94
+ return shouldUseLocalServerEntry() ? localMcpEntry() : portableMcpEntry();
95
+ }
96
+
97
+ function mcpSectionBlock(name = MCP_SERVER_NAME) {
98
+ const entry = canonicalMcpEntry();
99
+ return `[mcp_servers.${name}]\ncommand = "${entry.command}"\nargs = ${formatTomlStringArray(entry.args)}\n`;
100
+ }
101
+
102
+ function upsertCodexServerConfig(content) {
103
+ const canonicalBlock = mcpSectionBlock();
104
+ const sections = LEGACY_MCP_SERVER_NAMES.map((name) => ({
105
+ name,
106
+ regex: new RegExp(`^\\[mcp_servers\\.${escapeRegExp(name)}\\]\\n[\\s\\S]*?(?=^\\[|$)`, 'm'),
107
+ }));
108
+ const matches = sections
109
+ .map((section) => ({ ...section, match: content.match(section.regex) }))
110
+ .filter((section) => section.match);
111
+
112
+ if (matches.length === 0) {
113
+ const prefix = content.trimEnd();
114
+ return {
115
+ changed: true,
116
+ content: `${prefix}${prefix ? '\n\n' : ''}${canonicalBlock}`,
117
+ };
118
+ }
119
+
120
+ let nextContent = content;
121
+ let changed = false;
122
+ let canonicalPresent = false;
123
+
124
+ for (const section of matches) {
125
+ const normalized = canonicalBlock;
126
+ const current = section.match[0];
127
+
128
+ if (section.name === MCP_SERVER_NAME) {
129
+ canonicalPresent = true;
130
+ if (current !== normalized) {
131
+ nextContent = nextContent.replace(section.regex, normalized);
132
+ changed = true;
133
+ }
134
+ continue;
135
+ }
136
+
137
+ nextContent = nextContent.replace(section.regex, '');
138
+ changed = true;
139
+ }
140
+
141
+ if (!canonicalPresent) {
142
+ const prefix = nextContent.trimEnd();
143
+ nextContent = `${prefix}${prefix ? '\n\n' : ''}${canonicalBlock}`;
144
+ changed = true;
145
+ }
146
+
147
+ return {
148
+ changed,
149
+ content: nextContent.endsWith('\n') ? nextContent : `${nextContent}\n`,
150
+ };
151
+ }
46
152
 
47
153
  function mergeMcpJson(filePath, label) {
154
+ const canonicalEntry = canonicalMcpEntry();
48
155
  if (!fs.existsSync(filePath)) {
49
156
  const dir = path.dirname(filePath);
50
157
  if (!fs.existsSync(dir)) fs.mkdirSync(dir, { recursive: true });
51
- fs.writeFileSync(filePath, JSON.stringify({ mcpServers: { 'rlhf-feedback-loop': MCP_SERVER_ENTRY } }, null, 2) + '\n');
158
+ fs.writeFileSync(filePath, JSON.stringify({ mcpServers: { [MCP_SERVER_NAME]: canonicalEntry } }, null, 2) + '\n');
52
159
  console.log(` ${label}: wrote ${path.relative(CWD, filePath)}`);
53
160
  return true;
54
161
  }
55
162
  const existing = JSON.parse(fs.readFileSync(filePath, 'utf8'));
56
- if (existing.mcpServers && existing.mcpServers['rlhf-feedback-loop']) return false;
57
163
  existing.mcpServers = existing.mcpServers || {};
58
- existing.mcpServers['rlhf-feedback-loop'] = MCP_SERVER_ENTRY;
164
+
165
+ let changed = false;
166
+ const currentEntry = existing.mcpServers[MCP_SERVER_NAME];
167
+ if (!mcpEntriesMatch(currentEntry, canonicalEntry)) {
168
+ existing.mcpServers[MCP_SERVER_NAME] = canonicalEntry;
169
+ changed = true;
170
+ }
171
+
172
+ for (const legacyName of LEGACY_MCP_SERVER_NAMES) {
173
+ if (legacyName === MCP_SERVER_NAME) continue;
174
+ if (Object.prototype.hasOwnProperty.call(existing.mcpServers, legacyName)) {
175
+ delete existing.mcpServers[legacyName];
176
+ changed = true;
177
+ }
178
+ }
179
+
180
+ if (!changed) return false;
181
+
59
182
  fs.writeFileSync(filePath, JSON.stringify(existing, null, 2) + '\n');
60
183
  console.log(` ${label}: updated ${path.relative(CWD, filePath)}`);
61
184
  return true;
@@ -73,12 +196,37 @@ function whichExists(cmd) {
73
196
  }
74
197
 
75
198
  function setupClaude() {
76
- return mergeMcpJson(path.join(CWD, '.mcp.json'), 'Claude Code');
199
+ const mcpChanged = mergeMcpJson(path.join(CWD, '.mcp.json'), 'Claude Code');
200
+
201
+ // Upsert Stop hook into .claude/settings.json for autonomous self-scoring
202
+ const settingsPath = path.join(CWD, '.claude', 'settings.json');
203
+ const stopHookCommand = 'bash scripts/hook-stop-self-score.sh';
204
+
205
+ let settings = { hooks: {} };
206
+ if (fs.existsSync(settingsPath)) {
207
+ try { settings = JSON.parse(fs.readFileSync(settingsPath, 'utf8')); } catch (_) { /* fresh */ }
208
+ }
209
+ settings.hooks = settings.hooks || {};
210
+
211
+ const stopAlreadyPresent = (settings.hooks.Stop || [])
212
+ .some(entry => (entry.hooks || []).some(h => h.command === stopHookCommand));
213
+
214
+ let hooksChanged = false;
215
+ if (!stopAlreadyPresent) {
216
+ settings.hooks.Stop = settings.hooks.Stop || [];
217
+ settings.hooks.Stop.push({ hooks: [{ type: 'command', command: stopHookCommand }] });
218
+ fs.mkdirSync(path.dirname(settingsPath), { recursive: true });
219
+ fs.writeFileSync(settingsPath, JSON.stringify(settings, null, 2) + '\n');
220
+ console.log(' Claude Code: installed Stop hook in .claude/settings.json');
221
+ hooksChanged = true;
222
+ }
223
+
224
+ return mcpChanged || hooksChanged;
77
225
  }
78
226
 
79
227
  function setupCodex() {
80
228
  const configPath = path.join(HOME, '.codex', 'config.toml');
81
- const block = `\n[mcp_servers.rlhf_feedback_loop]\ncommand = "node"\nargs = ["${MCP_SERVER_ENTRY.args[0]}"]\n`;
229
+ const block = mcpSectionBlock();
82
230
  if (!fs.existsSync(configPath)) {
83
231
  fs.mkdirSync(path.dirname(configPath), { recursive: true });
84
232
  fs.writeFileSync(configPath, block);
@@ -86,8 +234,9 @@ function setupCodex() {
86
234
  return true;
87
235
  }
88
236
  const content = fs.readFileSync(configPath, 'utf8');
89
- if (content.includes('[mcp_servers.rlhf_feedback_loop]')) return false;
90
- fs.appendFileSync(configPath, block);
237
+ const updated = upsertCodexServerConfig(content);
238
+ if (!updated.changed) return false;
239
+ fs.writeFileSync(configPath, updated.content);
91
240
  console.log(' Codex: appended MCP server to ~/.codex/config.toml');
92
241
  return true;
93
242
  }
@@ -96,9 +245,24 @@ function setupGemini() {
96
245
  const settingsPath = path.join(HOME, '.gemini', 'settings.json');
97
246
  if (fs.existsSync(settingsPath)) {
98
247
  const settings = JSON.parse(fs.readFileSync(settingsPath, 'utf8'));
99
- if (settings.mcpServers && settings.mcpServers['rlhf-feedback-loop']) return false;
100
248
  settings.mcpServers = settings.mcpServers || {};
101
- settings.mcpServers['rlhf-feedback-loop'] = MCP_SERVER_ENTRY;
249
+ let changed = false;
250
+ const canonicalEntry = canonicalMcpEntry();
251
+
252
+ if (!mcpEntriesMatch(settings.mcpServers[MCP_SERVER_NAME], canonicalEntry)) {
253
+ settings.mcpServers[MCP_SERVER_NAME] = canonicalEntry;
254
+ changed = true;
255
+ }
256
+
257
+ for (const legacyName of LEGACY_MCP_SERVER_NAMES) {
258
+ if (legacyName === MCP_SERVER_NAME) continue;
259
+ if (Object.prototype.hasOwnProperty.call(settings.mcpServers, legacyName)) {
260
+ delete settings.mcpServers[legacyName];
261
+ changed = true;
262
+ }
263
+ }
264
+
265
+ if (!changed) return false;
102
266
  fs.writeFileSync(settingsPath, JSON.stringify(settings, null, 2) + '\n');
103
267
  console.log(' Gemini: updated ~/.gemini/settings.json');
104
268
  return true;
@@ -293,7 +457,7 @@ function stats() {
293
457
  console.log(` Repeated Failures detected: ${data.totalNegative}`);
294
458
  console.log(` Estimated Operational Loss: $${revenueAtRisk}`);
295
459
  console.log(' Action Required: Run "npx rlhf-feedback-loop rules" to generate guardrails.');
296
- console.log(' Strategic Recommendation: Upgrade to Cloud Pro to sync these rules across your team.');
460
+ console.log(' Strategic Recommendation: Upgrade to Context Gateway to sync these rules across your team.');
297
461
  console.log(' Run: npx rlhf-feedback-loop pro');
298
462
  } else {
299
463
  console.log('\n✅ System is currently high-reliability. No immediate revenue loss detected.');
@@ -302,7 +466,7 @@ function stats() {
302
466
 
303
467
  function pro() {
304
468
  const stripeUrl = 'https://buy.stripe.com/bJe14neyU4r4f0leOD3sI02';
305
- console.log('\n🚀 RLHF Feedback LoopCloud Pro');
469
+ console.log('\n🚀 MCP Memory GatewayContext Gateway');
306
470
  console.log('─'.repeat(50));
307
471
  console.log('Unlock the full Agentic Control Plane:');
308
472
  console.log(' - Hosted Team API (Shared memory across all repos)');
@@ -320,6 +484,65 @@ function summary() {
320
484
  console.log(feedbackSummary(Number(args.recent || 20)));
321
485
  }
322
486
 
487
+ function modelFit() {
488
+ const { writeModelFitReport } = require(path.join(PKG_ROOT, 'scripts', 'local-model-profile'));
489
+ const { reportPath, report } = writeModelFitReport();
490
+ console.log(JSON.stringify({ reportPath, report }, null, 2));
491
+ }
492
+
493
+ function risk() {
494
+ const args = parseArgs(process.argv.slice(3));
495
+ const riskScorer = require(path.join(PKG_ROOT, 'scripts', 'risk-scorer'));
496
+
497
+ if (args.context || args.tags || args.skill || args.domain || args['rubric-scores'] || args.guardrails) {
498
+ const { inferDomain } = require(path.join(PKG_ROOT, 'scripts', 'feedback-loop'));
499
+ const { buildRubricEvaluation } = require(path.join(PKG_ROOT, 'scripts', 'rubric-engine'));
500
+ const historyRows = riskScorer.readJSONL(riskScorer.sequencePathFor());
501
+ const tags = String(args.tags || '')
502
+ .split(',')
503
+ .map((tag) => tag.trim())
504
+ .filter(Boolean);
505
+
506
+ let rubric = null;
507
+ if (args['rubric-scores'] || args.guardrails) {
508
+ const evaluation = buildRubricEvaluation({
509
+ rubricScores: args['rubric-scores'],
510
+ guardrails: args.guardrails,
511
+ });
512
+ rubric = {
513
+ rubricId: evaluation.rubricId,
514
+ weightedScore: evaluation.weightedScore,
515
+ failingCriteria: evaluation.failingCriteria,
516
+ failingGuardrails: evaluation.failingGuardrails,
517
+ judgeDisagreements: evaluation.judgeDisagreements,
518
+ };
519
+ }
520
+
521
+ const candidate = riskScorer.buildRiskCandidate({
522
+ context: args.context || '',
523
+ tags,
524
+ skill: args.skill || null,
525
+ domain: args.domain || inferDomain(tags, args.context || ''),
526
+ rubric,
527
+ filePathCount: Number(args['file-count'] || 0),
528
+ errorType: args['error-type'] || null,
529
+ }, historyRows);
530
+ const model = riskScorer.loadRiskModel() || riskScorer.trainAndPersistRiskModel().model;
531
+ console.log(JSON.stringify({
532
+ prediction: riskScorer.predictRisk(model, candidate),
533
+ candidate,
534
+ }, null, 2));
535
+ return;
536
+ }
537
+
538
+ const { model, modelPath } = riskScorer.trainAndPersistRiskModel();
539
+ console.log(JSON.stringify({
540
+ modelPath,
541
+ metrics: model.metrics,
542
+ summary: riskScorer.getRiskSummary(),
543
+ }, null, 2));
544
+ }
545
+
323
546
  function exportDpo() {
324
547
  const extraArgs = process.argv.slice(3).join(' ');
325
548
  try {
@@ -359,7 +582,7 @@ function prove() {
359
582
  const script = path.join(PKG_ROOT, 'scripts', `prove-${target}.js`);
360
583
  if (!fs.existsSync(script)) {
361
584
  console.error(`Unknown proof target: ${target}`);
362
- console.error('Available: adapters, automation, attribution, lancedb, data-quality, intelligence, loop-closure, training-export');
585
+ console.error('Available: adapters, automation, attribution, lancedb, data-quality, intelligence, local-intelligence, loop-closure, training-export');
363
586
  process.exit(1);
364
587
  }
365
588
  try {
@@ -369,40 +592,65 @@ function prove() {
369
592
  }
370
593
  }
371
594
 
372
- function serve() {
373
- const rlhfDir = path.join(CWD, '.rlhf');
374
- if (!fs.existsSync(rlhfDir) && !fs.existsSync(path.join(CWD, '.claude', 'memory', 'feedback'))) {
375
- // If not initialized, ensure global fallback exists
376
- const projectName = path.basename(CWD) || 'default';
377
- const globalDir = path.join(HOME, '.rlhf', 'projects', projectName);
378
- if (!fs.existsSync(globalDir)) {
379
- fs.mkdirSync(globalDir, { recursive: true });
380
- }
595
+ function watchCmd() {
596
+ const args = parseArgs(process.argv.slice(3));
597
+ const { watch, once } = require(path.join(PKG_ROOT, 'scripts', 'jsonl-watcher'));
598
+ const sourceFilter = args.source || undefined;
599
+ if (args.once) {
600
+ once(sourceFilter);
601
+ } else {
602
+ watch(sourceFilter);
381
603
  }
604
+ }
382
605
 
606
+ function status() {
607
+ const statusDashboard = require(path.join(PKG_ROOT, 'scripts', 'status-dashboard'));
608
+ const { getFeedbackPaths } = require(path.join(PKG_ROOT, 'scripts', 'feedback-loop'));
609
+ const { FEEDBACK_DIR } = getFeedbackPaths();
610
+ const data = statusDashboard.generateStatus(FEEDBACK_DIR);
611
+ // printDashboard writes directly to stdout when run as main;
612
+ // for CLI we call the same renderer
613
+ statusDashboard.printDashboard
614
+ ? statusDashboard.printDashboard(data)
615
+ : console.log(JSON.stringify(data, null, 2));
616
+ }
617
+
618
+ function serve() {
383
619
  // Start MCP server over stdio
384
620
  const mcpServer = path.join(PKG_ROOT, 'adapters', 'mcp', 'server-stdio.js');
385
621
  const { startStdioServer } = require(mcpServer);
386
622
  startStdioServer();
623
+ // Start watcher as a background daemon alongside MCP server
624
+ try {
625
+ const { watch } = require(path.join(PKG_ROOT, 'scripts', 'jsonl-watcher'));
626
+ watch();
627
+ } catch (_) { /* watcher is non-critical */ }
387
628
  }
388
629
 
389
630
  function install() {
390
- console.log('Installing RLHF Feedback Loop as a global MCP skill...');
631
+ console.log('Installing MCP Memory Gateway as a global MCP skill...');
391
632
  const results = [
392
633
  setupClaude(),
393
634
  setupCodex(),
394
635
  setupGemini(),
395
- setupCursor()
636
+ setupCursor(),
637
+ setupAmp()
396
638
  ];
397
639
  const success = results.some(r => r === true);
398
640
  if (success) {
399
- console.log('\nSuccess! RLHF Feedback Loop is now available to your agents.');
641
+ console.log('\nSuccess! MCP Memory Gateway is now available to your agents.');
400
642
  console.log('Try asking your agent: "Capture positive feedback for this task"');
401
643
  } else {
402
- console.log('\nRLHF Feedback Loop is already configured.');
644
+ console.log('\nMCP Memory Gateway is already configured.');
403
645
  }
404
646
  }
405
647
 
648
+ function installMcp() {
649
+ const { installMcp: doInstall, parseFlags } = require(path.join(PKG_ROOT, 'scripts', 'install-mcp'));
650
+ const flags = parseFlags(process.argv.slice(3));
651
+ doInstall(flags);
652
+ }
653
+
406
654
  function startApi() {
407
655
  const serverPath = path.join(PKG_ROOT, 'src', 'api', 'server.js');
408
656
  try {
@@ -418,21 +666,28 @@ function help() {
418
666
  console.log('');
419
667
  console.log('Commands:');
420
668
  console.log(' init Scaffold .rlhf/ config + MCP server in current project');
669
+ console.log(' install-mcp Install RLHF MCP server into Claude Code settings (--project for local)');
421
670
  console.log(' serve Start MCP server (stdio) — for claude/codex/gemini mcp add');
422
671
  console.log(' capture [flags] Capture feedback (--feedback=up|down --context="..." --tags="...")');
423
672
  console.log(' stats Show feedback analytics + Revenue-at-Risk');
424
673
  console.log(' summary Human-readable feedback summary');
674
+ console.log(' model-fit Detect the current local embedding profile and write evidence report');
675
+ console.log(' risk [flags] Train or query the boosted local risk scorer');
425
676
  console.log(' export-dpo Export DPO training pairs (prompt/chosen/rejected JSONL)');
426
677
  console.log(' rules Generate prevention rules from repeated failures');
427
678
  console.log(' self-heal Run self-healing check and auto-fix');
428
- console.log(' pro Upgrade to Cloud Pro ($10/mo)');
429
- console.log(' prove [--target=X] Run proof harness (adapters|automation|attribution|lancedb|...)');
679
+ console.log(' pro Upgrade to Context Gateway ($10/mo)');
680
+ console.log(' prove [--target=X] Run proof harness (adapters|automation|attribution|lancedb|local-intelligence|...)');
681
+ console.log(' watch [flags] Watch .rlhf/ for external signals and ingest through pipeline (--once, --source=X)');
682
+ console.log(' status Show learning curve dashboard — approval trend + failure domains');
430
683
  console.log(' start-api Start the RLHF HTTPS API server');
431
684
  console.log(' help Show this help message');
432
685
  console.log('');
433
686
  console.log('Examples:');
434
687
  console.log(' npx rlhf-feedback-loop init');
435
688
  console.log(' npx rlhf-feedback-loop stats');
689
+ console.log(' npx rlhf-feedback-loop model-fit');
690
+ console.log(' npx rlhf-feedback-loop risk');
436
691
  console.log(' npx rlhf-feedback-loop pro');
437
692
  }
438
693
 
@@ -443,6 +698,9 @@ switch (COMMAND) {
443
698
  case 'install':
444
699
  install();
445
700
  break;
701
+ case 'install-mcp':
702
+ installMcp();
703
+ break;
446
704
  case 'serve':
447
705
  case 'mcp':
448
706
  serve();
@@ -457,6 +715,12 @@ switch (COMMAND) {
457
715
  case 'summary':
458
716
  summary();
459
717
  break;
718
+ case 'model-fit':
719
+ modelFit();
720
+ break;
721
+ case 'risk':
722
+ risk();
723
+ break;
460
724
  case 'export-dpo':
461
725
  case 'dpo':
462
726
  exportDpo();
@@ -473,6 +737,12 @@ switch (COMMAND) {
473
737
  case 'prove':
474
738
  prove();
475
739
  break;
740
+ case 'watch':
741
+ watchCmd();
742
+ break;
743
+ case 'status':
744
+ status();
745
+ break;
476
746
  case 'start-api':
477
747
  startApi();
478
748
  break;
@@ -1,10 +1,12 @@
1
1
  openapi: 3.1.0
2
2
  info:
3
- title: RLHF Feedback Loop API
3
+ title: MCP Memory Gateway API
4
4
  version: 1.2.0
5
5
  description: |
6
6
  Production API for feedback capture, schema-validated memory promotion,
7
7
  prevention rule generation, and DPO export.
8
+ Bare up/down signals are logged immediately, but the API returns
9
+ clarification_required until one sentence explains what worked or failed.
8
10
  servers:
9
11
  - url: https://rlhf-feedback-loop-710216278770.us-central1.run.app
10
12
  security:
@@ -32,13 +34,14 @@ components:
32
34
  type: string
33
35
  CaptureFeedbackRequest:
34
36
  type: object
35
- required: [signal, context]
37
+ required: [signal]
36
38
  properties:
37
39
  signal:
38
40
  type: string
39
41
  enum: [up, down, positive, negative]
40
42
  context:
41
43
  type: string
44
+ description: One-sentence reason describing what worked or failed
42
45
  whatWentWrong:
43
46
  type: string
44
47
  whatToChange:
@@ -155,7 +158,7 @@ paths:
155
158
  '200':
156
159
  description: Feedback accepted and promoted to memory
157
160
  '422':
158
- description: Feedback recorded but rejected for memory promotion
161
+ description: Feedback logged only; clarification required or promotion rejected
159
162
  '401':
160
163
  description: Unauthorized
161
164
  /v1/feedback/stats:
package/package.json CHANGED
@@ -1,8 +1,8 @@
1
1
  {
2
2
  "name": "rlhf-feedback-loop",
3
- "version": "0.6.11",
4
- "description": "RLHF-ready human feedback capture and DPO data pipeline for AI agents. Optimize agentic reliability with Feedback-Driven Development (FDD): capture preference signals, enforce guardrails, and export training pairs for downstream optimization.",
5
- "homepage": "https://github.com/IgorGanapolsky/rlhf-feedback-loop#readme",
3
+ "version": "0.6.13",
4
+ "description": "Feedback-Driven Development (FDD) for AI agents capture preference signals, steer behavior via Thompson Sampling, and export KTO/DPO training pairs for downstream fine-tuning.",
5
+ "homepage": "https://rlhf-feedback-loop-production.up.railway.app",
6
6
  "repository": {
7
7
  "type": "git",
8
8
  "url": "https://github.com/IgorGanapolsky/rlhf-feedback-loop.git"
@@ -28,39 +28,45 @@
28
28
  ],
29
29
  "type": "commonjs",
30
30
  "scripts": {
31
- "test": "npm run test:schema && npm run test:loop && npm run test:dpo && npm run test:api && npm run test:proof && npm run test:e2e && npm run test:rlaif && npm run test:attribution && npm run test:quality && npm run test:intelligence && npm run test:training-export && npm run test:deployment && npm run test:billing && npm run test:cli",
31
+ "test": "npm run test:schema && npm run test:loop && npm run test:dpo && npm run test:kto && npm run test:api && npm run test:proof && npm run test:e2e && npm run test:rlaif && npm run test:attribution && npm run test:quality && npm run test:intelligence && npm run test:training-export && npm run test:deployment && npm run test:workflow && npm run test:billing && npm run test:cli && npm run test:watcher",
32
32
  "test:e2e": "node --test tests/e2e-pipeline.test.js",
33
33
  "test:schema": "node scripts/feedback-schema.js --test",
34
34
  "test:loop": "node scripts/feedback-loop.js --test",
35
35
  "test:dpo": "node scripts/export-dpo-pairs.js --test",
36
- "test:api": "node --test tests/api-server.test.js tests/api-auth-config.test.js tests/mcp-server.test.js tests/adapters.test.js tests/openapi-parity.test.js tests/budget-guard.test.js tests/contextfs.test.js tests/mcp-policy.test.js tests/subagent-profiles.test.js tests/intent-router.test.js tests/rubric-engine.test.js tests/self-healing-check.test.js tests/self-heal.test.js tests/feedback-schema.test.js tests/thompson-sampling.test.js tests/feedback-sequences.test.js tests/diversity-tracking.test.js tests/vector-store.test.js tests/feedback-attribution.test.js tests/hybrid-feedback-context.test.js tests/loop-closure.test.js tests/code-reasoning.test.js tests/feedback-loop.test.js tests/feedback-inbox-read.test.js tests/feedback-to-memory.test.js tests/test-coverage.test.js tests/version-metadata.test.js",
37
- "test:proof": "node --test --test-concurrency=1 tests/prove-adapters.test.js tests/prove-automation.test.js tests/prove-attribution.test.js tests/prove-lancedb.test.js tests/prove-data-quality.test.js tests/prove-intelligence.test.js tests/prove-loop-closure.test.js tests/prove-subway-upgrades.test.js tests/prove-training-export.test.js",
36
+ "test:kto": "node --test tests/export-kto.test.js",
37
+ "test:api": "node --test tests/api-server.test.js tests/api-auth-config.test.js tests/mcp-server.test.js tests/adapters.test.js tests/openapi-parity.test.js tests/budget-guard.test.js tests/contextfs.test.js tests/mcp-policy.test.js tests/subagent-profiles.test.js tests/intent-router.test.js tests/rubric-engine.test.js tests/self-healing-check.test.js tests/self-heal.test.js tests/feedback-schema.test.js tests/thompson-sampling.test.js tests/feedback-sequences.test.js tests/diversity-tracking.test.js tests/vector-store.test.js tests/feedback-attribution.test.js tests/hybrid-feedback-context.test.js tests/loop-closure.test.js tests/code-reasoning.test.js tests/feedback-loop.test.js tests/feedback-inbox-read.test.js tests/feedback-to-memory.test.js tests/test-coverage.test.js tests/version-metadata.test.js tests/local-model-profile.test.js tests/risk-scorer.test.js tests/context-compaction.test.js tests/reminder-engine.test.js",
38
+ "test:proof": "node --test --test-concurrency=1 tests/prove-adapters.test.js tests/prove-automation.test.js tests/prove-attribution.test.js tests/prove-lancedb.test.js tests/prove-data-quality.test.js tests/prove-intelligence.test.js tests/prove-loop-closure.test.js tests/prove-subway-upgrades.test.js tests/prove-training-export.test.js tests/prove-local-intelligence.test.js tests/prove-workflow-contract.test.js",
38
39
  "test:rlaif": "node --test tests/rlaif-self-audit.test.js tests/dpo-optimizer.test.js tests/meta-policy.test.js",
39
40
  "test:attribution": "node --test tests/feedback-attribution.test.js tests/hybrid-feedback-context.test.js",
40
41
  "test:quality": "node --test tests/validate-feedback.test.js",
41
42
  "test:intelligence": "node --test tests/intelligence.test.js",
42
43
  "test:training-export": "node --test tests/training-export.test.js",
43
44
  "test:deployment": "node --test tests/deployment.test.js",
45
+ "test:workflow": "node --test tests/workflow-contract.test.js",
44
46
  "test:billing": "node --test tests/billing.test.js",
45
- "test:cli": "node --test tests/cli.test.js",
47
+ "test:cli": "node --test tests/cli.test.js tests/feedback-normalize.test.js tests/install-mcp.test.js",
46
48
  "test:coverage": "node scripts/test-coverage.js",
47
49
  "start:api": "node src/api/server.js",
48
50
  "start:mcp": "node adapters/mcp/server-stdio.js",
51
+ "mcp:install": "node scripts/install-mcp.js",
49
52
  "feedback:capture": "node .claude/scripts/feedback/capture-feedback.js",
50
53
  "feedback:stats": "node .claude/scripts/feedback/capture-feedback.js --stats",
51
54
  "feedback:summary": "node .claude/scripts/feedback/capture-feedback.js --summary",
52
55
  "feedback:rules": "node .claude/scripts/feedback/capture-feedback.js --rules",
53
56
  "feedback:export:dpo": "node scripts/export-dpo-pairs.js --from-local --output .claude/memory/feedback/dpo-pairs.jsonl",
57
+ "feedback:export:kto": "node scripts/export-kto-pairs.js --from-local --output .claude/memory/feedback/kto-pairs.jsonl",
54
58
  "budget:status": "node scripts/budget-guard.js --status",
55
59
  "diagrams:paperbanana": "bash scripts/generate-paperbanana-diagrams.sh",
56
60
  "prove:adapters": "node scripts/prove-adapters.js",
57
61
  "prove:automation": "node scripts/prove-automation.js",
62
+ "prove:workflow-contract": "node scripts/prove-workflow-contract.js",
58
63
  "prove:lancedb": "node scripts/prove-lancedb.js",
59
64
  "prove:rlaif": "node scripts/prove-rlaif.js",
60
65
  "prove:attribution": "node scripts/prove-attribution.js",
61
66
  "prove:data-quality": "node scripts/prove-data-quality.js",
62
67
  "prove:loop-closure": "node scripts/prove-loop-closure.js",
63
68
  "prove:intelligence": "node scripts/prove-intelligence.js",
69
+ "prove:local-intelligence": "node scripts/prove-local-intelligence.js",
64
70
  "prove:training-export": "node scripts/prove-training-export.js",
65
71
  "prove:v2-milestone": "node scripts/prove-v2-milestone.js",
66
72
  "feedback:export:pytorch": "node scripts/export-training.js --pytorch",
@@ -77,8 +83,14 @@
77
83
  "ml:incremental": "python3 scripts/train_from_feedback.py --incremental",
78
84
  "ml:reliability": "python3 scripts/train_from_feedback.py --reliability",
79
85
  "ml:sample": "python3 scripts/train_from_feedback.py --sample",
86
+ "ml:model-fit": "node scripts/local-model-profile.js",
87
+ "ml:risk": "node scripts/risk-scorer.js",
80
88
  "adk:consolidate": "node scripts/adk-consolidator.js",
81
- "adk:watch": "node scripts/adk-consolidator.js --watch"
89
+ "adk:watch": "node scripts/adk-consolidator.js --watch",
90
+ "pr:manage": "node scripts/pr-manager.js",
91
+ "watch": "node scripts/jsonl-watcher.js",
92
+ "status": "node scripts/status-dashboard.js",
93
+ "test:watcher": "node --test tests/jsonl-watcher.test.js"
82
94
  },
83
95
  "keywords": [
84
96
  "rlhf",
@@ -121,7 +133,8 @@
121
133
  "@google/genai": "^1.44.0",
122
134
  "@huggingface/transformers": "^3.8.1",
123
135
  "@lancedb/lancedb": "^0.26.2",
124
- "apache-arrow": "^18.1.0"
136
+ "apache-arrow": "^18.1.0",
137
+ "stripe": "^20.4.1"
125
138
  },
126
139
  "mcpName": "io.github.IgorGanapolsky/rlhf-feedback-loop"
127
140
  }