thumbgate 1.35.0 → 1.37.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.
Files changed (196) hide show
  1. package/.agents/skills/cyberstrike-compare-not-clone/SKILL.md +36 -0
  2. package/.agents/skills/gitlab-sandbox-allowlist-not-trust/SKILL.md +77 -0
  3. package/.agents/skills/jit-harness-compare-not-clone/SKILL.md +34 -0
  4. package/.agents/skills/openui-catalog-compose-honesty/SKILL.md +64 -0
  5. package/.agents/skills/zvec-grep-compare-not-clone/SKILL.md +34 -0
  6. package/.claude-plugin/plugin.json +1 -1
  7. package/.well-known/llms.txt +1 -0
  8. package/.well-known/mcp/server-card.json +1 -1
  9. package/CONTRIBUTING.md +95 -0
  10. package/README.md +195 -632
  11. package/THIRD_PARTY_NOTICES.md +89 -0
  12. package/adapters/claude/.mcp.json +2 -2
  13. package/adapters/forge/forge.yaml +3 -3
  14. package/adapters/future-agi/.mcp.json +8 -0
  15. package/adapters/future-agi/FUTURE_AGI.md +23 -0
  16. package/adapters/future-agi/config.toml +3 -0
  17. package/adapters/future-agi/future-agi-bridge.js +9 -0
  18. package/adapters/future-agi/opencode.json +8 -0
  19. package/adapters/herdr/herdr-plugin.toml +18 -0
  20. package/adapters/mcp/server-stdio.js +238 -25
  21. package/adapters/opencode/opencode.json +1 -1
  22. package/adapters/workos/WORKOS.md +52 -0
  23. package/bin/cli.js +336 -3
  24. package/bin/futureagi-bridge +9 -0
  25. package/config/gate-templates.json +581 -4
  26. package/config/gates/actor-critic-audit.json +34 -0
  27. package/config/gates/default.json +9 -3
  28. package/config/gates/five-walls-governance.json +34 -0
  29. package/config/gates/future-agi-guardrails.json +34 -0
  30. package/config/gates/radware-threat-defense-2026.json +61 -0
  31. package/config/gates/simatree-data-governance.json +33 -0
  32. package/config/mcp-allowlists.json +4 -0
  33. package/config/merge-quality-checks.json +6 -0
  34. package/config/model-candidates.json +312 -29
  35. package/config/model-tiers.json +18 -0
  36. package/config/post-deploy-marketing-pages.json +10 -0
  37. package/config/progressive/01-wire-only.json +11 -0
  38. package/config/progressive/02-dashboard-empty-ok.json +10 -0
  39. package/config/progressive/03-one-lesson.json +10 -0
  40. package/config/progressive/04-warn-fires.json +11 -0
  41. package/config/progressive/05-strict-optional.json +11 -0
  42. package/config/progressive/README.md +15 -0
  43. package/config/schemas/broker-execution-receipt.schema.json +139 -0
  44. package/config/schemas/provider-execution-attestation-v1.schema.json +58 -0
  45. package/conformance/provider-attestation/vectors.json +320 -0
  46. package/docs/specs/provider-execution-attestation-v1.md +69 -0
  47. package/openapi/openapi.yaml +15 -0
  48. package/package.json +390 -148
  49. package/public/about.html +2 -2
  50. package/public/ai-malpractice-prevention.html +7 -7
  51. package/public/blog/a-10-dollar-vps-is-not-a-computer.html +143 -0
  52. package/public/blog/a-receipt-is-not-world-state.html +388 -0
  53. package/public/blog/git-at-agent-scale.html +374 -0
  54. package/public/blog/no-llm-in-the-gate.html +133 -0
  55. package/public/blog.html +80 -0
  56. package/public/case-studies.html +16 -1
  57. package/public/compare.html +28 -0
  58. package/public/diagnostic.html +216 -7
  59. package/public/docs/connectors.html +39 -0
  60. package/public/federal.html +2 -2
  61. package/public/founders.html +639 -0
  62. package/public/index.html +87 -9
  63. package/public/install.html +8 -8
  64. package/public/learn.html +39 -0
  65. package/public/numbers.html +2 -2
  66. package/public/peter.html +310 -0
  67. package/public/platform-partners.html +119 -0
  68. package/public/pricing.html +24 -3
  69. package/public/privacy.html +117 -0
  70. package/public/pro.html +17 -0
  71. package/public/support.html +62 -0
  72. package/public/terms.html +130 -0
  73. package/public/third-party-notices.html +95 -0
  74. package/public/yt.html +351 -0
  75. package/scripts/action-receipts.js +133 -3
  76. package/scripts/adaptive-governance-arena.js +349 -0
  77. package/scripts/admin-override.js +205 -0
  78. package/scripts/agent-action-inventory.js +869 -0
  79. package/scripts/agent-audit-trace.js +42 -2
  80. package/scripts/agent-egress-policy.js +1117 -0
  81. package/scripts/agent-memory-lifecycle.js +141 -2
  82. package/scripts/agent-operations-planner.js +441 -1
  83. package/scripts/agent-readiness.js +68 -0
  84. package/scripts/agent-security-central.js +647 -0
  85. package/scripts/allowlist-bridge-honesty.js +417 -0
  86. package/scripts/async-job-runner.js +102 -11
  87. package/scripts/audit-trail.js +212 -0
  88. package/scripts/billing.js +1 -1
  89. package/scripts/broker-execution-receipts.js +719 -0
  90. package/scripts/budget-aware-gates-proof.js +423 -0
  91. package/scripts/claude-feedback-sync.js +29 -3
  92. package/scripts/claw-harness-production.js +237 -0
  93. package/scripts/cli-schema.js +163 -1
  94. package/scripts/codex-runbook-flywheel.js +318 -0
  95. package/scripts/context-footprint.js +186 -0
  96. package/scripts/contextfs.js +143 -61
  97. package/scripts/dashboard.js +251 -32
  98. package/scripts/deepseek-v4-runtime-guardrails.js +72 -6
  99. package/scripts/docker-sandbox-planner.js +18 -0
  100. package/scripts/double-blind-eval-protocol.js +252 -0
  101. package/scripts/edotenv-rl-gateway.js +259 -0
  102. package/scripts/ensure-production-search-corpus.js +162 -0
  103. package/scripts/eval-holdout.js +311 -0
  104. package/scripts/feedback-aggregate.js +21 -2
  105. package/scripts/feedback-loop.js +87 -5
  106. package/scripts/feedback-quality.js +9 -0
  107. package/scripts/file-ledger-lock.js +4 -1
  108. package/scripts/financial-control-plane.js +41 -1
  109. package/scripts/find-dormant-requires.js +118 -0
  110. package/scripts/fs-utils.js +84 -8
  111. package/scripts/gates-engine.js +810 -63
  112. package/scripts/generate-case-study-outreach.js +24 -15
  113. package/scripts/git-at-scale.js +628 -0
  114. package/scripts/governance-conflict-audit.js +1650 -0
  115. package/scripts/governance-difficulty-curriculum.js +328 -0
  116. package/scripts/graphrag-retrieval.js +275 -0
  117. package/scripts/gurobi-optimizer.js +324 -0
  118. package/scripts/gurobi_optimizer.py +485 -0
  119. package/scripts/harness-selector.js +82 -1
  120. package/scripts/hidden-entry-points.js +284 -0
  121. package/scripts/human-escalation.js +199 -1
  122. package/scripts/hybrid-feedback-context.js +152 -19
  123. package/scripts/intent-governed-execution.js +602 -0
  124. package/scripts/intervention-policy.js +123 -20
  125. package/scripts/jit-harness-compose.js +628 -0
  126. package/scripts/jsonl-watcher.js +10 -0
  127. package/scripts/lesson-embedding-index.js +95 -12
  128. package/scripts/lesson-retrieval.js +105 -19
  129. package/scripts/local-model-profile.js +19 -2
  130. package/scripts/mailer/resend-mailer.js +1 -1
  131. package/scripts/matryoshka-embedding.js +235 -0
  132. package/scripts/mcp-oauth.js +42 -4
  133. package/scripts/mcp-session-handles.js +1016 -0
  134. package/scripts/mcp-wiring-doctor.js +314 -0
  135. package/scripts/memory-firewall.js +115 -2
  136. package/scripts/memory-scope-readiness.js +299 -0
  137. package/scripts/memory-vs-rag-route.js +161 -0
  138. package/scripts/model-tier-router.js +148 -21
  139. package/scripts/nvidia-specdecode-al-doctor.js +536 -0
  140. package/scripts/openui-catalog-compose-honesty.js +593 -0
  141. package/scripts/operational-integrity.js +19 -1
  142. package/scripts/override-audit.js +213 -0
  143. package/scripts/package-manager-honesty-doctor.js +458 -0
  144. package/scripts/pr-manager.js +63 -1
  145. package/scripts/prove-herdr-adapter.js +52 -0
  146. package/scripts/prove-memory-pyramid-and-symbolic-canvas.js +95 -0
  147. package/scripts/prove-workos.js +73 -0
  148. package/scripts/provider-attestation-conformance.js +192 -0
  149. package/scripts/provider-receipt-contract.js +136 -0
  150. package/scripts/qwen38-max-cost-optimizer.js +401 -0
  151. package/scripts/radware-threat-defense.js +280 -0
  152. package/scripts/rag-embedding-identity.js +221 -0
  153. package/scripts/rag-precision-guardrails.js +112 -2
  154. package/scripts/remote-feedback-capture.js +159 -0
  155. package/scripts/research-agent-harness.js +256 -0
  156. package/scripts/rsi-safety-hillclimb.js +200 -0
  157. package/scripts/rule-sprawl.js +188 -0
  158. package/scripts/schedule-manager.js +147 -0
  159. package/scripts/self-heal.js +8 -0
  160. package/scripts/session-lease.js +415 -0
  161. package/scripts/simatree-data-governance.js +347 -0
  162. package/scripts/slo-alert-engine.js +172 -7
  163. package/scripts/solver-parity.js +539 -0
  164. package/scripts/stealth-memory-injection-gate.js +333 -0
  165. package/scripts/switchyard-router.js +366 -0
  166. package/scripts/telemetry-analytics.js +84 -27
  167. package/scripts/temporal-decay-weighting.js +138 -0
  168. package/scripts/test-all.js +165 -0
  169. package/scripts/token-savings.js +42 -0
  170. package/scripts/tool-kpi-tracker.js +108 -5
  171. package/scripts/tool-registry.js +193 -5
  172. package/scripts/universal-claim-evaluator.js +14 -2
  173. package/scripts/vector-store.js +279 -9
  174. package/scripts/workflow-notebook.js +391 -0
  175. package/scripts/workflow-sentinel.js +111 -12
  176. package/scripts/workos-production-guard.js +260 -0
  177. package/scripts/workspace-search-route.js +515 -0
  178. package/server.json +2 -2
  179. package/src/agent-identity-boundary.js +76 -0
  180. package/src/agent-retrieval-cache.js +155 -0
  181. package/src/alert-noise-ledger.js +502 -0
  182. package/src/api/server.js +724 -153
  183. package/src/git-fast-cache.js +220 -0
  184. package/src/git-wal-sync.js +156 -0
  185. package/src/hash-anchored-edit.js +82 -0
  186. package/src/hermes-platform-protocol.js +475 -0
  187. package/src/hermes-sync-plane.js +241 -0
  188. package/src/index.js +30 -1
  189. package/src/iso42001-compliance-guard.js +97 -0
  190. package/src/latency-budget.js +244 -0
  191. package/src/mcp-writeguard.js +316 -0
  192. package/src/miminions-adapter.js +106 -0
  193. package/src/pipeline-compass.js +104 -0
  194. package/src/ppl-alert-pipeline.js +284 -0
  195. package/src/rendezvous-router.js +90 -0
  196. package/src/security-questionnaire.js +195 -0
