@shomra/agent 0.3.16 → 0.3.18

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 (156) hide show
  1. package/NOTICE +1 -1
  2. package/README.md +57 -57
  3. package/package.json +3 -9
  4. package/shomra.mjs +9 -7168
  5. package/src/agents/hook-command.mjs +19 -0
  6. package/src/agents/hook-files.mjs +41 -0
  7. package/src/agents/installers.mjs +203 -0
  8. package/src/artifacts/matchers.mjs +59 -0
  9. package/src/artifacts/report.mjs +50 -0
  10. package/src/cli/flags.mjs +68 -0
  11. package/src/cli/help-sections.mjs +309 -0
  12. package/src/cli/help.mjs +27 -0
  13. package/src/cli/main.mjs +55 -0
  14. package/src/cli/registry.mjs +80 -0
  15. package/src/cli/suggestions.mjs +33 -0
  16. package/src/commands/add.mjs +149 -0
  17. package/src/commands/agent-identity.mjs +46 -0
  18. package/src/commands/check.mjs +194 -0
  19. package/src/commands/corpus.mjs +126 -0
  20. package/src/commands/design.mjs +168 -0
  21. package/src/commands/doctor.mjs +209 -0
  22. package/src/commands/fix.mjs +115 -0
  23. package/src/commands/gate.mjs +154 -0
  24. package/src/commands/git-hooks.mjs +163 -0
  25. package/src/commands/init.mjs +36 -0
  26. package/src/commands/install-hook.mjs +51 -0
  27. package/src/commands/llm-proxy.mjs +153 -0
  28. package/src/commands/mcp-add.mjs +185 -0
  29. package/src/commands/mcp.mjs +143 -0
  30. package/src/commands/memory-scan.mjs +181 -0
  31. package/src/commands/model-scan.mjs +99 -0
  32. package/src/commands/models.mjs +145 -0
  33. package/src/commands/new.mjs +64 -0
  34. package/src/commands/plan.mjs +87 -0
  35. package/src/commands/pr.mjs +249 -0
  36. package/src/commands/protect.mjs +38 -0
  37. package/src/commands/provenance.mjs +91 -0
  38. package/src/commands/redteam.mjs +166 -0
  39. package/src/commands/rules.mjs +220 -0
  40. package/src/commands/run.mjs +128 -0
  41. package/src/commands/scan-zip.mjs +118 -0
  42. package/src/commands/scan.mjs +102 -0
  43. package/src/commands/secrets.mjs +99 -0
  44. package/src/commands/status.mjs +50 -0
  45. package/src/commands/why.mjs +88 -0
  46. package/src/core/api-client.mjs +66 -0
  47. package/src/core/api-key.mjs +6 -0
  48. package/src/core/circuit-breaker.mjs +42 -0
  49. package/src/core/config.mjs +37 -0
  50. package/src/core/exit-codes.mjs +9 -0
  51. package/src/core/json-file.mjs +13 -0
  52. package/src/core/numbers.mjs +4 -0
  53. package/src/core/package-root.mjs +10 -0
  54. package/src/core/terminal.mjs +16 -0
  55. package/src/core/version.mjs +14 -0
  56. package/src/core/wire-limits.mjs +53 -0
  57. package/src/corpus/screening.mjs +127 -0
  58. package/{ai-usage.mjs → src/detect/ai-usage.mjs} +0 -27
  59. package/src/detect/code-sast.mjs +2 -0
  60. package/{design.mjs → src/detect/design.mjs} +18 -107
  61. package/src/detect/guard-signals.mjs +18 -0
  62. package/{model-refs.mjs → src/detect/model-refs.mjs} +18 -77
  63. package/src/detect/sast/chains.mjs +30 -0
  64. package/src/detect/sast/path-expressions.mjs +76 -0
  65. package/src/detect/sast/rules-chains.mjs +33 -0
  66. package/src/detect/sast/rules-config.mjs +51 -0
  67. package/src/detect/sast/rules-javascript.mjs +109 -0
  68. package/src/detect/sast/rules-python.mjs +292 -0
  69. package/src/detect/sast/scanner.mjs +104 -0
  70. package/src/detect/sast/source-lines.mjs +115 -0
  71. package/src/detect/sast/taint.mjs +71 -0
  72. package/src/detect/signals/artifacts.mjs +113 -0
  73. package/src/detect/signals/autonomy.mjs +55 -0
  74. package/src/detect/signals/config-markers.mjs +28 -0
  75. package/src/detect/signals/credential-harvest.mjs +64 -0
  76. package/src/detect/signals/durable-claims.mjs +73 -0
  77. package/src/detect/signals/egress.mjs +56 -0
  78. package/src/detect/signals/execution-hijack.mjs +128 -0
  79. package/src/detect/signals/gate.mjs +91 -0
  80. package/src/detect/signals/injection.mjs +55 -0
  81. package/src/detect/signals/lines.mjs +42 -0
  82. package/src/detect/signals/masking.mjs +99 -0
  83. package/src/detect/signals/memory.mjs +357 -0
  84. package/src/detect/signals/packages.mjs +45 -0
  85. package/src/detect/signals/propagation.mjs +86 -0
  86. package/src/detect/signals/prose-context.mjs +82 -0
  87. package/src/detect/signals/scan.mjs +91 -0
  88. package/src/detect/signals/secrets.mjs +85 -0
  89. package/src/detect/signals/sensitive.mjs +9 -0
  90. package/src/detect/signals/severity.mjs +10 -0
  91. package/src/detect/signals/shell.mjs +96 -0
  92. package/src/detect/signals/staged-fetch.mjs +66 -0
  93. package/src/detect/signals/text-match.mjs +35 -0
  94. package/src/gate/batch.mjs +157 -0
  95. package/src/gate/environment.mjs +122 -0
  96. package/src/gate/repo-policy.mjs +65 -0
  97. package/src/gate/result.mjs +53 -0
  98. package/src/gate/sarif.mjs +33 -0
  99. package/src/gate/sast.mjs +64 -0
  100. package/src/gate/suppressions.mjs +0 -0
  101. package/src/guard/classify.mjs +50 -0
  102. package/src/guard/emit.mjs +51 -0
  103. package/src/guard/ignore.mjs +24 -0
  104. package/src/guard/ledger.mjs +112 -0
  105. package/src/guard/model-load.mjs +50 -0
  106. package/src/guard/normalize.mjs +77 -0
  107. package/src/guard/options.mjs +10 -0
  108. package/src/guard/prompt-guard.mjs +184 -0
  109. package/src/guard/report.mjs +35 -0
  110. package/src/guard/result-guard.mjs +140 -0
  111. package/src/guard/tool-guard.mjs +166 -0
  112. package/src/inventory/agent-artifacts.mjs +5 -0
  113. package/src/inventory/agent-posture.mjs +249 -0
  114. package/src/inventory/artifacts/classify.mjs +27 -0
  115. package/src/inventory/artifacts/discover.mjs +187 -0
  116. package/src/inventory/artifacts/file-read.mjs +42 -0
  117. package/src/inventory/artifacts/hooks.mjs +14 -0
  118. package/src/inventory/artifacts/limits.mjs +37 -0
  119. package/src/inventory/artifacts/marketplaces.mjs +45 -0
  120. package/src/inventory/artifacts/roots.mjs +20 -0
  121. package/src/inventory/artifacts/walk.mjs +36 -0
  122. package/src/inventory/discovery/ai-dependencies.mjs +161 -0
  123. package/src/inventory/discovery/ai-tools.mjs +23 -0
  124. package/src/inventory/discovery/all.mjs +40 -0
  125. package/src/inventory/discovery/coding-agents.mjs +77 -0
  126. package/src/inventory/discovery/fs-read.mjs +36 -0
  127. package/src/inventory/discovery/local-runtimes.mjs +53 -0
  128. package/src/inventory/discovery/mcp-clients.mjs +67 -0
  129. package/src/inventory/discovery/mcp-servers.mjs +78 -0
  130. package/src/inventory/discovery/model-keys.mjs +97 -0
  131. package/src/inventory/discovery/platform.mjs +16 -0
  132. package/src/inventory/discovery/rules-files.mjs +25 -0
  133. package/src/inventory/discovery/vector-stores.mjs +176 -0
  134. package/src/inventory/discovery/workspace.mjs +124 -0
  135. package/src/inventory/discovery.mjs +10 -0
  136. package/src/mcp/child-process.mjs +50 -0
  137. package/src/mcp/config-wrapping.mjs +75 -0
  138. package/src/mcp/connect-gate.mjs +45 -0
  139. package/src/mcp/hosts.mjs +16 -0
  140. package/src/mcp/jsonrpc.mjs +48 -0
  141. package/src/mcp/lookup.mjs +50 -0
  142. package/src/mcp/screening.mjs +103 -0
  143. package/src/mcp/server-tools.mjs +97 -0
  144. package/src/mcp/server.mjs +102 -0
  145. package/src/mcp/shim.mjs +205 -0
  146. package/src/models/lookup.mjs +79 -0
  147. package/src/models/references.mjs +103 -0
  148. package/src/rules/context.mjs +98 -0
  149. package/src/rules/generate.mjs +103 -0
  150. package/src/rules/sections.mjs +145 -0
  151. package/src/scaffold/agent-project.mjs +185 -0
  152. package/src/scaffold/artifact-templates.mjs +35 -0
  153. package/code-sast.mjs +0 -1063
  154. package/discovery.mjs +0 -977
  155. package/guard-ledger.mjs +0 -239
  156. package/guard-signals.mjs +0 -1268
