Summary
The summarizer runs via the agent SDK, which inherits whatever API key is present in the environment. If a user has a provider API key exported globally in their shell (a setup many tools instruct), background summarization silently bills the metered API instead of the user's interactive (OAuth / subscription) auth — with no warning, no opt-in, and no spend cap. Combined with the retry loop in #103 / #96, this can produce large unexpected charges.
Why it's risky
getApiEnv() passes the full process.env to the spawned subprocess, so a globally-exported API key is used automatically.
- The user never explicitly chose to bill the metered API for background work: interactive use stays on OAuth, but the background summarizer quietly switches to the env key.
- There is no first-run warning, no per-sync cap, and no way to say "only summarize on my interactive auth / a dedicated key."
Request — a guard / explicit opt-in
- At sync start, detect whether summarization would run on an inherited env API key, and warn loudly once (and/or require an explicit opt-in setting before billing the metered API).
- Prefer the user's interactive auth by default; only bill an API key when one is explicitly configured via the existing
EPISODIC_MEMORY_API_* vars (a dedicated key the user opts into), instead of silently inheriting the global one.
- Optional: a per-sync call/spend cap as a backstop.
This makes the cost behavior explicit and prevents a globally-exported key from being billed without the user's knowledge.
Summary
The summarizer runs via the agent SDK, which inherits whatever API key is present in the environment. If a user has a provider API key exported globally in their shell (a setup many tools instruct), background summarization silently bills the metered API instead of the user's interactive (OAuth / subscription) auth — with no warning, no opt-in, and no spend cap. Combined with the retry loop in #103 / #96, this can produce large unexpected charges.
Why it's risky
getApiEnv()passes the fullprocess.envto the spawned subprocess, so a globally-exported API key is used automatically.Request — a guard / explicit opt-in
EPISODIC_MEMORY_API_*vars (a dedicated key the user opts into), instead of silently inheriting the global one.This makes the cost behavior explicit and prevents a globally-exported key from being billed without the user's knowledge.