Pinecone

Use Pinecone serverless and pod indexes from Flux tasks.

Pinecone is a managed vector database. Flux 0.56.0 has no native Pinecone client — wrap the official SDK in @task and store the API key in Flux’s secret store.

Install

pip install pinecone

The package was renamed from pinecone-client to pinecone in early 2024. Both still resolve on PyPI for now; new code should pin pinecone.

API key

Pinecone authenticates with a single API key. Put it in the Flux secret store rather than an environment variable:

flux secrets set pinecone_api_key pcsk_...

Then declare it on the task:

from flux import task

@task.with_options(secret_requests=["pinecone_api_key"])
async def upsert_vectors(secrets, index_name: str, records: list[dict]) -> int:
    from pinecone import Pinecone
    pc = Pinecone(api_key=secrets["pinecone_api_key"])
    index = pc.Index(index_name)
    index.upsert(vectors=records)
    return len(records)

The secrets dict is injected by Flux when secret_requests is set (flux/secret_managers.py). The key never appears in event logs or in the workflow source that travels server-to-worker.

Create an index

Index creation is a control-plane operation — do it once, outside of workflows, unless you have a real reason to create indexes on the fly:

from pinecone import Pinecone, ServerlessSpec
pc = Pinecone(api_key=...)
pc.create_index(
    name="kb",
    dimension=1536,
    metric="cosine",
    spec=ServerlessSpec(cloud="aws", region="us-east-1"),
)

The free tier allows one index. If create_index fails with a quota error in CI, an existing index is the most likely cause; check pc.list_indexes() before creating.

Query

@task.with_options(secret_requests=["pinecone_api_key"])
async def query(secrets, index_name: str, vector: list[float], k: int = 5):
    from pinecone import Pinecone
    pc = Pinecone(api_key=secrets["pinecone_api_key"])
    index = pc.Index(index_name)
    result = index.query(vector=vector, top_k=k, include_metadata=True)
    return [
        {"id": m.id, "score": m.score, "metadata": m.metadata}
        for m in result.matches
    ]

Pinecone’s query returns a QueryResponse whose matches have .id, .score, .values, and .metadata. Convert to a plain dict before returning so the result serializes cleanly into the event log.

Sparse-dense hybrid

Pinecone supports hybrid search by passing both vector (dense) and sparse_vector (lexical) to query. The sparse vector is {"indices": [...], "values": [...]}. Build sparse vectors with pinecone-text or a BM25 implementation; weight the two with the alpha parameter (0.0 = pure sparse, 1.0 = pure dense). Hybrid only works on indexes created with metric="dotproduct".

Namespaces

Pinecone namespaces are cheap logical partitions inside an index. They fit Flux’s multi-tenant model well: name the namespace after the workflow’s namespace, or after a tenant ID, and pass it to every upsert / query call. There is no separate “create namespace” call — writing to a new namespace creates it.

What goes wrong

See also


Derived against Pinecone Python SDK 5.x, 2026-05.