package/NOTICE CHANGED
@@ -7,4 +7,4 @@ Licensed under the Apache License, Version 2.0. See the LICENSE file for the
7
7
  full terms.
8
8
 
9
9
  The detection rules, signatures, and analyzers in this package are intended for
10
- authorized security use scanning your own AI artifacts, code, and machines.
10
+ authorized security use - scanning your own AI artifacts, code, and machines.
package/README.md CHANGED
@@ -2,13 +2,13 @@
2
2
 
3
3
  **Adversarial assurance for AI agents**, as a local-first CLI. It sits inside
4
4
  your coding agent and CI and blocks dangerous tool-calls, shell commands and
5
- data exfiltration *before they run* on your machine, even offline. Enrolled,
5
+ data exfiltration *before they run* - on your machine, even offline. Enrolled,
6
6
  it also attacks your org’s own guardrails (`shomra admin redteam`) and turns
7
7
  each breach into a false-positive-gated control (`shomra harden`). It also vets AI
8
8
  artifacts (MCP configs, Skills, slash commands, hooks, rules files) before they
9
- install. Start with a free on-machine scan no signup.
9
+ install. Start with a free on-machine scan - no signup.
10
10
 
11
- Zero dependencies Node ≥ 18 built-ins only.
11
+ Zero dependencies - Node ≥ 18 built-ins only.
12
12
 
