@shield-agent/kya 0.22.0 → 0.23.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.
Files changed (239) hide show
  1. package/.mcp.json +1 -1
  2. package/README.md +72 -30
  3. package/amp/settings.example.json +1 -1
  4. package/claude/claude_desktop_config.example.json +1 -1
  5. package/cline/cline_mcp_settings.example.json +1 -1
  6. package/copilot/mcp-config.example.json +1 -1
  7. package/dist/certify/attest.js +5 -5
  8. package/dist/certify/catalog.d.ts +1 -1
  9. package/dist/certify/catalog.js +3 -3
  10. package/dist/certify/context.js +1 -1
  11. package/dist/certify/evaluate.d.ts +2 -2
  12. package/dist/certify/evaluate.js +12 -12
  13. package/dist/certify/live.js +2 -2
  14. package/dist/certify/render.d.ts +1 -1
  15. package/dist/certify/render.js +10 -10
  16. package/dist/cli.d.ts +2 -2
  17. package/dist/cli.d.ts.map +1 -1
  18. package/dist/cli.js +49 -16
  19. package/dist/cli.js.map +1 -1
  20. package/dist/commands/certify.d.ts +1 -1
  21. package/dist/commands/certify.js +3 -3
  22. package/dist/commands/connect.d.ts +2 -2
  23. package/dist/commands/connect.js +22 -22
  24. package/dist/commands/dash.js +4 -4
  25. package/dist/commands/gate-serve.js +3 -3
  26. package/dist/commands/gate.d.ts +1 -1
  27. package/dist/commands/gate.js +16 -16
  28. package/dist/commands/hook.d.ts +1 -1
  29. package/dist/commands/hook.d.ts.map +1 -1
  30. package/dist/commands/hook.js +55 -18
  31. package/dist/commands/hook.js.map +1 -1
  32. package/dist/commands/import-traces.d.ts +16 -0
  33. package/dist/commands/import-traces.d.ts.map +1 -0
  34. package/dist/commands/import-traces.js +18 -0
  35. package/dist/commands/import-traces.js.map +1 -0
  36. package/dist/commands/init.js +1 -1
  37. package/dist/commands/investigate.d.ts +13 -0
  38. package/dist/commands/investigate.d.ts.map +1 -0
  39. package/dist/commands/investigate.js +22 -0
  40. package/dist/commands/investigate.js.map +1 -0
  41. package/dist/commands/notify-flush.d.ts +2 -0
  42. package/dist/commands/notify-flush.d.ts.map +1 -0
  43. package/dist/commands/notify-flush.js +47 -0
  44. package/dist/commands/notify-flush.js.map +1 -0
  45. package/dist/commands/orr.d.ts +3 -3
  46. package/dist/commands/orr.js +5 -5
  47. package/dist/commands/receipt-serve.d.ts +1 -1
  48. package/dist/commands/receipt-serve.js +1 -1
  49. package/dist/commands/serve-mcp.js +1 -1
  50. package/dist/commands/start.d.ts +2 -2
  51. package/dist/commands/start.js +20 -20
  52. package/dist/commands/stop.d.ts +1 -1
  53. package/dist/commands/stop.js +6 -6
  54. package/dist/commands/update.d.ts +19 -0
  55. package/dist/commands/update.d.ts.map +1 -0
  56. package/dist/commands/update.js +96 -0
  57. package/dist/commands/update.js.map +1 -0
  58. package/dist/commands/wire-hooks.d.ts +1 -1
  59. package/dist/commands/wire-hooks.js +14 -14
  60. package/dist/commands/wrap.d.ts.map +1 -1
  61. package/dist/commands/wrap.js +12 -7
  62. package/dist/commands/wrap.js.map +1 -1
  63. package/dist/config.d.ts +4 -4
  64. package/dist/config.js +5 -5
  65. package/dist/dash/dash.d.ts +1 -1
  66. package/dist/dash/dash.js +3 -3
  67. package/dist/dash/entitlement.d.ts +1 -1
  68. package/dist/dash/entitlement.js +1 -1
  69. package/dist/dash/render.js +2 -2
  70. package/dist/dash/screens/enterprise.js +9 -9
  71. package/dist/dash/screens/free.js +5 -5
  72. package/dist/diff-preview.d.ts +1 -1
  73. package/dist/diff-preview.js +2 -2
  74. package/dist/errors.d.ts +1 -1
  75. package/dist/errors.js +1 -1
  76. package/dist/fs-atomic.d.ts +1 -1
  77. package/dist/fs-atomic.js +2 -2
  78. package/dist/gate/binary.js +4 -4
  79. package/dist/gate/config-gen.d.ts +1 -1
  80. package/dist/gate/config-gen.js +7 -7
  81. package/dist/gate/config.d.ts +2 -2
  82. package/dist/gate/config.js +6 -6
  83. package/dist/gate/daemon.js +1 -1
  84. package/dist/gate/discover.d.ts +2 -2
  85. package/dist/gate/discover.js +7 -7
  86. package/dist/gate/hosted-sync.js +1 -1
  87. package/dist/gate/otlp-decode.d.ts +2 -2
  88. package/dist/gate/otlp-decode.js +2 -2
  89. package/dist/gate/otlp-receiver.d.ts +1 -1
  90. package/dist/gate/otlp-receiver.js +3 -3
  91. package/dist/host-reload.js +11 -11
  92. package/dist/host-tools.d.ts +1 -1
  93. package/dist/host-tools.js +1 -1
  94. package/dist/importers/formats.d.ts +26 -0
  95. package/dist/importers/formats.d.ts.map +1 -0
  96. package/dist/importers/formats.js +281 -0
  97. package/dist/importers/formats.js.map +1 -0
  98. package/dist/importers/index.d.ts +26 -0
  99. package/dist/importers/index.d.ts.map +1 -0
  100. package/dist/importers/index.js +122 -0
  101. package/dist/importers/index.js.map +1 -0
  102. package/dist/index.d.ts +1 -1
  103. package/dist/index.js +1 -1
  104. package/dist/investigate/detectors.d.ts +35 -0
  105. package/dist/investigate/detectors.d.ts.map +1 -0
  106. package/dist/investigate/detectors.js +277 -0
  107. package/dist/investigate/detectors.js.map +1 -0
  108. package/dist/investigate/fix-brief.d.ts +3 -0
  109. package/dist/investigate/fix-brief.d.ts.map +1 -0
  110. package/dist/investigate/fix-brief.js +88 -0
  111. package/dist/investigate/fix-brief.js.map +1 -0
  112. package/dist/investigate/incidents.d.ts +19 -0
  113. package/dist/investigate/incidents.d.ts.map +1 -0
  114. package/dist/investigate/incidents.js +84 -0
  115. package/dist/investigate/incidents.js.map +1 -0
  116. package/dist/investigate/index.d.ts +25 -0
  117. package/dist/investigate/index.d.ts.map +1 -0
  118. package/dist/investigate/index.js +46 -0
  119. package/dist/investigate/index.js.map +1 -0
  120. package/dist/mcp/protocol.d.ts +2 -2
  121. package/dist/mcp/protocol.d.ts.map +1 -1
  122. package/dist/mcp/protocol.js +39 -8
  123. package/dist/mcp/protocol.js.map +1 -1
  124. package/dist/mcp/stdio.d.ts +1 -1
  125. package/dist/mcp/stdio.js +2 -2
  126. package/dist/mcp-servers.d.ts +2 -2
  127. package/dist/mcp-servers.js +2 -2
  128. package/dist/node-upgrade.d.ts +2 -2
  129. package/dist/node-upgrade.js +9 -9
  130. package/dist/notify/dispatch.d.ts +20 -0
  131. package/dist/notify/dispatch.d.ts.map +1 -0
  132. package/dist/notify/dispatch.js +52 -0
  133. package/dist/notify/dispatch.js.map +1 -0
  134. package/dist/notify/index.d.ts +39 -0
  135. package/dist/notify/index.d.ts.map +1 -0
  136. package/dist/notify/index.js +119 -0
  137. package/dist/notify/index.js.map +1 -0
  138. package/dist/notify/sender.d.ts +56 -0
  139. package/dist/notify/sender.d.ts.map +1 -0
  140. package/dist/notify/sender.js +139 -0
  141. package/dist/notify/sender.js.map +1 -0
  142. package/dist/notify/templates.d.ts +33 -0
  143. package/dist/notify/templates.d.ts.map +1 -0
  144. package/dist/notify/templates.js +119 -0
  145. package/dist/notify/templates.js.map +1 -0
  146. package/dist/offline-evaluate.d.ts +2 -2
  147. package/dist/offline-evaluate.js +3 -3
  148. package/dist/orr/agentshield.d.ts +2 -2
  149. package/dist/orr/agentshield.js +4 -4
  150. package/dist/orr/scorecard.d.ts +1 -1
  151. package/dist/orr/scorecard.js +3 -3
  152. package/dist/otel/exporter.d.ts +64 -0
  153. package/dist/otel/exporter.d.ts.map +1 -0
  154. package/dist/otel/exporter.js +243 -0
  155. package/dist/otel/exporter.js.map +1 -0
  156. package/dist/parse-args.d.ts +1 -1
  157. package/dist/parse-args.js +1 -1
  158. package/dist/receipt/auto-open.d.ts +1 -1
  159. package/dist/receipt/auto-open.js +1 -1
  160. package/dist/receipt/daemon.d.ts +6 -6
  161. package/dist/receipt/daemon.js +15 -15
  162. package/dist/receipt/dashboard.d.ts +1 -1
  163. package/dist/receipt/dashboard.js +2 -2
  164. package/dist/receipt/embeddings.d.ts +15 -4
  165. package/dist/receipt/embeddings.d.ts.map +1 -1
  166. package/dist/receipt/embeddings.js +116 -35
  167. package/dist/receipt/embeddings.js.map +1 -1
  168. package/dist/receipt/enrich.d.ts +2 -2
  169. package/dist/receipt/enrich.js +5 -5
  170. package/dist/receipt/gate-card.d.ts +2 -2
  171. package/dist/receipt/gate-card.d.ts.map +1 -1
  172. package/dist/receipt/gate-card.js +3 -3
  173. package/dist/receipt/live-server.d.ts.map +1 -1
  174. package/dist/receipt/live-server.js +22 -8
  175. package/dist/receipt/live-server.js.map +1 -1
  176. package/dist/receipt/receipt-css.d.ts +1 -1
  177. package/dist/receipt/receipt-css.d.ts.map +1 -1
  178. package/dist/receipt/receipt-css.js +72 -11
  179. package/dist/receipt/receipt-css.js.map +1 -1
  180. package/dist/receipt/render-receipt.d.ts +1 -1
  181. package/dist/receipt/render-receipt.d.ts.map +1 -1
  182. package/dist/receipt/render-receipt.js +138 -87
  183. package/dist/receipt/render-receipt.js.map +1 -1
  184. package/dist/receipt/share.d.ts +2 -2
  185. package/dist/receipt/share.js +5 -5
  186. package/dist/sample-tools.d.ts +1 -1
  187. package/dist/sample-tools.js +1 -1
  188. package/dist/sandbox/mock-driver.d.ts +1 -1
  189. package/dist/sandbox/mock-driver.js +1 -1
  190. package/dist/sdk/a2a.d.ts +2 -2
  191. package/dist/sdk/a2a.js +1 -1
  192. package/dist/sdk/adapters/claude-agent.d.ts +1 -1
  193. package/dist/sdk/adapters/claude-agent.js +1 -1
  194. package/dist/sdk/adapters/langgraph.d.ts +1 -1
  195. package/dist/sdk/adapters/langgraph.js +1 -1
  196. package/dist/sdk/adapters/mastra.d.ts +1 -1
  197. package/dist/sdk/adapters/mastra.js +1 -1
  198. package/dist/sdk/adapters/openai-agents.d.ts +1 -1
  199. package/dist/sdk/adapters/openai-agents.js +1 -1
  200. package/dist/sdk/adapters/vercel-ai.d.ts +2 -2
  201. package/dist/sdk/adapters/vercel-ai.js +1 -1
  202. package/dist/sdk/govern.d.ts +2 -2
  203. package/dist/sdk/govern.js +3 -3
  204. package/dist/sdk/index.d.ts +1 -1
  205. package/dist/sdk/index.js +1 -1
  206. package/dist/showback/trail-usage.d.ts +30 -0
  207. package/dist/showback/trail-usage.d.ts.map +1 -0
  208. package/dist/showback/trail-usage.js +50 -0
  209. package/dist/showback/trail-usage.js.map +1 -0
  210. package/dist/sign/evidence-bundle.d.ts +6 -6
  211. package/dist/sign/evidence-bundle.js +5 -5
  212. package/dist/star-cta.d.ts +1 -1
  213. package/dist/star-cta.d.ts.map +1 -1
  214. package/dist/star-cta.js +3 -3
  215. package/dist/trail-summary.d.ts +1 -1
  216. package/dist/trail-summary.js +3 -3
  217. package/dist/trail.d.ts +8 -2
  218. package/dist/trail.d.ts.map +1 -1
  219. package/dist/trail.js +18 -5
  220. package/dist/trail.js.map +1 -1
  221. package/dist/update-check.d.ts +17 -0
  222. package/dist/update-check.d.ts.map +1 -0
  223. package/dist/update-check.js +134 -0
  224. package/dist/update-check.js.map +1 -0
  225. package/droid/README.md +1 -1
  226. package/droid/mcp.example.json +1 -1
  227. package/gemini/settings.example.json +1 -1
  228. package/grok/README.md +1 -1
  229. package/kilo/kilo.example.json +1 -1
  230. package/kimi/mcp.example.json +1 -1
  231. package/kiro/mcp.example.json +1 -1
  232. package/manifest.json +1 -1
  233. package/mastracode/mcp.example.json +1 -1
  234. package/mcp.json +1 -1
  235. package/openai/codex.config.example.toml +1 -1
  236. package/opencode/opencode.example.json +1 -1
  237. package/package.json +2 -2
  238. package/qwen/settings.example.json +1 -1
  239. package/server.json +2 -2