@@ -0,0 +1,89 @@
1
+ # Third-Party Notices
2
+
3
+ This document lists the third-party open-source software and assets used in the
4
+ ThumbGate project (`thumbgate` npm package and related repositories).
5
+
6
+ The ThumbGate source code itself is released under the MIT License (see `LICENSE`).
7
+ The following notices are required by the respective upstream licenses.
8
+
9
+ ## Open-Source Dependencies
10
+
11
+ The following direct dependencies are bundled or used in ThumbGate runtime
12
+ services:
13
+
14
+ | Package | License | Publisher / Source |
15
+ | --- | --- | --- |
16
+ | `@anthropic-ai/sdk` | MIT | Anthropic, PBC |
17
+ | `@google/genai` | Apache-2.0 | Google LLC |
18
+ | `@lancedb/lancedb` | Apache-2.0 | LanceDB.com |
19
+ | `apache-arrow` | Apache-2.0 | Apache Software Foundation |
20
+ | `better-sqlite3` | MIT | Joshua Wise |
21
+ | `dotenv` | BSD-2-Clause | scottmotte / Motdotla, Inc. |
22
+ | `js-yaml` | MIT | Vitaly Puzrin |
23
+ | `playwright-core` | Apache-2.0 | Microsoft Corporation |
24
+ | `protobufjs` | Apache-2.0 / BSD-3-Clause | Daniel Wirtz |
25
+ | `stripe` | MIT | Stripe, Inc. |
26
+
27
+ The following development dependencies are used to build, test, and release
28
+ ThumbGate:
29
+
30
+ | Package | License | Publisher / Source |
31
+ | --- | --- | --- |
32
+ | `@changesets/changelog-github` | MIT | Thinkmill |
33
+ | `@changesets/cli` | MIT | Thinkmill |
34
+ | `@playwright/test` | Apache-2.0 | Microsoft Corporation |
35
+ | `c8` | MIT |bcoe / c8 contributors |
36
+ | `undici` | MIT | Matteo Collina |
37
+
38
+ Additional transitive dependencies are installed automatically by npm. A
39
+ complete machine-readable dependency tree can be generated by running:
40
+
41
+ ```bash
42
+ npm install -g license-checker
43
+ license-checker --direct 0 --out licenses.json
44
+ ```
45
+
46
+ ## Trademarks and Brand Attribution
47
+
48
+ ThumbGate® is an independent product. The following trademarks and brands are
49
+ owned by their respective owners and are referenced solely for compatibility
50
+ and nominative fair use:
51
+
52
+ - Anthropic, Claude, and Claude Code are trademarks of Anthropic, PBC.
53
+ - OpenAI, ChatGPT, and Codex are trademarks of OpenAI, Inc.
54
+ - Cursor is a trademark of Anysphere, Inc.
55
+ - GitHub is a trademark of GitHub, Inc.
56
+ - Google, Gemini, and Google Cloud Platform are trademarks of Google LLC.
57
+ - Perplexity is a trademark of Perplexity AI, Inc.
58
+ - Hermes Agent is a project by Nous Research.
59
+ - Model Context Protocol (MCP) is a protocol introduced by Anthropic, PBC.
60
+ - Nvidia is a trademark of Nvidia Corporation.
61
+ - Railway is a trademark of Railway Corporation.
62
+ - Stripe is a trademark of Stripe, Inc.
63
+ - Supabase is a trademark of Supabase, Inc.
64
+ - PostHog is a trademark of PostHog, Inc.
65
+ - Plausible is a trademark of Plausible Insights OÜ.
66
+
67
+ Use of any third-party mark in this documentation, marketing material, or code
68
+ does not imply affiliation with, endorsement by, or sponsorship from the trademark
69
+ owner.
70
+
71
+ ## Font and Asset Attribution
72
+
73
+ ThumbGate uses system and open-source fonts where applicable. Any brand icons,
74
+ diagrams, or demo media that are not original to ThumbGate are credited in the
75
+ `public/assets/` directory or in the asset metadata file where applicable.
76
+
77
+ ## Proprietary Boundary
78
+
79
+ The open-source `thumbgate` npm package (MIT licensed) covers the local CLI,
80
+ MCP server, and public adapters. Hosted cloud services, enterprise dashboards,
81
+ multi-tenant adapters, commercial policy-sync engines, and operational tooling
82
+ for `thumbgate.app` are proprietary and not licensed under the public repository
83
+ terms unless a separate written agreement is executed.
84
+
85
+ ## Updates
86
+
87
+ This file is updated as part of each release. If you believe an attribution is
88
+ missing or incorrect, please open an issue at:
89
+ https://github.com/IgorGanapolsky/ThumbGate/issues
@@ -2,13 +2,13 @@
2
2
  "mcpServers": {
3
3
  "thumbgate": {
4
4
  "command": "npx",
5
- "args": ["--yes", "--package", "thumbgate@1.35.0", "thumbgate", "serve"]
5
+ "args": ["--yes", "--package", "thumbgate@1.37.1", "thumbgate", "serve"]
6
6
  }
7
7
  },