13
13
  ## Install
14
14
 
@@ -29,22 +29,22 @@ npx @shomra/agent gate .mcp.json
29
29
 
30
30
  ## Auth (optional)
31
31
 
32
- Shomra is **local-first** there is no built-in backend and no telemetry. `gate`,
32
+ Shomra is **local-first** - there is no built-in backend and no telemetry. `gate`,
33
33
  `check`, `models`, `secrets`, and the runtime firewall all run fully on your
34
34
  machine with no key and no network. You only connect to a Shomra org to layer on
35
35
  your **org policy**, cloud/deep scans, AI fixes, and the Model Security Index.
36
36
 
37
37
  - **Dev machine:** `shomra init --key shm_live_… --url https://shomra.your-co.com` (writes `~/.shomra/config.json`).
38
- - **CI / headless:** set env vars instead no `init` needed:
39
- - `SHOMRA_API_KEY` your org key
40
- - `SHOMRA_URL` your backend URL
38
+ - **CI / headless:** set env vars instead - no `init` needed:
39
+ - `SHOMRA_API_KEY` - your org key
40
+ - `SHOMRA_URL` - your backend URL
41
41
 
42
42
  Without either, every backend-only feature degrades cleanly to the on-machine result.
43
43
 
44
44
  ## Quickstart
45
45
 
46
46
  ```bash
47
- shomra check # "is my repo safe?" gate every AI artifact at once
47
+ shomra check # "is my repo safe?" - gate every AI artifact at once
48
48
  shomra check --staged # only what's git-staged (pre-commit / editor-on-save)
49
49
  shomra check --fix # gate, then remediate what isn't clean, in place
50
50
  shomra fix .mcp.json --apply # AI-fix one artifact and write it back
@@ -58,17 +58,17 @@ shomra status # config + firewall health
58
58
  shomra help # full command list
59
59
  ```
60
60
 
61
- `check`, `fix` and `why` are the verbs a developer lives in everything below is
61
+ `check`, `fix` and `why` are the verbs a developer lives in - everything below is
62
62
  CI, governance, or one-time setup. Findings carry a **file:line**, so `check --json`
63
63
  drives precise editor squiggles and `why`/`fix` point at the exact offending line.
64
64
 
65
65
  - **`check`** is the developer front door: it finds every AI artifact in the tree
66
66
  (MCP configs, Skills, slash commands, hooks, rules files) and gates them in one
67
- shot, **local-first** a real on-machine verdict with no backend or key, org
67
+ shot, **local-first** - a real on-machine verdict with no backend or key, org
68
68
  policy layered on when enrolled. It's `gate --all` with dev ergonomics
