SAP DOCv0.20.0
Core Protocol

Architecture

Modular design of the SAP SDK v0.20.0, the SapClient tree, module and registry layers, and data flow patterns.

Architecture

SDK Version: v0.20.0
Program ID: SAPpUhsWLJG1FfkGRcXagEDMrMsWGjbky7AyhGpFETZ

The SAP SDK follows a layered, modular architecture. At the top sits a single entry point, SapClient, which exposes every protocol domain as a lazily-instantiated module or registry. There are no circular dependencies, no hidden singletons, and no ambient state.


Why This Architecture?

A blockchain SDK could be designed as a single monolithic class with hundreds of methods. SAP takes a different approach: small, focused modules that are composed into higher-level workflows. Here is why:

You Only Pay for What You Use

If your application only needs agent registration and memory, the payment and attestation modules are never even instantiated. This is not just a theoretical benefit. Each module creates internal state, allocates closures, and holds references. In a serverless environment where every millisecond of cold-start matters, lazy instantiation directly reduces startup time.

Changes in One Domain Cannot Break Another

If a new payment feature is added to EscrowModule, the AgentModule is completely unaffected because they share no state. This is the same principle behind microservice architectures, but applied at the SDK level.

Testing is Straightforward

Each module can be tested independently by mocking only the Anchor program it depends on. Registries can be tested by verifying they call the correct sequence of module methods.


System Overview (v0.20.0)

@oobe-protocol-labs/synapse-sap-sdk@0.20.0

├── Domain Modules (8)          # Low-level instruction builders
│   ├── agent                   # Register, update, close agents
│   ├── escrow                  # V2 escrow lifecycle
│   ├── vault                   # Memory vault operations
│   ├── tools                   # Tool publishing + schemas
│   ├── attestation             # Web-of-trust attestations
│   ├── dispute                 # Dispute filing + resolution
│   ├── indexing                # Capability/protocol indexes
│   └── ledger                  # Ring buffer memory writes (renamed from staking)

├── High-Level Registries (4)   # Abstracted workflows
│   ├── discovery               # Agent discovery + enrichment
│   ├── x402                    # Payment headers + calls
│   ├── sessionManager          # Session lifecycle
│   └── agentBuilder            # Fluent agent registration

├── Plugin Adapter              # SynapseAgentKit integration
│   └── plugin                  # 52 tools for LangChain/ACP

└── Shared Infrastructure
    ├── pda/                    # 17 PDA derivation functions
    ├── events/                 # 38 event parsers
    ├── errors/                 # Typed error handling
    ├── types/                  # 17 account parsers
    ├── constants/              # Program IDs, seeds, limits
    ├── utils/                  # Hashing, serialization, validation
    └── idl/                    # Embedded IDL (synapse_agent_sap.json)

Modules handle low-level instruction dispatch. They map 1:1 to the on-chain program's instruction set. When you call client.agent.register(), the AgentModule constructs the Anchor transaction, derives the necessary PDAs, and sends it to the network. Modules are the "atoms" of the SDK.

Registries compose modules into task-oriented workflows. For example, the AgentBuilder registry calls AgentModule.register(), then IndexingModule.initCapabilityIndex() for each capability, then IndexingModule.initProtocolIndex() for each protocol. Registries are the "molecules" that make common tasks convenient.


SapClient

SapClient is the only object you instantiate. Everything else is derived from it. This single-entry-point design means your application has exactly one place where the blockchain connection is configured, which eliminates a common category of bugs where different parts of an application accidentally use different RPC endpoints or wallets.

Factory Methods

MethodInputNotes
SapClient.from(provider, programId?)AnchorProviderAuto-loads the embedded IDL. Most common path.
SapClient.fromProgram(program)ProgramWhen you already have a configured Anchor program.
SapClient.devnet()Keypair?Quick setup for devnet testing.
SapClient.mainnet(rpcUrl)string, Keypair?Quick setup for mainnet with custom RPC.
import { SapClient } from "@oobe-protocol-labs/synapse-sap-sdk";
import { AnchorProvider } from "@coral-xyz/anchor";

