@beingmartinbmc/ojas 0.2.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 (174) hide show
  1. package/LICENSE +21 -0
  2. package/README.md +308 -0
  3. package/dist/aahar/index.d.ts +179 -0
  4. package/dist/aahar/index.d.ts.map +1 -0
  5. package/dist/aahar/index.js +657 -0
  6. package/dist/aahar/index.js.map +1 -0
  7. package/dist/aahar/scoring.d.ts +85 -0
  8. package/dist/aahar/scoring.d.ts.map +1 -0
  9. package/dist/aahar/scoring.js +268 -0
  10. package/dist/aahar/scoring.js.map +1 -0
  11. package/dist/agni/index.d.ts +113 -0
  12. package/dist/agni/index.d.ts.map +1 -0
  13. package/dist/agni/index.js +328 -0
  14. package/dist/agni/index.js.map +1 -0
  15. package/dist/agni/model-router.d.ts +77 -0
  16. package/dist/agni/model-router.d.ts.map +1 -0
  17. package/dist/agni/model-router.js +163 -0
  18. package/dist/agni/model-router.js.map +1 -0
  19. package/dist/agni/response-distiller.d.ts +37 -0
  20. package/dist/agni/response-distiller.d.ts.map +1 -0
  21. package/dist/agni/response-distiller.js +193 -0
  22. package/dist/agni/response-distiller.js.map +1 -0
  23. package/dist/agni/tiktoken-adapter.d.ts +55 -0
  24. package/dist/agni/tiktoken-adapter.d.ts.map +1 -0
  25. package/dist/agni/tiktoken-adapter.js +113 -0
  26. package/dist/agni/tiktoken-adapter.js.map +1 -0
  27. package/dist/chikitsa/index.d.ts +130 -0
  28. package/dist/chikitsa/index.d.ts.map +1 -0
  29. package/dist/chikitsa/index.js +565 -0
  30. package/dist/chikitsa/index.js.map +1 -0
  31. package/dist/demo.d.ts +15 -0
  32. package/dist/demo.d.ts.map +1 -0
  33. package/dist/demo.js +278 -0
  34. package/dist/demo.js.map +1 -0
  35. package/dist/index.d.ts +201 -0
  36. package/dist/index.d.ts.map +1 -0
  37. package/dist/index.js +588 -0
  38. package/dist/index.js.map +1 -0
  39. package/dist/mcp/audit.d.ts +39 -0
  40. package/dist/mcp/audit.d.ts.map +1 -0
  41. package/dist/mcp/audit.js +73 -0
  42. package/dist/mcp/audit.js.map +1 -0
  43. package/dist/mcp/contracts.d.ts +76 -0
  44. package/dist/mcp/contracts.d.ts.map +1 -0
  45. package/dist/mcp/contracts.js +44 -0
  46. package/dist/mcp/contracts.js.map +1 -0
  47. package/dist/mcp/envelope.d.ts +107 -0
  48. package/dist/mcp/envelope.d.ts.map +1 -0
  49. package/dist/mcp/envelope.js +162 -0
  50. package/dist/mcp/envelope.js.map +1 -0
  51. package/dist/mcp/registry.d.ts +110 -0
  52. package/dist/mcp/registry.d.ts.map +1 -0
  53. package/dist/mcp/registry.js +258 -0
  54. package/dist/mcp/registry.js.map +1 -0
  55. package/dist/mcp/server.d.ts +26 -0
  56. package/dist/mcp/server.d.ts.map +1 -0
  57. package/dist/mcp/server.js +107 -0
  58. package/dist/mcp/server.js.map +1 -0
  59. package/dist/mcp/tools/agent.d.ts +4 -0
  60. package/dist/mcp/tools/agent.d.ts.map +1 -0
  61. package/dist/mcp/tools/agent.js +300 -0
  62. package/dist/mcp/tools/agent.js.map +1 -0
  63. package/dist/mcp/tools/context.d.ts +4 -0
  64. package/dist/mcp/tools/context.d.ts.map +1 -0
  65. package/dist/mcp/tools/context.js +261 -0
  66. package/dist/mcp/tools/context.js.map +1 -0
  67. package/dist/mcp/tools/index.d.ts +5 -0
  68. package/dist/mcp/tools/index.d.ts.map +1 -0
  69. package/dist/mcp/tools/index.js +20 -0
  70. package/dist/mcp/tools/index.js.map +1 -0
  71. package/dist/mcp/tools/memory.d.ts +4 -0
  72. package/dist/mcp/tools/memory.d.ts.map +1 -0
  73. package/dist/mcp/tools/memory.js +220 -0
  74. package/dist/mcp/tools/memory.js.map +1 -0
  75. package/dist/mcp/tools/output.d.ts +4 -0
  76. package/dist/mcp/tools/output.d.ts.map +1 -0
  77. package/dist/mcp/tools/output.js +206 -0
  78. package/dist/mcp/tools/output.js.map +1 -0
  79. package/dist/mcp/tools/recovery.d.ts +4 -0
  80. package/dist/mcp/tools/recovery.d.ts.map +1 -0
  81. package/dist/mcp/tools/recovery.js +165 -0
  82. package/dist/mcp/tools/recovery.js.map +1 -0
  83. package/dist/mcp/tools/registrar.d.ts +4 -0
  84. package/dist/mcp/tools/registrar.d.ts.map +1 -0
  85. package/dist/mcp/tools/registrar.js +17 -0
  86. package/dist/mcp/tools/registrar.js.map +1 -0
  87. package/dist/mcp/tools/report.d.ts +4 -0
  88. package/dist/mcp/tools/report.d.ts.map +1 -0
  89. package/dist/mcp/tools/report.js +68 -0
  90. package/dist/mcp/tools/report.js.map +1 -0
  91. package/dist/mcp/tools/shared.d.ts +37 -0
  92. package/dist/mcp/tools/shared.d.ts.map +1 -0
  93. package/dist/mcp/tools/shared.js +214 -0
  94. package/dist/mcp/tools/shared.js.map +1 -0
  95. package/dist/mcp/trace.d.ts +47 -0
  96. package/dist/mcp/trace.d.ts.map +1 -0
  97. package/dist/mcp/trace.js +216 -0
  98. package/dist/mcp/trace.js.map +1 -0
  99. package/dist/nidra/index.d.ts +275 -0
  100. package/dist/nidra/index.d.ts.map +1 -0
  101. package/dist/nidra/index.js +889 -0
  102. package/dist/nidra/index.js.map +1 -0
  103. package/dist/persistence/migrations.d.ts +10 -0
  104. package/dist/persistence/migrations.d.ts.map +1 -0
  105. package/dist/persistence/migrations.js +77 -0
  106. package/dist/persistence/migrations.js.map +1 -0
  107. package/dist/persistence/sqlite.d.ts +30 -0
  108. package/dist/persistence/sqlite.d.ts.map +1 -0
  109. package/dist/persistence/sqlite.js +209 -0
  110. package/dist/persistence/sqlite.js.map +1 -0
  111. package/dist/persistence/types.d.ts +104 -0
  112. package/dist/persistence/types.d.ts.map +1 -0
  113. package/dist/persistence/types.js +5 -0
  114. package/dist/persistence/types.js.map +1 -0
  115. package/dist/pulse/index.d.ts +144 -0
  116. package/dist/pulse/index.d.ts.map +1 -0
  117. package/dist/pulse/index.js +453 -0
  118. package/dist/pulse/index.js.map +1 -0
  119. package/dist/raksha/classifiers/http-classifier.d.ts +26 -0
  120. package/dist/raksha/classifiers/http-classifier.d.ts.map +1 -0
  121. package/dist/raksha/classifiers/http-classifier.js +62 -0
  122. package/dist/raksha/classifiers/http-classifier.js.map +1 -0
  123. package/dist/raksha/classifiers/index.d.ts +5 -0
  124. package/dist/raksha/classifiers/index.d.ts.map +1 -0
  125. package/dist/raksha/classifiers/index.js +8 -0
  126. package/dist/raksha/classifiers/index.js.map +1 -0
  127. package/dist/raksha/classifiers/onnx-classifier.d.ts +41 -0
  128. package/dist/raksha/classifiers/onnx-classifier.d.ts.map +1 -0
  129. package/dist/raksha/classifiers/onnx-classifier.js +99 -0
  130. package/dist/raksha/classifiers/onnx-classifier.js.map +1 -0
  131. package/dist/raksha/hallucination-detectors.d.ts +106 -0
  132. package/dist/raksha/hallucination-detectors.d.ts.map +1 -0
  133. package/dist/raksha/hallucination-detectors.js +327 -0
  134. package/dist/raksha/hallucination-detectors.js.map +1 -0
  135. package/dist/raksha/index.d.ts +168 -0
  136. package/dist/raksha/index.d.ts.map +1 -0
  137. package/dist/raksha/index.js +597 -0
  138. package/dist/raksha/index.js.map +1 -0
  139. package/dist/raksha/prompt-injection-detectors.d.ts +30 -0
  140. package/dist/raksha/prompt-injection-detectors.d.ts.map +1 -0
  141. package/dist/raksha/prompt-injection-detectors.js +153 -0
  142. package/dist/raksha/prompt-injection-detectors.js.map +1 -0
  143. package/dist/types.d.ts +1115 -0
  144. package/dist/types.d.ts.map +1 -0
  145. package/dist/types.js +71 -0
  146. package/dist/types.js.map +1 -0
  147. package/dist/util/calibration.d.ts +32 -0
  148. package/dist/util/calibration.d.ts.map +1 -0
  149. package/dist/util/calibration.js +108 -0
  150. package/dist/util/calibration.js.map +1 -0
  151. package/dist/util/id.d.ts +2 -0
  152. package/dist/util/id.d.ts.map +1 -0
  153. package/dist/util/id.js +9 -0
  154. package/dist/util/id.js.map +1 -0
  155. package/dist/vyayam/index.d.ts +76 -0
  156. package/dist/vyayam/index.d.ts.map +1 -0
  157. package/dist/vyayam/index.js +528 -0
  158. package/dist/vyayam/index.js.map +1 -0
  159. package/dist/vyayam/tool-fault-proxy.d.ts +95 -0
  160. package/dist/vyayam/tool-fault-proxy.d.ts.map +1 -0
  161. package/dist/vyayam/tool-fault-proxy.js +170 -0
  162. package/dist/vyayam/tool-fault-proxy.js.map +1 -0
  163. package/docs/ARCHITECTURE.md +162 -0
  164. package/docs/BACKLOG.md +342 -0
  165. package/docs/CONFIGURATION.md +305 -0
  166. package/docs/EVIDENCE.md +232 -0
  167. package/docs/EVIDENCE_MATRIX.md +293 -0
  168. package/docs/KNOWN_FAILURES.md +367 -0
  169. package/docs/MCP.md +614 -0
  170. package/docs/MODULES.md +368 -0
  171. package/docs/SECURITY.md +251 -0
  172. package/docs/TRUST.md +88 -0
  173. package/docs/assets/ojas-hero.png +0 -0
  174. package/package.json +101 -0