8
8
  "hooks": {
9
9
  "preToolUse": {
10
10
  "command": "npx",
11
- "args": ["--yes", "--package", "thumbgate@1.35.0", "thumbgate", "gate-check"]
11
+ "args": ["--yes", "--package", "thumbgate@1.37.1", "thumbgate", "gate-check"]
12
12
  }
13
13
  }
14
14
  }
@@ -9,12 +9,12 @@ version: "1"
9
9
  skills:
10
10
  thumbgate-gate-check:
11
11
  description: "ThumbGate PreToolUse gate — blocks known-bad tool calls"
12
- command: "npx --yes --package thumbgate@1.35.0 thumbgate gate-check"
12
+ command: "npx --yes --package thumbgate@1.37.1 thumbgate gate-check"
13
13
  trigger: pre_tool_use
14
14
 
15
15
  thumbgate-feedback:
16
16
  description: "ThumbGate feedback capture — logs user prompt context"
17
- command: "npx --yes --package thumbgate@1.35.0 thumbgate hook-auto-capture"
17
+ command: "npx --yes --package thumbgate@1.37.1 thumbgate hook-auto-capture"
18
18
  trigger: user_prompt
19
19
 
20
20
  mcp:
@@ -23,6 +23,6 @@ mcp:
23
23
  args:
24
24
  - "--yes"
25
25
  - "--package"
26
- - "thumbgate@1.35.0"
26
+ - "thumbgate@1.37.1"
27
27
  - "thumbgate"
28
28
  - "serve"
@@ -0,0 +1,8 @@
1
+ {
2
+ "mcpServers": {
3
+ "thumbgate": {
4
+ "command": "npx",
5
+ "args": ["--yes", "--package", "thumbgate@1.37.1", "thumbgate", "serve"]
6
+ }
7
+ }
8
+ }
@@ -0,0 +1,23 @@
1
+ # Future AGI Integration Guide
2
+
3
+ > Bridging Open-Source Agent Evaluation, Simulation, and Tracing with Deterministic PreToolUse Guardrails.
4
+
5
+ ## Overview
6
+ Future AGI (`future-agi/future-agi`) provides an open-source platform collapsing simulation, evals, guardrails, tracing, gateway, and optimization into a single feedback loop.
7
+
8
+ **ThumbGate** acts as the **deterministic pre-action execution firewall** at the tool-call interface. When paired together:
9
+ 1. **Simulation to Gate Synthesis**: Adversarial test failures in Future AGI are compiled into fail-closed PreToolUse gates in ThumbGate.
10
+ 2. **Runtime Action Receipts**: Blocked mutations, tool calls, and human approvals in ThumbGate emit OTel spans back to Future AGI for continuous model optimization.
11
+
12
+ ## Model Candidates
13
+ - `future-agi/agentic-eval-v1`: Specialized evaluator model for multi-turn tool calling and groundedness verification.
14
+ - `future-agi/guardrail-scanner`: Sub-10ms scanner for prompt injection and PII detection.
15
+
16
+ ## Quickstart
17
+ ```bash
18
+ # Evaluate a tool call payload with the Future AGI simulation rubric:
19
+ npx --package=thumbgate futureagi-bridge --simulate '{"tool": "Bash", "command": "publish_release"}'
20
+
21
+ # Run the Doctor check on the Future AGI bridge:
22
+ npx --package=thumbgate futureagi-bridge --doctor
23
+ ```
@@ -0,0 +1,3 @@
1
+ [mcp.servers.thumbgate]
2
+ command = "npx"
3
+ args = ["--yes", "--package", "thumbgate@1.37.1", "thumbgate", "serve"]
@@ -0,0 +1,9 @@
1
+ 'use strict';
2
+
3
+ const { evaluatePayload, synthesizeSelfHealingGate, exportOtelSpan } = require('../../scripts/future-agi-evaluator.js');
4
+
5
+ module.exports = {
6
+ evaluatePayload,
7
+ synthesizeSelfHealingGate,
8
+ exportOtelSpan,
9
+ };
@@ -0,0 +1,8 @@
1
+ {
2
+ "mcpServers": {
3
+ "thumbgate": {
4
+ "command": "npx",
5
+ "args": ["--yes", "--package", "thumbgate@1.37.1", "thumbgate", "serve"]
6
+ }
7
+ }
8
+ }
@@ -0,0 +1,18 @@
1
+ [plugin]
2
+ id = "thumbgate-approvals"
3
+ name = "ThumbGate Approvals"
4
+ version = "1.37.1"
5
+ minHerdrVersion = "0.7.0"
6
+ description = "Pre-action governance, spend guard, and safety approval gates for multi-agent terminal sessions in Herdr."
7
+ platforms = ["linux", "macos", "windows"]
8
+ author = "ThumbGate"
9
+ homepage = "https://thumbgate.ai"
10
+ repository = "https://github.com/IgorGanapolsky/ThumbGate"
11
+ category = "Security & Governance"
12
+
13
+ [mcp_server]
14
+ command = "npx"
15
+ args = ["--yes", "--package", "thumbgate@1.37.1", "thumbgate", "serve"]
16
+
17
+ [mcp_server.env]
18
+ THUMBGATE_ENFORCE_ENTITLEMENTS = "1"
@@ -91,6 +91,12 @@ const {
91
91
  readTaskOutcomes,
92
92
  recordTaskOutcome,
93
93
  } = require('../../scripts/task-outcomes');
