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/.claude-plugin/marketplace.json +2 -2
- package/.claude-plugin/plugin.json +1 -1
- package/.well-known/mcp/server-card.json +1 -1
- package/CHANGELOG.md +198 -0
- package/README.md +7 -6
- package/adapters/README.md +1 -1
- package/adapters/chatgpt/openapi.yaml +25 -0
- package/adapters/claude/.mcp.json +2 -2
- package/adapters/codex/config.toml +4 -4
- package/adapters/mcp/server-stdio.js +41 -2
- package/adapters/opencode/opencode.json +1 -1
- package/bin/cli.js +100 -10
- package/openapi/openapi.yaml +25 -0
- package/package.json +13 -3
- package/public/codex-plugin.html +277 -0
- package/public/dashboard.html +141 -13
- package/public/index.html +92 -34
- package/public/learn.html +13 -2
- package/public/lessons.html +5 -2
- package/public/pro.html +8 -1
- package/scripts/auto-wire-hooks.js +10 -5
- package/scripts/billing.js +503 -8
- package/scripts/contextfs.js +1 -1
- package/scripts/dashboard.js +236 -0
- package/scripts/feedback-loop.js +22 -0
- package/scripts/gates-engine.js +461 -7
- package/scripts/hook-runtime.js +42 -0
- package/scripts/llm-client.js +25 -10
- package/scripts/mailer/index.js +13 -0
- package/scripts/mailer/resend-mailer.js +350 -0
- package/scripts/mcp-config.js +13 -0
- package/scripts/published-cli.js +8 -0
- package/scripts/seo-gsd.js +118 -4
- package/scripts/statusline.sh +8 -0
- package/scripts/vector-store.js +21 -7
- package/src/api/server.js +112 -7
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 {
|
|
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 =
|
|
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,
|
|
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
|
-
//
|
|
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
|
-
|
|
1546
|
-
blockPatterns.forEach((p, i) =>
|
|
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 (_) { /*
|
|
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() {
|
package/openapi/openapi.yaml
CHANGED
|
@@ -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.
|
|
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>
|