@@ -0,0 +1,368 @@
1
+ # Module Reference
2
+
3
+ Seven specialised modules. Each maps to an analogue of a human-health system. Each exposes a 0–100 health score plus lower-level dimensions surfaced through `healthCheck()` and the MCP `ojas_get_health` / `ojas_generate_health_report` tools.
4
+
5
+ | Section | Role |
6
+ |---|---|
7
+ | [🥗 Aahar — Cognitive Nutrition](#aahar) | What the agent reads |
8
+ | [😴 Nidra — Recovery & Consolidation](#nidra) | How the agent learns from experience |
9
+ | [💪 Vyayam — Resilience & Stress](#vyayam) | How the agent holds up under pressure |
10
+ | [🛡️ Raksha — Immune Defense](#raksha) | What threats the agent rejects |
11
+ | [🔥 Agni — Cognitive Metabolism](#agni) | How efficiently the agent burns tokens / latency / tools |
12
+ | [📈 Pulse — Health Telemetry](#pulse) | Continuous vital-signs bus |
13
+ | [🩺 Chikitsa — Repair & Rehabilitation](#chikitsa) | What to do when something breaks |
14
+ | [Unified Health Report](#report) | Aggregate score + per-module dimensions |
15
+ | [Health Events](#events) | Canonical event payloads emitted by Pulse |
16
+
17
+ ---
18
+
19
+ <a id="aahar"></a>
20
+ ## 🥗 1. Aahar (आहार) — Cognitive Nutrition
21
+
22
+ Aahar controls what an AI agent cognitively consumes.
23
+
24
+ Agents consume context, retrieval results, memory, instructions, tool outputs, and prior reasoning traces. Poor intake leads to hallucination, instability, wasted tokens, and planning errors.
25
+
26
+ Aahar helps by:
27
+
28
+ - filtering irrelevant, stale, redundant, or noisy context
29
+ - ranking context by relevance, freshness, trust, and risk
30
+ - reducing cognitive load and attention fragmentation
31
+ - improving signal-to-noise ratio per token
32
+ - keeping the agent focused on the current objective
33
+
34
+ ```typescript
35
+ const healthy = ojas.feed(rawContextItems);
36
+
37
+ const result = await ojas.feedAndProcess(
38
+ 'Design an API',
39
+ rawContextItems
40
+ );
41
+ ```
42
+
43
+ Under the hood, `feed()` runs Raksha first, then Aahar:
44
+
45
+ ```text
46
+ raw context → immune defense → nutrition scoring → healthy context
47
+ ```
48
+
49
+ ---
50
+
51
+ <a id="nidra"></a>
52
+ ## 😴 2. Nidra (निद्रा) — Recovery and Consolidation
53
+
54
+ Nidra controls how agents recover, stabilize, and learn from experience.
55
+
56
+ Human sleep consolidates memory, removes noise, and restores cognition. Nidra brings the same idea to agent runtimes by turning execution traces into reusable intelligence.
57
+
58
+ Nidra helps by:
59
+
60
+ - consolidating traces into memories and heuristics
61
+ - detecting repeated failures and drift patterns
62
+ - compressing experience into reusable summaries
63
+ - reducing memory noise and cognitive instability
64
+ - extracting lessons from completed tasks
65
+
66
+ ```typescript
67
+ ojas.recordTrace({
68
+ id: 'trace-1',
69
+ agentId: 'research-agent',
70
+ action: 'search',
71
+ input: {},
72
+ output: {},
73
+ success: true,
74
+ durationMs: 120,
75
+ timestamp: new Date().toISOString(),
76
+ });
77
+
78
+ const recovery = await ojas.recover();
79
+
80
+ console.log(recovery.recovered);
81
+ console.log(recovery.memoriesCreated);
82
+ ```
83
+
84
+ Consolidated memories can be injected back into the bound agent through the `AgentAdapter` interface.
85
+
86
+ > **Transactionality:** `Ojas.recover()` is two-phase — `Nidra.analyseUnprocessed()` produces candidate memories without mutating, each is injected into the agent via `injectMemory()`, then `Nidra.commitAnalysis()` commits. If any injection throws, no traces are marked processed and no memories are persisted; a `recovery_injection_failed` pulse event explains the abort. See [`docs/CONFIGURATION.md`](./CONFIGURATION.md#adapter) for the adapter contract.
87
+
88
+ ---
89
+
90
+ <a id="vyayam"></a>
91
+ ## 💪 3. Vyayam (व्यायाम) — Resilience and Stress Engineering
92
+
93
+ Vyayam controls how agents become stronger under pressure.
94
+
95
+ Agents should not only be tested in clean, ideal conditions. They must be tested against ambiguity, hostile inputs, tool failures, memory corruption, and unstable environments.
96
+
97
+ Vyayam helps by:
98
+
99
+ - generating controlled stress scenarios
100
+ - testing prompt-injection resistance
101
+ - simulating tool failure, latency, and conflicting instructions
102
+ - measuring hallucination resistance and recovery ability
103
+ - identifying fragile workflows and weak reasoning patterns
104
+
105
+ Supported stress types include:
106
+
107
+ - adversarial input
108
+ - prompt injection
109
+ - memory corruption
110
+ - tool failure
111
+ - latency spike
112
+ - conflicting instructions
113
+ - context overflow
114
+ - ambiguous goal
115
+
116
+ ```typescript
117
+ const results = await ojas.stressTest();
118
+
119
+ console.log(results.passed);
120
+ console.log(results.failed);
121
+ console.log(results.hallucinationsDetected);
122
+
123
+ const scenario = ojas.vyayam.generateScenario('prompt_injection', 0.8);
124
+ ```
125
+
126
+ > Each scenario runs against the bound agent within `policy.maxScenarioDurationMs` (default 30s). Agents that exceed the budget are recorded as failed scenarios rather than hanging the harness.
127
+
128
+ ---
129
+
130
+ <a id="raksha"></a>
131
+ ## 🛡️ 4. Raksha (रक्षा) — Immune Defense (heuristic tripwire)
132
+
133
+ Raksha is a **regex-based prompt-injection tripwire**. It catches canonical attempts to override instructions, exfiltrate secrets, or confuse the agent's role, and it now reduces several common obfuscation bypasses (Cyrillic/Greek homoglyphs, zero-width insertions, full-width Latin, and one-shot printable base64). It still misses recursive obfuscation, non-covered homoglyphs, indirect/multi-document injection, policy laundering, and roleplay attacks — see [`KNOWN_FAILURES.md` → Raksha](./KNOWN_FAILURES.md#raksha-heuristic-regex-tripwire-with-a-bypass-reduction-pipeline). Treat it as one layer in defence-in-depth, not as a security boundary.
134
+
135
+ As agents consume web pages, documents, tool outputs, code, emails, and memories, they become vulnerable to malicious instructions and memory poisoning.
136
+
137
+ Raksha helps by:
138
+
139
+ - flagging canonical prompt-injection and instruction-override phrasings
140
+ - flagging canonical role-confusion and data-exfiltration phrasings
141
+ - quarantining risky context before it reaches the agent (heuristic; bypassable)
142
+ - preserving the system / developer / user instruction hierarchy by routing flagged items into quarantine
143
+ - downgrading or rejecting unsafe / low-confidence long-term memory writes
144
+
145
+ ```typescript
146
+ const { safe, quarantined, assessments } = ojas.raksha.defendContext(items);
147
+
148
+ console.log(safe);
149
+ console.log(quarantined);
150
+ console.log(assessments);
151
+ ```
152
+
153
+ Example assessment:
154
+
155
+ ```typescript
156
+ {
157
+ itemId: 'ctx-12',
158
+ threatType: 'prompt_injection',
159
+ riskScore: 0.72,
160
+ quarantined: true,
161
+ reasons: ['Attempts to override higher-priority instructions.']
162
+ }
163
+ ```
164
+
165
+ > Raksha is a regex-based tripwire today, not a learned classifier. Do **not** rely on it as a sole defence. Read [`SECURITY.md`](./SECURITY.md) and [`KNOWN_FAILURES.md`](./KNOWN_FAILURES.md) before deploying.
166
+
167
+ ---
168
+
169
+ <a id="agni"></a>
170
+ ## 🔥 5. Agni (अग्नि) — Cognitive Metabolism
171
+
172
+ Agni manages how efficiently the agent converts cognitive intake into useful action.
173
+
174
+ Agent cost is not only model cost. It also includes token waste, unnecessary retrieval, repeated tool calls, long latency, excessive reasoning, and failed retries.
175
+
176
+ Agni helps by:
177
+
178
+ - estimating reasoning depth from task risk and ambiguity
179
+ - optimizing token budgets and retrieval volume
180
+ - tracking latency and cost pressure
181
+ - detecting wasteful tool usage
182
+ - balancing deep reasoning with fast execution
183
+
184
+ ```typescript
185
+ const effort = ojas.agni.estimateReasoningEffort(0.9, 0.7);
186
+ // → 'deep'
187
+
188
+ const metabolism = ojas.agni.assess();
189
+
190
+ console.log(metabolism.tokenEfficiency);
191
+ console.log(metabolism.toolEconomy);
192
+ console.log(metabolism.costPressure);
193
+ ```
194
+
195
+ > **Token accounting falls back through three tiers:** explicit `trace.tokensUsed` → `trace.inputTokens + trace.outputTokens` → payload-length estimate. Failed tool calls still count against the average, because failed tokens still cost money.
196
+
197
+ ---
198
+
199
+ <a id="pulse"></a>
200
+ ## 📈 6. Pulse — Health Telemetry
201
+
202
+ Pulse continuously monitors the agent's cognitive vital signs.
203
+
204
+ Traditional telemetry tracks latency, logs, and errors. Pulse tracks agent health: clarity, context quality, memory health, drift, recovery, resilience, trust, and stability.
205
+
206
+ Pulse helps by:
207
+
208
+ - emitting structured health events
209
+ - detecting degradation before complete failure
210
+ - tracking repeated loops, fallback overuse, and contradiction
211
+ - routing health triggers to the correct Ojas module
212
+ - supporting dashboards and alerting systems
213
+
214
+ ```typescript
215
+ const telemetry = ojas.pulse.assess();
216
+
217
+ console.log(telemetry.vitalSigns);
218
+ console.log(telemetry.degradationRisk);
219
+ console.log(telemetry.activeAlerts);
220
+
221
+ const events = ojas.pulse.getEvents();
222
+ ```
223
+
224
+ ---
225
+
226
+ <a id="chikitsa"></a>
227
+ ## 🩺 7. Chikitsa (चिकित्सा) — Repair and Rehabilitation
228
+
229
+ Chikitsa diagnoses failures and generates structured repair protocols.
230
+
231
+ When an agent fails, the cause may be bad context, weak planning, unsafe memory, retrieval error, tool failure, instruction conflict, prompt injection, or model limitation. Chikitsa classifies the failure and recommends recovery actions.
232
+
233
+ Chikitsa helps by:
234
+
235
+ - identifying the likely failure cause
236
+ - generating repair protocols
237
+ - recommending rollback, reset, retry, or escalation
238
+ - preparing agents for rehabilitation through Vyayam
239
+ - recommending recovery so repeated failures don't become permanent behaviour *(advisory; correctness of the recommendation is not measured — see [`KNOWN_FAILURES.md` → Chikitsa](./KNOWN_FAILURES.md#chikitsa-recommendations-are-pattern-lookups))*
240
+
241
+ ```typescript
242
+ const protocols = ojas.chikitsa.diagnose([
243
+ {
244
+ type: 'tool_error',
245
+ message: 'Search API returned 503',
246
+ severity: 'high',
247
+ },
248
+ {
249
+ type: 'prompt_injection',
250
+ message: 'Instruction override attempt detected',
251
+ severity: 'critical',
252
+ },
253
+ ]);
254
+
255
+ console.log(protocols);
256
+ ```
257
+
258
+ Example protocol actions:
259
+
260
+ ```text
261
+ context_reset
262
+ memory_rollback
263
+ tool_retry
264
+ plan_regeneration
265
+ retrieval_refresh
266
+ instruction_regrounding
267
+ safe_mode_activation
268
+ human_escalation
269
+ ```
270
+
271
+ > **Preview vs commit:** `previewDiagnose()` returns the same protocols `diagnose()` would emit but without recording them. Useful inside `healthCheck()`, which is intentionally read-only and surfaces would-be repairs via the `previewRepairProtocols` field.
272
+
273
+ ---
274
+
275
+ <a id="report"></a>
276
+ ## Unified Health Report
277
+
278
+ ```typescript
279
+ const report = ojas.healthCheck(activeContext);
280
+
281
+ console.log(`Overall: ${Math.round(report.overall.value * 100)} / 100`);
282
+ console.log(report.moduleScores);
283
+ console.log(report.recommendations);
284
+ console.log(report.events);
285
+ ```
286
+
287
+ Example `moduleScores`:
288
+
289
+ ```typescript
290
+ {
291
+ aahar: 91,
292
+ nidra: 78,
293
+ vyayam: 97,
294
+ raksha: 93,
295
+ agni: 96,
296
+ pulse: 68,
297
+ chikitsa: 72
298
+ }
299
+ ```
300
+
301
+ Each module exposes a 0–100 health score plus lower-level dimensions:
302
+
303
+ | Module | Dimensions |
304
+ |---|---|
305
+ | `aahar` | `contextQuality`, `cognitiveLoad`, `attentionFocus`, `signalToNoise`, `tokenEfficiency` |
306
+ | `nidra` | `memoryConsolidation`, `cognitiveStability`, `learningRate`, `driftScore` |
307
+ | `vyayam` | `overallResilience`, `hallucinationResistance`, `recoveryAbility`, `planningStability`, `weaknesses[]` |
308
+ | `raksha` | `threatResistance`, `instructionIntegrity`, `quarantineEffectiveness`, `threatsDetected`, `quarantinedItems` |
309
+ | `agni` | `tokenEfficiency`, `toolEconomy`, `reasoningEfficiency`, `latencyEfficiency`, `costPressure` |
310
+ | `pulse` | `vitalSigns`, `degradationRisk`, `observabilityCoverage`, `eventsEmitted`, `activeAlerts` |
311
+ | `chikitsa` | `repairReadiness`, `rollbackSafety`, `recoveryPlaybooks`, `protocolsAvailable` |
312
+
313
+ ---
314
+
315
+ <a id="events"></a>
316
+ ## Health Events
317
+
318
+ Ojas emits canonical health events that can be consumed by dashboards, logs, alerting systems, or MCP clients.
319
+
320
+ ### Context overload
321
+
322
+ ```typescript
323
+ {
324
+ eventType: 'context_overload_detected',
325
+ detectedBy: 'aahar',
326
+ severity: 'medium',
327
+ details: {
328
+ contextTokens: 128000,
329
+ relevanceScore: 0.52,
330
+ duplicateContextRatio: 0.31,
331
+ },
332
+ recommendedAction: 'compress_context_and_rerank_memory',
333
+ }
334
+ ```
335
+
336
+ ### Recovery completed
337
+
338
+ ```typescript
339
+ {
340
+ eventType: 'recovery_cycle_completed',
341
+ detectedBy: 'nidra',
342
+ details: {
343
+ rawTracesProcessed: 42,
344
+ memoriesCreated: 5,
345
+ memoriesPruned: 11,
346
+ heuristicsUpdated: 3,
347
+ driftReduction: 0.18,
348
+ },
349
+ }
350
+ ```
351
+
352
+ ### Prompt injection quarantined
353
+
354
+ ```typescript
355
+ {
356
+ eventType: 'prompt_injection_quarantined',
357
+ detectedBy: 'raksha',
358
+ severity: 'critical',
359
+ details: {
360
+ source: 'retrieved_webpage',
361
+ attackType: 'instruction_override',
362
+ riskScore: 0.72,
363
+ actionTaken: 'quarantined_from_agent_context',
364
+ },
365
+ }
366
+ ```
367
+
368
+ See `KnownHealthEventType` and the `*Details` interfaces in `src/types.ts` for the full event schema.
@@ -0,0 +1,251 @@
1
+ # Security policy for Ojas
2
+
3
+ > **Trust model in one sentence:** Ojas v0.3 is **stdio-only, single
4
+ > trusted tenant**. The MCP host that launches the process is trusted;
5
+ > agent IDs are *routing identifiers, not credentials*. The security
6
+ > boundary is the OS / process boundary, not a per-call authentication
7
+ > layer. Acknowledge the model by setting `OJAS_TRUSTED_SINGLE_TENANT=1`
8
+ > (otherwise the server emits a loud stderr warning at startup). Do
9
+ > **not** expose the MCP server to untrusted callers, multiple tenants,
10
+ > or the network without an external authenticated gateway.
11
+
12
+ ## MCP authentication
13
+
14
+ Ojas MCP v0.3 is **stdio-only**. Stdio MCP does not provide a portable
15
+ caller identity, bearer-token channel, or per-request auth context —
16
+ the host that launches the process *is* the caller. Therefore Ojas does
17
+ not implement in-process MCP authentication in this version, and that
18
+ is **a scope decision, not a missing feature**.
19
+
20
+ The security boundary is the local OS / process boundary. Use:
21
+
22
+ - one process per trusted user / workspace
23
+ - OS user isolation
24
+ - workspace-specific configuration
25
+ - `OJAS_DISABLE_AUTO_REGISTER=1`
26
+ - `OJAS_ALLOWED_AGENT_IDS=<agent>`
27
+ - `OJAS_MAX_AGENTS=1` where appropriate
28
+
29
+ Network transports (HTTP, SSE, streamable-HTTP) are **out of scope**
30
+ unless protected by an external authentication and authorization layer.
31
+ If Ojas ever ships a non-stdio transport, that transport will fail
32
+ closed unless auth is configured.
33
+
34
+ ## MCP audit logging
35
+
36
+ When `OJAS_AUDIT=1` is set, the MCP server emits structured JSONL audit
37
+ entries to stderr for critical operations: agent registration, policy
38
+ changes, safe-mode toggles, health checks, and quarantine events. Each
39
+ entry contains `timestamp`, `operation`, `agentId`, `sessionId`,
40
+ `args_summary`, `result_summary`, and `durationMs`.
41
+
42
+ This is a local audit trail, not a centralized log pipeline. For
43
+ production multi-tenant deployments, feed stderr into your SIEM or log
44
+ aggregator.
45
+
46
+ ## Recommended network deployment architecture
47
+
48
+ Ojas itself does **not** implement HTTP transport, TLS termination, or
49
+ per-request authentication. For network-facing or multi-user deployments,
50
+ front the Ojas MCP server with an authenticated gateway:
51
+
52
+ ```
53
+ ┌─────────────┐ stdio ┌────────────────┐
54
+ │ nginx / │ ───────────→ │ Ojas MCP │
55
+ │ Caddy + │ │ (stdio server) │
56
+ │ OAuth2 │ └────────────────┘
57
+ │ Proxy │
58
+ └─────────────┘
59
+ ↑ HTTPS + OAuth2 / mTLS
60
+
61
+ Clients (IDEs, agents, CI)
62
+ ```
63
+
64
+ The gateway should provide:
65
+ - TLS termination
66
+ - OAuth2 / mTLS client authentication
67
+ - Tenant-ID header propagation (Ojas uses `agent_id` as a routing
68
+ identifier; the gateway maps authenticated users to allowed agent IDs)
69
+ - Rate limiting per tenant
70
+ - Request/response logging
71
+
72
+ ## Security non-goals for v0.3
73
+
74
+ To prevent recurring review churn, this version explicitly does **not**
75
+ implement:
76
+
77
+ - multi-user authentication on the MCP boundary
78
+ - per-client authorization or capability scoping
79
+ - network-facing access control
80
+ - tenant isolation between agents on the same process
81
+ - secret / token management
82
+
83
+ If you need any of those, run Ojas behind an authenticated MCP gateway
84
+ or use one Ojas process per trusted user / workspace.
85
+
86
+ ## Persistence encryption and backup
87
+
88
+ ### Encryption-at-rest
89
+
90
+ `SQLitePersistenceStore` supports encryption-at-rest via SQLCipher. Pass
91
+ `encryptionKey` in the options:
92
+
93
+ ```typescript
94
+ const store = new SQLitePersistenceStore({
95
+ dbPath: './ojas-data.db',
96
+ encryptionKey: process.env.OJAS_DB_KEY, // 256-bit key recommended
97
+ });
98
+ ```
99
+
100
+ This issues `PRAGMA key = '<key>'` at database open. Requires a
101
+ SQLCipher-compatible build of `better-sqlite3` (e.g., build with
102
+ `--build-from-source` against `sqlcipher`).
103
+
104
+ ### Backup and restore
105
+
106
+ ```typescript
107
+ // Hot backup (safe while server is running):
108
+ await store.backup('/backups/ojas-2026-05-14.db');
109
+
110
+ // Restore (closes current DB, copies, reopens):
111
+ await store.restore('/backups/ojas-2026-05-14.db');
112
+ ```
113
+
114
+ **Backup cadence recommendation**: daily for development, hourly for
115
+ production single-node deployments. The backup API uses `better-sqlite3`'s
116
+ native `.backup()` which is safe during concurrent reads.
117
+
118
+ ### Multi-host architecture pattern
119
+
120
+ For multi-host / multi-tenant / HA production, Ojas's SQLite store is not
121
+ sufficient. Instead:
122
+
123
+ 1. Implement `PersistenceStore` against your chosen backend
124
+ (Postgres, Turso, CockroachDB).
125
+ 2. Use the `PersistenceStore` interface — it requires `loadSessions`,
126
+ `saveSession`, `deleteSession`, and optionally `backup`/`restore`.
127
+ 3. Run one Ojas instance per host, each connected to the shared backend.
128
+ 4. Use the external database's own replication, encryption, and backup
129
+ facilities.
130
+
131
+ ## Production hardening checklist
132
+
133
+ The Ojas MCP server is designed for local IDE use. Before deploying to
134
+ anything else, at minimum:
135
+
136
+ | Setting | Recommended value | Why |
137
+ |---|---|---|
138
+ | `OJAS_TRUSTED_SINGLE_TENANT` | `1` | Acknowledge the trust model. Suppresses the startup warning but does **not** add auth. |
139
+ | `OJAS_DISABLE_AUTO_REGISTER` | `1` | Reject MCP calls for unknown `agent_id`s. Prevents an attacker who knows the schema from spinning up arbitrary agents. |
140
+ | `OJAS_ALLOWED_AGENT_IDS` | `a,b,c` | Hard allowlist of `agent_id`s the server will accept. |
141
+ | `OJAS_MAX_AGENTS` | small number | Bound registry growth. |
142
+ | `OJAS_ALLOW_REPLACE_EXISTING` | unset | Leave OFF in production. Replacement wipes accumulated Ojas state; default is to reject the request. |
143
+
144
+ A defence-in-depth deployment also wraps the MCP server with an
145
+ auth-aware MCP gateway, runs it in a process that cannot reach
146
+ production secrets, and treats every Ojas health score as advisory
147
+ rather than authoritative.
148
+
149
+ ## What Ojas's "immune defense" actually is
150
+
151
+ Ojas's Raksha module is **a deterministic detector stack** with an
152
+ optional **async classifier plugin interface**. The rule-based core
153
+ combines patterns, Unicode/base64 bypass reduction, and a semantic-intent
154
+ detector. When `classifiers` are configured, Raksha merges ML
155
+ probabilities with rule-based scores (max wins). It catches forms of:
156
+
157
+ - direct instruction overrides (`ignore previous instructions`, etc.)
158
+ - system / developer / role boundary markup (`<system>...</system>`)
159
+ - exfiltration-shaped phrases (`reveal the api_key`, `print the system prompt`)
160
+ - a handful of role-confusion and memory-poisoning patterns
161
+ - common policy-laundering frames that demote system/developer policy
162
+
163
+ It is **explicitly not** a complete prompt-injection defense system. The
164
+ current bypass-reduction pipeline handles Cyrillic/Greek homoglyphs,
165
+ zero-width insertions, full-width Latin, one-shot printable base64 payloads,
166
+ and common policy-laundering frames, but Raksha will still likely miss:
167
+
168
+ - novel paraphrased attacks outside the semantic-intent rules
169
+ - recursive / nested obfuscation, including base64-inside-base64 payloads
170
+ - non-Cyrillic / non-Greek homoglyphs and other Unicode confusables
171
+ - multi-turn / multi-item attacks split across context entries
172
+ - indirect injection in retrieved documents
173
+ - tool-output injection that exploits formatting / serialization boundaries
174
+ - benign content that legitimately discusses credentials, system prompts, or
175
+ similar terms (false positives on security documentation)
176
+ - adversarially-crafted Unicode / RTL / control-character sequences
177
+ - prompts that combine task-completion with subtle policy violation
178
+
179
+ **Do not** rely on Raksha as a sole control for any decision that has real
180
+ security or compliance impact. Treat it as one layer in a defense-in-depth
181
+ strategy, alongside (at minimum):
182
+
183
+ - a dedicated prompt-injection classifier or model judge
184
+ - structured-document isolation (the agent never reads raw retrieval verbatim)
185
+ - least-privilege tool capabilities and signed retrieval sources
186
+ - explicit human-in-the-loop gates on irreversible actions
187
+ - secret-redaction at retrieval / tool-output boundaries
188
+ - output filtering for known-leak patterns
189
+
190
+ ## What is in scope to harden
191
+
192
+ - Expanding obfuscation-resistant detection beyond the current one-shot normalization and decode pipeline
193
+ - ✅ **Done**: Pluggable `PromptInjectionClassifier` interface — callers can swap in a learned model
194
+ - ✅ **Done**: Bundled `OnnxPromptInjectionClassifier` (local ONNX inference) and `HttpPromptInjectionClassifier` (external API) shipped as reference implementations
195
+ - Source-trust policies (signed retrieval, allowlist by domain)
196
+ - Memory-write quarantine with reflection-only release
197
+ - Per-event-type retention and rate limiting on the MCP boundary
198
+
199
+ ## Reporting a vulnerability
200
+
201
+ If you believe you've found a security-relevant bug — for example a payload
202
+ that bypasses Raksha and reaches the agent context, a way to escape MCP
203
+ isolation, or a behaviour that contradicts the safety defaults documented
204
+ here — please:
205
+
206
+ 1. Open a private security advisory via GitHub's "Report a vulnerability"
207
+ workflow on the repository.
208
+ 2. Or email the maintainer listed in `package.json`.
209
+ 3. Please do **not** open a public issue first.
210
+
211
+ Include:
212
+ - a minimal reproduction (input / configuration / version)
213
+ - the observed vs expected behaviour
214
+ - impact (what an attacker could do)
215
+
216
+ We aim to acknowledge reports within a few days. As an early-stage project,
217
+ we make no formal time-to-fix guarantees.
218
+
219
+ ## Defaults that prefer safety over convenience
220
+
221
+ The following defaults are intentional, not accidental:
222
+
223
+ - `ojas_consolidate_memory.allow_new_memories` defaults to `false`. Memory
224
+ writes are dangerous; an explicit opt-in is required to commit.
225
+ - `ojas_run_recovery.mode` defaults to `recommend`. Apply-mode is opt-in.
226
+ - `criticalRequiresHuman` is enforced via `human_escalation` appended to
227
+ every critical repair protocol's actions.
228
+ - `OJAS_DISABLE_AUTO_REGISTER=1` rejects MCP calls for unregistered agents.
229
+ Production deployments are encouraged to set this.
230
+ - `OJAS_MAX_AGENTS` (default 256) caps registry growth to prevent unbounded
231
+ state expansion from a malicious / buggy client.
232
+ - `Aahar.filter()` rejects malformed numeric inputs rather than silently
233
+ letting them bypass token budgets or dominate prioritization.
234
+
235
+ ## Known limitations
236
+
237
+ These are not bugs, they are intentional v0.3 scope:
238
+
239
+ - The MCP server is stdio-only and assumes the launching host is trusted.
240
+ See the "MCP authentication" and "Security non-goals" sections above
241
+ — this is the intended trust boundary for v0.3, not a deferred fix.
242
+ For shared deployments, add an auth-aware MCP gateway in front or run
243
+ one process per trusted user / workspace.
244
+ - SQLite persistence is local single-node. For multi-host, implement
245
+ `PersistenceStore` against an external database (see "Multi-host
246
+ architecture pattern" above).
247
+ - Health scores are heuristic; treat them as observability signals, not
248
+ ground-truth quality metrics. Empirical calibration via L3 pipeline
249
+ is available but not yet validated against real agent populations.
250
+ - The `AbortSignal` cancellation mechanism is opt-in: agents that don't
251
+ check the signal parameter will still leak work after timeout.