seekrit
Docs/LlamaIndex

LlamaIndex

LlamaIndex reads OPENAI_API_KEY from the environment by default. For a custom endpoint the parameter is api_base (not base_url), and the class is OpenAILike.

note

Start here if seekrit is new: three commands put the keys in an environment, mint a token bound to it, and export SEEKRIT_TOKEN. A token reads everything in its environment, so there is no per-key or per-framework setup to do before any of the below.

1. Wrap the process

seekrit run -- python query.py
seekrit run -- uvicorn app:app
from llama_index.core import Settings
from llama_index.llms.openai import OpenAI

Settings.llm = OpenAI(model="gpt-5.6-terra")

A RAG app usually needs more than the model key — a vector store URL, a database password, an embedding provider. One seekrit run covers all of them; they are the same environment.

2. Resolve in code

import seekrit
from llama_index.core import Settings
from llama_index.llms.openai import OpenAI

secrets = seekrit.Client().resolve()

Settings.llm = OpenAI(model="gpt-5.6-terra", api_key=secrets["OPENAI_API_KEY"])

In a notebook, use the one-call form instead — it takes the token from a password prompt when there isn't one in the environment, so it never gets saved into the .ipynb, and it returns names rather than values so a displayed cell writes a summary and nothing more:

import seekrit

seekrit.load()

3. Never hold the key

from llama_index.llms.openai_like import OpenAILike

Settings.llm = OpenAILike(
    model="gpt-5.6-terra",
    api_base="http://127.0.0.1:8080/openai/v1",
    api_key="{{seekrit:OPENAI_API_KEY}}",
    is_chat_model=True,
)
# seekrit-proxy.toml
listen = "127.0.0.1:8080"

[[route]]
prefix = "/openai"
upstream = "https://api.openai.com"
allow = ["OPENAI_API_KEY"]
methods = ["POST"]
paths = ["/v1/chat/completions", "/v1/embeddings"]

OpenAILike exists because the first-party OpenAI class assumes OpenAI's own capabilities; tell it is_chat_model=True and, if you use tool calling, is_function_calling_model=True.

Without running the proxy

Both OpenAI and OpenAILike take an http_client:

import httpx
from llama_index.llms.openai import OpenAI
from seekrit.transport import SeekritTransport

Settings.llm = OpenAI(
    model="gpt-5.6-terra",
    api_key="{{seekrit:OPENAI_API_KEY}}",
    http_client=httpx.Client(
        transport=SeekritTransport(allow={"api.openai.com": ["OPENAI_API_KEY"]}),
    ),
)

Weaker than the proxy, since it runs in your process: in-process injection sets out the trade-off. Remember Settings.embed_model needs the same treatment.

Gotchas

  • Embeddings are a second route. Settings.embed_model builds its own client, so pointing only Settings.llm at the proxy leaves embedding calls going direct. Set both, and keep /v1/embeddings in the route's paths.
  • Indexes get built once and read forever. A vector store credential often outlives the process that used it. That is a rotation question, not an injection one — see secret rotation.
  • A notebook is the easiest place to leak a value. print(secrets) in a cell writes plaintext into a file people commit. seekrit.load() exists to make the safe thing the short thing.