69
69
  (`--staged` / `--changed` scoping, `--fix`, clean `--json` for an IDE extension).
70
70
  - **`fix`** generates a minimal fix for what the gate flags and (with `--apply`)
71
- writes it back to your working tree the fix is produced on the platform with
71
+ writes it back to your working tree - the fix is produced on the platform with
72
72
  your org's AI key, so no provider key sits on the dev machine. Nothing is
73
73
  committed or pushed. Without AI on the server it prints deterministic guidance.
74
74
 
@@ -87,7 +87,7 @@ shomra new agent triage-bot # a project that starts compliant
87
87
 
88
88
  Guard enforcing on every model call, an egress allowlist in code rather than in
89
89
  the prompt, untrusted input kept out of the system prompt, secrets referenced
90
- from the environment, and the gate wired into CI from commit zero. Remediating
90
+ from the environment, and the gate wired into CI - from commit zero. Remediating
91
91
  a project into this shape later means changing decisions that have already been
92
92
  built on.
93
93
 
@@ -104,23 +104,23 @@ on top.
104
104
  | Code | Meaning |
105
105
  |------|---------|
106
106
  | `0` | clean / pass |
107
- | `1` | hard fail BLOCK, vulnerable model, secret found, FAIL verdict, below `--min`, regression (also `--strict` + backend outage) |
108
- | `2` | soft fail FLAG under `--strict` (REVIEW when strict) |
109
- | `3` | usage / config error not configured, bad flags, unknown command |
107
+ | `1` | hard fail - BLOCK, vulnerable model, secret found, FAIL verdict, below `--min`, regression (also `--strict` + backend outage) |
108
+ | `2` | soft fail - FLAG under `--strict` (REVIEW when strict) |
109
+ | `3` | usage / config error - not configured, bad flags, unknown command |
110
110
 
111
111
  **Backend outage:** by default it falls back to the on-machine verdict (org
112
112
  policy not applied). `--strict` fails closed (exit 1) because org policy can't be
113
113
  verified. Every backend call is bounded by `SHOMRA_API_TIMEOUT_MS` (default 30s),
114
114
  so a job never hangs.
115
115
 
116
- ### GitHub Actions the reusable action
116
+ ### GitHub Actions - the reusable action
117
117
 
118
118
  ```yaml
119
119
  - uses: actions/checkout@v4
120
120
  - uses: shomra-org/agent@v0
121
121
  with:
122
122
  args: check # --strict is appended unless fail-on-flag: 'false'
123
- api-key: ${{ secrets.SHOMRA_API_KEY }} # optional the gate is local-first
123
+ api-key: ${{ secrets.SHOMRA_API_KEY }} # optional - the gate is local-first
124
124
  url: ${{ secrets.SHOMRA_URL }}
125
125
  ```
126
126
 
@@ -131,7 +131,7 @@ self-hosted Git and GitHub Enterprise, `shomra install-precommit --pre-receive`
131
131
 
132
132
  The hand-written workflow below still works and shows what the action does.
133
133
 
134
- ### GitHub Actions by hand
134
+ ### GitHub Actions - by hand
135
135
 
136
136
  ```yaml
137
137
  name: Shomra AI-artifact gate
@@ -153,11 +153,11 @@ jobs:
153
153
  CI provider, repo, branch and commit are auto-detected and recorded, so security
154
154
  sees local-vs-CI gate activity in the dashboard.
155
155
 
156
- ### GitHub PR reviewer inline annotations (`shomra pr`)
156
+ ### GitHub PR reviewer - inline annotations (`shomra pr`)
157
157
 
158
158
  `shomra pr` is a richer PR-native path: on a `pull_request` it gates only the AI
159
159
  artifacts **changed vs the base branch** and posts a **GitHub Check Run with
160
- inline annotations** on the offending lines no GitHub App or extra backend
160
+ inline annotations** on the offending lines - no GitHub App or extra backend
161
161
  required, just the workflow's `GITHUB_TOKEN`. Scaffold it in one shot:
162
162
 
163
163
  ```bash
@@ -183,8 +183,8 @@ jobs:
183
183
  - run: npx @shomra/agent pr
184
184
  env:
185
185
  GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
