thumbgate 1.5.8 → 1.7.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/bin/cli.js CHANGED
@@ -22,7 +22,14 @@ const fs = require('fs');
22
22
  const path = require('path');
23
23
  const crypto = require('crypto');
24
24
  const { execSync, execFileSync } = require('child_process');
25
- const { resolveMcpEntry } = require(path.join(__dirname, '..', 'scripts', 'mcp-config'));
25
+ const {
26
+ codexAutoUpdateCliEntry,
27
+ codexAutoUpdateMcpEntry,
28
+ isSourceCheckout,
29
+ publishedCliAvailable,
30
+ localMcpEntry,
31
+ resolveMcpEntry,
32
+ } = require(path.join(__dirname, '..', 'scripts', 'mcp-config'));
26
33
  const { trackEvent } = require(path.join(__dirname, '..', 'scripts', 'cli-telemetry'));
27
34
  const {
28
35
  cacheUpdateHookCommand,
@@ -215,11 +222,40 @@ function canonicalMcpEntry(scope = 'project') {
215
222
  });
216
223
  }
217
224
 
225
+ function canonicalCodexMcpEntry() {
226
+ const version = pkgVersion();
227
+ if (isSourceCheckout(PKG_ROOT) && !publishedCliAvailable(version)) {
228
+ return localMcpEntry(PKG_ROOT, 'home');
229
+ }
230
+ return codexAutoUpdateMcpEntry();
231
+ }
232
+
233
+ function canonicalCodexCliEntry(commandArgs) {
234
+ const version = pkgVersion();
235
+ if (isSourceCheckout(PKG_ROOT) && !publishedCliAvailable(version)) {
236
+ return {
237
+ command: 'node',
238
+ args: [path.join(PKG_ROOT, 'bin', 'cli.js'), ...commandArgs],
239
+ };
240
+ }
241
+ return codexAutoUpdateCliEntry(commandArgs);
242
+ }
243
+
218
244
  function mcpSectionBlock(name = MCP_SERVER_NAME, scope = 'project') {
219
245
  const entry = canonicalMcpEntry(scope);
220
246
  return `[mcp_servers.${name}]\ncommand = "${entry.command}"\nargs = ${formatTomlStringArray(entry.args)}\n`;
221
247
  }
222
248
 
