Compendium.Adapters.Pinecone
1.0.0-preview.0
dotnet add package Compendium.Adapters.Pinecone --version 1.0.0-preview.0
NuGet\Install-Package Compendium.Adapters.Pinecone -Version 1.0.0-preview.0
<PackageReference Include="Compendium.Adapters.Pinecone" Version="1.0.0-preview.0" />
<PackageVersion Include="Compendium.Adapters.Pinecone" Version="1.0.0-preview.0" />
<PackageReference Include="Compendium.Adapters.Pinecone" />
paket add Compendium.Adapters.Pinecone --version 1.0.0-preview.0
#r "nuget: Compendium.Adapters.Pinecone, 1.0.0-preview.0"
#:package Compendium.Adapters.Pinecone@1.0.0-preview.0
#addin nuget:?package=Compendium.Adapters.Pinecone&version=1.0.0-preview.0&prerelease
#tool nuget:?package=Compendium.Adapters.Pinecone&version=1.0.0-preview.0&prerelease
compendium-adapter-pinecone
Pinecone adapter for the Compendium framework. Implements IVectorStore from Compendium.Abstractions.VectorStore over Pinecone's managed serverless vector database via a hand-rolled HttpClient — no vendor SDK.
Built from template-compendium-adapter-dotnet. Companion to compendium-adapter-pgvector and compendium-adapter-qdrant — same abstraction, same tenant isolation posture, same Result-pattern error handling.
What's in this package
| Component | Implements | Purpose |
|---|---|---|
PineconeVectorStore |
IVectorStore |
Embedding storage + ANN similarity search against Pinecone's two-plane REST API |
PineconeOptions |
— | API key, control-plane URL, cloud / region, tenancy mode, request timeout |
TenantIdentifier |
— | Validates tenant ids against a strict alphanumeric+dash+underscore regex before any wire bind |
ServiceCollectionExtensions |
— | DI helpers (AddCompendiumPinecone(...)) |
Install
dotnet add package Compendium.Adapters.Pinecone
Quick start
Sign up for a free Pinecone account at app.pinecone.io. Free-tier serverless gives you one index in us-east-1 on AWS — enough to dogfood the round-trip.
using Compendium.Abstractions.VectorStore;
using Compendium.Abstractions.VectorStore.Models;
using Compendium.Adapters.Pinecone.DependencyInjection;
using Compendium.Adapters.Pinecone.Options;
services.AddCompendiumPinecone(o =>
{
o.ApiKey = builder.Configuration["Pinecone:ApiKey"]!; // required
o.Cloud = PineconeCloud.Aws;
o.Region = "us-east-1";
});
// IVectorStore is now resolvable from DI.
var store = services.BuildServiceProvider().GetRequiredService<IVectorStore>();
await store.EnsureCollectionAsync("documents", dimension: 1536, DistanceMetric.Cosine);
await store.UpsertAsync("documents", new[]
{
new VectorRecord("doc-1", embedding, metadata, tenantId: "tenant-1"),
});
var matches = await store.SearchAsync(
"documents",
queryEmbedding,
topK: 5,
VectorFilter.Eq("category", "support").ForTenant("tenant-1"));
A runnable example lives under samples/01-managed-rag.
Configuration options
Bind to the Compendium:Adapters:Pinecone section, or pass an inline callback.
| Option | Default | Purpose |
|---|---|---|
ApiKey |
(required) | Sent as the Api-Key header on every request. |
ControlPlaneBaseUrl |
https://api.pinecone.io |
Pinecone control plane (index lifecycle). |
Cloud |
Aws |
Serverless cloud provider (Aws / Gcp / Azure). |
Region |
us-east-1 |
Serverless region. |
TenancyMode |
Namespace |
How tenant ids are propagated to Pinecone (Namespace or Metadata). |
IndexPrefix |
(empty) | Prefix applied to every index name on the wire (e.g. dev-, staging-). |
Timeout |
30s |
Per-request HTTP timeout. |
The two-plane architecture (read this once)
Pinecone splits its REST API into two HTTP planes:
| Plane | Host | Used for |
|---|---|---|
| Control | api.pinecone.io (fixed) |
GET /indexes/{name}, POST /indexes — index lifecycle. |
| Data | <index>-<project>.svc.<region>-<cloud>.pinecone.io (per-index, returned by control) |
POST /vectors/upsert, POST /vectors/delete, POST /query — read/write. |
PineconeVectorStore resolves the per-index data-plane host on first use via GET /indexes/{name} and caches it in-process. Subsequent reads / writes go straight to the data plane — one extra round-trip on cold start, zero overhead afterwards. EnsureCollectionAsync pre-seeds the cache when it succeeds, so the typical flow (ensure → upsert → search) makes exactly one control-plane call.
If you delete an index outside the adapter, the cached host becomes stale — restart the process or let the data-plane 404 propagate as VectorStore.CollectionNotFound.
Tenancy
Pinecone offers two patterns for multi-tenant isolation. The adapter exposes both via PineconeOptions.TenancyMode.
Namespace mode (default — recommended)
Each tenant id maps to a Pinecone namespace. Every data-plane call includes a namespace field on the request body. This is the cleanest isolation Pinecone offers:
- Reads and writes to one namespace are physically partitioned from another.
- Per-namespace point counts are exposed in Pinecone's stats endpoint.
- No metadata-filter cost on every query.
Use this mode when tenant cardinality is low to moderate (Pinecone recommends ≤ 10,000 namespaces per index — past that, namespace overhead starts to matter).
Metadata mode
The tenant id is stored in the record's metadata under the reserved tenant_id key. Every search emits an $eq filter on that key. Use this mode when:
- You have very high tenant cardinality (hundreds of thousands of tenants) and namespaces would blow past Pinecone's recommended limits.
- You need cross-tenant searches in addition to per-tenant searches — switching modes per-call isn't supported, but a Metadata-mode index lets you omit the filter to query the whole index.
Trade-off: queries are slower (Pinecone applies the metadata filter on the hot path), and stats don't break down per-tenant.
Both modes
TenantIdentifier.IsValidrejects anything outside[a-zA-Z0-9_-]{1,255}before serialisation — defence-in-depth against tenant-id-driven injection. Mirrors the validator used bycompendium-adapter-pgvectorandcompendium-adapter-qdrant.- Tenanted deletes only touch the tenant's vectors. Cross-tenant deletes-by-id are impossible by construction.
Distance metrics
DistanceMetric |
Pinecone metric label |
|---|---|
Cosine |
cosine |
L2 |
euclidean |
InnerProduct |
dotproduct |
The metric is fixed at EnsureCollectionAsync time. Trying to recreate an existing index with a different dimension or metric returns VectorStore.DimensionMismatch / Pinecone.MetricMismatch.
Production checklist
- TLS — automatic. Every Pinecone endpoint is HTTPS.
- API key rotation — never check the API key into source. Rotate via your secret store (we read it via
IOptions<PineconeOptions>, so any provider works). After rotation you must restart the process: the key is bound to the singletonHttpClienton first construction. - Region selection — Pinecone serverless free-tier is
us-east-1/AWS only. For paid tiers, pick a region close to your application servers; cross-region latency dominates query time for small vectors. - Free-tier limits — one serverless index, 100K vectors / 4 GB write-units / 1M read-units per month. Plenty for prototyping, not enough for prod.
- Index name rules — Pinecone limits index names to lowercase
[a-z0-9-], 1–45 chars, no leading or trailing dash. The adapter enforces the same rules and returnsPinecone.InvalidIndexon violation. - Eventual consistency — Pinecone serverless reads are eventually consistent. Upserts may take a few seconds to be visible to queries. The sample sleeps 3 seconds before searching — adjust for your workload.
- Pooled
HttpClient— the DI extension registersPineconeVectorStoreviaIHttpClientFactory, so HTTP connections are pooled across requests by default. - Namespace vs metadata trade-off — start with namespace mode. Switch to metadata mode only when you've measured namespace overhead at scale.
Versioning
This package is published as Compendium.Adapters.Pinecone. Versions are driven by git tags via MinVer — see docs/RELEASE.md. The release tag is set by the orchestrator after merge to main.
Repository conventions
| Aspect | Choice |
|---|---|
| Target | .NET 9, C# 13 |
| HTTP | Hand-rolled HttpClient + System.Text.Json (camelCase naming policy) |
| Test framework | xUnit 2.9.3 + FluentAssertions 6.12.1 + NSubstitute 5.1.0 |
| HTTP mocking | RichardSzalay.MockHttp 7.0.0 |
| Integration tests | Live against the real Pinecone API, gated on PINECONE_API_KEY (cloud-only — no Testcontainer) |
| Coverage gate | ≥ 90 % line coverage on the unit-testable surface; integration suite covers wire-bound paths |
| Result pattern | Result<T> from Compendium.Core |
Build & test locally
# Unit tests — no Pinecone account required.
dotnet test --filter "FullyQualifiedName!~IntegrationTests"
# Integration tests — needs a Pinecone API key on a free-tier or higher account.
export PINECONE_API_KEY="..."
dotnet test --filter "FullyQualifiedName~IntegrationTests"
The integration suite covers idempotent ensure, namespaced upsert/search/delete round-trip, and collection-not-found behaviour against a live Pinecone serverless index. It skips cleanly when PINECONE_API_KEY is absent via the [RequiresPineconeFact] attribute.
License
MIT — Copyright © 2026 Sassy Solutions.
| Product | Versions Compatible and additional computed target framework versions. |
|---|---|
| .NET | net9.0 is compatible. net9.0-android was computed. net9.0-browser was computed. net9.0-ios was computed. net9.0-maccatalyst was computed. net9.0-macos was computed. net9.0-tvos was computed. net9.0-windows was computed. net10.0 was computed. net10.0-android was computed. net10.0-browser was computed. net10.0-ios was computed. net10.0-maccatalyst was computed. net10.0-macos was computed. net10.0-tvos was computed. net10.0-windows was computed. |
-
net9.0
- Compendium.Abstractions (>= 1.0.1)
- Compendium.Abstractions.VectorStore (>= 1.0.1)
- Compendium.Core (>= 1.0.1)
- Microsoft.Extensions.Configuration.Abstractions (>= 9.0.16)
- Microsoft.Extensions.DependencyInjection.Abstractions (>= 9.0.16)
- Microsoft.Extensions.Http (>= 9.0.16)
- Microsoft.Extensions.Logging.Abstractions (>= 9.0.16)
- Microsoft.Extensions.Options (>= 9.0.16)
- Microsoft.Extensions.Options.ConfigurationExtensions (>= 9.0.16)
- Microsoft.Extensions.Options.DataAnnotations (>= 9.0.16)
NuGet packages
This package is not used by any NuGet packages.
GitHub repositories
This package is not used by any popular GitHub repositories.
| Version | Downloads | Last Updated |
|---|---|---|
| 1.0.0-preview.0 | 57 | 5/18/2026 |