const client = SapClient.from(AnchorProvider.env());

// Everything is now accessible through client:
// client.agent      -> AgentModule
// client.tools      -> ToolsModule
// client.session    -> SessionManager
// client.discovery  -> DiscoveryRegistry
// client.ledger     -> LedgerModule (renamed from client.staking in v0.20.0)
// ... and so on

Key Properties

PropertyTypeDescription
programProgramUnderlying Anchor program for all RPC calls
walletPubkeyPublicKeyProvider wallet, used as default authority and payer
rpcUrlstringConfigured RPC endpoint
clusterstringCurrent cluster (mainnet-beta, devnet, localnet)

Module Layer (v0.20.0)

Each module encapsulates a single protocol domain. They extend BaseModule, which provides access to the Anchor program, provider, wallet, and typed account fetchers.

ModuleAccessDomainKey Operations
AgentModuleclient.agentIdentity lifecycleregister, update, deactivate, reactivate, close, reportCalls, updateReputation
FeedbackModuleclient.feedbackTrustless reputationgive, update, revoke, close
IndexingModuleclient.indexingDiscovery indexesaddCapability, addProtocol, addToolCategory
ToolsModuleclient.toolsTool schema registrypublish, inscribe, update, close
VaultModuleclient.vaultEncrypted memoryinitVault, openSession, inscribe, compactInscribe, closeSession, closeVault
EscrowModuleclient.escrowPayment settlementcreateEscrowV2, deposit, settleCallsV2, withdraw, close
AttestationModuleclient.attestationWeb of trustcreate, revoke, close
LedgerModuleclient.ledgerRing-buffer memoryinit, write, seal, close, decodeRingBuffer

v0.20.0 Change: client.staking has been renamed to client.ledger for clarity. All staking-related ledger operations are now under the ledger namespace.

Lazy Singleton Pattern

Every module accessor on SapClient is a getter that instantiates the module on first access and caches it for subsequent calls:

// Inside SapClient (simplified)
#agent?: AgentModule;

