Skip to content

Repository files navigation

Sanna — Trust Infrastructure for AI Agents

Sanna generates portable cryptographic receipts attesting to governance outcomes. The sannaObserve wrapper is post-execution detection and attestation -- the wrapped function executes before output checks run, so its side effects are not prevented; the gateway and interceptor surfaces enforce governance pre-execution and block disallowed actions before they occur. Constitution-as-code: your governance rules live in version-controlled YAML, not in a vendor dashboard.

This is the TypeScript implementation of Sanna Protocol v1.5. For the Python reference implementation, see sanna-ai/sanna.

v1.5.0 Release Notes

Receipt Schema v1.5 — 21-field fingerprint (up from 20), adding agent_identity at fingerprint position 21.

New receipt fields:

  • tool_name — required at cv>=9. Canonical SDK identity: "sanna-ts" (TS), "sanna" (Python). Participates in fingerprint at position 17.
  • agent_model / agent_model_provider / agent_model_version — optional nullable fields capturing LLM model identity. Null = opt-out; absent = not captured. Fingerprint positions 18-20.
  • agent_identity — optional object for agent session identity; must include agent_session_id when present. Triggers spec_version "1.5" / checks_version "10" emission. Participates in fingerprint at position 21 via hashObj. Absent in cv=9 legacy receipts.

Version changes:

  • SPEC_VERSION"1.5", CHECKS_VERSION"10", TOOL_VERSION"1.5.0" (bare semver; SDK identity moves to tool_name field).
  • All 4 npm packages bumped to 1.5.0.

v1.3.0 Release Notes

Receipt Schema v1.3 — 16-field fingerprint (up from 14), adding enforcement_surface and invariants_scope as required fields. The verifier now enforces these fields and the 4-action status override (halted→FAIL, warned→WARN, escalated→WARN) at verification time as well as at emission time.

New receipt fields:

  • parent_receipts — array of parent receipt fingerprints for causal chaining (e.g., escalation → execution)
  • workflow_id — per-session identifier for grouping related receipts across a workflow
  • content_mode / content_mode_source — attestation of what content mode (full, redacted, hashes_only) was active and where it was configured

ReceiptSink architecture — pluggable receipt delivery replacing direct SQLite coupling:

  • CloudHTTPSink — HTTPS delivery with retry, exponential backoff, batch support, and buffer-and-retry via JSONL
  • CompositeSink — fan-out to multiple sinks with Promise.allSettled() failure isolation
  • LocalSQLiteSink — wraps ReceiptStore as a ReceiptSink for backward compatibility
  • NullSink — no-op sink for testing

Gateway receipt chaining — escalation receipts are automatically linked as parents when the escalated tool call is approved and executed. Per-session workflow_id groups all receipts within a gateway session.

Content mode attestation — gateway records which content_mode is active and its source in receipt metadata.

926 tests across 48 files (up from 771 across 44).

Quick Start — Library Mode

npm install @sanna-ai/core
npm install -g @sanna-ai/cli

Set up governance (one-time):

sanna init         # Choose template, set agent name, enforcement level
sanna keygen       # Generate Ed25519 keypair (~/.sanna/keys/)
# Output:
#   Generated Ed25519 keypair (a1b2c3d4e5f6...)
#   Private key: /Users/you/.sanna/keys/a1b2c3d4e5f6...7890.key
#   Public key:  /Users/you/.sanna/keys/a1b2c3d4e5f6...7890.pub
sanna sign constitution.yaml --private-key ~/.sanna/keys/<key-id>.key

Now wrap the functions you want to govern. sannaObserve wraps the functions you choose — internal reasoning, prompt construction, and non-governed function calls produce no receipts.

import { sannaObserve, SannaHaltError } from "@sanna-ai/core";
import type { SannaResult } from "@sanna-ai/core";

const myAgent = sannaObserve(
  (query: string, context: string): string => {
    return "Based on the data, revenue grew 12% year-over-year.";
  },
  {
    constitutionPath: "constitution.yaml",
    constitutionPublicKeyPath: "~/.sanna/keys/<key-id>.pub",  // from sanna keygen above
  },
);