186
- SHOMRA_API_KEY: ${{ secrets.SHOMRA_API_KEY }} # optional applies org policy
187
- SHOMRA_URL: ${{ secrets.SHOMRA_URL }} # optional your backend
186
+ SHOMRA_API_KEY: ${{ secrets.SHOMRA_API_KEY }} # optional - applies org policy
187
+ SHOMRA_URL: ${{ secrets.SHOMRA_URL }} # optional - your backend
188
188
  ```
189
189
 
190
190
  The check-run **conclusion** mirrors the gate: `failure` on any BLOCK, `neutral`
@@ -192,7 +192,7 @@ on FLAG (or `failure` with `--strict`), `success` when clean. `--dry-run`/`--jso
192
192
  print the computed check-run without posting. Without `SHOMRA_API_KEY` it still
193
193
  runs local-first; with a key, your **org policy** (below) drives the verdict.
194
194
 
195
- ### SARIF native code-scanning annotations
195
+ ### SARIF - native code-scanning annotations
196
196
 
197
197
  `gate`/`gate --all`/`check` accept `--sarif` to emit SARIF 2.1.0, which GitHub
198
198
  (and GitLab) render as inline code-scanning annotations without a custom parser:
@@ -210,14 +210,14 @@ runs local-first; with a key, your **org policy** (below) drives the verdict.
210
210
 
211
211
  When enrolled, the same **org policy** that governs the dashboard decides the CI
212
212
  verdict (worst-wins across your org + project rules), so a build blocks on the
213
- policies you defined not just a fixed severity threshold. Two things follow:
213
+ policies you defined - not just a fixed severity threshold. Two things follow:
214
214
 
215
215
  - **Findings you've triaged away don't re-block the build.** If a security owner
216
216
  has **accepted the risk** or **ignored** a finding in the platform, the gate
217
217
  records the policy hit for transparency but no longer counts it toward
218
218
  BLOCK/FLAG. Matching is per file+line and survives across scan sources, and an
219
219
  accepted-risk that has **expired** re-blocks automatically.
220
- - **Mandatory guardrails are exempt** a finding that trips a policy marked
220
+ - **Mandatory guardrails are exempt** - a finding that trips a policy marked
221
221
  *mandatory* still blocks even if someone accepted the risk. Use a policy
222
222
  exception for those.
223
223
 
@@ -244,12 +244,12 @@ A pre-commit hook is a courtesy: it lives on the developer's machine, it is one
244
244
  at all. A pre-receive hook runs on the **server**, on every push, for every
245
245
  developer. Same check; the difference between a reminder and a control.
246
246
 
247
- It **fails closed** the opposite of the client hook. Blocking a local commit
247
+ It **fails closed** - the opposite of the client hook. Blocking a local commit
248
248
  because a binary is missing is hostile; waving a push through for the same reason
249
249
  makes deleting the binary the bypass.
250
250
 
251
251
  Available on self-hosted Git (GitLab, Gitea, Bitbucket DC, plain bare repos) and
252
- GitHub Enterprise. GitHub.com does not run server-side hooks use the action as
252
+ GitHub Enterprise. GitHub.com does not run server-side hooks - use the action as
253
253
  a required status check instead.
254
254
 
255
255
  ### pre-commit (local, blocks risky artifacts before they land)
@@ -274,7 +274,7 @@ Add `--json` anywhere to get machine-readable output for custom reporting.
274
274
  wires Shomra into a coding agent's own hooks. It is **tiered**: catastrophic tool
275
275
  calls (`curl|sh`, reverse shells, base64 RCE, live secrets, injection) are
276
276
  blocked on-machine with zero network; only policy-relevant calls escalate to the
277
- backend, behind a short timeout + circuit breaker so a slow or down backend
277
+ backend, behind a short timeout + circuit breaker - so a slow or down backend
278
278
  never freezes the agent. Fail-open by default; `SHOMRA_GUARD_STRICT=1` fails
279
279
  closed on the server tier.
280
280
 
@@ -285,12 +285,12 @@ Three channels are screened:
285
285
  | **Tool call** | PreToolUse / `beforeShellExecution` | the shell command, artifact write or MCP call, before it runs |
286
286
  | **Tool result** | PostToolUse / `afterMCPExecution` | injection, exfil sinks and hidden payloads in what a fetch/read brings *back* |
287
287
  | **Prompt** | `UserPromptSubmit` (Claude Code) / `beforeSubmitPrompt` (Cursor) | what **you** paste, before it leaves the machine |
