praxis-sec 1.0.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 (183) hide show
  1. package/LICENSE +21 -0
  2. package/README.md +170 -0
  3. package/ai-defense/cost-protection.md +292 -0
  4. package/ai-defense/llm-security-checklist.md +324 -0
  5. package/ai-defense/prompt-injection-patterns.js +283 -0
  6. package/ai-defense/system-prompt-armor.md +327 -0
  7. package/checklists/launch-day.md +168 -0
  8. package/cli/agents/abom-generator.js +225 -0
  9. package/cli/agents/agent-attestation-agent.js +318 -0
  10. package/cli/agents/agent-config-scanner.js +787 -0
  11. package/cli/agents/agent-telemetry-agent.js +415 -0
  12. package/cli/agents/agentic-security-agent.js +296 -0
  13. package/cli/agents/agentic-supply-chain-agent.js +463 -0
  14. package/cli/agents/ai-infra-inventory-agent.js +449 -0
  15. package/cli/agents/api-fuzzer.js +345 -0
  16. package/cli/agents/auth-bypass-agent.js +348 -0
  17. package/cli/agents/base-agent.js +280 -0
  18. package/cli/agents/cicd-scanner.js +300 -0
  19. package/cli/agents/config-auditor.js +757 -0
  20. package/cli/agents/deep-analyzer.js +776 -0
  21. package/cli/agents/endpoint-agent-abuse-agent.js +404 -0
  22. package/cli/agents/exception-handler-agent.js +187 -0
  23. package/cli/agents/git-history-scanner.js +169 -0
  24. package/cli/agents/governance-audits.js +138 -0
  25. package/cli/agents/hermes-security-agent.js +536 -0
  26. package/cli/agents/html-reporter.js +1125 -0
  27. package/cli/agents/index.js +147 -0
  28. package/cli/agents/injection-tester.js +502 -0
  29. package/cli/agents/legal-risk-agent.js +328 -0
  30. package/cli/agents/llm-redteam.js +199 -0
  31. package/cli/agents/managed-agent-scanner.js +333 -0
  32. package/cli/agents/mcp-security-agent.js +588 -0
  33. package/cli/agents/memory-poisoning-agent.js +305 -0
  34. package/cli/agents/mobile-scanner.js +231 -0
  35. package/cli/agents/model-file-scanner.js +259 -0
  36. package/cli/agents/orchestrator.js +355 -0
  37. package/cli/agents/pii-compliance-agent.js +301 -0
  38. package/cli/agents/policy-engine.js +229 -0
  39. package/cli/agents/prompt-injection-prober.js +224 -0
  40. package/cli/agents/rag-security-agent.js +204 -0
  41. package/cli/agents/recon-agent.js +207 -0
  42. package/cli/agents/sbom-generator.js +265 -0
  43. package/cli/agents/scoring-engine.js +273 -0
  44. package/cli/agents/ssrf-prober.js +130 -0
  45. package/cli/agents/stateful-watcher.js +238 -0
  46. package/cli/agents/supabase-rls-agent.js +154 -0
  47. package/cli/agents/supply-chain-agent.js +857 -0
  48. package/cli/agents/swarm-orchestrator.js +200 -0
  49. package/cli/agents/verifier-agent.js +303 -0
  50. package/cli/agents/vibe-coding-agent.js +250 -0
  51. package/cli/bin/praxis.js +866 -0
  52. package/cli/commands/abom.js +73 -0
  53. package/cli/commands/agent-fix.js +1245 -0
  54. package/cli/commands/audit.js +1180 -0
  55. package/cli/commands/autofix.js +383 -0
  56. package/cli/commands/baseline.js +193 -0
  57. package/cli/commands/benchmark.js +327 -0
  58. package/cli/commands/checklist.js +223 -0
  59. package/cli/commands/ci.js +403 -0
  60. package/cli/commands/deps.js +516 -0
  61. package/cli/commands/diff.js +200 -0
  62. package/cli/commands/doctor.js +195 -0
  63. package/cli/commands/env-audit.js +349 -0
  64. package/cli/commands/fix.js +218 -0
  65. package/cli/commands/guard.js +396 -0
  66. package/cli/commands/hooks.js +278 -0
  67. package/cli/commands/init.js +514 -0
  68. package/cli/commands/legal.js +158 -0
  69. package/cli/commands/live-advisories.js +241 -0
  70. package/cli/commands/mcp.js +660 -0
  71. package/cli/commands/openclaw.js +386 -0
  72. package/cli/commands/red-team.js +350 -0
  73. package/cli/commands/redteam.js +78 -0
  74. package/cli/commands/remediate.js +797 -0
  75. package/cli/commands/rotate.js +768 -0
  76. package/cli/commands/rules.js +196 -0
  77. package/cli/commands/scan-mcp.js +534 -0
  78. package/cli/commands/scan-skill.js +588 -0
  79. package/cli/commands/scan-standard.js +251 -0
  80. package/cli/commands/scan.js +524 -0
  81. package/cli/commands/score.js +449 -0
  82. package/cli/commands/shell.js +514 -0
  83. package/cli/commands/team-report.js +398 -0
  84. package/cli/commands/undo.js +161 -0
  85. package/cli/commands/update-intel.js +126 -0
  86. package/cli/commands/vibe-check.js +276 -0
  87. package/cli/commands/watch.js +757 -0
  88. package/cli/commands/web.js +63 -0
  89. package/cli/core/ast/guardrail-detector.js +141 -0
  90. package/cli/core/ast/index.js +22 -0
  91. package/cli/core/ast/parser.js +676 -0
  92. package/cli/core/ast/scope-tree.js +287 -0
  93. package/cli/core/ast/taint-tracker.js +158 -0
  94. package/cli/core/branding.js +37 -0
  95. package/cli/core/env.js +38 -0
  96. package/cli/core/errors.js +61 -0
  97. package/cli/core/fs.js +62 -0
  98. package/cli/core/output/compliance.js +90 -0
  99. package/cli/core/output/html-theme.js +158 -0
  100. package/cli/core/output/index.js +57 -0
  101. package/cli/core/output/json.js +48 -0
  102. package/cli/core/output/sarif.js +240 -0
  103. package/cli/core/version.js +67 -0
  104. package/cli/core/web/jobs.js +183 -0
  105. package/cli/core/web/projects.js +146 -0
  106. package/cli/core/web/server.js +439 -0
  107. package/cli/data/atlas-knowledge.json +5640 -0
  108. package/cli/data/eaa-catalog.json +39 -0
  109. package/cli/data/known-mcps.json +26 -0
  110. package/cli/data/probes/prompt-injection-corpus.json +271 -0
  111. package/cli/data/threat-intel.json +85 -0
  112. package/cli/data/threatpacks/latest.json +41 -0
  113. package/cli/hooks/patterns.js +313 -0
  114. package/cli/hooks/post-tool-use.js +140 -0
  115. package/cli/hooks/pre-tool-use.js +186 -0
  116. package/cli/index.js +90 -0
  117. package/cli/providers/llm-provider.js +766 -0
  118. package/cli/utils/autofix-rules.js +74 -0
  119. package/cli/utils/cache-manager.js +310 -0
  120. package/cli/utils/compliance-map.js +191 -0
  121. package/cli/utils/entropy.js +132 -0
  122. package/cli/utils/fix-ledger.js +127 -0
  123. package/cli/utils/hermes-tool-registry.js +252 -0
  124. package/cli/utils/intel/cache.js +61 -0
  125. package/cli/utils/intel/http.js +88 -0
  126. package/cli/utils/intel/index.js +235 -0
  127. package/cli/utils/intel/merge.js +229 -0
  128. package/cli/utils/intel/sources/epss.js +54 -0
  129. package/cli/utils/intel/sources/ghsa.js +81 -0
  130. package/cli/utils/intel/sources/gitguardian.js +40 -0
  131. package/cli/utils/intel/sources/gitleaks.js +101 -0
  132. package/cli/utils/intel/sources/kev.js +38 -0
  133. package/cli/utils/intel/sources/nvd.js +84 -0
  134. package/cli/utils/intel/sources/osv.js +132 -0
  135. package/cli/utils/intel/sources/phylum.js +44 -0
  136. package/cli/utils/intel/sources/snyk.js +46 -0
  137. package/cli/utils/intel/sources/socket.js +69 -0
  138. package/cli/utils/intel/sources/sonatype.js +84 -0
  139. package/cli/utils/intel/sources/threatpack.js +69 -0
  140. package/cli/utils/mcp-trust.js +60 -0
  141. package/cli/utils/output.js +251 -0
  142. package/cli/utils/patterns.js +1130 -0
  143. package/cli/utils/pdf-generator.js +94 -0
  144. package/cli/utils/plugin-loader.js +364 -0
  145. package/cli/utils/rule-import.js +228 -0
  146. package/cli/utils/rule-registry.js +426 -0
  147. package/cli/utils/scan-fingerprint.js +109 -0
  148. package/cli/utils/scan-playbook.js +312 -0
  149. package/cli/utils/score-history.js +119 -0
  150. package/cli/utils/secrets-verifier.js +247 -0
  151. package/cli/utils/security-memory.js +296 -0
  152. package/cli/utils/standards/atlas-knowledge.js +87 -0
  153. package/cli/utils/standards/index.js +127 -0
  154. package/cli/utils/standards/sources/avid.js +45 -0
  155. package/cli/utils/standards/sources/eu-ai-act.js +89 -0
  156. package/cli/utils/standards/sources/google-saif.js +39 -0
  157. package/cli/utils/standards/sources/iso-42001.js +94 -0
  158. package/cli/utils/standards/sources/mitre-atlas.js +54 -0
  159. package/cli/utils/standards/sources/nist-ai-600-1.js +45 -0
  160. package/cli/utils/standards/sources/owasp-llm.js +45 -0
  161. package/cli/utils/standards/sources/owasp-ml.js +45 -0
  162. package/cli/utils/threat-intel.js +265 -0
  163. package/configs/firebase/firestore-rules.txt +215 -0
  164. package/configs/firebase/security-checklist.md +236 -0
  165. package/configs/firebase/storage-rules.txt +206 -0
  166. package/configs/gitignore-template +258 -0
  167. package/configs/nextjs-security-headers.js +220 -0
  168. package/configs/praxisignore-template +50 -0
  169. package/configs/supabase/secure-client.ts +225 -0
  170. package/configs/supabase/security-checklist.md +278 -0
  171. package/docs/THIRD_PARTY_NOTICES.md +26 -0
  172. package/docs/THREAT_INTEL.md +292 -0
  173. package/docs/USAGE.md +1205 -0
  174. package/docs/design/WEB-UI.md +82 -0
  175. package/package.json +71 -0
  176. package/scripts/check-determinism.mjs +119 -0
  177. package/snippets/README.md +122 -0
  178. package/snippets/api-security/api-security-checklist.md +412 -0
  179. package/snippets/api-security/cors-config.ts +322 -0
  180. package/snippets/api-security/input-validation.ts +430 -0
  181. package/snippets/auth/jwt-checklist.md +322 -0
  182. package/snippets/rate-limiting/nextjs-middleware.ts +211 -0
  183. package/snippets/rate-limiting/upstash-ratelimit.ts +229 -0