// sannaObserve wraps the return value in a SannaResult with .output and .receipt.
// The original string return is available as result.output.
try {
  const result: SannaResult<string> = myAgent(
    "What was revenue growth?",
    "Annual report: revenue increased 12% YoY to $4.2B.",
  );
  console.log(result.output);   // The original string return value
  console.log(result.receipt);  // Cryptographic governance receipt
  // To persist receipts, use ReceiptStore separately:
  //   import { ReceiptStore } from "@sanna-ai/core";
  //   const store = new ReceiptStore(".sanna/receipts.db");
  //   store.save(result.receipt);
} catch (e) {
  if (e instanceof SannaHaltError) {
    console.error(`HALTED: ${e.message}`);  // Constitution violation detected
  }
}

Quick Start — Gateway Mode

No code changes to your agent. The gateway sits between your MCP client and downstream servers.

npm install @sanna-ai/gateway
npm install -g @sanna-ai/cli

sanna init         # Creates constitution.yaml + gateway.yaml
sanna keygen --label gateway
sanna sign constitution.yaml --private-key ~/.sanna/keys/<key-id>.key
sanna gateway gateway.yaml

Minimum gateway.yaml:

gateway:
  constitution:
    path: ./constitution.yaml
  enforcement:
    mode: enforced
    default_policy: deny

downstreams:
  - name: notion
    command: npx
    args: ["-y", "@notionhq/notion-mcp-server"]
    env:
      OPENAPI_MCP_HEADERS: "${OPENAPI_MCP_HEADERS}"

Point your MCP client (Claude Desktop, Claude Code, Cursor) at the gateway instead of directly at your downstream servers. Every tool call is now governed. The gateway governs tool calls that pass through it — only actions that cross the governance boundary produce receipts. Reasoning is captured via the explicit _justification parameter in tool calls, not from internal model reasoning. The gateway cannot observe LLM chain-of-thought.

MCP Client (Claude Desktop / Claude Code / Cursor)
        |
        v  (MCP stdio)
sanna-gateway
        |  1. Receive tool call
        |  2. Evaluate against constitution
        |  3. Enforce policy (allow / escalate / deny)
        |  4. Generate signed receipt
        |  5. Forward to downstream (if allowed)
        v  (MCP stdio)
Downstream MCP Servers (Notion, GitHub, filesystem, etc.)

Demo

Run a self-contained governance demo — no external dependencies:

sanna demo

This generates keys, creates a constitution, simulates a governed tool call, generates a receipt, and verifies it.

Core Concepts

Constitution — YAML document defining what the agent can, cannot, and must escalate. Ed25519-signed. Modification after signing is detected on load. Constitution signing (via sanna sign) is required for enforcement. Constitution approval is an optional additional governance step for multi-party review workflows.

Receipt — JSON artifact binding inputs, reasoning, action, and check results into a cryptographically signed, schema-validated, deterministically fingerprinted record. Receipts are generated per governed action — when an agent calls a tool or executes a wrapped function — not per conversational turn. An agent that reasons for twenty turns and executes one action produces one receipt.

Coherence Checks (C1-C5) — Five built-in deterministic heuristics. No API calls or external dependencies.

Check Invariant What it catches
C1 INV_NO_FABRICATION Output contradicts provided context
C2 INV_MARK_INFERENCE Definitive claims without hedging
C3 INV_NO_FALSE_CERTAINTY Confidence exceeding evidence strength
C4 INV_PRESERVE_TENSION Conflicting information collapsed
C5 INV_NO_PREMATURE_COMPRESSION Complex input reduced to single sentence

Authority Boundariescan_execute (forward), must_escalate (prompt user), cannot_execute (deny). Policy cascade: per-tool override > server default > constitution.

Key Management — Public keys are stored in ~/.sanna/keys/ and referenced by their key ID (SHA-256 fingerprint of the public key). For verification, pass the public key path explicitly via --public-key on the CLI or constitutionPublicKeyPath in code.

Receipt Format