288
- | **Plan** | `PreToolUse` on `ExitPlanMode` (Claude Code) | nothing it *informs*. See [`shomra plan`](#shomra-plan--threat-model-what-the-agent-is-about-to-build) |
288
+ | **Plan** | `PreToolUse` on `ExitPlanMode` (Claude Code) | nothing - it *informs*. See [`shomra plan`](#shomra-plan--threat-model-what-the-agent-is-about-to-build) |
289
289
 
290
290
  The prompt channel is the one a person controls, and the only one where the leak
291
291
  is a paste rather than a tool call. A live credential in a prompt is refused;
292
292
  pasted text that reads as an instruction to an agent is passed through but
293
- flagged **to the model** as untrusted data rather than blocked you meant to
293
+ flagged **to the model** as untrusted data rather than blocked - you meant to
294
294
  send it, the risk is that you did not read it. Backtick-quoted payloads are
295
295
  down-ranked, so asking *why does `<pattern>` get flagged* is never blocked.
296
296
  `SHOMRA_PROMPT_GUARD_OFF=1` disables just this channel. Only the two vendors with
@@ -310,10 +310,10 @@ shomra rules --check # CI: fail when the block goes stale
310
310
  shomra mcp install # let the agent gate its own content before writing it
311
311
  ```
312
312
 
313
- ### `shomra design` threat-model the ticket, not the repo
313
+ ### `shomra design` - threat-model the ticket, not the repo
314
314
 
315
- Every other command needs an artifact. This one reads a **description** an RFC,
316
- a design doc, a Jira/Linear ticket, a PR body and answers the only question
315
+ Every other command needs an artifact. This one reads a **description** - an RFC,
316
+ a design doc, a Jira/Linear ticket, a PR body - and answers the only question
317
317
  worth asking before anyone writes code: does the thing being described hand an
318
318
  attacker a path from untrusted input to a consequence?
319
319
 
@@ -327,7 +327,7 @@ shomra design docs/rfc-042.md --checklist | gh issue comment 42 -F -
327
327
  It uses the platform's own model: capabilities split into **sources** (untrusted
328
328
  input, sensitive data, filesystem) and **sinks** (network egress, execution,
329
329
  destructive action). A closed source→sink pair is an attack path. That model does
330
- not care whether the capabilities came from a scan or from a sentence here they
330
+ not care whether the capabilities came from a scan or from a sentence - here they
331
331
  come from a sentence, and each one cites the line that evidenced it so you can
332
332
  disagree with the machine's reading.
333
333
 
@@ -336,7 +336,7 @@ anyone actually acts on: paste it into the ticket as acceptance criteria.
336
336
 
337
337
  > **It reads prose, so it sees only what was written down.** There is deliberately
338
338
  > no clean verdict. `NOT_DESCRIBED` means the document did not describe
339
- > capabilities in a way this matched it is **not** a statement that the system
339
+ > capabilities in a way this matched - it is **not** a statement that the system
340
340
  > has none. A threat model that reads as a clean bill of health is worse than
341
341
  > none, because it is consumed exactly when the design is still cheap to change.
342
342
 
@@ -344,7 +344,7 @@ Exit codes: `1` when untrusted input reaches execution or a destructive action
344
344
  (the shape where the attacker picks the action), `2` for any other closed path
345
345
  under `--strict`.
346
346
 
347
- ### `shomra plan` threat-model what the agent is about to build
347
+ ### `shomra plan` - threat-model what the agent is about to build
348
348
 
349
349
  `design` reads a document a human remembered to write. Coding agents produce a
350
350
  **plan** before every non-trivial task, constantly and automatically, and nothing
@@ -357,11 +357,11 @@ refuse it three tool calls later.
357
357
 
358
358
  Three ways in, deliberately redundant, strongest first:
359
359
 
360
- 1. **`shomra_review_plan`** an MCP tool, so any MCP-capable agent can call it
360
+ 1. **`shomra_review_plan`** - an MCP tool, so any MCP-capable agent can call it
361
361
  mid-task with no vendor hook. Register it with `shomra mcp install`.
362
362
  2. **The rules block asks the agent to call it.** Once the MCP server is
363
363
  registered, `shomra rules --write` adds a *Before you implement a plan*
364
- section so `mcp install` and `rules --write` compose into a closed loop.
364
+ section - so `mcp install` and `rules --write` compose into a closed loop.
365
365
  3. **A Claude Code `PreToolUse` hook on `ExitPlanMode`**, wired by
366
366
  `install-hook`. Zero-effort, but that tool name is not in the published hook
367
367
  docs, so it is the optional path and never the only one.
@@ -371,22 +371,22 @@ shomra plan plan.md # or: … | shomra plan -
371
371
  ```
372
372
 
373
373
  **A plan is a proposal, so the default is to inform, never refuse.** Denying a
374
- plan spends a turn and tells the model only that it was wrong, not how the
374
+ plan spends a turn and tells the model only that it was wrong, not how - the
375
375
  controls are the useful payload. Only untrusted-input-reaches-a-hard-sink
376
376
  escalates to *ask*, and only under `SHOMRA_GUARD_STRICT=1`.
377
377
  `SHOMRA_PLAN_GUARD_OFF=1` disables just this channel.
378
378
 
379
- ### `shomra corpus` screen the index, not the retrieval
379
+ ### `shomra corpus` - screen the index, not the retrieval
380
380
 
381
381
  The result firewall screens what a retrieval brings *back*. Nothing screened what
382
- went **in** so a poisoned document sits in the vector store indefinitely,
382
+ went **in** - so a poisoned document sits in the vector store indefinitely,
383
383
  clean-until-retrieved, and is judged for the first time at the worst possible
384
384
  moment: as one chunk, stripped of its document, inside a request a user is
385
385
  waiting on.
386
386
 
387
387
  Index time wins on all three counts. The whole document is present, so a payload
388
388
  split across paragraphs is visible. The cost is paid once per document instead of
389
- once per retrieval. And a document that fails is simply never embedded a
389
+ once per retrieval. And a document that fails is simply never embedded - a
390
390
  control rather than a detection.
391
391
 
392
392
  ```bash
@@ -398,8 +398,8 @@ shomra corpus ./kb --manifest .shomra/corpus.json
398
398
  HIGH Injected instruction: "ignore all previous" (line 243 · chunk 19)
399
399
  ✗ QUARANTINE hidden.md
400
400
  CRITICAL Invisible / bidirectional characters
401
- ⚠ 2 files could not be read they are NOT covered by the result above:
402
- 2 × binary format no text extractor
401
+ ⚠ 2 files could not be read - they are NOT covered by the result above:
402
+ 2 × binary format - no text extractor
403
403
  ```
404
404
 
405
405
  Findings carry the **chunk index**, not just the line, because retrieval returns
@@ -408,16 +408,16 @@ point of the command: feed it to your ingestion job so a quarantined document is
408
408
  never embedded.
409
409
 
410
410
  > **Absence accounting is load-bearing.** Real corpora are mostly PDF, DOCX and
411
- > PPTX formats this cannot read. A screen that silently skips them and prints
411
+ > PPTX - formats this cannot read. A screen that silently skips them and prints
412
412
  > "clean" is a lie about the majority of the corpus, so every unreadable file is
413
413
  > counted and reported next to the verdict, and `--strict` fails on them:
414
414
  > *we could not check it* is not *it is fine*.
415
415
 
416
- Fenced code blocks are down-ranked a docs corpus is full of examples, and an
416
+ Fenced code blocks are down-ranked - a docs corpus is full of examples, and an
417
417
  example is not a live instruction. A directive in prose is the real threat and
418
418
  survives the down-rank.
419
419
 
420
- ### `shomra add` vet at acquisition, not after
420
+ ### `shomra add` - vet at acquisition, not after
421
421
 
422
422
  `mcp add` gated one channel. An agent acquires from four, and the other three had
423
423
  no gate at all: a skill copied out of a gist, a model pulled from the Hub, a
@@ -436,11 +436,11 @@ the question changes from *should we take this?* to *is it safe to remove?*,
436
436
  which is a much worse question to be asked.
437
437
 
438
438
  **Unknown is never clean.** An unreachable Model Index, an unscanned model, and a
439
- package the AI catalog does not recognise all return **FLAG**, not ALLOW
439
+ package the AI catalog does not recognise all return **FLAG**, not ALLOW -
440
440
  "we could not check" and "it is fine" are different answers.
441
441
 
442
- **`shomra rules`** compiles what Shomra actually enforces plus what *this repo*
443
- already trips, plus your org's policy when enrolled into the agent's own
442
+ **`shomra rules`** compiles what Shomra actually enforces - plus what *this repo*
443
+ already trips, plus your org's policy when enrolled - into the agent's own
444
444
  context files:
445
445
 
446
446
  | Agent | File |
@@ -465,7 +465,7 @@ The generated block is itself an AI rules file, so `shomra rules` gates its own
465
465
  output and refuses to write anything its own checker would block.
466
466
 
467
467
  **`shomra mcp install`** registers Shomra *as* an MCP server with your agents, so
468
- the model can call it in its own loop most usefully `shomra_review_change`,
468
+ the model can call it in its own loop - most usefully `shomra_review_change`,
469
469
  which takes proposed file content plus its intended path and returns a verdict
470
470
  **without writing anything to disk**. A BLOCK there costs nothing; the same
471
471
  content on disk costs a blocked tool call and a wasted turn. `shomra_rules`,
@@ -476,21 +476,21 @@ prefer to wire it by hand.
476
476
  ## Adopting Shomra on an existing repo
477
477
 
478
478
  A brand-new gate on a repo with history will flag things. Three layers make
479
- adoption friction-free all of them re-grade the artifact, so a fully
479
+ adoption friction-free - all of them re-grade the artifact, so a fully
480
480
  suppressed file drops to ALLOW and never fails the build:
481
481
 
482
482
  - **`shomra baseline`** records every current finding (line-independent
483
- fingerprints) in `.shomra/baseline.json` commit it so the whole team shares
483
+ fingerprints) in `.shomra/baseline.json` - commit it so the whole team shares
484
484
  it. From then on only findings introduced *after* the baseline fail; re-run it
485
485
  to refresh after cleanups. Skip it per-run with `--no-baseline`.
486
- - **`.shomraignore`** a repo file of `path/glob` lines (skip the file) or
486
+ - **`.shomraignore`** - a repo file of `path/glob` lines (skip the file) or
487
487
  `path/glob :: title-substring` lines (skip one finding class in those files).
488
488
  The runtime firewall honors it too, so test fixtures and detection source
489
489
  aren't withheld. Silence a single finding inline with `// shomra-ignore` (or
490
490
  `# shomra-ignore`) on the finding's line or the line above, or opt a whole