94
+ const {
95
+ appendReceiptToLedger,
96
+ readReceiptLedger,
97
+ reconcileReceiptChain,
98
+ verifyBrokerReceipt,
99
+ } = require('../../scripts/broker-execution-receipts');
94
100
  const {
95
101
  listEscalations,
96
102
  requestEscalation,
@@ -328,7 +334,7 @@ const {
328
334
  finalizeSession: finalizeFeedbackSession,
329
335
  } = require('../../scripts/feedback-session');
330
336
 
331
- const SERVER_INFO = { name: 'thumbgate-mcp', version: '1.35.0' };
337
+ const SERVER_INFO = { name: 'thumbgate-mcp', version: '1.37.1' };
332
338
  const COMMERCE_CATEGORIES = [
333
339
  'product_recommendation',
334
340
  'brand_compliance',
@@ -638,29 +644,37 @@ function buildContextPackResponse(args = {}) {
638
644
  maxItems: Number(args.maxItems || 8),
639
645
  maxChars: Number(args.maxChars || 6000),
640
646
  namespaces,
647
+ strategy: args.strategy || null,
648
+ contextEnvelope: args.contextEnvelope || null,
641
649
  });
642
- // Feed outcome-paired action receipts into the pack so an action->outcome
643
- // history is available alongside lessons/rules. Additive + guarded: a
644
- // receipt-store failure must never break context pack construction.
645
650
  try {
646
651
  const receiptEntries = buildReceiptContextEntries(args.query || '', Number(args.maxItems || 8));
647
652
  if (Array.isArray(receiptEntries) && receiptEntries.length && Array.isArray(pack.items)) {
648
653
  for (const entry of receiptEntries) {
654
+ if (pack.items.length >= pack.maxItems) break;
655
+ const receiptText = entry && entry.text ? String(entry.text) : '';
656
+ const receiptChars = `Action receipt outcome\n${receiptText}`.length;
657
+ if (pack.usedChars + receiptChars > pack.maxChars) continue;
649
658
  pack.items.push({
650
659
  id: `action-receipt_${entry && entry.score != null ? entry.score : ''}_${pack.items.length}`,
651
660
  namespace: 'action-receipts',
652
661
  title: 'Action receipt outcome',
653
- structuredContext: { rawContent: entry && entry.text ? String(entry.text) : '' },
662
+ structuredContext: { rawContent: receiptText },
663
+ provenance: { source: 'action-receipts', freshness: 'unknown' },
654
664
  tags: ['action-receipt', 'outcome-paired'],
655
665
  score: entry && typeof entry.score === 'number' ? entry.score : 0,
656
666
  });
667
+ pack.usedChars += receiptChars;
657
668
  }
658
669
  if (!Array.isArray(pack.namespaces)) pack.namespaces = [];
659
670
  if (!pack.namespaces.includes('action-receipts')) pack.namespaces.push('action-receipts');
671
+ if (pack.visibility) {
672
+ pack.visibility.itemCount = pack.items.length;
673
+ pack.visibility.remainingCharBudget = Math.max(pack.maxChars - pack.usedChars, 0);
674
+ pack.visibility.visibleTitles = pack.items.slice(0, 5).map((item) => item.title);
675
+ }
660
676
  }
661
- } catch {
662
- // ignore receipt enrichment failures
663
- }
677
+ } catch { /* ignore */ }
664
678
  return toTextResult(pack);
665
679
  }
666
680
 
@@ -772,13 +786,23 @@ function buildEstimateUncertaintyResponse(args = {}) {
772
786
  });
773
787
  }
774
788
 