Every governed action produces a reasoning receipt — a JSON artifact that cryptographically binds inputs, outputs, check results, and constitution provenance. See the Sanna Protocol specification for the full specification.

Identification

Field Type Description
spec_version string Schema version, "1.5"
tool_version string Package version, e.g. "1.5.0"
checks_version string Check algorithm version, e.g. "10"
tool_name string Canonical SDK identity, "sanna-ts" (v1.4+, required at cv>=9)
receipt_id string UUID v4 unique identifier
correlation_id string Path-prefixed identifier for grouping related receipts

Integrity

Field Type Description
receipt_fingerprint string 16-hex SHA-256 truncation for compact display
full_fingerprint string 64-hex SHA-256 of all fingerprinted fields
context_hash string 64-hex SHA-256 of canonical inputs
output_hash string 64-hex SHA-256 of canonical outputs

Content

Field Type Description
timestamp string ISO 8601 timestamp
inputs object Dictionary of function arguments passed to the wrapped function (e.g., query, context)
outputs object Contains response

Governance

Field Type Description
checks array List of CheckResult objects with check_id, passed, severity, evidence
checks_passed integer Count of checks that passed
checks_failed integer Count of checks that failed
status string "PASS" / "WARN" / "FAIL" / "PARTIAL"
constitution_ref object Contains document_id, policy_hash, version, source, signature_verified, constitution_approval
enforcement object or null Contains action, reason, failed_checks, enforcement_mode, timestamp when enforcement triggered
evaluation_coverage object Contains total_invariants, evaluated, not_checked, coverage_basis_points

Receipt Triad (Gateway)

Field Type Description
input_hash string 64-hex SHA-256, present in gateway receipts
reasoning_hash string 64-hex SHA-256 of reasoning content
action_hash string 64-hex SHA-256 of action content
assurance string "full" or "partial"

Identity and Signature

Field Type Description
receipt_signature object Contains value, key_id, signed_by, signed_at, scheme
identity_verification object or null Verification results for identity claims, when present
agent_identity object or null Agent session identity; must include agent_session_id. Present only in v1.5 (cv=10) receipts. Participates in fingerprint at position 21.

Chaining and Workflow

Field Type Description
parent_receipts string[] or null Fingerprints of causally-linked parent receipts (e.g., escalation → execution)
workflow_id string or null Per-session identifier grouping related receipts
content_mode string or null Active content mode: "full", "redacted", or "hashes_only"
content_mode_source string or null Where content mode was configured (e.g., "gateway.yaml")

Extensions

Field Type Description
extensions object Reverse-domain namespaced metadata (com.sanna.gateway, com.sanna.middleware)

This section provides a high-level overview. For a complete field reference and normative format details, see the Sanna Protocol specification.

Minimal example receipt (abbreviated — production receipts typically contain 3-7 checks):

{
  "spec_version": "1.5",
  "tool_version": "1.5.0",
  "checks_version": "10",
  "tool_name": "sanna-ts",
  "receipt_id": "a1b2c3d4-e5f6-4a7b-8c9d-0e1f2a3b4c5d",
  "receipt_fingerprint": "7b4d06e836514eef",
  "full_fingerprint": "7b4d06e836514eef26ab96f5c62b193d036c92b45d966ef7025d75539ff93aca",
  "correlation_id": "sanna-my-agent-1708128000",
  "timestamp": "2026-02-17T00:00:00.000Z",
  "inputs": {"query": "refund policy", "context": "All sales are final."},
  "outputs": {"response": "Unfortunately, all sales are final per our policy."},
  "context_hash": "...(64 hex)...",
  "output_hash": "...(64 hex)...",
  "checks": [
    {"check_id": "C1", "name": "Context Contradiction", "passed": true, "severity": "info"}
  ],
  "checks_passed": 1,
  "checks_failed": 0,
  "status": "PASS",
  "constitution_ref": {"document_id": "support-agent/1.0", "policy_hash": "...", "signature_verified": true},
  "enforcement": null,
  "enforcement_surface": "middleware",
  "invariants_scope": "full",
  "parent_receipts": null,
  "workflow_id": null,
  "content_mode": null,
  "content_mode_source": null,
  "agent_identity": {"agent_session_id": "session-a1b2c3d4e5f6"}
}