491
491
  file out with `shomra-ignore-file` in its first lines (works in JSON as a
492
492
  `"_shomra": "shomra-ignore-file"` key). `--no-suppress` ignores all of this.
493
- - **`.shomra/policy.yml`** policy-as-code, reviewed in PRs like any code:
493
+ - **`.shomra/policy.yml`** - policy-as-code, reviewed in PRs like any code:
494
494
 
495
495
  ```yaml
496
496
  block: high # min severity that BLOCKS (critical|high|medium|low|none)
@@ -500,7 +500,7 @@ suppressed file drops to ALLOW and never fails the build:
500
500
  ```
501
501
 
502
502
  For a local verdict the repo policy fully re-grades; when the backend
503
- returned an org decision it can only make it *stricter* (worst-wins) repo
503
+ returned an org decision it can only make it *stricter* (worst-wins) - repo
504
504
  config never loosens org enforcement. `--no-policy` skips it.
505
505
 
506
506
  ## Environment variables
@@ -511,7 +511,7 @@ suppressed file drops to ALLOW and never fails the build:
511
511
  | `SHOMRA_URL` | Backend URL (overrides config) |
512
512
  | `SHOMRA_API_TIMEOUT_MS` | Per-request backend timeout (default 30000) |
513
513
  | `SHOMRA_AGENT` | Agent-identity handle presented to `llm-proxy` + firewall |