package/.mcp.json CHANGED
@@ -2,7 +2,7 @@
2
2
  "mcpServers": {
3
3
  "shield-kya": {
4
4
  "command": "npx",
5
- "args": ["--no-install", "@shield-agent/kya@0.22.0", "serve-mcp", "--stdio"],
5
+ "args": ["--no-install", "@shield-agent/kya@0.23.0", "serve-mcp", "--stdio"],
6
6
  "env": {
7
7
  "KYA_BASE_URL": "https://shield-agent.com",
8
8
  "KYA_API_KEY": "${KYA_API_KEY}",
package/README.md CHANGED
@@ -8,7 +8,7 @@
8
8
  [![X](https://img.shields.io/badge/X-%40coscosmico-000000?logo=x&logoColor=white)](https://x.com/coscosmico)
9
9
 
10
10
 
11
- **AI agents audit trail & traceability.** Every tool call your coding agents make — gated (Allow / Review / Deny), recorded on a live local dashboard, and certifiable against the Agent Trust Baseline. One command. Free forever under MIT.
11
+ **AI agents audit trail & traceability.** Every tool call your coding agents make - gated (Allow / Review / Deny), recorded on a live local dashboard, and certifiable against the Agent Trust Baseline. One command. Free forever under MIT.
12
12
 
13
13
  ```bash
14
14
  npm i -g @shield-agent/kya@latest && kya start
@@ -27,7 +27,7 @@ Walkthrough: [how you use it](https://shield-agent.com/how-kya-works#using).
27
27
  npx @shield-agent/kya@latest --help
28
28
  ```
29
29
 
30
- Requires **Node.js 24+** (`engines.node: >=24`). On an older Node the CLI offers to install 24 for you (via volta / fnm / nvm / brew), reinstall itself, and finish the command — declining just prints a warning and continues.
30
+ Requires **Node.js 24+** (`engines.node: >=24`). On an older Node the CLI offers to install 24 for you (via volta / fnm / nvm / brew), reinstall itself, and finish the command - declining just prints a warning and continues.
31
31
 
32
32
  It works with any host that speaks MCP or OpenAPI. Vertical packs are optional. Shield is the only policy decision point: this gate never auto-approves an irreversible side effect.
33
33
 
@@ -43,17 +43,17 @@ npm i -g @shield-agent/kya@latest && kya start
43
43
 
44
44
  Run it in your project directory. (From a clone of this repo, `./scripts/install-local.sh` replaces the npm install.)
45
45
 
46
- That **inits** `.kya/`, **wires** local MCP (`.mcp.json`, `mcp.json`, `.cursor/mcp.json` → `kya serve-mcp --stdio`), also **wires user-level configs for every installed host it detects** (`~/.claude.json`, `~/.kimi-code/`, `~/.grok/`, `~/.cursor/`, …), and **opens** the live activity report. The report runs in the background — you get your terminal back; `kya stop` stops it, `kya receipt --open` reopens it. Cursor, Kiro, Qwen, Amp, Droid, Cline, and Grok pick the server up live with no restart (Kimi: just a new session); Claude Code, Codex, OpenCode, Gemini, Copilot CLI, and Kilo CLI load it on next launch — `claude --resume` keeps your conversation.
46
+ That **inits** `.kya/`, **wires** local MCP (`.mcp.json`, `mcp.json`, `.cursor/mcp.json` → `kya serve-mcp --stdio`), also **wires user-level configs for every installed host it detects** (`~/.claude.json`, `~/.kimi-code/`, `~/.grok/`, `~/.cursor/`, …), and **opens** the live activity report. The report runs in the background - you get your terminal back; `kya stop` stops it, `kya receipt --open` reopens it. Cursor, Kiro, Qwen, Amp, Droid, Cline, and Grok pick the server up live with no restart (Kimi: just a new session); Claude Code, Codex, OpenCode, Gemini, Copilot CLI, and Kilo CLI load it on next launch - `claude --resume` keeps your conversation.
47
47
 
48
- ![KYA report — live dashboard: Certify trust baseline, verdicts, analytics](https://raw.githubusercontent.com/The-Pixel-Boys/shield-kya/main/assets/report-overview.png)
48
+ ![KYA report - live dashboard: Certify trust baseline, verdicts, analytics](https://raw.githubusercontent.com/The-Pixel-Boys/shield-kya/main/assets/report-overview.png)
49
49
 
50
- ![Certify tab — full Agent Trust Baseline requirement table with evidence](https://raw.githubusercontent.com/The-Pixel-Boys/shield-kya/main/assets/report-certify.png)
50
+ ![Certify tab - full Agent Trust Baseline requirement table with evidence](https://raw.githubusercontent.com/The-Pixel-Boys/shield-kya/main/assets/report-certify.png)
51
51
 
52
- ![Activity tab — filterable agent tool-call feed with verdicts](https://raw.githubusercontent.com/The-Pixel-Boys/shield-kya/main/assets/report-activity.png)
52
+ ![Activity tab - filterable agent tool-call feed with verdicts](https://raw.githubusercontent.com/The-Pixel-Boys/shield-kya/main/assets/report-activity.png)
53
53
 
54
- ![Changes tab — what actually changed per session: files touched with redacted diff previews](https://raw.githubusercontent.com/The-Pixel-Boys/shield-kya/main/assets/report-changes.png)
54
+ ![Changes tab - what actually changed per session: files touched with redacted diff previews](https://raw.githubusercontent.com/The-Pixel-Boys/shield-kya/main/assets/report-changes.png)
55
55
 
56
- ![Gateway section — local MCP gate with listeners, routes, backends, policies, and a dry-run playground](https://raw.githubusercontent.com/The-Pixel-Boys/shield-kya/main/assets/report-gateway.png)
56
+ ![Gateway section - local MCP gate with listeners, routes, backends, policies, and a dry-run playground](https://raw.githubusercontent.com/The-Pixel-Boys/shield-kya/main/assets/report-gateway.png)
57
57
 
58
58
  <!-- Local paths kept in package for offline viewers: assets/report-overview.png, assets/report-certify.png, assets/report-activity.png, assets/report-changes.png, assets/report-gateway.png (legacy: assets/activity-receipt.png) -->
59
59
 
@@ -66,7 +66,7 @@ kya start --force # rewrite MCP blocks
66
66
 
67
67
  ## One command per host
68
68
 
69
- `kya start` covers Claude Code, Cursor, and any host that reads `.mcp.json` — and auto-wires the user-level config of every installed host it detects. For the rest, `kya connect` writes the host's own config dialect directly:
69
+ `kya start` covers Claude Code, Cursor, and any host that reads `.mcp.json` - and auto-wires the user-level config of every installed host it detects. For the rest, `kya connect` writes the host's own config dialect directly:
70
70
 
71
71
  ```bash
72
72
  kya connect claude # ~/.claude.json (merges mcpServers only)
@@ -78,7 +78,7 @@ kya connect qwen --project # project scope instead of global
78
78
  kya connect kiro --force # overwrite an existing shield-kya entry
79
79
  ```
80
80
 
81
- Connect merges — it never rewrites a host config it can't parse, and it keeps your other servers and keys. Supported hosts: `claude`, `grok`, `opencode`, `kilo`, `kiro`, `qwen`, `kimi`, `mastracode`, `amp`, `copilot`, `cursor`. Each wires `serve-mcp --stdio` with `KYA_OFFLINE=1` so the gate starts keyless; set `KYA_API_KEY` in the host env when you point at an authenticated plane.
81
+ Connect merges - it never rewrites a host config it can't parse, and it keeps your other servers and keys. Supported hosts: `claude`, `grok`, `opencode`, `kilo`, `kiro`, `qwen`, `kimi`, `mastracode`, `amp`, `copilot`, `cursor`. Each wires `serve-mcp --stdio` with `KYA_OFFLINE=1` so the gate starts keyless; set `KYA_API_KEY` in the host env when you point at an authenticated plane.
82
82
 
83
83
  Hosts without a `connect` target still work: `kya wrap --offline -- <agent command>` puts the same evaluate gate in front of any CLI. Per-host recipes with verify steps and troubleshooting live in [docs/hosts/](docs/hosts/).
84
84
 
@@ -88,7 +88,7 @@ Hosts without a `connect` target still work: `kya wrap --offline -- <agent comma
88
88
 
89
89
  Decision mapping: a local never-list **DENY** blocks the tool call (exit `2` plus `hookSpecificOutput` deny JSON with `permissionDecision: "deny"`). **ALLOW** and **REQUIRE_APPROVE** are recorded on the trail as advisory and the call proceeds. Manual wiring can pass `--strict` on the hook command to also block **REQUIRE_APPROVE**.
90
90
 
91
- Hooks are fail-open: any hook error or timeout allows the call. They are alerts plus local never-list enforcement, not the sole barrier — plane enforcement remains the MCP `kya.policy_evaluate` path. Hooks take effect in new sessions; all three hosts load hooks at session start.
91
+ Hooks are fail-open: any hook error or timeout allows the call. They are alerts plus local never-list enforcement, not the sole barrier - plane enforcement remains the MCP `kya.policy_evaluate` path. Hooks take effect in new sessions; all three hosts load hooks at session start.
92
92
 
93
93
  ```bash
94
94
  kya connect claude --hooks # wire the PreToolUse hook by hand
@@ -98,9 +98,9 @@ kya connect kimi --hooks
98
98
 
99
99
  ## Gate (local MCP gateway)
100
100
 
101
- `kya gate` puts one loopback-only listener (`127.0.0.1`, default port `3930`) in front of any MCP server you already use. Your host talks to the gateway; the gateway fans out to the real servers. Per-tool policy is generated from the [top-20 server taxonomy](docs/mcp-servers.md) — destructive names (`drop`/`truncate`/`purge`/`transfer`) and each server's ADMIN-tier tools are denied outright (and filtered from `tools/list`), everything else runs in observe mode: allowed, and audited. Every call is traced into the local trail and the live report, and can be forwarded as OTLP to the hosted intake.
101
+ `kya gate` puts one loopback-only listener (`127.0.0.1`, default port `3930`) in front of any MCP server you already use. Your host talks to the gateway; the gateway fans out to the real servers. Per-tool policy is generated from the [top-20 server taxonomy](docs/mcp-servers.md) - destructive names (`drop`/`truncate`/`purge`/`transfer`) and each server's ADMIN-tier tools are denied outright (and filtered from `tools/list`), everything else runs in observe mode: allowed, and audited. Every call is traced into the local trail and the live report, and can be forwarded as OTLP to the hosted intake.
102
102
 
103
- **Zero-touch:** `kya start` already does this for you. It scans your detected host configs for third-party MCP servers, imports them into `.kya/gateways.json` (recorded with an `importedFrom` provenance field), installs the gateway binary, starts the listener, and rewrites each source host so the imported servers route through the gateway — the original host config is preserved under `.kya/backups/` before anything is removed. Nothing found → nothing downloaded, no listener. Opt out with `kya start --no-gate` or `KYA_GATE=off`. If the binary download fails (offline, no network), `kya start` warns once and continues without the gateway — host configs stay untouched. The manual path below is still there when you want full control:
103
+ **Zero-touch:** `kya start` already does this for you. It scans your detected host configs for third-party MCP servers, imports them into `.kya/gateways.json` (recorded with an `importedFrom` provenance field), installs the gateway binary, starts the listener, and rewrites each source host so the imported servers route through the gateway - the original host config is preserved under `.kya/backups/` before anything is removed. Nothing found → nothing downloaded, no listener. Opt out with `kya start --no-gate` or `KYA_GATE=off`. If the binary download fails (offline, no network), `kya start` warns once and continues without the gateway - host configs stay untouched. The manual path below is still there when you want full control:
104
104
 
105
105
  ```bash
106
106
  kya gate init # scaffold .kya/gateways.json with ready-to-move recipes
@@ -111,7 +111,7 @@ kya connect claude --gate # point the host at the gateway (server key shield-k
111
111
  kya gate doctor # binary, config, listener health, loopback-only posture
112
112
  ```
113
113
 
114
- `kya gate stop` stops the supervisor and the binary with it. Honest notes: `kya gate setup` (and `kya start`'s auto-bootstrap, only when it found servers to govern) downloads the pinned gateway binary from our releases — nothing else downloads anything (the only other network use is the opt-in anonymous usage stats in [docs/telemetry.md](docs/telemetry.md), off unless you say yes); `run` never downloads. Observe mode means allowed calls are recorded, not blocked — the deny set above is the only hard stop, and plane enforcement stays with `kya.policy_evaluate`. `kya connect <host> --gate` covers the same hosts as plain `connect` — grok gets a `[mcp_servers.shield-kya-gate]` url table in its config.toml (Grok supports remote MCP servers over HTTP). Per-server tiers and recipes: [docs/mcp-servers.md](docs/mcp-servers.md).
114
+ `kya gate stop` stops the supervisor and the binary with it. Honest notes: `kya gate setup` (and `kya start`'s auto-bootstrap, only when it found servers to govern) downloads the pinned gateway binary from our releases - nothing else downloads anything (the only other network use is the opt-in anonymous usage stats in [docs/telemetry.md](docs/telemetry.md), off unless you say yes); `run` never downloads. Observe mode means allowed calls are recorded, not blocked - the deny set above is the only hard stop, and plane enforcement stays with `kya.policy_evaluate`. `kya connect <host> --gate` covers the same hosts as plain `connect` - grok gets a `[mcp_servers.shield-kya-gate]` url table in its config.toml (Grok supports remote MCP servers over HTTP). Per-server tiers and recipes: [docs/mcp-servers.md](docs/mcp-servers.md).
115
115
 
116
116
  ## Longer path (optional)
117
117
 
@@ -130,19 +130,19 @@ Install hub: [https://shield-agent.com/install](https://shield-agent.com/install
130
130
 
131
131
  ## Activity trail (global)
132
132
 
133
- One trail for all projects: `~/.kya/trail.jsonl` (`KYA_HOME` overrides `~`). `kya receipt --open` from any directory shows activity from every project. Each event carries its project folder name — the report adds a Projects rollup once two or more projects appear, and shows the project on each feed entry. Older per-project `<project>/.kya/trail.jsonl` files are still read and merged; no migration. The trail is capped at 1 MB (tail-read: oldest events drop away), shared across all projects.
133
+ One trail for all projects: `~/.kya/trail.jsonl` (`KYA_HOME` overrides `~`). `kya receipt --open` from any directory shows activity from every project. Each event carries its project folder name - the report adds a Projects rollup once two or more projects appear, and shows the project on each feed entry. Older per-project `<project>/.kya/trail.jsonl` files are still read and merged; no migration. The trail is capped at 1 MB (tail-read: oldest events drop away), shared across all projects.
134
134
 
135
- The report itself is a dashboard: a hero row on top (live **Certify** result, verdict mix, activity sparkline, showback) with tabbed sections below — **Overview** (analytics, sessions, reasons), **Certify** (the full live requirement table — every requirement grouped by domain with status, evidence, and attestation), **Activity** (the filterable event feed), **System** (wired hosts, sandboxes, ORR). Everything is one standalone offline HTML page (the live view adds a single external link: "Star on GitHub"); the live daemon from `kya start` re-renders it on every event.
135
+ The report itself is a dashboard: a hero row on top (live **Certify** result, verdict mix, activity sparkline, showback) with tabbed sections below - **Overview** (analytics, sessions, reasons), **Certify** (the full live requirement table - every requirement grouped by domain with status, evidence, and attestation), **Activity** (the filterable event feed), **System** (wired hosts, sandboxes, ORR). Everything is one standalone offline HTML page (the live view adds a single external link: "Star on GitHub"); the live daemon from `kya start` re-renders it on every event.
136
136
 
137
137
  ### Sharing a report
138
138
 
139
- `kya receipt --share` publishes a **redacted summary** of the current window (aggregate verdict counts, product and reason-code rollups, and the Certify status — no paths, no tool arguments, no session IDs) to shield-agent.com and prints a public URL (`/r/<id>`, expires after 7 days) anyone can open — every shared page carries the one-line install so readers can audit their own agents. Point it at a different collector with `--share-url <base>` or `KYA_SHARE_URL`.
139
+ `kya receipt --share` publishes a **redacted summary** of the current window (aggregate verdict counts, product and reason-code rollups, and the Certify status - no paths, no tool arguments, no session IDs) to shield-agent.com and prints a public URL (`/r/<id>`, expires after 7 days) anyone can open - every shared page carries the one-line install so readers can audit their own agents. Point it at a different collector with `--share-url <base>` or `KYA_SHARE_URL`.
140
140
 
141
141
  Sharing is a single attempt by design (storm-proof: no silent retries against the collector); `--share-retries <n>` (max 3) opts into bounded retries on 429/5xx/network failures with exponential backoff + jitter, honoring the server's `Retry-After`.
142
142
 
143
143
  ### Natural-language search
144
144
 
145
- The **Activity** search box understands plain English. It runs a hybrid of BM25 over tool IDs, summaries, reason codes, projects, and MCP server labels, plus optional local MiniLM semantic reranking. You can type things like `failed stripe transfers`, `files written by grok`, or `approval required production` — stopwords and stemming are handled automatically, and the same search works across the global trail.
145
+ The **Activity** search box understands plain English. It runs a hybrid of BM25 over tool IDs, summaries, reason codes, projects, and MCP server labels, plus optional local MiniLM semantic reranking. You can type things like `failed stripe transfers`, `files written by grok`, or `approval required production` - stopwords and stemming are handled automatically, and the same search works across the global trail.
146
146
 
147
147
  - Offline or `KYA_OFFLINE=1` keeps search purely lexical (no model download).
148
148
  - By default the live server downloads `BAAI/bge-small-en-v1.5` once into `~/.kya/models` and caches event vectors in `~/.kya/search-index.json`.
@@ -183,7 +183,7 @@ Tag sessions with `KYA_HOST=ide` or `KYA_HOST=runtime`. Same policy path either
183
183
  | `DO_NOT_TRACK` | No | `1` forces anonymous usage stats off, same as `KYA_TELEMETRY=0` |
184
184
 
185
185
  Gate mode can also be pinned in the project's `.kya/config.json`:
186
- `{"gateMode": "hold"}` or `{"gateMode": "offline"}` (exact values only —
186
+ `{"gateMode": "hold"}` or `{"gateMode": "offline"}` (exact values only -
187
187
  anything else is ignored). The gate itself (wrap / hook / eval) honors it
188
188
  with the precedence flags > env > config > observe, and `kya certify`
189
189
  reports through the same resolver, so a certify pass on gate mode always
@@ -204,7 +204,7 @@ MCP Registry entry: `server.json` plus package `mcpName` `io.github.The-Pixel-Bo
204
204
  "mcpServers": {
205
205
  "shield-kya": {
206
206
  "command": "npx",
207
- "args": ["--no-install", "@shield-agent/kya@0.22.0", "serve-mcp", "--stdio"],
207
+ "args": ["--no-install", "@shield-agent/kya@0.23.0", "serve-mcp", "--stdio"],
208
208
  "env": {
209
209
  "KYA_BASE_URL": "http://127.0.0.1:8090",
210
210
  "KYA_API_KEY": "${KYA_API_KEY}",
@@ -244,7 +244,7 @@ Offline evaluate by default (no network, no hosted plane); an explicit config ho
244
244
 
245
245
  ```bash
246
246
  # Prefer a preinstalled package (no registry auto-install):
247
- npx --no-install @shield-agent/kya@0.22.0 serve-mcp --stdio
247
+ npx --no-install @shield-agent/kya@0.23.0 serve-mcp --stdio
248
248
  # Or after npm i -g / local install:
249
249
  kya serve-mcp --stdio
250
250
  ```
@@ -255,7 +255,7 @@ Copy `claude/claude_desktop_config.example.json` into Claude Desktop MCP setting
255
255
 
256
256
  ## OpenAI (Codex / Responses)
257
257
 
258
- **Codex CLI / IDE:** copy `openai/codex.config.example.toml` into `~/.codex/config.toml`. Local stdio uses `npx --no-install @shield-agent/kya@0.22.0 serve-mcp --stdio`. Hosted Codex uses `url = "https://shield-agent.com/mcp"` with `bearer_token_env_var = "KYA_API_KEY"`.
258
+ **Codex CLI / IDE:** copy `openai/codex.config.example.toml` into `~/.codex/config.toml`. Local stdio uses `npx --no-install @shield-agent/kya@0.23.0 serve-mcp --stdio`. Hosted Codex uses `url = "https://shield-agent.com/mcp"` with `bearer_token_env_var = "KYA_API_KEY"`.
259
259
 
260
260
  **Responses API:** see `openai/responses-mcp.example.json` (`server_url` + `Authorization: Bearer <KYA_API_KEY>`).
261
261
 
@@ -277,8 +277,8 @@ Each ships a copy-paste example in its own directory; `kya connect <host>` write
277
277
 
278
278
  | Host | Setup | Example |
279
279
  |------|-------|---------|
280
- | Claude Code | `kya connect claude` (or `kya start`) | — (merges `~/.claude.json` / `.mcp.json`) |
281
- | Grok CLI | `kya connect grok` | — (appends `[mcp_servers.shield-kya]` to `~/.grok/config.toml`) |
280
+ | Claude Code | `kya connect claude` (or `kya start`) | - (merges `~/.claude.json` / `.mcp.json`) |
281
+ | Grok CLI | `kya connect grok` | - (appends `[mcp_servers.shield-kya]` to `~/.grok/config.toml`) |
282
282
  | OpenCode | `kya connect opencode` | `opencode/opencode.example.json` |
283
283
  | Kilo Code | `kya connect kilo` | `kilo/kilo.example.json` |
284
284
  | Kiro | `kya connect kiro` | `kiro/mcp.example.json` |
@@ -307,7 +307,7 @@ ORR is a reporting board. Scanners, `--scorecard`, and `harness.agentshield` are
307
307
 
308
308
  ## Certify (continuous agent assurance)
309
309
 
310
- `kya certify` evaluates the open **Agent Trust Baseline** catalog (`catalog/agent-trust-baseline-v0.json` — 30 requirements across Data & Privacy, Security, Safety, Reliability, Accountability, Society) against local evidence: the global trail, ORR output, wired hosts, sandbox inventory, receipts, showback, and your recorded attestations. It writes a gap report to `.kya/certify/` (JSON + Markdown + HTML). The gap list is your work plan. The receipt report shows the same state live: a **Certify** panel recomputed on every render (so `kya start`'s live report updates as events stream in), plus a dedicated **Certify** tab with the full live requirement table — run `kya certify` for the full gap report + signed evidence bundle.
310
+ `kya certify` evaluates the open **Agent Trust Baseline** catalog (`catalog/agent-trust-baseline-v0.json` - 30 requirements across Data & Privacy, Security, Safety, Reliability, Accountability, Society) against local evidence: the global trail, ORR output, wired hosts, sandbox inventory, receipts, showback, and your recorded attestations. It writes a gap report to `.kya/certify/` (JSON + Markdown + HTML). The gap list is your work plan. The receipt report shows the same state live: a **Certify** panel recomputed on every render (so `kya start`'s live report updates as events stream in), plus a dedicated **Certify** tab with the full live requirement table - run `kya certify` for the full gap report + signed evidence bundle.
311
311
 
312
312
  ```bash
313
313
  npx @shield-agent/kya certify # gap report; exit 1 when gaps exist (CI-friendly)
@@ -317,11 +317,49 @@ npx @shield-agent/kya certify --attest SOC-01 --text "Acceptable-use policy: htt
317
317
  npx @shield-agent/kya certify --sign # also emit a signed evidence-bundle.json
318
318
  ```
319
319
 
320
- Certify is **evidence-only**. It never ALLOWs, DENYs, or blocks anything — the sole PEP remains Shield KYA. Trail-based machine checks never pass on an empty trail (they report `insufficient_evidence`). What a machine cannot check is covered by explicit local attestations (`--attest`), recorded in `.kya/attestations.json` — unverified operator statements, labeled as such.
320
+ Certify is **evidence-only**. It never ALLOWs, DENYs, or blocks anything - the sole PEP remains Shield KYA. Trail-based machine checks never pass on an empty trail (they report `insufficient_evidence`). What a machine cannot check is covered by explicit local attestations (`--attest`), recorded in `.kya/attestations.json` - unverified operator statements, labeled as such.
321
321
 
322
- `--sign` emits `evidence-bundle.json`: canonical JSON, ed25519-signed by a locally generated key (`~/.kya/keys/evidence-ed25519.json`, mode 0600, auto-created on first use). Each `--sign` run prints the signing key fingerprint; when the key was just created the CLI notes that key continuity resets there (earlier bundles stay verifiable only under the old pubkey). A self-signed developer key proves bundle **integrity** and **continuity of a key** — **not identity**. Identity binding and the verified badge are the hosted verification product (separate). The bundle format is open and documented in `docs/certify.md`; anyone can verify a bundle offline with the embedded pubkey.
322
+ `--sign` emits `evidence-bundle.json`: canonical JSON, ed25519-signed by a locally generated key (`~/.kya/keys/evidence-ed25519.json`, mode 0600, auto-created on first use). Each `--sign` run prints the signing key fingerprint; when the key was just created the CLI notes that key continuity resets there (earlier bundles stay verifiable only under the old pubkey). A self-signed developer key proves bundle **integrity** and **continuity of a key** - **not identity**. Identity binding and the verified badge are the hosted verification product (separate). The bundle format is open and documented in `docs/certify.md`; anyone can verify a bundle offline with the embedded pubkey.
323
323
 
324
- `kya certify` is local, free, and offline: no account, no network calls, no license check (it never sends usage stats). The catalog is MIT-licensed and PRs are welcome.
324
+ `kya certify` is local, free, and offline: no account, no network calls, no license check (it never sends usage stats). The catalog is MIT-licensed and PRs are welcome. An EU AI Act crosswalk (baseline requirements mapped to Articles 9-15, 26, 72) ships in [docs/certify-eu-ai-act.md](docs/certify-eu-ai-act.md) and `src/certify/eu-ai-act-map.json`.
325
+
326
+ ## Import traces (LangSmith, Langfuse, Phoenix, OTel)
327
+
328
+ Bring existing observability exports into the trail so the receipt and certify see them:
329
+
330
+ ```bash
331
+ kya import --from langsmith ./runs.json
332
+ kya import --from langfuse ./observations.jsonl
333
+ kya import --from otel ./otraces.json
334
+ ```
335
+
336
+ Imports land as observe-mode events (`host: import`, `reasonCode: IMPORTED`, error runs become `DENY`/`IMPORTED_ERROR`), with latency and token counts mapped when the source carries them. Files over 50MB are refused; malformed records are skipped, never fatal.
337
+
338
+ ## Investigate (detections + fix briefs)
339
+
340
+ `kya investigate` runs deterministic local detectors over the trail - no LLM calls: PII leaks in summaries, DENY spikes, approval retry loops, repeated never-event attempts, unknown tools under hold, slow tools. Findings group into incidents, and each incident renders a markdown fix brief shaped to paste into Claude Code / Cursor / Codex.
341
+
342
+ ```bash
343
+ kya investigate # summary: counts by severity + top incidents
344
+ kya investigate --json # findings + incidents + briefs, machine-readable
345
+ ```
346
+
347
+ ## Alert webhooks (verdict routing)
348
+
349
+ Route DENY / REQUIRE_APPROVE events to Slack, Linear, Jira, or any webhook. Config lives in `.kya/config.json` (project) or `~/.kya/config.json` (global):
350
+
351
+ ```json
352
+ {
353
+ "notify": {
354
+ "webhooks": [
355
+ { "url": "https://hooks.slack.com/services/...", "template": "slack", "events": ["DENY", "REQUIRE_APPROVE"] },
356
+ { "url": "https://example.invalid/jira", "template": "jira", "events": ["DENY"] }
357
+ ]
358
+ }
359
+ }
360
+ ```
361
+
362
+ `KYA_NOTIFY_WEBHOOK=<url>` is the zero-config variant (generic payload). Delivery retries with exponential backoff (250ms/1s/4s + jitter), per-attempt timeouts, a per-URL circuit breaker, and a send rate limiter; payloads are built only from redacted trail fields, with an automatic minimized fallback if the secret scan trips. From short-lived hook/wrap spawns delivery rides a detached helper (`kya notify-flush`), so the gate path never waits on the network.
325
363
 
326
364
  ## Optional sandbox wrap (Firecracker)
327
365
 
@@ -337,7 +375,7 @@ KYA_SANDBOX=mock kya sandbox kill --sandbox-id <id>
337
375
 
338
376
  ## Cost showback (observe only)
339
377
 
340
- `kya orr run --usage ./usage.json` (or `.kya/usage.json`) adds a showback section: tokens and estimated USD by agent and run. Subagents nest under `parentRunId`. That section is not a billing meter and not a policy gate. Hosted metrics show the same rollup when usage is ingested with a session.
378
+ `kya orr run --usage ./usage.json` (or `.kya/usage.json`) adds a showback section: tokens and estimated USD by agent and run. Subagents nest under `parentRunId`. That section is not a billing meter and not a policy gate. Hosted metrics show the same rollup when usage is ingested with a session. Trail events that carry host-reported token counts (hook payloads with a `usage` object, imported traces) are preferred over the static per-event estimate, and the report states how many window events had real usage.
341
379
 
342
380
  ## Enterprise (separate tier)
343
381
 
@@ -360,7 +398,9 @@ pnpm build
360
398
  - [OTLP metrics (OSS + hosted)](docs/otlp.md)
361
399
  - [Anonymous usage stats (opt-in): what is sent, controls, retention](docs/telemetry.md)
362
400
  - [OWASP MCP governance map](docs/owasp-mcp-governance.md)
363
- - [kya certify — Agent Trust Baseline gap reports](docs/certify.md)
401
+ - [kya certify - Agent Trust Baseline gap reports](docs/certify.md)
402
+ - [EU AI Act crosswalk for the Agent Trust Baseline](docs/certify-eu-ai-act.md)
403
+ - [Works with your observability stack](docs/marketing/observability-stack.md)
364
404
  - [SDK & framework integrations (in-process shims)](docs/sdk-integrations.md)
365
405
  - [Hosted operator SSO / SCIM (not in OSS CLI)](docs/hosted-operator-sso.md)
366
406
  - See also `LIMITATIONS.md` in this repo
@@ -383,6 +423,8 @@ Opt-in. Default off.
383
423
 
384
424
  **OSS CLI:** set `KYA_OTLP_ENDPOINT` (or `OTEL_EXPORTER_OTLP_ENDPOINT`) to export thin evaluate latency (`kya.client.evaluate.latency`) with tags `verdict` and `host` only. No tool args or API keys.
385
425
 
426
+ **Verdict span export:** set `KYA_OTLP_EXPORT_ENDPOINT` (or `"otlpExport": { "endpoint": ... }` in `.kya/config.json`) to emit every verdict as an OTLP/JSON GenAI span (`gen_ai.tool.name`, `kya.verdict`, `kya.reason_code`, token attributes when known) to any OTLP/HTTP backend. Long-lived processes (MCP gate, gateway) export every verdict; hook/wrap spawns export DENY / REQUIRE_APPROVE via the detached `notify-flush` helper. Plaintext http is accepted for loopback only unless `"insecure": true`.
427
+
386
428
  **Hosted plane:** richer Micrometer gauges and timers when `KYA_OTLP_ENABLED=true`.
387
429
 
388
430
  Full env, Grafana/Datadog notes, forbid list, and a Collector sample: [`docs/otlp.md`](docs/otlp.md).
@@ -2,7 +2,7 @@
2
2
  "amp.mcpServers": {
3
3
  "shield-kya": {
4
4
  "command": "npx",
5
- "args": ["--no-install", "@shield-agent/kya@0.22.0", "serve-mcp", "--stdio"],
5
+ "args": ["--no-install", "@shield-agent/kya@0.23.0", "serve-mcp", "--stdio"],
6
6
  "env": {
7
7
  "KYA_BASE_URL": "https://shield-agent.com",
8
8
  "KYA_API_KEY": "${KYA_API_KEY}",
@@ -2,7 +2,7 @@
2
2
  "mcpServers": {
3
3
  "shield-kya": {
4
4
  "command": "npx",
5
- "args": ["--no-install", "@shield-agent/kya@0.22.0", "serve-mcp", "--stdio"],
5
+ "args": ["--no-install", "@shield-agent/kya@0.23.0", "serve-mcp", "--stdio"],
6
6
  "env": {
7
7
  "KYA_BASE_URL": "https://shield-agent.com",
8
8
  "KYA_API_KEY": "${KYA_API_KEY}",
@@ -2,7 +2,7 @@
2
2
  "mcpServers": {
3
3
  "shield-kya": {
4
4
  "command": "npx",
5
- "args": ["--no-install", "@shield-agent/kya@0.22.0", "serve-mcp", "--stdio"],
5
+ "args": ["--no-install", "@shield-agent/kya@0.23.0", "serve-mcp", "--stdio"],
6
6
  "env": {
7
7
  "KYA_BASE_URL": "https://shield-agent.com",
8
8
  "KYA_API_KEY": "${KYA_API_KEY}",
@@ -2,7 +2,7 @@
2
2
  "mcpServers": {
3
3
  "shield-kya": {
4
4
  "command": "npx",
5
- "args": ["--no-install", "@shield-agent/kya@0.22.0", "serve-mcp", "--stdio"],
5
+ "args": ["--no-install", "@shield-agent/kya@0.23.0", "serve-mcp", "--stdio"],
6
6
  "env": {
7
7
  "KYA_BASE_URL": "https://shield-agent.com",
8
8
  "KYA_API_KEY": "${KYA_API_KEY}",
@@ -1,5 +1,5 @@
1
1
  /**
2
- * Operator attestations — the explicit escape hatch for requirements a machine
2
+ * Operator attestations - the explicit escape hatch for requirements a machine
3
3
  * cannot check. Local file only (<cwd>/.kya/attestations.json); never uploaded,
4
4
  * never a PEP. Latest attestation per requirement id wins.
5
5
  */
@@ -13,7 +13,7 @@ const MAX_ATTESTATIONS_BYTES = 256 * 1024;
13
13
  const MAX_TEXT_CHARS = 2000;
14
14
  const REQ_ID = /^[A-Z]+-\d+$/;
15
15
  // Attestation text and timestamps are interpolated into single-line evidence
16
- // strings, reports, and signed bundles — same rule as catalog attest prompts.
16
+ // strings, reports, and signed bundles - same rule as catalog attest prompts.
17
17
  const CONTROL_CHARS = /[\x00-\x1f\x7f]/;
18
18
  export function attestationsPath(cwd) {
19
19
  return join(configDir(cwd), "attestations.json");
@@ -80,7 +80,7 @@ export function recordAttestation(cwd, requirementId, text) {
80
80
  assertNoSecrets(clean);
81
81
  }
82
82
  catch {
83
- throw new UsageError("--text looks like it contains a secret — attestations describe policy, never credentials");
83
+ throw new UsageError("--text looks like it contains a secret - attestations describe policy, never credentials");
84
84
  }
85
85
  const record = {
86
86
  requirementId: id,
@@ -91,11 +91,11 @@ export function recordAttestation(cwd, requirementId, text) {
91
91
  const store = { version: 1, attestations: [...others, record] };
92
92
  mkdirSync(configDir(cwd), { recursive: true, mode: 0o700 });
93
93
  // Atomic tmp+rename: a crash or concurrent run must never truncate the
94
- // store — the fail-safe load would silently discard all attestation history.
94
+ // store - the fail-safe load would silently discard all attestation history.
95
95
  const path = attestationsPath(cwd);
96
96
  atomicWriteSync(path, `${JSON.stringify(store, null, 2)}\n`);
97
97
  try {
98
- chmodSync(path, 0o600); // operator statements are sensitive — evidence-bundle perms
98
+ chmodSync(path, 0o600); // operator statements are sensitive - evidence-bundle perms
99
99
  }
100
100
  catch {
101
101
  /* best-effort on non-POSIX */
@@ -63,7 +63,7 @@ export interface Catalog {
63
63
  readonly requirements: readonly CatalogRequirement[];
64
64
  }
65
65
  export declare const MAX_CATALOG_BYTES: number;
66
- /** Bundled catalog: <pkg>/catalog/… — works from both src/ (vitest) and dist/ (built). */
66
+ /** Bundled catalog: <pkg>/catalog/… - works from both src/ (vitest) and dist/ (built). */
67
67
  export declare function defaultCatalogPath(): string;
68
68
  export declare function loadCatalog(path?: string): Catalog;
69
69
  export declare function validateCatalog(raw: unknown): Catalog;
@@ -1,7 +1,7 @@
1
1
  /**
2
2
  * Agent Trust Baseline catalog: types, loader, validator.
3
3
  * The bundled catalog/agent-trust-baseline-v0.json at the package root is the
4
- * source of truth (shipped via package.json "files"). Evidence only — a
4
+ * source of truth (shipped via package.json "files"). Evidence only - a
5
5
  * catalog requirement never ALLOWs anything.
6
6
  */
7
7
  import { existsSync, readFileSync, statSync } from "node:fs";
@@ -26,7 +26,7 @@ const CHECK_KINDS = new Set([
26
26
  const ORR_MAX = new Set(["green", "amber"]);
27
27
  const TRAIL_MODES = new Set(["observe", "hold", "offline"]);
28
28
  const REQ_ID = /^[A-Z]+-\d+$/;
29
- /** Bundled catalog: <pkg>/catalog/… — works from both src/ (vitest) and dist/ (built). */
29
+ /** Bundled catalog: <pkg>/catalog/… - works from both src/ (vitest) and dist/ (built). */
30
30
  export function defaultCatalogPath() {
31
31
  return fileURLToPath(new URL("../../catalog/agent-trust-baseline-v0.json", import.meta.url));
32
32
  }
@@ -172,7 +172,7 @@ function parseCheck(id, raw) {
172
172
  case "attest": {
173
173
  if (!nonEmpty(c.prompt))
174
174
  throw reqErr(id, "attest requires non-empty prompt");
175
- // Prompts are interpolated into one-line evidence — no control chars.
175
+ // Prompts are interpolated into one-line evidence - no control chars.
176
176
  if (/[\x00-\x1f\x7f]/.test(c.prompt)) {
177
177
  throw reqErr(id, "attest prompt must not contain control characters");
178
178
  }
@@ -34,7 +34,7 @@ export function assembleEvidenceContext(cwd, env, now = new Date()) {
34
34
  return {
35
35
  now,
36
36
  events,
37
- // The shared resolver the gate itself uses (config.ts) — certify can
37
+ // The shared resolver the gate itself uses (config.ts) - certify can
38
38
  // never report a mode the gate would not actually run.
39
39
  gateMode: resolveGateMode({ cwd, env }),
40
40
  wiredHostCount: wiredHosts.filter((h) => h.wired !== "none").length,
@@ -1,6 +1,6 @@
1
1
  /**
2
2
  * Agent Trust Baseline evaluators. Pure functions over a pre-assembled
3
- * EvidenceContext — no I/O here; all loading lives in certify/context.ts.
3
+ * EvidenceContext - no I/O here; all loading lives in certify/context.ts.
4
4
  * Evidence only: never a second PEP, never ALLOWs anything. Empty evidence
5
5
  * windows yield insufficient_evidence, never a vacuous pass.
6
6
  */
@@ -88,7 +88,7 @@ export interface CertifyOverallCounts {
88
88
  export declare function countRequirements(requirements: readonly CertifyRequirementResult[]): CertifyOverallCounts;
89
89
  /**
90
90
  * Fail-closed overall: zero certifiable evidence (all insufficient_evidence)
91
- * must never headline as pass — a green badge requires real evidence.
91
+ * must never headline as pass - a green badge requires real evidence.
92
92
  * Shared by runCertify and computeLiveCertify so they can never diverge.
93
93
  */
94
94
  export declare function computeOverall(counts: CertifyOverallCounts): CertifyReport["overall"];
@@ -15,7 +15,7 @@ export function countRequirements(requirements) {
15
15
  }
16
16
  /**
17
17
  * Fail-closed overall: zero certifiable evidence (all insufficient_evidence)
18
- * must never headline as pass — a green badge requires real evidence.
18
+ * must never headline as pass - a green badge requires real evidence.
19
19
  * Shared by runCertify and computeLiveCertify so they can never diverge.
20
20
  */
21
21
  export function computeOverall(counts) {
@@ -138,7 +138,7 @@ export function evaluateRequirement(req, ctx) {
138
138
  }
139
139
  case "config_mode": {
140
140
  if (ctx.gateMode === check.not) {
141
- return result("gap", `gate mode is ${ctx.gateMode} — set KYA_HOLD=1 / KYA_OFFLINE=1 or "gateMode" in .kya/config.json`);
141
+ return result("gap", `gate mode is ${ctx.gateMode} - set KYA_HOLD=1 / KYA_OFFLINE=1 or "gateMode" in .kya/config.json`);
142
142
  }
143
143
  return result("pass", `gate mode is ${ctx.gateMode}`);
144
144
  }
@@ -146,33 +146,33 @@ export function evaluateRequirement(req, ctx) {
146
146
  if (ctx.wiredHostCount >= check.min) {
147
147
  return result("pass", `${ctx.wiredHostCount} wired host(s) (need ${check.min})`);
148
148
  }
149
- return result("gap", `${ctx.wiredHostCount} wired host(s), need ${check.min} — kya connect <host> --hooks`);
149
+ return result("gap", `${ctx.wiredHostCount} wired host(s), need ${check.min} - kya connect <host> --hooks`);
150
150
  }
151
151
  case "sandbox_inventory": {
152
152
  if (ctx.sandboxCount >= check.min) {
153
153
  return result("pass", `${ctx.sandboxCount} sandbox record(s)`);
154
154
  }
155
- return result("gap", `no sandbox inventory — KYA_SANDBOX=mock kya sandbox spawn`);
155
+ return result("gap", `no sandbox inventory - KYA_SANDBOX=mock kya sandbox spawn`);
156
156
  }
157
157
  case "receipts_present": {
158
158
  if (ctx.receiptCount >= check.min) {
159
159
  return result("pass", `${ctx.receiptCount} receipt file(s) in .kya/receipts`);
160
160
  }
161
- return result("gap", `no receipts yet — run kya receipt`);
161
+ return result("gap", `no receipts yet - run kya receipt`);
162
162
  }
163
163
  case "showback_present": {
164
164
  return ctx.showbackPresent
165
165
  ? result("pass", "showback card present (.kya/usage.json)")
166
- : result("gap", "no showback card — add .kya/usage.json or run orr with --usage");
166
+ : result("gap", "no showback card - add .kya/usage.json or run orr with --usage");
167
167
  }
168
168
  case "attest": {
169
169
  if (attestation)
170
170
  return result("attested", `attested ${attestation.at}`);
171
- return result("gap", `no attestation recorded — kya certify --attest ${req.id} --text "…" (${check.prompt})`);
171
+ return result("gap", `no attestation recorded - kya certify --attest ${req.id} --text "…" (${check.prompt})`);
172
172
  }
173
173
  case "orr_overall": {
174
174
  if (!ctx.orr) {
175
- return result("insufficient_evidence", "no ORR report — kya orr run --path .");
175
+ return result("insufficient_evidence", "no ORR report - kya orr run --path .");
176
176
  }
177
177
  if (RATING_RANK[ctx.orr.overall] <= RATING_RANK[check.max]) {
178
178
  return result("pass", `ORR overall ${ctx.orr.overall} (max ${check.max})`);
@@ -181,7 +181,7 @@ export function evaluateRequirement(req, ctx) {
181
181
  }
182
182
  case "orr_category": {
183
183
  if (!ctx.orrCategories) {
184
- return result("insufficient_evidence", "no ORR report — kya orr run --path .");
184
+ return result("insufficient_evidence", "no ORR report - kya orr run --path .");
185
185
  }
186
186
  const rating = ctx.orrCategories[check.id];
187
187
  if (!rating) {
@@ -194,7 +194,7 @@ export function evaluateRequirement(req, ctx) {
194
194
  }
195
195
  case "orr_fresh": {
196
196
  if (!ctx.orr || !ctx.orr.generatedAt) {
197
- return result("insufficient_evidence", "no ORR report — kya orr run --path .");
197
+ return result("insufficient_evidence", "no ORR report - kya orr run --path .");
198
198
  }
199
199
  const t = Date.parse(ctx.orr.generatedAt);
200
200
  if (Number.isNaN(t)) {
@@ -202,7 +202,7 @@ export function evaluateRequirement(req, ctx) {
202
202
  }
203
203
  const nowMs = ctx.now.getTime();
204
204
  if (t > nowMs) {
205
- return result("insufficient_evidence", "ORR generatedAt is in the future — clock skew, re-run kya orr run");
205
+ return result("insufficient_evidence", "ORR generatedAt is in the future - clock skew, re-run kya orr run");
206
206
  }
207
207
  const ageMs = nowMs - t;
208
208
  // Exact ms comparison decides; the floored day count is display-only.
@@ -210,7 +210,7 @@ export function evaluateRequirement(req, ctx) {
210
210
  if (ageMs <= check.maxAgeDays * DAY_MS) {
211
211
  return result("pass", `ORR is ${ageDays}d old (max ${check.maxAgeDays}d)`);
212
212
  }
213
- return result("gap", `ORR is ${ageDays}d old (max ${check.maxAgeDays}d) — re-run kya orr run`);
213
+ return result("gap", `ORR is ${ageDays}d old (max ${check.maxAgeDays}d) - re-run kya orr run`);
214
214
  }
215
215
  }
216
216
  // Unreachable: RequirementCheck union is exhaustive (checked at compile time).
@@ -1,5 +1,5 @@
1
1
  /**
2
- * Live in-memory certify evaluation — the "certified right now" panel data.
2
+ * Live in-memory certify evaluation - the "certified right now" panel data.
3
3
  * Recomputes the full Agent Trust Baseline from local evidence on every call
4
4
  * and returns a real CertifyReport, identical in shape to `kya certify` output
5
5
  * so the receipt panel and any other consumer can treat them interchangeably.
@@ -11,7 +11,7 @@ import { loadCatalog } from "./catalog.js";
11
11
  import { assembleEvidenceContext } from "./context.js";
12
12
  import { computeOverall, countRequirements, DAY_MS, evaluateRequirement, trailStats, trailWindow, } from "./evaluate.js";
13
13
  export function computeLiveCertify(cwd, env = process.env, windowDays = 30, now = new Date()) {
14
- // Public SDK surface — enforce the same window rule as the CLI boundary.
14
+ // Public SDK surface - enforce the same window rule as the CLI boundary.
15
15
  if (!Number.isInteger(windowDays) || windowDays < 1 || windowDays > 366) {
16
16
  throw new UsageError("windowDays must be an integer between 1 and 366");
17
17
  }
@@ -1,5 +1,5 @@
1
1
  import type { CertifyReport } from "./evaluate.js";
2
- /** Shared domain display labels — the receipt Certify tab uses these too. */
2
+ /** Shared domain display labels - the receipt Certify tab uses these too. */
3
3
  export declare const DOMAIN_LABELS: Record<string, string>;
4
4
  /** Catalog order of domains, derived from requirement order. */
5
5
  export declare function domainOrder(requirements: readonly {
@@ -1,10 +1,10 @@
1
1
  /**
2
2
  * Markdown + standalone HTML rendering for the certify gap report.
3
3
  * Same visual language as the activity receipt (pills, panels, dark/light),
4
- * own minimal CSS — the certify page is fully standalone and offline.
4
+ * own minimal CSS - the certify page is fully standalone and offline.
5
5
  */
6
6
  import { assertNoSecrets, clip, stripEscapes } from "../dash/render.js";
7
- /** Shared domain display labels — the receipt Certify tab uses these too. */
7
+ /** Shared domain display labels - the receipt Certify tab uses these too. */
8
8
  export const DOMAIN_LABELS = {
9
9
  "data-privacy": "Data & Privacy",
10
10
  security: "Security",
@@ -37,7 +37,7 @@ export function formatCertifyMarkdown(report) {
37
37
  `- **Result:** ${o.result === "gap" ? "GAP" : "PASS"}`,
38
38
  `- **Generated:** ${mdText(report.generatedAt)}`,
39
39
  `- **Window:** last ${report.window.days} days (${mdText(report.window.since)} → ${mdText(report.window.until)})`,
40
- `- **Trail:** ${report.trail.eventCount} events in window — allow ${report.trail.verdictMix.ALLOW} · deny ${report.trail.verdictMix.DENY} · review ${report.trail.verdictMix.REQUIRE_APPROVE}`,
40
+ `- **Trail:** ${report.trail.eventCount} events in window - allow ${report.trail.verdictMix.ALLOW} · deny ${report.trail.verdictMix.DENY} · review ${report.trail.verdictMix.REQUIRE_APPROVE}`,
41
41
  `- **Tally:** ${o.pass} pass · ${o.gap} gap · ${o.insufficientEvidence} insufficient evidence · ${o.attested} attested`,
42
42
  "",
43
43
  "## Gaps (work plan)",
@@ -45,12 +45,12 @@ export function formatCertifyMarkdown(report) {
45
45
  const gaps = report.requirements.filter((r) => r.status === "gap");
46
46
  if (gaps.length === 0) {
47
47
  lines.push(o.result === "gap"
48
- ? "- No certifiable evidence in this window — every requirement is insufficient_evidence. Run the gate first (kya wrap / kya connect), then re-run kya certify."
48
+ ? "- No certifiable evidence in this window - every requirement is insufficient_evidence. Run the gate first (kya wrap / kya connect), then re-run kya certify."
49
49
  : "- (none)");
50
50
  }
51
51
  else {
52
52
  for (const r of gaps) {
53
- lines.push(`- **${r.id}** [${r.severity}] ${mdText(r.title)} — ${mdText(r.evidence)}`);
53
+ lines.push(`- **${r.id}** [${r.severity}] ${mdText(r.title)} - ${mdText(r.evidence)}`);
54
54
  }
55
55
  }
56
56
  lines.push("");
@@ -84,7 +84,7 @@ const STATUS_TONE = {
84
84
  };
85
85
  function requirementRow(r) {
86
86
  const att = r.attestation
87
- ? `<div class="att">attested ${esc(r.attestation.at)} — ${esc(clip(r.attestation.text, 200))}</div>`
87
+ ? `<div class="att">attested ${esc(r.attestation.at)} - ${esc(clip(r.attestation.text, 200))}</div>`
88
88
  : "";
89
89
  return ` <li class="req">
90
90
  <span class="pill ${STATUS_TONE[r.status]}">${esc(r.status.replace(/_/g, " "))}</span>
@@ -102,8 +102,8 @@ export function renderCertifyHtml(report) {
102
102
  const gaps = report.requirements.filter((r) => r.status === "gap");
103
103
  const gapList = gaps.length === 0
104
104
  ? o.result === "gap"
105
- ? `<p class="empty">No certifiable evidence in this window — every requirement is insufficient evidence. Run the gate first (kya wrap / kya connect), then re-run kya certify.</p>`
106
- : `<p class="empty">No gaps. Evidence-only report — not a certificate.</p>`
105
+ ? `<p class="empty">No certifiable evidence in this window - every requirement is insufficient evidence. Run the gate first (kya wrap / kya connect), then re-run kya certify.</p>`
106
+ : `<p class="empty">No gaps. Evidence-only report - not a certificate.</p>`
107
107
  : `<ol class="gaps">
108
108
  ${gaps
109
109
  .map((r) => ` <li><strong>${esc(r.id)}</strong> <span class="sev ${esc(r.severity)}">${esc(r.severity)}</span> ${esc(clip(r.title, 120))}<br/><span class="mute">${esc(clip(r.evidence, 240))}</span></li>`)
@@ -127,7 +127,7 @@ ${rows.map((r) => requirementRow(r)).join("\n")}
127
127
  <head>
128
128
  <meta charset="utf-8"/>
129
129
  <meta name="viewport" content="width=device-width, initial-scale=1"/>
130
- <title>Certify — ${esc(report.catalog.id)} v${esc(report.catalog.version)}</title>
130
+ <title>Certify - ${esc(report.catalog.id)} v${esc(report.catalog.version)}</title>
131
131
  <style>
132
132
  :root {
133
133
  color-scheme: dark;
@@ -215,7 +215,7 @@ ${rows.map((r) => requirementRow(r)).join("\n")}
215
215
  </head>
216
216
  <body>
217
217
  <main>
218
- <h1>Certify — <code>${esc(report.catalog.id)} v${esc(report.catalog.version)}</code></h1>
218
+ <h1>Certify - <code>${esc(report.catalog.id)} v${esc(report.catalog.version)}</code></h1>
219
219
  <div class="sub">generated ${esc(report.generatedAt)} · window last ${report.window.days} days (${esc(report.window.since)} → ${esc(report.window.until)}) · ${report.trail.eventCount} trail events in window</div>
220
220
  <span class="result ${o.result}">${o.result === "gap" ? "GAP" : "PASS"}</span>
221
221
  <div class="stats" role="group" aria-label="Tally">