Constitution Format

Constitutions are YAML documents that define an agent's governance boundaries. They are version-controlled, cryptographically signed (and optionally approved) before enforcement.

sanna_constitution: "1.1"

identity:
  agent_name: support-agent
  domain: customer-support
  description: Handles refund and billing inquiries

provenance:
  authored_by: governance-team
  approved_by: vp-risk
  approval_date: "2026-01-15"

boundaries:
  - id: B1
    description: Only answer questions about products in the catalog
    category: scope
    severity: critical
  - id: B2
    description: Never promise refunds outside the 30-day window
    category: policy
    severity: critical

invariants:
  - id: INV_NO_FABRICATION
    rule: Never state facts not grounded in provided context
    enforcement: critical
  - id: INV_MARK_INFERENCE
    rule: Clearly mark any inference or assumption
    enforcement: warning
  - id: INV_NO_FALSE_CERTAINTY
    rule: Do not express certainty beyond what evidence supports
    enforcement: warning
  - id: INV_PRESERVE_TENSION
    rule: When context contains conflicting rules, surface both
    enforcement: warning
  - id: INV_NO_PREMATURE_COMPRESSION
    rule: Do not over-summarize multi-faceted context
    enforcement: warning

authority_boundaries:
  can_execute:
    - Look up order status
    - Search knowledge base
  must_escalate:
    - Issue refund over $500
    - Override account restrictions
  cannot_execute:
    - Delete customer accounts
    - Access payment credentials

escalation_targets:
  - condition: "refund over limit"
    target:
      type: webhook
      url: https://ops.example.com/escalate

reasoning:
  require_justification: true
  assurance_level: full

Custom Invariant Checks

Invariants defined in your constitution YAML are automatically detected and enforced. Sanna maps rule text to built-in check types:

Type Detected when rule contains Example
pii_detection "PII" No PII in output
max_length "maximum" + number + "characters" Maximum 500 characters per response
regex_match "must match" + /pattern/ Output must match /^\d{4}-\d{2}$/
regex_deny "must not match" + /pattern/ Must not match /password:\s*.+/
required_keywords "must contain" + quoted words Output must contain 'disclaimer', 'terms'
import { loadConstitution, runAllInvariantChecks } from "@sanna-ai/core";

const constitution = loadConstitution("constitution.yaml");
const output = "Here is the response from the agent.";

const results = runAllInvariantChecks(constitution, output);
for (const result of results) {
  console.log(`${result.check_id}: ${result.passed ? "PASS" : "FAIL"}`);
  if (!result.passed) {
    console.log(`  Evidence: ${result.evidence}`);
  }
}

Invariants with explicit check fields (e.g., check: sanna.context_contradiction) skip type detection and are handled by the coherence check engine. Unrecognized rules return NOT_CHECKED status — they are not silently ignored.

Regex patterns are validated by safe-regex2 before execution. Catastrophic backtracking patterns (e.g., (a+)+) are rejected with UNSAFE_PATTERN status and fail-open.

Receipt Querying

import { ReceiptStore, DriftAnalyzer } from "@sanna-ai/core";

const store = new ReceiptStore(".sanna/receipts.db");

// Query with filters
const receipts = store.query({
  agent_id: "support-agent",
  status: "FAIL",
  limit: 10,
});

// Drift analysis
const analyzer = new DriftAnalyzer(store);
const report = analyzer.analyze(30, { threshold: 0.15 });

store.close();

Or via CLI:

sanna drift-report --db .sanna/receipts.db --window 30 --json

Constitution Templates

sanna init offers four templates:

Template Use Case
Developer Advisory enforcement, starter template for development
Production Strict enforcement, full governance for production agents
Privacy-Focused PII-aware, data handling boundaries
Minimal Bare minimum constitution for custom configuration

Gateway Constitution Templates

Six ready-to-use constitution templates for gateway deployments live in examples/constitutions/. Each includes evaluation order documentation explaining how cannot_execute, must_escalate, and can_execute interact.