514
- | `SHOMRA_GATE_CONCURRENCY` | Parallel backend calls in batch gate / model lookups (default 8, 132) |
514
+ | `SHOMRA_GATE_CONCURRENCY` | Parallel backend calls in batch gate / model lookups (default 8, 1-32) |
515
515
  | `SHOMRA_GH_TOKEN` | GitHub token for `shomra pr` (falls back to `GITHUB_TOKEN`) |
516
516
  | `SHOMRA_GUARD_STRICT` | `1` = firewall fails closed on the server tier |
517
517
  | `SHOMRA_GUARD_LOCAL` | `0` = disable the on-machine Tier-0 guard |
package/package.json CHANGED
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "name": "@shomra/agent",
3
- "version": "0.3.16",
4
- "description": "Shomra adversarial assurance for AI agents, as a local-first CLI. Blocks dangerous tool-calls before they run, attacks your own guardrails to prove they hold, and gates AI artifacts in your editor and CI.",
3
+ "version": "0.3.18",
4
+ "description": "Shomra - adversarial assurance for AI agents, as a local-first CLI. Blocks dangerous tool-calls before they run, attacks your own guardrails to prove they hold, and gates AI artifacts in your editor and CI.",
5
5
  "type": "module",
6
6
  "bin": {
7
7
  "shomra": "./shomra.mjs"
@@ -14,13 +14,7 @@
14
14
  },
15
15
  "files": [
16
16
  "shomra.mjs",
17
- "discovery.mjs",
18
- "guard-signals.mjs",
19
- "guard-ledger.mjs",
20
- "code-sast.mjs",
21
- "model-refs.mjs",
22
- "ai-usage.mjs",
23
- "design.mjs",
17
+ "src",
24
18
  "README.md",
25
19
  "LICENSE",
26
20
  "NOTICE"