249
+ function codexMcpSectionBlock(name = MCP_SERVER_NAME) {
250
+ const entry = canonicalCodexMcpEntry();
251
+ return `[mcp_servers.${name}]\ncommand = "${entry.command}"\nargs = ${formatTomlStringArray(entry.args)}\n`;
252
+ }
253
+
254
+ function codexPreToolHookSectionBlock() {
255
+ const entry = canonicalCodexCliEntry(['gate-check']);
256
+ return `[hooks.pre_tool_use]\ncommand = "${entry.command}"\nargs = ${formatTomlStringArray(entry.args)}\n`;
257
+ }
258
+
223
259
  function mcpSectionRegex(name) {
224
260
  return new RegExp(
225
261
  `^\\[mcp_servers\\.${escapeRegExp(name)}\\]\\n(?:^(?!\\[).*(?:\\n|$))*`,
@@ -227,8 +263,16 @@ function mcpSectionRegex(name) {
227
263
  );
228
264
  }
229
265
 
266
+ function tomlSectionRegex(name) {
267
+ return new RegExp(
268
+ `^\\[${escapeRegExp(name)}\\]\\n(?:^(?!\\[).*(?:\\n|$))*`,
269
+ 'm'
270
+ );
271
+ }
272
+
230
273
  function upsertCodexServerConfig(content) {
231
- const canonicalBlock = mcpSectionBlock(MCP_SERVER_NAME, 'home');
274
+ const canonicalBlock = codexMcpSectionBlock(MCP_SERVER_NAME);
275
+ const canonicalHookBlock = codexPreToolHookSectionBlock();
232
276
  const sections = MCP_SERVER_NAMES.map((name) => ({
233
277
  name,
234
278
  regex: mcpSectionRegex(name),
@@ -241,7 +285,7 @@ function upsertCodexServerConfig(content) {
241
285
  const prefix = content.trimEnd();
242
286
  return {
243
287
  changed: true,
244
- content: `${prefix}${prefix ? '\n\n' : ''}${canonicalBlock}`,
288
+ content: `${prefix}${prefix ? '\n\n' : ''}${canonicalBlock}\n${canonicalHookBlock}`,
245
289
  };
246
290
  }
247
291
 
@@ -272,6 +316,19 @@ function upsertCodexServerConfig(content) {
272
316
  changed = true;
273
317
  }
274
318
 
319
+ const hookRegex = tomlSectionRegex('hooks.pre_tool_use');
320
+ if (hookRegex.test(nextContent)) {
321
+ const current = nextContent.match(hookRegex)[0];
322
+ if (current !== canonicalHookBlock) {
323
+ nextContent = nextContent.replace(hookRegex, canonicalHookBlock);
324
+ changed = true;
325
+ }
326
+ } else {
327
+ const prefix = nextContent.trimEnd();
328
+ nextContent = `${prefix}${prefix ? '\n\n' : ''}${canonicalHookBlock}`;
329
+ changed = true;
330
+ }
331
+
275
332
  return {
276
333
  changed,
277
334
  content: nextContent.endsWith('\n') ? nextContent : `${nextContent}\n`,
@@ -387,11 +444,10 @@ function setupClaude() {
387
444
 
388
445
  function setupCodex() {
389
446
  const configPath = path.join(HOME, '.codex', 'config.toml');
390
- const block = mcpSectionBlock(MCP_SERVER_NAME, 'home');
391
447
  let configChanged = false;
392
448
  if (!fs.existsSync(configPath)) {
393
449
  fs.mkdirSync(path.dirname(configPath), { recursive: true });
394
- fs.writeFileSync(configPath, block);
450
+ fs.writeFileSync(configPath, upsertCodexServerConfig('').content);
395
451
  console.log(' Codex: created ~/.codex/config.toml');
396
452
  configChanged = true;
397
453
  } else {
@@ -1535,19 +1591,53 @@ function sessionStart() {
1535
1591
  const { refreshStatuslineCache } = require(path.join(PKG_ROOT, 'scripts', 'hook-thumbgate-cache-updater'));
1536
1592
  refreshStatuslineCache(analyzeFeedback());
1537
1593
 
1538
- // Surface gate-program.md active rules so the agent starts aware of what is blocked.
1594
+ // Build a top-level <system-reminder> block that Claude Code's SessionStart
1595
+ // hook surfaces to the agent as first-class context — not buried stderr.
1596
+ // Contract: emit JSON `{hookSpecificOutput:{hookEventName:"SessionStart",
1597
+ // additionalContext:"..."}}` to stdout. Supported by Claude Code v0.4+.
1598
+ const reminderLines = [];
1599
+
1600
+ // Active hard-block rules from gate-program.md
1539
1601
  try {
1540
1602
  const { readGateProgram, extractBlockPatterns } = require(path.join(PKG_ROOT, 'scripts', 'meta-agent-loop'));
1541
1603
  const gateProgram = readGateProgram();
1542
1604
  if (gateProgram) {
1543
1605
  const blockPatterns = extractBlockPatterns(gateProgram);
1544
1606
  if (blockPatterns.length > 0) {
1545
- process.stderr.write('\n[ThumbGate] Active hard-block rules from gate-program.md:\n');
1546
- blockPatterns.forEach((p, i) => process.stderr.write(` ${i + 1}. ${p}\n`));
1547
- process.stderr.write('\n');
1607
+ reminderLines.push('Active ThumbGate hard-block rules:');
1608
+ blockPatterns.forEach((p, i) => reminderLines.push(` ${i + 1}. ${p}`));
1548
1609
  }
1549
1610
  }
1550
- } catch (_) { /* gate-program awareness is best-effort */ }
1611
+ } catch (_) { /* non-critical */ }
1612
+
1613
+ // Top high-risk tags — force agent to see them at session start, not opt-in
1614
+ try {
1615
+ const { getRiskSummary } = require(path.join(PKG_ROOT, 'scripts', 'risk-scorer'));
1616
+ const summary = getRiskSummary();
1617
+ if (summary && Array.isArray(summary.highRiskTags) && summary.highRiskTags.length > 0) {
1618
+ if (reminderLines.length > 0) reminderLines.push('');
1619
+ reminderLines.push('Top high-risk tags from prior failures:');
1620
+ summary.highRiskTags.slice(0, 5).forEach((bucket, i) => {
1621
+ const key = bucket && (bucket.key || bucket.tag);
1622
+ const score = bucket && (bucket.risk || bucket.score || bucket.riskScore);
1623
+ if (key) reminderLines.push(` ${i + 1}. ${key} (risk=${score || '?'})`);
1624
+ });
1625
+ }
1626
+ } catch (_) { /* non-critical */ }
1627
+
1628
+ if (reminderLines.length > 0) {
1629
+ const additionalContext = ['<system-reminder>', ...reminderLines, '</system-reminder>'].join('\n');
1630
+ try {
1631
+ process.stdout.write(JSON.stringify({
1632
+ hookSpecificOutput: {
1633
+ hookEventName: 'SessionStart',
1634
+ additionalContext,
1635
+ },
1636
+ }));
1637
+ } catch (_) { /* stdout write failure is non-critical */ }
1638
+ // Legacy stderr fallback for older Claude Code versions
1639
+ process.stderr.write('\n[ThumbGate] ' + reminderLines.join('\n[ThumbGate] ') + '\n');
1640
+ }
1551
1641
  }
1552
1642
 
1553
1643
  function installMcp() {
@@ -779,6 +779,31 @@ paths:
779
779
  additionalProperties: true
780
780
  '401':
781
781
  description: Unauthorized
782
+ /v1/dashboard/review-state:
783
+ get:
784
+ operationId: getDashboardReviewState
785
+ responses:
786
+ '200':
787
+ description: Persisted dashboard review checkpoint and the current delta since that checkpoint
788
+ content:
789
+ application/json:
790
+ schema:
791
+ type: object
792
+ additionalProperties: true
793
+ '401':
794
+ description: Unauthorized
795
+ post:
796
+ operationId: markDashboardReviewed
797
+ responses:
798
+ '200':
799
+ description: Persist and return the current dashboard review checkpoint
800
+ content:
801
+ application/json:
802
+ schema:
803
+ type: object
804
+ additionalProperties: true
805
+ '401':
806
+ description: Unauthorized
782
807
  /v1/dashboard/render-spec:
783
808
  get:
784
809
  operationId: getDashboardRenderSpec
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "thumbgate",
3
- "version": "1.5.8",
3
+ "version": "1.7.0",
4
4
  "description": "Self-improving agent governance: type thumbs-up or thumbs-down on any AI agent action. ThumbGate turns every mistake into a prevention rule and blocks the pattern from repeating. One thumbs-down, never again. 33 pre-action gates, budget enforcement, and self-protection for Claude Code, Cursor, Codex, Gemini CLI, and Amp.",
5
5
  "homepage": "https://thumbgate-production.up.railway.app",
6
6
  "repository": {
@@ -36,6 +36,7 @@
36
36
  "config/",
37
37
  "openapi/",
38
38
  "public/blog.html",
39
+ "public/codex-plugin.html",
39
40
  "public/compare.html",
40
41
  "public/dashboard.html",
41
42
  "public/guide.html",
@@ -126,6 +127,8 @@
126
127
  "scripts/lesson-synthesis.js",
127
128
  "scripts/license.js",
128
129
  "scripts/llm-client.js",
130
+ "scripts/mailer/index.js",
131
+ "scripts/mailer/resend-mailer.js",
129
132
  "scripts/local-model-profile.js",
130
133
  "scripts/managed-lesson-agent.js",
131
134
  "scripts/mcp-config.js",
@@ -248,7 +251,7 @@
248
251
  "trace:eval": "node scripts/decision-trace.js eval",
249
252
  "social:reply-monitor": "node scripts/social-reply-monitor.js",
250
253
  "social:reply-monitor:dry": "node scripts/social-reply-monitor.js --dry-run",
251
- "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:operational-integrity && npm run test:workflow && npm run test:billing && npm run test:cli && npm run test:watcher && npm run test:autoresearch && npm run test:ops && npm run test:session-analyzer && npm run test:tessl && npm run test:gates && npm run test:evoskill && npm run test:gates-hardening && npm run test:workers && npm run test:social-analytics && npm run test:memalign && npm run test:xmemory-lite && npm run test:filesystem-search && npm run test:zernio && npm run test:post-video && npm run test:post-everywhere-instagram && npm run test:obsidian-export && npm run test:lesson-db && npm run test:lesson-rotation && npm run test:memory-dedup && npm run test:feedback-quality && npm run test:sync-version && npm run test:check-congruence && npm run test:tool-registry && npm run test:feedback-to-rules && npm run test:memory-firewall && npm run test:belief-update && npm run test:hosted-config && npm run test:operational-summary && npm run test:operator-key-auth && npm run test:cloudflare-sandbox && npm run test:mcp-config && npm run test:plan-gate && npm run test:pulse && npm run test:semantic-layer && npm run test:data-pipeline && npm run test:optimize-context && npm run test:principle-extractor && npm run test:analytics-window && npm run test:funnel-analytics && npm run test:experiment-tracker && npm run test:build-metadata && npm run test:context-engine && npm run test:hf-papers && npm run test:marketing-experiment && npm run test:seo-gsd && npm run test:verify-run && npm run test:export-dpo-pairs && npm run test:export-hf-dataset && npm run test:license && npm run test:bot-detector && npm run test:postinstall && npm run test:funnel-invariants && npm run test:cli-telemetry && npm run test:pro-parity && npm run test:model-tier-router && npm run test:computer-use-firewall && npm run test:skill-exporter && npm run test:statusline && npm run test:evolution && npm run test:org-dashboard && npm run test:multi-hop-recall && npm run test:synthetic-dpo && npm run test:thumbgate-skill && npm run test:learn-hub && npm run test:feedback-fallback && npm run test:metaclaw && npm run test:server-lock && npm run test:control-tower && npm run test:pii-scanner && npm run test:data-governance && npm run test:lesson-inference && npm run test:semantic-dedup && npm run test:fs-utils && npm run test:cli-schema && npm run test:explore && npm run test:lesson-reranker && npm run test:lesson-retrieval && npm run test:cross-encoder && npm run test:reflector-agent && npm run test:feedback-session && npm run test:feedback-history-distiller && npm run test:hallucination-detector && npm run test:history-distiller && npm run test:predictive-insights && npm run test:prove-predictive-insights && npm run test:statusbar-cli && npm run test:generate-instagram-card && npm run test:instagram-thumbgate-post && npm run test:publish-instagram-thumbgate && npm run test:lesson-synthesis && npm run test:background-governance && npm run test:memory-migration && npm run test:prompt-dlp && npm run test:ephemeral-store && npm run test:agent-security && npm run test:skill-progressive && npm run test:per-step-scoring && npm run test:weekly-auto-post && npm run test:social-post-hourly && npm run test:social-quality-gate && npm run test:a2ui-engine && npm run test:gate-satisfy && npm run test:money-watcher && npm run test:budget && npm run test:quick-start && npm run test:utm && npm run test:product-feedback && npm run test:feedback-root-consolidator && npm run test:engagement-audit && npm run test:install-growth-automation && npm run test:publish-thumbgate-launch && npm run test:reconcile-thumbgate-campaign && npm run test:reddit-publisher && npm run test:schedule-thumbgate-campaign && npm run test:social-reply-monitor && npm run test:sync-launch-assets && npm run test:ai-search-visibility && npm run test:perplexity && npm run test:security-scanner && npm run test:llm-client && npm run test:managed-lesson-agent && npm run test:self-distill && npm run test:meta-agent && npm run test:harness-selector && npm run test:thumbgate-bench && npm run test:seo-guides && npm run test:enforcement-loop && npm run test:cli-agent-experience && npm run test:bot-detection && npm run test:checkout-bot-guard && npm run test:session-health && npm run test:session-episodes && npm run test:spec-gate && npm run test:decision-trace && npm run test:dashboard-insights && npm run test:prompt-eval && npm run test:demo-voiceover && npm run test:gate-coherence && npm run test:gate-eval && npm run test:high-roi && npm run test:public-static-assets && npm run test:token-savings && npm run test:workflow-gate-checkpoint && npm run test:lesson-export-import && npm run test:landing-page-claims && npm run test:dashboard-deeplink-e2e && npm run test:public-package-parity && npm run test:token-savings-dashboard && npm run test:cursor-wiring",
254
+ "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:operational-integrity && npm run test:workflow && npm run test:billing && npm run test:cli && npm run test:watcher && npm run test:autoresearch && npm run test:ops && npm run test:session-analyzer && npm run test:tessl && npm run test:gates && npm run test:evoskill && npm run test:gates-hardening && npm run test:workers && npm run test:social-analytics && npm run test:memalign && npm run test:xmemory-lite && npm run test:filesystem-search && npm run test:zernio && npm run test:platform-limits && npm run test:post-video && npm run test:post-everywhere-instagram && npm run test:obsidian-export && npm run test:lesson-db && npm run test:lesson-rotation && npm run test:memory-dedup && npm run test:feedback-quality && npm run test:sync-version && npm run test:check-congruence && npm run test:tool-registry && npm run test:feedback-to-rules && npm run test:memory-firewall && npm run test:belief-update && npm run test:hosted-config && npm run test:operational-summary && npm run test:operator-key-auth && npm run test:cloudflare-sandbox && npm run test:mcp-config && npm run test:plan-gate && npm run test:pulse && npm run test:semantic-layer && npm run test:data-pipeline && npm run test:optimize-context && npm run test:principle-extractor && npm run test:analytics-window && npm run test:funnel-analytics && npm run test:experiment-tracker && npm run test:build-metadata && npm run test:context-engine && npm run test:hf-papers && npm run test:marketing-experiment && npm run test:seo-gsd && npm run test:verify-run && npm run test:export-dpo-pairs && npm run test:export-hf-dataset && npm run test:license && npm run test:bot-detector && npm run test:postinstall && npm run test:funnel-invariants && npm run test:cli-telemetry && npm run test:pro-parity && npm run test:model-tier-router && npm run test:computer-use-firewall && npm run test:skill-exporter && npm run test:statusline && npm run test:evolution && npm run test:org-dashboard && npm run test:multi-hop-recall && npm run test:synthetic-dpo && npm run test:thumbgate-skill && npm run test:learn-hub && npm run test:feedback-fallback && npm run test:metaclaw && npm run test:server-lock && npm run test:control-tower && npm run test:pii-scanner && npm run test:data-governance && npm run test:lesson-inference && npm run test:semantic-dedup && npm run test:fs-utils && npm run test:cli-schema && npm run test:explore && npm run test:lesson-reranker && npm run test:lesson-retrieval && npm run test:cross-encoder && npm run test:reflector-agent && npm run test:feedback-session && npm run test:feedback-history-distiller && npm run test:hallucination-detector && npm run test:history-distiller && npm run test:predictive-insights && npm run test:prove-predictive-insights && npm run test:statusbar-cli && npm run test:generate-instagram-card && npm run test:instagram-thumbgate-post && npm run test:publish-instagram-thumbgate && npm run test:lesson-synthesis && npm run test:background-governance && npm run test:memory-migration && npm run test:prompt-dlp && npm run test:ephemeral-store && npm run test:agent-security && npm run test:skill-progressive && npm run test:per-step-scoring && npm run test:weekly-auto-post && npm run test:social-post-hourly && npm run test:social-quality-gate && npm run test:a2ui-engine && npm run test:gate-satisfy && npm run test:money-watcher && npm run test:budget && npm run test:quick-start && npm run test:utm && npm run test:product-feedback && npm run test:feedback-root-consolidator && npm run test:engagement-audit && npm run test:install-growth-automation && npm run test:publish-thumbgate-launch && npm run test:reconcile-thumbgate-campaign && npm run test:reddit-publisher && npm run test:schedule-thumbgate-campaign && npm run test:social-reply-monitor && npm run test:sync-launch-assets && npm run test:ai-search-visibility && npm run test:perplexity && npm run test:security-scanner && npm run test:llm-client && npm run test:managed-lesson-agent && npm run test:self-distill && npm run test:meta-agent && npm run test:harness-selector && npm run test:thumbgate-bench && npm run test:seo-guides && npm run test:enforcement-loop && npm run test:cli-agent-experience && npm run test:bot-detection && npm run test:checkout-bot-guard && npm run test:session-health && npm run test:session-episodes && npm run test:spec-gate && npm run test:decision-trace && npm run test:dashboard-insights && npm run test:prompt-eval && npm run test:demo-voiceover && npm run test:gate-coherence && npm run test:gate-eval && npm run test:high-roi && npm run test:public-static-assets && npm run test:token-savings && npm run test:workflow-gate-checkpoint && npm run test:lesson-export-import && npm run test:landing-page-claims && npm run test:dashboard-deeplink-e2e && npm run test:public-package-parity && npm run test:token-savings-dashboard && npm run test:cursor-wiring && npm run test:pretooluse-injection && npm run test:recent-corrective-context && npm run test:durability-step && npm run test:mailer && npm run test:brand-assets && npm run test:enforcement-teeth",
252
255
  "test:session-health": "node --test tests/session-health-sensor.test.js",
253
256
  "test:session-episodes": "node --test tests/session-episode-store.test.js",
254
257
  "test:spec-gate": "node --test tests/spec-gate.test.js",
@@ -380,6 +383,8 @@
380
383
  "social:poll:zernio": "node scripts/social-analytics/pollers/zernio.js",
381
384
  "social:publish:zernio": "node scripts/social-analytics/publishers/zernio.js",
382
385
  "test:zernio": "node --test tests/zernio-integration.test.js",
386
+ "test:platform-limits": "node --test tests/platform-limits.test.js",
387
+ "test:durability-step": "node --test tests/durability-step.test.js",
383
388
  "test:post-video": "node --test tests/post-video.test.js",
384
389
  "test:post-everywhere-instagram": "node --test tests/post-everywhere-instagram.test.js",
385
390
  "test:license": "node --test tests/license.test.js",
@@ -489,7 +494,12 @@
489
494
  "prepare": "bash bin/install-hooks.sh >/dev/null 2>&1 || true",
490
495
  "install:hooks": "bash bin/install-hooks.sh",
491
496
  "test:token-savings-dashboard": "node --test tests/token-savings-dashboard.test.js",
492
- "test:cursor-wiring": "node --test tests/cursor-wiring.test.js"
497
+ "test:cursor-wiring": "node --test tests/cursor-wiring.test.js",
498
+ "test:pretooluse-injection": "node --test tests/pretooluse-lesson-injection.test.js",
499
+ "test:recent-corrective-context": "node --test tests/recent-corrective-actions-context.test.js",
500
+ "test:mailer": "node --test tests/mailer.test.js tests/billing-webhook-email.test.js",
501
+ "test:brand-assets": "node --test tests/brand-assets.test.js",
502
+ "test:enforcement-teeth": "node --test tests/enforcement-teeth.test.js"
493
503
  },
494
504
  "keywords": [
495
505
  "mcp",
@@ -0,0 +1,277 @@
1
+ <!DOCTYPE html>
2
+ <html lang="en">
3
+ <head>
4
+ <meta charset="UTF-8">
5
+ <meta name="viewport" content="width=device-width, initial-scale=1.0">
6
+ <title>ThumbGate for Codex - Auto-Updating MCP Plugin</title>
7
+ <script defer data-domain="thumbgate-production.up.railway.app" src="https://plausible.io/js/script.js"></script>
8
+ <meta name="description" content="Install ThumbGate for Codex with an auto-updating MCP plugin, Pre-Action Gates, thumbs-up/down feedback memory, and a local-first Reliability Gateway.">
9
+ <meta name="keywords" content="ThumbGate Codex plugin, Codex MCP server, Codex pre-action gates, Codex guardrails, thumbgate latest, AI coding agent reliability">
10
+ <meta property="og:title" content="ThumbGate for Codex">
11
+ <meta property="og:description" content="Auto-updating MCP and hook launcher for Codex. One install, then ThumbGate resolves the latest npm runtime when Codex starts.">
12
+ <meta property="og:type" content="website">
13
+ <meta property="og:url" content="https://thumbgate-production.up.railway.app/codex-plugin">
14
+ <link rel="canonical" href="https://thumbgate-production.up.railway.app/codex-plugin">
15
+ <link rel="llm-context" href="/public/llm-context.md" type="text/markdown">
16
+
17
+ <script type="application/ld+json">
18
+ {
19
+ "@context": "https://schema.org",
20
+ "@type": "SoftwareApplication",
21
+ "name": "ThumbGate for Codex",
22
+ "applicationCategory": "DeveloperApplication",
23
+ "operatingSystem": "macOS, Linux, Windows with Node.js",
24
+ "description": "ThumbGate for Codex installs an MCP server and hook launcher that resolves thumbgate@latest at startup, captures thumbs-up/down feedback, and enforces Pre-Action Gates before risky agent actions run.",
25
+ "url": "https://thumbgate-production.up.railway.app/codex-plugin",
26
+ "downloadUrl": "https://github.com/IgorGanapolsky/ThumbGate/releases/latest/download/thumbgate-codex-plugin.zip",
27
+ "installUrl": "https://thumbgate-production.up.railway.app/codex-plugin",
28
+ "license": "https://opensource.org/licenses/MIT",
29
+ "creator": {
30
+ "@type": "Person",
31
+ "name": "Igor Ganapolsky",
32
+ "url": "https://github.com/IgorGanapolsky"
33
+ },
34
+ "offers": {
35
+ "@type": "Offer",
36
+ "price": "0",
37
+ "priceCurrency": "USD",
38
+ "description": "Free local Codex MCP setup with optional Pro dashboard upgrade."
39
+ }
40
+ }
41
+ </script>
42
+
43
+ <script type="application/ld+json">
44
+ {
45
+ "@context": "https://schema.org",
46
+ "@type": "FAQPage",
47
+ "mainEntity": [
48
+ {
49
+ "@type": "Question",
50
+ "name": "Does the ThumbGate Codex MCP server update automatically?",
51
+ "acceptedAnswer": {
52
+ "@type": "Answer",
53
+ "text": "The Codex MCP and hook launcher resolves thumbgate@latest when Codex starts. After a new npm release is published, restarting Codex lets the launcher install the latest runtime into the local ThumbGate runtime cache before it serves MCP or checks gates."
54
+ }
55
+ },
56
+ {
57
+ "@type": "Question",
58
+ "name": "Do Codex thumbs-up and thumbs-down signals work by default?",
59
+ "acceptedAnswer": {
60
+ "@type": "Answer",
61
+ "text": "ThumbGate works when the MCP server and hooks are enabled in Codex settings. The Codex settings page should show the thumbgate MCP server toggled on. Typed thumbs-up/down feedback with concrete context can then be captured and promoted into prevention rules."
62
+ }
63
+ },
64
+ {
65
+ "@type": "Question",
66
+ "name": "What is the fastest Codex install path?",
67
+ "acceptedAnswer": {
68
+ "@type": "Answer",
69
+ "text": "Run npx thumbgate init --agent codex for the automatic local setup, or use the standalone Codex plugin bundle if you want a portable plugin surface."
70
+ }
71
+ }
72
+ ]
73
+ }
74
+ </script>
75
+
76
+ <style>
77
+ *, *::before, *::after { box-sizing: border-box; }
78
+ :root {
79
+ --bg: #090a0d;
80
+ --panel: #12141a;
81
+ --panel-2: #171a21;
82
+ --line: #2b313c;
83
+ --text: #f1f5f9;
84
+ --muted: #9aa4b2;
85
+ --cyan: #22d3ee;
86
+ --green: #4ade80;
87
+ --red: #fb7185;
88
+ --yellow: #facc15;
89
+ }
90
+ body {
91
+ margin: 0;
92
+ background: var(--bg);
93
+ color: var(--text);
94
+ font-family: -apple-system, BlinkMacSystemFont, "Segoe UI", Roboto, sans-serif;
95
+ line-height: 1.65;
96
+ }
97
+ a { color: var(--cyan); }
98
+ nav {
99
+ display: flex;
100
+ align-items: center;
101
+ justify-content: space-between;
102
+ gap: 16px;
103
+ padding: 18px 28px;
104
+ border-bottom: 1px solid var(--line);
105
+ background: rgba(9, 10, 13, 0.88);
106
+ position: sticky;
107
+ top: 0;
108
+ z-index: 10;
109
+ backdrop-filter: blur(12px);
110
+ }
111
+ nav a { color: var(--muted); text-decoration: none; font-size: 14px; }
112
+ nav .brand { color: var(--text); font-weight: 800; }
113
+ .nav-links { display: flex; gap: 14px; flex-wrap: wrap; justify-content: flex-end; }
114
+ .wrap { width: min(1120px, calc(100% - 32px)); margin: 0 auto; }
115
+ .hero { padding: 72px 0 42px; }
116
+ .eyebrow { color: var(--green); font: 700 13px ui-monospace, SFMono-Regular, Menlo, monospace; text-transform: uppercase; letter-spacing: 0.08em; margin-bottom: 14px; }
117
+ h1 { font-size: clamp(38px, 7vw, 76px); line-height: 1.02; margin: 0 0 22px; letter-spacing: 0; max-width: 980px; }
118
+ .sub { color: var(--muted); font-size: 20px; max-width: 820px; margin: 0 0 28px; }
119
+ .actions { display: flex; gap: 12px; flex-wrap: wrap; align-items: center; }
120
+ .button {
121
+ display: inline-flex;
122
+ align-items: center;
123
+ justify-content: center;
124
+ border-radius: 8px;
125
+ padding: 13px 18px;
126
+ min-height: 48px;
127
+ text-decoration: none;
128
+ font-weight: 800;
129
+ border: 1px solid var(--line);
130
+ }
131
+ .button.primary { background: var(--cyan); color: #061014; border-color: var(--cyan); }
132
+ .button.secondary { background: var(--panel); color: var(--text); }
133
+ .terminal {
134
+ background: #050608;
135
+ border: 1px solid var(--line);
136
+ border-radius: 8px;
137
+ padding: 18px;
138
+ color: var(--green);
139
+ font: 14px ui-monospace, SFMono-Regular, Menlo, monospace;
140
+ overflow-x: auto;
141
+ margin: 28px 0 0;
142
+ }
143
+ .grid { display: grid; grid-template-columns: repeat(3, 1fr); gap: 18px; margin: 38px 0; }
144
+ .tile, .proof, .step, .faq {
145
+ background: var(--panel);
146
+ border: 1px solid var(--line);
147
+ border-radius: 8px;
148
+ padding: 22px;
149
+ }
150
+ .tile h3, .step h3, .faq h3 { margin: 0 0 10px; font-size: 19px; }
151
+ .tile p, .step p, .faq p { color: var(--muted); margin: 0; }
152
+ .split { display: grid; grid-template-columns: 1.1fr 0.9fr; gap: 28px; align-items: center; margin: 54px 0; }
153
+ .proof img { width: 100%; height: auto; display: block; border-radius: 8px; border: 1px solid var(--line); background: #050608; }
154
+ .caption { color: var(--muted); font-size: 14px; margin-top: 10px; }
155
+ h2 { font-size: 32px; line-height: 1.15; margin: 0 0 16px; letter-spacing: 0; }
156
+ .steps { display: grid; grid-template-columns: repeat(3, 1fr); gap: 18px; margin: 24px 0 44px; }
157
+ code {
158
+ background: rgba(34, 211, 238, 0.1);
159
+ border: 1px solid rgba(34, 211, 238, 0.2);
160
+ border-radius: 6px;
161
+ padding: 2px 6px;
162
+ color: var(--text);
163
+ }
164
+ .status { color: var(--yellow); }
165
+ .faq-list { display: grid; gap: 14px; margin: 24px 0 54px; }
166
+ footer { border-top: 1px solid var(--line); padding: 28px 0 42px; color: var(--muted); }
167
+ @media (max-width: 820px) {
168
+ nav { align-items: flex-start; flex-direction: column; }
169
+ .grid, .split, .steps { grid-template-columns: 1fr; }
170
+ .hero { padding-top: 44px; }
171
+ h1 { font-size: 38px; }
172
+ .sub { font-size: 18px; }
173
+ }
174
+ </style>
175
+ </head>
176
+ <body>
177
+ <nav>
178
+ <a class="brand" href="/">ThumbGate</a>
179
+ <div class="nav-links">
180
+ <a href="/guide">Setup Guide</a>
181
+ <a href="/dashboard">Dashboard</a>
182
+ <a href="https://github.com/IgorGanapolsky/ThumbGate" target="_blank" rel="noopener">GitHub</a>
183
+ <a href="https://www.npmjs.com/package/thumbgate" target="_blank" rel="noopener">npm</a>
184
+ </div>
185
+ </nav>
186
+
187
+ <main>
188
+ <section class="hero">
189
+ <div class="wrap">
190
+ <div class="eyebrow">Codex MCP plugin + Pre-Action Gates</div>
191
+ <h1>Give Codex a thumbs-down once. Block the repeat before it runs again.</h1>
192
+ <p class="sub">ThumbGate wires Codex into local-first feedback memory, MCP tools, and hook enforcement. The launcher resolves <code>thumbgate@latest</code> when Codex starts, so published npm fixes reach your active MCP server after a restart.</p>
193
+ <div class="actions">
194
+ <a class="button primary" href="https://github.com/IgorGanapolsky/ThumbGate/releases/latest/download/thumbgate-codex-plugin.zip" target="_blank" rel="noopener" onclick="if(typeof plausible==='function')plausible('codex_plugin_download')">Download Codex plugin</a>
195
+ <a class="button secondary" href="https://github.com/IgorGanapolsky/ThumbGate/blob/main/plugins/codex-profile/INSTALL.md" target="_blank" rel="noopener">Read install docs</a>
196
+ <a class="button secondary" href="/guide">Use CLI setup</a>
197
+ </div>
198
+ <pre class="terminal">$ npx thumbgate init --agent codex
199
+ # Writes ~/.codex/config.toml and ~/.codex/config.json
200
+ # MCP + hooks install thumbgate@latest before serving or checking gates</pre>
201
+ </div>
202
+ </section>
203
+
204
+ <section class="wrap grid" aria-label="Codex install promises">
205
+ <div class="tile">
206
+ <h3>Always-on when enabled</h3>
207
+ <p>If Codex settings show the <code>thumbgate</code> MCP server toggled on, Codex can call the local ThumbGate tools. Typed feedback still needs useful context before it becomes a durable rule.</p>
208
+ </div>
209
+ <div class="tile">
210
+ <h3>Latest runtime on restart</h3>
211
+ <p>The Codex launcher installs <code>thumbgate@latest</code> into <code>~/.thumbgate/runtime</code> before running MCP or gate checks. A new npm publish reaches Codex after the app restarts.</p>
212
+ </div>
213
+ <div class="tile">
214
+ <h3>Hard stop before action</h3>
215
+ <p>Pre-Action Gates evaluate commands, file edits, publishes, merges, and other high-risk actions before execution. Bad repeats get blocked before they burn time or tokens.</p>
216
+ </div>
217
+ </section>
218
+
219
+ <section class="wrap split">
220
+ <div>
221
+ <div class="eyebrow">What Codex gets</div>
222
+ <h2>MCP memory, hook checks, and a dashboard lane in the same install path.</h2>
223
+ <p>Use the standalone plugin when you want a portable Codex bundle. Use <code>npx thumbgate init --agent codex</code> when you want the shortest path on this machine. Both paths point at the same Reliability Gateway and the same npm runtime.</p>
224
+ <p class="status">The Codex launcher checks npm on startup. Restart Codex after a ThumbGate publish to let the MCP server and hook bundle pick up the latest runtime.</p>
225
+ </div>
226
+ <figure class="proof">
227
+ <img src="/assets/codex-thumbgate-statusbar-test.svg" alt="Codex terminal footer test lane with ThumbGate status and enforcement proof.">
228
+ <figcaption class="caption">Codex test lane after ThumbGate writes MCP, PreToolUse, UserPromptSubmit, PostToolUse, SessionStart, and the status line target.</figcaption>
229
+ </figure>
230
+ </section>
231
+
232
+ <section class="wrap">
233
+ <div class="eyebrow">Install flow</div>
234
+ <h2>Three paths. Same local gateway.</h2>
235
+ <div class="steps">
236
+ <div class="step">
237
+ <h3>1. Automatic setup</h3>
238
+ <p>Run <code>npx thumbgate init --agent codex</code>. ThumbGate writes the MCP server block and hook bundle into your Codex config files.</p>
239
+ </div>
240
+ <div class="step">
241
+ <h3>2. Standalone plugin</h3>
242
+ <p>Use the release bundle when Codex loads plugin surfaces directly. The bundle includes the manifest, MCP config, marketplace entry, and install docs.</p>
243
+ </div>
244
+ <div class="step">
245
+ <h3>3. Verify in Codex</h3>
246
+ <p>Open Codex settings, confirm <code>thumbgate</code> is toggled on, then restart Codex after npm releases to pick up the latest runtime.</p>
247
+ </div>
248
+ </div>
249
+ </section>
250
+
251
+ <section class="wrap">
252
+ <div class="eyebrow">Operator questions</div>
253
+ <h2>What happens when I click thumbs up or thumbs down?</h2>
254
+ <div class="faq-list">
255
+ <div class="faq">
256
+ <h3>Is the MCP server always on?</h3>
257
+ <p>It is on when the Codex MCP settings toggle is enabled and the configured command can start successfully. In the Codex app, the blue toggle next to <code>thumbgate</code> is the visible check.</p>
258
+ </div>
259
+ <div class="faq">
260
+ <h3>Does bare feedback become a rule?</h3>
261
+ <p>No. Bare "thumbs down" is intentionally too vague for memory promotion. Add one concrete sentence about what went wrong, the file, command, or behavior to block next time.</p>
262
+ </div>
263
+ <div class="faq">
264
+ <h3>Where is the direct asset?</h3>
265
+ <p>The standalone zip remains available at <a href="https://github.com/IgorGanapolsky/ThumbGate/releases/latest/download/thumbgate-codex-plugin.zip" target="_blank" rel="noopener">GitHub Releases</a>. This page is the human install surface so users do not land on an unexplained file download.</p>
266
+ </div>
267
+ </div>
268
+ </section>
269
+ </main>
270
+
271
+ <footer>
272
+ <div class="wrap">
273
+ ThumbGate MIT License. Pre-Action Gates, DPO-ready feedback, and local-first Codex enforcement.
274
+ </div>
275
+ </footer>
276
+ </body>
277
+ </html>