-
-
- try interactive demo
-
-
{/* Current Delegate Key */}
@@ -290,7 +316,7 @@ const result = await generateText({
className="btn btn-secondary btn-sm"
onClick={() => copyToClipboard(accountObjectId, 'acct')}
>
- {copied === 'acct' ? 'copied!' : 'copy'}
+
{copied === 'acct' ? 'copied!' : 'copy'}
@@ -307,7 +333,7 @@ const result = await generateText({
className="btn btn-secondary btn-sm"
onClick={() => copyToClipboard(delegatePublicKey!, 'pub')}
>
- {copied === 'pub' ? 'copied!' : 'copy'}
+ {copied === 'pub' ? 'copied!' : 'copy'}
@@ -323,10 +349,10 @@ const result = await generateText({
className="btn btn-secondary btn-sm"
onClick={() => copyToClipboard(delegateKey!, 'priv')}
>
- {copied === 'priv' ? 'copied!' : 'copy'}
+ {copied === 'priv' ? 'copied!' : 'copy'}
>
@@ -337,7 +363,7 @@ const result = await generateText({
>
@@ -360,14 +386,14 @@ const result = await generateText({
onClick={fetchOnChainKeys}
disabled={loadingKeys}
>
- {loadingKeys ? '...' : 'refresh'}
+ {loadingKeys ? '...' : 'refresh'}
@@ -402,7 +428,7 @@ const result = await generateText({
className="btn btn-secondary btn-sm"
onClick={() => copyToClipboard(newPrivateKey, 'new-priv')}
>
- {copied === 'new-priv' ? 'copied!' : 'copy'}
+ {copied === 'new-priv' ? 'copied!' : 'copy'}
@@ -530,14 +556,14 @@ const result = await generateText({
-
- {sdkSnippet}
-
+
+ {sdkSnippet}
+
@@ -552,14 +578,14 @@ const result = await generateText({
-
- {aiSnippet}
-
+
+ {aiSnippet}
+
@@ -568,9 +594,23 @@ const result = await generateText({
-
- npm install @cmdoss/memwal
-
+
+ {(['npm', 'pnpm', 'yarn', 'bun'] as const).map((pm) => (
+
+ ))}
+
+
+ {pkgManager === 'npm' ? 'npm install @mysten/memwal' :
+ pkgManager === 'pnpm' ? 'pnpm add @mysten/memwal' :
+ pkgManager === 'yarn' ? 'yarn add @mysten/memwal' :
+ 'bun add @mysten/memwal'}
+
>
diff --git a/apps/app/src/pages/LandingPage.tsx b/apps/app/src/pages/LandingPage.tsx
index 466e0a82..2b9b6296 100644
--- a/apps/app/src/pages/LandingPage.tsx
+++ b/apps/app/src/pages/LandingPage.tsx
@@ -9,7 +9,10 @@ import {
useWallets,
} from '@mysten/dapp-kit'
import { isEnokiWallet, type EnokiWallet, type AuthProvider } from '@mysten/enoki'
+import { Github } from 'lucide-react'
+import { useNavigate } from 'react-router-dom'
import { config } from '../config'
+import memwalLogo from '../assets/memwal-logo.svg'
export default function LandingPage() {
const currentAccount = useCurrentAccount()
@@ -24,88 +27,91 @@ export default function LandingPage() {
)
const googleWallet = walletsByProvider.get('google')
+ const navigate = useNavigate()
const hasEnokiConfig = config.enokiApiKey && config.googleClientId
- // If somehow already connected, this page shouldn't show
- if (currentAccount) return null
+ const handleConnect = () => {
+ if (currentAccount) {
+ navigate('/dashboard')
+ } else if (hasEnokiConfig && googleWallet) {
+ connect({ wallet: googleWallet })
+ navigate('/dashboard')
+ }
+ }
return (
- <>
-
-
-
-
-
privacy-preserving AI memory
-
- give your AI permanent memory
-
-
- store memories on Walrus, encrypt with SEAL, and recall with semantic search.
- memwal gives agents long-term context while users keep ownership.
-
+
+ {/* ── Nav ── */}
+
-
+ {/* ── Hero ── */}
+
+
+
+
Privacy-Preserving
AI Memory
+
+ Store memories on Walrus, encrypt with SEAL, and recall with
+ semantic search. memwal gives agents long-term context while
+ users keep ownership.
+
-
-
-
-
-
-
- encrypted storage
- SEAL encryption, persisted to Walrus blobs.
-
-
- semantic recall
- embedding search for relevant memories in milliseconds.
-
-
- delegate keys
- low-risk keys for apps, revocable anytime onchain.
-
-
- AI middleware
- wrap models with memory context using one SDK.
-
+
-
-
+
+
+

+

+
-
- >
+
+
)
}
diff --git a/apps/app/src/pages/Playground.tsx b/apps/app/src/pages/Playground.tsx
index 7c217b50..852bad78 100644
--- a/apps/app/src/pages/Playground.tsx
+++ b/apps/app/src/pages/Playground.tsx
@@ -6,6 +6,13 @@
*/
import { useState, useCallback, useMemo, type ReactNode } from 'react'
+import { Link } from 'react-router-dom'
+import { LogOut } from 'lucide-react'
+import { Light as SyntaxHighlighter } from 'react-syntax-highlighter'
+import js from 'react-syntax-highlighter/dist/esm/languages/hljs/javascript'
+import { githubGist } from 'react-syntax-highlighter/dist/esm/styles/hljs'
+
+SyntaxHighlighter.registerLanguage('javascript', js)
import {
useCurrentAccount,
useDisconnectWallet,
@@ -13,10 +20,11 @@ import {
useSuiClient,
} from '@mysten/dapp-kit'
import { useSponsoredTransaction } from '../hooks/useSponsoredTransaction'
-import { MemWal } from '@cmdoss/memwal'
-import { MemWalManual } from '@cmdoss/memwal/manual'
+import { MemWal } from '@mysten/memwal'
+import { MemWalManual } from '@mysten/memwal/manual'
import { useDelegateKey } from '../App'
import { config } from '../config'
+import memwalLogo from '../assets/memwal-logo.svg'
// ============================================================
// Demo Step — reusable step card
@@ -81,9 +89,16 @@ function DemoStep({
{children}
{/* Code block */}
-
- {code}
-
+
+
+ {code}
+
+
{/* Success result */}
{result && (
@@ -417,29 +432,21 @@ export default function Playground() {
<>
@@ -465,7 +475,7 @@ export default function Playground() {
key:
{keyPreview}
- SDK: @cmdoss/memwal
+ SDK: @mysten/memwal
namespace:
@@ -484,7 +494,7 @@ export default function Playground() {
number={1}
title="health check"
description="verify the memwal server is running"
- code={`import { MemWal } from "@cmdoss/memwal"
+ code={`import { MemWal } from "@mysten/memwal"
const memwal = MemWal.create({
key: "${keyPreview}",
@@ -647,14 +657,14 @@ const result = await memwal.restore("${namespace || 'default'}")
-
- {`// memwal doesn't include an LLM — you choose your own.
+
+{`// memwal doesn't include an LLM — you choose your own.
// steps 7–9 use this key for:
// • ask AI: recalls memories → injects into your LLM prompt
// • full client-side: embeds text via your OpenAI / OpenRouter key
//
-// your key is never sent to memwal servers.`}
-
+// your key is never sent to memwal servers.`}
+
{/* Step 6: Ask AI — true middleware pattern */}
@@ -693,8 +703,9 @@ const result = await memwal.restore("${namespace || 'default'}")
/>
-
- {`import { withMemWal } from "@cmdoss/memwal/ai"
+
+
+{`import { withMemWal } from "@mysten/memwal/ai"
import { openai } from "@ai-sdk/openai"
import { generateText } from "ai"
@@ -710,8 +721,9 @@ const { text } = await generateText({
model,
prompt: "${askQuestion.slice(0, 50)}"
})
-// → AI answers using your encrypted memories as context`}
-
+// → AI answers using your encrypted memories as context`}
+
+
{/* Loading phase */}
{askPhase && (
@@ -823,8 +835,9 @@ const { text } = await generateText({
/>
-
- {`import { MemWalManual } from "@cmdoss/memwal/manual"
+
+
+{`import { MemWalManual } from "@mysten/memwal/manual"
const memwal = MemWalManual.create({
key: delegateKeyHex,
@@ -845,8 +858,9 @@ const memwal = MemWalManual.create({
// server then:
// 3. upload encrypted bytes to Walrus (server pays gas)
// 4. store vector + blob_id in DB
-await memwal.rememberManual("${fullRememberText.slice(0, 40)}...")`}
-
+await memwal.rememberManual("${fullRememberText.slice(0, 40)}...")`}
+
+
{fullRememberPhase && (
@@ -904,8 +918,9 @@ await memwal.rememberManual("${fullRememberText.slice(0, 40)}...")`}
/>
-
- {`// client does:
+
+
+{`// client does:
// 1. embed query via OpenAI
// 2. SEAL decrypt each result (wallet popup)
// server then:
@@ -913,8 +928,9 @@ await memwal.rememberManual("${fullRememberText.slice(0, 40)}...")`}
// 4. download encrypted blobs from Walrus
// 5. return encrypted results to client
const result = await memwal.recallManual("${fullRecallQuery}", 5)
-// → { results: [{ blob_id, text, distance }], total }`}
-
+// → { results: [{ blob_id, text, distance }], total }`}
+
+
{fullRecallPhase && (
diff --git a/apps/app/src/pages/SetupWizard.tsx b/apps/app/src/pages/SetupWizard.tsx
index 50ee93b9..25df17f5 100644
--- a/apps/app/src/pages/SetupWizard.tsx
+++ b/apps/app/src/pages/SetupWizard.tsx
@@ -17,7 +17,10 @@ import {
import { Transaction } from '@mysten/sui/transactions'
import { useSponsoredTransaction } from '../hooks/useSponsoredTransaction'
import { useDelegateKey } from '../App'
+import { Link } from 'react-router-dom'
+import { LogOut, Copy } from 'lucide-react'
import { config } from '../config'
+import memwalLogo from '../assets/memwal-logo.svg'
type Step = 'intro' | 'generating' | 'show-key' | 'onchain' | 'done'
@@ -204,15 +207,15 @@ export default function SetupWizard() {
<>
-
+
generate delegate key
@@ -297,7 +300,7 @@ export default function SetupWizard() {
{privateKeyHex}
- {copied ? 'copied!' : 'copy'}
+ {copied ? 'copied!' : 'copy'}
@@ -341,8 +344,8 @@ export default function SetupWizard() {
@@ -369,7 +372,7 @@ export default function SetupWizard() {
all set!
- your delegate key has been registered onchain. redirecting to dashboard...
+ your delegate key has been registered onchain. loading dashboard...
)}
diff --git a/apps/app/ws-resources.json b/apps/app/ws-resources.json
new file mode 100644
index 00000000..6d560de6
--- /dev/null
+++ b/apps/app/ws-resources.json
@@ -0,0 +1,7 @@
+{
+ "site_name": "MemWal",
+ "object_id": "0xf2e1de6b5f0d413a3f4b92521881aabe1c52d9f30c4bd27af7d8ed7d56fc8a32",
+ "routes": {
+ "/*": "/index.html"
+ }
+}
diff --git a/apps/chatbot/Dockerfile b/apps/chatbot/Dockerfile
index 4527ff8a..9831f217 100644
--- a/apps/chatbot/Dockerfile
+++ b/apps/chatbot/Dockerfile
@@ -20,14 +20,14 @@ COPY package.json pnpm-workspace.yaml pnpm-lock.yaml ./
COPY packages/sdk/package.json ./packages/sdk/
COPY apps/chatbot/package.json ./apps/chatbot/
-# Install all workspace deps (resolves workspace:* for @cmdoss/memwal)
+# Install all workspace deps (resolves workspace:* for @mysten/memwal)
RUN pnpm install --frozen-lockfile
# ── Stage 2: Build SDK ─────────────────────────────────────
FROM deps AS sdk-builder
COPY packages/sdk/ ./packages/sdk/
-RUN pnpm --filter @cmdoss/memwal build
+RUN pnpm --filter @mysten/memwal build
# ── Stage 3: Build Next.js App ─────────────────────────────
FROM sdk-builder AS builder
diff --git a/apps/chatbot/lib/ai/providers.ts b/apps/chatbot/lib/ai/providers.ts
index 226b7e03..c425baef 100644
--- a/apps/chatbot/lib/ai/providers.ts
+++ b/apps/chatbot/lib/ai/providers.ts
@@ -4,7 +4,7 @@ import {
extractReasoningMiddleware,
wrapLanguageModel,
} from "ai";
-import { withMemWal } from "@cmdoss/memwal/ai";
+import { withMemWal } from "@mysten/memwal/ai";
import { isTestEnvironment } from "../constants";
const THINKING_SUFFIX_REGEX = /-thinking$/;
diff --git a/apps/chatbot/package.json b/apps/chatbot/package.json
index 988af6a3..188b3807 100644
--- a/apps/chatbot/package.json
+++ b/apps/chatbot/package.json
@@ -22,7 +22,7 @@
"@ai-sdk/openai": "^3.0.41",
"@ai-sdk/provider": "^3.0.3",
"@ai-sdk/react": "3.0.39",
- "@cmdoss/memwal": "workspace:*",
+ "@mysten/memwal": "workspace:*",
"@codemirror/lang-javascript": "^6.2.2",
"@codemirror/lang-python": "^6.1.6",
"@codemirror/state": "^6.5.0",
diff --git a/apps/noter/Dockerfile b/apps/noter/Dockerfile
index 6c672bdc..f51ecdfe 100644
--- a/apps/noter/Dockerfile
+++ b/apps/noter/Dockerfile
@@ -20,12 +20,12 @@ COPY package.json pnpm-workspace.yaml pnpm-lock.yaml ./
COPY packages/sdk/package.json ./packages/sdk/
COPY apps/noter/package.json ./apps/noter/
-# Install all workspace deps (resolves workspace:* for @cmdoss/memwal)
+# Install all workspace deps (resolves workspace:* for @mysten/memwal)
RUN pnpm install --frozen-lockfile
-# Build SDK first (@cmdoss/memwal is the package name — matches sdk/package.json)
+# Build SDK first (@mysten/memwal is the package name — matches sdk/package.json)
COPY packages/sdk/ ./packages/sdk/
-RUN pnpm --filter @cmdoss/memwal build
+RUN pnpm --filter @mysten/memwal build
# ── Stage 2: Build Next.js App ─────────────────────────────
FROM deps AS builder
diff --git a/apps/noter/app/api/chat/route.ts b/apps/noter/app/api/chat/route.ts
index c812df36..e0a56899 100644
--- a/apps/noter/app/api/chat/route.ts
+++ b/apps/noter/app/api/chat/route.ts
@@ -1,6 +1,6 @@
import { streamText, convertToModelMessages, stepCountIs } from "ai";
import { createOpenAI } from "@ai-sdk/openai";
-import { withMemWal } from "@cmdoss/memwal/ai";
+import { withMemWal } from "@mysten/memwal/ai";
import { DEFAULT_MODEL } from "@/shared/lib/ai/constant";
import { createTools } from "@/shared/lib/ai/tools";
import { db } from "@/shared/lib/db";
diff --git a/apps/noter/next.config.ts b/apps/noter/next.config.ts
index 2bbf9910..34663cab 100644
--- a/apps/noter/next.config.ts
+++ b/apps/noter/next.config.ts
@@ -11,7 +11,7 @@ const nextConfig: NextConfig = {
],
},
serverExternalPackages: [
- "@cmdoss/memwal",
+ "@mysten/memwal",
"@mysten/seal",
"@mysten/walrus",
"@mysten/sui",
diff --git a/apps/noter/package.json b/apps/noter/package.json
index ed2bcfc6..65292b26 100644
--- a/apps/noter/package.json
+++ b/apps/noter/package.json
@@ -18,7 +18,7 @@
"@ai-sdk/openai": "^3.0.41",
"@ai-sdk/react": "3.0.39",
"@base-ui/react": "^1.2.0",
- "@cmdoss/memwal": "workspace:*",
+ "@mysten/memwal": "workspace:*",
"@hookform/resolvers": "^5.2.2",
"@lexical/code": "^0.41.0",
"@lexical/link": "^0.41.0",
diff --git a/apps/noter/package/feature/auth/ui/auth-button-group.tsx b/apps/noter/package/feature/auth/ui/auth-button-group.tsx
index d71a9831..113839b7 100644
--- a/apps/noter/package/feature/auth/ui/auth-button-group.tsx
+++ b/apps/noter/package/feature/auth/ui/auth-button-group.tsx
@@ -74,53 +74,24 @@ export function AuthButtonGroup() {
return (
- {/* Primary Button - Continue with Google */}
-
-
- {/* Dropdown Trigger */}
-
-
-
- {isWalletConnecting ? (
-
- ) : (
-
- )}
-
-
-
-
- Other sign-in options
-
-
- {/* Wallet Options */}
- handleWalletSelect("slush")}
- disabled={isWalletConnecting}
- className="cursor-pointer"
- >
- {isWalletConnecting ? (
-
- ) : (
-
- )}
- Slush Wallet
- {!slushInstalled && (
- Install
- )}
-
-
- {/* Future: Add more OAuth providers here */}
- {/*
-
- Facebook
- */}
-
-
+ {/* Primary Button - Connect with Slush Wallet */}
+ handleWalletSelect("slush")}
+ disabled={isLoginPending || isWalletConnecting}
+ className="flex-1"
+ >
+ {isWalletConnecting ? (
+ <>
+
+ Connecting...
+ >
+ ) : (
+ <>
+
+ {slushInstalled ? "Continue with Slush Wallet" : "Install Slush Wallet"}
+ >
+ )}
+
{/* Error Message */}
diff --git a/apps/noter/package/feature/note/lib/pdw-client.ts b/apps/noter/package/feature/note/lib/pdw-client.ts
index eae9ff2b..13dd8562 100644
--- a/apps/noter/package/feature/note/lib/pdw-client.ts
+++ b/apps/noter/package/feature/note/lib/pdw-client.ts
@@ -6,7 +6,7 @@
* Key can be set from env var OR at runtime via setMemWalKey().
*/
-import { MemWal } from "@cmdoss/memwal";
+import { MemWal } from "@mysten/memwal";
let _memwal: MemWal | null = null;
let _runtimeKey: string | null = null;
diff --git a/apps/researcher/Dockerfile b/apps/researcher/Dockerfile
index d8fae623..d41b19e0 100644
--- a/apps/researcher/Dockerfile
+++ b/apps/researcher/Dockerfile
@@ -12,7 +12,7 @@ WORKDIR /app
COPY apps/researcher/package.json ./
-# Install deps — @cmdoss/memwal is now on npm, no local SDK needed
+# Install deps — @mysten/memwal is now on npm, no local SDK needed
RUN bun install
# ── Stage 2: Build ─────────────────────────────────────────
diff --git a/apps/researcher/docker-compose.yml b/apps/researcher/docker-compose.yml
index 251e854d..3d51464b 100644
--- a/apps/researcher/docker-compose.yml
+++ b/apps/researcher/docker-compose.yml
@@ -1,23 +1,23 @@
-name: memwal-chatbot
+name: memwal-researcher
services:
postgres:
image: pgvector/pgvector:pg17
- container_name: chatbot-postgres
+ container_name: researcher-postgres
restart: unless-stopped
environment:
- POSTGRES_DB: chatbot
- POSTGRES_USER: chatbot
- POSTGRES_PASSWORD: chatbot_secret
+ POSTGRES_DB: researcher
+ POSTGRES_USER: researcher
+ POSTGRES_PASSWORD: researcher_secret
ports:
- - "5433:5432"
+ - "5436:5432"
volumes:
- - chatbot_pgdata:/var/lib/postgresql/data
+ - researcher_pgdata:/var/lib/postgresql/data
healthcheck:
- test: ["CMD-SHELL", "pg_isready -U chatbot"]
+ test: ["CMD-SHELL", "pg_isready -U researcher"]
interval: 5s
timeout: 5s
retries: 5
volumes:
- chatbot_pgdata:
+ researcher_pgdata:
diff --git a/apps/researcher/lib/sprint/memwal.ts b/apps/researcher/lib/sprint/memwal.ts
index 31075792..f681b32c 100644
--- a/apps/researcher/lib/sprint/memwal.ts
+++ b/apps/researcher/lib/sprint/memwal.ts
@@ -1,7 +1,7 @@
import "server-only";
-import { MemWal } from "@cmdoss/memwal";
-import type { RememberResult } from "@cmdoss/memwal";
+import { MemWal } from "@mysten/memwal";
+import type { RememberResult } from "@mysten/memwal";
import type { Citation, SourceMeta } from "./types";
function getMemWalClient(key: string, accountId?: string) {
diff --git a/apps/researcher/package.json b/apps/researcher/package.json
index bb28ffa6..065dfa0c 100644
--- a/apps/researcher/package.json
+++ b/apps/researcher/package.json
@@ -24,7 +24,7 @@
"@ai-sdk/openai": "^3.0.41",
"@ai-sdk/provider": "^3.0.3",
"@ai-sdk/react": "3.0.39",
- "@cmdoss/memwal": "2.0.0-alpha.5",
+ "@mysten/memwal": "0.0.1-dev.0",
"@codemirror/lang-javascript": "^6.2.2",
"@codemirror/lang-python": "^6.1.6",
"@codemirror/state": "^6.5.0",
diff --git a/docs/contract/delegate-key-management.md b/docs/contract/delegate-key-management.md
index 2f26ee77..d8ceacdb 100644
--- a/docs/contract/delegate-key-management.md
+++ b/docs/contract/delegate-key-management.md
@@ -2,21 +2,84 @@
title: "Delegate Key Management"
---
-Delegate keys are lightweight Ed25519 keys used for SDK authentication.
+Delegate keys are lightweight Ed25519 keys used for SDK authentication. They are registered onchain in a `MemWalAccount` and verified by the relayer on every request.
## Why They Exist
-- apps need a usable key for API calls
-- users should not hand over the owner wallet for day-to-day memory access
+- Apps need a usable key for API calls without exposing the owner wallet
+- Users should not hand over the owner wallet for day-to-day memory access
+- Different apps or devices can each have their own delegate key with a descriptive label
-## Main Lifecycle
+## Lifecycle
-- create a delegate key
-- register the public key onchain
-- use the private key in the SDK
-- revoke the delegate key when it should stop working
+### 1. Generate a delegate keypair
-## Practical Result
+Use the SDK's `generateDelegateKey()` helper to create a new Ed25519 keypair:
-Removing a delegate key from the onchain account should prevent future relayer access from that
-key.
+```ts
+import { generateDelegateKey } from "@mysten/memwal/account";
+
+const delegate = await generateDelegateKey();
+// delegate.privateKey — hex string, store securely
+// delegate.publicKey — 32-byte Uint8Array
+// delegate.suiAddress — derived Sui address (0x...)
+```
+
+### 2. Register the public key onchain
+
+Only the account owner can add delegate keys:
+
+```ts
+import { addDelegateKey } from "@mysten/memwal/account";
+
+await addDelegateKey({
+ packageId: "0x...",
+ accountId: "0x...",
+ publicKey: delegate.publicKey,
+ label: "MacBook Pro",
+ suiPrivateKey: "suiprivkey1...", // or walletSigner
+});
+```
+
+### 3. Use the private key in the SDK
+
+```ts
+import { MemWal } from "@mysten/memwal";
+
+const memwal = MemWal.create({
+ key: delegate.privateKey,
+ accountId: "0x...",
+});
+```
+
+### 4. Revoke the delegate key
+
+Removing a delegate key prevents future relayer access from that key:
+
+```ts
+import { removeDelegateKey } from "@mysten/memwal/account";
+
+await removeDelegateKey({
+ packageId: "0x...",
+ accountId: "0x...",
+ publicKey: delegate.publicKey,
+ suiPrivateKey: "suiprivkey1...", // or walletSigner
+});
+```
+
+## Limits
+
+- Each account supports up to **20 delegate keys**
+- Each delegate key must be a valid 32-byte Ed25519 public key
+- Duplicate keys are rejected (error code 0)
+- Only the account owner can add or remove delegate keys
+
+## Account Deactivation
+
+An account owner can deactivate (freeze) their account. When deactivated:
+
+- SEAL decryption access is denied for all keys (owner and delegates)
+- Delegate keys cannot be added or removed
+- The owner can reactivate the account at any time
+
+This is useful as an emergency kill switch if a key is compromised.
diff --git a/docs/contract/overview.md b/docs/contract/overview.md
index ad43c613..b505fac5 100644
--- a/docs/contract/overview.md
+++ b/docs/contract/overview.md
@@ -2,15 +2,90 @@
title: "Smart Contract Overview"
---
-The smart contract defines the onchain account model for MemWal.
+The smart contract (`memwal::account`) defines the onchain account model for MemWal. It is a Move module deployed on Sui.
-## Current Focus
+## What It Manages
-- who owns a MemWal account
-- which delegate keys are allowed to act through the relayer
-- how application access is separated from wallet ownership
+- **Ownership** — who owns a MemWal account
+- **Delegate keys** — which Ed25519 keys are authorized to act through the relayer
+- **SEAL access control** — who can decrypt encrypted memories via `seal_approve`
+- **Account lifecycle** — activation and deactivation (freeze/unfreeze)
-## Key Object
+The contract does not store memory content — it only manages identity, permissions, and access control.
-The docs refer to the onchain account model as `MemWalAccount`, which holds ownership and
-delegate-key data.
+## Key Objects
+
+### `AccountRegistry`
+
+A shared object created at module publish time. It tracks all MemWalAccount objects and prevents duplicate account creation (one account per Sui address).
+
+### `MemWalAccount`
+
+A shared object representing a single user's account. It stores:
+
+| Field | Type | Description |
+|-------|------|-------------|
+| `owner` | `address` | The Sui wallet address that owns this account |
+| `delegate_keys` | `vector
` | List of authorized Ed25519 delegate keys |
+| `created_at` | `u64` | Timestamp when the account was created (epoch ms) |
+| `active` | `bool` | Whether the account is active (false = frozen) |
+
+### `DelegateKey`
+
+A struct stored inside `MemWalAccount.delegate_keys`:
+
+| Field | Type | Description |
+|-------|------|-------------|
+| `public_key` | `vector` | Ed25519 public key (32 bytes) |
+| `sui_address` | `address` | Sui address derived from this Ed25519 key |
+| `label` | `String` | Human-readable label (e.g., "MacBook Pro") |
+| `created_at` | `u64` | Timestamp when the key was added (epoch ms) |
+
+## Limits
+
+- **Maximum delegate keys per account**: 20
+
+## Error Codes
+
+| Code | Name | Description |
+|------|------|-------------|
+| 0 | `EDelegateKeyAlreadyExists` | Key already registered in this account |
+| 1 | `EDelegateKeyNotFound` | Key not found when trying to remove |
+| 2 | `ETooManyDelegateKeys` | Account has reached the 20-key limit |
+| 3 | `EAccountAlreadyExists` | Address already has an account |
+| 4 | `ENotOwner` | Caller is not the account owner |
+| 5 | `EInvalidPublicKeyLength` | Public key is not exactly 32 bytes |
+| 6 | `EAccountDeactivated` | Account is frozen — operation denied |
+| 100 | `ENoAccess` | SEAL access denied — caller is neither owner nor delegate |
+
+## Entry Functions
+
+| Function | Description |
+|----------|-------------|
+| `create_account(registry, clock)` | Create a new MemWalAccount (one per address) |
+| `add_delegate_key(account, public_key, sui_address, label, clock)` | Add a delegate key (owner only) |
+| `remove_delegate_key(account, public_key)` | Remove a delegate key (owner only) |
+| `deactivate_account(account)` | Freeze the account — SEAL access denied, keys locked (owner only) |
+| `reactivate_account(account)` | Unfreeze the account (owner only) |
+| `seal_approve(id, account)` | SEAL policy — authorizes owner or delegate key holder to decrypt |
+
+## View Functions
+
+| Function | Description |
+|----------|-------------|
+| `is_delegate(account, public_key)` | Check if a public key is an authorized delegate |
+| `is_delegate_address(account, addr)` | Check if a Sui address is an authorized delegate |
+| `owner(account)` | Get the owner address |
+| `delegate_count(account)` | Get the number of delegate keys |
+| `has_account(registry, addr)` | Check if an address already has an account |
+| `is_active(account)` | Check if the account is active |
+
+## Events
+
+| Event | Emitted when |
+|-------|-------------|
+| `AccountCreated` | A new account is created |
+| `DelegateKeyAdded` | A delegate key is added to an account |
+| `DelegateKeyRemoved` | A delegate key is removed from an account |
+| `AccountDeactivated` | An account is frozen |
+| `AccountReactivated` | A frozen account is unfrozen |
diff --git a/docs/contract/ownership-and-permissions.md b/docs/contract/ownership-and-permissions.md
index 68c36936..278c31fd 100644
--- a/docs/contract/ownership-and-permissions.md
+++ b/docs/contract/ownership-and-permissions.md
@@ -4,16 +4,46 @@ title: "Ownership and Permissions"
## Owner
-The owner wallet controls the MemWal account model onchain.
+The owner is the Sui wallet address that created the `MemWalAccount`. The owner has full control:
+
+- Add and remove delegate keys
+- Deactivate (freeze) and reactivate the account
+- Decrypt any memory encrypted under their address via SEAL
+
+Each Sui address can only create **one** MemWalAccount (enforced by the `AccountRegistry`).
## Delegate
-The delegate key authenticates API calls through the relayer.
+A delegate key authenticates API calls through the relayer. Delegates can:
+
+- Store memories (`remember`, `analyze`)
+- Recall memories (`recall`)
+- Restore namespaces (`restore`)
+- Decrypt SEAL-encrypted content (via `seal_approve`)
+
+Delegates **cannot**:
+
+- Add or remove other delegate keys
+- Deactivate or reactivate the account
+- Transfer ownership
+
+## SEAL Access Control
+
+The contract's `seal_approve` function is the SEAL policy that controls who can decrypt memories. Access is granted if the caller is:
+
+1. **The data owner** — the key ID ends with the BCS-encoded owner address and the caller is the account owner
+2. **A registered delegate** — the caller's Sui address is in the account's `delegate_keys` list
+
+The account must also be **active** (not frozen). If the account is deactivated, all SEAL access is denied.
## Permission Boundary
-The docs should treat these as separate layers:
+These are separate layers that work together:
+
+| Layer | Controls | Enforced by |
+|-------|----------|-------------|
+| **Owner** | Account control — keys, activation, ownership | Sui smart contract |
+| **Delegate** | Application access — read/write memory | Sui smart contract + relayer verification |
+| **Relayer** | Backend execution — encryption, storage, search | Server-side auth middleware |
-- owner-level account control
-- delegate-level application access
-- relayer-level backend execution
+The relayer verifies every request against the onchain contract before executing any operation. Even if the relayer is compromised, it cannot forge delegate permissions or change ownership — those are cryptographically enforced onchain.
diff --git a/docs/contributing/run-docs-locally.md b/docs/contributing/run-docs-locally.md
index 18443bf3..52edd9dd 100644
--- a/docs/contributing/run-docs-locally.md
+++ b/docs/contributing/run-docs-locally.md
@@ -9,7 +9,7 @@ pnpm install
pnpm dev:docs
```
-This starts the Docusaurus site using the docs in this repository.
+This starts the Mintlify site using the docs in this repository.
## Build the Docs
diff --git a/docs/contributing/run-repo-locally.md b/docs/contributing/run-repo-locally.md
index ac7ca7b4..7d5bae4e 100644
--- a/docs/contributing/run-repo-locally.md
+++ b/docs/contributing/run-repo-locally.md
@@ -7,7 +7,7 @@ This monorepo contains:
- TypeScript applications under `apps/`
- the SDK under `packages/sdk`
- Rust backend services under `services/`
-- Docusaurus docs under `docs/`
+- Mintlify docs under `docs/`
## Common Local Entry Points
@@ -37,5 +37,4 @@ For relayer-oriented local work you will typically need:
If you want to run the backend locally, start with the Relayer docs:
-- [Installation and Setup](/relayer/installation-and-setup)
-- [Operate Your Own Relayer](/relayer/self-hosting)
+- [Self-Hosting](/relayer/self-hosting)
diff --git a/docs/docs.json b/docs/docs.json
index 7d0d6890..bf64dd91 100644
--- a/docs/docs.json
+++ b/docs/docs.json
@@ -3,30 +3,34 @@
"theme": "mint",
"name": "MemWal",
"description": "Privacy-preserving decentralized memory protocol for humans and AI agents",
+ "logo": {
+ "light": "/logo-light.svg",
+ "dark": "/logo-dark.svg"
+ },
"favicon": "/favicon.ico",
"colors": {
"primary": "#191a23",
- "light": "#98efe4",
+ "light": "#E8FF75",
"dark": "#191a23"
},
"appearance": {
"default": "system"
},
"banner": {
- "content": "**MemWal is in active beta.** APIs and features may evolve between releases.",
+ "content": "MemWal is in beta with ongoing improvements to APIs and features based on developer feedback.",
"dismissible": false
},
"navbar": {
"links": [
{
"label": "GitHub",
- "href": "https://github.com/CommandOSSLabs/personal-data-wallet"
+ "href": "https://github.com/CommandOSSLabs/memwal"
}
]
},
"footer": {
"socials": {
- "github": "https://github.com/CommandOSSLabs/personal-data-wallet"
+ "github": "https://github.com/CommandOSSLabs/memwal"
}
},
"navigation": {
@@ -70,14 +74,17 @@
{
"group": "SDK",
"pages": [
- "sdk/overview",
"sdk/quick-start",
- "sdk/usage",
- "sdk/ai-integration",
- "sdk/basic-usage",
- "sdk/advanced-usage",
- "sdk/research-app-example",
- "sdk/example-map"
+ {
+ "group": "Usage",
+ "root": "sdk/usage",
+ "pages": [
+ "sdk/usage/memwal",
+ "sdk/usage/memwal-manual",
+ "sdk/usage/with-memwal"
+ ]
+ },
+ "sdk/api-reference"
]
}
]
@@ -90,8 +97,8 @@
"pages": [
"relayer/overview",
"relayer/public-relayer",
- "relayer/installation-and-setup",
- "relayer/self-hosting"
+ "relayer/self-hosting",
+ "relayer/api-reference"
]
}
]
@@ -128,8 +135,6 @@
{
"group": "Reference",
"pages": [
- "reference/sdk-api",
- "reference/relayer-api",
"reference/configuration",
"reference/environment-variables"
]
diff --git a/docs/examples/basic-usage.md b/docs/examples/basic-usage.md
index ff584bef..a05a559b 100644
--- a/docs/examples/basic-usage.md
+++ b/docs/examples/basic-usage.md
@@ -1,65 +1,70 @@
-# Basic Usage
+---
+title: "Basic Usage"
+---
## Installation
-First, install the MemWal SDK:
-
```bash
-pnpm add @cmdoss/memwal
+pnpm add @mysten/memwal
```
## Initialize
```typescript
-import { MemWal } from '@cmdoss/memwal'
+import { MemWal } from "@mysten/memwal";
+
+const memwal = MemWal.create({
+ key: process.env.MEMWAL_PRIVATE_KEY!,
+ accountId: process.env.MEMWAL_ACCOUNT_ID!,
+ serverUrl: process.env.MEMWAL_SERVER_URL,
+ namespace: "my-app",
+});
+```
-const memwal = new MemWal({
- network: 'testnet',
- packageId: '0xcf6ad755a1cdff7217865c796778fabe5aa399cb0cf2eba986f4b582047229c6',
- registryId: '0xe80f2feec1c139616a86c9f71210152e2a7ca552b20841f2e192f99f75864437',
-})
+## Store a Memory
+
+```typescript
+const result = await memwal.remember("User prefers dark mode and works in TypeScript.");
+console.log("Blob ID:", result.blob_id);
```
-## Connect Wallet
+## Recall Memories
```typescript
-// Using Enoki zkLogin (Google)
-await memwal.connectEnoki()
+const results = await memwal.recall("What do we know about this user?", 10);
-// Or using Sui wallet
-await memwal.connectWallet()
+for (const memory of results.results) {
+ console.log(memory.text, `(distance: ${memory.distance})`);
+}
```
-## Store Memory
+## Analyze Text
+
+Extract structured facts from longer text and store each as a separate memory.
```typescript
-const memory = await memwal.addMemory({
- content: 'Your memory content here',
- metadata: {
- type: 'note',
- tags: ['important', 'work']
- }
-})
-
-console.log('Memory ID:', memory.id)
+const analyzed = await memwal.analyze(
+ "I live in Hanoi, prefer dark mode, and usually work late at night."
+);
+
+console.log(`Extracted ${analyzed.total} facts:`);
+for (const fact of analyzed.facts) {
+ console.log(`- ${fact.text}`);
+}
```
-## Search Memories
+## Restore a Namespace
-```typescript
-const results = await memwal.search('search query', {
- limit: 10
-})
+Rebuild missing indexed entries from Walrus if your local database is incomplete.
-results.forEach(memory => {
- console.log(memory.content)
-})
+```typescript
+const restored = await memwal.restore("my-app", 50);
+console.log(`Restored ${restored.restored} memories, skipped ${restored.skipped}`);
```
-## Get All Memories
+## Health Check
```typescript
-const allMemories = await memwal.getMemories()
-
-console.log(`Found ${allMemories.length} memories`)
+const health = await memwal.health();
+console.log(health.status); // "ok"
```
diff --git a/docs/favicon.ico b/docs/favicon.ico
index e69de29b..4c43716e 100644
Binary files a/docs/favicon.ico and b/docs/favicon.ico differ
diff --git a/docs/fundamentals/architecture/core-components.md b/docs/fundamentals/architecture/core-components.md
index a1e73db0..28cd8cea 100644
--- a/docs/fundamentals/architecture/core-components.md
+++ b/docs/fundamentals/architecture/core-components.md
@@ -38,6 +38,7 @@ The TypeScript SDK is the main entry point for developers. It wraps all MemWal o
```ts
const memwal = MemWal.create({
key: process.env.MEMWAL_PRIVATE_KEY!,
+ accountId: process.env.MEMWAL_ACCOUNT_ID!,
serverUrl: process.env.MEMWAL_SERVER_URL,
namespace: "my-app",
});
@@ -58,7 +59,7 @@ This means Web2 developers can integrate MemWal without touching wallets, signin
- Encrypts and decrypts memory payloads
- Uploads and downloads blobs to/from Walrus
- Stores and searches vector metadata in the indexed database
-- Scopes all operations to `owner + namespace + app_id`
+- Scopes all operations to `owner + namespace` (with SEAL encryption bound to the app's package ID)
- Can sponsor transaction and storage fees for user requests
@@ -101,11 +102,17 @@ Walrus is an external protocol — MemWal uses it as infrastructure, not as some
## Indexed Database
-PostgreSQL with pgvector serves as the local search and sync layer.
+PostgreSQL with the [pgvector](https://github.com/pgvector/pgvector) extension serves as the local search and sync layer.
+
+**Key tables:**
+- `vector_entries` — stores 1536-dimensional embeddings linked to Walrus blob IDs, with an HNSW index for fast cosine similarity search
+- `delegate_key_cache` — caches delegate key → account mappings for fast auth
+- `accounts` — synced by the indexer for account lookups
+- `indexer_state` — tracks the indexer's event polling cursor
**Responsibilities:**
- Stores vector embeddings for semantic search during recall
- Caches account and delegate data synced by the indexer
-- Scopes all queries to `owner + namespace + app_id`
+- Scopes all queries to `owner + namespace` (package ID provides cross-deployment isolation via SEAL)
-This is an operational component — it makes recall fast and keeps onchain lookups efficient, but the encrypted source of truth always lives on Walrus.
+This is an operational component — it makes recall fast and keeps onchain lookups efficient, but the encrypted source of truth always lives on Walrus. If the database is lost, the [restore flow](/sdk/usage/memwal) can rebuild it from Walrus.
diff --git a/docs/fundamentals/architecture/data-flow-security-model.md b/docs/fundamentals/architecture/data-flow-security-model.md
index 1ec3e15a..87ad249e 100644
--- a/docs/fundamentals/architecture/data-flow-security-model.md
+++ b/docs/fundamentals/architecture/data-flow-security-model.md
@@ -31,6 +31,12 @@ This means the **relayer operator can see your data in transit**. This is simila
You have options depending on your trust requirements:
+| Option | Trust level | What the relayer sees |
+|--------|------------|----------------------|
+| **Public relayer** | You trust the MemWal team | Plaintext content, embeddings, decrypted results |
+| **Self-hosted relayer** | You trust your own infra | Same as above, but under your control |
+| **Manual client flow** | Minimal trust | Only encrypted payloads and pre-computed vectors — never plaintext |
+
- **Use the public relayer** — convenient for getting started and prototyping. You trust the MemWal team to operate it responsibly.
- **Self-host your own relayer** — you control the infrastructure, so the trust boundary is entirely yours. No third party sees your data.
- **Manual client flow** — use `MemWalManual` to handle encryption and embedding entirely on the client side. The relayer only sees encrypted payloads and vectors, never plaintext. This is recommended for Web3-native users who want full control over their data and are comfortable managing keys, signing, and SEAL operations directly.
@@ -59,6 +65,17 @@ flowchart LR
- **Offchain (operator trust)**: encryption, embedding, search — handled by the relayer and indexed database
- **Decentralized (durable)**: encrypted memory payloads — stored on Walrus, no single point of failure
+## Authentication flow
+
+Every protected API call goes through Ed25519 signature verification:
+
+1. The SDK signs a message: `{timestamp}.{method}.{path}.{body_sha256}` using the delegate private key
+2. The relayer verifies the Ed25519 signature against the provided public key
+3. Timestamps must be within a **5-minute window** to prevent replay attacks
+4. The relayer resolves the public key to a `MemWalAccount` using the priority chain: cache → indexed accounts → onchain registry → header hint → config fallback
+5. The onchain account is fetched to verify the delegate key is registered in `delegate_keys`
+6. The resolved owner address is used to scope all subsequent operations
+
## Current status
This describes the production beta model. The trust boundaries are designed to evolve — future versions may introduce client-side encryption by default or additional verifiability layers. Self-hosting remains the strongest option for teams that need full control today.
diff --git a/docs/fundamentals/architecture/how-storage-works.md b/docs/fundamentals/architecture/how-storage-works.md
index e5757b8b..5407cd43 100644
--- a/docs/fundamentals/architecture/how-storage-works.md
+++ b/docs/fundamentals/architecture/how-storage-works.md
@@ -47,7 +47,7 @@ sequenceDiagram
### Vector indexing
- The vector embedding, along with the blob ID, owner address, namespace, and app ID, is stored in the indexed database (PostgreSQL + pgvector). This is the searchable index that powers recall.
+ The vector embedding (1536-dimensional, generated by `text-embedding-3-small`), along with the blob ID, owner address, and namespace, is stored in the `vector_entries` table in PostgreSQL with pgvector. An HNSW index on the embedding column enables fast approximate nearest neighbor search during recall.
@@ -63,7 +63,7 @@ sequenceDiagram
App->>Relayer: query ("What does this user prefer?")
Relayer->>Relayer: generate query embedding
- Relayer->>DB: vector search (owner + namespace + app_id)
+ Relayer->>DB: vector search (owner + namespace)
DB-->>Relayer: matching blob IDs
Relayer->>Walrus: download encrypted blobs
Walrus-->>Relayer: encrypted payloads
@@ -73,16 +73,51 @@ sequenceDiagram
```
1. Your query is converted into a vector embedding
-2. The database is searched for the closest matching vectors, scoped to your memory space (`owner + namespace + app_id`)
-3. Matching encrypted blobs are downloaded from Walrus
-4. The blobs are decrypted via SEAL
-5. Plaintext results are returned to your app
+2. The database is searched for the closest matching vectors using pgvector's cosine distance operator (`<=>`), scoped to your memory space (`owner + namespace`)
+3. Matching encrypted blobs are downloaded from Walrus concurrently
+4. Each blob is decrypted via SEAL using the delegate key
+5. Plaintext results are returned to your app, sorted by distance (most relevant first)
+
+
+If a blob has expired on Walrus (returns 404), the relayer automatically deletes the stale vector entry from the database. This reactive cleanup keeps your recall results clean without manual intervention.
+
+
+## Restoring a memory space
+
+If the local database is lost or incomplete, the restore flow rebuilds it from Walrus — the permanent source of truth.
+
+```mermaid
+sequenceDiagram
+ participant App as Your App
+ participant Relayer as Relayer
+ participant Chain as Sui Chain
+ participant Walrus as Walrus
+ participant DB as Indexed Database
+
+ App->>Relayer: restore("my-namespace")
+ Relayer->>Chain: query blobs by owner + namespace
+ Chain-->>Relayer: blob IDs (on-chain metadata)
+ Relayer->>DB: check which blobs already exist locally
+ DB-->>Relayer: existing blob IDs
+ Relayer->>Walrus: download missing blobs
+ Walrus-->>Relayer: encrypted payloads
+ Relayer->>Relayer: SEAL decrypt + re-embed
+ Relayer->>DB: insert new vector entries
+ Relayer-->>App: restored count
+```
+
+1. The relayer queries on-chain Walrus blob objects owned by the user, filtered by namespace metadata
+2. It compares against the local database to find which blobs are already indexed
+3. Only missing blobs are downloaded, decrypted, re-embedded, and re-indexed
+4. The restore supports a configurable `limit` (default: 50) to control how many blobs are processed per call
+
+Restore is incremental and idempotent — you can call it multiple times safely.
## Two layers, one system
| Layer | Stores | Purpose |
|-------|--------|---------|
| **Walrus** | Encrypted blobs | Durable, decentralized source of truth |
-| **Indexed Database** | Vector embeddings + metadata | Fast semantic search for recall |
+| **PostgreSQL + pgvector** | Vector embeddings + metadata | Fast semantic search for recall |
-The indexed database is rebuildable — if it's ever lost, the [restore flow](/sdk/usage) can rediscover blobs from Walrus by owner and namespace, then re-embed and re-index them. Walrus is the permanent record.
+The database is rebuildable — if it's ever lost, the restore flow can rediscover blobs from Walrus by owner and namespace, then re-embed and re-index them. Walrus is the permanent record.
diff --git a/docs/fundamentals/concepts/memory-space.md b/docs/fundamentals/concepts/memory-space.md
index 12f2a1a5..02e92bb7 100644
--- a/docs/fundamentals/concepts/memory-space.md
+++ b/docs/fundamentals/concepts/memory-space.md
@@ -15,9 +15,9 @@ Every memory space is uniquely identified by three values:
|-----------|-----------|
| **Owner address** | The Sui wallet address that owns the memory |
| **Namespace** | A developer-defined label to group and organize memories |
-| **App ID** | A globally unique identifier for the deployed MemWal instance |
+| **App ID** | The MemWal package ID (`MEMWAL_PACKAGE_ID`) — unique per relayer deployment |
-Together, `owner_address + namespace + app_id` form the boundary — no two memory spaces can overlap.
+Together, `owner + namespace + app_id` form the boundary — no two memory spaces can overlap.
## Namespace
@@ -33,6 +33,7 @@ Namespaces are set in the SDK when you create a client:
```ts
const memwal = MemWal.create({
key: process.env.MEMWAL_PRIVATE_KEY!,
+ accountId: process.env.MEMWAL_ACCOUNT_ID!,
serverUrl: process.env.MEMWAL_SERVER_URL,
namespace: "personal",
});
@@ -40,9 +41,9 @@ const memwal = MemWal.create({
## App ID
-MemWal is not a singleton service — developers can clone the repo and run their own deployed instance. The **app ID** is a globally unique identifier for each deployment, ensuring that different apps don't clash on the same owner + namespace combination.
+The **app ID** is the MemWal package ID deployed on Sui (`MEMWAL_PACKAGE_ID`). Each relayer deployment is tied to a single package ID, which is used for SEAL encryption key derivation and Walrus blob metadata.
-Two separate MemWal deployments can each have a user with a `personal` namespace, and their memories will never mix — because the app ID is different.
+Two separate MemWal deployments can each have a user with a `personal` namespace, and their memories will never mix — because the app ID (package ID) is different. This means the vector database scopes queries by `owner + namespace`, while the encryption and blob discovery layer provides an additional isolation boundary through the package ID.
## How it works in practice
diff --git a/docs/fundamentals/concepts/ownership-and-access.md b/docs/fundamentals/concepts/ownership-and-access.md
index 07d915c2..d5561a24 100644
--- a/docs/fundamentals/concepts/ownership-and-access.md
+++ b/docs/fundamentals/concepts/ownership-and-access.md
@@ -11,7 +11,8 @@ Memory content in MemWal is stored on Walrus and cryptographically owned by a us
```ts
const memwal = MemWal.create({
- key: process.env.MEMWAL_PRIVATE_KEY!, // owner's private key
+ key: process.env.MEMWAL_PRIVATE_KEY!, // delegate private key
+ accountId: process.env.MEMWAL_ACCOUNT_ID!, // MemWalAccount object ID
serverUrl: process.env.MEMWAL_SERVER_URL,
namespace: "personal",
});
@@ -46,7 +47,7 @@ flowchart TD
D3 -->|reads| Memory
```
-## Acess Control Enforcement
+## Access Control Enforcement
The relationship between owners and delegates is enforced on chain by the Sui smart contract system — not by application logic or database permissions.
diff --git a/docs/getting-started/choose-your-path.md b/docs/getting-started/choose-your-path.md
index 1f7d8d6c..3772057d 100644
--- a/docs/getting-started/choose-your-path.md
+++ b/docs/getting-started/choose-your-path.md
@@ -10,7 +10,7 @@ These paths aren't mutually exclusive. You can combine them — for example, use
## 1. Default SDK
-Use `@cmdoss/memwal` when you want the fastest working integration.
+Use `@mysten/memwal` when you want the fastest working integration.
- relayer handles embedding, encryption, retrieval, and restore
- best starting point for most teams
@@ -25,7 +25,7 @@ Go to: [Public Relayer](/relayer/public-relayer)
## 3. Manual Client Flow
-Use `@cmdoss/memwal/manual` when you want full client-side control over encryption and embeddings. Recommended for Web3-native users who want to minimize trust in the relayer — it never sees your plaintext data.
+Use `@mysten/memwal/manual` when you want full client-side control over encryption and embeddings. Recommended for Web3-native users who want to minimize trust in the relayer — it never sees your plaintext data.
- client handles embeddings and SEAL encryption locally
- relayer only sees encrypted payloads and vectors
@@ -34,9 +34,9 @@ Go to: [SDK Usage](/sdk/usage)
## 4. AI Middleware
-Use `@cmdoss/memwal/ai` when you already use the AI SDK and want recall plus auto-save behavior.
+Use `@mysten/memwal/ai` when you already use the AI SDK and want recall plus auto-save behavior.
-Go to: [AI Integration](/sdk/ai-integration)
+Go to: [AI Integration](/sdk/usage/with-memwal)
## 5. Self-Host the Relayer
diff --git a/docs/getting-started/quick-start.md b/docs/getting-started/quick-start.md
index 8c906d1e..1527227a 100644
--- a/docs/getting-started/quick-start.md
+++ b/docs/getting-started/quick-start.md
@@ -8,7 +8,8 @@ The fastest way to get MemWal running is through the TypeScript SDK.
- [Node.js](https://nodejs.org/) v18+ or [Bun](https://bun.sh/) v1+
- A delegate key (Ed25519 private key in hex)
-- A relayer URL — use the [public relayer](/relayer/public-relayer) to get started
+- A MemWalAccount object ID on Sui
+- A relayer URL - use a public relayer if one is available to you, or your own local or self-hosted relayer
## Quick Start
@@ -19,29 +20,29 @@ The fastest way to get MemWal running is through the TypeScript SDK.
```bash
- pnpm add @cmdoss/memwal
+ pnpm add @mysten/memwal
```
```bash
- npm install @cmdoss/memwal
+ npm install @mysten/memwal
```
```bash
- yarn add @cmdoss/memwal
+ yarn add @mysten/memwal
```
```bash
- bun add @cmdoss/memwal
+ bun add @mysten/memwal
```
**Optional packages**
- For AI middleware with [Vercel AI SDK](https://sdk.vercel.ai/) (`@cmdoss/memwal/ai`):
+ For AI middleware with [Vercel AI SDK](https://sdk.vercel.ai/) (`@mysten/memwal/ai`):
@@ -66,7 +67,7 @@ The fastest way to get MemWal running is through the TypeScript SDK.
- For the [manual client flow](/getting-started/choose-your-path) (`@cmdoss/memwal/manual`):
+ For the [manual client flow](/getting-started/choose-your-path) (`@mysten/memwal/manual`):
@@ -95,17 +96,20 @@ The fastest way to get MemWal running is through the TypeScript SDK.
### Configure the SDK
- Set up the SDK with your delegate key and relayer URL:
+ Set up the SDK with your delegate key, account ID, and relayer URL:
```ts
- import { MemWal } from "@cmdoss/memwal";
+ import { MemWal } from "@mysten/memwal";
const memwal = MemWal.create({
key: process.env.MEMWAL_PRIVATE_KEY!,
+ accountId: process.env.MEMWAL_ACCOUNT_ID!,
serverUrl: process.env.MEMWAL_SERVER_URL,
namespace: "my-app",
});
```
+
+ If you are self-hosting the relayer and do not have `MEMWAL_ACCOUNT_ID` yet, see [Self-Hosting](/relayer/self-hosting) for the account-creation and delegate-key setup flow after the relayer starts.
@@ -128,6 +132,6 @@ The fastest way to get MemWal running is through the TypeScript SDK.
console.log(result.results);
```
- That's it — you're up and running.
+ That's it - you're up and running.
diff --git a/docs/getting-started/what-is-memwal.md b/docs/getting-started/what-is-memwal.md
index ea6f8887..15454af2 100644
--- a/docs/getting-started/what-is-memwal.md
+++ b/docs/getting-started/what-is-memwal.md
@@ -1,9 +1,9 @@
---
title: "What is MemWal?"
-description: "Privacy-preserving, decentralized memory protocol for humans and AI agents — powered by Walrus and Sui."
+description: "Privacy-preserving, decentralized memory layer for humans and AI agents — powered by Walrus and Sui."
---
-MemWal is a privacy-preserving, decentralized memory protocol for humans and AI agents — powered by Walrus and Sui. Store, recall, and share memory across apps, sessions, and agents.
+MemWal is a privacy-preserving, decentralized memory layer for humans and AI agents — powered by Walrus and Sui. Store, recall, and share memory across apps, sessions, and agents.
@@ -86,7 +86,7 @@ AI agents today lose context between sessions — every conversation starts from
## Use Cases
-MemWal fits any app or protocol that needs to store, retrieve, and update memory persistently:
+MemWal fits any app that needs to store, retrieve, and update memory persistently:
- **AI chat apps** — capture valuable knowledge from conversations so agents remember context across sessions
- **Note-taking and knowledge tools** — save user insights, summaries, and references as persistent, encrypted memory
@@ -113,7 +113,7 @@ The repo ships with ready-to-run apps in the [`/apps`](https://github.com/Comman
System overview, component responsibilities, core flows, data flow security
-
+
Quickstart, usage patterns, AI integration, and examples
@@ -125,7 +125,7 @@ The repo ships with ready-to-run apps in the [`/apps`](https://github.com/Comman
Event indexing, onchain events, database sync
-
+
SDK API, relayer API, configuration, environment variables
diff --git a/docs/indexer/database-sync.md b/docs/indexer/database-sync.md
index 63b6a3ac..1848a29c 100644
--- a/docs/indexer/database-sync.md
+++ b/docs/indexer/database-sync.md
@@ -2,15 +2,81 @@
title: "Database Sync"
---
-The indexer syncs account data into PostgreSQL so the relayer can resolve ownership quickly.
+The indexer syncs account data into PostgreSQL so the relayer can resolve ownership quickly without hitting the blockchain on every request.
-## Current Stored State
+## Database
-- `accounts`
-- `indexer_state`
+Both the relayer and the indexer connect to the same PostgreSQL instance (with the `pgvector` extension enabled). Migrations run automatically on boot.
-## Why It Helps
+## Tables
-- avoids repeated onchain registry scans during auth
-- keeps a resumable cursor for long-running event polling
-- makes account lookup effectively constant-time for the backend
+### `vector_entries`
+
+The primary search table — stores vector embeddings linked to encrypted Walrus blobs.
+
+| Column | Type | Description |
+|--------|------|-------------|
+| `id` | `TEXT` (PK) | UUID for this entry |
+| `owner` | `TEXT` | Owner's Sui address |
+| `namespace` | `TEXT` | Namespace label (default: `"default"`) |
+| `blob_id` | `TEXT` | Walrus blob ID pointing to the encrypted payload |
+| `embedding` | `vector(1536)` | 1536-dimensional vector embedding (pgvector) |
+| `created_at` | `TIMESTAMPTZ` | Insertion timestamp |
+
+**Indexes:**
+- `idx_vector_entries_owner` — B-tree on `owner`
+- `idx_vector_entries_blob_id` — B-tree on `blob_id`
+- `idx_vector_entries_owner_ns` — composite B-tree on `(owner, namespace)` for scoped queries
+- `idx_vector_entries_embedding` — HNSW on `embedding` using `vector_cosine_ops` for fast similarity search
+
+### `delegate_key_cache`
+
+Auth optimization — caches the mapping from delegate public key to account, so the relayer doesn't need to scan the onchain registry on every request.
+
+| Column | Type | Description |
+|--------|------|-------------|
+| `public_key` | `TEXT` (PK) | Hex-encoded Ed25519 public key |
+| `account_id` | `TEXT` | MemWalAccount object ID |
+| `owner` | `TEXT` | Owner's Sui address |
+| `cached_at` | `TIMESTAMPTZ` | When this mapping was cached |
+
+The cache is populated lazily during auth. If a cached entry becomes stale (key was removed onchain), the relayer re-resolves from the chain and updates the cache.
+
+### `accounts`
+
+Populated by the indexer — maps owner addresses to their MemWalAccount object IDs.
+
+| Column | Type | Description |
+|--------|------|-------------|
+| `account_id` | `TEXT` (PK) | MemWalAccount object ID |
+| `owner` | `TEXT` (unique) | Owner's Sui address |
+| `created_at` | `TIMESTAMPTZ` | When this row was indexed |
+
+### `indexer_state`
+
+Tracks the indexer's cursor position so it can resume from where it left off after restarts.
+
+| Column | Type | Description |
+|--------|------|-------------|
+| `key` | `TEXT` (PK) | State key (e.g., `"event_cursor"`) |
+| `value` | `TEXT` | JSON-serialized cursor (`txDigest` + `eventSeq`) |
+
+## How It Helps
+
+- **Constant-time account lookup** — the relayer checks `delegate_key_cache` and `accounts` instead of scanning the onchain registry
+- **Resumable event polling** — the indexer stores its cursor in `indexer_state`, so it picks up where it left off after restarts without re-processing old events
+- **Reactive cleanup** — when Walrus returns 404 for an expired blob during recall, the relayer deletes the corresponding `vector_entries` rows automatically
+
+## Similarity Search
+
+Recall queries use pgvector's cosine distance operator (`<=>`) against the HNSW index:
+
+```sql
+SELECT blob_id, (embedding <=> $1)::float8 AS distance
+FROM vector_entries
+WHERE owner = $2 AND namespace = $3
+ORDER BY embedding <=> $1
+LIMIT $4
+```
+
+The HNSW index provides approximate nearest neighbor search, which is fast enough for interactive recall even with large numbers of stored memories.
diff --git a/docs/indexer/onchain-events.md b/docs/indexer/onchain-events.md
index 80c338ab..6a7b6fa2 100644
--- a/docs/indexer/onchain-events.md
+++ b/docs/indexer/onchain-events.md
@@ -2,12 +2,20 @@
title: "Onchain Events"
---
-The current indexer listens to Sui events for the MemWal package and uses them to update local
-backend state.
+The indexer listens to Sui events emitted by the MemWal contract and uses them to update local backend state.
-## Current Event Coverage
+## Events
-- `AccountCreated`
+The MemWal contract emits the following events:
-The current service comment also points to delegate-key events as part of the broader V2 design,
-even though the main loop shown in the repo currently targets account creation flow first.
+| Event | Emitted when | Fields |
+|-------|-------------|--------|
+| `AccountCreated` | A new account is created | `account_id`, `owner` |
+| `DelegateKeyAdded` | A delegate key is added | `account_id`, `public_key`, `sui_address`, `label` |
+| `DelegateKeyRemoved` | A delegate key is removed | `account_id`, `public_key` |
+| `AccountDeactivated` | An account is frozen | `account_id`, `owner` |
+| `AccountReactivated` | A frozen account is unfrozen | `account_id`, `owner` |
+
+## Current Coverage
+
+The indexer currently targets the `AccountCreated` event flow as its primary sync path. Delegate key events and account activation events are part of the broader design and may be indexed in future iterations.
diff --git a/docs/indexer/purpose.md b/docs/indexer/purpose.md
index 1154bf78..5c00c67f 100644
--- a/docs/indexer/purpose.md
+++ b/docs/indexer/purpose.md
@@ -2,7 +2,52 @@
title: "Purpose"
---
-The indexer exists to keep backend account lookup fast.
+The indexer keeps the backend in sync with onchain state so the relayer can resolve accounts quickly.
-Instead of forcing the relayer to scan the chain for every request, the indexer listens to
-MemWal events and syncs the relevant account data into PostgreSQL.
+## Why It Exists
+
+Without the indexer, every authenticated request would require the relayer to scan the onchain `AccountRegistry` to find which `MemWalAccount` holds a given delegate key. This involves fetching the registry object, iterating through its dynamic fields, and checking each account — an expensive chain of RPC calls.
+
+The indexer eliminates this by listening to Sui events and syncing account data into PostgreSQL. The relayer can then resolve delegate key ownership with a single database lookup.
+
+## How It Works
+
+The indexer is a standalone Rust service (`services/indexer`) that:
+
+1. Connects to the same PostgreSQL database as the relayer
+2. Polls Sui blockchain events using `suix_queryEvents`
+3. Filters for `AccountCreated` events from the MemWal package
+4. Inserts `account_id → owner` mappings into the `accounts` table
+5. Stores its event cursor in `indexer_state` so it can resume after restarts
+
+## Auth Resolution Flow
+
+When the relayer receives a request, it resolves the delegate key's account using this priority:
+
+1. **PostgreSQL cache** (`delegate_key_cache`) — fastest, populated lazily by the relayer itself
+2. **Indexed accounts** (`accounts`) — populated by the indexer, enables account discovery without chain scans
+3. **Onchain registry scan** — fallback, scans `AccountRegistry` dynamic fields via RPC
+4. **Header hint** (`x-account-id`) — client-provided hint, useful during first-time setup
+5. **Config fallback** (`MEMWAL_ACCOUNT_ID`) — server-level default
+
+After successful resolution through any strategy, the mapping is cached in `delegate_key_cache` for future requests.
+
+## Configuration
+
+The indexer reads these environment variables:
+
+| Variable | Required | Default | Description |
+|----------|----------|---------|-------------|
+| `DATABASE_URL` | Yes | — | PostgreSQL connection string |
+| `MEMWAL_PACKAGE_ID` | Yes | — | MemWal contract package ID to filter events |
+| `SUI_RPC_URL` | No | Mainnet fullnode | Sui RPC endpoint |
+| `POLL_INTERVAL_SECS` | No | `5` | Seconds between event poll cycles |
+
+## Running
+
+```bash
+cd services/indexer
+cargo run
+```
+
+The indexer is recommended for production but optional for development — the relayer can fall back to onchain resolution without it.
diff --git a/docs/logo-dark.svg b/docs/logo-dark.svg
new file mode 100644
index 00000000..f9b0bb40
--- /dev/null
+++ b/docs/logo-dark.svg
@@ -0,0 +1,13 @@
+
diff --git a/docs/logo-light.svg b/docs/logo-light.svg
new file mode 100644
index 00000000..02124e7b
--- /dev/null
+++ b/docs/logo-light.svg
@@ -0,0 +1,13 @@
+
diff --git a/docs/reference/configuration.md b/docs/reference/configuration.md
index 71187c65..0dbf9188 100644
--- a/docs/reference/configuration.md
+++ b/docs/reference/configuration.md
@@ -14,6 +14,7 @@ Used by:
| Field | Required | Notes |
| --- | --- | --- |
| `key` | yes | Delegate private key in hex |
+| `accountId` | yes | MemWalAccount object ID on Sui |
| `serverUrl` | no | Relayer URL. Default: `http://localhost:8000` |
| `namespace` | no | Default memory boundary. Default: `"default"` |
@@ -21,7 +22,7 @@ Used by:
Used by:
-- `new MemWalManual(config)`
+- `MemWalManual.create(config)`
Core fields:
diff --git a/docs/reference/environment-variables.md b/docs/reference/environment-variables.md
index 23582b5c..ab4b171a 100644
--- a/docs/reference/environment-variables.md
+++ b/docs/reference/environment-variables.md
@@ -48,7 +48,7 @@ These are not all enforced at boot, but most real deployments need them.
- `SEAL_KEY_SERVERS` is required for the sidecar SEAL encrypt and decrypt path.
- `SUI_NETWORK` now drives the default RPC URL, Walrus endpoints, Walrus package ID, and upload relay selection.
- `MEMWAL_PACKAGE_ID` and `MEMWAL_REGISTRY_ID` are server env vars. Do not replace them with `VITE_*` app env vars.
-- For testnet, use `MEMWAL_PACKAGE_ID=0x12b28adbe55c25341f08b8ad9ac69462aab917048c7cd5b736d951200090ee3f` and `MEMWAL_REGISTRY_ID=0xfb8a1d298e2a73bdab353da3fcb3b16f68ab7d1f392f3a5c4944c747c026fc05`.
+- For testnet, use `MEMWAL_PACKAGE_ID=0xcf6ad755a1cdff7217865c796778fabe5aa399cb0cf2eba986f4b582047229c6` and `MEMWAL_REGISTRY_ID=0xe80f2feec1c139616a86c9f71210152e2a7ca552b20841f2e192f99f75864437`.
- Without `OPENAI_API_KEY`, the server can fall back to mock embeddings. That is useful for local testing, not for normal production behavior.
- The Rust server starts the TypeScript sidecar automatically.
- `/health` is the fastest way to confirm the relayer is up.
diff --git a/docs/reference/relayer-api.md b/docs/reference/relayer-api.md
deleted file mode 100644
index c2d584ac..00000000
--- a/docs/reference/relayer-api.md
+++ /dev/null
@@ -1,91 +0,0 @@
----
-title: "Relayer API Reference"
----
-
-The current Rust server exposes these routes from `services/server/src/main.rs`.
-
-See also:
-
-- [Environment Variables](/reference/environment-variables)
-- [Configuration](/reference/configuration)
-
-## Public
-
-### `GET /health`
-
-- Use for a simple service check
-
-Example response:
-
-```json
-{
- "status": "ok",
- "version": "..."
-}
-```
-
-## Protected
-
-### `POST /api/remember`
-
-- Store text for the authenticated owner and namespace
-
-```json
-{
- "text": "User prefers dark mode",
- "namespace": "demo"
-}
-```
-
-### `POST /api/recall`
-
-- Search and return plaintext results
-
-```json
-{
- "query": "What do we know about this user?",
- "limit": 10,
- "namespace": "demo"
-}
-```
-
-### `POST /api/remember/manual`
-
-- Register encrypted payload plus precomputed vector
-- Current backend expects `encrypted_data`, not a pre-existing `blob_id`
-
-### `POST /api/recall/manual`
-
-- Search with a precomputed vector
-- Returns `{ blob_id, distance }` hits
-
-### `POST /api/analyze`
-
-- Extract facts from text and store them as memories
-
-### `POST /api/ask`
-
-- Recall memories, inject them into an LLM prompt, and return an answer
-
-### `POST /api/restore`
-
-- Rebuild missing vector entries for one owner and namespace
-- Uses chain metadata plus blob discovery
-
-```json
-{
- "namespace": "demo",
- "limit": 50
-}
-```
-
-## Signed Headers
-
-The SDK signs requests and sends headers such as:
-
-- `x-public-key`
-- `x-signature`
-- `x-timestamp`
-
-The default SDK also sends `x-delegate-key` for backend flows that may require delegate-key-backed
-decrypt or restore behavior.
diff --git a/docs/reference/sdk-api.md b/docs/reference/sdk-api.md
deleted file mode 100644
index c7803094..00000000
--- a/docs/reference/sdk-api.md
+++ /dev/null
@@ -1,101 +0,0 @@
----
-title: "SDK API Reference"
----
-
-See also:
-
-- [Configuration](/reference/configuration)
-- [Relayer API](/reference/relayer-api)
-
-## `MemWal.create(config)`
-
-```ts
-MemWal.create(config: MemWalConfig): MemWal
-```
-
-Config:
-
-| Property | Type | Notes |
-| --- | --- | --- |
-| `key` | `string` | Ed25519 private key in hex |
-| `serverUrl?` | `string` | Relayer URL |
-| `namespace?` | `string` | Default namespace, fallback is `"default"` |
-
-For the full config surface, see [Configuration](/reference/configuration).
-
-## `MemWal`
-
-### `remember(text, namespace?)`
-
-- Store one memory through the relayer
-- Returns: `id`, `blob_id`, `owner`
-
-### `recall(query, limit?, namespace?)`
-
-- Search one owner-and-namespace boundary
-- Returns plaintext matches
-
-### `analyze(text, namespace?)`
-
-- Extract memorable facts from text
-- Stores each fact as memory
-
-### `restore(namespace, limit?)`
-
-- Rebuild missing indexed entries for one namespace
-- Use when local vector state is incomplete
-
-### `health()`
-
-- Check relayer health
-
-### `getPublicKeyHex()`
-
-- Return the public key for the current delegate key
-
-### Lower-Level `MemWal` Methods
-
-- `rememberManual({ blobId, vector, namespace? })`
-- `recallManual({ vector, limit?, namespace? })`
-- `embed(text)`
-
-These exist on the current SDK surface, but the main beta path is still `remember`, `recall`,
-`analyze`, and `restore`.
-
-## `MemWalManual`
-
-Import:
-
-```ts
-import { MemWalManual } from "@cmdoss/memwal/manual";
-```
-
-Main methods:
-
-- `rememberManual(text, namespace?)`
-- `recallManual(query, limit?, namespace?)`
-- `restore(namespace, limit?)`
-- `isWalletMode`
-
-Use this client when the app must handle embedding calls and local SEAL operations.
-
-Important config notes:
-
-- `suiNetwork` now defaults to `mainnet`
-- `sealKeyServers?` lets the client override the built-in SEAL key server list
-
-## `withMemWal`
-
-Import:
-
-```ts
-import { withMemWal } from "@cmdoss/memwal/ai";
-```
-
-Use it to add:
-
-- recall before generation
-- memory context injection
-- optional auto-save after generation
-
-See [Configuration](/reference/configuration) for middleware options.
diff --git a/docs/relayer/api-reference.md b/docs/relayer/api-reference.md
new file mode 100644
index 00000000..0476a90f
--- /dev/null
+++ b/docs/relayer/api-reference.md
@@ -0,0 +1,263 @@
+---
+title: "API Reference"
+---
+
+The Rust relayer exposes these routes. Routes are defined in `services/server/src/main.rs`.
+
+See also:
+
+- [Environment Variables](/reference/environment-variables)
+- [Configuration](/reference/configuration)
+
+## Authentication
+
+All `/api/*` routes require signed headers. The SDK handles this automatically.
+
+### Required Headers
+
+| Header | Description |
+|--------|-------------|
+| `x-public-key` | Hex-encoded Ed25519 public key (32 bytes) |
+| `x-signature` | Hex-encoded Ed25519 signature (64 bytes) |
+| `x-timestamp` | Unix timestamp in seconds (5-minute validity window) |
+
+### Optional Headers
+
+| Header | Description |
+|--------|-------------|
+| `x-account-id` | MemWalAccount object ID hint — speeds up account resolution when not cached |
+| `x-delegate-key` | Delegate private key (hex) — used by the default SDK for SEAL decrypt flows |
+
+### Signature Format
+
+The signed message is: `{timestamp}.{method}.{path}.{body_sha256}`
+
+The relayer verifies the Ed25519 signature, then resolves the owner by looking up the public key in onchain `MemWalAccount.delegate_keys`.
+
+## Public Routes
+
+### `GET /health`
+
+Service health check. No authentication required.
+
+**Response:**
+
+```json
+{
+ "status": "ok",
+ "version": "0.1.0"
+}
+```
+
+### `POST /sponsor`
+
+Proxy to the SEAL/Walrus sidecar's `/sponsor` endpoint for sponsored transactions. No authentication required.
+
+### `POST /sponsor/execute`
+
+Proxy to the sidecar's `/sponsor/execute` endpoint. No authentication required.
+
+## Protected Routes
+
+### `POST /api/remember`
+
+Store text as an encrypted memory. The relayer handles embedding, SEAL encryption, Walrus upload, and vector indexing.
+
+**Request:**
+
+```json
+{
+ "text": "User prefers dark mode",
+ "namespace": "demo"
+}
+```
+
+`namespace` defaults to `"default"` if omitted.
+
+**Response:**
+
+```json
+{
+ "id": "uuid",
+ "blob_id": "walrus-blob-id",
+ "owner": "0x...",
+ "namespace": "demo"
+}
+```
+
+### `POST /api/recall`
+
+Search for memories matching a natural language query. Returns decrypted plaintext results.
+
+**Request:**
+
+```json
+{
+ "query": "What do we know about this user?",
+ "limit": 10,
+ "namespace": "demo"
+}
+```
+
+`limit` defaults to `10`. `namespace` defaults to `"default"`.
+
+**Response:**
+
+```json
+{
+ "results": [
+ {
+ "blob_id": "walrus-blob-id",
+ "text": "User prefers dark mode",
+ "distance": 0.15
+ }
+ ],
+ "total": 1
+}
+```
+
+### `POST /api/remember/manual`
+
+Register a client-encrypted payload. The client sends SEAL-encrypted data (base64) and a precomputed embedding vector. The relayer uploads the encrypted bytes to Walrus and stores the vector mapping.
+
+**Request:**
+
+```json
+{
+ "encrypted_data": "base64-encoded-seal-encrypted-bytes",
+ "vector": [0.01, -0.02, ...],
+ "namespace": "demo"
+}
+```
+
+**Response:**
+
+```json
+{
+ "id": "uuid",
+ "blob_id": "walrus-blob-id",
+ "owner": "0x...",
+ "namespace": "demo"
+}
+```
+
+### `POST /api/recall/manual`
+
+Search with a precomputed query vector. Returns blob IDs and distances only — the client handles downloading and decrypting.
+
+**Request:**
+
+```json
+{
+ "vector": [0.01, -0.02, ...],
+ "limit": 10,
+ "namespace": "demo"
+}
+```
+
+**Response:**
+
+```json
+{
+ "results": [
+ {
+ "blob_id": "walrus-blob-id",
+ "distance": 0.15
+ }
+ ],
+ "total": 1
+}
+```
+
+### `POST /api/analyze`
+
+Extract facts from text using an LLM, then store each fact as a separate memory (embed, encrypt, upload, index).
+
+**Request:**
+
+```json
+{
+ "text": "I live in Hanoi and prefer dark mode.",
+ "namespace": "demo"
+}
+```
+
+**Response:**
+
+```json
+{
+ "facts": [
+ {
+ "text": "User lives in Hanoi",
+ "id": "uuid",
+ "blob_id": "walrus-blob-id"
+ },
+ {
+ "text": "User prefers dark mode",
+ "id": "uuid",
+ "blob_id": "walrus-blob-id"
+ }
+ ],
+ "total": 2,
+ "owner": "0x..."
+}
+```
+
+### `POST /api/ask`
+
+Recall memories, inject them into an LLM prompt, and return an AI-generated answer with the context used.
+
+**Request:**
+
+```json
+{
+ "question": "What do you know about my preferences?",
+ "limit": 5,
+ "namespace": "demo"
+}
+```
+
+`limit` defaults to `5`. `namespace` defaults to `"default"`.
+
+**Response:**
+
+```json
+{
+ "answer": "Based on your memories, you prefer dark mode and live in Hanoi.",
+ "memories_used": 2,
+ "memories": [
+ {
+ "blob_id": "walrus-blob-id",
+ "text": "User prefers dark mode",
+ "distance": 0.12
+ }
+ ]
+}
+```
+
+### `POST /api/restore`
+
+Rebuild missing vector entries for one namespace. Queries onchain blobs by owner and namespace, downloads from Walrus, decrypts, re-embeds, and re-indexes only the entries missing from the local database.
+
+**Request:**
+
+```json
+{
+ "namespace": "demo",
+ "limit": 50
+}
+```
+
+`limit` defaults to `50`.
+
+**Response:**
+
+```json
+{
+ "restored": 3,
+ "skipped": 7,
+ "total": 10,
+ "namespace": "demo",
+ "owner": "0x..."
+}
+```
diff --git a/docs/relayer/installation-and-setup.md b/docs/relayer/installation-and-setup.md
deleted file mode 100644
index 640213e7..00000000
--- a/docs/relayer/installation-and-setup.md
+++ /dev/null
@@ -1,106 +0,0 @@
----
-title: "Installation and Setup"
----
-
-The relayer is configured through environment variables and starts its sidecar automatically.
-
-## Main Environment Variables
-
-- `PORT`
-- `DATABASE_URL`
-- `OPENAI_API_KEY`
-- `OPENAI_API_BASE`
-- `SUI_NETWORK`
-- `SUI_RPC_URL`
-- `WALRUS_PUBLISHER_URL`
-- `WALRUS_AGGREGATOR_URL`
-- `SERVER_SUI_PRIVATE_KEY`
-- `SERVER_SUI_PRIVATE_KEYS`
-- `SEAL_KEY_SERVERS`
-- `MEMWAL_PACKAGE_ID`
-- `MEMWAL_REGISTRY_ID`
-- `WALRUS_PACKAGE_ID`
-- `WALRUS_UPLOAD_RELAY_URL`
-- `ENOKI_API_KEY`
-- `ENOKI_NETWORK`
-- `SIDECAR_URL`
-
-## Defaults That Matter
-
-- `PORT` defaults to `8000`
-- `SIDECAR_URL` defaults to `http://localhost:9000`
-- `SUI_RPC_URL` falls back to a network default based on `SUI_NETWORK`
-- `SUI_NETWORK` now defaults to `mainnet`
-- Walrus endpoints fall back to mainnet defaults if not overridden
-- `WALRUS_PACKAGE_ID` and `WALRUS_UPLOAD_RELAY_URL` also follow `SUI_NETWORK` if not set
-
-## Setup Checklist
-
-1. create `services/server/.env`
-2. set `DATABASE_URL`
-3. set `OPENAI_API_KEY` and, if needed, `OPENAI_API_BASE`
-4. set contract and network values
-5. set `SEAL_KEY_SERVERS`
-6. set Walrus endpoints
-7. set one server key or a key pool
-8. install `services/server/scripts` dependencies
-9. run `cargo run` in `services/server`
-
-## Contract IDs
-
-For a testnet relayer setup, use:
-
-```env
-SUI_NETWORK=testnet
-MEMWAL_PACKAGE_ID=0x12b28adbe55c25341f08b8ad9ac69462aab917048c7cd5b736d951200090ee3f
-MEMWAL_REGISTRY_ID=0xfb8a1d298e2a73bdab353da3fcb3b16f68ab7d1f392f3a5c4944c747c026fc05
-```
-
-Notes:
-
-- the relayer uses `MEMWAL_PACKAGE_ID` and `MEMWAL_REGISTRY_ID`
-- `MEMWAL_REGISTRY_ID` is still required by the current server config
-- `VITE_MEMWAL_PACKAGE_ID` and `VITE_MEMWAL_REGISTRY_ID` are frontend env vars for the app or playground
-
-## Embedding Provider
-
-- `OPENAI_API_KEY` is the server-side key used for embedding and fact extraction
-- `OPENAI_API_BASE` lets you point the relayer to an OpenAI-compatible provider such as OpenRouter
-- when these are set, the relayer calls the provider directly during `remember`, `recall`, `analyze`,
- `ask`, and restore re-indexing
-- without `OPENAI_API_KEY`, the relayer falls back to mock embeddings for local testing
-
-## SEAL Key Servers
-
-- `SEAL_KEY_SERVERS` is a comma-separated list of SEAL key server object IDs
-- the sidecar uses this list for backend SEAL encrypt and decrypt operations
-- the server no longer relies on hardcoded testnet key server IDs
-- make sure the list matches the selected `SUI_NETWORK`
-- for testnet setup, use https://seal-docs.wal.app/Pricing to find the current SEAL key server object IDs
-
-## Notes On Keys
-
-- `SERVER_SUI_PRIVATE_KEY` is the main server key
-- `SERVER_SUI_PRIVATE_KEYS` is a comma-separated key pool for parallel Walrus uploads
-- if both are set, the key pool takes priority for uploads
-
-## Database Behavior
-
-- the server connects to PostgreSQL on boot
-- migrations in `services/server/migrations` run automatically
-- `pgvector` must already be available in the database
-
-## Sidecar Behavior
-
-- the Rust server starts the TypeScript sidecar on boot
-- the sidecar handles backend SEAL and Walrus operations
-- if sidecar startup fails, the relayer will fail fast on boot
-
-## Operational Notes
-
-- `/health` is the basic service check
-- API routes live under `/api/*`
-- account lookup improves when the indexer is running
-- `OPENAI_API_KEY` + `OPENAI_API_BASE` control which embedding API the relayer calls
-- `SEAL_KEY_SERVERS` controls which SEAL key servers the sidecar trusts
-- without `OPENAI_API_KEY`, the server can fall back to mock embeddings, but that is not the normal production path
diff --git a/docs/relayer/overview.md b/docs/relayer/overview.md
index 631dc8b1..82cffa90 100644
--- a/docs/relayer/overview.md
+++ b/docs/relayer/overview.md
@@ -1,63 +1,76 @@
---
-title: "Relayer Overview"
+title: "Overview"
---
-The relayer turns signed SDK calls into memory operations.
+The relayer is the backend that turns SDK calls into memory operations. Using a delegate key signed by the client, it handles the critical workflows — embedding, encryption, storage, and search — on behalf of the user.
## What It Does
-- verifies delegate-key access
-- resolves owner and account context
-- stores and searches vectors by `owner + namespace`
-- coordinates SEAL and Walrus operations through the sidecar
-- runs `remember`, `recall`, `analyze`, `ask`, and `restore`
-- uses env-driven network config for RPC, Walrus, and SEAL sidecar behavior
+- **Authenticates requests** by verifying Ed25519 signatures against onchain delegate keys, then resolving the owner and account context
+- **Generates embeddings** for text using an OpenAI-compatible API (default model: `text-embedding-3-small`, 1536 dimensions)
+- **Encrypts and decrypts** data through the SEAL sidecar, bound to the owner's address and the MemWal package ID
+- **Uploads and downloads** encrypted blobs to Walrus, with the server wallet covering storage costs
+- **Stores and searches vectors** in PostgreSQL (pgvector), scoped by memory space (`owner + namespace`)
+- **Orchestrates higher-level flows** like `analyze` (LLM-based fact extraction using `gpt-4o-mini`) and `ask` (memory-augmented Q&A)
+- **Restores memory spaces** by querying onchain blobs, decrypting, re-embedding, and re-indexing anything missing from the local database
+- **Cleans up expired blobs** reactively — when Walrus returns 404 during recall, the relayer deletes the stale vector entries from the database
-## Trust Boundary
+## Architecture
-In the default SDK path, the relayer sees plaintext data because it handles encryption and embedding on your behalf. This is a deliberate trade-off for developer experience — it means Web2 developers don't need to manage cryptographic operations.
+The relayer is a Rust service (Axum) that manages a TypeScript sidecar process for SEAL and Walrus operations that require the `@mysten/seal` and `@mysten/walrus` SDKs.
+
+```mermaid
+flowchart LR
+ Client["SDK / App"]
+
+ %% ===== HOST =====
+ subgraph Host["Relayer Host"]
+ direction LR
-The relayer currently handles:
+ Axum["Rust Relayer (Axum)
Auth + routes"]
+ Sidecar["TypeScript Sidecar
SEAL + Walrus"]
-- embedding generation
-- encryption and decryption orchestration
-- Walrus upload and download orchestration
-- fact extraction for `analyze`
-- restore and re-index flows
+ %% container backend
+ subgraph Stack
+ direction TB
+ DB["PostgreSQL + pgvector"]
+ Sui["Sui RPC"]
+ AI["Embedding / LLM API"]
+ end
+ end
-If you need to minimize this trust, you can [self-host](/relayer/self-hosting) the relayer or use the [manual client flow](/sdk/usage) to handle encryption and embedding entirely on the client side. See [Trust & Security Model](/fundamentals/architecture/data-flow-security-model) for the full breakdown.
+ %% external
+ Seal["SEAL key servers"]
+ Walrus["Walrus"]
-## Network and Sidecar Config
+ %% flows
+ Client --> Axum
-- the relayer now defaults to `mainnet` network settings
-- `SUI_NETWORK` drives the default RPC URL and Walrus service endpoints
-- `SEAL_KEY_SERVERS` tells the sidecar which SEAL key server objects to use
-- self-hosted deployments can override Walrus package and upload relay defaults through env vars
+ %% chỉ nối vào container (qua node đầu)
+ Axum --> DB
-## Namespace Behavior
+ %% sidecar
+ Axum --> Sidecar
+ Sidecar --> Seal
+ Sidecar --> Walrus
+```
-- vector entries are stored by `owner + namespace`
-- Walrus uploads carry `memwal_namespace` metadata
-- restore runs one namespace at a time
+The sidecar is started automatically when the Rust server boots and communicates over HTTP on `localhost:9000` (configurable via `SIDECAR_URL`). If the sidecar fails to start, the relayer exits immediately.
-Namespace is recorded onchain through Walrus blob metadata during upload. It is not a separate
-MemWal contract object.
+## Key Pool
-## Restore Behavior
+For the `analyze` endpoint (which stores multiple facts concurrently), the relayer supports a pool of Sui private keys (`SERVER_SUI_PRIVATE_KEYS`). Each concurrent Walrus upload uses a different key from the pool in round-robin order, bypassing per-signer serialization and enabling parallel uploads.
-Restore is incremental:
+## Single-Instance Design
-1. query blobs for one owner and namespace
-2. compare with local DB state
-3. restore only missing entries
+Each relayer deployment is tied to a single MemWal package ID (`MEMWAL_PACKAGE_ID`). The package ID is used for SEAL encryption key derivation and Walrus blob metadata. Queries in the vector database are scoped by `owner + namespace`, while the package ID provides cross-deployment isolation at the encryption layer.
-## Routes
+
+The current relayer does not support multi-tenancy across multiple package IDs. If you deploy a separate MemWal contract, you need to run a separate relayer instance with its own database.
+
+
+## Trust Boundary
+
+In the default SDK path, the relayer sees plaintext data because it handles encryption and embedding on your behalf. This is a deliberate trade-off for developer experience — it means Web2 developers don't need to manage cryptographic operations.
-- `GET /health`
-- `POST /api/remember`
-- `POST /api/recall`
-- `POST /api/remember/manual`
-- `POST /api/recall/manual`
-- `POST /api/analyze`
-- `POST /api/ask`
-- `POST /api/restore`
+If you need to minimize this trust, you can [self-host](/relayer/self-hosting) the relayer or use the [manual client flow](/sdk/usage/memwal-manual) to handle encryption and embedding entirely on the client side. See [Trust & Security Model](/fundamentals/architecture/data-flow-security-model) for the full breakdown.
diff --git a/docs/relayer/public-relayer.md b/docs/relayer/public-relayer.md
index 79f30486..5d02bb50 100644
--- a/docs/relayer/public-relayer.md
+++ b/docs/relayer/public-relayer.md
@@ -2,42 +2,35 @@
title: "Public Relayer"
---
-The public relayer is the fastest way to evaluate MemWal during beta.
+The public relayer is a managed MemWal deployment for teams that want to get started without running infrastructure. If a public relayer endpoint is available for your environment, it gives you the fastest path to integration.
-## Use It When
+## Endpoints
-- you are testing the SDK
-- you want to validate namespace-aware flows quickly
-- you want to try `remember`, `recall`, `analyze`, and `restore` before self-hosting
+| | Value |
+|---|---|
+| **Relayer URL** | Provided by the relayer operator |
+| **Package ID** | Provided by the relayer operator |
+
+If you do not have these values yet, use a local or [self-hosted relayer](/relayer/self-hosting) instead.
## Minimal Config
```ts
-import { MemWal } from "@cmdoss/memwal";
+import { MemWal } from "@mysten/memwal";
const memwal = MemWal.create({
- key: process.env.MEMWAL_PRIVATE_KEY!,
- serverUrl: process.env.MEMWAL_SERVER_URL!,
+ key: "",
+ accountId: "",
+ serverUrl: "https://your-relayer-url.com",
namespace: "demo",
});
```
-## Good Evaluation Flow
-
-1. call `health()`
-2. store one memory with `remember()`
-3. retrieve it with `recall()`
-4. try `analyze()` on a longer passage
-5. use `restore()` only when you want to validate recovery behavior
-
-## Assume This
-
-- the public relayer is a managed beta surface
-- the documented routes are the supported surface
-- your integration should set a namespace explicitly
+## What to Know
-## Self-Host Instead If You Need
+- **Shared App ID** - all users of the public relayer share the same MemWal package ID. Your data is isolated by your own `owner + namespace` (Memory Space), but the underlying deployment is shared.
+- **Trust assumption** - the relayer sees plaintext during encryption and embedding. By using the public relayer, you're trusting the Mysten-hosted instance with that data. See [Trust & Security Model](/fundamentals/architecture/data-flow-security-model) for details.
+- **Availability** - the public relayer is a managed beta service. There are no SLA guarantees.
+- **Storage costs** - the server wallet covers Walrus storage fees. Usage limits may apply during beta.
-- your own infra and credentials
-- tighter operational guarantees
-- your own rollout control
+If you need full control over the trust boundary or your own dedicated instance, see [Self-Hosting](/relayer/self-hosting).
diff --git a/docs/relayer/self-hosting.md b/docs/relayer/self-hosting.md
index e76b6886..7121f330 100644
--- a/docs/relayer/self-hosting.md
+++ b/docs/relayer/self-hosting.md
@@ -1,143 +1,124 @@
---
-title: "Operate Your Own Relayer"
+title: "Self-Hosting"
---
-Run your own relayer when you need your own backend, secrets, and rollout control.
+Self-hosting means running your own relayer — either pointing at an existing MemWal package ID or deploying an entirely new MemWal instance with your own contract, database, and server wallet.
-## Use It When
+The public relayer provided by Mysten is a reference implementation. You can also build your own implementation that fits the same API surface with custom logic. This guide covers how to run the reference implementation as your own self-hosted relayer.
-- you want your own deployment environment
-- you want your own database and credentials
-- you want to control relayer upgrades and uptime
-- you want the server to use your own embedding provider credentials
+## When to Self-Host
-## What Runs
+The most common reasons are removing the trust assumption on a third-party relayer or running your own MemWal instance entirely:
+
+- **Control the trust boundary** — a self-hosted relayer keeps plaintext, encryption, and embedding under your own control
+- **Run your own MemWal instance** — deploy your own contract with a separate package ID, SEAL encryption keys, and data isolation
+- **Choose your own embedding provider** — use your own OpenAI-compatible API and credentials
+- **Guarantee availability** — the public relayer is a beta service with no SLA
-A self-hosted MemWal backend usually has:
+## What Runs
-- the Rust relayer in `services/server`
-- the TypeScript sidecar in `services/server/scripts`
-- PostgreSQL with pgvector
-- optional but recommended: the indexer in `services/indexer`
+A self-hosted MemWal backend has:
-## Local Run Flow
+| Component | Location | Description |
+|-----------|----------|-------------|
+| **Rust relayer** | `services/server` | Axum HTTP server — auth, routing, embedding, vector search |
+| **TypeScript sidecar** | `services/server/scripts` | SEAL encrypt/decrypt, Walrus upload, blob query (uses `@mysten/seal` and `@mysten/walrus`) |
+| **PostgreSQL + pgvector** | External | Vector storage, auth cache, indexer state |
+| **Indexer** (recommended) | `services/indexer` | Polls Sui events, syncs account data into PostgreSQL |
-1. create a PostgreSQL database with `pgvector`
-2. copy `services/server/.env.example` to `services/server/.env`
-3. fill in the required env vars
-4. install sidecar deps in `services/server/scripts`
-5. run the Rust server from `services/server`
-6. optionally run the indexer from `services/indexer`
+The Rust relayer starts the TypeScript sidecar as a child process on boot. They communicate over HTTP (`localhost:9000` by default). If the sidecar fails to start within 15 seconds, the relayer exits.
## Quick Start
-If you already have PostgreSQL + pgvector running, the shortest path is:
+If you do not already have PostgreSQL + pgvector running, start it with:
```bash
-cp services/server/.env.example services/server/.env
-cd services/server/scripts && npm ci
-cd ../ && cargo run
-cd ../indexer && cargo run
+docker compose -f services/server/docker-compose.yml up -d postgres
```
-Then check:
+Then run the relayer:
```bash
-curl http://localhost:8000/health
+cp services/server/.env.example services/server/.env
+cd services/server/scripts
+npm ci
+cd ..
+cargo run
```
-Use this quick start for local evaluation. For production operation, review the full env setup
-and key configuration below.
-
-## Testnet Contract IDs
-
-If you want to run your own relayer on testnet, use these server env vars:
+Then check:
-```env
-SUI_NETWORK=testnet
-MEMWAL_PACKAGE_ID=0x12b28adbe55c25341f08b8ad9ac69462aab917048c7cd5b736d951200090ee3f
-MEMWAL_REGISTRY_ID=0xfb8a1d298e2a73bdab353da3fcb3b16f68ab7d1f392f3a5c4944c747c026fc05
+```bash
+curl http://localhost:8000/health
```
-Important:
-
-- use `MEMWAL_PACKAGE_ID` and `MEMWAL_REGISTRY_ID` in `services/server/.env`
-- `VITE_MEMWAL_PACKAGE_ID` and `VITE_MEMWAL_REGISTRY_ID` are for the app or playground, not for the relayer
-- the current server config still requires `MEMWAL_REGISTRY_ID`
-
-If you want the relayer to create real embeddings, set:
+## Environment Variables
-- `OPENAI_API_KEY`
-- `OPENAI_API_BASE`
+### Required
-The relayer uses these values to call an OpenAI-compatible `/embeddings` API during `remember`,
-`recall`, `analyze`, `ask`, and restore re-indexing.
-
-You also need:
+- `DATABASE_URL`
+- `MEMWAL_PACKAGE_ID`
+- `MEMWAL_REGISTRY_ID`
+- `SERVER_SUI_PRIVATE_KEY` or `SERVER_SUI_PRIVATE_KEYS`
+- `SEAL_KEY_SERVERS` — comma-separated list of SEAL key server object IDs
-- `SEAL_KEY_SERVERS`
+### Recommended
-The sidecar uses this comma-separated list of object IDs for backend SEAL encrypt and decrypt.
+- `OPENAI_API_KEY` — enables real embeddings (falls back to mock embeddings without it)
+- `OPENAI_API_BASE` — point to an OpenAI-compatible provider like OpenRouter
-For testnet setup, use https://seal-docs.wal.app/Pricing to get the current SEAL key server object IDs.
+### Defaults
-## Commands
+- `PORT` defaults to `8000`
+- `SIDECAR_URL` defaults to `http://localhost:9000`
+- `SUI_NETWORK` defaults to `mainnet`
+- `SUI_RPC_URL`, Walrus endpoints, and `WALRUS_PACKAGE_ID` fall back to network defaults based on `SUI_NETWORK`
-Install sidecar dependencies:
+### Server Keys
-```bash
-cd services/server/scripts
-npm ci
-```
+- `SERVER_SUI_PRIVATE_KEY` is the main server key
+- `SERVER_SUI_PRIVATE_KEYS` is a comma-separated key pool for parallel Walrus uploads
+- if both are set, the key pool takes priority for uploads
-Start the relayer:
+## Testnet Contract IDs
-```bash
-cd services/server
-cargo run
+```env
+SUI_NETWORK=testnet
+MEMWAL_PACKAGE_ID=0xcf6ad755a1cdff7217865c796778fabe5aa399cb0cf2eba986f4b582047229c6
+MEMWAL_REGISTRY_ID=0xe80f2feec1c139616a86c9f71210152e2a7ca552b20841f2e192f99f75864437
```
-The server starts the sidecar automatically through `npx tsx sidecar-server.ts`.
-
-Start the indexer:
-
-```bash
-cd services/indexer
-cargo run
-```
+For SEAL key server object IDs on testnet, see https://seal-docs.wal.app/Pricing.
-## What To Expect
+
+`VITE_MEMWAL_PACKAGE_ID` and `VITE_MEMWAL_REGISTRY_ID` are frontend env vars for the app or playground — not for the relayer.
+
-- the relayer listens on `http://localhost:8000` by default
-- the sidecar listens on `http://localhost:9000` by default
-- the server runs DB migrations automatically on boot
-- `/health` is the first endpoint to test
+## Database Setup
-## Required For A Working Relayer
+The relayer requires PostgreSQL with the `pgvector` extension. The relayer runs migrations automatically on boot, creating these tables:
-- `DATABASE_URL`
-- `SUI_RPC_URL`
-- `WALRUS_PUBLISHER_URL`
-- `WALRUS_AGGREGATOR_URL`
-- `MEMWAL_PACKAGE_ID`
-- `MEMWAL_REGISTRY_ID`
-- `SERVER_SUI_PRIVATE_KEY` or `SERVER_SUI_PRIVATE_KEYS`
+- `vector_entries` — 1536-dimensional embeddings with HNSW index for cosine similarity search
+- `delegate_key_cache` — auth optimization (delegate key → account mapping)
+- `accounts` — populated by the indexer (account → owner mapping)
+- `indexer_state` — indexer cursor tracking
-## Recommended But Context-Dependent
+See [Database Sync](/indexer/database-sync) for the full schema.
-- `OPENAI_API_KEY`: lets the relayer call your embedding provider for real embeddings
-- `OPENAI_API_BASE`: use this when your provider is not the default OpenAI base URL
-- `SEAL_KEY_SERVERS`: required for backend SEAL encrypt and decrypt
-- indexer: recommended for fast account lookup, especially outside quick local testing
+## Operational Notes
-## Docker Path
+- The server starts the sidecar automatically on boot — if sidecar startup fails, the relayer will exit
+- DB migrations run automatically on boot (`pgvector` must already be installed as a PostgreSQL extension)
+- Connection pool: 10 max connections (relayer), 3 max connections (indexer)
+- `/health` is the basic service check, API routes live under `/api/*`
+- The indexer is recommended for fast account lookup in production — without it, the relayer falls back to onchain registry scans
+- Without `OPENAI_API_KEY`, the server uses deterministic mock embeddings (hash-based) — useful for local testing but not production
-If you want to deploy the relayer as a container, use:
+## Docker
- `services/server/Dockerfile` for the relayer
- `services/indexer/Dockerfile` for the indexer
## Read Next
-- [Installation and Setup](/relayer/installation-and-setup)
-- [Relayer API](/reference/relayer-api)
+- [Relayer API](/relayer/api-reference)
diff --git a/docs/sdk/ai-integration.md b/docs/sdk/ai-integration.md
index b6eb6dd5..559f0f3e 100644
--- a/docs/sdk/ai-integration.md
+++ b/docs/sdk/ai-integration.md
@@ -1,5 +1,5 @@
---
-title: "AI Integration"
+title: "@ai-sdk Integration"
---
MemWal includes an AI SDK integration for applications that already use model middleware.
@@ -8,11 +8,12 @@ MemWal includes an AI SDK integration for applications that already use model mi
```ts
import { generateText } from "ai";
-import { withMemWal } from "@cmdoss/memwal/ai";
+import { withMemWal } from "@mysten/memwal/ai";
import { openai } from "@ai-sdk/openai";
const model = withMemWal(openai("gpt-4o"), {
key: process.env.MEMWAL_PRIVATE_KEY!,
+ accountId: process.env.MEMWAL_ACCOUNT_ID!,
serverUrl: process.env.MEMWAL_SERVER_URL,
namespace: "chatbot-prod",
maxMemories: 5,
diff --git a/docs/sdk/api-reference.md b/docs/sdk/api-reference.md
new file mode 100644
index 00000000..c1f5cbc6
--- /dev/null
+++ b/docs/sdk/api-reference.md
@@ -0,0 +1,205 @@
+---
+title: "API Reference"
+---
+
+See also:
+
+- [Configuration](/reference/configuration)
+- [Relayer API](/relayer/api-reference)
+
+## `MemWal.create(config)`
+
+```ts
+MemWal.create(config: MemWalConfig): MemWal
+```
+
+Config:
+
+| Property | Type | Required | Default | Notes |
+| --- | --- | --- | --- | --- |
+| `key` | `string` | Yes | — | Ed25519 delegate private key in hex |
+| `accountId` | `string` | Yes | — | MemWalAccount object ID on Sui |
+| `serverUrl` | `string` | No | `http://localhost:8000` | Relayer URL |
+| `namespace` | `string` | No | `"default"` | Default namespace for memory isolation |
+
+For the full config surface, see [Configuration](/reference/configuration).
+
+## `MemWal` Methods
+
+### `remember(text, namespace?): Promise`
+
+Store one memory through the relayer. The relayer handles embedding, SEAL encryption, Walrus upload, and vector indexing.
+
+**Returns:**
+
+```ts
+{
+ id: string; // UUID for this entry
+ blob_id: string; // Walrus blob ID
+ owner: string; // Owner Sui address
+ namespace: string; // Namespace used
+}
+```
+
+### `recall(query, limit?, namespace?): Promise`
+
+Search for memories matching a natural language query, scoped to `owner + namespace`.
+
+- `limit` defaults to `10`
+
+**Returns:**
+
+```ts
+{
+ results: Array<{
+ blob_id: string; // Walrus blob ID
+ text: string; // Decrypted plaintext
+ distance: number; // Cosine distance (lower = more similar)
+ }>;
+ total: number;
+}
+```
+
+### `analyze(text, namespace?): Promise`
+
+Extract memorable facts from text using an LLM, then store each fact as a separate memory.
+
+**Returns:**
+
+```ts
+{
+ facts: Array<{
+ text: string; // Extracted fact
+ id: string; // UUID
+ blob_id: string; // Walrus blob ID
+ }>;
+ total: number;
+ owner: string;
+}
+```
+
+### `restore(namespace, limit?): Promise`
+
+Rebuild missing indexed entries for one namespace from Walrus. Incremental — only re-indexes blobs that aren't already in the local database.
+
+- `limit` defaults to `50`
+
+**Returns:**
+
+```ts
+{
+ restored: number; // Entries newly indexed
+ skipped: number; // Entries already in DB
+ total: number; // Total blobs found on-chain
+ namespace: string;
+ owner: string;
+}
+```
+
+### `health(): Promise`
+
+Check relayer health. Does not require authentication.
+
+**Returns:** `{ status: string, version: string }`
+
+### `getPublicKeyHex(): Promise`
+
+Return the hex-encoded public key for the current delegate key.
+
+### Lower-level methods
+
+These exist on the `MemWal` class for advanced use cases:
+
+| Method | Description |
+|--------|-------------|
+| `rememberManual({ blobId, vector, namespace? })` | Register a pre-uploaded blob ID with a pre-computed vector |
+| `recallManual({ vector, limit?, namespace? })` | Search with a pre-computed query vector (returns blob IDs, no decryption) |
+| `embed(text)` | Generate an embedding vector for text (no storage) |
+
+## `MemWalManual`
+
+```ts
+import { MemWalManual } from "@mysten/memwal/manual";
+```
+
+See [MemWalManual usage](/sdk/usage/memwal-manual) for the full setup and flow details.
+
+### `rememberManual(text, namespace?): Promise`
+
+Embed locally, SEAL encrypt locally, send encrypted payload + vector to relayer for Walrus upload and vector registration.
+
+### `recallManual(query, limit?, namespace?): Promise`
+
+Embed locally, search via relayer, download from Walrus, SEAL decrypt locally. Returns decrypted text results.
+
+### `restore(namespace, limit?): Promise`
+
+Same as `MemWal.restore()` — delegates to the relayer.
+
+### `isWalletMode: boolean`
+
+Whether this client uses a connected wallet signer (vs. raw keypair).
+
+### Config notes
+
+- `suiNetwork` defaults to `mainnet`
+- `sealKeyServers` lets the client override the built-in SEAL key server object IDs
+- All `@mysten/*` peer dependencies are loaded dynamically — only needed if you use `MemWalManual`
+
+## `withMemWal`
+
+```ts
+import { withMemWal } from "@mysten/memwal/ai";
+```
+
+Wraps a Vercel AI SDK model with automatic memory recall and save.
+
+**Before generation:**
+- Reads the last user message
+- Runs `recall()` against MemWal
+- Filters by minimum relevance (`minRelevance`, default `0.3`)
+- Injects matching memories into the prompt as a system message
+
+**After generation:**
+- Optionally runs `analyze()` on the user message (fire-and-forget)
+- Saves extracted facts asynchronously
+
+**Options** (extends `MemWalConfig`):
+
+| Option | Default | Description |
+|--------|---------|-------------|
+| `maxMemories` | `5` | Max memories to inject per request |
+| `autoSave` | `true` | Auto-save new facts from conversation |
+| `minRelevance` | `0.3` | Minimum similarity score (0–1) to include a memory |
+| `debug` | `false` | Enable debug logging |
+
+See [Configuration](/reference/configuration) for all options.
+
+## Account Management
+
+```ts
+import {
+ createAccount,
+ addDelegateKey,
+ removeDelegateKey,
+ generateDelegateKey,
+} from "@mysten/memwal/account";
+```
+
+| Function | Description |
+|----------|-------------|
+| `generateDelegateKey()` | Generate a new Ed25519 keypair (returns `privateKey`, `publicKey`, `suiAddress`) |
+| `createAccount(opts)` | Create a new MemWalAccount on-chain (one per Sui address) |
+| `addDelegateKey(opts)` | Add a delegate key to an account (owner only) |
+| `removeDelegateKey(opts)` | Remove a delegate key from an account (owner only) |
+
+## Utility Functions
+
+```ts
+import { delegateKeyToSuiAddress, delegateKeyToPublicKey } from "@mysten/memwal";
+```
+
+| Function | Description |
+|----------|-------------|
+| `delegateKeyToSuiAddress(privateKeyHex)` | Derive the Sui address from a delegate private key |
+| `delegateKeyToPublicKey(privateKeyHex)` | Get the 32-byte public key from a delegate private key |
diff --git a/docs/sdk/basic-usage.md b/docs/sdk/basic-usage.md
index c871e068..4d88389f 100644
--- a/docs/sdk/basic-usage.md
+++ b/docs/sdk/basic-usage.md
@@ -10,10 +10,11 @@ title: "Basic Usage"
## Code
```ts
-import { MemWal } from "@cmdoss/memwal";
+import { MemWal } from "@mysten/memwal";
const memwal = MemWal.create({
key: process.env.MEMWAL_PRIVATE_KEY!,
+ accountId: process.env.MEMWAL_ACCOUNT_ID!,
serverUrl: process.env.MEMWAL_SERVER_URL,
namespace: "demo",
});
diff --git a/docs/sdk/examples.md b/docs/sdk/examples.md
new file mode 100644
index 00000000..c3be717f
--- /dev/null
+++ b/docs/sdk/examples.md
@@ -0,0 +1,72 @@
+---
+title: "Examples"
+---
+
+## Basic: Store and Recall
+
+The shortest working MemWal example using the default relayer-backed SDK.
+
+```ts
+import { MemWal } from "@mysten/memwal";
+
+const memwal = MemWal.create({
+ key: process.env.MEMWAL_PRIVATE_KEY!,
+ accountId: process.env.MEMWAL_ACCOUNT_ID!,
+ serverUrl: process.env.MEMWAL_SERVER_URL,
+ namespace: "demo",
+});
+
+await memwal.health();
+
+const stored = await memwal.remember(
+ "User prefers dark mode and works in TypeScript."
+);
+
+const recalled = await memwal.recall(
+ "What do we know about this user?",
+ 5
+);
+
+console.log(stored.blob_id);
+console.log(recalled.results);
+```
+
+What you should see:
+
+- `health()` succeeds
+- `remember()` returns a `blob_id`
+- `recall()` returns plaintext results for the same namespace
+
+## Advanced: Manual Methods and Analyze
+
+### Manual Registration
+
+Use `rememberManual()` when you already have an encrypted payload plus vector, and `recallManual()`
+when you already have a query vector.
+
+### Fact Extraction
+
+Use `analyze()` when you want the relayer to extract facts from longer text and store them as
+memories.
+
+```ts
+const analyzed = await memwal.analyze(
+ "I live in Hanoi, prefer dark mode, and usually work late at night."
+);
+console.log(analyzed.facts);
+```
+
+### AI Middleware
+
+Use `withMemWal` when you want recall before generation and optional auto-save after generation.
+See [AI Integration](/sdk/ai-integration) for the full setup.
+
+## Research App Pattern
+
+Use this when you want to store structured research findings and recall them in later sessions.
+
+1. Save a structured summary with `remember()`
+2. Generate targeted queries later
+3. Use `recall()` to pull relevant findings back into context
+
+Structured summaries usually recall better than raw transcripts because they keep the signal high.
diff --git a/docs/sdk/overview.md b/docs/sdk/overview.md
index 190cb873..32e8f307 100644
--- a/docs/sdk/overview.md
+++ b/docs/sdk/overview.md
@@ -1,10 +1,10 @@
---
-title: "SDK Overview"
+title: "Overview"
---
MemWal exposes three SDK surfaces.
-## `@cmdoss/memwal`
+## `@mysten/memwal`
Use this first.
@@ -13,25 +13,25 @@ Use this first.
- main methods: `remember`, `recall`, `analyze`, `restore`, `health`
```ts
-import { MemWal } from "@cmdoss/memwal";
+import { MemWal } from "@mysten/memwal";
```
-## `@cmdoss/memwal/manual`
+## `@mysten/memwal/manual`
Use this when the client must handle embeddings and local SEAL operations.
- relayer still handles upload relay, registration, search, and restore
```ts
-import { MemWalManual } from "@cmdoss/memwal/manual";
+import { MemWalManual } from "@mysten/memwal/manual";
```
-## `@cmdoss/memwal/ai`
+## `@mysten/memwal/ai`
Use this when you already use the AI SDK.
```ts
-import { withMemWal } from "@cmdoss/memwal/ai";
+import { withMemWal } from "@mysten/memwal/ai";
```
## Namespace
@@ -40,7 +40,7 @@ Both clients support a default namespace. If you omit it, it falls back to `"def
## Recommended Path
-1. start with `MemWal`
-2. set a namespace explicitly
-3. validate `remember`, `recall`, `analyze`, and `restore`
-4. move to `MemWalManual` only if you need client-managed embeddings and local SEAL work
+1. Start with `MemWal`
+2. Set a namespace explicitly
+3. Validate `remember`, `recall`, `analyze`, and `restore`
+4. Move to `MemWalManual` only if you need client-managed embeddings and local SEAL work
diff --git a/docs/sdk/quick-start.md b/docs/sdk/quick-start.md
index bb148bca..a3abb84b 100644
--- a/docs/sdk/quick-start.md
+++ b/docs/sdk/quick-start.md
@@ -1,56 +1,101 @@
---
title: "Quick Start"
+description: "Install the MemWal SDK and store your first memory in under a minute."
---
-This example uses the default relayer-backed client.
+The MemWal SDK gives your app persistent, encrypted memory — store, recall, and analyze context across sessions. It exposes three entry points:
-```ts
-import { MemWal } from "@cmdoss/memwal";
+| Entry point | Import | When to use |
+| --- | --- | --- |
+| `MemWal` | `@mysten/memwal` | **Recommended default** for most integrations — relayer handles embeddings, SEAL, and storage |
+| `MemWalManual` | `@mysten/memwal/manual` | You need client-managed embeddings and local SEAL operations |
+| `withMemWal` | `@mysten/memwal/ai` | You already use the Vercel AI SDK and want memory as middleware |
-const memwal = MemWal.create({
- key: process.env.MEMWAL_PRIVATE_KEY!,
- serverUrl: process.env.MEMWAL_SERVER_URL,
- namespace: process.env.MEMWAL_NAMESPACE ?? "demo",
-});
+## Installation
-await memwal.health();
-await memwal.remember("I live in Hanoi and prefer dark mode.");
+
-const recall = await memwal.recall("What do we know about this user?");
-console.log(recall.results);
+```bash npm
+npm install @mysten/memwal
+```
-const analyzed = await memwal.analyze(
- "I live in Hanoi, prefer dark mode, and usually work late at night."
-);
-console.log(analyzed.facts);
+```bash pnpm
+pnpm add @mysten/memwal
```
-## Good Namespace Examples
+```bash yarn
+yarn add @mysten/memwal
+```
-- `chatbot-prod`
-- `researcher-staging`
-- `support-agent`
+
-Avoid keeping everything in `"default"` after early testing.
+For `MemWalManual`, you also need the optional peer dependencies:
-## What Happens
+
-- the SDK signs each request
-- the relayer verifies delegate access
-- data is stored and searched by `owner + namespace`
-- the relayer coordinates embeddings, SEAL, Walrus, and vector indexing
+```bash npm
+npm install @mysten/sui @mysten/seal @mysten/walrus
+```
-## Restore Example
+```bash pnpm
+pnpm add @mysten/sui @mysten/seal @mysten/walrus
+```
-```ts
-const result = await memwal.restore("demo");
-console.log(result);
+```bash yarn
+yarn add @mysten/sui @mysten/seal @mysten/walrus
+```
+
+
+
+For `withMemWal`, you also need:
+
+
+
+```bash npm
+npm install ai zod
+```
+
+```bash pnpm
+pnpm add ai zod
```
-Use restore when the relayer needs to rebuild missing indexed state for one namespace.
+```bash yarn
+yarn add ai zod
+```
+
+
+
+## Configuration
+
+`MemWal.create` takes a config object with the following fields:
+
+| Property | Type | Required | Description |
+| --- | --- | --- | --- |
+| `key` | `string` | Yes | Ed25519 private key in hex |
+| `accountId` | `string` | Yes | MemWalAccount object ID on Sui |
+| `serverUrl` | `string` | No | Relayer URL |
+| `namespace` | `string` | No | Default namespace — falls back to `"default"` |
+
+## First Memory
+
+```ts
+import { MemWal } from "@mysten/memwal";
+
+const memwal = MemWal.create({
+ key: "",
+ accountId: "",
+ serverUrl: "https://your-relayer-url.com",
+ namespace: "demo",
+});
+
+await memwal.health();
+await memwal.remember("I live in Hanoi and prefer dark mode.");
+
+const result = await memwal.recall("What do we know about this user?");
+console.log(result.results);
+```
## Next Steps
-- [SDK Usage](/sdk/usage)
-- [AI Integration](/sdk/ai-integration)
-- [SDK API Reference](/reference/sdk-api)
+- [Usage](/sdk/usage) — all three clients in detail, namespace rules, and restore
+- [API Reference](/sdk/api-reference) — full method signatures and config fields
diff --git a/docs/sdk/usage.md b/docs/sdk/usage.md
index 13f81e22..0318feaa 100644
--- a/docs/sdk/usage.md
+++ b/docs/sdk/usage.md
@@ -1,136 +1,20 @@
---
title: "Usage"
+description: "Detailed usage for all three MemWal clients — MemWal, MemWalManual, and withMemWal."
---
-This page lists the current public SDK surface in one place.
+MemWal exposes three entry points:
-## Namespace Rules
-
-- set a default namespace in `create(...)` when one app or tenant uses one boundary
-- pass `namespace` per call when one client needs multiple boundaries
-- if omitted, namespace falls back to client config, then to `"default"`
-
-## `MemWal`
-
-Use `MemWal` when you want the relayer to handle the main workflow.
-
-### Create
-
-```ts
-const memwal = MemWal.create({
- key: process.env.MEMWAL_PRIVATE_KEY!,
- serverUrl: process.env.MEMWAL_SERVER_URL,
- namespace: "chatbot-prod",
-});
-```
-
-Config:
-
-- `key`
-- `serverUrl?`
-- `namespace?`
-
-### Main Methods
-
-- `remember(text, namespace?)`: store text as memory
-- `recall(query, limit?, namespace?)`: return decrypted matches
-- `analyze(text, namespace?)`: extract facts and store them
-- `restore(namespace, limit?)`: rebuild missing indexed entries for one namespace
-- `health()`: check relayer health
-- `getPublicKeyHex()`: return the current public key
-
-### Lower-Level Methods
-
-- `rememberManual({ blobId, vector, namespace? })`
-- `recallManual({ vector, limit?, namespace? })`
-- `embed(text)`
-
-### Restore
-
-```ts
-const result = await memwal.restore("chatbot-prod", 50);
-console.log(result);
-```
-
-Restore is:
-
-- incremental
-- namespace-scoped
-- meant to repair PostgreSQL vector state from Walrus-backed memory
-
-## `MemWalManual`
+| Entry point | Import | When to use |
+| --- | --- | --- |
+| `MemWal` | `@mysten/memwal` | **Recommended default** — relayer handles embeddings, SEAL, and storage |
+| `MemWalManual` | `@mysten/memwal/manual` | You need client-managed embeddings and local SEAL operations |
+| `withMemWal` | `@mysten/memwal/ai` | You already use the Vercel AI SDK and want memory as middleware |
-Use `MemWalManual` when the client must handle embeddings and local SEAL operations.
-
-### Create
-
-```ts
-const manual = MemWalManual.create({
- key: process.env.MEMWAL_PRIVATE_KEY!,
- serverUrl: process.env.MEMWAL_SERVER_URL,
- suiPrivateKey: process.env.SUI_PRIVATE_KEY!,
- embeddingApiKey: process.env.OPENAI_API_KEY!,
- packageId: process.env.MEMWAL_PACKAGE_ID!,
- accountId: process.env.MEMWAL_ACCOUNT_ID!,
- namespace: "chatbot-prod",
-});
-```
-
-Key config fields:
-
-- `key`
-- `serverUrl?`
-- `suiPrivateKey?` or `walletSigner?`
-- `suiNetwork?`
-- `sealKeyServers?`
-- `embeddingApiKey`
-- `embeddingApiBase?`
-- `embeddingModel?`
-- `packageId`
-- `accountId`
-- `namespace?`
-
-Manual mode notes:
-
-- `suiNetwork` defaults to `mainnet`
-- `sealKeyServers` lets the client override the built-in SEAL key server object IDs
-- Walrus publisher, aggregator, and upload relay defaults now follow `suiNetwork`
-
-### Main Methods
-
-- `rememberManual(text, namespace?)`: embed locally, encrypt locally, then send encrypted payload plus vector to the relayer
-- `recallManual(query, limit?, namespace?)`: embed locally, search through the relayer, download blobs, and decrypt locally
-- `restore(namespace, limit?)`: call the same relayer restore endpoint
-- `isWalletMode`: tells you whether the client uses a connected wallet signer
-
-## `withMemWal`
-
-Use `withMemWal(model, options)` when your app already uses the AI SDK.
-
-```ts
-const model = withMemWal(openai("gpt-4o"), {
- key: process.env.MEMWAL_PRIVATE_KEY!,
- serverUrl: process.env.MEMWAL_SERVER_URL,
- namespace: "chatbot-prod",
-});
-```
-
-Behavior:
-
-- recall before generation
-- inject memory context
-- optional `analyze()` after generation
-
-Options:
-
-- `key`, `serverUrl?`, `namespace?`
-- `maxMemories?`
-- `autoSave?`
-- `minRelevance?`
-- `debug?`
+## Namespace Rules
-## Recommended Paths
+- Set a default namespace in `create(...)` when one app or tenant uses one boundary
+- Pass `namespace` per call when one client needs multiple boundaries
+- If omitted, namespace falls back to client config, then to `"default"`
-- `MemWal`: best default for most integrations
-- `MemWalManual`: use when you need client-managed embeddings and local SEAL work
-- `withMemWal`: use when you already run the AI SDK
+Good namespace examples: `todo`, `personal`, `password`, `project-x`. Avoid keeping everything in `"default"` after early testing.
diff --git a/docs/sdk/usage/memwal-manual.md b/docs/sdk/usage/memwal-manual.md
new file mode 100644
index 00000000..a7f70c49
--- /dev/null
+++ b/docs/sdk/usage/memwal-manual.md
@@ -0,0 +1,100 @@
+---
+title: "MemWalManual"
+description: "Client-managed embeddings and local SEAL operations."
+---
+
+Use when the client must handle embedding calls and local SEAL operations. The relayer still handles
+upload relay, vector registration, search, and restore.
+
+This is the recommended path for Web3-native users who want to minimize trust in the relayer — it never sees your plaintext data.
+
+## What the client handles vs. what the relayer handles
+
+| Operation | Client (MemWalManual) | Relayer |
+|-----------|----------------------|---------|
+| Embedding | Client calls OpenAI/compatible API | — |
+| SEAL encryption | Client encrypts locally | — |
+| Walrus upload | — | Server uploads via sidecar (server pays gas) |
+| Vector registration | — | Server stores `{blob_id, vector}` in PostgreSQL |
+| Recall search | — | Server searches vectors, returns `{blob_id, distance}` |
+| Walrus download | Client downloads from aggregator | — |
+| SEAL decryption | Client decrypts locally (SessionKey) | — |
+
+## Setup
+
+```ts
+import { MemWalManual } from "@mysten/memwal/manual";
+
+const manual = MemWalManual.create({
+ key: "",
+ serverUrl: "https://your-relayer-url.com",
+ suiPrivateKey: "", // OR walletSigner
+ embeddingApiKey: "",
+ packageId: "",
+ accountId: "",
+ namespace: "chatbot-prod",
+});
+```
+
+## Core Methods
+
+```ts
+// Embed locally, encrypt locally, relay encrypted payload + vector
+await manual.rememberManual("User prefers dark mode.");
+
+// Embed locally, search via relayer, download and decrypt locally
+const result = await manual.recallManual("What do we know?", 5);
+for (const memory of result.results) {
+ console.log(memory.text, memory.distance);
+}
+
+// Same relayer restore endpoint
+await manual.restore("chatbot-prod", 50);
+
+// Check if using a connected wallet signer
+console.log(manual.isWalletMode);
+```
+
+## Remember flow (under the hood)
+
+1. Client generates embedding via OpenAI-compatible API
+2. Client SEAL-encrypts the plaintext locally (no wallet signature needed)
+3. Client sends `{encrypted_data (base64), vector}` to the relayer
+4. Relayer uploads encrypted bytes to Walrus via upload-relay sidecar (server pays gas)
+5. Relayer stores `{blob_id, vector, owner, namespace}` in PostgreSQL
+
+## Recall flow (under the hood)
+
+1. Client generates query embedding via OpenAI-compatible API
+2. Client sends the vector to the relayer
+3. Relayer searches PostgreSQL and returns `{blob_id, distance}` hits
+4. Client downloads all matching encrypted blobs from Walrus concurrently
+5. Client creates a single SEAL SessionKey (one wallet popup in browser mode)
+6. Client decrypts each blob locally using the shared session key
+
+## Browser Integration (wallet signer)
+
+Use `walletSigner` instead of `suiPrivateKey` when integrating with a connected wallet (e.g., `@mysten/dapp-kit`):
+
+```ts
+const manual = MemWalManual.create({
+ key: "",
+ walletSigner: {
+ address: walletAddress,
+ signAndExecuteTransaction: signAndExecuteTransaction,
+ signPersonalMessage: signPersonalMessage,
+ },
+ embeddingApiKey: "",
+ packageId: "",
+ accountId: "",
+});
+```
+
+## Config Notes
+
+- `suiNetwork` defaults to `mainnet`
+- `sealKeyServers` lets the client override the built-in SEAL key server object IDs
+- Walrus publisher, aggregator, and upload relay defaults follow `suiNetwork`
+- `embeddingModel` defaults to `text-embedding-3-small` (or `openai/text-embedding-3-small` for OpenRouter)
+- `walrusEpochs` defaults to `50` (storage duration)
+- All `@mysten/*` peer dependencies are loaded dynamically — users who only use the default `MemWal` client don't need them installed
diff --git a/docs/sdk/usage/memwal.md b/docs/sdk/usage/memwal.md
new file mode 100644
index 00000000..85919ed0
--- /dev/null
+++ b/docs/sdk/usage/memwal.md
@@ -0,0 +1,60 @@
+---
+title: "MemWal"
+description: "The recommended default client — relayer handles embeddings, SEAL, and storage."
+---
+
+The recommended default client. The relayer handles embeddings, SEAL encryption, Walrus upload, and vector indexing.
+
+## How It Works
+
+1. The SDK signs each request with your delegate key
+2. The relayer verifies delegate access
+3. `remember` encrypts via SEAL, uploads to Walrus, and indexes the vector embedding
+4. `recall` searches by Memory Space and returns decrypted matches
+
+```ts
+import { MemWal } from "@mysten/memwal";
+
+const memwal = MemWal.create({
+ key: "",
+ accountId: "",
+ serverUrl: "https://your-relayer-url.com",
+ namespace: "chatbot-prod",
+});
+```
+
+## Core Methods
+
+```ts
+// Store a memory
+await memwal.remember("User prefers dark mode and works in TypeScript.");
+
+// Recall relevant memories
+const result = await memwal.recall("What do we know about this user?", 5);
+
+// Extract and store facts from longer text
+const analyzed = await memwal.analyze(
+ "I live in Hanoi, prefer dark mode, and usually work late at night."
+);
+console.log(analyzed.facts);
+
+// Check relayer health
+await memwal.health();
+```
+
+## Restore
+
+Rebuild missing indexed entries for one namespace. Incremental, namespace-scoped, and meant to
+repair PostgreSQL vector state from Walrus-backed memory.
+
+```ts
+const result = await memwal.restore("chatbot-prod", 50);
+```
+
+## Lower-Level Methods
+
+Use these when you already have a vector or encrypted payload:
+
+- `rememberManual({ blobId, vector, namespace? })`
+- `recallManual({ vector, limit?, namespace? })`
+- `embed(text)`
diff --git a/docs/sdk/usage/with-memwal.md b/docs/sdk/usage/with-memwal.md
new file mode 100644
index 00000000..2788e0c6
--- /dev/null
+++ b/docs/sdk/usage/with-memwal.md
@@ -0,0 +1,51 @@
+---
+title: "withMemWal"
+description: "Drop-in memory middleware for Vercel AI SDK apps."
+---
+
+Drop-in memory middleware for Vercel AI SDK apps.
+
+```ts
+import { generateText } from "ai";
+import { withMemWal } from "@mysten/memwal/ai";
+import { openai } from "@ai-sdk/openai";
+
+const model = withMemWal(openai("gpt-4o"), {
+ key: "",
+ accountId: "",
+ serverUrl: "https://your-relayer-url.com",
+ namespace: "chatbot-prod",
+ maxMemories: 5,
+ autoSave: true,
+});
+
+const result = await generateText({
+ model,
+ messages: [{ role: "user", content: "What do you know about me?" }],
+});
+```
+
+## What It Does
+
+Before generation:
+
+- Reads the last user message
+- Runs `recall()` against MemWal
+- Filters by relevance
+- Injects memory context into the prompt
+
+After generation:
+
+- Optionally runs `analyze()` on the user message
+- Saves extracted facts asynchronously
+
+Set a namespace explicitly for each product surface that uses the middleware. Otherwise recalled
+and auto-saved memories fall back to `"default"`.
+
+## When To Use Direct SDK Calls Instead
+
+Use direct SDK methods when your app needs precise control over:
+
+- When memory is stored
+- Which text is analyzed
+- How recall results are displayed or filtered
diff --git a/package.json b/package.json
index 0bb33b6a..b1b19a23 100644
--- a/package.json
+++ b/package.json
@@ -4,8 +4,8 @@
"private": true,
"type": "module",
"scripts": {
- "build:sdk": "pnpm --filter @cmdoss/memwal build",
- "dev:sdk": "pnpm --filter @cmdoss/memwal dev",
+ "build:sdk": "pnpm --filter @mysten/memwal build",
+ "dev:sdk": "pnpm --filter @mysten/memwal dev",
"dev:noter": "pnpm --filter noter dev",
"dev:chatbot": "pnpm --filter chatbot dev",
"dev:app": "pnpm --filter app dev",
@@ -17,7 +17,7 @@
"changeset": "changeset",
"changeset:add": "changeset add",
"version": "changeset version",
- "release": "pnpm build:sdk && changeset publish"
+ "release": "changeset publish"
},
"devDependencies": {
"@changesets/changelog-github": "^0.5.2",
diff --git a/packages/sdk/README.md b/packages/sdk/README.md
index 2d24d5ef..e932990a 100644
--- a/packages/sdk/README.md
+++ b/packages/sdk/README.md
@@ -1,16 +1,13 @@
-# @cmdoss/memwal
+# @mysten/memwal
-Privacy-first AI memory SDK. Stores encrypted memories on Walrus (decentralized storage) and
-retrieves them via semantic search.
+Privacy-first AI memory SDK for storing encrypted memories on Walrus and retrieving them with semantic search.
-> MemWal is currently in beta. It works today, but rough edges and operational guidance may still
-> evolve. Feedback and contributions are welcome while we harden the protocol and developer
-> experience.
+> MemWal is currently in beta and actively evolving. While fully usable today, we continue to refine the developer experience and operational guidance. We welcome feedback from early builders as we continue to improve the product.
## Install
```bash
-pnpm add @cmdoss/memwal
+pnpm add @mysten/memwal
```
Peer dependencies (install as needed):
@@ -22,11 +19,12 @@ pnpm add @mysten/sui @mysten/seal @mysten/walrus ai zod
## Quick Start
```ts
-import { MemWal } from "@cmdoss/memwal";
+import { MemWal } from "@mysten/memwal";
const memwal = MemWal.create({
key: "your-delegate-key-hex",
- serverUrl: "https://your-memwal-server.com",
+ accountId: "your-memwal-account-id",
+ serverUrl: "https://your-relayer-url.com",
namespace: "demo",
});
@@ -35,13 +33,15 @@ const memories = await memwal.recall("What are the user's preferences?");
await memwal.restore("demo");
```
+If you are self-hosting the relayer and do not have an account ID yet, see [Self-Hosting](../../docs/relayer/self-hosting.md) for the account creation and delegate key setup flow.
+
## Exports
| Entry | Description |
|---|---|
-| `@cmdoss/memwal` | Default client (`MemWal`). The relayer handles embedding, encryption, Walrus upload/download, retrieval, and restore. |
-| `@cmdoss/memwal/manual` | Manual client flow (`MemWalManual`). You handle embedding calls and local SEAL operations. The relayer still handles upload relay, registration, search, and restore. |
-| `@cmdoss/memwal/ai` | Vercel AI SDK integration - wraps `MemWal` as middleware for use with `streamText`, `generateText`, etc. |
+| `@mysten/memwal` | Default client (`MemWal`). The relayer handles embedding, encryption, Walrus upload/download, retrieval, and restore. |
+| `@mysten/memwal/manual` | Manual client flow (`MemWalManual`). You handle embedding calls and local SEAL operations. The relayer still handles upload relay, registration, search, and restore. |
+| `@mysten/memwal/ai` | Vercel AI SDK integration - wraps `MemWal` as middleware for use with `streamText`, `generateText`, etc. |
## How It Works
@@ -52,4 +52,4 @@ await memwal.restore("demo");
## License
-MIT
+Apache 2.0
diff --git a/packages/sdk/package.json b/packages/sdk/package.json
index ca2e7a04..3b822cf2 100644
--- a/packages/sdk/package.json
+++ b/packages/sdk/package.json
@@ -1,6 +1,6 @@
{
- "name": "@cmdoss/memwal",
- "version": "2.0.0-alpha.5",
+ "name": "@mysten/memwal",
+ "version": "0.0.1-dev.0",
"description": "MemWal — Privacy-first AI memory SDK with Ed25519 delegate key auth",
"type": "module",
"main": "./dist/index.js",
@@ -75,5 +75,8 @@
"ed25519",
"tee"
],
- "license": "MIT"
-}
+ "license": "MIT",
+ "publishConfig": {
+ "access": "public",
+ "registry": "https://registry.npmjs.org/"
+ }}
diff --git a/packages/sdk/src/account-entry.ts b/packages/sdk/src/account-entry.ts
index bc5a5f37..1d463322 100644
--- a/packages/sdk/src/account-entry.ts
+++ b/packages/sdk/src/account-entry.ts
@@ -1,12 +1,12 @@
/**
- * @cmdoss/memwal/account
+ * @mysten/memwal/account
*
* Account management entry point — on-chain operations.
* Requires @mysten/sui as a peer dependency.
*
* @example
* ```typescript
- * import { createAccount, addDelegateKey, generateDelegateKey } from "@cmdoss/memwal/account"
+ * import { createAccount, addDelegateKey, generateDelegateKey } from "@mysten/memwal/account"
* ```
*/
diff --git a/packages/sdk/src/account.ts b/packages/sdk/src/account.ts
index 53d13447..e435d4fc 100644
--- a/packages/sdk/src/account.ts
+++ b/packages/sdk/src/account.ts
@@ -6,7 +6,7 @@
*
* @example
* ```typescript
- * import { createAccount, addDelegateKey, generateDelegateKey } from "@cmdoss/memwal/account"
+ * import { createAccount, addDelegateKey, generateDelegateKey } from "@mysten/memwal/account"
*
* // Generate a delegate keypair
* const delegate = await generateDelegateKey()
diff --git a/packages/sdk/src/ai/middleware.ts b/packages/sdk/src/ai/middleware.ts
index a4a80517..6ba68939 100644
--- a/packages/sdk/src/ai/middleware.ts
+++ b/packages/sdk/src/ai/middleware.ts
@@ -6,7 +6,7 @@
* @example
* ```typescript
* import { generateText } from "ai"
- * import { withMemWal } from "@cmdoss/memwal/ai"
+ * import { withMemWal } from "@mysten/memwal/ai"
* import { openai } from "@ai-sdk/openai"
*
* const model = withMemWal(openai("gpt-4o"), {
diff --git a/packages/sdk/src/index.ts b/packages/sdk/src/index.ts
index 66b6c211..8a67d63f 100644
--- a/packages/sdk/src/index.ts
+++ b/packages/sdk/src/index.ts
@@ -1,5 +1,5 @@
/**
- * @cmdoss/memwal
+ * @mysten/memwal
*
* Privacy-first AI memory SDK.
* Ed25519 delegate key auth + server-side TEE processing.
@@ -7,8 +7,8 @@
* This is the default entry point — MemWal client + types only.
* Does NOT import account.js (which requires @mysten/sui).
*
- * For account management, import from "@cmdoss/memwal/account".
- * For manual (client-side SEAL + Walrus), import from "@cmdoss/memwal/manual".
+ * For account management, import from "@mysten/memwal/account".
+ * For manual (client-side SEAL + Walrus), import from "@mysten/memwal/manual".
*/
// Core client (server-mode: server handles SEAL + Walrus + embedding)
diff --git a/packages/sdk/src/manual-entry.ts b/packages/sdk/src/manual-entry.ts
index 03a48a4c..8fcdbb71 100644
--- a/packages/sdk/src/manual-entry.ts
+++ b/packages/sdk/src/manual-entry.ts
@@ -1,11 +1,11 @@
/**
- * @cmdoss/memwal/manual
+ * @mysten/memwal/manual
*
* Manual (client-side) mode entry point.
* Requires: @mysten/seal, @mysten/walrus, @mysten/sui
*
* Usage:
- * import { MemWalManual } from "@cmdoss/memwal/manual";
+ * import { MemWalManual } from "@mysten/memwal/manual";
*/
export { MemWalManual } from "./manual.js";
diff --git a/packages/sdk/src/manual.ts b/packages/sdk/src/manual.ts
index b9a2e6e5..9c84cfce 100644
--- a/packages/sdk/src/manual.ts
+++ b/packages/sdk/src/manual.ts
@@ -9,7 +9,7 @@
*
* @example
* ```typescript
- * import { MemWalManual } from "@cmdoss/memwal"
+ * import { MemWalManual } from "@mysten/memwal"
*
* const memwal = MemWalManual.create({
* key: process.env.MEMWAL_DELEGATE_KEY!, // Ed25519 delegate key
@@ -45,7 +45,7 @@ import { sha256hex, hexToBytes, bytesToHex } from "./utils.js";
// Users can override via SEAL_KEY_SERVERS in their environment
const DEFAULT_KEY_SERVERS: Record = {
mainnet: [
- "0x145540d931f182fef76467dd8074c9839aea126852d90d18e1556fcbbd1208b6", // Overclock (Open)
+ "0x145540d931f182fef76467dd8074c9839aea126852d90d18e1556fcbbd1208b6", // Overclock (Open)
],
testnet: [
"0x73d05d62c18d9374e3ea529e8e0ed6161da1a141a94d3f76ae3fe4e99356db75",
diff --git a/packages/sdk/src/memwal.ts b/packages/sdk/src/memwal.ts
index 6e9b764f..0d4bf07a 100644
--- a/packages/sdk/src/memwal.ts
+++ b/packages/sdk/src/memwal.ts
@@ -11,7 +11,7 @@
*
* @example
* ```typescript
- * import { MemWal } from "@cmdoss/memwal"
+ * import { MemWal } from "@mysten/memwal"
*
* const memwal = MemWal.create({
* key: process.env.MEMWAL_PRIVATE_KEY, // Ed25519 private key (hex)
diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml
index a811efd6..a3c14e1d 100644
--- a/pnpm-lock.yaml
+++ b/pnpm-lock.yaml
@@ -23,15 +23,15 @@ importers:
apps/app:
dependencies:
- '@cmdoss/memwal':
- specifier: workspace:*
- version: link:../../packages/sdk
'@mysten/dapp-kit':
specifier: ^1.0.3
version: 1.0.4(@mysten/sui@2.8.0(typescript@5.9.3))(@tanstack/react-query@5.90.21(react@19.2.3))(@types/react-dom@19.2.3(@types/react@19.2.14))(@types/react@19.2.14)(immer@9.0.21)(react-dom@19.2.3(react@19.2.3))(react@19.2.3)(typescript@5.9.3)(use-sync-external-store@1.6.0(react@19.2.3))
'@mysten/enoki':
specifier: ^1.0.4
version: 1.0.4(@mysten/sui@2.8.0(typescript@5.9.3))(@types/react@19.2.14)(react@19.2.3)
+ '@mysten/memwal':
+ specifier: workspace:*
+ version: link:../../packages/sdk
'@mysten/seal':
specifier: ^1.1.0
version: 1.1.1(@mysten/sui@2.8.0(typescript@5.9.3))
@@ -80,6 +80,9 @@ importers:
react-router-dom:
specifier: ^7.13.1
version: 7.13.1(react-dom@19.2.3(react@19.2.3))(react@19.2.3)
+ react-syntax-highlighter:
+ specifier: ^15.6.6
+ version: 15.6.6(react@19.2.3)
tailwind-merge:
specifier: ^3.5.0
version: 3.5.0
@@ -105,6 +108,9 @@ importers:
'@types/react-dom':
specifier: ^19.2.3
version: 19.2.3(@types/react@19.2.14)
+ '@types/react-syntax-highlighter':
+ specifier: ^15.5.13
+ version: 15.5.13
'@vitejs/plugin-react':
specifier: ^5.1.1
version: 5.2.0(vite@7.3.1(@types/node@24.12.0)(jiti@2.6.1)(lightningcss@1.31.1)(terser@5.46.1)(tsx@4.21.0)(yaml@2.8.2))
@@ -153,9 +159,6 @@ importers:
'@ai-sdk/react':
specifier: 3.0.39
version: 3.0.39(react@19.0.1)(zod@3.25.76)
- '@cmdoss/memwal':
- specifier: workspace:*
- version: link:../../packages/sdk
'@codemirror/lang-javascript':
specifier: ^6.2.2
version: 6.2.5
@@ -174,6 +177,9 @@ importers:
'@icons-pack/react-simple-icons':
specifier: ^13.7.0
version: 13.12.0(react@19.0.1)
+ '@mysten/memwal':
+ specifier: workspace:*
+ version: link:../../packages/sdk
'@opentelemetry/api':
specifier: ^1.9.0
version: 1.9.0
@@ -460,9 +466,6 @@ importers:
'@base-ui/react':
specifier: ^1.2.0
version: 1.3.0(@types/react@19.2.14)(react-dom@19.2.3(react@19.2.3))(react@19.2.3)
- '@cmdoss/memwal':
- specifier: workspace:*
- version: link:../../packages/sdk
'@hookform/resolvers':
specifier: ^5.2.2
version: 5.2.2(react-hook-form@7.71.2(react@19.2.3))
@@ -496,6 +499,9 @@ importers:
'@lexical/utils':
specifier: ^0.41.0
version: 0.41.0
+ '@mysten/memwal':
+ specifier: workspace:*
+ version: link:../../packages/sdk
'@mysten/sui':
specifier: ^2.5.0
version: 2.8.0(typescript@5.9.3)
@@ -677,9 +683,6 @@ importers:
'@ai-sdk/react':
specifier: 3.0.39
version: 3.0.39(react@19.0.1)(zod@3.25.76)
- '@cmdoss/memwal':
- specifier: 2.0.0-alpha.2
- version: 2.0.0-alpha.2(@mysten/seal@1.1.1(@mysten/sui@2.8.0(typescript@5.9.3)))(@mysten/sui@2.8.0(typescript@5.9.3))(@mysten/walrus@1.0.4(@mysten/sui@2.8.0(typescript@5.9.3)))(ai@6.0.37(zod@3.25.76))(zod@3.25.76)
'@codemirror/lang-javascript':
specifier: ^6.2.2
version: 6.2.5
@@ -698,6 +701,9 @@ importers:
'@icons-pack/react-simple-icons':
specifier: ^13.7.0
version: 13.12.0(react@19.0.1)
+ '@mysten/memwal':
+ specifier: 0.0.1-dev.0
+ version: 0.0.1-dev.0(@mysten/seal@1.1.1(@mysten/sui@2.8.0(typescript@5.9.3)))(@mysten/sui@2.8.0(typescript@5.9.3))(@mysten/walrus@1.0.4(@mysten/sui@2.8.0(typescript@5.9.3)))(ai@6.0.37(zod@3.25.76))(zod@3.25.76)
'@noble/ed25519':
specifier: ^2.2.3
version: 2.3.0
@@ -1478,26 +1484,6 @@ packages:
'@clack/prompts@1.1.0':
resolution: {integrity: sha512-pkqbPGtohJAvm4Dphs2M8xE29ggupihHdy1x84HNojZuMtFsHiUlRvqD24tM2+XmI+61LlfNceM3Wr7U5QES5g==}
- '@cmdoss/memwal@2.0.0-alpha.2':
- resolution: {integrity: sha512-7JAFbsrvommDHzmolKdnGkcuFKa5LLbNKOPcyN/cv8jd9/1pw44vyaU2bxyMlNAXWYTtq8Qk2HwZ1lXr7HSA3Q==}
- peerDependencies:
- '@mysten/seal': '>=1.1.0'
- '@mysten/sui': '>=2.5.0'
- '@mysten/walrus': '>=1.0.3'
- ai: '>=4.0.0'
- zod: ^3.23.0
- peerDependenciesMeta:
- '@mysten/seal':
- optional: true
- '@mysten/sui':
- optional: true
- '@mysten/walrus':
- optional: true
- ai:
- optional: true
- zod:
- optional: true
-
'@codemirror/autocomplete@6.20.1':
resolution: {integrity: sha512-1cvg3Vz1dSSToCNlJfRA2WSI4ht3K+WplO0UMOgmUYPivCyy2oueZY6Lx7M9wThm7SDUBViRmuT+OG/i8+ON9A==}
@@ -3090,6 +3076,26 @@ packages:
'@mysten/ledgerjs-hw-app-sui@0.7.1':
resolution: {integrity: sha512-2KfPyTzdIeSq4auepS56T09rPE2dHz2VX3G9rFnYjayzynJtNd9tzKWPRpjpCEdBGjp8wg0kEzAeHSOwB0P/Kg==}
+ '@mysten/memwal@0.0.1-dev.0':
+ resolution: {integrity: sha512-WJ9uD7V0NKakYLiw2aphkJiTGFNxU3VbsdWncPyaVXtKmt1ySSlXmP7fiMY09JNwJsYmYAJiCb9M6ujiz7hejg==}
+ peerDependencies:
+ '@mysten/seal': '>=1.1.0'
+ '@mysten/sui': '>=2.5.0'
+ '@mysten/walrus': '>=1.0.3'
+ ai: '>=4.0.0'
+ zod: ^3.23.0
+ peerDependenciesMeta:
+ '@mysten/seal':
+ optional: true
+ '@mysten/sui':
+ optional: true
+ '@mysten/walrus':
+ optional: true
+ ai:
+ optional: true
+ zod:
+ optional: true
+
'@mysten/seal@1.1.1':
resolution: {integrity: sha512-OGxEDmEuXQAzxJKz3ap1dkRSf5fD/iKpz/J8+wZlPbeSok2fVt3KPaCZngjrvqqVRn5lmQomNpzXQCKo929A3w==}
peerDependencies:
@@ -11781,16 +11787,6 @@ snapshots:
'@clack/core': 1.1.0
sisteransi: 1.0.5
- '@cmdoss/memwal@2.0.0-alpha.2(@mysten/seal@1.1.1(@mysten/sui@2.8.0(typescript@5.9.3)))(@mysten/sui@2.8.0(typescript@5.9.3))(@mysten/walrus@1.0.4(@mysten/sui@2.8.0(typescript@5.9.3)))(ai@6.0.37(zod@3.25.76))(zod@3.25.76)':
- dependencies:
- '@noble/ed25519': 2.3.0
- optionalDependencies:
- '@mysten/seal': 1.1.1(@mysten/sui@2.8.0(typescript@5.9.3))
- '@mysten/sui': 2.8.0(typescript@5.9.3)
- '@mysten/walrus': 1.0.4(@mysten/sui@2.8.0(typescript@5.9.3))
- ai: 6.0.37(zod@3.25.76)
- zod: 3.25.76
-
'@codemirror/autocomplete@6.20.1':
dependencies:
'@codemirror/language': 6.12.2
@@ -13567,6 +13563,17 @@ snapshots:
'@mysten/ledgerjs-hw-app-sui@0.7.1': {}
+ '@mysten/memwal@0.0.1-dev.0(@mysten/seal@1.1.1(@mysten/sui@2.8.0(typescript@5.9.3)))(@mysten/sui@2.8.0(typescript@5.9.3))(@mysten/walrus@1.0.4(@mysten/sui@2.8.0(typescript@5.9.3)))(ai@6.0.37(zod@3.25.76))(zod@3.25.76)':
+ dependencies:
+ '@noble/ed25519': 2.3.0
+ '@noble/hashes': 2.0.1
+ optionalDependencies:
+ '@mysten/seal': 1.1.1(@mysten/sui@2.8.0(typescript@5.9.3))
+ '@mysten/sui': 2.8.0(typescript@5.9.3)
+ '@mysten/walrus': 1.0.4(@mysten/sui@2.8.0(typescript@5.9.3))
+ ai: 6.0.37(zod@3.25.76)
+ zod: 3.25.76
+
'@mysten/seal@1.1.1(@mysten/sui@2.8.0(typescript@5.9.3))':
dependencies:
'@mysten/bcs': 2.0.3
@@ -19009,7 +19016,7 @@ snapshots:
eslint: 9.39.4(jiti@2.6.1)
eslint-import-resolver-node: 0.3.9
eslint-import-resolver-typescript: 3.10.1(eslint-plugin-import@2.32.0(eslint@9.39.4(jiti@2.6.1)))(eslint@9.39.4(jiti@2.6.1))
- eslint-plugin-import: 2.32.0(eslint-import-resolver-typescript@3.10.1(eslint-plugin-import@2.32.0(eslint@9.39.4(jiti@2.6.1)))(eslint@9.39.4(jiti@2.6.1)))(eslint@9.39.4(jiti@2.6.1))
+ eslint-plugin-import: 2.32.0(eslint-import-resolver-typescript@3.10.1)(eslint@9.39.4(jiti@2.6.1))
eslint-plugin-jsx-a11y: 6.10.2(eslint@9.39.4(jiti@2.6.1))
eslint-plugin-react: 7.37.5(eslint@9.39.4(jiti@2.6.1))
eslint-plugin-react-hooks: 7.0.1(eslint@9.39.4(jiti@2.6.1))
@@ -19042,7 +19049,7 @@ snapshots:
tinyglobby: 0.2.15
unrs-resolver: 1.11.1
optionalDependencies:
- eslint-plugin-import: 2.32.0(eslint-import-resolver-typescript@3.10.1(eslint-plugin-import@2.32.0(eslint@9.39.4(jiti@2.6.1)))(eslint@9.39.4(jiti@2.6.1)))(eslint@9.39.4(jiti@2.6.1))
+ eslint-plugin-import: 2.32.0(eslint-import-resolver-typescript@3.10.1)(eslint@9.39.4(jiti@2.6.1))
transitivePeerDependencies:
- supports-color
@@ -19056,7 +19063,7 @@ snapshots:
transitivePeerDependencies:
- supports-color
- eslint-plugin-import@2.32.0(eslint-import-resolver-typescript@3.10.1(eslint-plugin-import@2.32.0(eslint@9.39.4(jiti@2.6.1)))(eslint@9.39.4(jiti@2.6.1)))(eslint@9.39.4(jiti@2.6.1)):
+ eslint-plugin-import@2.32.0(eslint-import-resolver-typescript@3.10.1)(eslint@9.39.4(jiti@2.6.1)):
dependencies:
'@rtsao/scc': 1.1.0
array-includes: 3.1.9
@@ -22640,6 +22647,16 @@ snapshots:
react: 19.0.1
refractor: 3.6.0
+ react-syntax-highlighter@15.6.6(react@19.2.3):
+ dependencies:
+ '@babel/runtime': 7.28.6
+ highlight.js: 10.7.3
+ highlightjs-vue: 1.0.0
+ lowlight: 1.20.0
+ prismjs: 1.30.0
+ react: 19.2.3
+ refractor: 3.6.0
+
react-transition-group@4.4.5(react-dom@19.2.3(react@19.2.3))(react@19.2.3):
dependencies:
'@babel/runtime': 7.29.2
diff --git a/services/server/scripts/sidecar-server.ts b/services/server/scripts/sidecar-server.ts
index 18887d3f..b0fc727a 100644
--- a/services/server/scripts/sidecar-server.ts
+++ b/services/server/scripts/sidecar-server.ts
@@ -415,7 +415,7 @@ app.post("/seal/decrypt-batch", async (req, res) => {
// ============================================================
app.post("/walrus/upload", async (req, res) => {
try {
- const { data, privateKey, owner, namespace, packageId, epochs = 50 } = req.body;
+ const { data, privateKey, owner, namespace, packageId, epochs = 2 } = req.body;
if (!data || !privateKey) {
return res.status(400).json({ error: "Missing required fields: data, privateKey" });
}