Template Agent Use Case
openclaw-developer openclaw-developer Development agent with full workspace access, escalation for dangerous patterns
openclaw-personal openclaw-personal Personal productivity agent with broad file and execution access
openclaw-team openclaw-team Shared team agent with strict governance, file modifications require escalation
cowork-personal knowledge-worker-agent Knowledge workers using Cowork / Claude Desktop with MCP servers
cowork-team team-workspace-agent Small teams sharing governance via Git with per-developer sidecars
claude-code-standard claude-code-agent Developers using Claude Code with MCP connectors

CLI Reference

All commands are available as sanna <command>:

Command Description
sanna init Interactive constitution generator with template selection
sanna keygen Generate Ed25519 keypair (--label for human-readable name)
sanna sign Sign a constitution with Ed25519 (--private-key required)
sanna verify Verify receipt integrity, signature, and provenance chain
sanna verify-constitution Verify constitution signature (--public-key required)
sanna inspect Pretty-print receipt contents (--json for machine output)
sanna diff Unified diff of two constitution YAML files
sanna drift-report Fleet governance drift report (--db, --window, --json)
sanna demo Run self-contained governance demo
sanna check-config Validate gateway config (dry-run)
sanna gateway Start MCP enforcement proxy
sanna migrate Migrate Claude Desktop / Cursor config to gateway format
sanna approve Sign a constitution approval request with an Ed25519 key (--private-key required)
sanna bundle-create Create a self-contained evidence bundle zip from receipt, constitution, and public key
sanna bundle-verify Verify a self-contained evidence bundle (8-step; --trusted-key-ids for trust anchor)
sanna generate Generate a receipt from a trace data JSON file (--signing-key optional)
sanna verify-aarm Verify AARM Core (R1-R6) conformance across a set of receipts (--format, --public-key)

Packages

Package Description
@sanna-ai/core Constitution engine, Ed25519 crypto, receipts, coherence checks, middleware, receipt store, receipt sinks, drift analysis, evidence bundles, approval workflows, identity claims
@sanna-ai/cli Command-line tools (17 commands)
@sanna-ai/mcp-server 10 governance tools over MCP stdio transport
@sanna-ai/gateway MCP enforcement proxy with circuit breakers, escalation, receipt chaining, content mode attestation, PII redaction, config migration

Documentation: TypeScript SDK Reference — full API reference with signatures, the interceptor behavior matrix, and exact thrown types. TypeScript SDK Cookbook — delta recipes (interceptors, custom evaluators, drift, bundles, Cloud delivery).

API Reference

The @sanna-ai/core package exports the primary API:

import {
  // Governance wrapper
  sannaObserve,
  withSannaGovernance,
  SannaHaltError,

  // Receipts
  generateReceipt,
  signReceipt,
  verifyReceipt,
  computeFingerprints,

  // Constitutions
  loadConstitution,
  parseConstitution,
  signConstitution,
  saveConstitution,
  verifyConstitutionSignature,

  // Authority
  evaluateAuthority,

  // Checks
  runCoherenceChecks,
  loadInvariantChecks,
  runAllInvariantChecks,

  // Cryptography
  generateKeypair,
  sign,
  verify,
  loadPrivateKey,
  loadPublicKey,

  // Storage and analytics
  ReceiptStore,
  DriftAnalyzer,

  // Receipt sinks
  NullSink,
  LocalSQLiteSink,
  CloudHTTPSink,
  CompositeSink,

  // Bundles
  createBundle,
  verifyBundle,

  // Approval workflows
  createApprovalRequest,
  signApproval,
  verifyApproval,
  ApprovalStore,

  // Identity
  createIdentityClaim,
  verifyIdentityClaim,
  IdentityRegistry,

  // Safe I/O
  safeWriteFile,
  safeWriteJson,
  safeReadFile,
  validatePath,
} from "@sanna-ai/core";

Type imports for advanced usage:

import type {
  Constitution,
  Receipt,
  CheckResult,
  AuthorityDecision,
  SannaResult,
  SannaObserveOptions,
  ReceiptQueryFilters,
  DriftReport,
  EnforcementMode,
  InvariantDefinition,
  ReceiptSink,
  SinkResult,
  ContentMode,
  FailurePolicy,
  CloudHTTPSinkOptions,
} from "@sanna-ai/core";

Verification

Verification proves four properties:

  • Schema validation: Receipt structure matches the expected format.
  • Hash verification: Content hashes match the actual inputs and outputs (tamper detection).
  • Signature verification: Receipt was signed by a known key (authenticity).
  • Chain verification: Constitution was signed, and any approvals are cryptographically bound.
# Verify receipt integrity
sanna verify receipt.json

# Verify with signature check
sanna verify receipt.json --public-key <key-id>.pub

# Verify constitution signature
sanna verify-constitution constitution.yaml --public-key <key-id>.pub

Programmatic verification:

import { verifyReceipt, loadPublicKey } from "@sanna-ai/core";
import { readFileSync } from "node:fs";

const receipt = JSON.parse(readFileSync("receipt.json", "utf-8"));
const publicKey = loadPublicKey("~/.sanna/keys/<key-id>.pub");

const result = verifyReceipt(receipt, publicKey);
console.log(result.valid);            // true or false
console.log(result.checks_performed); // list of verification steps

Evidence bundles package a receipt, its constitution, and public keys into a self-contained zip for auditors:

import { createBundle, verifyBundle } from "@sanna-ai/core";

// Create bundle
await createBundle({
  receiptPath: "receipt.json",
  constitutionPath: "constitution.yaml",
  publicKeyPath: "~/.sanna/keys/<key-id>.pub",
  outputPath: "evidence.zip",
});

// Verify bundle (7-step verification)
const result = verifyBundle("evidence.zip");
console.log(result.passed);  // true if all 7 checks pass

No network. No API keys. No vendor dependency.

Enterprise Features

  • DMARC-style adoption: Start with permissive enforcement (observe), move to advisory (warn), then enforced (halt).
  • Ed25519 cryptographic signatures: Constitutions, receipts, and approval records are independently signed and verifiable.
  • Offline verification: No platform dependency. Verify receipts with a public key and the CLI.
  • Evidence bundles: Self-contained zip archives with receipt, constitution, and public keys for auditors.
  • Drift analytics: Per-agent failure-rate trending with linear regression and breach projection.
  • Receipt Triad: Cryptographic binding of input, reasoning, and action for auditability.
  • Receipt queries: SQLite-backed receipt persistence with filtered queries via ReceiptStore.
  • Key management: SHA-256 key fingerprints, labeled keypairs, PKCS#8/SPKI PEM format.
  • Multi-party approval: Quorum-based constitution approval workflows with expiration and cryptographic binding.
  • MCP governance tools: 10 governance tools available via MCP stdio for integration with Claude Desktop, Claude Code, and Cursor.
  • Receipt sinks: Pluggable receipt delivery — CloudHTTPSink (HTTPS with retry/batch/buffer), CompositeSink (fan-out), LocalSQLiteSink, NullSink.
  • Receipt chaining: Causal linking via parent_receipts (e.g., escalation → execution) with per-session workflow_id correlation.
  • Content mode attestation: Gateway records active content mode and its configuration source in receipt metadata.

Security

  • Ed25519 cryptographic signatures: Constitutions, receipts, and approval records are independently signed and verifiable offline.
  • Atomic file writes: All file operations use symlink-protected atomic writes (temp file + fsync + rename).
  • SQLite hardening: Receipt stores validate file ownership, enforce 0o600 permissions, and reject symlinks.
  • Safe regex execution: User-supplied regex patterns are validated by safe-regex2 before execution. Catastrophic backtracking patterns are rejected.
  • PII redaction: Credit card detection uses a two-pass approach (strip separators, match digit runs) to avoid ReDoS. Object redaction enforces a recursion depth limit (default 20) to prevent stack overflow.
  • Escalation token hashing: Only SHA-256 hashes of HMAC tokens are stored at rest. Raw tokens are returned to the caller but never persisted.
  • Config secret isolation: Gateway config supports $ENV{VAR_NAME} interpolation for HMAC secrets and key paths. File permission warnings on group/world-readable config files.
  • Path validation: File I/O validates against symlink attacks, path traversal, and excessively large files.
  • CloudHTTPSink hardening: Non-retryable status codes (400/401/403) fail immediately. 429 respects Retry-After. Buffer-and-retry via JSONL with background flush interval.

