@sanctuary-framework/mcp-server 0.7.0 → 0.8.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.
package/dist/index.d.cts CHANGED
@@ -127,157 +127,6 @@ interface StorageBackend {
127
127
  totalSize(): Promise<number>;
128
128
  }
129
129
 
130
- /**
131
- * Sanctuary MCP Server — AES-256-GCM Encryption
132
- *
133
- * All state encryption in Sanctuary uses AES-256-GCM (authenticated encryption).
134
- * This provides both confidentiality and integrity — a modified ciphertext will
135
- * fail authentication, detecting tampering.
136
- *
137
- * Security invariants:
138
- * - Every encryption uses a unique 12-byte IV (NIST SP 800-38D)
139
- * - The 16-byte authentication tag is always verified on decryption
140
- * - Keys are 256 bits (32 bytes)
141
- */
142
- /** Encrypted payload structure stored on disk */
143
- interface EncryptedPayload {
144
- /** Format version */
145
- v: number;
146
- /** Algorithm identifier */
147
- alg: "aes-256-gcm";
148
- /** Initialization vector (base64url) */
149
- iv: string;
150
- /** Ciphertext (base64url) */
151
- ct: string;
152
- /** Authentication tag (base64url) — included in ciphertext by @noble/ciphers */
153
- /** Timestamp */
154
- ts: string;
155
- }
156
-
157
- /**
158
- * Sanctuary MCP Server — L1 Cognitive Sovereignty: StateStore
159
- *
160
- * The encrypted state store is the foundation of Sanctuary.
161
- * Every read and write goes through here. All data is encrypted
162
- * with namespace-specific keys. All writes are signed by an identity.
163
- * All reads verify integrity via Merkle proofs.
164
- *
165
- * Security invariants:
166
- * - Plaintext never touches the filesystem
167
- * - Every write gets a unique IV
168
- * - Every write is signed (non-repudiation)
169
- * - Monotonic version numbers prevent rollback
170
- * - Merkle tree verifies namespace integrity
171
- * - Secure deletion overwrites before unlinking
172
- */
173
-
174
- /** Result of a state write operation */
175
- interface WriteResult {
176
- key: string;
177
- namespace: string;
178
- version: number;
179
- merkle_root: string;
180
- written_at: string;
181
- size_bytes: number;
182
- integrity_hash: string;
183
- }
184
- /** Result of a state read operation */
185
- interface ReadResult {
186
- key: string;
187
- namespace: string;
188
- value: string;
189
- version: number;
190
- integrity_verified: boolean;
191
- merkle_proof: string[];
192
- written_at: string;
193
- written_by: string;
194
- }
195
- /** Options for state write */
196
- interface WriteOptions {
197
- content_type?: string;
198
- ttl_seconds?: number;
199
- tags?: string[];
200
- }
201
- declare class StateStore {
202
- private storage;
203
- private masterKey;
204
- private versionCache;
205
- private contentHashes;
206
- constructor(storage: StorageBackend, masterKey: Uint8Array);
207
- private versionKey;
208
- /**
209
- * Get or initialize the content hash map for a namespace.
210
- */
211
- private getNamespaceHashes;
212
- /**
213
- * Write encrypted state.
214
- *
215
- * @param namespace - Logical grouping
216
- * @param key - State key
217
- * @param value - Plaintext value (will be encrypted)
218
- * @param identityId - Identity performing the write
219
- * @param encryptedPrivateKey - Identity's encrypted private key (for signing)
220
- * @param identityEncryptionKey - Key to decrypt the identity's private key
221
- * @param options - Optional metadata
222
- */
223
- write(namespace: string, key: string, value: string, identityId: string, encryptedPrivateKey: EncryptedPayload, identityEncryptionKey: Uint8Array, options?: WriteOptions): Promise<WriteResult>;
224
- /**
225
- * Read and decrypt state.
226
- *
227
- * @param namespace - Logical grouping
228
- * @param key - State key
229
- * @param signerPublicKey - Expected signer's public key (for signature verification)
230
- * @param verifyIntegrity - Whether to verify Merkle proof (default: true)
231
- */
232
- read(namespace: string, key: string, signerPublicKey?: Uint8Array, verifyIntegrity?: boolean): Promise<ReadResult | null>;
233
- /**
234
- * List keys in a namespace (metadata only — no decryption).
235
- */
236
- list(namespace: string, prefix?: string, tags?: string[], limit?: number, offset?: number): Promise<{
237
- keys: Array<{
238
- key: string;
239
- version: number;
240
- size_bytes: number;
241
- written_at: string;
242
- tags: string[];
243
- }>;
244
- total: number;
245
- merkle_root: string;
246
- }>;
247
- /**
248
- * Securely delete state (overwrite with random bytes before removal).
249
- */
250
- delete(namespace: string, key: string): Promise<{
251
- deleted: boolean;
252
- key: string;
253
- namespace: string;
254
- new_merkle_root: string;
255
- deleted_at: string;
256
- }>;
257
- /**
258
- * Export all state for a namespace as an encrypted bundle.
259
- */
260
- export(namespace?: string): Promise<{
261
- bundle: string;
262
- namespaces: string[];
263
- total_keys: number;
264
- bundle_hash: string;
265
- exported_at: string;
266
- }>;
267
- /**
268
- * Import a previously exported state bundle.
269
- */
270
- import(bundleBase64: string, conflictResolution: "skip" | "overwrite" | "version" | undefined, publicKeyResolver: (kid: string) => Uint8Array | null): Promise<{
271
- imported_keys: number;
272
- skipped_keys: number;
273
- skipped_invalid_sig: number;
274
- skipped_unknown_kid: number;
275
- conflicts: number;
276
- namespaces: string[];
277
- imported_at: string;
278
- }>;
279
- }
280
-
281
130
  /**
282
131
  * Sanctuary MCP Server — L2 Operational Isolation: Audit Log
283
132
  *
@@ -328,942 +177,995 @@ declare class AuditLog {
328
177
  }
329
178
 
330
179
  /**
331
- * Sanctuary MCP Server — L3 Selective Disclosure: Commitment Schemes
332
- *
333
- * Cryptographic commitments allow an agent to commit to a value
334
- * without revealing it, then later prove what was committed.
335
- *
336
- * This is the MVS approach to selective disclosure — simpler than
337
- * full ZK proofs but still cryptographically sound. The commitment
338
- * is SHA-256(value || blinding_factor), which is:
339
- * - Hiding: the commitment reveals nothing about the value
340
- * - Binding: the committer cannot change the value after committing
180
+ * Sanctuary MCP Server — Principal Policy Types
341
181
  *
342
- * Security invariants:
343
- * - Blinding factors are cryptographically random (32 bytes)
344
- * - Commitments are stored encrypted under L1 sovereignty
345
- * - Revealed values are verified via constant-time comparison
182
+ * Type definitions for the Principal Policy system.
183
+ * The Principal Policy is the human-controlled, agent-immutable
184
+ * configuration that gates operations through approval tiers.
346
185
  */