@@ -0,0 +1,292 @@
1
+ # Threat Intelligence — Praxis
2
+
3
+ This is the local quick reference for the multi-source threat-intel system that
4
+ powers `praxis scan`, `praxis intel deps`, the supply-chain agent, and every
5
+ other command that consumes the merged feed. It explains what each command
6
+ does, how the system is laid out internally, and what knobs you can turn.
7
+
8
+ For everything else (general CLI usage, scanning, hooks, etc.), see the main
9
+ [`README.md`](./README.md).
10
+
11
+ ---
12
+
13
+ ## 1. Commands
14
+
15
+ Run these from any directory — they only touch `~/.praxis/` (your home dir).
16
+
17
+ | Command | What it does |
18
+ | --- | --- |
19
+ | `praxis intel update` | Refresh every configured source in parallel |
20
+ | `praxis intel update --list` | List all available sources and which are active |
21
+ | `praxis intel update --only osv,kev,epss` | Refresh a subset (comma-separated names) |
22
+ | `praxis intel update --force` | Ignore per-source TTL caches and re-fetch |
23
+ | `praxis scan ci .` | Normal CI run (does not enforce intel freshness) |
24
+ | `praxis scan ci . --strict-intel` | Fail CI if the merged feed is stale or core sources errored |
25
+ | `praxis scan ci . --strict-intel --max-intel-age 24h` | Custom freshness window (`7d`, `24h`, `30m`, `60s`) |
26
+
27
+ `praxis intel update` is safe to run any time — it caches per source and falls
28
+ back to the last good payload if a source is offline. Stale data is preferred
29
+ over no data.
30
+
31
+ ### First-time setup
32
+
33
+ ```bash
34
+ # Pull every free source. No keys required.
35
+ praxis intel update
36
+ ```
37
+
38
+ Expected output:
39
+
40
+ ```
41
+ Fetching sources...
42
+
43
+ osv OK
44
+ ghsa OK
45
+ kev OK
46
+ epss OK
47
+ nvd OK
48
+ gitleaks OK
49
+ snyk skipped (SNYK_TOKEN not set)
50
+ socket skipped (SOCKET_API_KEY not set)
51
+ ...
52
+
53
+ Merged feed v1.0.1 written.
54
+
55
+ Indicators loaded:
56
+ CVE advisories: ...
57
+ KEV entries: 1586
58
+ EPSS scores: ...
59
+ Extra secret rules: 221
60
+ ```
61
+
62
+ ### CI usage
63
+
64
+ ```bash
65
+ # Soft mode — runs even if the feed is missing.
66
+ praxis scan ci .
67
+
68
+ # Hard mode — fails the build if intel is older than 7 days
69
+ # or any core source erred on the last update.
70
+ praxis scan ci . --strict-intel
71
+ ```
72
+
73
+ ---
74
+
75
+ ## 2. Architecture
76
+
77
+ ```
78
+ cli/
79
+ ├── bin/
80
+ │ └── praxis.js # CLI entry; defines update-intel + ci flags
81
+ ├── commands/
82
+ │ ├── update-intel.js # User-facing command (progress, summary)
83
+ │ └── ci.js # Reads intel-meta.json, applies strict-intel
84
+ ├── utils/
85
+ │ ├── threat-intel.js # ThreatIntel class — query API
86
+ │ └── intel/
87
+ │ ├── index.js # runUpdate() orchestrator + isStale()
88
+ │ ├── cache.js # Per-source TTL'd disk cache
89
+ │ ├── http.js # safeFetch (timeout + retry + backoff)
90
+ │ ├── merge.js # mergeIntel(seed, results) → unified schema
91
+ │ └── sources/
92
+ │ ├── osv.js # core
93
+ │ ├── ghsa.js # core
94
+ │ ├── kev.js # core
95
+ │ ├── epss.js # core
96
+ │ ├── nvd.js # core
97
+ │ ├── gitleaks.js # core
98
+ │ ├── snyk.js # optional
99
+ │ ├── socket.js # optional
100
+ │ ├── gitguardian.js # optional
101
+ │ ├── sonatype.js # optional (works anonymously, env raises limits)
102
+ │ └── phylum.js # optional
103
+ └── agents/
104
+ └── supply-chain-agent.js # Consumes ThreatIntel.lookupOsv / lookupGhsa,
105
+ # enriches findings with KEV/EPSS signals
106
+ ```
107
+
108
+ ### Update flow
109
+
110
+ 1. `praxis intel update` calls `runUpdate()` in `cli/utils/intel/index.js`.
111
+ 2. **Pass 1** — every source except NVD runs in parallel via `Promise.all`.
112
+ - Each source first checks `cache.read(name)`. If the cache is fresh
113
+ (within its TTL), it's reused and `'cached'` is reported.
114
+ - Otherwise it calls `source.fetchAll()`, writes the result to
115
+ `~/.praxis/intel/<name>.json`, and reports `'ok'`.
116
+ - On fetch error, the source falls back to whatever's in the cache
117
+ (even if stale) so a transient outage doesn't blow away your data.
118
+ - Optional sources without their env var return `{ skipped: true }` and
119
+ are reported `'skipped'`.
120
+ 3. **Pass 2** — NVD runs after Pass 1, using the union of CVEs collected from
121
+ OSV/GHSA/KEV to decide which CVE descriptions to fetch (capped at 500).
122
+ 4. `mergeIntel(seed, results)` produces the unified feed. Internal merge
123
+ functions per source build:
124
+ - `osvIndex[ecosystem/package]` → array of advisories
125
+ - `ghsaIndex[ecosystem/package]` → array of advisories
126
+ - `cveAdvisories[]` (deduplicated by CVE)
127
+ - `kevList[]`, `kevDetails{}`, `epssScores{}`, `nvdDetails{}`
128
+ - `secretRules[]` (Gitleaks regex rules)
129
+ - `sources{}` (per-source status / stats / error)
130
+ 5. The merged feed is written to `~/.praxis/threat-intel.json` and a
131
+ summary to `~/.praxis/intel-meta.json`.
132
+
133
+ ### Query flow
134
+
135
+ `ThreatIntel` (in `cli/utils/threat-intel.js`) lazy-loads the merged feed once
136
+ and caches it in memory. Resolution order:
137
+
138
+ 1. `~/.praxis/threat-intel.json` (merged feed)
139
+ 2. `cli/data/threat-intel.json` (bundled seed)
140
+
141
+ Public API (used by agents and scanners):
142
+
143
+ ```js
144
+ ThreatIntel.lookupOsv(pkg, version, ecosystem) // → [{...advisory, isAffected}]
145
+ ThreatIntel.lookupGhsa(pkg, ecosystem)
146
+ ThreatIntel.getEpss(cve) // → {score, percentile} | null
147
+ ThreatIntel.isInKev(cve) // → bool
148
+ ThreatIntel.getKevDetails(cve)
149
+ ThreatIntel.getNvdDetail(cve)
150
+ ThreatIntel.getExtraSecretRules() // → [{id, regex, ...}]
151
+ ThreatIntel.stats() // → counts for each indicator
152
+ ThreatIntel.isStale(maxAgeMs)
153
+ ```
154
+
155
+ ### File layout (on disk)
156
+
157
+ ```
158
+ ~/.praxis/
159
+ ├── intel/
160
+ │ ├── osv.json # raw per-source payload + fetchedAt + ttlMs
161
+ │ ├── ghsa.json
162
+ │ ├── kev.json
163
+ │ └── ...
164
+ ├── threat-intel.json # merged feed (everything joined into one file)
165
+ └── intel-meta.json # { updatedAt, version, sources: {...} }
166
+ ```
167
+
168
+ You can delete any of these to force a clean re-fetch. They will be recreated
169
+ on the next `praxis intel update` run.
170
+
171
+ ---
172
+
173
+ ## 3. Customization
174
+
175
+ ### Sources
176
+
177
+ | Source | Tier | Env var | TTL | Notes |
178
+ | --- | --- | --- | --- | --- |
179
+ | `osv` | core | — | 12h | OSV.dev queries (npm, PyPI, Go, Maven, NuGet, RubyGems...) |
180
+ | `ghsa` | core | `GITHUB_TOKEN` or `GH_TOKEN` *(optional, raises rate limit)* | 12h | GitHub Advisory DB |
181
+ | `kev` | core | — | 24h | CISA Known Exploited Vulnerabilities |
182
+ | `epss` | core | — | 24h | FIRST.org exploit-likelihood scores |
183
+ | `nvd` | core | `NVD_API_KEY` *(optional, faster requests)* | 7d | CVE detail enrichment |
184
+ | `gitleaks` | core | — | 7d | Gitleaks regex rule set |
185
+ | `threatpack` | core | — (override with `PRAXIS_THREATPACK_URL`) | 7d | Praxis AI attack-vector signature pack — prompt-injection probes, EAA additions, model-gateway allowlists. Bundled seed at `cli/data/threatpacks/latest.json`; a fetch failure degrades to the seed |
186
+ | `snyk` | optional | `SNYK_TOKEN` (+ `SNYK_ORG_ID`) | 12h | Snyk Vulnerability DB |
187
+ | `socket` | optional | `SOCKET_API_KEY` | 6h | Socket.dev supply-chain risk |
188
+ | `gitguardian` | optional | `GITGUARDIAN_API_KEY` | 7d | GitGuardian secret detector defs |
189
+ | `sonatype` | optional | `SONATYPE_USER` + `SONATYPE_TOKEN` *(works anonymously too)* | 12h | OSS Index |
190
+ | `phylum` | optional | `PHYLUM_API_KEY` | 6h | Phylum supply-chain risk |
191
+
192
+ Without any env vars the system fully works using the seven core sources. Optional
193
+ sources gracefully report `skipped` and don't fail the run.
194
+
195
+ ### Environment variables
196
+
197
+ ```bash
198
+ # Optional — speeds up GHSA and NVD by raising rate limits.
199
+ export GITHUB_TOKEN=ghp_...
200
+ export NVD_API_KEY=...
201
+
202
+ # Optional paid sources — enable any subset by setting the corresponding key.
203
+ export SNYK_TOKEN=...
204
+ export SNYK_ORG_ID=...
205
+ export SOCKET_API_KEY=...
206
+ export GITGUARDIAN_API_KEY=...
207
+ export SONATYPE_USER=...
208
+ export SONATYPE_TOKEN=...
209
+ export PHYLUM_API_KEY=...
210
+ ```
211
+
212
+ After setting an env var, run `praxis intel update --list` to confirm it
213
+ shows up as `[active]`.
214
+
215
+ ### Tuning freshness
216
+
217
+ Per-source TTLs are constants at the top of each
218
+ `cli/utils/intel/sources/<name>.js` file (see the table above). To shorten the
219
+ TTL — e.g. fetch KEV every 6 hours instead of 24 — edit `kev.js`:
220
+
221
+ ```js
222
+ const TTL_MS = 6 * 60 * 60 * 1000;
223
+ ```
224
+
225
+ ### CI freshness gate
226
+
227
+ ```bash
228
+ praxis scan ci . --strict-intel --max-intel-age 24h
229
+ ```
230
+
231
+ Accepted duration formats: `7d`, `24h`, `30m`, `60s`. Default is `7d`. The
232
+ gate fails if either:
233
+ - `~/.praxis/intel-meta.json` is missing or older than the threshold, **or**
234
+ - any **core** source's last update errored without a stale-cache fallback.
235
+
236
+ Optional/paid sources never fail the gate — only core sources do.
237
+
238
+ ### Adding a custom source
239
+
240
+ A source is just an ES module that exports five things:
241
+
242
+ ```js
243
+ // cli/utils/intel/sources/my-source.js
244
+ export const name = 'mysource';
245
+ export const tier = 'optional'; // 'core' or 'optional'
246
+ export const description = 'My custom advisory feed';
247
+ export const envKey = 'MYSOURCE_API_KEY'; // optional
248
+ export const TTL = 6 * 60 * 60 * 1000; // 6h
249
+
250
+ export async function fetchAll(args) {
251
+ const key = process.env.MYSOURCE_API_KEY;
252
+ if (!key) return { skipped: true, reason: 'MYSOURCE_API_KEY not set' };
253
+ // ...fetch and return a payload...
254
+ return { records: [...] };
255
+ }
256
+ ```
257
+
258
+ Then register it in `cli/utils/intel/index.js`:
259
+
260
+ ```js
261
+ import * as mysource from './sources/my-source.js';
262
+ const ALL_SOURCES = [..., mysource];
263
+ ```
264
+
265
+ If you want the merger to do something special with the payload (e.g. populate
266
+ `osvIndex`), add a case for `name === 'mysource'` in `cli/utils/intel/merge.js`.
267
+ Otherwise it'll just appear under `sources.mysource` in the merged feed without
268
+ contributing to any index.
269
+
270
+ ### Reset everything
271
+
272
+ ```bash
273
+ rm -rf ~/.praxis/intel ~/.praxis/threat-intel.json ~/.praxis/intel-meta.json
274
+ praxis intel update
275
+ ```
276
+
277
+ This wipes all caches and the merged feed. The bundled seed at
278
+ `cli/data/threat-intel.json` is untouched, so scanning still works in the
279
+ window between deletion and the next update.
280
+
281
+ ---
282
+
283
+ ## 4. Troubleshooting
284
+
285
+ | Symptom | Cause / fix |
286
+ | --- | --- |
287
+ | `Indicators loaded: 0` after a successful update | The in-memory `ThreatIntel` cache wasn't invalidated — re-run the command, or restart the process. |
288
+ | `praxis intel update` is slow | NVD is rate-limited (6s between requests without a key). Set `NVD_API_KEY` to drop to 600ms. |
289
+ | GHSA reports `error: HTTP 403` | Set `GITHUB_TOKEN` to lift the unauthenticated rate limit. |
290
+ | A source reports `error` but the run still succeeds | By design — the orchestrator falls back to the cached payload. Check `~/.praxis/intel/<source>.json` for the last known good copy. |
291
+ | `praxis scan ci --strict-intel` fails locally | Run `praxis intel update` first. The freshness window defaults to 7 days. |
292
+ | Feed lives somewhere else | `~/.praxis/` is derived from `os.homedir()`. Override `HOME` (Unix) or `USERPROFILE` (Windows) to relocate it (this is how the test suite isolates state). |