Skip to Content
TypeScript SDKMemory Sharing

Memory Sharing

The SDK provides a simple API for creating and using grants to share memories between agents.

Creating Grants

Use createGrant() to generate a signed grant that allows another agent to access your memories:

import { fromPrivateKey } from "@zkstash/sdk/rest"; const client = await fromPrivateKey(process.env.PRIVATE_KEY!); const { grant, shareCode } = await client.createGrant({ grantee: "0xAgentBAddress...", // Recipient's wallet address agentId: "my-agent", // Optional: limit to specific agent duration: "7d", // How long the grant is valid });

Parameters

ParameterTypeRequiredDescription
granteestringYesWallet address of the agent receiving access
agentIdstringNoLimit access to a specific agent’s memories
durationstringYesGrant validity period (e.g., "1h", "24h", "7d", "30d")

Return Value

{ grant: SignedGrant; // The signed grant object shareCode: string; // Base64-encoded string starting with "zkg1_" }

The shareCode is a compact, shareable representation of the grant that can be easily transmitted.

Using Grants

Adding Grants to Client Instance

Add grants to your client for automatic inclusion in all searches:

import { fromPrivateKey } from "@zkstash/sdk/rest"; const client = await fromPrivateKey(process.env.PRIVATE_KEY!); // Add using share code (string starting with "zkg1_") client.addGrant(shareCode); // Or add using SignedGrant object client.addGrant(grantObject);

Searching with Grants

Once grants are added, search results automatically include shared memories:

const results = await client.searchMemories({ query: "research findings", filters: { agentId: "researcher" }, }); // Results include source annotation results.memories.forEach((m) => { console.log(m.source); // "own" | "shared" if (m.source === "shared") { console.log(`From: ${m.grantor}`); } });

Search Scope

Control which namespaces to search using the scope option:

// Search only your own memories (ignores all grants) await client.searchMemories( { query: "...", filters: { agentId: "..." } }, { scope: "own" } ); // Search only shared memories (requires at least one valid grant) await client.searchMemories( { query: "...", filters: { agentId: "..." } }, { scope: "shared" } ); // Search both own and shared (default) await client.searchMemories( { query: "...", filters: { agentId: "..." } }, { scope: "all" } // or omit - "all" is the default );

Per-Request Grants

Pass grants for a single request without adding them to the instance:

await client.searchMemories( { query: "...", filters: { agentId: "..." } }, { grants: [grantFromAgentA, grantFromAgentB] } );

Grant Management

Remove a Grant

client.removeGrant(grantObject);

List Instance Grants

const grants = client.getInstanceGrants(); console.log(`Active grants: ${grants.length}`);

Working with Share Codes

The SDK provides utilities to convert between grant objects and share codes:

import { grantToShareCode, grantFromShareCode } from "@zkstash/sdk/utils"; // Convert grant to share code const shareCode = grantToShareCode(grant); // "zkg1_eyJwIjp7ImYiOiIweC4uLiIs..." // Convert share code back to grant const grant = grantFromShareCode(shareCode);

Example: Research Agent Collaboration

Here’s a complete example of two agents sharing memories:

import { fromPrivateKey } from "@zkstash/sdk/rest"; // === Agent A: The Researcher === const researcher = await fromPrivateKey(process.env.RESEARCHER_KEY!); // Store some research findings await researcher.storeMemories("research-bot", [ { kind: "ResearchFinding", data: { topic: "AI memory systems", summary: "Long-term memory improves agent performance by 40%", source: "arxiv:2024.12345", }, }, ]); // Create a grant for the coordinator const { shareCode } = await researcher.createGrant({ grantee: "0xCoordinatorAddress...", agentId: "research-bot", duration: "30d", }); console.log("Send this to coordinator:", shareCode); // === Agent B: The Coordinator === const coordinator = await fromPrivateKey(process.env.COORDINATOR_KEY!); // Add the grant from researcher coordinator.addGrant(shareCode); // Search includes researcher's memories const results = await coordinator.searchMemories({ query: "AI memory performance", filters: { agentId: "research-bot" }, }); results.memories.forEach((m) => { if (m.source === "shared") { console.log(`Research from ${m.grantor}:`, m.data); } });

Chain Support

Grants work with both EVM and Solana wallets:

// EVM (Base, Ethereum, etc.) const evmClient = await fromPrivateKey("0x..."); const { grant } = await evmClient.createGrant({ grantee: "0x...", // EVM address duration: "7d", }); // grant.c === "evm" // Solana const solanaClient = await fromPrivateKey("base58PrivateKey..."); const { grant: solGrant } = await solanaClient.createGrant({ grantee: "base58PublicKey...", // Solana address duration: "7d", }); // solGrant.c === "sol"

API Key Grantees

If the grantee uses API key authentication, use their Clerk userId as the grantee:

// Grant for an API key user const { grant } = await grantor.createGrant({ grantee: "user_2abc123xyz...", // Clerk userId (shown in dashboard) duration: "7d", });

The Clerk userId is displayed in the zkStash dashboard. When verifying, zkStash checks if the grantee matches either the caller’s wallet address (for wallet auth) or their Clerk userId (for API key auth).

Best Practices

  1. Use short durations when possible—grants cannot be revoked
  2. Scope to specific agents using agentId to limit access
  3. Don’t log share codes in production—treat them like passwords
  4. Validate grantee addresses before creating grants
  5. Use per-request grants for one-time access instead of adding to instance

Error Handling

try { const { grant } = await client.createGrant({ grantee: "0x...", duration: "invalid", // Invalid duration }); } catch (error) { console.error("Failed to create grant:", error.message); } // Searching with scope="shared" requires grants await client.searchMemories( { query: "...", filters: { agentId: "..." } }, { scope: "shared" } // Throws if no valid grants ); // Error: "scope='shared' requires at least one valid grant"
Last updated on