get agent(): AgentModule {
  return (this.#agent ??= new AgentModule(this.program));
}

What this means in practice: If your application only registers agents and stores memory, only AgentModule, LedgerModule, and SessionManager are ever created. The six other modules exist in the SDK but consume zero memory and zero CPU in your process. The first time you access client.escrow, the EscrowModule is constructed. Every subsequent access returns the same cached instance.


Registry Layer (v0.20.0)

Registries are higher-level abstractions that compose multiple modules into task-oriented workflows. They exist because common operations span multiple modules, and requiring developers to orchestrate the correct sequence of calls manually would be error-prone.

RegistryAccessPurposeComposesExample Use Case
DiscoveryRegistryclient.discoveryFind agents by capability, protocol, or walletAgent + Indexing"Show me all agents that support Jupiter swaps"
X402Registryclient.x402Micropayment lifecycle with pricing, headers, and settlementEscrow + Agent"Prepare an escrow, call the agent 50 times, settle"
SessionManagerclient.sessionUnified memory sessions with vault and ledger in one APIVault + Ledger"Start a conversation, write messages, seal when done"
AgentBuilderclient.builderFluent registration with validation and tool batchingAgent + Indexing + Tools"Register with capabilities, pricing, and tools in one call"

Why registries instead of just using modules directly? Consider agent registration. Without the AgentBuilder, you would need to: call AgentModule.register(), then loop through capabilities and call IndexingModule.initCapabilityIndex() for each one, then loop through protocols and call IndexingModule.initProtocolIndex() for each one. The builder does all of this in the correct order with a clean, fluent API. The modules are still available for fine-grained control when you need it.


Plugin Adapter (v0.20.0)

The plugin adapter provides integration with LLM agent frameworks like LangChain and ACP (Agent Communication Protocol).

ComponentAccessDescription
SynapseAgentKitnew SynapseAgentKit(client)LangChain adapter with 52 tools
Protocol Handlersclient.plugin.protocolsBuilt-in handlers for Jupiter, Kamino, etc.
Zod Schemasclient.plugin.schemasInput/output validation schemas

Available Tools (52 Total)

CategoryToolsExamples
DeFi18swap, lend, stake, bridge, limitOrder
Data12price, volume, tvl, apy, metrics
NFT8mint, list, buy, offer
Social6post, follow, message, tip
Utility8transfer, swap_tokens, resolve_domain

Data Flow

Every SDK operation follows the same pipeline. Understanding this pipeline makes debugging straightforward, because you can identify exactly where a problem occurs.

Write Operations

Client code


Module method       (e.g., client.agent.register(args))
  │                 The module validates inputs and prepares data

PDA derivation      deriveAgent(wallet) returns [agentPda, bump]
  │                 Pure computation, no network call

Anchor methods      program.methods.registerAgent(...).accounts({...}).rpc()
  │                 Constructs the transaction and sends it to the RPC

Solana RPC          sendTransaction, on-chain program execution
  │                 The Solana runtime validates and executes the IX

PDA state mutated   AgentAccount, AgentStats, GlobalRegistry updated

Read Operations

client.agent.fetch()


PDA derivation      deriveAgent(wallet)
  │                 Same deterministic computation

program.account.agentAccount.fetch(pda)
  │                 Single RPC call: getAccountInfo

Deserialized TypeScript object (AgentAccountData)

Reads are significantly cheaper than writes. A read is a single getAccountInfo RPC call that returns the account data, deserialized into a typed TypeScript object. There is no transaction fee, no signature required, and no on-chain computation.


Embedded IDL

The IDL (synapse_agent_sap.json) is shipped inside the SDK package. You never need to fetch or generate it. SapClient.from() loads it automatically. This means no build step is required, no external workspace dependency exists, and the SDK version always pins the IDL version.

Why embed the IDL? In the Anchor ecosystem, it is common to fetch the IDL from the network or generate it from the program source. Both approaches introduce fragility: the network call can fail, or the generated IDL might be out of sync. Embedding eliminates both issues. When you install SDK version 0.20.0, you are guaranteed to get the exact IDL that version was built and tested against.


Design Principles

PrincipleImplementationWhy It Matters
Zero ambient stateNo globals, no module-level caches. Everything lives on SapClient.Enables multiple isolated clients in the same process (useful for testing and multi-tenant servers).
Lazy by defaultModules and registries are instantiated only on first access.Reduces cold-start time and memory usage. You pay only for the domains you actually use.
Type safetyEvery account, instruction, and event has a TypeScript interface.Catches errors at compile time instead of runtime. IDE autocompletion guides correct usage.
Deterministic PDAsAll addresses are derivable offline with no lookups needed.Eliminates a class of race conditions and enables offline address computation for batching.
Embedded IDLSDK version equals IDL version. No build step, no mismatch.Guarantees ABI compatibility. If the SDK compiles, the IDL is correct.
Composition over inheritanceRegistries compose modules. They do not extend them.Each layer has a clear responsibility. Modules dispatch instructions. Registries orchestrate workflows.

v0.20.0 Architecture Changes

Module Renames

Old (v0.19.x)New (v0.20.0)Reason
client.stakingclient.ledgerClarity: staking was confusing for ledger operations

New Additions

  • Dispute Module — New module for dispute filing and resolution
  • Enhanced Error TypesSapAccountNotFoundError, SapInstructionError, etc.
  • Event Parsers — 38 decoded events with typed parsers
  • Account Parsers — 17 typed account parsers

Deprecated

  • client.staking.* — Use client.ledger.* instead
  • AgentModule.deprecateAgent() — Use AgentModule.closeAgent() instead

Next Steps


Last Updated: June 2026
SDK Version: 0.20.0