Context providers inject dynamic runtime data as system messages into every LLM call. Use them when information is needed frequently and fetching it on-demand every time would be wasteful (current URL, hostname, server status, etc.).
Create a file in context_providers/ at the project root. File name must not start with _.
# context_providers/my_provider.py
name = "my_provider"
description = "One-line description of what this injects."
global_provider = False # True = injected in ALL profiles automatically
async def get_context() -> str | None:
"""Return a string or None. None means skip silently."""
return "[System] My info: ..."
| Field | Type | Description |
|---|---|---|
name |
str |
Unique identifier |
description |
str |
What data this provides |
get_context |
async def |
Returns str to inject or None to skip |
| Field | Type | Default | Description |
|---|---|---|---|
global_provider |
bool |
False |
True = inject in every profile; False = only in profiles that list this name in context_providers |
For non-global providers, add the name to the profile's config.json:
"context_providers": ["my_provider"]
After writing, call reload_tools — it reloads both tools and context providers. The new data will appear in the next LLM call.
# context_providers/hostname.py
import socket
name = "hostname"
description = "Injects the current server hostname."
global_provider = True
async def get_context() -> str | None:
return f"[System] Server hostname: {socket.gethostname()}"
role="system" right after the memory summary, before conversation history.get_context() are caught and logged — they never crash the agent.global_provider = True providers are loaded for every profile; no config change needed.navi/context_providers/ and cannot be overwritten by user providers.