347
-
348
- /** A cryptographic commitment */
349
- interface Commitment {
350
- /** The commitment hash: SHA-256(value || blinding_factor) as base64url */
351
- commitment: string;
352
- /** The blinding factor (must be stored securely for later reveal) */
353
- blinding_factor: string;
354
- /** When the commitment was created */
355
- committed_at: string;
356
- }
357
- /** Stored commitment metadata (encrypted at rest) */
358
- interface StoredCommitment {
359
- commitment: string;
360
- blinding_factor: string;
361
- value: string;
362
- committed_at: string;
363
- revealed: boolean;
364
- revealed_at?: string;
186
+ /** Tier 2 anomaly action: what to do when an anomaly is detected */
187
+ type AnomalyAction = "approve" | "log" | "allow";
188
+ /** Tier 2 anomaly detection configuration */
189
+ interface Tier2Config {
190
+ /** Action when agent accesses a namespace it hasn't used before */
191
+ new_namespace_access: AnomalyAction;
192
+ /** Action when agent interacts with an unknown counterparty DID */
193
+ new_counterparty: AnomalyAction;
194
+ /** Tool call frequency multiplier that triggers anomaly */
195
+ frequency_spike_multiplier: number;
196
+ /** Maximum signing operations per minute before triggering */
197
+ max_signs_per_minute: number;
198
+ /** Reading more than N keys in a namespace within 60 seconds */
199
+ bulk_read_threshold: number;
200
+ /** Policy for first session when no baseline exists */
201
+ first_session_policy: AnomalyAction;
365
202
  }
366
- /**
367
- * Commitment store — manages commitments encrypted under L1 sovereignty.
368
- */
369
- declare class CommitmentStore {
370
- private storage;
371
- private encryptionKey;
372
- constructor(storage: StorageBackend, masterKey: Uint8Array);
373
- /**
374
- * Store a commitment (encrypted) for later reference.
375
- */
376
- store(commitment: Commitment, value: string): Promise<string>;
377
- /**
378
- * Retrieve a stored commitment by ID.
379
- */
380
- get(id: string): Promise<StoredCommitment | null>;
203
+ /** Approval channel configuration */
204
+ interface ApprovalChannelConfig {
205
+ type: "stderr" | "webhook" | "callback";
206
+ timeout_seconds: number;
381
207
  /**
382
- * Mark a commitment as revealed.
208
+ * SEC-002: auto_deny is hardcoded to true and not configurable.
209
+ * Timeout on any approval channel ALWAYS results in denial.
210
+ * This field is retained for backward compatibility with existing
211
+ * policy files but is ignored — timeout always denies.
383
212
  */
384
- markRevealed(id: string): Promise<void>;
213
+ auto_deny?: boolean;
214
+ webhook_url?: string;
215
+ webhook_secret?: string;
385
216
  }
386
-
387
- /**
388
- * Sanctuary MCP Server — L3 Selective Disclosure: Zero-Knowledge Proofs
389
- *
390
- * Upgrades the commitment-only L3 to support real zero-knowledge proofs.
391
- * Uses Ristretto255 (prime-order curve group, no cofactor issues) for:
392
- *
393
- * 1. Pedersen commitments: C = v*G + b*H (computationally hiding, perfectly binding)
394
- * 2. ZK proof of knowledge: Schnorr sigma protocol via Fiat-Shamir
395
- * 3. ZK range proofs: Prove value ∈ [min, max] without revealing it
396
- *
397
- * Ristretto255 is available via @noble/curves/ed25519, which we already depend on.
398
- * This is genuine zero-knowledge — proofs reveal nothing beyond the stated property.
399
- *
400
- * Architecture note:
401
- * The existing commitment scheme (SHA-256 based) remains available for backward
402
- * compatibility. The ZK proofs operate on a separate Pedersen commitment system
403
- * that provides algebraic structure for proper ZK properties.
404
- *
405
- * Security invariants:
406
- * - Generator H is derived via hash-to-curve (nothing-up-my-sleeve)
407
- * - Blinding factors are cryptographically random (32 bytes)
408
- * - Fiat-Shamir challenges use domain-separated hashing
409
- * - Range proofs use a bit-decomposition approach (sound but logarithmic size)
410
- */
411
- /** A Pedersen commitment: C = v*G + b*H */
412
- interface PedersenCommitment {
413
- /** The commitment point (encoded as base64url) */
414
- commitment: string;
415
- /** The blinding factor b (base64url, 32 bytes) — keep secret */
416
- blinding_factor: string;
417
- /** When the commitment was created */
418
- committed_at: string;
217
+ /** Complete Principal Policy */
218
+ interface PrincipalPolicy {
219
+ version: number;
220
+ /** Operations that always require human approval */
221
+ tier1_always_approve: string[];
222
+ /** Behavioral anomaly detection configuration */
223
+ tier2_anomaly: Tier2Config;
224
+ /** Operations that never require approval (audit only) */
225
+ tier3_always_allow: string[];
226
+ /** How approval requests reach the human */
227
+ approval_channel: ApprovalChannelConfig;
419
228
  }
420
- /** A non-interactive ZK proof of knowledge of a commitment's opening */
421
- interface ZKProofOfKnowledge {
422
- /** Proof type identifier */
423
- type: "schnorr-pedersen-ristretto255";
424
- /** The commitment this proof is for */
425
- commitment: string;
426
- /** Announcement point R (base64url) */
427
- announcement: string;
428
- /** Response scalar s_v (base64url) */
429
- response_v: string;
430
- /** Response scalar s_b (base64url) */
431
- response_b: string;
432
- /** Proof generated at */
433
- generated_at: string;
229
+ /** Approval request sent to the human */
230
+ interface ApprovalRequest {
231
+ operation: string;
232
+ tier: 1 | 2;
233
+ reason: string;
234
+ context: Record<string, unknown>;
235
+ timestamp: string;
434
236
  }
435
- /** A ZK range proof: proves value ∈ [min, max] */
436
- interface ZKRangeProof {
437
- /** Proof type identifier */
438
- type: "range-pedersen-ristretto255";
439
- /** The commitment this proof is for */
440
- commitment: string;
441
- /** Minimum value (inclusive) */
442
- min: number;
443
- /** Maximum value (inclusive) */
444
- max: number;
445
- /** Bit commitments for the shifted value (v - min) */
446
- bit_commitments: string[];
447
- /** Proofs that each bit commitment is 0 or 1 */
448
- bit_proofs: Array<{
449
- announcement_0: string;
450
- announcement_1: string;
451
- challenge_0: string;
452
- challenge_1: string;
453
- response_0: string;
454
- response_1: string;
455
- }>;
456
- /** Sum proof: bit commitments sum to the value commitment */
457
- sum_proof: {
458
- announcement: string;
459
- response: string;
460
- };
461
- /** Proof generated at */
462
- generated_at: string;
237
+ /** Approval response from the human */
238
+ interface ApprovalResponse {
239
+ decision: "approve" | "deny";
240
+ decided_at: string;
241
+ decided_by: "human" | "timeout" | "auto" | "stderr:non-interactive";
242
+ }
243
+ /** Result of the approval gate evaluation */
244
+ interface GateResult {
245
+ allowed: boolean;
246
+ tier: 1 | 2 | 3;
247
+ reason: string;
248
+ approval_required: boolean;
249
+ approval_response?: ApprovalResponse;
250
+ }
251
+ /** Behavioral baseline for anomaly detection */
252
+ interface SessionProfile {
253
+ /** Namespaces accessed (read or write) */
254
+ known_namespaces: string[];
255
+ /** Counterparty DIDs seen in reputation operations */
256
+ known_counterparties: string[];
257
+ /** Tool call counts per tool name (lifetime in session) */
258
+ tool_call_counts: Record<string, number>;
259
+ /** Whether this is the first session (no prior baseline) */
260
+ is_first_session: boolean;
261
+ /** Session start time */
262
+ started_at: string;
263
+ /** When the baseline was last saved */
264
+ saved_at?: string;
463
265
  }
266
+
464
267
  /**
465
- * Create a Pedersen commitment to a numeric value.
466
- *
467
- * C = v*G + b*H
468
- *
469
- * Properties:
470
- * - Computationally hiding (under discrete log assumption)
471
- * - Perfectly binding (information-theoretic)
472
- * - Homomorphic: C(v1) + C(v2) = C(v1+v2) with adjusted blinding
268
+ * Sanctuary MCP Server Approval Channel
473
269
  *
474
- * @param value - The value to commit to (integer)
475
- * @returns The commitment and blinding factor
476
- */
477
- declare function createPedersenCommitment(value: number): PedersenCommitment;
478
- /**
479
- * Verify a Pedersen commitment against a revealed value and blinding factor.
270
+ * Out-of-band communication with the human principal for operation approval.
271
+ * The default channel uses stderr (outside MCP's stdin/stdout protocol),
272
+ * ensuring the agent cannot intercept or forge approval responses.
480
273
  *
481
- * Recomputes C' = v*G + b*H and checks C' == C.
274
+ * Security invariant:
275
+ * - Approval prompts go through a channel the agent cannot access.
276
+ * - Timeouts result in denial by default (fail closed).
482
277
  */
483
- declare function verifyPedersenCommitment(commitment: string, value: number, blindingFactor: string): boolean;
278
+
279
+ /** Abstract approval channel interface */
280
+ interface ApprovalChannel {
281
+ requestApproval(request: ApprovalRequest): Promise<ApprovalResponse>;
282
+ }
484
283
  /**
485
- * Create a non-interactive ZK proof that you know the opening (v, b)
486
- * of a Pedersen commitment C = v*G + b*H.
487
- *
488
- * Schnorr sigma protocol with Fiat-Shamir transform:
489
- * 1. Pick random r_v, r_b
490
- * 2. Compute R = r_v*G + r_b*H (announcement)
491
- * 3. Compute e = H_FS(C || R) (challenge via Fiat-Shamir)
492
- * 4. Compute s_v = r_v + e*v, s_b = r_b + e*b (responses)
493
- * 5. Proof = (R, s_v, s_b)
284
+ * Stderr approval channel — non-interactive informational channel.
494
285
  *
495
- * Zero-knowledge: the transcript (R, e, s_v, s_b) can be simulated
496
- * without knowing (v, b), so it reveals nothing.
286
+ * In the MCP stdio model:
287
+ * - stdin/stdout carry the MCP protocol (JSON-RPC)
288
+ * - stderr is available for out-of-band human communication
497
289
  *
498
- * @param value - The committed value
499
- * @param blindingFactor - The blinding factor (base64url)
500
- * @param commitment - The commitment (base64url)
501
- */
502
- declare function createProofOfKnowledge(value: number, blindingFactor: string, commitment: string): ZKProofOfKnowledge;
503
- /**
504
- * Verify a ZK proof of knowledge of a commitment's opening.
290
+ * Because stdin is consumed by the MCP JSON-RPC transport, this channel
291
+ * CANNOT read interactive human input. It is strictly informational:
292
+ * the prompt is displayed so the human sees what is happening, and the
293
+ * operation is denied immediately.
505
294
  *
506
- * Check: s_v*G + s_b*H == R + e*C
295
+ * SEC-002 + SEC-016 invariants:
296
+ * - This channel ALWAYS denies. No configuration can change this.
297
+ * - There is no timeout or async delay — denial is synchronous.
298
+ * - The `auto_deny` config field is ignored (SEC-002).
299
+ * - For interactive approval, use the dashboard or webhook channel.
507
300
  */
508
- declare function verifyProofOfKnowledge(proof: ZKProofOfKnowledge): boolean;
301
+ declare class StderrApprovalChannel implements ApprovalChannel {
302
+ constructor(_config: ApprovalChannelConfig);
303
+ requestApproval(request: ApprovalRequest): Promise<ApprovalResponse>;
304
+ private formatPrompt;
305
+ }
509
306
  /**
510
- * Create a ZK range proof: prove value [min, max] without revealing value.
511
- *
512
- * Approach: bit-decomposition of (value - min) into n bits where 2^n > max - min.
513
- * Each bit gets a Pedersen commitment and a proof it's 0 or 1.
514
- * A sum proof shows the bit commitments reconstruct the original commitment
515
- * (shifted by min).
516
- *
517
- * @param value - The committed value
518
- * @param blindingFactor - The blinding factor (base64url)
519
- * @param commitment - The commitment (base64url)
520
- * @param min - Minimum value (inclusive)
521
- * @param max - Maximum value (inclusive)
307
+ * Programmatic approval channel for testing and API integration.
522
308
  */
523
- declare function createRangeProof(value: number, blindingFactor: string, commitment: string, min: number, max: number): ZKRangeProof | {
524
- error: string;
525
- };
309
+ declare class CallbackApprovalChannel implements ApprovalChannel {
310
+ private callback;
311
+ constructor(callback: (request: ApprovalRequest) => Promise<ApprovalResponse>);
312
+ requestApproval(request: ApprovalRequest): Promise<ApprovalResponse>;
313
+ }
526
314
  /**
527
- * Verify a ZK range proof.
315
+ * Auto-approve channel for testing. Approves everything.
528
316
  */
529
- declare function verifyRangeProof(proof: ZKRangeProof): boolean;
317
+ declare class AutoApproveChannel implements ApprovalChannel {
318
+ requestApproval(_request: ApprovalRequest): Promise<ApprovalResponse>;
319
+ }
530
320
 
531
321
  /**
532
- * Sanctuary MCP Server — L3 Selective Disclosure: Disclosure Policies
533
- *
534
- * Disclosure policies define what an agent will and will not disclose
535
- * in different interaction contexts. Policies are evaluated against
536
- * incoming disclosure requests to produce per-field decisions.
322
+ * Sanctuary MCP Server — Behavioral Baseline Tracker
537
323
  *
538
- * This is the agent's "privacy preferences" layer it codifies the
539
- * human principal's intent about what information can flow where.
324
+ * Tracks the agent's behavioral profile during a session and persists
325
+ * it for cross-session anomaly detection. The baseline defines "normal"
326
+ * so that deviations can trigger Tier 2 approval.
540
327
  *
541
328
  * Security invariants:
542
- * - Policies are stored encrypted under L1 sovereignty
543
- * - Default action is always "withhold" unless explicitly overridden
544
- * - Policy evaluation is deterministic (same request same decision)
329
+ * - Baseline is stored encrypted under L1 sovereignty
330
+ * - Baseline changes are audit-logged
331
+ * - Baseline is integrity-verified via L1 Merkle tree
332
+ * - No MCP tool can directly modify the baseline
545
333
  */
546
334
 
547
- /** A single disclosure rule within a policy */
548
- interface DisclosureRule {
549
- /** Interaction context this rule applies to */
550
- context: string;
551
- /** Fields/claims the agent MAY disclose */
552
- disclose: string[];
553
- /** Fields/claims the agent MUST NOT disclose */
554
- withhold: string[];
555
- /** Fields that require proof rather than plain disclosure */
556
- proof_required: string[];
557
- }
558
- /** A complete disclosure policy */
559
- interface DisclosurePolicy {
560
- policy_id: string;
561
- policy_name: string;
562
- rules: DisclosureRule[];
563
- default_action: "withhold" | "ask-principal";
564
- identity_id?: string;
565
- created_at: string;
566
- updated_at: string;
567
- }
568
- /**
569
- * Policy store — manages disclosure policies encrypted under L1 sovereignty.
570
- */
571
- declare class PolicyStore {
335
+ declare class BaselineTracker {
572
336
  private storage;
573
337
  private encryptionKey;
574
- private policies;
338
+ private profile;
339
+ /** Sliding window: timestamps of tool calls per tool name (last 60s) */
340
+ private callWindows;
341
+ /** Sliding window: read counts per namespace (last 60s) */
342
+ private readWindows;
343
+ /** Sliding window: sign call timestamps (last 60s) */
344
+ private signWindow;
575
345
  constructor(storage: StorageBackend, masterKey: Uint8Array);
576
346
  /**
577
- * Create and store a new disclosure policy.
347
+ * Load the previous session's baseline from storage.
348
+ * If none exists, this is a first session.
578
349
  */
579
- create(policyName: string, rules: DisclosureRule[], defaultAction: "withhold" | "ask-principal", identityId?: string): Promise<DisclosurePolicy>;
350
+ load(): Promise<void>;
580
351
  /**
581
- * Get a policy by ID.
352
+ * Save the current baseline to storage (encrypted).
353
+ * Called at session end or periodically.
582
354
  */
583
- get(policyId: string): Promise<DisclosurePolicy | null>;
355
+ save(): Promise<void>;
584
356
  /**
585
- * List all policies.
357
+ * Record a tool call for baseline tracking.
358
+ * Returns anomaly information if applicable.
586
359
  */
587
- list(): Promise<DisclosurePolicy[]>;
360
+ recordToolCall(toolName: string): void;
588
361
  /**
589
- * Load all persisted policies into memory.
362
+ * Record a namespace access.
363
+ * @returns true if this is a new namespace (not in baseline)
590
364
  */
591
- private loadAll;
592
- private persist;
365
+ recordNamespaceAccess(namespace: string): boolean;
366
+ /**
367
+ * Record a namespace read for bulk-read detection.
368
+ * @returns the number of reads in the current 60-second window
369
+ */
370
+ recordNamespaceRead(namespace: string): number;
371
+ /**
372
+ * Record a counterparty DID interaction.
373
+ * @returns true if this is a new counterparty (not in baseline)
374
+ */
375
+ recordCounterparty(did: string): boolean;
376
+ /**
377
+ * Record a signing operation.
378
+ * @returns the number of signs in the current 60-second window
379
+ */
380
+ recordSign(): number;
381
+ /**
382
+ * Get the current call rate for a tool (calls per minute).
383
+ */
384
+ getCallRate(toolName: string): number;
385
+ /**
386
+ * Get the average call rate across all tools in the baseline.
387
+ */
388
+ getAverageCallRate(): number;
389
+ /** Whether this is the first session */
390
+ get isFirstSession(): boolean;
391
+ /** Get a read-only view of the current profile */
392
+ getProfile(): SessionProfile;
593
393
  }
594
394
 
595
395
  /**
596
- * Sanctuary MCP Server — Ed25519 Identity Management
396
+ * Sanctuary MCP Server — Prompt Injection Detection Layer
597
397
  *
598
- * Sovereign identity based on Ed25519 keypairs.
599
- * Private keys are always encrypted at rest never stored in plaintext.
398
+ * Fast, zero-dependency detection of common prompt injection patterns.
399
+ * Scans tool arguments for role override, security bypass, encoding evasion,
400
+ * data exfiltration, and prompt stuffing signals.
401
+ *
402
+ * SEC-034/SEC-035: Enhanced with Unicode sanitization pre-pass, decoded content
403
+ * re-scanning, token budget analysis, and outbound content scanning.
600
404
  *
601
405
  * Security invariants:
602
- * - Private keys never appear in any MCP tool response
603
- * - Private keys are encrypted with identity-specific keys derived from the master key
604
- * - Key rotation produces a signed rotation event (verifiable chain)
406
+ * - Always returns a result, never throws
407
+ * - Typical scan completes in < 5ms
408
+ * - False positives minimized via field-aware scanning
409
+ * - Recursive scanning of nested objects/arrays
410
+ * - Outbound scanning catches secret leaks and injection artifact survival
605
411
  */
606
-
607
- /** Public identity information (safe to share) */
608
- interface PublicIdentity {
609
- identity_id: string;
610
- label: string;
611
- public_key: string;
612
- did: string;
613
- created_at: string;
614
- key_type: "ed25519";
615
- key_protection: "passphrase" | "hardware-key" | "recovery-key";
412
+ interface InjectionDetectorConfig {
413
+ enabled: boolean;
414
+ sensitivity: "low" | "medium" | "high";
415
+ on_detection: "escalate" | "block" | "log";
416
+ custom_patterns?: string[];
616
417
  }
617
- /** Stored identity (private key is encrypted) */
618
- interface StoredIdentity extends PublicIdentity {
619
- encrypted_private_key: EncryptedPayload;
620
- /** Previous public keys (for rotation chain verification) */
621
- rotation_history: Array<{
622
- old_public_key: string;
623
- new_public_key: string;
624
- rotation_event: string;
625
- rotated_at: string;
626
- }>;
418
+ interface InjectionSignal {
419
+ type: string;
420
+ pattern: string;
421
+ location: string;
422
+ severity: "low" | "medium" | "high";
423
+ }
424
+ interface DetectionResult {
425
+ flagged: boolean;
426
+ confidence: number;
427
+ signals: InjectionSignal[];
428
+ recommendation: "allow" | "escalate" | "block";
429
+ }
430
+ declare class InjectionDetector {
431
+ private config;
432
+ private stats;
433
+ constructor(config?: Partial<InjectionDetectorConfig>);
434
+ /**
435
+ * Scan tool arguments for injection signals.
436
+ * @param toolName Full tool name (e.g., "state_read")
437
+ * @param args Tool arguments
438
+ * @returns DetectionResult with all detected signals
439
+ */
440
+ scan(toolName: string, args: Record<string, unknown>): DetectionResult;
441
+ /**
442
+ * SEC-035: Scan outbound content for secret leaks, data exfiltration,
443
+ * internal path exposure, and injection artifact survival.
444
+ *
445
+ * @param content The outbound content string to scan
446
+ * @returns DetectionResult with outbound-specific signal types
447
+ */
448
+ scanOutbound(content: string): DetectionResult;
449
+ /**
450
+ * Recursively scan a value and all nested values.
451
+ */
452
+ private scanValue;
453
+ /**
454
+ * Scan a single string for injection signals.
455
+ */
456
+ private scanString;
457
+ /**
458
+ * Count invisible Unicode characters in a string.
459
+ * Includes zero-width chars, soft hyphens, directional marks,
460
+ * variation selectors, and other invisible categories.
461
+ */
462
+ private countInvisibleChars;
463
+ /**
464
+ * Strip invisible characters from a string for clean pattern matching.
465
+ * Returns a new string with all invisible chars removed.
466
+ */
467
+ private stripInvisibleChars;
468
+ /**
469
+ * SEC-034: Token budget attack detection.
470
+ * Some Unicode sequences expand dramatically during tokenization (e.g., CJK
471
+ * ideographs, combining characters, emoji sequences). If the estimated token
472
+ * cost per character is anomalously high, this may be a wallet-drain payload.
473
+ *
474
+ * Heuristic: count chars that typically tokenize into multiple tokens.
475
+ * If the ratio of estimated tokens to char count exceeds 3x, flag it.
476
+ */
477
+ private detectTokenBudgetAttack;
478
+ /**
479
+ * Detect encoded content (base64, hex, HTML entities, URL encoding),
480
+ * decode it, and re-scan the decoded content through injection patterns.
481
+ * If the decoded content contains injection patterns, flag as encoding_evasion.
482
+ */
483
+ private detectEncodedPayloads;
484
+ /**
485
+ * Check if a string contains any injection patterns (role override or security bypass).
486
+ */
487
+ private containsInjectionPatterns;
488
+ /**
489
+ * Safely decode a base64 string. Returns null if it's not valid base64
490
+ * or doesn't decode to a meaningful string.
491
+ */
492
+ private safeBase64Decode;
493
+ /**
494
+ * Safely decode a hex string. Returns null on failure.
495
+ */
496
+ private safeHexDecode;
497
+ /**
498
+ * Decode HTML numeric entities (&#xHH; and &#DDD;) in a string.
499
+ */
500
+ private decodeHtmlEntities;
501
+ /**
502
+ * Safely decode a URL-encoded string. Returns null on failure.
503
+ */
504
+ private safeUrlDecode;
505
+ /**
506
+ * Heuristic: does this look like readable text (vs. binary garbage)?
507
+ * Checks that most characters are printable ASCII or common Unicode.
508
+ */
509
+ private looksLikeText;
510
+ /**
511
+ * Detect API keys and secrets in outbound content.
512
+ */
513
+ private detectSecretPatterns;
514
+ /**
515
+ * Detect data exfiltration via markdown images with data-carrying query params.
516
+ */
517
+ private detectOutboundExfiltration;
518
+ /**
519
+ * Detect internal filesystem path leaks in outbound content.
520
+ */
521
+ private detectInternalPathLeaks;
522
+ /**
523
+ * Detect private IP addresses and localhost references in outbound content.
524
+ */
525
+ private detectPrivateNetworkLeaks;
526
+ /**
527
+ * Detect role markers / prompt template artifacts in outbound content.
528
+ * These should never appear in agent output — their presence indicates
529
+ * injection artifact survival.
530
+ */
531
+ private detectOutputRoleMarkers;
532
+ /**
533
+ * Detect base64 strings, base64url, and zero-width character evasion.
534
+ */
535
+ private detectEncodingEvasion;
536
+ /**
537
+ * Detect URLs and emails in fields that shouldn't have them.
538
+ */
539
+ private detectDataExfiltration;
540
+ /**
541
+ * Detect prompt stuffing: very large strings or high repetition.
542
+ */
543
+ private detectPromptStuffing;
544
+ /**
545
+ * Determine if this field is inherently safe from role override.
546
+ */
547
+ private isSafeField;
548
+ /**
549
+ * Determine if this is a tool name field (where tool refs are expected).
550
+ */
551
+ private isToolNameField;
552
+ /**
553
+ * Determine if this field is safe for URLs.
554
+ */
555
+ private isUrlSafeField;
556
+ /**
557
+ * Determine if this field is safe for emails.
558
+ */
559
+ private isEmailSafeField;
560
+ /**
561
+ * Determine if this field is safe for structured data (JSON/XML).
562
+ */
563
+ private isStructuredField;
564
+ /**
565
+ * SEC-032/SEC-034: Map common cross-script confusable characters to their
566
+ * Latin equivalents. NFKC normalization handles fullwidth and compatibility
567
+ * forms, but does NOT map Cyrillic/Greek/Armenian/Georgian lookalikes to
568
+ * Latin (they're distinct codepoints by design).
569
+ *
570
+ * Extended to 50+ confusable pairs covering Cyrillic, Greek, Armenian,
571
+ * Georgian, Cherokee, and mathematical/symbol lookalikes.
572
+ */
573
+ private normalizeConfusables;
574
+ /**
575
+ * Compute confidence score based on signals.
576
+ * More high-severity signals = higher confidence.
577
+ */
578
+ private computeConfidence;
579
+ /**
580
+ * Compute recommendation based on signals and sensitivity.
581
+ */
582
+ private computeRecommendation;
583
+ /**
584
+ * Get statistics about scans performed.
585
+ */
586
+ getStats(): {
587
+ total_scans: number;
588
+ total_flags: number;
589
+ total_blocks: number;
590
+ signals_by_type: Record<string, number>;
591
+ };
592
+ /**
593
+ * Reset statistics.
594
+ */
595
+ resetStats(): void;
627
596
  }
628
597
 
629
598
  /**
630
- * Sanctuary MCP Server — Sovereignty Health Report (SHR) Types
599
+ * Sanctuary MCP Server — Approval Gate
631
600
  *
632
- * Machine-readable, signed, versioned sovereignty capability advertisement.
633
- * An agent presents its SHR to counterparties to prove its sovereignty posture.
634
- * The SHR is signed by one of the instance's Ed25519 identities and can be
635
- * independently verified by any party without trusting the presenter.
601
+ * The three-tier approval gate sits between the MCP router and tool handlers.
602
+ * Every tool call passes through the gate before execution.
636
603
  *
637
- * SHR version: 1.0
604
+ * Evaluation order:
605
+ * 1. Tier 1: Is this operation in the always-approve list? → Request approval.
606
+ * 2. Tier 2: Does this call represent a behavioral anomaly? → Request approval.
607
+ * 3. Tier 3 / default: Allow with audit logging.
608
+ *
609
+ * Security invariants:
610
+ * - The gate cannot be bypassed — it wraps every tool handler.
611
+ * - Denial responses do not reveal policy details to the agent.
612
+ * - All gate decisions (approve, deny, allow) are audit-logged.
638
613
  */
639
- type LayerStatus = "active" | "degraded" | "inactive";
640
- type DegradationSeverity = "info" | "warning" | "critical";
641
- type DegradationCode = "NO_TEE" | "PROCESS_ISOLATION_ONLY" | "COMMITMENT_ONLY" | "NO_ZK_PROOFS" | "SELF_REPORTED_ATTESTATION" | "NO_SELECTIVE_DISCLOSURE" | "BASIC_SYBIL_ONLY";
642
- interface SHRLayerL1 {
643
- status: LayerStatus;
644
- encryption: string;
645
- key_custody: "self" | "delegated" | "platform";
646
- integrity: string;
647
- identity_type: string;
648
- state_portable: boolean;
649
- }
650
- interface SHRLayerL2 {
651
- status: LayerStatus;
652
- isolation_type: string;
653
- attestation_available: boolean;
654
- /** Model provenance: what inference model(s) power this agent */
655
- model_provenance?: {
656
- model_id: string;
657
- model_name: string;
658
- provider: string;
659
- open_weights: boolean;
660
- open_source: boolean;
661
- local_inference: boolean;
662
- weights_hash?: string;
663
- };
664
- }
665
- interface SHRLayerL3 {
666
- status: LayerStatus;
667
- proof_system: string;
668
- selective_disclosure: boolean;
669
- }
670
- interface SHRLayerL4 {
671
- status: LayerStatus;
672
- reputation_mode: string;
673
- attestation_format: string;
674
- reputation_portable: boolean;
675
- }
676
- interface SHRDegradation {
677
- layer: "l1" | "l2" | "l3" | "l4";
678
- code: DegradationCode;
679
- severity: DegradationSeverity;
680
- description: string;
681
- mitigation?: string;
682
- }
683
- interface SHRCapabilities {
684
- handshake: boolean;
685
- shr_exchange: boolean;
686
- reputation_verify: boolean;
687
- encrypted_channel: boolean;
614
+
615
+ /** Callback invoked when an injection is detected, for dashboard broadcasting */
616
+ type InjectionAlertCallback = (alert: {
617
+ toolName: string;
618
+ result: DetectionResult;
619
+ timestamp: string;
620
+ }) => void;
621
+ /** Resolver for proxy tool tiers — provided by the ProxyRouter */
622
+ type ProxyTierResolver = (toolName: string) => (1 | 2 | 3) | null;
623
+ declare class ApprovalGate {
624
+ private policy;
625
+ private baseline;
626
+ private channel;
627
+ private auditLog;
628
+ private injectionDetector;
629
+ private onInjectionAlert?;
630
+ private proxyTierResolver?;
631
+ constructor(policy: PrincipalPolicy, baseline: BaselineTracker, channel: ApprovalChannel, auditLog: AuditLog, injectionDetector?: InjectionDetector, onInjectionAlert?: InjectionAlertCallback);
632
+ /**
633
+ * Set the proxy tier resolver. Called after the proxy router is initialized.
634
+ */
635
+ setProxyTierResolver(resolver: ProxyTierResolver): void;
636
+ /**
637
+ * Evaluate a tool call against the Principal Policy.
638
+ *
639
+ * @param toolName - Full MCP tool name (e.g., "state_export")
640
+ * @param args - Tool call arguments (for context extraction)
641
+ * @returns GateResult indicating whether the call is allowed
642
+ */
643
+ evaluate(toolName: string, args: Record<string, unknown>): Promise<GateResult>;
644
+ /**
645
+ * Detect Tier 2 behavioral anomalies.
646
+ */
647
+ private detectAnomaly;
648
+ /**
649
+ * Request approval from the human principal.
650
+ */
651
+ private requestApproval;
652
+ /**
653
+ * Summarize tool arguments for the approval prompt.
654
+ * Strips potentially large values to keep the prompt readable.
655
+ */
656
+ private summarizeArgs;
657
+ /** Get the baseline tracker for saving at session end */
658
+ getBaseline(): BaselineTracker;
659
+ /** Get the injection detector for stats/configuration access */
660
+ getInjectionDetector(): InjectionDetector;
688
661
  }
662
+
689
663
  /**
690
- * The SHR bodythe content that gets signed.
691
- * Canonical form: JSON with sorted keys, no whitespace.
664
+ * Sanctuary MCP ServerTool Router
665
+ *
666
+ * Routes sanctuary/* tool calls to their layer-specific handlers.
667
+ * Every tool call passes through schema validation and the ApprovalGate
668
+ * (if configured) before execution. Neither can be bypassed.
669
+ *
670
+ * This module is the abstraction boundary for MCP SDK version migration —
671
+ * if the SDK API changes, only this module needs updating.
692
672
  */
693
- interface SHRBody {
694
- shr_version: "1.0";
695
- implementation: {
696
- sanctuary_version: string;
697
- node_version: string;
698
- generated_by: string;
699
- };
700
- instance_id: string;
701
- generated_at: string;
702
- expires_at: string;
703
- layers: {
704
- l1: SHRLayerL1;
705
- l2: SHRLayerL2;
706
- l3: SHRLayerL3;
707
- l4: SHRLayerL4;
708
- };
709
- capabilities: SHRCapabilities;
710
- degradations: SHRDegradation[];
673
+
674
+ /** Tool handler function signature */
675
+ type ToolHandler = (args: Record<string, unknown>) => Promise<{
676
+ content: Array<{
677
+ type: "text";
678
+ text: string;
679
+ }>;
680
+ }>;
681
+ /** Tool definition for registration */
682
+ interface ToolDefinition {
683
+ name: string;
684
+ description: string;
685
+ inputSchema: Record<string, unknown>;
686
+ handler: ToolHandler;
711
687
  }
688
+
712
689
  /**
713
- * The complete signed SHR body + signature envelope.
690
+ * Sanctuary MCP ServerAES-256-GCM Encryption
691
+ *
692
+ * All state encryption in Sanctuary uses AES-256-GCM (authenticated encryption).
693
+ * This provides both confidentiality and integrity — a modified ciphertext will
694
+ * fail authentication, detecting tampering.
695
+ *
696
+ * Security invariants:
697
+ * - Every encryption uses a unique 12-byte IV (NIST SP 800-38D)
698
+ * - The 16-byte authentication tag is always verified on decryption
699
+ * - Keys are 256 bits (32 bytes)
714
700
  */
715
- interface SignedSHR {
716
- body: SHRBody;
717
- signed_by: string;
718
- signature: string;
719
- }
720
- interface SHRVerificationResult {
721
- valid: boolean;
722
- errors: string[];
723
- warnings: string[];
724
- sovereignty_level: "full" | "degraded" | "minimal";
725
- counterparty_id: string;
726
- expires_at: string;
701
+ /** Encrypted payload structure stored on disk */
702
+ interface EncryptedPayload {
703
+ /** Format version */
704
+ v: number;
705
+ /** Algorithm identifier */
706
+ alg: "aes-256-gcm";
707
+ /** Initialization vector (base64url) */
708
+ iv: string;
709
+ /** Ciphertext (base64url) */
710
+ ct: string;
711
+ /** Authentication tag (base64url) — included in ciphertext by @noble/ciphers */
712
+ /** Timestamp */
713
+ ts: string;
727
714
  }
728
715
 
729
716
  /**
730
- * Sanctuary MCP Server — Sovereignty Handshake Types
717
+ * Sanctuary MCP Server — L1 Cognitive Sovereignty: StateStore
731
718
  *
732
- * The sovereignty handshake is a mutual verification protocol between
733
- * two Sanctuary instances. Each party presents its SHR and proves
734
- * liveness via nonce challenge-response.
719
+ * The encrypted state store is the foundation of Sanctuary.
720
+ * Every read and write goes through here. All data is encrypted
721
+ * with namespace-specific keys. All writes are signed by an identity.
722
+ * All reads verify integrity via Merkle proofs.
735
723
  *
736
- * Protocol:
737
- * A B: HandshakeChallenge (A's SHR + nonce)
738
- * B A: HandshakeResponse (B's SHR + B's nonce + signature over A's nonce)
739
- * A B: HandshakeCompletion (signature over B's nonce)
740
- * Result: Both hold a HandshakeResult with verified counterparty status
724
+ * Security invariants:
725
+ * - Plaintext never touches the filesystem
726
+ * - Every write gets a unique IV
727
+ * - Every write is signed (non-repudiation)
728
+ * - Monotonic version numbers prevent rollback
729
+ * - Merkle tree verifies namespace integrity
730
+ * - Secure deletion overwrites before unlinking
741
731
  */
742
732
 
743
- /** Trust tier derived from sovereignty handshake */
744
- type TrustTier = "verified-sovereign" | "verified-degraded" | "unverified";
745
- /** Sovereignty level from SHR assessment */
746
- type SovereigntyLevel = "full" | "degraded" | "minimal" | "unverified";
747
- /**
748
- * Step 1: Initiator sends challenge
749
- */
750
- interface HandshakeChallenge {
751
- protocol_version: "1.0";
752
- shr: SignedSHR;
753
- nonce: string;
754
- initiated_at: string;
755
- }
756
- /**
757
- * Step 2: Responder sends response
758
- */
759
- interface HandshakeResponse {
760
- protocol_version: "1.0";
761
- shr: SignedSHR;
762
- responder_nonce: string;
763
- initiator_nonce_signature: string;
764
- responded_at: string;
733
+ /** Result of a state write operation */
734
+ interface WriteResult {
735
+ key: string;
736
+ namespace: string;
737
+ version: number;
738
+ merkle_root: string;
739
+ written_at: string;
740
+ size_bytes: number;
741
+ integrity_hash: string;
765
742
  }
766
- /**
767
- * Step 3: Initiator sends completion
768
- */
769
- interface HandshakeCompletion {
770
- protocol_version: "1.0";
771
- responder_nonce_signature: string;
772
- completed_at: string;
743
+ /** Result of a state read operation */
744
+ interface ReadResult {
745
+ key: string;
746
+ namespace: string;
747
+ value: string;
748
+ version: number;
749
+ integrity_verified: boolean;
750
+ merkle_proof: string[];
751
+ written_at: string;
752
+ written_by: string;
773
753
  }
774
- /**
775
- * Final result: both parties hold this after a successful handshake
776
- */
777
- interface HandshakeResult {
778
- counterparty_id: string;
779
- counterparty_shr: SignedSHR;
780
- verified: boolean;
781
- sovereignty_level: SovereigntyLevel;
782
- trust_tier: TrustTier;
783
- completed_at: string;
784
- expires_at: string;
785
- errors: string[];
754
+ /** Options for state write */
755
+ interface WriteOptions {
756
+ content_type?: string;
757
+ ttl_seconds?: number;
758
+ tags?: string[];
786
759
  }
787
- /**
788
- * In-progress handshake state (stored on initiator side)
789
- */
790
- interface HandshakeSession {
791
- session_id: string;
792
- role: "initiator" | "responder";
793
- state: "initiated" | "responded" | "completed" | "failed";
794
- our_nonce: string;
795
- their_nonce?: string;
796
- our_shr: SignedSHR;
797
- their_shr?: SignedSHR;
798
- initiated_at: string;
799
- result?: HandshakeResult;
760
+ declare class StateStore {
761
+ private storage;
762
+ private masterKey;
763
+ private versionCache;
764
+ private contentHashes;
765
+ constructor(storage: StorageBackend, masterKey: Uint8Array);
766
+ private versionKey;
767
+ /**
768
+ * Get or initialize the content hash map for a namespace.
769
+ */
770
+ private getNamespaceHashes;
771
+ /**
772
+ * Write encrypted state.
773
+ *
774
+ * @param namespace - Logical grouping
775
+ * @param key - State key
776
+ * @param value - Plaintext value (will be encrypted)
777
+ * @param identityId - Identity performing the write
778
+ * @param encryptedPrivateKey - Identity's encrypted private key (for signing)
779
+ * @param identityEncryptionKey - Key to decrypt the identity's private key
780
+ * @param options - Optional metadata
781
+ */
782
+ write(namespace: string, key: string, value: string, identityId: string, encryptedPrivateKey: EncryptedPayload, identityEncryptionKey: Uint8Array, options?: WriteOptions): Promise<WriteResult>;
783
+ /**
784
+ * Read and decrypt state.
785
+ *
786
+ * @param namespace - Logical grouping
787
+ * @param key - State key
788
+ * @param signerPublicKey - Expected signer's public key (for signature verification)
789
+ * @param verifyIntegrity - Whether to verify Merkle proof (default: true)
790
+ */
791
+ read(namespace: string, key: string, signerPublicKey?: Uint8Array, verifyIntegrity?: boolean): Promise<ReadResult | null>;
792
+ /**
793
+ * List keys in a namespace (metadata only — no decryption).
794
+ */
795
+ list(namespace: string, prefix?: string, tags?: string[], limit?: number, offset?: number): Promise<{
796
+ keys: Array<{
797
+ key: string;
798
+ version: number;
799
+ size_bytes: number;
800
+ written_at: string;
801
+ tags: string[];
802
+ }>;
803
+ total: number;
804
+ merkle_root: string;
805
+ }>;
806
+ /**
807
+ * Securely delete state (overwrite with random bytes before removal).
808
+ */
809
+ delete(namespace: string, key: string): Promise<{
810
+ deleted: boolean;
811
+ key: string;
812
+ namespace: string;
813
+ new_merkle_root: string;
814
+ deleted_at: string;
815
+ }>;
816
+ /**
817
+ * Export all state for a namespace as an encrypted bundle.
818
+ */
819
+ export(namespace?: string): Promise<{
820
+ bundle: string;
821
+ namespaces: string[];
822
+ total_keys: number;
823
+ bundle_hash: string;
824
+ exported_at: string;
825
+ }>;
826
+ /**
827
+ * Import a previously exported state bundle.
828
+ */
829
+ import(bundleBase64: string, conflictResolution: "skip" | "overwrite" | "version" | undefined, publicKeyResolver: (kid: string) => Uint8Array | null): Promise<{
830
+ imported_keys: number;
831
+ skipped_keys: number;
832
+ skipped_invalid_sig: number;
833
+ skipped_unknown_kid: number;
834
+ conflicts: number;
835
+ namespaces: string[];
836
+ imported_at: string;
837
+ }>;
800
838
  }
801
839
 
802
840
  /**
803
- * Sanctuary MCP Server — Sovereignty-Gated Reputation Tiers
804
- *
805
- * Attestations carry a sovereignty_tier field reflecting the signer's
806
- * sovereignty posture at the time of recording. When querying or evaluating
807
- * reputation, attestations from verified-sovereign agents carry more weight
808
- * than those from unverified agents.
841
+ * Sanctuary MCP Server — Ed25519 Identity Management
809
842
  *
810
- * Tier hierarchy (descending credibility):
811
- * 1. "verified-sovereign" — signer completed a handshake with full sovereignty
812
- * 2. "verified-degraded" — signer completed a handshake with degraded sovereignty
813
- * 3. "self-attested" — signer has a Sanctuary identity but no handshake verification
814
- * 4. "unverified" — no Sanctuary identity or sovereignty proof
843
+ * Sovereign identity based on Ed25519 keypairs.
844
+ * Private keys are always encrypted at rest — never stored in plaintext.
815
845
  *
816
- * Weight multipliers are applied during reputation scoring. They are NOT
817
- * gatekeeping unverified attestations still count, just less.
846
+ * Security invariants:
847
+ * - Private keys never appear in any MCP tool response
848
+ * - Private keys are encrypted with identity-specific keys derived from the master key
849
+ * - Key rotation produces a signed rotation event (verifiable chain)
818
850
  */
819
851
 
820
- type SovereigntyTier = "verified-sovereign" | "verified-degraded" | "self-attested" | "unverified";
821
- /** Weight multipliers for each tier */
822
- declare const TIER_WEIGHTS: Record<SovereigntyTier, number>;
823
- /** Tier metadata embedded in attestations */
824
- interface TierMetadata {
825
- sovereignty_tier: SovereigntyTier;
826
- /** If verified, the handshake that established it */
827
- handshake_completed_at?: string;
828
- /** Counterparty ID from handshake (if applicable) */
829
- verified_by?: string;
852
+ /** Public identity information (safe to share) */
853
+ interface PublicIdentity {
854
+ identity_id: string;
855
+ label: string;
856
+ public_key: string;
857
+ did: string;
858
+ created_at: string;
859
+ key_type: "ed25519";
860
+ key_protection: "passphrase" | "hardware-key" | "recovery-key";
830
861
  }
831
- /**
832
- * Resolve the sovereignty tier for a counterparty based on handshake history.
833
- *
834
- * @param counterpartyId - The counterparty's instance ID
835
- * @param handshakeResults - Map of counterparty ID → most recent handshake result
836
- * @param hasSanctuaryIdentity - Whether the counterparty has a known Sanctuary identity
837
- * @returns TierMetadata for embedding in attestations
838
- */
839
- declare function resolveTier(counterpartyId: string, handshakeResults: Map<string, HandshakeResult>, hasSanctuaryIdentity: boolean): TierMetadata;
840
- /** An attestation with its tier for weighted scoring */
841
- interface TieredAttestation {
842
- /** The raw metric value */
843
- value: number;
844
- /** The sovereignty tier of the attestation signer */
845
- tier: SovereigntyTier;
862
+ /** Stored identity (private key is encrypted) */
863
+ interface StoredIdentity extends PublicIdentity {
864
+ encrypted_private_key: EncryptedPayload;
865
+ /** Previous public keys (for rotation chain verification) */
866
+ rotation_history: Array<{
867
+ old_public_key: string;
868
+ new_public_key: string;
869
+ rotation_event: string;
870
+ rotated_at: string;
871
+ }>;
846
872
  }
847
- /**
848
- * Compute a weighted reputation score from tiered attestations.
849
- *
850
- * Each attestation's contribution is multiplied by its tier weight.
851
- * The result is normalized by total weight (not count), so adding
852
- * low-tier attestations doesn't dilute high-tier ones.
853
- *
854
- * @param attestations - Array of value + tier pairs
855
- * @returns Weighted score, or null if no attestations
856
- */
857
- declare function computeWeightedScore(attestations: TieredAttestation[]): number | null;
858
- /**
859
- * Compute a tier distribution summary for a set of attestations.
860
- */
861
- declare function tierDistribution(tiers: SovereigntyTier[]): Record<SovereigntyTier, number>;
862
873
 
863
874
  /**
864
- * Sanctuary MCP Server — L4 Verifiable Reputation: Reputation Store
865
- *
866
- * Records interaction outcomes as signed attestations, queries aggregated
867
- * reputation data, and supports export/import for cross-platform portability.
868
- *
869
- * Attestation format is EAS-compatible (Ethereum Attestation Service) to
870
- * enable future on-chain anchoring without requiring blockchain for MVS.
875
+ * Sanctuary MCP Server — L1 Cognitive Sovereignty: Tool Definitions
871
876
  *
872
- * Security invariants:
873
- * - All attestations are signed by the recording identity
874
- * - Attestations are stored encrypted under L1 sovereignty
875
- * - Reputation queries return aggregates, never raw interaction data
876
- * - Export bundles include all signatures for independent verification
877
- * - Import verifies every signature before accepting attestations
877
+ * MCP tool wrappers for StateStore and IdentityRoot operations.
878
+ * These tools are the public API that agents interact with.
878
879
  */
879
880
 
880
- /** Interaction outcome for recording */
881
- interface InteractionOutcome {
882
- type: "transaction" | "negotiation" | "service" | "dispute" | "custom";
883
- result: "completed" | "partial" | "failed" | "disputed";
884
- metrics?: Record<string, number>;
885
- }
886
- /** A signed attestation of an interaction */
887
- interface Attestation {
888
- attestation_id: string;
889
- schema: "sanctuary-interaction-v1";
890
- data: {
891
- interaction_id: string;
892
- participant_did: string;
893
- counterparty_did: string;
894
- outcome_type: string;
895
- outcome_result: string;
896
- metrics: Record<string, number>;
897
- context: string;
898
- timestamp: string;
899
- /** Sovereignty tier of the signer at time of recording */
900
- sovereignty_tier?: SovereigntyTier;
901
- };
902
- signature: string;
903
- signer: string;
904
- }
905
- /** Stored attestation (encrypted at rest) */
906
- interface StoredAttestation {
907
- attestation: Attestation;
908
- counterparty_attestation?: string;
909
- counterparty_confirmed: boolean;
910
- recorded_at: string;
911
- }
912
- /** Aggregated metric statistics */
913
- interface MetricAggregate {
914
- mean: number;
915
- median: number;
916
- min: number;
917
- max: number;
918
- count: number;
919
- }
920
- /** Reputation query result */
921
- interface ReputationSummary {
922
- total_interactions: number;
923
- completed: number;
924
- partial: number;
925
- failed: number;
926
- disputed: number;
927
- contexts: string[];
928
- time_range: {
929
- start: string;
930
- end: string;
931
- };
932
- aggregate_metrics: Record<string, MetricAggregate>;
933
- }
934
- /** Portable reputation bundle */
935
- interface ReputationBundle {
936
- version: "SANCTUARY_REP_V1";
937
- attestations: Attestation[];
938
- exported_at: string;
939
- exporter_did: string;
940
- bundle_signature: string;
941
- }
942
- /** Escrow for trust bootstrapping */
943
- interface Escrow {
944
- escrow_id: string;
945
- transaction_terms: string;
946
- terms_hash: string;
947
- collateral_amount?: number;
948
- counterparty_did: string;
949
- creator_did: string;
950
- created_at: string;
951
- expires_at: string;
952
- status: "pending" | "active" | "released" | "disputed" | "expired";
953
- }
954
- /** Principal guarantee for a new agent */
955
- interface Guarantee {
956
- guarantee_id: string;
957
- principal_did: string;
958
- agent_did: string;
959
- scope: string;
960
- max_liability?: number;
961
- valid_until: string;
962
- certificate: string;
963
- created_at: string;
964
- }
965
- declare class ReputationStore {
881
+ /** Manages all identities provides storage and retrieval */
882
+ declare class IdentityManager {
966
883
  private storage;
967
- private encryptionKey;
884
+ private masterKey;
885
+ private identities;
886
+ private primaryIdentityId;
887
+ private metadataKey;
968
888
  constructor(storage: StorageBackend, masterKey: Uint8Array);
969
- /**
970
- * Record an interaction outcome as a signed attestation.
971
- */
972
- record(interactionId: string, counterpartyDid: string, outcome: InteractionOutcome, context: string, identity: StoredIdentity, identityEncryptionKey: Uint8Array, counterpartyAttestation?: string, sovereigntyTier?: SovereigntyTier): Promise<StoredAttestation>;
973
- /**
974
- * Query reputation data with filtering.
975
- * Returns aggregates only — not raw interaction data.
976
- */
977
- query(options: {
978
- context?: string;
979
- time_range?: {
980
- start: string;
981
- end: string;
982
- };
983
- metrics?: string[];
984
- counterparty_did?: string;
985
- }): Promise<ReputationSummary>;
986
- /**
987
- * Export attestations as a portable reputation bundle.
988
- */
989
- exportBundle(identity: StoredIdentity, identityEncryptionKey: Uint8Array, context?: string): Promise<ReputationBundle>;
990
- /**
991
- * Import attestations from a reputation bundle.
992
- * Verifies signatures if requested (default: true).
993
- *
994
- * @param publicKeys - Map of DID → public key bytes for signature verification
889
+ private get encryptionKey();
890
+ /** Load identities from storage on startup.
891
+ * Returns { total: number of encrypted files found, loaded: number successfully decrypted }.
892
+ * A mismatch (total > 0, loaded === 0) indicates a wrong master key / missing passphrase.
995
893
  */
996
- importBundle(bundle: ReputationBundle, verifySignatures: boolean, publicKeys: Map<string, Uint8Array>): Promise<{
997
- imported: number;
998
- invalid: number;
999
- contexts: string[];
894
+ load(): Promise<{
895
+ total: number;
896
+ loaded: number;
897
+ failed: number;
1000
898
  }>;
899
+ /** Save an identity to storage */
900
+ save(identity: StoredIdentity): Promise<void>;
901
+ /** Set which identity is the default/primary identity */
902
+ setPrimary(identityId: string): Promise<boolean>;
903
+ /** Persist the primary identity ID to storage */
904
+ private savePrimaryIdentityId;
905
+ get(id: string): StoredIdentity | undefined;
906
+ getDefault(): StoredIdentity | undefined;
907
+ getPrimaryIdentityId(): string | null;
908
+ list(): PublicIdentity[];
909
+ }
910
+
911
+ /**
912
+ * Sanctuary MCP Server — L3 Selective Disclosure: Commitment Schemes
913
+ *
914
+ * Cryptographic commitments allow an agent to commit to a value
915
+ * without revealing it, then later prove what was committed.
916
+ *
917
+ * This is the MVS approach to selective disclosure — simpler than
918
+ * full ZK proofs but still cryptographically sound. The commitment
919
+ * is SHA-256(value || blinding_factor), which is:
920
+ * - Hiding: the commitment reveals nothing about the value
921
+ * - Binding: the committer cannot change the value after committing
922
+ *
923
+ * Security invariants:
924
+ * - Blinding factors are cryptographically random (32 bytes)
925
+ * - Commitments are stored encrypted under L1 sovereignty
926
+ * - Revealed values are verified via constant-time comparison
927
+ */
928
+
929
+ /** A cryptographic commitment */
930
+ interface Commitment {
931
+ /** The commitment hash: SHA-256(value || blinding_factor) as base64url */
932
+ commitment: string;
933
+ /** The blinding factor (must be stored securely for later reveal) */
934
+ blinding_factor: string;
935
+ /** When the commitment was created */
936
+ committed_at: string;
937
+ }
938
+ /** Stored commitment metadata (encrypted at rest) */
939
+ interface StoredCommitment {
940
+ commitment: string;
941
+ blinding_factor: string;
942
+ value: string;
943
+ committed_at: string;
944
+ revealed: boolean;
945
+ revealed_at?: string;
946
+ }
947
+ /**
948
+ * Commitment store — manages commitments encrypted under L1 sovereignty.
949
+ */
950
+ declare class CommitmentStore {
951
+ private storage;
952
+ private encryptionKey;
953
+ constructor(storage: StorageBackend, masterKey: Uint8Array);
1001
954
  /**
1002
- * Create an escrow for trust bootstrapping.
1003
- */
1004
- createEscrow(transactionTerms: string, counterpartyDid: string, timeoutSeconds: number, creatorDid: string, collateralAmount?: number): Promise<Escrow>;
1005
- /**
1006
- * Get an escrow by ID.
955
+ * Store a commitment (encrypted) for later reference.
1007
956
  */
1008
- getEscrow(escrowId: string): Promise<Escrow | null>;
957
+ store(commitment: Commitment, value: string): Promise<string>;
1009
958
  /**
1010
- * Create a principal's guarantee for a new agent.
959
+ * Retrieve a stored commitment by ID.
1011
960
  */
1012
- createGuarantee(principalIdentity: StoredIdentity, agentDid: string, scope: string, durationSeconds: number, identityEncryptionKey: Uint8Array, maxLiability?: number): Promise<Guarantee>;
961
+ get(id: string): Promise<StoredCommitment | null>;
1013
962
  /**
1014
- * Load attestations for tier-weighted scoring.
1015
- * Applies basic context/counterparty filtering, returns full StoredAttestations
1016
- * so callers can access sovereignty_tier from attestation data.
963
+ * Mark a commitment as revealed.
1017
964
  */
1018
- loadAllForTierScoring(options?: {
1019
- context?: string;
1020
- counterparty_did?: string;
1021
- }): Promise<StoredAttestation[]>;
1022
- private loadAll;
965
+ markRevealed(id: string): Promise<void>;
1023
966
  }
1024
967
 
1025
968
  /**
1026
- * Sanctuary MCP Server — Federation Types
969
+ * Sanctuary MCP Server — L3 Selective Disclosure: Zero-Knowledge Proofs
1027
970
  *
1028
- * MCP-to-MCP federation enables two Sanctuary instances to:
1029
- * 1. Discover each other's capabilities (SIM exchange)
1030
- * 2. Establish mutual trust (sovereignty handshake)
1031
- * 3. Exchange signed reputation attestations
1032
- * 4. Evaluate trust for cross-instance interactions
971
+ * Upgrades the commitment-only L3 to support real zero-knowledge proofs.
972
+ * Uses Ristretto255 (prime-order curve group, no cofactor issues) for:
1033
973
  *
1034
- * Federation operates as a protocol layer atop the handshake:
1035
- * Handshake establishes trust Federation uses that trust for ongoing operations.
974
+ * 1. Pedersen commitments: C = v*G + b*H (computationally hiding, perfectly binding)
975
+ * 2. ZK proof of knowledge: Schnorr sigma protocol via Fiat-Shamir
976
+ * 3. ZK range proofs: Prove value ∈ [min, max] without revealing it
1036
977
  *
1037
- * Key constraint: Federation MUST respect each party's sovereignty.
1038
- * Neither party can compel the other to share data they haven't disclosed
1039
- * via their disclosure policy.
978
+ * Ristretto255 is available via @noble/curves/ed25519, which we already depend on.
979
+ * This is genuine zero-knowledge proofs reveal nothing beyond the stated property.
980
+ *
981
+ * Architecture note:
982
+ * The existing commitment scheme (SHA-256 based) remains available for backward
983
+ * compatibility. The ZK proofs operate on a separate Pedersen commitment system
984
+ * that provides algebraic structure for proper ZK properties.
985
+ *
986
+ * Security invariants:
987
+ * - Generator H is derived via hash-to-curve (nothing-up-my-sleeve)
988
+ * - Blinding factors are cryptographically random (32 bytes)
989
+ * - Fiat-Shamir challenges use domain-separated hashing
990
+ * - Range proofs use a bit-decomposition approach (sound but logarithmic size)
1040
991
  */
1041
-
1042
- /** A known federation peer */
1043
- interface FederationPeer {
1044
- /** The peer's instance ID (from their SHR) */
1045
- peer_id: string;
1046
- /** The peer's DID (identity) */
1047
- peer_did: string;
1048
- /** When this peer was first seen */
1049
- first_seen: string;
1050
- /** When last handshake completed */
1051
- last_handshake: string;
1052
- /** Current trust tier from most recent handshake */
1053
- trust_tier: SovereigntyTier;
1054
- /** Handshake result (for tier resolution) */
1055
- handshake_result: HandshakeResult;
1056
- /** Peer's advertised capabilities (from their SIM) */
1057
- capabilities: FederationCapabilities;
1058
- /** Whether we have a valid (non-expired) handshake */
1059
- active: boolean;
992
+ /** A Pedersen commitment: C = v*G + b*H */
993
+ interface PedersenCommitment {
994
+ /** The commitment point (encoded as base64url) */
995
+ commitment: string;
996
+ /** The blinding factor b (base64url, 32 bytes) — keep secret */
997
+ blinding_factor: string;
998
+ /** When the commitment was created */
999
+ committed_at: string;
1060
1000
  }
1061
- /** Capabilities a peer advertises for federation */
1062
- interface FederationCapabilities {
1063
- /** Whether the peer supports reputation exchange */
1064
- reputation_exchange: boolean;
1065
- /** Whether the peer supports mutual attestation */
1066
- mutual_attestation: boolean;
1067
- /** Whether the peer supports encrypted channels */
1068
- encrypted_channel: boolean;
1069
- /** Supported attestation formats */
1070
- attestation_formats: string[];
1001
+ /** A non-interactive ZK proof of knowledge of a commitment's opening */
1002
+ interface ZKProofOfKnowledge {
1003
+ /** Proof type identifier */
1004
+ type: "schnorr-pedersen-ristretto255";
1005
+ /** The commitment this proof is for */
1006
+ commitment: string;
1007
+ /** Announcement point R (base64url) */
1008
+ announcement: string;
1009
+ /** Response scalar s_v (base64url) */
1010
+ response_v: string;
1011
+ /** Response scalar s_b (base64url) */
1012
+ response_b: string;
1013
+ /** Proof generated at */
1014
+ generated_at: string;
1071
1015
  }
1072
- /** Trust evaluation result for a federation peer */
1073
- interface PeerTrustEvaluation {
1074
- peer_id: string;
1075
- /** Current sovereignty tier (from handshake) */
1076
- sovereignty_tier: SovereigntyTier;
1077
- /** Whether handshake is current (not expired) */
1078
- handshake_current: boolean;
1079
- /** Reputation summary (if available) */
1080
- reputation_score?: number;
1081
- /** How many mutual attestations we share */
1082
- mutual_attestation_count: number;
1083
- /** Overall trust assessment */
1084
- trust_level: "high" | "medium" | "low" | "none";
1085
- /** Reasoning for the assessment */
1086
- factors: string[];
1087
- /** Evaluated at */
1088
- evaluated_at: string;
1016
+ /** A ZK range proof: proves value [min, max] */
1017
+ interface ZKRangeProof {
1018
+ /** Proof type identifier */
1019
+ type: "range-pedersen-ristretto255";
1020
+ /** The commitment this proof is for */
1021
+ commitment: string;
1022
+ /** Minimum value (inclusive) */
1023
+ min: number;
1024
+ /** Maximum value (inclusive) */
1025
+ max: number;
1026
+ /** Bit commitments for the shifted value (v - min) */
1027
+ bit_commitments: string[];
1028
+ /** Proofs that each bit commitment is 0 or 1 */
1029
+ bit_proofs: Array<{
1030
+ announcement_0: string;
1031
+ announcement_1: string;
1032
+ challenge_0: string;
1033
+ challenge_1: string;
1034
+ response_0: string;
1035
+ response_1: string;
1036
+ }>;
1037
+ /** Sum proof: bit commitments sum to the value commitment */
1038
+ sum_proof: {
1039
+ announcement: string;
1040
+ response: string;
1041
+ };
1042
+ /** Proof generated at */
1043
+ generated_at: string;
1089
1044
  }
1090
-
1091
1045
  /**
1092
- * Sanctuary MCP Server Federation Peer Registry
1046
+ * Create a Pedersen commitment to a numeric value.
1093
1047
  *
1094
- * Manages known federation peers. Peers are discovered through handshakes
1095
- * and tracked for ongoing federation operations.
1048
+ * C = v*G + b*H
1096
1049
  *
1097
- * The registry is the source of truth for:
1098
- * - Who we've federated with
1099
- * - Current trust status of each peer
1100
- * - Peer capabilities (what operations they support)
1050
+ * Properties:
1051
+ * - Computationally hiding (under discrete log assumption)
1052
+ * - Perfectly binding (information-theoretic)
1053
+ * - Homomorphic: C(v1) + C(v2) = C(v1+v2) with adjusted blinding
1101
1054
  *
1102
- * Security invariants:
1103
- * - Peers are ONLY added through completed handshakes (not self-registration)
1104
- * - Trust tiers degrade automatically when handshakes expire
1105
- * - Peer data is stored encrypted under L1 sovereignty
1055
+ * @param value - The value to commit to (integer)
1056
+ * @returns The commitment and blinding factor
1106
1057
  */
1107
-
1108
- declare class FederationRegistry {
1109
- private peers;
1110
- /**
1111
- * Register or update a peer from a completed handshake.
1112
- * This is the ONLY way peers enter the registry.
1113
- */
1114
- registerFromHandshake(result: HandshakeResult, peerDid: string, capabilities?: Partial<FederationCapabilities>): FederationPeer;
1115
- /**
1116
- * Get a peer by instance ID.
1117
- * Automatically updates active status based on handshake expiry.
1118
- */
1119
- getPeer(peerId: string): FederationPeer | null;
1120
- /**
1121
- * List all known peers, optionally filtered by status.
1122
- */
1123
- listPeers(filter?: {
1124
- active_only?: boolean;
1125
- }): FederationPeer[];
1126
- /**
1127
- * Evaluate trust for a federation peer.
1128
- *
1129
- * Trust assessment considers:
1130
- * - Handshake status (current vs expired)
1131
- * - Sovereignty tier (verified-sovereign vs degraded vs unverified)
1132
- * - Reputation data (if available)
1133
- * - Mutual attestation history
1134
- */
1135
- evaluateTrust(peerId: string, mutualAttestationCount?: number, reputationScore?: number): PeerTrustEvaluation;
1136
- /**
1137
- * Remove a peer from the registry.
1138
- */
1139
- removePeer(peerId: string): boolean;
1140
- /**
1141
- * Get the handshake results map (for tier resolution integration).
1142
- */
1143
- getHandshakeResults(): Map<string, HandshakeResult>;
1144
- }
1145
-
1058
+ declare function createPedersenCommitment(value: number): PedersenCommitment;
1059
+ /**
1060
+ * Verify a Pedersen commitment against a revealed value and blinding factor.
1061
+ *
1062
+ * Recomputes C' = v*G + b*H and checks C' == C.
1063
+ */
1064
+ declare function verifyPedersenCommitment(commitment: string, value: number, blindingFactor: string): boolean;
1065
+ /**
1066
+ * Create a non-interactive ZK proof that you know the opening (v, b)
1067
+ * of a Pedersen commitment C = v*G + b*H.
1068
+ *
1069
+ * Schnorr sigma protocol with Fiat-Shamir transform:
1070
+ * 1. Pick random r_v, r_b
1071
+ * 2. Compute R = r_v*G + r_b*H (announcement)
1072
+ * 3. Compute e = H_FS(C || R) (challenge via Fiat-Shamir)
1073
+ * 4. Compute s_v = r_v + e*v, s_b = r_b + e*b (responses)
1074
+ * 5. Proof = (R, s_v, s_b)
1075
+ *
1076
+ * Zero-knowledge: the transcript (R, e, s_v, s_b) can be simulated
1077
+ * without knowing (v, b), so it reveals nothing.
1078
+ *
1079
+ * @param value - The committed value
1080
+ * @param blindingFactor - The blinding factor (base64url)
1081
+ * @param commitment - The commitment (base64url)
1082
+ */
1083
+ declare function createProofOfKnowledge(value: number, blindingFactor: string, commitment: string): ZKProofOfKnowledge;
1146
1084
  /**
1147
- * Sanctuary MCP Server L2 Operational Isolation: Context Gating
1085
+ * Verify a ZK proof of knowledge of a commitment's opening.
1148
1086
  *
1149
- * Context gating controls what information leaves the sovereignty boundary
1150
- * when an agent makes outbound calls — especially inference calls to remote
1151
- * LLM providers. This is the "minimum-necessary context" enforcement layer.
1087
+ * Check: s_v*G + s_b*H == R + e*C
1088
+ */
1089
+ declare function verifyProofOfKnowledge(proof: ZKProofOfKnowledge): boolean;
1090
+ /**
1091
+ * Create a ZK range proof: prove value ∈ [min, max] without revealing value.
1152
1092
  *
1153
- * The problem: When an agent sends a request to a remote LLM provider (Claude,
1154
- * GPT, etc.), most harnesses send the agent's full context — conversation
1155
- * history, memory, tool results, preferences, internal reasoning. The agent
1156
- * has no control over what the provider sees.
1093
+ * Approach: bit-decomposition of (value - min) into n bits where 2^n > max - min.
1094
+ * Each bit gets a Pedersen commitment and a proof it's 0 or 1.
1095
+ * A sum proof shows the bit commitments reconstruct the original commitment
1096
+ * (shifted by min).
1157
1097
  *
1158
- * Context gating lets the agent define:
1159
- * - Provider categories (inference, tool-api, logging, analytics, etc.)
1160
- * - What fields/categories of context may flow to each provider type
1161
- * - What must always be redacted (secrets, internal reasoning, PII, etc.)
1162
- * - What requires transformation (hashing, summarizing, anonymizing)
1098
+ * @param value - The committed value
1099
+ * @param blindingFactor - The blinding factor (base64url)
1100
+ * @param commitment - The commitment (base64url)
1101
+ * @param min - Minimum value (inclusive)
1102
+ * @param max - Maximum value (inclusive)
1103
+ */
1104
+ declare function createRangeProof(value: number, blindingFactor: string, commitment: string, min: number, max: number): ZKRangeProof | {
1105
+ error: string;
1106
+ };
1107
+ /**
1108
+ * Verify a ZK range proof.
1109
+ */
1110
+ declare function verifyRangeProof(proof: ZKRangeProof): boolean;
1111
+
1112
+ /**
1113
+ * Sanctuary MCP Server — L3 Selective Disclosure: Disclosure Policies
1163
1114
  *
1164
- * This sits in L2 (Operational Isolation) because it controls information
1165
- * flow at the execution boundary. L3 (Selective Disclosure) handles agent-
1166
- * to-agent trust negotiation with cryptographic proofs; context gating
1167
- * handles agent-to-infrastructure information flow.
1115
+ * Disclosure policies define what an agent will and will not disclose
1116
+ * in different interaction contexts. Policies are evaluated against
1117
+ * incoming disclosure requests to produce per-field decisions.
1118
+ *
1119
+ * This is the agent's "privacy preferences" layer — it codifies the
1120
+ * human principal's intent about what information can flow where.
1168
1121
  *
1169
1122
  * Security invariants:
1170
- * - Redact rules take absolute priority (like withhold in L3)
1171
1123
  * - Policies are stored encrypted under L1 sovereignty
1172
- * - Every filter operation is audit-logged with a content hash
1173
- * (what was sent, what was redacted without storing the content itself)
1174
- * - Default policy: redact everything not explicitly allowed
1124
+ * - Default action is always "withhold" unless explicitly overridden
1125
+ * - Policy evaluation is deterministic (same request same decision)
1175
1126
  */
1176
1127
 
1177
- /** Provider categories that context may flow to */
1178
- type ProviderCategory = "inference" | "tool-api" | "logging" | "analytics" | "peer-agent" | "custom";
1179
- /** Actions that can be taken on a context field */
1180
- type ContextAction = "allow" | "redact" | "hash" | "summarize" | "deny";
1181
- /** A rule within a context-gating policy */
1182
- interface ContextGateRule {
1183
- /** Provider category this rule applies to */
1184
- provider: ProviderCategory | "*";
1185
- /** Fields/patterns that may pass through */
1186
- allow: string[];
1187
- /** Fields/patterns that must be redacted (highest priority) */
1188
- redact: string[];
1189
- /** Fields/patterns that should be hashed */
1190
- hash: string[];
1191
- /** Fields/patterns that should be summarized (advisory) */
1192
- summarize: string[];
1128
+ /** A single disclosure rule within a policy */
1129
+ interface DisclosureRule {
1130
+ /** Interaction context this rule applies to */
1131
+ context: string;
1132
+ /** Fields/claims the agent MAY disclose */
1133
+ disclose: string[];
1134
+ /** Fields/claims the agent MUST NOT disclose */
1135
+ withhold: string[];
1136
+ /** Fields that require proof rather than plain disclosure */
1137
+ proof_required: string[];
1193
1138
  }
1194
- /** A complete context-gating policy */
1195
- interface ContextGatePolicy {
1139
+ /** A complete disclosure policy */
1140
+ interface DisclosurePolicy {
1196
1141
  policy_id: string;
1197
1142
  policy_name: string;
1198
- rules: ContextGateRule[];
1199
- /** Default action when no rule matches a field */
1200
- default_action: "redact" | "deny";
1201
- /** Identity this policy is bound to (optional) */
1143
+ rules: DisclosureRule[];
1144
+ default_action: "withhold" | "ask-principal";
1202
1145
  identity_id?: string;
1203
1146
  created_at: string;
1204
1147
  updated_at: string;
1205
1148
  }
1206
- /** Result of filtering a single field */
1207
- interface FieldFilterResult {
1208
- field: string;
1209
- action: ContextAction;
1210
- reason: string;
1211
- /** If action is "hash", contains the hash */
1212
- hash_value?: string;
1213
- }
1214
- /** Result of a full context filter operation */
1215
- interface ContextFilterResult {
1216
- policy_id: string;
1217
- provider: ProviderCategory | string;
1218
- fields_allowed: number;
1219
- fields_redacted: number;
1220
- fields_hashed: number;
1221
- fields_summarized: number;
1222
- fields_denied: number;
1223
- decisions: FieldFilterResult[];
1224
- /** SHA-256 hash of the original context (for audit trail) */
1225
- original_context_hash: string;
1226
- /** SHA-256 hash of the filtered output (for audit trail) */
1227
- filtered_context_hash: string;
1228
- filtered_at: string;
1229
- }
1230
- /**
1231
- * Evaluate a context field against a policy for a given provider.
1232
- *
1233
- * Priority order (same as L3 disclosure):
1234
- * 1. Redact (blocks — highest priority)
1235
- * 2. Deny (blocks entire request)
1236
- * 3. Hash (transforms)
1237
- * 4. Summarize (advisory transform)
1238
- * 5. Allow (passes through)
1239
- * 6. Default action
1240
- */
1241
- declare function evaluateField(policy: ContextGatePolicy, provider: ProviderCategory | string, field: string): FieldFilterResult;
1242
- /**
1243
- * Filter a full context object against a policy for a given provider.
1244
- * Returns per-field decisions and content hashes for the audit trail.
1245
- */
1246
- declare function filterContext(policy: ContextGatePolicy, provider: ProviderCategory | string, context: Record<string, unknown>): ContextFilterResult;
1247
1149
  /**
1248
- * Context gate policy store — encrypted under L1 sovereignty.
1150
+ * Policy store — manages disclosure policies encrypted under L1 sovereignty.
1249
1151
  */
1250
- declare class ContextGatePolicyStore {
1152
+ declare class PolicyStore {
1251
1153
  private storage;
1252
1154
  private encryptionKey;
1253
1155
  private policies;
1254
1156
  constructor(storage: StorageBackend, masterKey: Uint8Array);
1255
1157
  /**
1256
- * Create and store a new context-gating policy.
1158
+ * Create and store a new disclosure policy.
1257
1159
  */
1258
- create(policyName: string, rules: ContextGateRule[], defaultAction: "redact" | "deny", identityId?: string): Promise<ContextGatePolicy>;
1160
+ create(policyName: string, rules: DisclosureRule[], defaultAction: "withhold" | "ask-principal", identityId?: string): Promise<DisclosurePolicy>;
1259
1161
  /**
1260
1162
  * Get a policy by ID.
1261
1163
  */
1262
- get(policyId: string): Promise<ContextGatePolicy | null>;
1164
+ get(policyId: string): Promise<DisclosurePolicy | null>;
1263
1165
  /**
1264
- * List all context-gating policies.
1166
+ * List all policies.
1265
1167
  */
1266
- list(): Promise<ContextGatePolicy[]>;
1168
+ list(): Promise<DisclosurePolicy[]>;
1267
1169
  /**
1268
1170
  * Load all persisted policies into memory.
1269
1171
  */
@@ -1272,736 +1174,871 @@ declare class ContextGatePolicyStore {
1272
1174
  }
1273
1175
 
1274
1176
  /**
1275
- * Sanctuary MCP Server — L2 Context Gating: Starter Policy Templates
1276
- *
1277
- * Pre-built policies for common use cases. These are starting points —
1278
- * users should customize them for their specific context structure.
1279
- *
1280
- * Templates:
1281
- *
1282
- * inference-minimal
1283
- * Only the current task and query reach the LLM. Everything else
1284
- * is redacted. Secrets, PII, memory, reasoning, and history are
1285
- * all blocked. IDs are hashed. Maximum privacy, minimum context.
1286
- *
1287
- * inference-standard
1288
- * Task, query, and tool results pass through. Conversation history
1289
- * is flagged for summarization (compress before sending). Secrets,
1290
- * PII, and internal reasoning are redacted. IDs are hashed.
1291
- * Balanced: the LLM has enough context to be useful without seeing
1292
- * everything the agent knows.
1177
+ * Sanctuary MCP Server — Sovereignty Health Report (SHR) Types
1293
1178
  *
1294
- * logging-strict
1295
- * Redacts everything for logging/analytics providers. Only
1296
- * operation names and timestamps pass through. Use this for
1297
- * telemetry services where you want usage metrics without
1298
- * content exposure.
1179
+ * Machine-readable, signed, versioned sovereignty capability advertisement.
1180
+ * An agent presents its SHR to counterparties to prove its sovereignty posture.
1181
+ * The SHR is signed by one of the instance's Ed25519 identities and can be
1182
+ * independently verified by any party without trusting the presenter.
1299
1183
  *
1300
- * tool-api-scoped
1301
- * Allows tool-specific parameters and the current task, redacts
1302
- * memory, history, secrets, and PII. Hashes IDs. For outbound
1303
- * calls to external APIs (search, database, etc.) where you need
1304
- * to send query parameters but not your agent's full state.
1184
+ * SHR version: 1.0
1185
+ */
1186
+ type LayerStatus = "active" | "degraded" | "inactive";
1187
+ type DegradationSeverity = "info" | "warning" | "critical";
1188
+ type DegradationCode = "NO_TEE" | "PROCESS_ISOLATION_ONLY" | "COMMITMENT_ONLY" | "NO_ZK_PROOFS" | "SELF_REPORTED_ATTESTATION" | "NO_SELECTIVE_DISCLOSURE" | "BASIC_SYBIL_ONLY";
1189
+ interface SHRLayerL1 {
1190
+ status: LayerStatus;
1191
+ encryption: string;
1192
+ key_custody: "self" | "delegated" | "platform";
1193
+ integrity: string;
1194
+ identity_type: string;
1195
+ state_portable: boolean;
1196
+ }
1197
+ interface SHRLayerL2 {
1198
+ status: LayerStatus;
1199
+ isolation_type: string;
1200
+ attestation_available: boolean;
1201
+ /** Model provenance: what inference model(s) power this agent */
1202
+ model_provenance?: {
1203
+ model_id: string;
1204
+ model_name: string;
1205
+ provider: string;
1206
+ open_weights: boolean;
1207
+ open_source: boolean;
1208
+ local_inference: boolean;
1209
+ weights_hash?: string;
1210
+ };
1211
+ }
1212
+ interface SHRLayerL3 {
1213
+ status: LayerStatus;
1214
+ proof_system: string;
1215
+ selective_disclosure: boolean;
1216
+ }
1217
+ interface SHRLayerL4 {
1218
+ status: LayerStatus;
1219
+ reputation_mode: string;
1220
+ attestation_format: string;
1221
+ reputation_portable: boolean;
1222
+ }
1223
+ interface SHRDegradation {
1224
+ layer: "l1" | "l2" | "l3" | "l4";
1225
+ code: DegradationCode;
1226
+ severity: DegradationSeverity;
1227
+ description: string;
1228
+ mitigation?: string;
1229
+ }
1230
+ interface SHRCapabilities {
1231
+ handshake: boolean;
1232
+ shr_exchange: boolean;
1233
+ reputation_verify: boolean;
1234
+ encrypted_channel: boolean;
1235
+ }
1236
+ /**
1237
+ * The SHR body — the content that gets signed.
1238
+ * Canonical form: JSON with sorted keys, no whitespace.
1239
+ */
1240
+ interface SHRBody {
1241
+ shr_version: "1.0";
1242
+ implementation: {
1243
+ sanctuary_version: string;
1244
+ node_version: string;
1245
+ generated_by: string;
1246
+ };
1247
+ instance_id: string;
1248
+ generated_at: string;
1249
+ expires_at: string;
1250
+ layers: {
1251
+ l1: SHRLayerL1;
1252
+ l2: SHRLayerL2;
1253
+ l3: SHRLayerL3;
1254
+ l4: SHRLayerL4;
1255
+ };
1256
+ capabilities: SHRCapabilities;
1257
+ degradations: SHRDegradation[];
1258
+ }
1259
+ /**
1260
+ * The complete signed SHR — body + signature envelope.
1305
1261
  */
1306
-
1307
- /** A template definition ready to be applied via the policy store */
1308
- interface ContextGateTemplate {
1309
- /** Machine-readable template ID */
1310
- id: string;
1311
- /** Human-readable name */
1312
- name: string;
1313
- /** One-line description */
1314
- description: string;
1315
- /** When to use this template */
1316
- use_when: string;
1317
- /** The rules that make up this template */
1318
- rules: ContextGateRule[];
1319
- /** Default action for unmatched fields */
1320
- default_action: "redact" | "deny";
1262
+ interface SignedSHR {
1263
+ body: SHRBody;
1264
+ signed_by: string;
1265
+ signature: string;
1266
+ }
1267
+ interface SHRVerificationResult {
1268
+ valid: boolean;
1269
+ errors: string[];
1270
+ warnings: string[];
1271
+ sovereignty_level: "full" | "degraded" | "minimal";
1272
+ counterparty_id: string;
1273
+ expires_at: string;
1321
1274
  }
1322
- /** All available templates, keyed by ID */
1323
- declare const TEMPLATES: Record<string, ContextGateTemplate>;
1324
- /** List all available template IDs */
1325
- declare function listTemplateIds(): string[];
1326
- /** Get a template by ID (returns undefined if not found) */
1327
- declare function getTemplate(id: string): ContextGateTemplate | undefined;
1328
1275
 
1329
1276
  /**
1330
- * Sanctuary MCP Server — L2 Context Gating: Policy Recommendation Engine
1331
- *
1332
- * Analyzes a sample context object and recommends a context-gating policy
1333
- * based on field name heuristics. The agent (or human) can then review,
1334
- * adjust, and apply the recommendation.
1335
- *
1336
- * This is deliberately conservative: when in doubt, it recommends redact.
1337
- * A false redaction is a usability issue; a false allow is a privacy leak.
1277
+ * Sanctuary MCP Server — Sovereignty Handshake Types
1338
1278
  *
1339
- * Classification heuristics:
1340
- * - Known secret patterns redact (highest confidence)
1341
- * - Known PII patterns → redact (high confidence)
1342
- * - Known internal state patterns → redact (high confidence)
1343
- * - Known ID patterns → hash (medium confidence)
1344
- * - Known history patterns → summarize (medium confidence)
1345
- * - Known task/query patterns → allow (medium confidence)
1346
- * - Everything else → redact (conservative default)
1279
+ * The sovereignty handshake is a mutual verification protocol between
1280
+ * two Sanctuary instances. Each party presents its SHR and proves
1281
+ * liveness via nonce challenge-response.
1347
1282
  *
1348
- * WARNING: Fields like 'tool_results' and 'tool_output' are classified as
1349
- * "allow" (medium confidence) but may contain sensitive data from external
1350
- * API responses, including auth tokens, user data, or PII. Always review
1351
- * recommendations before applying the heuristic classifies by field NAME,
1352
- * not field CONTENT.
1283
+ * Protocol:
1284
+ * A B: HandshakeChallenge (A's SHR + nonce)
1285
+ * B A: HandshakeResponse (B's SHR + B's nonce + signature over A's nonce)
1286
+ * A B: HandshakeCompletion (signature over B's nonce)
1287
+ * Result: Both hold a HandshakeResult with verified counterparty status
1353
1288
  */
1354
- /** Classification result for a single field */
1355
- interface FieldClassification {
1356
- field: string;
1357
- recommended_action: "allow" | "redact" | "hash" | "summarize";
1358
- reason: string;
1359
- confidence: "high" | "medium" | "low";
1360
- /** Pattern that matched, if any */
1361
- matched_pattern: string | null;
1289
+
1290
+ /** Trust tier derived from sovereignty handshake */
1291
+ type TrustTier = "verified-sovereign" | "verified-degraded" | "unverified";
1292
+ /** Sovereignty level from SHR assessment */
1293
+ type SovereigntyLevel = "full" | "degraded" | "minimal" | "unverified";
1294
+ /**
1295
+ * Step 1: Initiator sends challenge
1296
+ */
1297
+ interface HandshakeChallenge {
1298
+ protocol_version: "1.0";
1299
+ shr: SignedSHR;
1300
+ nonce: string;
1301
+ initiated_at: string;
1362
1302
  }
1363
- /** Full recommendation result */
1364
- interface PolicyRecommendation {
1365
- provider: string;
1366
- classifications: FieldClassification[];
1367
- recommended_rules: {
1368
- allow: string[];
1369
- redact: string[];
1370
- hash: string[];
1371
- summarize: string[];
1372
- };
1373
- default_action: "redact";
1374
- summary: {
1375
- total_fields: number;
1376
- allow: number;
1377
- redact: number;
1378
- hash: number;
1379
- summarize: number;
1380
- };
1381
- warnings: string[];
1303
+ /**
1304
+ * Step 2: Responder sends response
1305
+ */
1306
+ interface HandshakeResponse {
1307
+ protocol_version: "1.0";
1308
+ shr: SignedSHR;
1309
+ responder_nonce: string;
1310
+ initiator_nonce_signature: string;
1311
+ responded_at: string;
1382
1312
  }
1383
1313
  /**
1384
- * Classify a single field name and return a recommendation.
1314
+ * Step 3: Initiator sends completion
1385
1315
  */
1386
- declare function classifyField(fieldName: string): FieldClassification;
1316
+ interface HandshakeCompletion {
1317
+ protocol_version: "1.0";
1318
+ responder_nonce_signature: string;
1319
+ completed_at: string;
1320
+ }
1387
1321
  /**
1388
- * Analyze a full context object and recommend a policy.
1322
+ * Final result: both parties hold this after a successful handshake
1389
1323
  */
1390
- declare function recommendPolicy(context: Record<string, unknown>, provider?: string): PolicyRecommendation;
1324
+ interface HandshakeResult {
1325
+ counterparty_id: string;
1326
+ counterparty_shr: SignedSHR;
1327
+ verified: boolean;
1328
+ sovereignty_level: SovereigntyLevel;
1329
+ trust_tier: TrustTier;
1330
+ completed_at: string;
1331
+ expires_at: string;
1332
+ errors: string[];
1333
+ }
1334
+ /**
1335
+ * In-progress handshake state (stored on initiator side)
1336
+ */
1337
+ interface HandshakeSession {
1338
+ session_id: string;
1339
+ role: "initiator" | "responder";
1340
+ state: "initiated" | "responded" | "completed" | "failed";
1341
+ our_nonce: string;
1342
+ their_nonce?: string;
1343
+ our_shr: SignedSHR;
1344
+ their_shr?: SignedSHR;
1345
+ initiated_at: string;
1346
+ result?: HandshakeResult;
1347
+ }
1391
1348
 
1392
1349
  /**
1393
- * Sanctuary MCP Server — L2 Model Provenance
1394
- *
1395
- * Declares and attests to the model(s) powering this agent.
1350
+ * Sanctuary MCP Server — Sovereignty-Gated Reputation Tiers
1396
1351
  *
1397
- * Vitalik Buterin's "Secure LLM" post (April 2026) identified a critical gap:
1398
- * open-weights-but-not-open-source models can have trained-in backdoors. Model
1399
- * provenance declaration lets agents and their operators verify the integrity
1400
- * of the inference backbone.
1352
+ * Attestations carry a sovereignty_tier field reflecting the signer's
1353
+ * sovereignty posture at the time of recording. When querying or evaluating
1354
+ * reputation, attestations from verified-sovereign agents carry more weight
1355
+ * than those from unverified agents.
1401
1356
  *
1402
- * Tracks: model name, version, weights hash, license, open-source status,
1403
- * training data hash (if available). Included in SHR L2 section.
1357
+ * Tier hierarchy (descending credibility):
1358
+ * 1. "verified-sovereign" — signer completed a handshake with full sovereignty
1359
+ * 2. "verified-degraded" — signer completed a handshake with degraded sovereignty
1360
+ * 3. "self-attested" — signer has a Sanctuary identity but no handshake verification
1361
+ * 4. "unverified" — no Sanctuary identity or sovereignty proof
1404
1362
  *
1405
- * This sits in L2 (Operational Isolation) because it's part of the runtime
1406
- * attestation surface the agent declares what model(s) it's actually running.
1407
- */
1408
- /**
1409
- * Metadata about a single model powering this agent.
1363
+ * Weight multipliers are applied during reputation scoring. They are NOT
1364
+ * gatekeepingunverified attestations still count, just less.
1410
1365
  */
1411
- interface ModelProvenance {
1412
- /** Machine-readable model ID (e.g., "qwen3.5-35b", "claude-opus-4", "llama-3.3-70b-instruct") */
1413
- model_id: string;
1414
- /** Human-readable model name (e.g., "Qwen 3.5", "Claude Opus 4", "Llama 3.3 70B Instruct") */
1415
- model_name: string;
1416
- /** Semantic version (e.g., "3.5", "4.0", "3.3") */
1417
- model_version: string;
1418
- /** Provider/vendor (e.g., "Alibaba Cloud", "Anthropic", "Meta", "local") */
1419
- provider: string;
1420
- /** SHA-256 of model weights file, if available and verifiable */
1421
- weights_hash?: string;
1422
- /** SHA-256 of training data manifest or metadata, if available */
1423
- training_data_hash?: string;
1424
- /** License identifier (e.g., "Apache-2.0", "CC-BY-4.0", "proprietary", "unknown") */
1425
- license: string;
1426
- /** True if model weights are publicly available (even if training is proprietary) */
1427
- open_weights: boolean;
1428
- /** True if full training code, data, and methodology are publicly available */
1429
- open_source: boolean;
1430
- /** True if inference runs on the local agent's hardware (not delegated to cloud API) */
1431
- local_inference: boolean;
1432
- /** ISO 8601 timestamp when this provenance was declared */
1433
- declared_at: string;
1366
+
1367
+ type SovereigntyTier = "verified-sovereign" | "verified-degraded" | "self-attested" | "unverified";
1368
+ /** Weight multipliers for each tier */
1369
+ declare const TIER_WEIGHTS: Record<SovereigntyTier, number>;
1370
+ /** Tier metadata embedded in attestations */
1371
+ interface TierMetadata {
1372
+ sovereignty_tier: SovereigntyTier;
1373
+ /** If verified, the handshake that established it */
1374
+ handshake_completed_at?: string;
1375
+ /** Counterparty ID from handshake (if applicable) */
1376
+ verified_by?: string;
1434
1377
  }
1435
1378
  /**
1436
- * In-memory and persistent store for model provenance declarations.
1437
- * Declarations are encrypted under L1 sovereignty.
1379
+ * Resolve the sovereignty tier for a counterparty based on handshake history.
1380
+ *
1381
+ * @param counterpartyId - The counterparty's instance ID
1382
+ * @param handshakeResults - Map of counterparty ID → most recent handshake result
1383
+ * @param hasSanctuaryIdentity - Whether the counterparty has a known Sanctuary identity
1384
+ * @returns TierMetadata for embedding in attestations
1438
1385
  */
1439
- interface ModelProvenanceStore {
1440
- /**
1441
- * Declare a model's provenance and add it to the store.
1442
- */
1443
- declare(provenance: ModelProvenance): void;
1444
- /**
1445
- * Retrieve a model's provenance by ID.
1446
- */
1447
- get(model_id: string): ModelProvenance | undefined;
1448
- /**
1449
- * List all declared models.
1450
- */
1451
- list(): ModelProvenance[];
1452
- /**
1453
- * Get the primary/main model (the one the agent uses by default for inference).
1454
- */
1455
- primary(): ModelProvenance | undefined;
1456
- /**
1457
- * Set which model is the primary.
1458
- */
1459
- setPrimary(model_id: string): void;
1386
+ declare function resolveTier(counterpartyId: string, handshakeResults: Map<string, HandshakeResult>, hasSanctuaryIdentity: boolean): TierMetadata;
1387
+ /** An attestation with its tier for weighted scoring */
1388
+ interface TieredAttestation {
1389
+ /** The raw metric value */
1390
+ value: number;
1391
+ /** The sovereignty tier of the attestation signer */
1392
+ tier: SovereigntyTier;
1460
1393
  }
1461
1394
  /**
1462
- * In-memory implementation of ModelProvenanceStore.
1463
- * Suitable for most use cases. For encrypted persistence, integrate with L1 state store.
1464
- */
1465
- declare class InMemoryModelProvenanceStore implements ModelProvenanceStore {
1466
- private models;
1467
- private primaryModelId;
1468
- declare(provenance: ModelProvenance): void;
1469
- get(model_id: string): ModelProvenance | undefined;
1470
- list(): ModelProvenance[];
1471
- primary(): ModelProvenance | undefined;
1472
- setPrimary(model_id: string): void;
1473
- }
1395
+ * Compute a weighted reputation score from tiered attestations.
1396
+ *
1397
+ * Each attestation's contribution is multiplied by its tier weight.
1398
+ * The result is normalized by total weight (not count), so adding
1399
+ * low-tier attestations doesn't dilute high-tier ones.
1400
+ *
1401
+ * @param attestations - Array of value + tier pairs
1402
+ * @returns Weighted score, or null if no attestations
1403
+ */
1404
+ declare function computeWeightedScore(attestations: TieredAttestation[]): number | null;
1474
1405
  /**
1475
- * Common model provenance presets for quick initialization.
1406
+ * Compute a tier distribution summary for a set of attestations.
1476
1407
  */
1477
- declare const MODEL_PRESETS: {
1478
- /**
1479
- * Claude Opus 4 via Anthropic API (cloud inference, closed weights/source)
1480
- */
1481
- claudeOpus4: () => ModelProvenance;
1482
- /**
1483
- * Qwen 3.5 via local inference (open weights, proprietary training)
1484
- */
1485
- qwen35Local: () => ModelProvenance;
1486
- /**
1487
- * Llama 3.3 70B via local inference (open weights and code)
1488
- */
1489
- llama33Local: () => ModelProvenance;
1490
- /**
1491
- * Mistral 7B (open weights, open code, local inference)
1492
- */
1493
- mistral7bLocal: () => ModelProvenance;
1494
- };
1408
+ declare function tierDistribution(tiers: SovereigntyTier[]): Record<SovereigntyTier, number>;
1495
1409
 
1496
1410
  /**
1497
- * Sanctuary MCP Server — Prompt Injection Detection Layer
1411
+ * Sanctuary MCP Server — L4 Verifiable Reputation: Reputation Store
1498
1412
  *
1499
- * Fast, zero-dependency detection of common prompt injection patterns.
1500
- * Scans tool arguments for role override, security bypass, encoding evasion,
1501
- * data exfiltration, and prompt stuffing signals.
1413
+ * Records interaction outcomes as signed attestations, queries aggregated
1414
+ * reputation data, and supports export/import for cross-platform portability.
1502
1415
  *
1503
- * SEC-034/SEC-035: Enhanced with Unicode sanitization pre-pass, decoded content
1504
- * re-scanning, token budget analysis, and outbound content scanning.
1416
+ * Attestation format is EAS-compatible (Ethereum Attestation Service) to
1417
+ * enable future on-chain anchoring without requiring blockchain for MVS.
1505
1418
  *
1506
1419
  * Security invariants:
1507
- * - Always returns a result, never throws
1508
- * - Typical scan completes in < 5ms
1509
- * - False positives minimized via field-aware scanning
1510
- * - Recursive scanning of nested objects/arrays
1511
- * - Outbound scanning catches secret leaks and injection artifact survival
1420
+ * - All attestations are signed by the recording identity
1421
+ * - Attestations are stored encrypted under L1 sovereignty
1422
+ * - Reputation queries return aggregates, never raw interaction data
1423
+ * - Export bundles include all signatures for independent verification
1424
+ * - Import verifies every signature before accepting attestations
1512
1425
  */
1513
- interface InjectionDetectorConfig {
1514
- enabled: boolean;
1515
- sensitivity: "low" | "medium" | "high";
1516
- on_detection: "escalate" | "block" | "log";
1517
- custom_patterns?: string[];
1426
+
1427
+ /** Interaction outcome for recording */
1428
+ interface InteractionOutcome {
1429
+ type: "transaction" | "negotiation" | "service" | "dispute" | "custom";
1430
+ result: "completed" | "partial" | "failed" | "disputed";
1431
+ metrics?: Record<string, number>;
1518
1432
  }
1519
- interface InjectionSignal {
1520
- type: string;
1521
- pattern: string;
1522
- location: string;
1523
- severity: "low" | "medium" | "high";
1433
+ /** A signed attestation of an interaction */
1434
+ interface Attestation {
1435
+ attestation_id: string;
1436
+ schema: "sanctuary-interaction-v1";
1437
+ data: {
1438
+ interaction_id: string;
1439
+ participant_did: string;
1440
+ counterparty_did: string;
1441
+ outcome_type: string;
1442
+ outcome_result: string;
1443
+ metrics: Record<string, number>;
1444
+ context: string;
1445
+ timestamp: string;
1446
+ /** Sovereignty tier of the signer at time of recording */
1447
+ sovereignty_tier?: SovereigntyTier;
1448
+ };
1449
+ signature: string;
1450
+ signer: string;
1524
1451
  }
1525
- interface DetectionResult {
1526
- flagged: boolean;
1527
- confidence: number;
1528
- signals: InjectionSignal[];
1529
- recommendation: "allow" | "escalate" | "block";
1452
+ /** Stored attestation (encrypted at rest) */
1453
+ interface StoredAttestation {
1454
+ attestation: Attestation;
1455
+ counterparty_attestation?: string;
1456
+ counterparty_confirmed: boolean;
1457
+ recorded_at: string;
1530
1458
  }
1531
- declare class InjectionDetector {
1532
- private config;
1533
- private stats;
1534
- constructor(config?: Partial<InjectionDetectorConfig>);
1535
- /**
1536
- * Scan tool arguments for injection signals.
1537
- * @param toolName Full tool name (e.g., "state_read")
1538
- * @param args Tool arguments
1539
- * @returns DetectionResult with all detected signals
1540
- */
1541
- scan(toolName: string, args: Record<string, unknown>): DetectionResult;
1542
- /**
1543
- * SEC-035: Scan outbound content for secret leaks, data exfiltration,
1544
- * internal path exposure, and injection artifact survival.
1545
- *
1546
- * @param content The outbound content string to scan
1547
- * @returns DetectionResult with outbound-specific signal types
1548
- */
1549
- scanOutbound(content: string): DetectionResult;
1550
- /**
1551
- * Recursively scan a value and all nested values.
1552
- */
1553
- private scanValue;
1459
+ /** Aggregated metric statistics */
1460
+ interface MetricAggregate {
1461
+ mean: number;
1462
+ median: number;
1463
+ min: number;
1464
+ max: number;
1465
+ count: number;
1466
+ }
1467
+ /** Reputation query result */
1468
+ interface ReputationSummary {
1469
+ total_interactions: number;
1470
+ completed: number;
1471
+ partial: number;
1472
+ failed: number;
1473
+ disputed: number;
1474
+ contexts: string[];
1475
+ time_range: {
1476
+ start: string;
1477
+ end: string;
1478
+ };
1479
+ aggregate_metrics: Record<string, MetricAggregate>;
1480
+ }
1481
+ /** Portable reputation bundle */
1482
+ interface ReputationBundle {
1483
+ version: "SANCTUARY_REP_V1";
1484
+ attestations: Attestation[];
1485
+ exported_at: string;
1486
+ exporter_did: string;
1487
+ bundle_signature: string;
1488
+ }
1489
+ /** Escrow for trust bootstrapping */
1490
+ interface Escrow {
1491
+ escrow_id: string;
1492
+ transaction_terms: string;
1493
+ terms_hash: string;
1494
+ collateral_amount?: number;
1495
+ counterparty_did: string;
1496
+ creator_did: string;
1497
+ created_at: string;
1498
+ expires_at: string;
1499
+ status: "pending" | "active" | "released" | "disputed" | "expired";
1500
+ }
1501
+ /** Principal guarantee for a new agent */
1502
+ interface Guarantee {
1503
+ guarantee_id: string;
1504
+ principal_did: string;
1505
+ agent_did: string;
1506
+ scope: string;
1507
+ max_liability?: number;
1508
+ valid_until: string;
1509
+ certificate: string;
1510
+ created_at: string;
1511
+ }
1512
+ declare class ReputationStore {
1513
+ private storage;
1514
+ private encryptionKey;
1515
+ constructor(storage: StorageBackend, masterKey: Uint8Array);
1554
1516
  /**
1555
- * Scan a single string for injection signals.
1517
+ * Record an interaction outcome as a signed attestation.
1556
1518
  */
1557
- private scanString;
1519
+ record(interactionId: string, counterpartyDid: string, outcome: InteractionOutcome, context: string, identity: StoredIdentity, identityEncryptionKey: Uint8Array, counterpartyAttestation?: string, sovereigntyTier?: SovereigntyTier): Promise<StoredAttestation>;
1558
1520
  /**
1559
- * Count invisible Unicode characters in a string.
1560
- * Includes zero-width chars, soft hyphens, directional marks,
1561
- * variation selectors, and other invisible categories.
1521
+ * Query reputation data with filtering.
1522
+ * Returns aggregates only not raw interaction data.
1562
1523
  */
1563
- private countInvisibleChars;
1524
+ query(options: {
1525
+ context?: string;
1526
+ time_range?: {
1527
+ start: string;
1528
+ end: string;
1529
+ };
1530
+ metrics?: string[];
1531
+ counterparty_did?: string;
1532
+ }): Promise<ReputationSummary>;
1564
1533
  /**
1565
- * Strip invisible characters from a string for clean pattern matching.
1566
- * Returns a new string with all invisible chars removed.
1534
+ * Export attestations as a portable reputation bundle.
1567
1535
  */
1568
- private stripInvisibleChars;
1536
+ exportBundle(identity: StoredIdentity, identityEncryptionKey: Uint8Array, context?: string): Promise<ReputationBundle>;
1569
1537
  /**
1570
- * SEC-034: Token budget attack detection.
1571
- * Some Unicode sequences expand dramatically during tokenization (e.g., CJK
1572
- * ideographs, combining characters, emoji sequences). If the estimated token
1573
- * cost per character is anomalously high, this may be a wallet-drain payload.
1538
+ * Import attestations from a reputation bundle.
1539
+ * Verifies signatures if requested (default: true).
1574
1540
  *
1575
- * Heuristic: count chars that typically tokenize into multiple tokens.
1576
- * If the ratio of estimated tokens to char count exceeds 3x, flag it.
1577
- */
1578
- private detectTokenBudgetAttack;
1579
- /**
1580
- * Detect encoded content (base64, hex, HTML entities, URL encoding),
1581
- * decode it, and re-scan the decoded content through injection patterns.
1582
- * If the decoded content contains injection patterns, flag as encoding_evasion.
1583
- */
1584
- private detectEncodedPayloads;
1585
- /**
1586
- * Check if a string contains any injection patterns (role override or security bypass).
1587
- */
1588
- private containsInjectionPatterns;
1589
- /**
1590
- * Safely decode a base64 string. Returns null if it's not valid base64
1591
- * or doesn't decode to a meaningful string.
1592
- */
1593
- private safeBase64Decode;
1594
- /**
1595
- * Safely decode a hex string. Returns null on failure.
1596
- */
1597
- private safeHexDecode;
1598
- /**
1599
- * Decode HTML numeric entities (&#xHH; and &#DDD;) in a string.
1600
- */
1601
- private decodeHtmlEntities;
1602
- /**
1603
- * Safely decode a URL-encoded string. Returns null on failure.
1604
- */
1605
- private safeUrlDecode;
1606
- /**
1607
- * Heuristic: does this look like readable text (vs. binary garbage)?
1608
- * Checks that most characters are printable ASCII or common Unicode.
1609
- */
1610
- private looksLikeText;
1611
- /**
1612
- * Detect API keys and secrets in outbound content.
1613
- */
1614
- private detectSecretPatterns;
1615
- /**
1616
- * Detect data exfiltration via markdown images with data-carrying query params.
1617
- */
1618
- private detectOutboundExfiltration;
1619
- /**
1620
- * Detect internal filesystem path leaks in outbound content.
1621
- */
1622
- private detectInternalPathLeaks;
1623
- /**
1624
- * Detect private IP addresses and localhost references in outbound content.
1541
+ * @param publicKeys - Map of DID public key bytes for signature verification
1625
1542
  */
1626
- private detectPrivateNetworkLeaks;
1543
+ importBundle(bundle: ReputationBundle, verifySignatures: boolean, publicKeys: Map<string, Uint8Array>): Promise<{
1544
+ imported: number;
1545
+ invalid: number;
1546
+ contexts: string[];
1547
+ }>;
1627
1548
  /**
1628
- * Detect role markers / prompt template artifacts in outbound content.
1629
- * These should never appear in agent output — their presence indicates
1630
- * injection artifact survival.
1549
+ * Create an escrow for trust bootstrapping.
1631
1550
  */
1632
- private detectOutputRoleMarkers;
1551
+ createEscrow(transactionTerms: string, counterpartyDid: string, timeoutSeconds: number, creatorDid: string, collateralAmount?: number): Promise<Escrow>;
1633
1552
  /**
1634
- * Detect base64 strings, base64url, and zero-width character evasion.
1553
+ * Get an escrow by ID.
1635
1554
  */
1636
- private detectEncodingEvasion;
1555
+ getEscrow(escrowId: string): Promise<Escrow | null>;
1637
1556
  /**
1638
- * Detect URLs and emails in fields that shouldn't have them.
1557
+ * Create a principal's guarantee for a new agent.
1639
1558
  */
1640
- private detectDataExfiltration;
1559
+ createGuarantee(principalIdentity: StoredIdentity, agentDid: string, scope: string, durationSeconds: number, identityEncryptionKey: Uint8Array, maxLiability?: number): Promise<Guarantee>;
1641
1560
  /**
1642
- * Detect prompt stuffing: very large strings or high repetition.
1561
+ * Load attestations for tier-weighted scoring.
1562
+ * Applies basic context/counterparty filtering, returns full StoredAttestations
1563
+ * so callers can access sovereignty_tier from attestation data.
1643
1564
  */
1644
- private detectPromptStuffing;
1565
+ loadAllForTierScoring(options?: {
1566
+ context?: string;
1567
+ counterparty_did?: string;
1568
+ }): Promise<StoredAttestation[]>;
1569
+ private loadAll;
1570
+ }
1571
+
1572
+ /**
1573
+ * Sanctuary MCP Server — Federation Types
1574
+ *
1575
+ * MCP-to-MCP federation enables two Sanctuary instances to:
1576
+ * 1. Discover each other's capabilities (SIM exchange)
1577
+ * 2. Establish mutual trust (sovereignty handshake)
1578
+ * 3. Exchange signed reputation attestations
1579
+ * 4. Evaluate trust for cross-instance interactions
1580
+ *
1581
+ * Federation operates as a protocol layer atop the handshake:
1582
+ * Handshake establishes trust → Federation uses that trust for ongoing operations.
1583
+ *
1584
+ * Key constraint: Federation MUST respect each party's sovereignty.
1585
+ * Neither party can compel the other to share data they haven't disclosed
1586
+ * via their disclosure policy.
1587
+ */
1588
+
1589
+ /** A known federation peer */
1590
+ interface FederationPeer {
1591
+ /** The peer's instance ID (from their SHR) */
1592
+ peer_id: string;
1593
+ /** The peer's DID (identity) */
1594
+ peer_did: string;
1595
+ /** When this peer was first seen */
1596
+ first_seen: string;
1597
+ /** When last handshake completed */
1598
+ last_handshake: string;
1599
+ /** Current trust tier from most recent handshake */
1600
+ trust_tier: SovereigntyTier;
1601
+ /** Handshake result (for tier resolution) */
1602
+ handshake_result: HandshakeResult;
1603
+ /** Peer's advertised capabilities (from their SIM) */
1604
+ capabilities: FederationCapabilities;
1605
+ /** Whether we have a valid (non-expired) handshake */
1606
+ active: boolean;
1607
+ }
1608
+ /** Capabilities a peer advertises for federation */
1609
+ interface FederationCapabilities {
1610
+ /** Whether the peer supports reputation exchange */
1611
+ reputation_exchange: boolean;
1612
+ /** Whether the peer supports mutual attestation */
1613
+ mutual_attestation: boolean;
1614
+ /** Whether the peer supports encrypted channels */
1615
+ encrypted_channel: boolean;
1616
+ /** Supported attestation formats */
1617
+ attestation_formats: string[];
1618
+ }
1619
+ /** Trust evaluation result for a federation peer */
1620
+ interface PeerTrustEvaluation {
1621
+ peer_id: string;
1622
+ /** Current sovereignty tier (from handshake) */
1623
+ sovereignty_tier: SovereigntyTier;
1624
+ /** Whether handshake is current (not expired) */
1625
+ handshake_current: boolean;
1626
+ /** Reputation summary (if available) */
1627
+ reputation_score?: number;
1628
+ /** How many mutual attestations we share */
1629
+ mutual_attestation_count: number;
1630
+ /** Overall trust assessment */
1631
+ trust_level: "high" | "medium" | "low" | "none";
1632
+ /** Reasoning for the assessment */
1633
+ factors: string[];
1634
+ /** Evaluated at */
1635
+ evaluated_at: string;
1636
+ }
1637
+
1638
+ /**
1639
+ * Sanctuary MCP Server — Federation Peer Registry
1640
+ *
1641
+ * Manages known federation peers. Peers are discovered through handshakes
1642
+ * and tracked for ongoing federation operations.
1643
+ *
1644
+ * The registry is the source of truth for:
1645
+ * - Who we've federated with
1646
+ * - Current trust status of each peer
1647
+ * - Peer capabilities (what operations they support)
1648
+ *
1649
+ * Security invariants:
1650
+ * - Peers are ONLY added through completed handshakes (not self-registration)
1651
+ * - Trust tiers degrade automatically when handshakes expire
1652
+ * - Peer data is stored encrypted under L1 sovereignty
1653
+ */
1654
+
1655
+ declare class FederationRegistry {
1656
+ private peers;
1645
1657
  /**
1646
- * Determine if this field is inherently safe from role override.
1658
+ * Register or update a peer from a completed handshake.
1659
+ * This is the ONLY way peers enter the registry.
1647
1660
  */
1648
- private isSafeField;
1661
+ registerFromHandshake(result: HandshakeResult, peerDid: string, capabilities?: Partial<FederationCapabilities>): FederationPeer;
1649
1662
  /**
1650
- * Determine if this is a tool name field (where tool refs are expected).
1663
+ * Get a peer by instance ID.
1664
+ * Automatically updates active status based on handshake expiry.
1651
1665
  */
1652
- private isToolNameField;
1666
+ getPeer(peerId: string): FederationPeer | null;
1653
1667
  /**
1654
- * Determine if this field is safe for URLs.
1668
+ * List all known peers, optionally filtered by status.
1655
1669
  */
1656
- private isUrlSafeField;
1670
+ listPeers(filter?: {
1671
+ active_only?: boolean;
1672
+ }): FederationPeer[];
1657
1673
  /**
1658
- * Determine if this field is safe for emails.
1674
+ * Evaluate trust for a federation peer.
1675
+ *
1676
+ * Trust assessment considers:
1677
+ * - Handshake status (current vs expired)
1678
+ * - Sovereignty tier (verified-sovereign vs degraded vs unverified)
1679
+ * - Reputation data (if available)
1680
+ * - Mutual attestation history
1659
1681
  */
1660
- private isEmailSafeField;
1682
+ evaluateTrust(peerId: string, mutualAttestationCount?: number, reputationScore?: number): PeerTrustEvaluation;
1661
1683
  /**
1662
- * Determine if this field is safe for structured data (JSON/XML).
1684
+ * Remove a peer from the registry.
1663
1685
  */
1664
- private isStructuredField;
1686
+ removePeer(peerId: string): boolean;
1665
1687
  /**
1666
- * SEC-032/SEC-034: Map common cross-script confusable characters to their
1667
- * Latin equivalents. NFKC normalization handles fullwidth and compatibility
1668
- * forms, but does NOT map Cyrillic/Greek/Armenian/Georgian lookalikes to
1669
- * Latin (they're distinct codepoints by design).
1670
- *
1671
- * Extended to 50+ confusable pairs covering Cyrillic, Greek, Armenian,
1672
- * Georgian, Cherokee, and mathematical/symbol lookalikes.
1688
+ * Get the handshake results map (for tier resolution integration).
1673
1689
  */
1674
- private normalizeConfusables;
1690
+ getHandshakeResults(): Map<string, HandshakeResult>;
1691
+ }
1692
+
1693
+ /**
1694
+ * Sanctuary MCP Server — L2 Operational Isolation: Context Gating
1695
+ *
1696
+ * Context gating controls what information leaves the sovereignty boundary
1697
+ * when an agent makes outbound calls — especially inference calls to remote
1698
+ * LLM providers. This is the "minimum-necessary context" enforcement layer.
1699
+ *
1700
+ * The problem: When an agent sends a request to a remote LLM provider (Claude,
1701
+ * GPT, etc.), most harnesses send the agent's full context — conversation
1702
+ * history, memory, tool results, preferences, internal reasoning. The agent
1703
+ * has no control over what the provider sees.
1704
+ *
1705
+ * Context gating lets the agent define:
1706
+ * - Provider categories (inference, tool-api, logging, analytics, etc.)
1707
+ * - What fields/categories of context may flow to each provider type
1708
+ * - What must always be redacted (secrets, internal reasoning, PII, etc.)
1709
+ * - What requires transformation (hashing, summarizing, anonymizing)
1710
+ *
1711
+ * This sits in L2 (Operational Isolation) because it controls information
1712
+ * flow at the execution boundary. L3 (Selective Disclosure) handles agent-
1713
+ * to-agent trust negotiation with cryptographic proofs; context gating
1714
+ * handles agent-to-infrastructure information flow.
1715
+ *
1716
+ * Security invariants:
1717
+ * - Redact rules take absolute priority (like withhold in L3)
1718
+ * - Policies are stored encrypted under L1 sovereignty
1719
+ * - Every filter operation is audit-logged with a content hash
1720
+ * (what was sent, what was redacted — without storing the content itself)
1721
+ * - Default policy: redact everything not explicitly allowed
1722
+ */
1723
+
1724
+ /** Provider categories that context may flow to */
1725
+ type ProviderCategory = "inference" | "tool-api" | "logging" | "analytics" | "peer-agent" | "custom";
1726
+ /** Actions that can be taken on a context field */
1727
+ type ContextAction = "allow" | "redact" | "hash" | "summarize" | "deny";
1728
+ /** A rule within a context-gating policy */
1729
+ interface ContextGateRule {
1730
+ /** Provider category this rule applies to */
1731
+ provider: ProviderCategory | "*";
1732
+ /** Fields/patterns that may pass through */
1733
+ allow: string[];
1734
+ /** Fields/patterns that must be redacted (highest priority) */
1735
+ redact: string[];
1736
+ /** Fields/patterns that should be hashed */
1737
+ hash: string[];
1738
+ /** Fields/patterns that should be summarized (advisory) */
1739
+ summarize: string[];
1740
+ }
1741
+ /** A complete context-gating policy */
1742
+ interface ContextGatePolicy {
1743
+ policy_id: string;
1744
+ policy_name: string;
1745
+ rules: ContextGateRule[];
1746
+ /** Default action when no rule matches a field */
1747
+ default_action: "redact" | "deny";
1748
+ /** Identity this policy is bound to (optional) */
1749
+ identity_id?: string;
1750
+ created_at: string;
1751
+ updated_at: string;
1752
+ }
1753
+ /** Result of filtering a single field */
1754
+ interface FieldFilterResult {
1755
+ field: string;
1756
+ action: ContextAction;
1757
+ reason: string;
1758
+ /** If action is "hash", contains the hash */
1759
+ hash_value?: string;
1760
+ }
1761
+ /** Result of a full context filter operation */
1762
+ interface ContextFilterResult {
1763
+ policy_id: string;
1764
+ provider: ProviderCategory | string;
1765
+ fields_allowed: number;
1766
+ fields_redacted: number;
1767
+ fields_hashed: number;
1768
+ fields_summarized: number;
1769
+ fields_denied: number;
1770
+ decisions: FieldFilterResult[];
1771
+ /** SHA-256 hash of the original context (for audit trail) */
1772
+ original_context_hash: string;
1773
+ /** SHA-256 hash of the filtered output (for audit trail) */
1774
+ filtered_context_hash: string;
1775
+ filtered_at: string;
1776
+ }
1777
+ /**
1778
+ * Evaluate a context field against a policy for a given provider.
1779
+ *
1780
+ * Priority order (same as L3 disclosure):
1781
+ * 1. Redact (blocks — highest priority)
1782
+ * 2. Deny (blocks entire request)
1783
+ * 3. Hash (transforms)
1784
+ * 4. Summarize (advisory transform)
1785
+ * 5. Allow (passes through)
1786
+ * 6. Default action
1787
+ */
1788
+ declare function evaluateField(policy: ContextGatePolicy, provider: ProviderCategory | string, field: string): FieldFilterResult;
1789
+ /**
1790
+ * Filter a full context object against a policy for a given provider.
1791
+ * Returns per-field decisions and content hashes for the audit trail.
1792
+ */
1793
+ declare function filterContext(policy: ContextGatePolicy, provider: ProviderCategory | string, context: Record<string, unknown>): ContextFilterResult;
1794
+ /**
1795
+ * Context gate policy store — encrypted under L1 sovereignty.
1796
+ */
1797
+ declare class ContextGatePolicyStore {
1798
+ private storage;
1799
+ private encryptionKey;
1800
+ private policies;
1801
+ constructor(storage: StorageBackend, masterKey: Uint8Array);
1675
1802
  /**
1676
- * Compute confidence score based on signals.
1677
- * More high-severity signals = higher confidence.
1803
+ * Create and store a new context-gating policy.
1678
1804
  */
1679
- private computeConfidence;
1805
+ create(policyName: string, rules: ContextGateRule[], defaultAction: "redact" | "deny", identityId?: string): Promise<ContextGatePolicy>;
1680
1806
  /**
1681
- * Compute recommendation based on signals and sensitivity.
1807
+ * Get a policy by ID.
1682
1808
  */
1683
- private computeRecommendation;
1809
+ get(policyId: string): Promise<ContextGatePolicy | null>;
1684
1810
  /**
1685
- * Get statistics about scans performed.
1811
+ * List all context-gating policies.
1686
1812
  */
1687
- getStats(): {
1688
- total_scans: number;
1689
- total_flags: number;
1690
- total_blocks: number;
1691
- signals_by_type: Record<string, number>;
1692
- };
1813
+ list(): Promise<ContextGatePolicy[]>;
1693
1814
  /**
1694
- * Reset statistics.
1815
+ * Load all persisted policies into memory.
1695
1816
  */
1696
- resetStats(): void;
1817
+ private loadAll;
1818
+ private persist;
1697
1819
  }
1698
1820
 
1699
1821
  /**
1700
- * Sanctuary MCP Server — Principal Policy Types
1822
+ * Sanctuary MCP Server — L2 Context Gating: Starter Policy Templates
1701
1823
  *
1702
- * Type definitions for the Principal Policy system.
1703
- * The Principal Policy is the human-controlled, agent-immutable
1704
- * configuration that gates operations through approval tiers.
1705
- */
1706
- /** Tier 2 anomaly action: what to do when an anomaly is detected */
1707
- type AnomalyAction = "approve" | "log" | "allow";
1708
- /** Tier 2 anomaly detection configuration */
1709
- interface Tier2Config {
1710
- /** Action when agent accesses a namespace it hasn't used before */
1711
- new_namespace_access: AnomalyAction;
1712
- /** Action when agent interacts with an unknown counterparty DID */
1713
- new_counterparty: AnomalyAction;
1714
- /** Tool call frequency multiplier that triggers anomaly */
1715
- frequency_spike_multiplier: number;
1716
- /** Maximum signing operations per minute before triggering */
1717
- max_signs_per_minute: number;
1718
- /** Reading more than N keys in a namespace within 60 seconds */
1719
- bulk_read_threshold: number;
1720
- /** Policy for first session when no baseline exists */
1721
- first_session_policy: AnomalyAction;
1722
- }
1723
- /** Approval channel configuration */
1724
- interface ApprovalChannelConfig {
1725
- type: "stderr" | "webhook" | "callback";
1726
- timeout_seconds: number;
1727
- /**
1728
- * SEC-002: auto_deny is hardcoded to true and not configurable.
1729
- * Timeout on any approval channel ALWAYS results in denial.
1730
- * This field is retained for backward compatibility with existing
1731
- * policy files but is ignored — timeout always denies.
1732
- */
1733
- auto_deny?: boolean;
1734
- webhook_url?: string;
1735
- webhook_secret?: string;
1736
- }
1737
- /** Complete Principal Policy */
1738
- interface PrincipalPolicy {
1739
- version: number;
1740
- /** Operations that always require human approval */
1741
- tier1_always_approve: string[];
1742
- /** Behavioral anomaly detection configuration */
1743
- tier2_anomaly: Tier2Config;
1744
- /** Operations that never require approval (audit only) */
1745
- tier3_always_allow: string[];
1746
- /** How approval requests reach the human */
1747
- approval_channel: ApprovalChannelConfig;
1748
- }
1749
- /** Approval request sent to the human */
1750
- interface ApprovalRequest {
1751
- operation: string;
1752
- tier: 1 | 2;
1753
- reason: string;
1754
- context: Record<string, unknown>;
1755
- timestamp: string;
1756
- }
1757
- /** Approval response from the human */
1758
- interface ApprovalResponse {
1759
- decision: "approve" | "deny";
1760
- decided_at: string;
1761
- decided_by: "human" | "timeout" | "auto" | "stderr:non-interactive";
1762
- }
1763
- /** Result of the approval gate evaluation */
1764
- interface GateResult {
1765
- allowed: boolean;
1766
- tier: 1 | 2 | 3;
1767
- reason: string;
1768
- approval_required: boolean;
1769
- approval_response?: ApprovalResponse;
1770
- }
1771
- /** Behavioral baseline for anomaly detection */
1772
- interface SessionProfile {
1773
- /** Namespaces accessed (read or write) */
1774
- known_namespaces: string[];
1775
- /** Counterparty DIDs seen in reputation operations */
1776
- known_counterparties: string[];
1777
- /** Tool call counts per tool name (lifetime in session) */
1778
- tool_call_counts: Record<string, number>;
1779
- /** Whether this is the first session (no prior baseline) */
1780
- is_first_session: boolean;
1781
- /** Session start time */
1782
- started_at: string;
1783
- /** When the baseline was last saved */
1784
- saved_at?: string;
1785
- }
1786
-
1787
- /**
1788
- * Sanctuary MCP Server — Approval Channel
1824
+ * Pre-built policies for common use cases. These are starting points —
1825
+ * users should customize them for their specific context structure.
1789
1826
  *
1790
- * Out-of-band communication with the human principal for operation approval.
1791
- * The default channel uses stderr (outside MCP's stdin/stdout protocol),
1792
- * ensuring the agent cannot intercept or forge approval responses.
1827
+ * Templates:
1793
1828
  *
1794
- * Security invariant:
1795
- * - Approval prompts go through a channel the agent cannot access.
1796
- * - Timeouts result in denial by default (fail closed).
1829
+ * inference-minimal
1830
+ * Only the current task and query reach the LLM. Everything else
1831
+ * is redacted. Secrets, PII, memory, reasoning, and history are
1832
+ * all blocked. IDs are hashed. Maximum privacy, minimum context.
1833
+ *
1834
+ * inference-standard
1835
+ * Task, query, and tool results pass through. Conversation history
1836
+ * is flagged for summarization (compress before sending). Secrets,
1837
+ * PII, and internal reasoning are redacted. IDs are hashed.
1838
+ * Balanced: the LLM has enough context to be useful without seeing
1839
+ * everything the agent knows.
1840
+ *
1841
+ * logging-strict
1842
+ * Redacts everything for logging/analytics providers. Only
1843
+ * operation names and timestamps pass through. Use this for
1844
+ * telemetry services where you want usage metrics without
1845
+ * content exposure.
1846
+ *
1847
+ * tool-api-scoped
1848
+ * Allows tool-specific parameters and the current task, redacts
1849
+ * memory, history, secrets, and PII. Hashes IDs. For outbound
1850
+ * calls to external APIs (search, database, etc.) where you need
1851
+ * to send query parameters but not your agent's full state.
1797
1852
  */
1798
1853
 
1799
- /** Abstract approval channel interface */
1800
- interface ApprovalChannel {
1801
- requestApproval(request: ApprovalRequest): Promise<ApprovalResponse>;
1854
+ /** A template definition ready to be applied via the policy store */
1855
+ interface ContextGateTemplate {
1856
+ /** Machine-readable template ID */
1857
+ id: string;
1858
+ /** Human-readable name */
1859
+ name: string;
1860
+ /** One-line description */
1861
+ description: string;
1862
+ /** When to use this template */
1863
+ use_when: string;
1864
+ /** The rules that make up this template */
1865
+ rules: ContextGateRule[];
1866
+ /** Default action for unmatched fields */
1867
+ default_action: "redact" | "deny";
1802
1868
  }
1869
+ /** All available templates, keyed by ID */
1870
+ declare const TEMPLATES: Record<string, ContextGateTemplate>;
1871
+ /** List all available template IDs */
1872
+ declare function listTemplateIds(): string[];
1873
+ /** Get a template by ID (returns undefined if not found) */
1874
+ declare function getTemplate(id: string): ContextGateTemplate | undefined;
1875
+
1803
1876
  /**
1804
- * Stderr approval channelnon-interactive informational channel.
1877
+ * Sanctuary MCP ServerL2 Context Gating: Policy Recommendation Engine
1805
1878
  *
1806
- * In the MCP stdio model:
1807
- * - stdin/stdout carry the MCP protocol (JSON-RPC)
1808
- * - stderr is available for out-of-band human communication
1879
+ * Analyzes a sample context object and recommends a context-gating policy
1880
+ * based on field name heuristics. The agent (or human) can then review,
1881
+ * adjust, and apply the recommendation.
1809
1882
  *
1810
- * Because stdin is consumed by the MCP JSON-RPC transport, this channel
1811
- * CANNOT read interactive human input. It is strictly informational:
1812
- * the prompt is displayed so the human sees what is happening, and the
1813
- * operation is denied immediately.
1883
+ * This is deliberately conservative: when in doubt, it recommends redact.
1884
+ * A false redaction is a usability issue; a false allow is a privacy leak.
1814
1885
  *
1815
- * SEC-002 + SEC-016 invariants:
1816
- * - This channel ALWAYS denies. No configuration can change this.
1817
- * - There is no timeout or async delay — denial is synchronous.
1818
- * - The `auto_deny` config field is ignored (SEC-002).
1819
- * - For interactive approval, use the dashboard or webhook channel.
1886
+ * Classification heuristics:
1887
+ * - Known secret patterns redact (highest confidence)
1888
+ * - Known PII patterns redact (high confidence)
1889
+ * - Known internal state patterns redact (high confidence)
1890
+ * - Known ID patterns hash (medium confidence)
1891
+ * - Known history patterns → summarize (medium confidence)
1892
+ * - Known task/query patterns → allow (medium confidence)
1893
+ * - Everything else → redact (conservative default)
1894
+ *
1895
+ * WARNING: Fields like 'tool_results' and 'tool_output' are classified as
1896
+ * "allow" (medium confidence) but may contain sensitive data from external
1897
+ * API responses, including auth tokens, user data, or PII. Always review
1898
+ * recommendations before applying — the heuristic classifies by field NAME,
1899
+ * not field CONTENT.
1820
1900
  */
1821
- declare class StderrApprovalChannel implements ApprovalChannel {
1822
- constructor(_config: ApprovalChannelConfig);
1823
- requestApproval(request: ApprovalRequest): Promise<ApprovalResponse>;
1824
- private formatPrompt;
1901
+ /** Classification result for a single field */
1902
+ interface FieldClassification {
1903
+ field: string;
1904
+ recommended_action: "allow" | "redact" | "hash" | "summarize";
1905
+ reason: string;
1906
+ confidence: "high" | "medium" | "low";
1907
+ /** Pattern that matched, if any */
1908
+ matched_pattern: string | null;
1909
+ }
1910
+ /** Full recommendation result */
1911
+ interface PolicyRecommendation {
1912
+ provider: string;
1913
+ classifications: FieldClassification[];
1914
+ recommended_rules: {
1915
+ allow: string[];
1916
+ redact: string[];
1917
+ hash: string[];
1918
+ summarize: string[];
1919
+ };
1920
+ default_action: "redact";
1921
+ summary: {
1922
+ total_fields: number;
1923
+ allow: number;
1924
+ redact: number;
1925
+ hash: number;
1926
+ summarize: number;
1927
+ };
1928
+ warnings: string[];
1825
1929
  }
1826
1930
  /**
1827
- * Programmatic approval channel for testing and API integration.
1931
+ * Classify a single field name and return a recommendation.
1828
1932
  */
1829
- declare class CallbackApprovalChannel implements ApprovalChannel {
1830
- private callback;
1831
- constructor(callback: (request: ApprovalRequest) => Promise<ApprovalResponse>);
1832
- requestApproval(request: ApprovalRequest): Promise<ApprovalResponse>;
1833
- }
1933
+ declare function classifyField(fieldName: string): FieldClassification;
1834
1934
  /**
1835
- * Auto-approve channel for testing. Approves everything.
1935
+ * Analyze a full context object and recommend a policy.
1836
1936
  */
1837
- declare class AutoApproveChannel implements ApprovalChannel {
1838
- requestApproval(_request: ApprovalRequest): Promise<ApprovalResponse>;
1839
- }
1937
+ declare function recommendPolicy(context: Record<string, unknown>, provider?: string): PolicyRecommendation;
1840
1938
 
1841
1939
  /**
1842
- * Sanctuary MCP Server — Behavioral Baseline Tracker
1940
+ * Sanctuary MCP Server — L2 Model Provenance
1843
1941
  *
1844
- * Tracks the agent's behavioral profile during a session and persists
1845
- * it for cross-session anomaly detection. The baseline defines "normal"
1846
- * so that deviations can trigger Tier 2 approval.
1942
+ * Declares and attests to the model(s) powering this agent.
1847
1943
  *
1848
- * Security invariants:
1849
- * - Baseline is stored encrypted under L1 sovereignty
1850
- * - Baseline changes are audit-logged
1851
- * - Baseline is integrity-verified via L1 Merkle tree
1852
- * - No MCP tool can directly modify the baseline
1944
+ * Vitalik Buterin's "Secure LLM" post (April 2026) identified a critical gap:
1945
+ * open-weights-but-not-open-source models can have trained-in backdoors. Model
1946
+ * provenance declaration lets agents and their operators verify the integrity
1947
+ * of the inference backbone.
1948
+ *
1949
+ * Tracks: model name, version, weights hash, license, open-source status,
1950
+ * training data hash (if available). Included in SHR L2 section.
1951
+ *
1952
+ * This sits in L2 (Operational Isolation) because it's part of the runtime
1953
+ * attestation surface — the agent declares what model(s) it's actually running.
1853
1954
  */
1854
-
1855
- declare class BaselineTracker {
1856
- private storage;
1857
- private encryptionKey;
1858
- private profile;
1859
- /** Sliding window: timestamps of tool calls per tool name (last 60s) */
1860
- private callWindows;
1861
- /** Sliding window: read counts per namespace (last 60s) */
1862
- private readWindows;
1863
- /** Sliding window: sign call timestamps (last 60s) */
1864
- private signWindow;
1865
- constructor(storage: StorageBackend, masterKey: Uint8Array);
1866
- /**
1867
- * Load the previous session's baseline from storage.
1868
- * If none exists, this is a first session.
1869
- */
1870
- load(): Promise<void>;
1871
- /**
1872
- * Save the current baseline to storage (encrypted).
1873
- * Called at session end or periodically.
1874
- */
1875
- save(): Promise<void>;
1876
- /**
1877
- * Record a tool call for baseline tracking.
1878
- * Returns anomaly information if applicable.
1879
- */
1880
- recordToolCall(toolName: string): void;
1881
- /**
1882
- * Record a namespace access.
1883
- * @returns true if this is a new namespace (not in baseline)
1884
- */
1885
- recordNamespaceAccess(namespace: string): boolean;
1955
+ /**
1956
+ * Metadata about a single model powering this agent.
1957
+ */
1958
+ interface ModelProvenance {
1959
+ /** Machine-readable model ID (e.g., "qwen3.5-35b", "claude-opus-4", "llama-3.3-70b-instruct") */
1960
+ model_id: string;
1961
+ /** Human-readable model name (e.g., "Qwen 3.5", "Claude Opus 4", "Llama 3.3 70B Instruct") */
1962
+ model_name: string;
1963
+ /** Semantic version (e.g., "3.5", "4.0", "3.3") */
1964
+ model_version: string;
1965
+ /** Provider/vendor (e.g., "Alibaba Cloud", "Anthropic", "Meta", "local") */
1966
+ provider: string;
1967
+ /** SHA-256 of model weights file, if available and verifiable */
1968
+ weights_hash?: string;
1969
+ /** SHA-256 of training data manifest or metadata, if available */
1970
+ training_data_hash?: string;
1971
+ /** License identifier (e.g., "Apache-2.0", "CC-BY-4.0", "proprietary", "unknown") */
1972
+ license: string;
1973
+ /** True if model weights are publicly available (even if training is proprietary) */
1974
+ open_weights: boolean;
1975
+ /** True if full training code, data, and methodology are publicly available */
1976
+ open_source: boolean;
1977
+ /** True if inference runs on the local agent's hardware (not delegated to cloud API) */
1978
+ local_inference: boolean;
1979
+ /** ISO 8601 timestamp when this provenance was declared */
1980
+ declared_at: string;
1981
+ }
1982
+ /**
1983
+ * In-memory and persistent store for model provenance declarations.
1984
+ * Declarations are encrypted under L1 sovereignty.
1985
+ */
1986
+ interface ModelProvenanceStore {
1886
1987
  /**
1887
- * Record a namespace read for bulk-read detection.
1888
- * @returns the number of reads in the current 60-second window
1988
+ * Declare a model's provenance and add it to the store.
1889
1989
  */
1890
- recordNamespaceRead(namespace: string): number;
1990
+ declare(provenance: ModelProvenance): void;
1891
1991
  /**
1892
- * Record a counterparty DID interaction.
1893
- * @returns true if this is a new counterparty (not in baseline)
1992
+ * Retrieve a model's provenance by ID.
1894
1993
  */
1895
- recordCounterparty(did: string): boolean;
1994
+ get(model_id: string): ModelProvenance | undefined;
1896
1995
  /**
1897
- * Record a signing operation.
1898
- * @returns the number of signs in the current 60-second window
1996
+ * List all declared models.
1899
1997
  */
1900
- recordSign(): number;
1998
+ list(): ModelProvenance[];
1901
1999
  /**
1902
- * Get the current call rate for a tool (calls per minute).
2000
+ * Get the primary/main model (the one the agent uses by default for inference).
1903
2001
  */
1904
- getCallRate(toolName: string): number;
2002
+ primary(): ModelProvenance | undefined;
1905
2003
  /**
1906
- * Get the average call rate across all tools in the baseline.
2004
+ * Set which model is the primary.
1907
2005
  */
1908
- getAverageCallRate(): number;
1909
- /** Whether this is the first session */
1910
- get isFirstSession(): boolean;
1911
- /** Get a read-only view of the current profile */
1912
- getProfile(): SessionProfile;
2006
+ setPrimary(model_id: string): void;
1913
2007
  }
1914
-
1915
2008
  /**
1916
- * Sanctuary MCP Server — Approval Gate
1917
- *
1918
- * The three-tier approval gate sits between the MCP router and tool handlers.
1919
- * Every tool call passes through the gate before execution.
1920
- *
1921
- * Evaluation order:
1922
- * 1. Tier 1: Is this operation in the always-approve list? → Request approval.
1923
- * 2. Tier 2: Does this call represent a behavioral anomaly? → Request approval.
1924
- * 3. Tier 3 / default: Allow with audit logging.
1925
- *
1926
- * Security invariants:
1927
- * - The gate cannot be bypassed — it wraps every tool handler.
1928
- * - Denial responses do not reveal policy details to the agent.
1929
- * - All gate decisions (approve, deny, allow) are audit-logged.
2009
+ * In-memory implementation of ModelProvenanceStore.
2010
+ * Suitable for most use cases. For encrypted persistence, integrate with L1 state store.
1930
2011
  */
1931
-
1932
- /** Callback invoked when an injection is detected, for dashboard broadcasting */
1933
- type InjectionAlertCallback = (alert: {
1934
- toolName: string;
1935
- result: DetectionResult;
1936
- timestamp: string;
1937
- }) => void;
1938
- /** Resolver for proxy tool tiers — provided by the ProxyRouter */
1939
- type ProxyTierResolver = (toolName: string) => (1 | 2 | 3) | null;
1940
- declare class ApprovalGate {
1941
- private policy;
1942
- private baseline;
1943
- private channel;
1944
- private auditLog;
1945
- private injectionDetector;
1946
- private onInjectionAlert?;
1947
- private proxyTierResolver?;
1948
- constructor(policy: PrincipalPolicy, baseline: BaselineTracker, channel: ApprovalChannel, auditLog: AuditLog, injectionDetector?: InjectionDetector, onInjectionAlert?: InjectionAlertCallback);
1949
- /**
1950
- * Set the proxy tier resolver. Called after the proxy router is initialized.
1951
- */
1952
- setProxyTierResolver(resolver: ProxyTierResolver): void;
2012
+ declare class InMemoryModelProvenanceStore implements ModelProvenanceStore {
2013
+ private models;
2014
+ private primaryModelId;
2015
+ declare(provenance: ModelProvenance): void;
2016
+ get(model_id: string): ModelProvenance | undefined;
2017
+ list(): ModelProvenance[];
2018
+ primary(): ModelProvenance | undefined;
2019
+ setPrimary(model_id: string): void;
2020
+ }
2021
+ /**
2022
+ * Common model provenance presets for quick initialization.
2023
+ */
2024
+ declare const MODEL_PRESETS: {
1953
2025
  /**
1954
- * Evaluate a tool call against the Principal Policy.
1955
- *
1956
- * @param toolName - Full MCP tool name (e.g., "state_export")
1957
- * @param args - Tool call arguments (for context extraction)
1958
- * @returns GateResult indicating whether the call is allowed
2026
+ * Claude Opus 4 via Anthropic API (cloud inference, closed weights/source)
1959
2027
  */
1960
- evaluate(toolName: string, args: Record<string, unknown>): Promise<GateResult>;
2028
+ claudeOpus4: () => ModelProvenance;
1961
2029
  /**
1962
- * Detect Tier 2 behavioral anomalies.
2030
+ * Qwen 3.5 via local inference (open weights, proprietary training)
1963
2031
  */
1964
- private detectAnomaly;
2032
+ qwen35Local: () => ModelProvenance;
1965
2033
  /**
1966
- * Request approval from the human principal.
2034
+ * Llama 3.3 70B via local inference (open weights and code)
1967
2035
  */
1968
- private requestApproval;
2036
+ llama33Local: () => ModelProvenance;
1969
2037
  /**
1970
- * Summarize tool arguments for the approval prompt.
1971
- * Strips potentially large values to keep the prompt readable.
2038
+ * Mistral 7B (open weights, open code, local inference)
1972
2039
  */
1973
- private summarizeArgs;
1974
- /** Get the baseline tracker for saving at session end */
1975
- getBaseline(): BaselineTracker;
1976
- /** Get the injection detector for stats/configuration access */
1977
- getInjectionDetector(): InjectionDetector;
1978
- }
1979
-
1980
- /**
1981
- * Sanctuary MCP Server — Tool Router
1982
- *
1983
- * Routes sanctuary/* tool calls to their layer-specific handlers.
1984
- * Every tool call passes through schema validation and the ApprovalGate
1985
- * (if configured) before execution. Neither can be bypassed.
1986
- *
1987
- * This module is the abstraction boundary for MCP SDK version migration —
1988
- * if the SDK API changes, only this module needs updating.
1989
- */
1990
-
1991
- /** Tool handler function signature */
1992
- type ToolHandler = (args: Record<string, unknown>) => Promise<{
1993
- content: Array<{
1994
- type: "text";
1995
- text: string;
1996
- }>;
1997
- }>;
1998
- /** Tool definition for registration */
1999
- interface ToolDefinition {
2000
- name: string;
2001
- description: string;
2002
- inputSchema: Record<string, unknown>;
2003
- handler: ToolHandler;
2004
- }
2040
+ mistral7bLocal: () => ModelProvenance;
2041
+ };
2005
2042
 
2006
2043
  /**
2007
2044
  * Sanctuary MCP Server — L2 Context Gating: Automatic Enforcer
@@ -2620,37 +2657,6 @@ declare class FilesystemStorage implements StorageBackend {
2620
2657
  */
2621
2658
  declare function loadPrincipalPolicy(storagePath: string): Promise<PrincipalPolicy>;
2622
2659
 
2623
- /**
2624
- * Sanctuary MCP Server — L1 Cognitive Sovereignty: Tool Definitions
2625
- *
2626
- * MCP tool wrappers for StateStore and IdentityRoot operations.
2627
- * These tools are the public API that agents interact with.
2628
- */
2629
-
2630
- /** Manages all identities — provides storage and retrieval */
2631
- declare class IdentityManager {
2632
- private storage;
2633
- private masterKey;
2634
- private identities;
2635
- private primaryIdentityId;
2636
- constructor(storage: StorageBackend, masterKey: Uint8Array);
2637
- private get encryptionKey();
2638
- /** Load identities from storage on startup.
2639
- * Returns { total: number of encrypted files found, loaded: number successfully decrypted }.
2640
- * A mismatch (total > 0, loaded === 0) indicates a wrong master key / missing passphrase.
2641
- */
2642
- load(): Promise<{
2643
- total: number;
2644
- loaded: number;
2645
- failed: number;
2646
- }>;
2647
- /** Save an identity to storage */
2648
- save(identity: StoredIdentity): Promise<void>;
2649
- get(id: string): StoredIdentity | undefined;
2650
- getDefault(): StoredIdentity | undefined;
2651
- list(): PublicIdentity[];
2652
- }
2653
-
2654
2660
  /**
2655
2661
  * Sanctuary MCP Server — SHR Generator
2656
2662
  *
@@ -3368,6 +3374,16 @@ declare function verifyBridgeCommitment(commitment: BridgeCommitment, outcome: C
3368
3374
  interface SanctuaryServer {
3369
3375
  server: Server;
3370
3376
  config: SanctuaryConfig;
3377
+ /**
3378
+ * Runtime dependencies exposed for embedding callers that need
3379
+ * direct access to the Sanctuary substrate (e.g., the EU AI Act
3380
+ * compliance CLI subcommand). Most callers only use `server` and
3381
+ * `config`; these are optional-usage extras.
3382
+ */
3383
+ identityManager: IdentityManager;
3384
+ masterKey: Uint8Array;
3385
+ auditLog: AuditLog;
3386
+ policy: PrincipalPolicy;
3371
3387
  }
3372
3388
  /**
3373
3389
  * Initialize the Sanctuary MCP Server.