npm package: @one137th/mesh
Description: RDF semantic graph layer for Meshpocalypse — SPARQL routing, JSON-LD/CRDT bridge, W3C PROV-O provenance, and AI framework adapters
Latest version: 1.4.1

# @one137th/mesh — Meshpocalypse

> **Secure agent coordination infrastructure for multi-agent AI teams — works with LangGraph, CrewAI, AutoGen, OpenClaw, or any HTTP client.**

> *For engineers:* Semantic mesh layer built on NATS + Oxigraph — TLS + Ed25519 signed envelopes, SPARQL routing, JSON-LD/CRDT bridge, W3C PROV-O provenance, and AI framework adapters. 📖 [Plain English Wiki](https://github.com/one137th/Meshpocalypse/wiki)

[![CI](https://github.com/one137th/Meshpocalypse/actions/workflows/ci.yml/badge.svg)](https://github.com/one137th/Meshpocalypse/actions/workflows/ci.yml)
[![npm version](https://img.shields.io/npm/v/@one137th/mesh)](https://www.npmjs.com/package/@one137th/mesh)
[![License: MIT](https://img.shields.io/badge/License-MIT-green.svg)](LICENSE)

---

> 🎉 **v1.4.0 Released — 2026-03-12** · [Changelog](CHANGELOG.md) · [Roadmap](ROADMAP.md)
>
> **v1.4.0** ships a complete security architecture (TLS, Ed25519 signed envelopes, CRDT signing, CF JWT validation, subject injection protection), hierarchical capability taxonomy, auction provenance tracing, confidence signal bus, and a Grafana token budget dashboard.
>
> The core semantic layer is **stable**. The following areas remain pre-production:
>
> - The OpenClaw extension hook API (`onBootstrap`, `onAfterTurn`) depends on OpenClaw's public lifecycle API being finalised
> - The Cloudflare Durable Object cloud tier requires additional implementation work (see [ROADMAP Phase 4](ROADMAP.md))
> - The LoRa/Meshtastic offline transport is architecture-ready but **not yet validated on physical hardware** (see [ROADMAP Phase 4](ROADMAP.md))

---

## Project Status

| Component | Status |
|---|---|
| NATS transport + Oxigraph SPARQL graph | ✅ **Production-ready** |
| Security layer (TLS, Ed25519, CRDT signing, CF JWT) | ✅ **Production-ready** (v1.4.0) |
| HTTP/REST Gateway, SwarmNode API | ✅ **Production-ready** (v1.3.0) |
| LangGraph / CrewAI / AutoGen adapters | ✅ Stable |
| Cloudflare Durable Objects cloud tier | 🔧 Architecture designed; additional implementation work required |
| LoRa/Meshtastic offline transport | 🔬 Architecture-ready; **not yet validated on physical Meshtastic hardware** |
| Federated SPARQL (cross-cluster) | 📋 Phase 4 roadmap item |

---

## What is Meshpocalypse?

When your AI agents need to coordinate, they typically do it through the LLM — which is slow (2–10 seconds), burns tokens, and drops around 5% of messages. There's no shared memory, no audit trail, and no way to enforce trust between agents.

**Meshpocalypse fixes this.** Drop it into any agent framework — LangGraph, CrewAI, AutoGen, or plain HTTP — and your agents get a shared knowledge graph, sub-100ms direct messaging, deterministic routing, and a tamper-proof audit trail.

| Capability | Before (LLM round-trip) | After (Meshpocalypse) |
|---|---|---|
| Agent-to-agent messaging | 2–10s, 1K–3K tokens | Direct via NATS (sub-100ms over direct NATS; [see benchmarks/](benchmarks/)) |
| Shared knowledge | Each agent isolated | Live SPARQL graph shared across all agents |
| Finding the right agent | LLM guesses | Deterministic SPARQL query in milliseconds |
| Trust enforcement | None | 5-level ATF framework with SHACL validation |
| Message delivery guarantee | ~95% | >99.9% with ACK + retry + circuit breaker |
| Audit trail | None | W3C PROV-O tamper-evident chain |
| Transport security | Plaintext | TLS + Ed25519 signed envelopes |

> **Not an engineer?** Jump straight to [LAUNCH.md](./LAUNCH.md) — it walks you through setup with no coding required.

> 📖 **Why Meshpocalypse?** See [docs/WHY-MESHPOCALYPSE.md](./docs/WHY-MESHPOCALYPSE.md) for the full comparison against LangGraph, AutoGen, and CrewAI.

---

## Meshpocalypse vs Alternatives

Meshpocalypse is **infrastructure, not a framework**. It sits underneath your orchestration layer — not instead of it.

| | Meshpocalypse | LangGraph | AutoGen | CrewAI |
|---|---|---|---|---|
| **What it is** | Agent coordination bus | Workflow engine | LLM chat coordination | Agent framework |
| **Routing mechanism** | NATS + SPARQL (deterministic) | LLM calls | LLM chat rounds | LLM calls |
| **Agent-to-agent latency** | Sub-100ms (NATS direct) | 2–10s per hop | 2–10s per hop | 2–10s per hop |
| **Shared state** | CRDT + SPARQL graph | Checkpointing | None built-in | None built-in |
| **Audit trail** | W3C PROV-O tamper-evident | None | None | None |
| **Transport security** | TLS + Ed25519 signed envelopes | None built-in | None built-in | None built-in |
| **Framework lock-in** | None — adapts to any framework | LangGraph only | AutoGen only | CrewAI only |
| **Use together?** | ✅ Yes — mesh sits underneath | ✅ Use LangGraph on top | ✅ Use AutoGen on top | ✅ Use CrewAI on top |

**vs LangGraph:** LangGraph is a workflow engine for defining agent graphs. Meshpocalypse is the communication bus those agents use to talk to each other — you can run LangGraph agents on top of Meshpocalypse.

**vs AutoGen:** AutoGen coordinates agents via LLM chat rounds. Meshpocalypse routes via NATS subjects and SPARQL queries — deterministic, auditable, and orders of magnitude faster for routing decisions.

**vs CrewAI:** CrewAI is a framework for defining agent roles and tasks. Meshpocalypse is the infrastructure layer underneath — any CrewAI team can use it for secure, auditable inter-agent messaging.

> 💡 The pattern IBM describes for hierarchical multi-agent systems requires exactly the infrastructure Meshpocalypse provides — and doesn't specify how to build it. See [docs/WHY-MESHPOCALYPSE.md](./docs/WHY-MESHPOCALYPSE.md).

---

## Quick Start

```bash
# Clone and start the full stack (Docker required)
git clone https://github.com/one137th/Meshpocalypse.git
cd Meshpocalypse
docker compose up -d
```

This starts Oxigraph (SPARQL knowledge graph) + NATS (message broker), loads the ontology, and makes Grafana available at http://localhost:3000.

| Platform | Time | Cost | How |
|---|---|---|---|
| **Local (Docker)** | ~2 min | Free | `./scripts/start-local.sh` |
| **Windows (Docker)** | ~2 min | Free | `scripts\start-local.bat` |
| **Railway** | ~5 min | Free tier | [LAUNCH.md → Railway](./LAUNCH.md#2-railway-deploy-free-tier) |
| **Fly.io (production)** | ~15 min | Pay-as-you-go | [LAUNCH.md → Fly.io](./LAUNCH.md#3-flyio-production-deployment) |

---

## Connect your framework

Four lines of TypeScript. Works with any framework that can call Node.js or HTTP:

```typescript
import { SwarmNode } from '@one137th/mesh';

const node = new SwarmNode({ agentId: 'my-agent', capabilities: ['summarise', 'search'] });
await node.connect();
await node.publish('task.result', { result: 'done' });
const peers = await node.discoverCapability('search');
await node.disconnect();
```

**Python SDK:**

```python
from meshpocalypse import SwarmNode, SwarmNodeConfig

config = SwarmNodeConfig(agent_id="my-agent", capabilities=["summarise", "search"])
async with SwarmNode(config) as node:
    await node.publish("task.result", {"result": "done"})
    peers = await node.discover_capability("search")
```

### Framework-specific guides

| Framework | Guide | Adapter import |
|---|---|---|
| **LangGraph** | [docs/getting-started/langgraph.md](./docs/getting-started/langgraph.md) | `@one137th/mesh/adapters/langgraph` |
| **CrewAI** | [docs/getting-started/crewai.md](./docs/getting-started/crewai.md) | `@one137th/mesh/adapters/crewai` |
| **AutoGen** | [docs/getting-started/autogen.md](./docs/getting-started/autogen.md) | `@one137th/mesh/adapters/autogen` |
| **HTTP/REST** | [docs/getting-started/http-rest.md](./docs/getting-started/http-rest.md) | Any HTTP client |
| **OpenClaw** | [docs/OPENCLAW-GUIDE.md](./docs/OPENCLAW-GUIDE.md) | `@one137th/mesh` (first-class) |

---

## How it works

Three components work together:

**NATS** — the real-time message broker. Every agent message flows through here. It guarantees delivery, retries on failure, and routes to the right agent without involving the LLM.

**Oxigraph** — the shared knowledge graph. Stores facts about your agents as connected data (RDF triples): their capabilities, current status, trust level, and action history. Agents query this with SPARQL to make routing decisions in milliseconds instead of burning a full LLM call.

**The Semantic Layer (this package)** — sits on top of NATS and Oxigraph and adds a security layer, SPARQL routing, a shared CRDT team task board, a tamper-proof W3C PROV-O audit trail, a 5-level trust framework, and MCP tool exposure for AI frameworks.

```
+-----------------------------------------------------------+
|                      AGENT LAYER                          |
|   LangGraph · CrewAI · AutoGen · OpenClaw · HTTP clients  |
+-----------------------------------------------------------+
                    |                    |
         +------------------+  +------------------+
         |  BROKER LAYER    |  |   CLOUD LAYER    |
         |  NATS real-time  |  | CF Durable Objs  |
         |  pub/sub routing |  |  Workers + KV    |
         +------------------+  +------------------+
                    |                    |
+-----------------------------------------------------------+
|                  TRANSPORT ABSTRACTION                     |
|    Protobuf wire format, agent discovery, channel routing  |
+-----------------------------------------------------------+
```

The semantic layer adds:

```
+-----------------------------------------------------------+
|              AI FRAMEWORK LAYER                           |
|    LangGraph · CrewAI · AutoGen · Solid/LDP               |
+-----------------------------------------------------------+
                           |
+-----------------------------------------------------------+
|             SEMANTIC LAYER  (this package)                |
|  SemanticModule · MeshGraph · SPARQL Optimizer            |
|  JSON-LD Bridge · PROV-O Provenance · ATF Trust · MCP     |
+-----------------------------------------------------------+
                           |
+-----------------------------------------------------------+
|           SECURITY LAYER  (v1.4.0)                        |
|  TLS (NATS_TLS_MODE) · Subject Validation                 |
|  From-Field Verification · Ed25519 Envelope Signing       |
|  CRDT Signing · CF JWT Validation                         |
+-----------------------------------------------------------+
                           |
+-----------------------------------------------------------+
|        CORE MESH  (@one137th/mesh-network)                |
|   MeshNode · NATS Transport · Routing · Circuit Breaker   |
+-----------------------------------------------------------+
```

**Normal operation:** Agent → NATS Broker → Agent (sub-100ms over direct NATS; [see benchmarks/](benchmarks/))
**Broker unavailable:** Agent → Cloudflare Durable Object (buffer + recovery) ⚠️ *additional implementation work required*

---

## Install

```bash
npm install @one137th/mesh
```

> Python SDK (`meshpocalypse`) and Semantic Kernel adapter are available. See [docs/integrations/python.md](docs/integrations/python.md) and [docs/integrations/semantic-kernel.md](docs/integrations/semantic-kernel.md).

Node.js ≥ 20 required.

---

## Advanced Usage — Raw MeshNode

Need full control? Drop down to `MeshNode` directly.

```typescript
import { SemanticModule } from '@one137th/mesh';
import { MeshNode } from '@one137th/mesh/mesh';

const node = new MeshNode({ agentId: 'my-agent' });
const semantic = new SemanticModule({ oxigraphUrl: 'http://localhost:7878' });

await node.use(semantic);
await node.start();
```

---

## Security Architecture (v1.4.0)

Meshpocalypse v1.4.0 ships a layered security model addressing OWASP ASI07 (Insecure Inter-Agent Communication). Every message passes through five independent defences:

```
1. TLS (NATS_TLS_MODE)              — encrypt the wire
2. Subject validation               — prevent NATS injection attacks
3. From-field verification          — bind sender claims to transport identity
4. Ed25519 envelope signing         — application-level non-repudiation
5. CRDT signing (MESH_CRDT_SIGNING) — tamper-evident shared state
   + CF JWT validation              — edge authentication via Cloudflare Access
```

**Quick security config:**

```bash
# Transport encryption (CVSS 9.8 if disabled in production)
NATS_TLS_MODE=STRICT
NATS_TLS_CERT=<PEM>
NATS_TLS_KEY=<PEM>
NATS_TLS_CA=<PEM>

# Application-level signing
MESH_SIGNATURE_ENFORCEMENT=strict   # reject unsigned envelopes
MESH_CRDT_SIGNING=true              # sign all CRDT state updates

# Cloudflare Access JWT validation
CF_ACCESS_TEAM_NAME=your-team
CF_ACCESS_AUD=your-audience-tag

# Provenance tracing
PROVENANCE_ENABLED=true
```

See [docs/SECURITY.md](./docs/SECURITY.md) for the full reference including key generation, enforcement modes, and migration path from plaintext.

---

## Feature Flags

All features are **off by default**. Enable only what you need in your `.env` file:

| Flag | What it enables | Start here? |
|---|---|---|
| `GRAPH_CRDT_ENABLED=true` | Shared RDF graph + Yjs CRDT team state | ✅ Yes |
| `SPARQL_ROUTING_ENABLED=true` | SPARQL-based agent routing | ✅ Yes |
| `NATS_TLS_MODE=STRICT` | TLS encryption for all NATS traffic | ✅ **Production required** |
| `MESH_SIGNATURE_ENFORCEMENT=strict` | Reject envelopes without Ed25519 signatures | ✅ **Production required** |
| `MESH_CRDT_SIGNING=true` | Sign all CRDT state updates | ✅ **Production required** |
| `PROVENANCE_ENABLED=true` | W3C PROV-O tamper-evident audit trail | Optional |
| `TRUST_LEVELS_ENABLED=true` | 5-level ATF trust + SHACL validation | Optional |
| `CF_ACCESS_TEAM_NAME=<team>` | Cloudflare JWT validation at the edge | Optional |
| `FEDERATION_ENABLED=true` | Cross-mesh SPARQL federation | Advanced |
| `MCP_SEMANTIC_ENABLED=true` | MCP server for AI framework integration | Advanced |
| `OBSERVABILITY_ENABLED=true` | Prometheus metrics export | Production |

---

## Exports

| Import path | What you get |
|---|---|
| `@one137th/mesh` | Everything — core mesh + full semantic layer (includes `SwarmNode`) |
| `@one137th/mesh/mesh` | Core `MeshNode` (advanced use) |
| `@one137th/mesh/modules` | Module registry |
| `@one137th/mesh/graph` | `MeshGraph` — RDF graph interface |
| `@one137th/mesh/bridge` | `EventSourcedBridge` — Yjs CRDTs ↔ RDF |
| `@one137th/mesh/sparql` | SPARQL optimizer + template engine |
| `@one137th/mesh/sparql/federation` | Cross-mesh SPARQL federation |
| `@one137th/mesh/semantic` | JSON-LD encoding/decoding |
| `@one137th/mesh/provenance` | W3C PROV-O hash-chained audit trail |
| `@one137th/mesh/trust` | ATF 5-level trust framework + SHACL |
| `@one137th/mesh/ontology` | Transparent reasoning via SPARQL-backed MCP |
| `@one137th/mesh/adapters/langgraph` | LangGraph adapter |
| `@one137th/mesh/adapters/crewai` | CrewAI adapter |
| `@one137th/mesh/adapters/autogen` | AutoGen adapter |
| `@one137th/mesh/adapters/solid-ldp` | Solid/LDP adapter |

---

## Documentation

| Document | For who | What's in it |
|---|---|---|
| [LAUNCH.md](./LAUNCH.md) | Everyone — start here | Full setup guide, all platforms |
| [docs/WHY-MESHPOCALYPSE.md](./docs/WHY-MESHPOCALYPSE.md) | Decision makers | Why Meshpocalypse vs LangGraph/AutoGen/CrewAI |
| [docs/DEPLOYMENT-PROFILES.md](./docs/DEPLOYMENT-PROFILES.md) | Engineers | Broker-first, Federated SPARQL, and Offline-First profiles |
| [ROADMAP.md](./ROADMAP.md) | Everyone | v1.4.0+ feature roadmap by phase |
| **Framework Guides** | | |
| [docs/getting-started/langgraph.md](./docs/getting-started/langgraph.md) | LangGraph users | Minimal LangGraph integration |
| [docs/getting-started/crewai.md](./docs/getting-started/crewai.md) | CrewAI users | Minimal CrewAI integration |
| [docs/getting-started/autogen.md](./docs/getting-started/autogen.md) | AutoGen users | Minimal AutoGen integration |
| [docs/getting-started/http-rest.md](./docs/getting-started/http-rest.md) | Any framework | HTTP/REST standalone integration |
| [docs/OPENCLAW-GUIDE.md](./docs/OPENCLAW-GUIDE.md) | OpenClaw users | Step-by-step wiring guide (first-class) |
| **Reference** | | |
| [docs/ARCHITECTURE.md](./docs/ARCHITECTURE.md) | Engineers | System design and component detail |
| [docs/SECURITY.md](./docs/SECURITY.md) | Engineers | Security model, TLS, Ed25519, CF JWT |
| [docs/API-REFERENCE.md](./docs/API-REFERENCE.md) | Engineers | Full API reference |
| [docs/CONFIGURATION-GUIDE.md](./docs/CONFIGURATION-GUIDE.md) | Engineers | All config options |
| [docs/EXAMPLES.md](./docs/EXAMPLES.md) | Engineers | 10 working code examples |
| [docs/JOB-PROTOCOL.md](./docs/JOB-PROTOCOL.md) | Engineers | Job Protocol spec — NATS subjects, envelope schema, SwarmRuntime API |
| [docs/TROUBLESHOOTING.md](./docs/TROUBLESHOOTING.md) | Everyone | Common issues and fixes |
| [docs/CLOUDFLARE-INTEGRATION.md](./docs/CLOUDFLARE-INTEGRATION.md) | Engineers | Cloudflare setup and cost analysis |
| [docs/integrations/http-gateway.md](./docs/integrations/http-gateway.md) | Engineers | HTTP/REST Gateway setup and routes |
| [docs/integrations/budget-delegation.md](./docs/integrations/budget-delegation.md) | Engineers | Hierarchical budget delegation guide |
| [CONTRIBUTING.md](./CONTRIBUTING.md) | Contributors | How to contribute |
| [CHANGELOG.md](./CHANGELOG.md) | Everyone | Release history |

---

## OpenClaw Integration

OpenClaw is one of many first-class integrations, with dedicated lifecycle hooks (`onBootstrap`, `onAfterTurn`) and deep MCP support. Meshpocalypse is framework-agnostic — OpenClaw is just one adapter. If you're running OpenClaw agents, start with the [OpenClaw Guide](./docs/OPENCLAW-GUIDE.md).

> The OpenClaw hook API depends on OpenClaw's public lifecycle API being finalised — see [ROADMAP.md](./ROADMAP.md) for status.

---

## Observability

### Metrics (Prometheus + Grafana)

See the [Quick Start](#quick-start) for the full stack including Prometheus and Grafana. v1.4.0 ships a pre-configured **token budget dashboard** in `deploy/grafana/` — visible at http://localhost:3000 out of the box with `docker compose up`.

### Distributed Traces (OpenTelemetry)

Every NATS publish, NATS receive, and SPARQL/Oxigraph update is instrumented with OpenTelemetry spans.
Traces are no-ops unless you opt in:

```typescript
import { initTelemetry } from '@one137th/mesh/telemetry';

initTelemetry({
  serviceName: 'my-mesh-agent',
  otlpEndpoint: 'http://localhost:4318',  // optional — default
});
```

Start Grafana Tempo (included in `docker-compose.yml`):

```bash
docker compose up -d otel-collector tempo
```

Then open Grafana → **Explore** → **Tempo** to search traces.

→ [Full OpenTelemetry integration guide](docs/integrations/opentelemetry.md)

---

## Examples

### Two-Agent Demo

A self-contained, runnable demo showing two agents communicating via the semantic mesh layer:

```
examples/two-agent-demo/
```

→ [Read the demo README](examples/two-agent-demo/README.md)

Features demonstrated:
- Agent-to-agent messaging over NATS
- Direct message routing by agent ID
- Graceful startup and shutdown

---

## Development

```bash
npm ci
npm run type-check
npm test
npm run test:coverage
```

| Script | What |
|---|---|
| `./scripts/start-local.sh` | Start full local stack (Oxigraph + NATS + ontology load) |
| `npm run dev:semantic:up` | Start Oxigraph + NATS via Docker Compose (manual) |
| `npm run ontology:load` | Load core ontology into Oxigraph |
| `npm run ontology:validate` | Validate Turtle syntax (requires Docker) |
| `npm run test:graph-crdt` | CRDT bridge tests |
| `npm run test:sparql-routing` | SPARQL routing tests |
| `npm run test:shacl` | SHACL validation tests |
| `npm run test:provenance` | Provenance chain tests |
| `npm run test:security` | Security regression suite (TLS, signing, injection, replay) |
| `npm run benchmark:routing` | Routing latency benchmark |

---

## Ontology

Core ontology: [`ontology/meshpocalypse-core-ontology.ttl`](./ontology/meshpocalypse-core-ontology.ttl)
SHACL shapes: [`ontology/shacl-shapes.ttl`](./ontology/shacl-shapes.ttl)
JSON-LD context: [`ontology/json-ld-context.jsonld`](./ontology/json-ld-context.jsonld)

---

## License

MIT © [one137th](https://github.com/one137th)

---

## Key Persistence

By default, the JWT `IdentityProvider` generates ES256 signing keys in memory on startup. Keys are lost on restart, invalidating all active tokens.

To survive restarts, inject a `JsonFileKeyPersistenceAdapter`:

```typescript
import {
  IdentityProvider,
  JsonFileKeyPersistenceAdapter,
} from '@one137th/mesh';

const adapter = new JsonFileKeyPersistenceAdapter({
  filePath: '/data/jwt-keys.json',
});

const provider = new IdentityProvider({
  keyPersistenceAdapter: adapter,
});

await provider.initialize(); // loads persisted keys if available

// Expose JWKS endpoint
app.get('/.well-known/jwks.json', (_req, res) => {
  res.json(provider.getJwks());
});
```

Keys are stored as JWK JSON, written atomically (via a `.tmp` rename) to prevent corruption. The file contains the active signing key and, after the first rotation, the previous key (for grace-period validation).

To implement a custom persistence backend (Redis, KV, etc.), implement the `KeyPersistenceAdapter` interface exported from the package.

### Redis/Valkey Key Adapter (multi-node)

For multi-node deployments where all nodes must share JWT signing keys:

```typescript
import { createClient } from 'redis';
import { IdentityProvider, RedisKeyPersistenceAdapter } from '@one137th/mesh';

const client = createClient({ url: process.env.REDIS_URL ?? 'redis://localhost:6379' });
await client.connect();

const adapter = new RedisKeyPersistenceAdapter({
  client,
  ttlSeconds: 604_800, // optional — 7 days
});
const provider = new IdentityProvider({ keyPersistenceAdapter: adapter });
```

> **Peer dependency:** `npm install redis`

---

## ATF Persistence

`ATFTrustSystem` tracks per-agent trust levels in memory by default. Every restart wipes the complete trust graph. To persist state across restarts, use `JsonFilePersistenceAdapter`:

```typescript
import { ATFTrustSystem } from '@one137th/mesh';
import { JsonFilePersistenceAdapter } from '@one137th/mesh';

const adapter = new JsonFilePersistenceAdapter({
  filePath: '/data/atf-state.json',
});

const atf = new ATFTrustSystem(undefined, undefined, adapter);

// On startup — load persisted trust state
await atf.hydrate();

// After mutations — persist updated state
await atf.persist();
```

State is written atomically (`.tmp` rename) to prevent corruption. Implement `ATFPersistenceAdapter` directly for custom backends (Redis, Cloudflare KV, etc.).

### Redis/Valkey Adapter (multi-node)

For production deployments spanning multiple nodes, use `RedisPersistenceAdapter` to share ATF state via Redis or Valkey:

```typescript
import { createClient } from 'redis';
import { ATFTrustSystem, RedisPersistenceAdapter } from '@one137th/mesh';

const client = createClient({ url: process.env.REDIS_URL ?? 'redis://localhost:6379' });
await client.connect();

const adapter = new RedisPersistenceAdapter({
  client,
  ttlSeconds: 86_400, // optional
});
const atf = new ATFTrustSystem(undefined, undefined, adapter);
await atf.hydrate();
```

> **Peer dependency:** `npm install redis` — the `redis` package is not bundled.