seekrit
Docs/CrewAI

CrewAI

CrewAI reads OPENAI_API_KEY and OPENAI_BASE_URL from the environment, and its LLM class takes api_key and base_url directly. All three shapes are short.

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 crew.py
seekrit run -- crewai run
from crewai import Agent, Task, Crew

researcher = Agent(role="Research Specialist", goal="Conduct comprehensive analysis")
search = Task(description="Research the topic: {topic}", expected_output="A report", agent=researcher)

crew = Crew(agents=[researcher], tasks=[search])
print(crew.kickoff(inputs={"topic": "AI safety"}))

CrewAI's own docs tell you never to commit API keys and to use secret management; this is that, without the .env step in between.

2. Resolve in code

import seekrit
from crewai import LLM

secrets = seekrit.Client().resolve()

llm = LLM(model="openai/gpt-5.6-terra", api_key=secrets["OPENAI_API_KEY"])
researcher = Agent(role="Research Specialist", goal="Analyse", llm=llm)

3. Never hold the key

from crewai import LLM

llm = LLM(
    model="openai/gpt-5.6-terra",
    base_url="http://127.0.0.1:8080/openai/v1",
    api_key="{{seekrit:OPENAI_API_KEY}}",
)
# 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"]

# The crew's tools, bounded to the operations they actually need.
[[route]]
prefix = "/github"
upstream = "https://api.github.com"
allow = ["GITHUB_TOKEN"]
methods = ["GET", "POST"]
paths = ["/repos/*/*/issues", "/repos/*/*/issues/*"]

Without running the proxy

CrewAI reaches the network through LiteLLM, whose only seam is a module global:

import httpx, litellm
from seekrit.transport import AsyncSeekritTransport, SeekritTransport

allow = {"api.openai.com": ["OPENAI_API_KEY"]}
litellm.client_session = httpx.Client(transport=SeekritTransport(allow=allow))
litellm.aclient_session = httpx.AsyncClient(transport=AsyncSeekritTransport(allow=allow))

It works, and being process-wide it cannot scope per request. In-process injection sets out the trade-off against the proxy.

Gotchas

  • The tools are the reason to bother. A crew is several agents sharing one process, so every agent effectively has every tool's credentials. The proxy's methods and paths are how you stop a research agent from being able to perform a write the delegation graph never intended.
  • kickoff is one long process. Values resolved at start hold for the whole run. For a crew that runs for hours, either restart on rotation or use shape 3, where the proxy re-resolves on its own interval.
  • Delegation crosses no security boundary. allow_delegation moves work between agents in the same process with the same environment. If two agents must have different reach, that is two processes, or the proxy's session tickets.