An agent is only as good as the context it has access to. You can write the perfect system prompt, but without the right context, the agent will not deliver good results. AgentOS gives you three primitives for getting context to the agent:Documentation Index
Fetch the complete documentation index at: https://docs.agno.com/llms.txt
Use this file to discover all available pages before exploring further.
| Primitive | Shape | When it loads |
|---|---|---|
| Knowledge | Indexed content (RAG) | Auto-searched before each run, or via tool |
| Dependencies | A dict you pass in | Injected into the prompt and available to tools |
| Context providers | Live external systems | A clean tool surface backed by source-scoped sub-agents |
Knowledge
Knowledge is what the agent looks up: documentation, policies, code conventions, table schemas. It lives in your database with embeddings and surfaces via similarity search.| Flag | Behavior |
|---|---|
search_knowledge=True | The agent gets a search_knowledge_base(query) tool. Known as Agentic RAG. |
add_knowledge_to_context=True | AgentOS runs knowledge.search(message) before each turn and injects the top-k chunks into the prompt. |
Dependencies
Sometimes an agent needs runtime values that aren’t in knowledge: a feature flag, a tenant ID, a per-request DB connection, an API key scoped to the caller.add_dependencies_to_context=True injects them into the system prompt. Tools that take a RunContext parameter get access via run_context.dependencies.
Per-request dependencies override the agent-level ones for a single run:
Context providers
If you’ve built an agent with a real number of tools, you’ve hit three walls:- Context pollution. Every tool description, schema, and example lands in the system prompt. Slack alone is 8 to 12 tools. Add Drive, GitHub, your CRM, and you’re at 50 tools before adding anything custom. Past 20, models start hallucinating tools, calling them with the wrong shape, or skipping the right one.
- Scope collisions.
searchin one toolkit collides withsearchin another.send_messagecould be Slack, email, or your CRM. The agent picks wrong half the time, and no naming convention fixes it. - System-prompt sprawl. Using Slack well requires Slack-specific guidance: look up user IDs before DMing, resolve channel names, prefer
conversations.historyfor channels andconversations.repliesfor threads. Multiply by every API. The system prompt becomes the union of every source’s quirks.
ContextProvider is a thin layer between the agent and the tools that fixes all three:
Agent↔ContextProvider↔Tools
To the calling agent, each provider exposes exactly two tools: query_<id> for natural-language reads, and update_<id> for writes (or a clean read-only error). Behind the tool is a sub-agent scoped to that one source. The sub-agent owns the source’s tools, the source’s quirks, the lookup-before-write patterns, the pagination weirdness. It runs in its own context, returns an answer, and the calling agent gets a clean result.
query_slack, query_drive, query_crm, update_crm. Add ten more sources and the surface stays linear at 2N. The agent’s prompt doesn’t grow with the number of integrations.
Built-in providers
| Provider | Source | Read | Write |
|---|---|---|---|
FilesystemContextProvider | A scoped local directory | query_<id> | — |
WebContextProvider | Web search and fetch (Exa or Parallel; SDK or MCP) | query_<id> | — |
DatabaseContextProvider | Any SQL database via SQLAlchemy | query_<id> | update_<id> |
SlackContextProvider | A Slack workspace | query_<id> | update_<id> |
GmailContextProvider | Gmail via OAuth or service account | query_<id> | update_<id> |
GoogleCalendarContextProvider | Google Calendar via OAuth or service account | query_<id> | update_<id> |
GoogleDriveContextProvider | Google Drive; all-drives + Office extraction | query_<id> | update_<id> |
WikiContextProvider | Git-backed markdown wiki (FS or Git backend) | query_<id> | update_<id> |
WorkspaceContextProvider | Composite: Drive + Gmail + Calendar | query_<id> | update_<id> |
MCPContextProvider | Any MCP server (stdio, SSE, streamable-HTTP) | query_<id> | — |
Web backends
WebContextProvider takes a backend, so you can swap providers without touching the agent:
| Backend | What | When |
|---|---|---|
ExaBackend | Exa direct SDK. web_search + web_extract. | You have an EXA_API_KEY and want full extraction payloads. |
ExaMCPBackend | Exa public MCP server. Keyless, rate-limited. | First experiment with no signup. Keyed for higher throughput. |
ParallelBackend | Parallel direct SDK. web_search + web_extract. | You prefer Parallel’s ranking and excerpt shape. Needs PARALLEL_API_KEY. |
ParallelMCPBackend | Parallel public MCP. web_search + web_fetch (compressed markdown). | Token-efficient output. Keyless for trial; keyed for higher limits. |
Read/write separation
Writable providers (Database, Slack, GitHub) run two sub-agents under the hood with minimum privilege per role:- Database: read sub-agent uses the readonly engine; write sub-agent uses the writable engine. The read path can’t mutate even if the model tries.
- Slack: read sub-agent gets
search_workspace,get_channel_history,get_thread, lookup tools. Write sub-agent getssend_messageand the lookup tools it needs to resolve names. The reader never seessend_message. The writer never sees search. - GitHub: read sub-agent operates on a clone with read-only Workspace + git tools. Write sub-agent operates on a per-session worktree on a
<prefix>/<task>branch and ends in a PR. The agent cannot push to the default branch.
Configuration
Lifecycle
Some providers hold async resources: MCP sessions, watched inboxes, cloned repos. They implementasetup() and aclose(). Bracket their use so the resource is owned by a single task:
FilesystemContextProvider, DatabaseContextProvider with sync engines, the SDK-based web backends) work without asetup / aclose.
Mode
Every provider has amode parameter that controls how it exposes tools to the calling agent:
| Mode | What happens |
|---|---|
ContextMode.default | Provider’s recommended exposure. Read/write providers typically expose two tools: query_<id> + update_<id>. Read-only providers expose query_<id> only. |
ContextMode.agent | Single query_<id> tool wrapping a sub-agent. Good for complex sources that need internal orchestration. |
ContextMode.tools | Expose the underlying tools directly (flat). Calling agent orchestrates raw tools itself. Use for fine-grained control. |
default mode, WebContextProvider wraps its backend in a sub-agent that synthesizes cited answers. In tools mode, your agent calls web_search and web_fetch directly and does its own synthesis. The tradeoff is control vs. complexity.
RunContext propagation
When a provider runs a sub-agent, it extracts auth and framework state from the caller’sRunContext and forwards it:
user_id, session_id, metadata, and dependencies. This ensures:
- Per-user auth tokens reach the sub-agent’s tools
- Framework-injected state (e.g., Slack’s
action_tokeninmetadata) survives the hop - User/session isolation works across provider boundaries
session_state stay with the outer agent. Sub-agents run isolated.
Read/write flags
Providers with both read and write support can be restricted to one direction:Composition
Multi-provider
Three providers on one agent compose cleanly because each provider has its own namespace:query_cookbooks, query_web, query_releases and picks the right one per question. The compositional payoff lands when one provider’s output feeds another’s query: pull a topic from Slack, run a web search on it, synthesize the briefing in one turn.
Custom providers
When the built-ins don’t fit, subclassContextProvider. The base class handles tool wrapping, name derivation, and error shaping.
Required methods (abstract):
| Method | Purpose |
|---|---|
query(question, *, run_context=None) -> Answer | Sync read |
aquery(question, *, run_context=None) -> Answer | Async read |
status() -> Status | Sync health check |
astatus() -> Status | Async health check |
| Method | Default | Override when |
|---|---|---|
update() / aupdate() | Raises NotImplementedError | Provider supports writes |
asetup() | No-op | Need async init (MCP sessions, cache priming) |
aclose() | No-op | Hold long-lived state (watches, connections) |
instructions() | Generic guidance | Want source-specific usage hints |
_default_tools() | [_query_tool()] | Custom tool surface for mode=default |
_all_tools() | [_query_tool()] | Custom surface for mode=tools |
query_faq tool. Same shape as every built-in provider.
Sub-agent model
Every provider runs its own sub-agent on a configurable model. Default to a cheap one for the source-specific work and let the calling agent use a stronger model for synthesis:Provider catalog
Google providers
Agno includes four Google-specific providers. All support two auth methods:Service Account + domain-wide delegation (headless)
Service Account + domain-wide delegation (headless)
For workspace accounts. Set environment variables:
GOOGLE_SERVICE_ACCOUNT_FILE— path to service account JSONGOOGLE_DELEGATED_USER— email to impersonate (required for Gmail since service accounts have no inbox)
OAuth (interactive)
OAuth (interactive)
For personal accounts. Set environment variables:
GOOGLE_CLIENT_IDGOOGLE_CLIENT_SECRETGOOGLE_PROJECT_ID
- Gmail
- Calendar
- Drive
- Workspace
Search, read, draft, send, reply, and manage labels.
| Sub-agent | Tools |
|---|---|
| Read | search_emails, get_message, list_labels |
| Write | draft_email, send_email, reply_to_email, create_label, apply_label |
WikiContextProvider
Read/write access to a directory of markdown files. Choose a backend based on your versioning needs:- Filesystem
- Git
Local directory, no versioning. Good for prototyping.
Optional: Web ingestion
Optional: Web ingestion
Pass a
web backend to let the write sub-agent pull content from URLs before writing:Worked examples
Scout
Open-source company intelligence agent. Navigates live information sources (web, Slack, Drive, wiki, CRM, MCP servers) to assemble context on demand — and builds its own wiki and CRM as it learns.
Filesystem
Agent explores your codebase or docs folder
Database
Read and write with separate engines for safety
MCP Server
Raw MCP tools on the agent, no sub-agent wrapper
Multi-provider
Three sources on one agent, no tool collisions
Web + Slack
Pull topics from Slack, research on web, synthesize
Custom provider
Build your own provider for any data source
Gmail
Search, read, draft, send emails
Calendar
Query events, check availability, create meetings
Wiki (filesystem)
Prose memory backed by local markdown files
Wiki (git)
Prose memory with automatic git commits
Google Workspace
Drive, Gmail, and Calendar in one surface