775
- async function callTool(name, args = {}) {
789
+ async function callTool(name, args = {}, options = {}) {
776
790
  const attemptStartMs = Date.now();
777
791
  const activeProfile = getActiveMcpProfile();
792
+ const attribution = {
793
+ clientId: options.clientId || null,
794
+ sessionId: options.sessionId || null,
795
+ agentId: options.agentId || null,
796
+ serverName: options.serverName || 'mcp',
797
+ };
798
+ const trace = (outcome = {}) => recordMcpToolTrace(name, args, {
799
+ ...outcome,
800
+ ...attribution,
801
+ });
778
802
  try {
779
803
  assertToolAllowed(name, activeProfile);
780
804
  } catch (error) {
781
- recordMcpToolTrace(name, args, {
805
+ trace({
782
806
  success: false,
783
807
  category: 'profile_denied',
784
808
  evidence: [error.message],
@@ -788,7 +812,7 @@ async function callTool(name, args = {}) {
788
812
  }
789
813
  const capability = getToolCapability(name);
790
814
  if (!capability.available) {
791
- recordMcpToolTrace(name, args, {
815
+ trace({
792
816
  success: false,
793
817
  category: 'capability',
794
818
  evidence: capability.missingModules,
@@ -806,6 +830,55 @@ async function callTool(name, args = {}) {
806
830
  throw error;
807
831
  }
808
832
 
833
+ // WriteGuard: pre-action MCP governance (destructive pattern + tier policy).
834
+ // Runs before contract validation so schema gaps cannot bypass interdiction.
835
+ // Covers stdio tools/call and HTTP transport (both route through callTool).
836
+ if (process.env.THUMBGATE_DISABLE_MCP_WRITEGUARD !== '1') {
837
+ const { evaluateMcpCall } = require('../../src/mcp-writeguard');
838
+ const writeGuardReceipt = evaluateMcpCall(
839
+ {
840
+ server: attribution.serverName || 'mcp',
841
+ tool: name,
842
+ parameters: args || {},
843
+ context: {
844
+ user: attribution.agentId || process.env.THUMBGATE_AGENT_ID || process.env.USER || 'operator',
845
+ client: attribution.clientId || 'mcp-client',
846
+ sessionId: attribution.sessionId || process.env.THUMBGATE_SESSION_AGENT || 'default-session',
847
+ },
848
+ },
849
+ {
850
+ // Existing Semantic Firewall / gates own admin escalation UX.
851
+ // Destructive patterns still return decision=blocked.
852
+ allowAdmin: options.allowAdmin !== false
853
+ && process.env.THUMBGATE_WRITEGUARD_STRICT_ADMIN !== '1',
854
+ requireReviewForPrivileged: options.requireReviewForPrivileged === true
855
+ || process.env.THUMBGATE_WRITEGUARD_REQUIRE_REVIEW === '1',
856
+ },
857
+ );
858
+ if (writeGuardReceipt.decision === 'blocked' || writeGuardReceipt.decision === 'escalated') {
859
+ const err = new Error(
860
+ `Action blocked by WriteGuard [${writeGuardReceipt.decision}]: ${
861
+ writeGuardReceipt.reasons.join('; ') || writeGuardReceipt.decision
862
+ }`,
863
+ );
864
+ err.errorCategory = 'permission';
865
+ err.code = writeGuardReceipt.decision === 'blocked'
866
+ ? 'WRITEGUARD_BLOCKED'
867
+ : 'WRITEGUARD_ESCALATED';
868
+ err.isRetryable = false;
869
+ err.writeGuardReceipt = writeGuardReceipt;
870
+ trace({
871
+ success: false,
872
+ category: 'blocked',
873
+ evidence: writeGuardReceipt.reasons.length > 0
874
+ ? writeGuardReceipt.reasons
875
+ : [writeGuardReceipt.decision],
876
+ latencyMs: Date.now() - attemptStartMs,
877
+ });
878
+ throw err;
879
+ }
880
+ }
881
+
809
882
  // Validate tool input contract against schema
810
883
  const { TOOLS } = require('../../scripts/tool-registry');
811
884
  const toolDef = TOOLS.find(t => t.name === name);
@@ -816,7 +889,7 @@ async function callTool(name, args = {}) {
816
889
  const err = new Error(`Tool contract violation on '${name}': ${validation.errors.join('; ')}`);
817
890
  err.errorCategory = 'contract';
818
891
  err.isRetryable = false;
819
- recordMcpToolTrace(name, args, {
892
+ trace({
820
893
  success: false,
821
894
  category: 'contract',
822
895
  evidence: validation.errors,
@@ -826,13 +899,41 @@ async function callTool(name, args = {}) {
826
899
  }
827
900
  }
828
901
 
902
+ // Model-carried MCP session handles (InfoWorld correlation controls).
903
+ // Authorize whenever the model re-emits a handle, or when
904
+ // THUMBGATE_MCP_HANDLE_REQUIRED=1 forces handles on every tools/call.
905
+ if (process.env.THUMBGATE_DISABLE_MCP_SESSION_HANDLES !== '1') {
906
+ const {
907
+ authorizeMcpToolCall,
908
+ } = require('../../scripts/mcp-session-handles');
909
+ const handleAuth = authorizeMcpToolCall(name, args || {}, {
910
+ principalId: process.env.THUMBGATE_PRINCIPAL_ID || process.env.THUMBGATE_AGENT_ID || null,
911
+ tenantId: process.env.THUMBGATE_TENANT_ID || 'default',
912
+ });
913
+ if (handleAuth && handleAuth.allowed === false) {
914
+ const err = new Error(
915
+ `Action blocked by MCP session handle gate [${handleAuth.code}]: ${handleAuth.reason}`
916
+ );
917
+ err.errorCategory = 'permission';
918
+ err.code = handleAuth.code || 'SESSION_HANDLE_DENIED';
919
+ err.isRetryable = false;
920
+ trace({
921
+ success: false,
922
+ category: 'session_handle',
923
+ evidence: [handleAuth.code, handleAuth.reason],
924
+ latencyMs: Date.now() - attemptStartMs,
925
+ });
926
+ throw err;
927
+ }
928
+ }
929
+
829
930
  if (name !== 'workflow_sentinel' && process.env.THUMBGATE_DISABLE_MCP_FIREWALL !== '1') {
830
931
  const firewallResult = (await evaluateGatesAsync(name, args)) || evaluateSecretGuard({ tool_name: name, tool_input: args });
831
932
  if (firewallResult && firewallResult.decision === 'deny') {
832
933
  const err = new Error(`Action blocked by Semantic Firewall: ${firewallResult.message}`);
833
934
  err.errorCategory = 'permission';
834
935
  err.isRetryable = false;
835
- recordMcpToolTrace(name, args, {
936
+ trace({
836
937
  success: false,
837
938
  category: 'permission',
838
939
  evidence: [firewallResult.message],
@@ -846,7 +947,7 @@ async function callTool(name, args = {}) {
846
947
  try {
847
948
  result = await callToolInner(name, args);
848
949
  } catch (err) {
849
- recordMcpToolTrace(name, args, {
950
+ trace({
850
951
  success: false,
851
952
  category: err.errorCategory || 'execution',
852
953
  evidence: [err.code || err.message || 'tool execution failed'],
@@ -860,7 +961,7 @@ async function callTool(name, args = {}) {
860
961
  const err = new Error(`Structured output contract violation on '${name}': ${outputValidation.errors.join('; ')}`);
861
962
  err.errorCategory = 'output_contract';
862
963
  err.isRetryable = false;
863
- recordMcpToolTrace(name, args, {
964
+ trace({
864
965
  success: false,
865
966
  category: 'output_contract',
866
967
  evidence: outputValidation.errors,
@@ -868,7 +969,7 @@ async function callTool(name, args = {}) {
868
969
  });
869
970
  throw err;
870
971
  }
871
- recordMcpToolTrace(name, args, {
972
+ trace({
872
973
  success: true,
873
974
  category: 'success',
874
975
  evidence: [`tool completed in ${latencyMs}ms`],
@@ -896,17 +997,51 @@ function validateMcpToolOutput(toolDef, result) {
896
997
  return validateStructuredOutput(result.structuredContent, toolDef.outputSchema);
897
998
  }
898
999
 
1000
+ function resolveWriteRiskTierForTool(name) {
1001
+ try {
1002
+ const { TOOLS, inferWriteRiskTier } = require('../../scripts/tool-registry');
1003
+ const tool = TOOLS.find((candidate) => candidate.name === name);
1004
+ return inferWriteRiskTier(name, tool?.annotations || {});
1005
+ } catch {
1006
+ return null;
1007
+ }
1008
+ }
1009
+
899
1010
  function recordMcpToolTrace(name, args, outcome = {}) {
900
1011
  try {
1012
+ const category = outcome.category || 'unknown';
1013
+ // Policy / profile / session denials are WriteGuard "blocked"; execution
1014
+ // and contract failures stay "failed".
1015
+ const blockedCategories = new Set([
1016
+ 'blocked',
1017
+ 'denied',
1018
+ 'permission',
1019
+ 'session_handle',
1020
+ 'profile_denied',
1021
+ ]);
1022
+ const blocked = blockedCategories.has(category) || outcome.blocked === true;
1023
+ const kpiOutcome = blocked
1024
+ ? 'blocked'
1025
+ : (outcome.success === true ? 'successful' : 'failed');
1026
+ const writeRiskTier = outcome.writeRiskTier || resolveWriteRiskTierForTool(name);
1027
+ // KPI identity must come only from trusted transport/options metadata
1028
+ // (HTTP OAuth session, explicit callTool options). Never trust tool args —
1029
+ // callers can poison clientId/sessionId via schemas that allow extras.
901
1030
  recordToolCall({
902
1031
  toolName: name,
903
- serverName: 'mcp',
1032
+ serverName: outcome.serverName || 'mcp',
904
1033
  latencyMs: Number(outcome.latencyMs || 0),
905
1034
  success: outcome.success === true,
906
- agentId: args.agentId || args.processId || args.taskId || 'unknown',
1035
+ outcome: kpiOutcome,
1036
+ blocked,
1037
+ agentId: outcome.agentId || process.env.THUMBGATE_AGENT_ID || process.env.THUMBGATE_SESSION_AGENT || 'unknown',
1038
+ clientId: outcome.clientId || null,
1039
+ sessionId: outcome.sessionId || null,
1040
+ writeRiskTier,
907
1041
  metadata: {
908
- category: outcome.category || 'unknown',
1042
+ category,
909
1043
  traceId: args.traceId || args.taskId || null,
1044
+ writeRiskTier,
910
1045
  },
911
1046
  });
912
1047
  } catch {
@@ -1260,18 +1395,28 @@ async function callToolInner(name, args) {
1260
1395
  return toTextResult(formatUnifiedContext(ctx));
1261
1396
  }
1262
1397
  case 'satisfy_gate': {
1263
- if (!args.gate) {
1264
- throw new Error('gate is required');
1398
+ // Accept gate | gateId | gate_id — docs/block messages historically said gateId=
1399
+ // while the schema only lists `gate`, which deadlocked agents (2026-08-03).
1400
+ const gateName = args.gate || args.gateId || args.gate_id;
1401
+ if (!gateName) {
1402
+ throw new Error('gate is required (aliases: gateId, gate_id)');
1265
1403
  }
1266
- const entry = satisfyCondition(args.gate, args.evidence || '', args.structuredReasoning || null);
1267
- const result = { satisfied: true, gate: args.gate, ...entry };
1404
+ // Attribute the override to the MCP surface. Omitting this defaults the
1405
+ // audit record to 'cli', which would misreport every agent-driven unlock.
1406
+ const entry = satisfyCondition(
1407
+ gateName,
1408
+ args.evidence || '',
1409
+ args.structuredReasoning || null,
1410
+ { source: 'mcp', actor: args.actor || 'agent' },
1411
+ );
1412
+ const result = { satisfied: true, gate: gateName, ...entry };
1268
1413
  // Log structured reasoning to audit trail for learning
1269
1414
  if (args.structuredReasoning) {
1270
1415
  recordAuditEvent({
1271
1416
  toolName: 'satisfy_gate',
1272
- toolInput: { gate: args.gate },
1417
+ toolInput: { gate: gateName },
1273
1418
  decision: 'allow',
1274
- gateId: args.gate,
1419
+ gateId: gateName,
1275
1420
  message: `Gate satisfied with structured reasoning: ${args.structuredReasoning.conclusion || 'no conclusion'}`,
1276
1421
  source: 'structured-reasoning',
1277
1422
  });
@@ -1368,6 +1513,27 @@ async function callToolInner(name, args) {
1368
1513
  ? getReceiptForAction(args.actionId)
1369
1514
  : getRecentReceipts(Number(args.limit || 20)),
1370
1515
  );
1516
+ case 'verify_broker_execution_receipt':
1517
+ return toTextResult(verifyBrokerReceipt(args.receipt || args));
1518
+ case 'issue_broker_execution_receipt': {
1519
+ // Intentionally NOT on the default MCP allowlist. Even with a host key,
1520
+ // agent-facing sessions must not mint broker signatures. Brokers call the
1521
+ // library/CLI outside the agent tool surface.
1522
+ const error = new Error(
1523
+ 'issue_broker_execution_receipt is not available on the agent MCP surface. '
1524
+ + 'Credential-holding brokers must sign out-of-band via scripts/broker-execution-receipts.js.',
1525
+ );
1526
+ error.code = 'THUMBGATE_BROKER_ISSUE_NOT_ON_AGENT_SURFACE';
1527
+ throw error;
1528
+ }
1529
+ case 'record_broker_execution_receipt': {
1530
+ const receipt = args.receipt || args;
1531
+ return toTextResult(appendReceiptToLedger(receipt));
1532
+ }
1533
+ case 'get_broker_execution_receipts':
1534
+ return toTextResult(readReceiptLedger().slice(-Number(args.limit || 20)));
1535
+ case 'reconcile_broker_receipt_chain':
1536
+ return toTextResult(reconcileReceiptChain());
1371
1537
  case 'record_task_outcome':
1372
1538
  return toTextResult(recordTaskOutcome(args));
1373
1539
  case 'get_task_outcomes': {
@@ -1597,6 +1763,8 @@ async function callToolInner(name, args) {
1597
1763
  windowSize: args.windowSize,
1598
1764
  perEntryMaxChars: args.perEntryMaxChars,
1599
1765
  totalMaxChars: args.totalMaxChars,
1766
+ matryoshkaEmbedding: args.matryoshkaEmbedding !== false,
1767
+ matryoshkaOptions: args.matryoshkaOptions || undefined,
1600
1768
  }));
1601
1769
  case 'plan_agent_design_governance':
1602
1770
  return toTextResult(buildAgentDesignGovernancePlan(args));
@@ -1815,8 +1983,52 @@ function acquireLock() {
1815
1983
  return { lockFile, cleanupLock: () => {} };
1816
1984
  }
1817
1985
 
1986
+ /**
1987
+ * Register this MCP session as a first-class agent identity at startup.
1988
+ * Fulfills the registry's "called on MCP server startup" contract: a session
1989
+ * with an attributed id gets that id registered; a session without one gets a
1990
+ * generated id, exported via THUMBGATE_SESSION_AGENT so every audit record and
1991
+ * the gates-engine identity gate can attribute its tool calls. Best-effort by
1992
+ * design — identity bootstrap must never block or crash server start.
1993
+ */
1994
+ function registerSessionIdentity() {
1995
+ try {
1996
+ const { registerAgent, loadAgentRegistry, getRegistryPath } = require('../../scripts/audit-trail');
1997
+ const { withFileLedgerLock } = require('../../scripts/file-ledger-lock');
1998
+ const envId = process.env.THUMBGATE_SESSION_AGENT || process.env.THUMBGATE_AGENT_ID || null;
1999
+ // Check-then-append runs under the registry ledger lock: concurrent stdio
2000
+ // servers inheriting one session id must not both pass the existence check
2001
+ // and register duplicate rows. A busy lock throws into the catch below —
2002
+ // the session simply starts unregistered and the next startup retries.
2003
+ const finalId = withFileLedgerLock(`${getRegistryPath()}.lock`, () => {
2004
+ const alreadyRegistered = envId
2005
+ ? loadAgentRegistry().some((agent) => agent && agent.id === envId)
2006
+ : false;
2007
+ if (alreadyRegistered) return envId;
2008
+ const record = registerAgent({
2009
+ agentId: envId || undefined,
2010
+ source: 'mcp',
2011
+ metadata: { transport: 'stdio', pid: process.pid },
2012
+ });
2013
+ return record && record.id ? record.id : envId;
2014
+ });
2015
+ if (finalId && !process.env.THUMBGATE_SESSION_AGENT) {
2016
+ process.env.THUMBGATE_SESSION_AGENT = finalId;
2017
+ }
2018
+ // MCP tool telemetry (recordMcpToolTrace) attributes via THUMBGATE_AGENT_ID;
2019
+ // without this a generated identity would trace as agentId "unknown".
2020
+ if (finalId && !process.env.THUMBGATE_AGENT_ID) {
2021
+ process.env.THUMBGATE_AGENT_ID = finalId;
2022
+ }
2023
+ return finalId;
2024
+ } catch {
2025
+ return null;
2026
+ }
2027
+ }
2028
+
1818
2029
  function startStdioServer() {
1819
2030
  acquireLock();
2031
+ registerSessionIdentity();
1820
2032
 
1821
2033
  process.stdin.resume();
1822
2034
 
@@ -1894,6 +2106,7 @@ module.exports = {
1894
2106
  handleRequest,
1895
2107
  callTool,
1896
2108
  startStdioServer,
2109
+ registerSessionIdentity,
1897
2110
  acquireLock,
1898
2111
  toCaptureFeedbackTextResult,
1899
2112
  formatCorrectiveActionsReminder,
@@ -7,7 +7,7 @@
7
7
  "npx",
8
8
  "--yes",
9
9
  "--package",
10
- "thumbgate@1.35.0",
10
+ "thumbgate@1.37.1",
11
11
  "thumbgate",
12
12
  "serve"
13
13
  ],