GoodMemGoodMem
ReferenceClient SDKs.NET

.NET SDK

The GoodMem .NET SDK offers an OpenAI-style API where any operation is accessed through client.<Namespace>.<Method>Async(...) on a GoodmemClient. The surface is async-only — every network method returns a Task<T> (or an IAsyncEnumerable<T> for pagination and streaming) and takes a CancellationToken; deadlines and cancellation come from the token you pass in.

Installation

dotnet add package PairSystems.Goodmem.Client
using Goodmem.Client;

Requirements: .NET 8 or later — the package targets net8.0 and net10.0, so it works on .NET 8 (LTS), 9, and 10. The SDK depends only on the base class library (System.Text.Json).

Client

GoodmemClient is safe for concurrent use. Construct it in one of two mutually exclusive modes.

// SDK-managed HttpClient (base URL + API key):
using var client = new GoodmemClient(new GoodmemClientOptions
{
    BaseUrl = "http://localhost:8080",
    ApiKey = "gm_...",
});
  • The base URL may carry a mount-path prefix (e.g. https://host/api) — it is preserved on every request.
  • An empty API key is allowed (the unauthenticated bootstrap endpoints /v1/system/info and /v1/system/init are callable without one); every other endpoint returns 401.
  • To supply your own HttpClient (proxy, custom TLS, handlers), pass it via GoodmemClientOptions.HttpClient. In bring-your-own mode you own the redirect policy; the SDK-built default refuses redirects so the x-api-key header cannot leak across a host boundary.

Pagination

List methods return an IAsyncEnumerable<T>; await foreach walks every item across pages transparently, and break stops fetching further pages.

await foreach (var memory in client.Memories.ListAsync(spaceId))
{
    // handle each memory
}

Streaming

Streaming methods (memories.retrieve, ping.stream) also return an IAsyncEnumerable<T> over the NDJSON event stream; the connection is released when iteration ends or you break.

await foreach (var ev in client.Memories.RetrieveAsync("What do you know about ...?"))
{
    // handle each retrieval event
}

Errors

Every method throws a typed exception on failure. Transport problems surface as NetworkException; non-2xx HTTP responses surface as an ApiException (or one of its status-specific subtypes). All derive from GoodmemException.

try
{
    var space = await client.Spaces.GetAsync(spaceId);
}
catch (NotFoundException)
{
    // 404 — handle missing space
}
catch (ApiException e)
{
    Console.WriteLine($"server returned {e.StatusCode}: {e.Body}");
}

The status-specific subtypes are BadRequestException (400), AuthenticationException (401), PermissionDeniedException (403), NotFoundException (404), ConflictException (409), UnprocessableEntityException (422), RateLimitException (429) and InternalServerException (5xx). All derive from ApiException, so a catch (ApiException) matches any of them.

Namespaces

NamespaceDescriptionReference
EmbeddersEmbedder managementclient.Embedders
RerankersReranker managementclient.Rerankers
LlmsLLM managementclient.Llms
SpacesMemory space managementclient.Spaces
MemoriesMemory CRUD, retrieval, and batch operationsclient.Memories
OcrDocument text extractionclient.Ocr
SystemServer info and initializationclient.System
UsersUser lookupclient.Users
AdminServer lifecycle operationsclient.Admin
ApiKeysAPI key lifecycle managementclient.ApiKeys
PingEndpoint health probes (single-shot and streaming)client.Ping

Common Data Models

Wire types shared across namespaces. Fields are shown with their C# property names; JSON payloads use the camelCase wire name noted on each field.

ProviderType

Embedding provider types

String enum: "OPENAI" · "VLLM" · "TEI" · "LLAMA_CPP" · "VOYAGE" · "COHERE" · "JINA"

Modality

Content modality types supported by embedders

String enum: "TEXT" · "IMAGE" · "AUDIO" · "VIDEO"

EndpointAuthentication

Structured credential payload describing how GoodMem should authenticate with an upstream provider.

PropertyTypeJSON (wire)Description
KindCredentialKindkindSelected credential strategy
ApiKeyApiKeyAuthapiKeyConfiguration when kind is CREDENTIAL_KIND_API_KEY (optional)
GcpAdcGcpAdcAuthgcpAdcConfiguration when kind is CREDENTIAL_KIND_GCP_ADC (optional)
LabelsIReadOnlyDictionary<string, string>labelsOptional annotations to aid operators (e.g., "owner=vertex") (optional)

CredentialKind

Credential kinds supported for upstream endpoint authentication.

String enum: "CREDENTIAL_KIND_UNSPECIFIED" · "CREDENTIAL_KIND_API_KEY" · "CREDENTIAL_KIND_GCP_ADC"

ApiKeyAuth

Configuration for classic API-key authentication.

PropertyTypeJSON (wire)Description
InlineSecretstringinlineSecretSecret stored directly in GoodMem (mutually exclusive with secretRef) (optional)
SecretRefSecretReferencesecretRefReference to an external secret manager entry (mutually exclusive with inlineSecret) (optional)
HeaderNamestringheaderNameDesired HTTP header to carry the credential (defaults to Authorization) (optional)
PrefixstringprefixOptional prefix prepended to the secret (e.g., "Bearer ") (optional)

GcpAdcAuth

Configuration for Google Application Default Credentials (ADC).

PropertyTypeJSON (wire)Description
ScopesIReadOnlyList<string>scopesAdditional OAuth scopes. Empty list falls back to the default cloud-platform scope. (optional)
QuotaProjectIdstringquotaProjectIdOptional quota project used for billing (optional)

SecretReference

PropertyTypeJSON (wire)Description
UristringuriURI identifying where the secret can be resolved (e.g., vault://, env://)
HintsIReadOnlyDictionary<string, string>hintsOptional metadata to help resolvers decode the secret (e.g., {"encoding":"base64"}) (optional)

GoodMemStatus

Warning or non-fatal status with granular codes (operation continues)

PropertyTypeJSON (wire)Description
CodestringcodeStatus code for the warning or informational message
MessagestringmessageHuman-readable status message
DetailsIReadOnlyDictionary<string, string>detailsAdditional contextual details (optional)

ChunkingConfiguration

Configuration for text chunking strategy used when processing content. Exactly one of none, recursive, or sentence must be provided.

PropertyTypeJSON (wire)Description
NoneNoChunkingConfigurationnoneNo chunking strategy - preserve original content as single unit (optional)
RecursiveRecursiveChunkingConfigurationrecursiveRecursive hierarchical chunking strategy with configurable separators (optional)
SentenceSentenceChunkingConfigurationsentenceSentence-based chunking strategy with language detection (optional)

NoChunkingConfiguration

No chunking strategy - preserves original content as a single unit

(no fields)

RecursiveChunkingConfiguration

Recursive hierarchical chunking strategy with configurable separators and overlap

PropertyTypeJSON (wire)Description
ChunkSizeintchunkSizeMaximum size of a chunk (should be ≤ context window)
ChunkOverlapintchunkOverlapSliding overlap between chunks
SeparatorsIReadOnlyList<string>separatorsHierarchical separator list (order = preference) (optional)
KeepStrategySeparatorKeepStrategykeepStrategyHow to handle separators after splitting. KEEP_NONE is deprecated and behaves as KEEP_END.
SeparatorIsRegexboolseparatorIsRegexWhether separators are regex patterns (optional)
LengthMeasurementLengthMeasurementlengthMeasurementHow to measure chunk length

SentenceChunkingConfiguration

Sentence-based chunking strategy with language detection support

PropertyTypeJSON (wire)Description
MaxChunkSizeintmaxChunkSizeMaximum size of a chunk
MinChunkSizeintminChunkSizeMinimum size before creating a new chunk
EnableLanguageDetectionboolenableLanguageDetectionWhether to detect language for better segmentation (optional)
LengthMeasurementLengthMeasurementlengthMeasurementHow to measure chunk length

SeparatorKeepStrategy

Strategy for handling separators after text splitting. KEEP_NONE is deprecated and treated as KEEP_END.

String enum: "KEEP_NONE" · "KEEP_START" · "KEEP_END"

LengthMeasurement

Strategy for measuring chunk length during text splitting

String enum: "CHARACTER_COUNT" · "TOKEN_COUNT" · "CUSTOM"

SortOrder

String enum: "ASCENDING" · "DESCENDING" · "SORT_ORDER_UNSPECIFIED"

Support

File issues against the GoodMem repository. The .NET SDK is generated from the same universal API IR (api_ir.json) that drives the Python, Java, Go and MCP SDKs, so the wire contract is identical across every language.