Cryptographic Design

  • Signing: Ed25519 over canonical JSON (RFC 8785-style deterministic serialization)
  • Hashing: SHA-256 for all content hashes, fingerprints, and key IDs
  • Canonicalization: Sorted keys, NFC Unicode normalization, integer-only numerics (no floats in signed content)
  • Fingerprinting: 14 pipe-delimited fields hashed with SHA-256; 16-hex truncation for display, 64-hex for full fingerprint

See the Sanna Protocol specification for full cryptographic construction details.

Threat Model

Defends against:

  • Tampering with stored receipts (detected via fingerprint and signature verification)
  • Unverifiable governance claims (receipts are cryptographically signed attestations)
  • Substitution of receipts across contexts (receipts are cryptographically bound to specific inputs, outputs, and correlation IDs; verifiers should enforce timestamp and correlation expectations)
  • Unauthorized tool execution (constitution enforcement blocks or escalates disallowed actions)

Does not defend against:

  • Compromised runtime environment (if the host is compromised, all bets are off)
  • Stolen signing keys (key compromise requires re-keying and re-signing)
  • Bypassing Sanna entirely (governance only applies to functions wrapped with sannaObserve or tool calls routed through the gateway)
  • Malicious constitutions (Sanna enforces the constitution as written; it does not validate whether the constitution itself is correct or sufficient)

Limitations

Receipts are attestations of process, not guarantees of outcome.

  • Receipts do not prove internal reasoning was truthful — they prove that checks were run against the output
  • Receipts do not prove upstream input was complete or accurate
  • Receipts do not protect against a compromised host or stolen signing keys
  • Receipts do not prove the constitution itself was correct or sufficient for the use case
  • Heuristic checks (C1-C5) are deterministic but not exhaustive — they catch common failure modes, not all possible failures

Cross-Language Compatibility

Receipts generated by the TypeScript SDK verify in the Python SDK, and vice versa. Key pairs are interchangeable — both SDKs use PKCS#8 (private) and SPKI (public) PEM encoding for Ed25519 keys.

Cross-language parity is verified against golden fixtures in the sanna-protocol repository. The test suite includes cross-language verification tests covering receipt fingerprinting, content hashing, canonicalization, and signature verification. v1.5 Python fixtures (21-field fingerprint, checks_version "10") are verified end-to-end including tool_name, agent_model, enforcement_surface, invariants_scope, and agent_identity; v1.5 TypeScript receipts use the same 21-field fingerprint formula.

// Keys generated by the Python SDK work in TypeScript
import { loadPublicKey, verifyReceipt } from "@sanna-ai/core";

const pythonKey = loadPublicKey("python-generated-key.pub");
const pythonReceipt = JSON.parse(readFileSync("python-receipt.json", "utf-8"));
const result = verifyReceipt(pythonReceipt, pythonKey);
// result.valid === true

Install

npm install @sanna-ai/core           # Core library
npm install @sanna-ai/cli            # CLI tools (includes core)
npm install @sanna-ai/mcp-server     # MCP governance server
npm install @sanna-ai/gateway        # MCP enforcement proxy

Requires Node.js 22+ for native Ed25519 support (zero external crypto dependencies).

Development

git clone https://github.com/sanna-ai/sanna-ts.git
cd sanna-ts
git submodule update --init        # Pull sanna-protocol spec fixtures
npm install                        # Workspaces auto-linked
npm run build                      # Build all 4 packages
npm test                           # 926 tests across 48 test files

The spec/ git submodule points to sanna-ai/sanna-protocol and provides golden fixtures, JSON schemas, and the protocol specification used by the cross-language test suite.

License

AGPL-3.0. The protocol specification is licensed under Apache 2.0.

Releases

Packages

Contributors

Languages