diff --git a/agent-os/connect-your-os.mdx b/agent-os/connect-your-os.mdx
index 0a999763a..fc94fee5b 100644
--- a/agent-os/connect-your-os.mdx
+++ b/agent-os/connect-your-os.mdx
@@ -3,10 +3,63 @@ title: "Connect Your AgentOS"
description: "Connect your AgentOS to the control plane for monitoring and management."
---
-## Connect Your AgentOS
+Connect a local or deployed AgentOS runtime to monitor and manage its agents, teams, and workflows from the [AgentOS Control Plane](https://os.agno.com).
-1. Open [os.agno.com](https://os.agno.com) and sign in
-2. Click **"Add new OS"**
+## Before You Connect
+
+| Runtime | Requirements |
+|---------|--------------|
+| Local | AgentOS running on your machine and reachable from your browser, usually at `http://localhost:7777` or `http://localhost:8000` |
+| Live | AgentOS available at a browser-reachable HTTPS URL with [Security & Auth](/agent-os/security/overview) configured for production traffic |
+
+
+Live AgentOS connections require a paid plan.
+
+
+## Connect the Runtime
+
+
+
+ Open [os.agno.com](https://os.agno.com), sign in, and click **CONNECT OS**.
+
+
+
+ Choose **Local** or **Live**, then complete the form:
+
+ | Field | Value |
+ |-------|-------|
+ | **Environment** | **Local** for a runtime on your machine. **Live** for a browser-reachable HTTPS endpoint. |
+ | **Endpoint URL** | The AgentOS base URL, such as `http://localhost:7777`. Do not include `/docs` or another route. |
+ | **Name** | The label shown in the runtime selector, such as `Development`. |
+ | **Tags** | Optional labels such as `dev`, `stg`, or `prd`. |
+
+
+
+ Click **CONNECT**. For Control Plane-managed JWT authorization, enable **Token-Based Authorization (JWT)** before connecting. The Control Plane creates a signing key pair and shows the public verification key.
+
+
+
+ If you enabled **Token-Based Authorization (JWT)**, copy the generated public key into `JWT_VERIFICATION_KEY`, run AgentOS with `authorization=True`, then restart or redeploy the runtime.
+
+ ```bash
+ export JWT_VERIFICATION_KEY="your-public-key"
+ ```
+
+ The Control Plane keeps the matching private signing key and uses it to issue scoped tokens. See the [Authorization quickstart](/agent-os/security/authorization/quickstart) for the complete runtime configuration.
+
+ Keep your existing credential setup when the runtime already uses `OS_SECURITY_KEY` or self-managed JWTs. See [Security & Auth](/agent-os/security/overview) for the available authentication paths.
+
+
+
+ Select the runtime again after it restarts.
+
+ | Check | Expected |
+ |-------|----------|
+ | Connection | A green indicator appears beside the runtime name. |
+ | Components | Registered agents, teams, and workflows appear on Home. |
+ | Test run | Select a component in Chat and start a new session. |
+
+
-## Configure Connection
-
-| Field | Description |
-|-------|-------------|
-| **Environment** | Local (`http://localhost:7777`) or Live (your HTTPS URL) |
-| **Endpoint URL** | Where your AgentOS is running |
-| **OS Name** | A descriptive name, e.g. "Development OS" |
-| **Tags** | Optional. Organize with labels like `dev`, `stg`, `prd` |
-
-Click **"CONNECT"**. If successful, your OS appears in the dashboard.
+
+If your browser blocks a local connection, allow local-network access for `os.agno.com`. See [AgentOS Connection Issues](/faq/agentos-connection) for browser-specific steps.
+
-## Verify Connection
+## Next Steps
-| Indicator | Expected |
-|-----------|----------|
-| Status | "Running" |
-| Features | Chat, Knowledge, Memory, Sessions accessible |
-| Agents | Configured agents appear in the chat interface |
\ No newline at end of file
+| Task | Guide |
+|------|-------|
+| Run a component and inspect its session | [AgentOS Control Plane](/agent-os/control-plane) |
+| Configure authentication and permissions | [Security & Auth](/agent-os/security/overview) |
+| Call the runtime from an application | [Using the AgentOS API](/agent-os/using-the-api) |
diff --git a/agent-os/control-plane.mdx b/agent-os/control-plane.mdx
index cf3b64963..cdbe9c4b5 100644
--- a/agent-os/control-plane.mdx
+++ b/agent-os/control-plane.mdx
@@ -1,282 +1,116 @@
---
title: "AgentOS Control Plane"
-description: "A web interface for testing, monitoring, and managing your multi-agent system."
+description: "Run components, inspect runs, and manage AgentOS runtimes."
---
-The control plane at [os.agno.com](https://os.agno.com) is where you chat with agents, view traces, manage knowledge, track sessions, and monitor performance.
+Use the [AgentOS Control Plane](https://os.agno.com) to test agents, teams, and workflows, follow runs from sessions into traces, and manage the state and automation exposed by a connected AgentOS runtime.
-
+
-
+## Follow Your First Run
-It connects directly from your browser to your AgentOS runtime. No data is sent to Agno.
+
+
+ Open **Home** and select the local, staging, or production runtime you want to inspect. A green indicator shows that the browser can reach it.
+
-
+
+ Open **Chat**, choose **Agents**, **Teams**, or **Workflows**, then select a registered component. Start a new session and provide an input.
+
-## Chat Interface
+
+ Open **Sessions** to review stored runs, messages, metrics, session metadata, and summaries when configured.
+
-Chat with agents, collaborate with teams, and run workflows from one screen.
+
+ Open **Traces** to follow instrumented model calls, tool calls, team delegation, and workflow steps. Traces require `tracing=True` and a database available to AgentOS tracing.
+
+
-
-
-
-
-
-
-See [Agents](/agents/overview), [Teams](/teams/overview), and [Workflows](/workflows/overview) for more details.
-
-### Agents
-
-Select an agent from the right panel and start a conversation. Each agent maintains its own history, tools, and instructions. Switching agents won't mix contexts.
-
-### Teams
-
-Switch the toggle to Teams. Use the chat stream to watch how the team divides and solves the task.
-
-
-
-
-
-
-
-### Workflows
-
-Switch to Workflows. Provide input (plain text or structured, depending on the workflow) and watch execution live as steps stream, produce output, and finish.
-
-
-
-
-
-
+## Control Plane Views
-## Studio
+Each view reflects capabilities configured on the selected runtime.
-Build agents, teams, and workflows visually on a live canvas. Drag, drop, configure, and deploy without leaving the control plane.
+| View | Use It To | Runtime Setup |
+|------|-----------|---------------|
+| Home | Select a runtime and open registered components | Agents, teams, or workflows registered with AgentOS |
+| Chat | Run agents and teams, execute workflows, and continue sessions | A registered component |
+| Sessions | Inspect stored runs, messages, summaries, and metrics | A database used by the component or AgentOS |
+| Traces | Follow instrumented operations, timing, errors, and model token metrics when available | `tracing=True` and a database available to tracing |
+| Studio | Compose, test, publish, and version components | A `Registry` and a synchronous AgentOS `db` |
+| Memory | Inspect and update records for memory-enabled agents | User memory and a database |
+| Knowledge | Add and inspect content in registered knowledge bases | A `Knowledge` instance, contents database, vector database, and embedder |
+| Metrics | Review aggregate runs, sessions, users, token usage, and model activity | Stored run and session metrics |
+| Evaluation | Review evaluation results stored by the SDK or AgentOS | Evaluation runs persisted to a database |
+| Approvals | Review tool arguments and resolve paused executions | An AgentOS `db` and approval-enabled tools |
+| Scheduler | Create recurring runs, trigger them manually, and inspect run history | An AgentOS `db` and `scheduler=True` |
-
-
-
-
-
-
-See [Studio](/agent-os/studio/introduction) for setup details.
-
-## Approvals
-
-Pending tool executions can require human confirmation. Approvals pause runs until an admin resolves the request.
-
-
-
-
-
-
+## Inspect and Improve Runs
-See [Approvals](/agent-os/approvals/overview) for setup details.
+With `tracing=True`, AgentOS stores spans for instrumented agent, team, workflow, model, and tool operations. Trace trees show status, timing, errors, and model token metrics when available. Use them to find the model call, tool argument, member response, or workflow step behind an unexpected result.
-## Tracing
+Stored sessions provide the surrounding conversation and run history. The Metrics view summarizes run, session, user, token, and model activity. Individual run and session records include timing and cost when available. Evaluation results let you compare component behavior as models, instructions, tools, and knowledge change.
-Traces capture the complete execution flow of agents and teams. Each trace contains spans representing individual operations (LLM calls, tool executions, etc.) with token usage, latency, and error information.
+| Task | Guide |
+|------|-------|
+| Configure trace storage | [Tracing](/agent-os/tracing/overview) |
+| Work with run and session metrics | [Metrics](/sessions/metrics/overview) |
+| Build and store evaluations | [Agent Evaluation](/features/evaluation) |
-### Tree View
+## Build and Manage State
-Displays spans in a hierarchical structure showing parent-child relationships between operations. Useful for understanding how teams delegate to agents and how agents invoke tools.
+Studio composes agents, teams, and workflows from components registered by the runtime. Save drafts, test them, publish immutable versions, and choose which published version the runtime serves.
-
-
-
-
-
-
-### Waterfall View
+Knowledge and memory expose the state used to ground and personalize runs:
-Visualizes spans on a time axis showing when each operation started, how long it took, and which operations ran in parallel. Helps identify bottlenecks and optimize performance.
+- **Knowledge**: Add and inspect content in knowledge bases registered with AgentOS. Ingestion, chunking, embeddings, and storage follow the knowledge configuration in your application.
+- **Memory**: For agents with user memory enabled, inspect, create, edit, and delete records stored for a `user_id`.
-
-
-
-
-
+| Task | Guide |
+|------|-------|
+| Configure Studio and its Registry | [Studio](/agent-os/studio/introduction) |
+| Register and manage knowledge | [Manage Knowledge](/agent-os/knowledge/manage-knowledge) |
+| Configure user memory | [Memory](/memory/overview) |
-See [Tracing](/agent-os/tracing/overview) for configuration and filter options.
+## Operate the Runtime
-## Session Tracking
+Approvals persist requests for tool executions that require review. Authorized users can inspect the tool and its arguments, approve or reject the request, and follow its resolution history.
-Sessions group related runs under a single `session_id`. Each session captures messages, tool calls, metrics, and summaries for a single conversation. Sessions are stored in your database and can be queried and managed from the control plane.
+The Scheduler stores cron-based jobs for AgentOS endpoints. Use it to create or update schedules, enable or disable execution, trigger a run immediately, and inspect run history.
-
-
-
-
-
+| Task | Guide |
+|------|-------|
+| Add required or audit approvals | [Approvals](/agent-os/approvals/overview) |
+| Configure scheduled execution | [Scheduler](/agent-os/scheduler/overview) |
-See [Chat History](/database/chat-history) and [Session Storage](/database/session-storage) for more details.
+## Data Path
-## Knowledge
+The browser sends requests to the selected AgentOS endpoint. That runtime executes components, enforces its authorization configuration, and reads or writes the state shown in the Control Plane.
-Knowledge bases provide agents with domain-specific information through RAG (Retrieval-Augmented Generation). Manage multiple knowledge bases, add content from URLs, files, or text, and monitor embedding status. Each knowledge base stores documents, chunks them, generates embeddings, and makes them searchable for agents.
+| Layer | Role |
+|-------|------|
+| Control Plane | Provides the browser interface and calls the AgentOS endpoint you select |
+| AgentOS runtime | Runs components, exposes APIs, and enforces runtime authorization |
+| Configured databases | Store sessions, memories, traces, evaluations, approvals, schedules, metrics, and Studio component versions |
+| External services | Models, tools, interfaces, telemetry, and custom exporters follow their own configuration and data paths |
-
-
-
-
-
+The Control Plane reads conversations, traces, memories, and knowledge from the selected runtime and its configured databases. It stores the endpoint and organization metadata needed to connect. Control Plane-managed JWT authorization also stores the private signing key; the runtime receives the corresponding public verification key. Model providers and other external services follow their own configuration. AgentOS anonymous telemetry is separate and can be configured or disabled. See [Telemetry](/telemetry).
-See [Manage Knowledge](/agent-os/knowledge/manage-knowledge) for setup details.
+## Security and Team Access
-## Memories
+Serve live runtimes over HTTPS and configure [Security & Auth](/agent-os/security/overview). The Control Plane can issue RS256 tokens and provides the public verification key for your runtime. JWT scopes control which AgentOS endpoints each role can use. Per-user data isolation is an additional opt-in setting for multi-tenant deployments.
-Memories store information that agents learn about users across conversations. Each memory is tied to a user ID and contains content, topics, timestamps, and the input that generated it. You can view, create, edit, or delete memories from the control plane.
+Owners and administrators can invite members from **Settings > Organization**. Default roles cover owners, administrators, and members. Custom roles are available on the Enterprise plan.
-
-
-
-
-
-
-See [Memory](/memory/overview) for more details.
-
-## Schedules
-
-Automate agents, teams, and workflows via AgentOS cron schedules. Configure custom intervals, retry logic, and timezones. Use the control plane to monitor run history, enable/disable job states, or trigger manual executions.
-
-For setup and API details, see [Scheduler](/agent-os/scheduler/overview) documentation.
-
-
-
-
-
-
-
-## Managing Your AgentOS
-
-Connect and inspect your AgentOS runtimes from a single interface. Switch between local development and production instances and monitor connection health.
-
-
-
-
-
-
-
-See [Connect Your AgentOS](/agent-os/connect-your-os) for the connection steps.
-
-## Authorization
-
-Enable JWT verification and generate key pairs from the control plane, either when connecting an OS or later from Settings.
-
-
-
-
-
-
-
-See [AgentOS Security](/agent-os/security/overview) and [Authorization](/agent-os/security/authorization/overview) for setup details.
-
-## User Management
-
-Invite team members by entering their email addresses. Separate multiple emails with commas or press Enter/Tab between addresses.
-
-Every organization has three default roles. Custom roles are available on the Enterprise plan.
-
-| Role | Access |
-|------|--------|
-| **Owner** | Full access including billing, organization settings, and deletion |
-| **Administrator** | Manage members, roles, settings, and resources; cannot update billing or delete the organization |
-| **Member** | Run and edit AgentOS resources; cannot delete resources or manage members |
-
-See [Roles](/agent-os/security/authorization/roles) for the full capability matrix and custom role setup.
-
-
-
-
-
-
+| Task | Guide |
+|------|-------|
+| Connect another runtime | [Connect Your AgentOS](/agent-os/connect-your-os) |
+| Configure JWT verification | [Authorization Quickstart](/agent-os/security/authorization/quickstart) |
+| Review roles and scopes | [Roles](/agent-os/security/authorization/roles) |
+| Isolate persistent data by user | [Per-User Data Isolation](/agent-os/security/authorization/user-isolation) |
diff --git a/agent-os/introduction.mdx b/agent-os/introduction.mdx
index a8bc38b87..143facd32 100644
--- a/agent-os/introduction.mdx
+++ b/agent-os/introduction.mdx
@@ -1,20 +1,12 @@
---
title: "What is AgentOS?"
sidebarTitle: "Introduction"
-description: "The runtime for your agent platform."
+description: "The FastAPI runtime for serving agents, teams, and workflows."
---
-**AgentOS is a FastAPI app that turns your agents into a platform.** It's a backend service that:
+**AgentOS is a FastAPI-powered runtime for serving multi-agent systems.**
-1. Runs agents via REST API, MCP, or interfaces like Slack, WhatsApp and Telegram.
-2. Maintains long-running stateful sessions that last from minutes to days to weeks.
-3. Is durable across restarts, replicas, and infrastructure failures.
-4. Is secure against unauthenticated access.
-5. Logs, traces and audits every run and action.
-
-Build your agents using the [Agno SDK](/sdk/introduction). Run them using the AgentOS runtime.
-
-Here's the smallest possible AgentOS:
+The smallest AgentOS looks like this:
```python agno_assist.py
from agno.agent import Agent
@@ -32,72 +24,79 @@ agent_os = AgentOS(agents=[agent])
app = agent_os.get_app()
```
-## Key Features
+This registers one agent, stores its sessions in a local SQLite database, and returns a FastAPI app that you can run locally or deploy to your cloud provider.
+
+Engineering teams use AgentOS to serve agents, teams, and workflows through one backend. It provides REST endpoints for runs, sessions, memory, knowledge, evaluations, approvals, and schedules. Add MCP, messaging interfaces, tracing, and JWT authorization as your deployment needs them.
+
+Build components with the [Agno SDK](/sdk/introduction) or supported adapters for the [Claude Agent SDK, LangGraph, DSPy, and Antigravity](/agent-os/multi-framework/overview). Register them with AgentOS to power product features, automations, and internal tools.
-- **Production API**: 50+ ready to use endpoints with SSE-compatible streaming.
-- **Data Ownership**: Sessions, memory, knowledge, and traces stored in your database.
-- **Request Isolation**: No state bleed between users, agents, or sessions.
-- **Security**: JWT-based RBAC with hierarchical scopes.
-- **Observability**: Traces stored in your database with no third-party egress or vendor lock-in.
-- **Governance**: Guardrails, human-in-the-loop, and approval flows for full control.
-- **Multi-framework**: Serve agents built with the Claude Agent SDK, LangGraph and DSPy alongside native Agno agents. See [Multi-Framework Support](/agent-os/multi-framework/overview).
+## What AgentOS Provides
+
+| Capability | What It Does |
+|------------|--------------|
+| API | Exposes 80+ REST endpoints with SSE streaming for runs |
+| Persistence | Stores sessions and enabled memory, knowledge, evaluation, approval, schedule, and trace data in configured databases |
+| Request isolation | Deep-copies native Agno components on core REST, MCP, and A2A run endpoints |
+| Authorization | Supports JWT validation, endpoint permissions, service accounts, and opt-in per-user data isolation |
+| Observability | Writes OpenTelemetry traces to a configured database when tracing is enabled |
+| Interfaces | Serves MCP, A2A, AG-UI, Slack, WhatsApp, and Telegram when configured |
+| Multi-framework | Runs native Agno components alongside Claude Agent SDK, LangGraph, DSPy, and Antigravity adapters |
## Architecture
AgentOS has two parts:
-1. **Runtime**: A FastAPI service that runs agents, teams, and workflows.
-2. **Control plane**: A UI for managing, monitoring, and debugging your system.
+| Layer | Role |
+|-------|------|
+| Runtime | Runs agents, teams, and workflows as a FastAPI service |
+| Control Plane | Provides the web interface for testing, inspecting, and operating connected runtimes |
-The runtime exposes the APIs that power both the control plane and your AI products. The runtime can serve agents built with the [Agno SDK](/sdk/introduction), the [Claude Agent SDK, LangGraph, or DSPy](/agent-os/multi-framework/overview).
+The runtime exposes the same APIs to your product and the [AgentOS Control Plane](/agent-os/control-plane).
-## Private by Design
-
-Most AI tooling stores your data on their servers. You pay retention costs, deal with egress fees, and depend on their security. AgentOS runs entirely in your infrastructure: the runtime runs as a container in your cloud, and the [control plane](/agent-os/control-plane) connects directly from your browser. No proxies. No data relays.
+## Where Data Flows
-- **Your database**: Sessions, memory, knowledge, traces. All stored where you control it.
-- **Zero transmission**: No conversations, logs, or metrics sent to Agno.
-- **From browser to runtime**: The control plane connects from your browser to the runtime. Agno stores no data except for your runtime endpoint. All data resides in your database.
+Your AgentOS runtime and configured databases run in infrastructure you control. The Control Plane sends requests directly from your browser to the selected runtime.
-See [AgentOS Security](/agent-os/security/overview) for more details.
+| Layer | Data Path |
+|-------|-----------|
+| Runtime | Runs in your infrastructure |
+| Stored application state | Written to the databases you configure |
+| Control Plane requests | Travel from the browser to the selected runtime |
+| Models, tools, and interfaces | Call the external services you configure |
+| Agno telemetry | Sends usage metadata according to your telemetry configuration |
-
-
-
+See [Telemetry](/telemetry) for the collected fields and configuration options. See [Security & Auth](/agent-os/security/overview) for runtime authentication and authorization.
## Next Steps
-
- Initialize and serve a basic agent.
+
+ Serve one agent and store its sessions in SQLite.
-
- Manage AgentOS using a Web UI.
+
+ Connect a local or deployed runtime to the web interface.
-
- Inspect sessions and debug traces.
+
+ Run components, inspect execution, and operate the connected runtime.
-
- Parameter reference and configuration options for the AgentOS class.
+
+ Protect endpoints with a security key, JWTs, and scoped permissions.
+
+## Developer Resources
+
+- [Configure AgentOS](/agent-os/overview)
+- [AgentOS class reference](/reference/agent-os/agent-os)
diff --git a/agent-os/overview.mdx b/agent-os/overview.mdx
index 79582e8f7..44db69318 100644
--- a/agent-os/overview.mdx
+++ b/agent-os/overview.mdx
@@ -1,124 +1,73 @@
---
-title: "Overview"
-description: "The production runtime and control plane for your agentic systems."
+title: "Configure AgentOS"
+sidebarTitle: "Runtime Setup"
+description: "Configure persistence, tracing, authentication, MCP, interfaces, and scheduling for an AgentOS runtime."
---
-AgentOS transforms your agents into a production-ready API.
+AgentOS gives engineering teams building agent-powered products one FastAPI runtime for agents, teams, and workflows. The runtime provides stable APIs for runs, sessions, memory, knowledge, traces, schedules, and approvals.
-A minimal application looks like this:
-
-```python my_os.py
+```python product_os.py
+from agno.agent import Agent
+from agno.db.sqlite import SqliteDb
+from agno.models.anthropic import Claude
from agno.os import AgentOS
+db = SqliteDb(db_file="agentos.db")
+
+agent = Agent(
+ id="product-agent",
+ model=Claude(id="claude-sonnet-4-5"),
+)
+
agent_os = AgentOS(
- name="My AgentOS",
- agents=[my_agent],
- teams=[my_team],
- workflows=[my_workflow],
- tracing=True
+ id="product-platform",
+ agents=[agent],
+ db=db,
+ tracing=True,
)
app = agent_os.get_app()
if __name__ == "__main__":
- agent_os.serve(app="my_os:app", reload=True)
+ agent_os.serve(app="product_os:app", reload=True)
```
-## Parameters
-
-| Parameter | Type | Default | Description |
-| ------------------------- | ------------------------ | ------- | -------------------------------------------------------------- |
-| `id` | `str` | `None` | Unique instance ID. Generated from `name` or a UUID when unset |
-| `name` | `str` | `None` | AgentOS name |
-| `description` | `str` | `None` | AgentOS description |
-| `version` | `str` | `None` | AgentOS version |
-| `agents` | `List[Agent]` | `None` | Agents to include |
-| `teams` | `List[Team]` | `None` | Teams to include |
-| `workflows` | `List[Workflow]` | `None` | Workflows to include |
-| `db` | `BaseDb` or `AsyncBaseDb` | `None` | Database used for the AgentOS |
-| `checkpoint` | `str` | `None` | Default checkpoint level for agents without their own: `"runs"`, `"tool-batch"`, or `"tools"` |
-| `tracing` | `bool` | `False` | Enable tracing to AgentOS `db` |
-| `knowledge` | `List[Knowledge]` | `None` | Knowledge bases |
-| `interfaces` | `List[BaseInterface]` | `None` | Agent interfaces ([docs](/agent-os/interfaces/overview)) |
-| `a2a_interface` | `bool` | `False` | Expose agents and teams over an A2A server ([docs](/agent-os/interfaces/a2a/introduction)) |
-| `config` | `str` or `AgentOSConfig` | `None` | Configuration path or object ([docs](/agent-os/config)) |
-| `settings` | `AgnoAPISettings` | `None` | API settings for the OS |
-| `base_app` | `FastAPI` | `None` | Custom FastAPI app ([docs](/agent-os/custom-fastapi/overview)) |
-| `on_route_conflict` | `str` | `"preserve_agentos"` | Route conflict handling with a custom `base_app`: `"preserve_agentos"`, `"preserve_base_app"`, or `"error"` |
-| `lifespan` | `Any` | `None` | Lifespan context manager ([docs](/agent-os/lifespan)) |
-| `authorization` | `bool` | `False` | Enable authorization ([docs](/agent-os/security/authorization/overview)) |
-| `authorization_config` | `AuthorizationConfig` | `None` | JWT verification config |
-| `mcp_server` | `bool` or `MCPServerConfig` | `False` | Enable MCP server ([docs](/agent-os/mcp/mcp)) |
-| `mcp_auth` | `AuthProvider` | `None` | Auth provider for the MCP endpoint (OAuth for connector clients). Requires `mcp_server` |
-| `cors_allowed_origins` | `List[str]` | `None` | Allowed CORS origins |
-| `auto_provision_dbs` | `bool` | `True` | Auto-provision databases |
-| `run_hooks_in_background` | `bool` | `False` | Run hooks in background |
-| `telemetry` | `bool` | `True` | Enable telemetry |
-| `registry` | `Registry` | `None` | Component registry for the OS ([docs](/agent-os/studio/registry)) |
-| `scheduler` | `bool` | `False` | Enable the cron scheduler ([docs](/agent-os/scheduler/overview)) |
-| `scheduler_poll_interval` | `int` | `15` | Seconds between scheduler poll cycles |
-| `scheduler_base_url` | `str` | `None` | Base URL for scheduler HTTP calls. Falls back to `http://127.0.0.1:7777` |
-| `internal_service_token` | `str` | `None` | Token for scheduler-to-OS auth. Auto-generated when the scheduler is enabled |
-
-See [AgentOS class reference](/reference/agent-os/agent-os) for details.
-
-## Methods
-
-### `get_app()`
-
-Returns the configured FastAPI application.
-
-### `serve()`
-
-Starts the AgentOS server.
-
-| Parameter | Type | Default | Description |
-| --------- | ------------------ | ----------- | ----------------------------------- |
-| `app` | `str` or `FastAPI` | Required | FastAPI app instance or module path |
-| `host` | `str` | `localhost` | Host to bind |
-| `port` | `int` | `7777` | Port to bind |
-| `workers` | `int` | `None` | Number of workers |
-| `reload` | `bool` | `False` | Enable auto-reload |
-
-#### Environment variable overrides
-
-`serve()` reads `AGENT_OS_HOST` and `AGENT_OS_PORT` from the environment. When set, they override the `host` and `port` arguments.
-
-| Environment Variable | Overrides | Default |
-| -------------------- | --------- | ----------- |
-| `AGENT_OS_HOST` | `host` | `localhost` |
-| `AGENT_OS_PORT` | `port` | `7777` |
-
-Precedence: environment variable > explicit argument > default value.
-
-This is useful for containerized deployments where host and port are configured externally:
-
-```bash
-# In your Dockerfile or orchestrator config
-ENV AGENT_OS_HOST=0.0.0.0
-ENV AGENT_OS_PORT=8000
-```
+`db` supplies the default storage for the registered agent and stores its traces. `get_app()` returns the configured FastAPI application.
-```python my_os.py
-# No host/port needed. serve() reads from AGENT_OS_HOST and AGENT_OS_PORT.
-if __name__ == "__main__":
- agent_os.serve(app="my_os:app", reload=True)
-```
+## Choose What to Enable
-### `resync(app)`
+Start with the capabilities your application needs. Add the rest as the platform moves toward production.
-Reloads agents, teams, workflows, and resources on the given FastAPI app.
+| Requirement | Configuration | Guide |
+|-------------|---------------|-------|
+| Serve agents, teams, and workflows | `agents=[...]`, `teams=[...]`, `workflows=[...]` | [Use the API](/agent-os/using-the-api) |
+| Persist sessions and enabled memory | `db=...` | [Databases](/database/overview) |
+| Inspect production runs | `tracing=True` with a database | [Tracing](/agent-os/tracing/overview) |
+| Protect API endpoints | `authorization=True` with a JWT verification source | [Authorization](/agent-os/security/authorization/quickstart) |
+| Isolate user data | JWT authorization plus `AuthorizationConfig(user_isolation=True)` | [Per-user isolation](/agent-os/security/authorization/user-isolation) |
+| Connect MCP clients | `mcp_server=True`; add `mcp_auth=...` for OAuth | [MCP](/agent-os/mcp/mcp) |
+| Add chat and protocol surfaces | `interfaces=[...]` | [Interfaces](/agent-os/interfaces/overview) |
+| Run recurring jobs | `scheduler=True` with an AgentOS database | [Scheduler](/agent-os/scheduler/overview) |
+| Extend an existing FastAPI service | `base_app=app` | [Custom FastAPI](/agent-os/custom-fastapi/overview) |
-## Configuration
+## Python and YAML Configuration
-The `config` parameter accepts a YAML path or `AgentOSConfig` object. Use it to configure prompts, display names, and database settings.
+Register live components through the `AgentOS` constructor. Set `config` to a YAML path or an `AgentOSConfig` object for quick prompts, display names, and database mappings used by the Control Plane.
```python
agent_os = AgentOS(
- name="My AgentOS",
- agents=[my_agent],
- config="config.yaml", # or AgentOSConfig(...)
+ agents=[agent],
+ db=db,
+ config="config.yaml",
)
```
-See [Configuration](/agent-os/config) for details.
+See [AgentOS Configuration](/agent-os/config) for the YAML schema and typed configuration options.
+
+## Developer Resources
+
+| Task | Guide |
+|------|-------|
+| Run a local AgentOS | [Run Your AgentOS](/agent-os/run-your-os) |
+| Call agents from an application | [Use the AgentOS API](/agent-os/using-the-api) |
+| Review every constructor parameter and method | [AgentOS class reference](/reference/agent-os/agent-os) |
diff --git a/agent-os/run-your-os.mdx b/agent-os/run-your-os.mdx
index c90efa727..a17c9e5e7 100644
--- a/agent-os/run-your-os.mdx
+++ b/agent-os/run-your-os.mdx
@@ -1,9 +1,11 @@
---
-title: "Run Your AgentOS"
-description: "Run a local AgentOS in a few lines of code."
+title: "Run AgentOS Locally"
+description: "Serve one agent through AgentOS with SQLite-backed sessions."
---
-Save the following code to `agno_assist.py`:
+Run a local AgentOS with one agent and persistent session history.
+
+Save the following code as `agno_assist.py`:
```python agno_assist.py
from agno.agent import Agent
@@ -25,23 +27,23 @@ if __name__ == "__main__":
```
-
-An Agent served as a FastAPI application with persistent sessions.
-
+This creates a FastAPI application with one agent and SQLite-backed session storage.
-## Run Your AgentOS
+Requires [uv](https://docs.astral.sh/uv/).
+
+## Start the Server
-
+
- ```bash Mac
+ ```bash macOS and Linux
uv venv --python 3.12
source .venv/bin/activate
```
- ```bash Windows
+ ```powershell Windows PowerShell
uv venv --python 3.12
- .venv\Scripts\activate
+ .venv\Scripts\Activate.ps1
```
@@ -52,32 +54,54 @@ An Agent served as a FastAPI application with persistent sessions.
```
-
+
- ```bash Mac
- export ANTHROPIC_API_KEY=sk-***
+ ```bash macOS and Linux
+ export ANTHROPIC_API_KEY="sk-***"
```
- ```bash Windows
- setx ANTHROPIC_API_KEY sk-***
+ ```powershell Windows PowerShell
+ $env:ANTHROPIC_API_KEY="sk-***"
```
-
+
```bash
python agno_assist.py
```
-Your AgentOS is now running at `http://localhost:7777`.
+AgentOS is now running at `http://localhost:7777`.
| Endpoint | Description |
|----------|-------------|
-| `http://localhost:7777` | Connect to the control plane |
+| `http://localhost:7777` | AgentOS API information |
+| `http://localhost:7777/health` | Runtime health check |
| `http://localhost:7777/docs` | Interactive API documentation |
-| `http://localhost:7777/config` | View AgentOS configuration |
+| `http://localhost:7777/config` | Runtime configuration and registered capabilities |
+
+## Run the Agent
+
+
+```bash macOS and Linux
+curl -X POST http://localhost:7777/agents/agno-assist/runs \
+ -F 'message=What can you help me with?' \
+ -F 'stream=false'
+```
+```powershell Windows PowerShell
+curl.exe -X POST http://localhost:7777/agents/agno-assist/runs `
+ -F "message=What can you help me with?" `
+ -F "stream=false"
+```
+
+
+AgentOS creates a session, runs the agent, and stores the session in `agno.db`.
-To manage your AgentOS in a UI, head to [os.agno.com](https://os.agno.com) and connect this runtime. See [Connect Your AgentOS](/agent-os/connect-your-os) for the steps.
+## Next Steps
-For the full list of endpoints AgentOS exposes, see the [AgentOS API reference](/reference-api/overview).
+| Task | Guide |
+|------|-------|
+| Manage the runtime in a web interface | [Connect Your AgentOS](/agent-os/connect-your-os) |
+| Call agents from your application | [Using the AgentOS API](/agent-os/using-the-api) |
+| Browse every endpoint | [AgentOS API reference](/reference-api/overview) |
diff --git a/agent-platform/create-agent.mdx b/agent-platform/create-agent.mdx
index 28a050832..17bc9d7f8 100644
--- a/agent-platform/create-agent.mdx
+++ b/agent-platform/create-agent.mdx
@@ -1,29 +1,32 @@
---
title: Create an Agent
-description: "Use Claude Code to create a new agent."
+description: "Use a coding-agent skill to create and verify an agent."
---
-Next we're going to create a new agent using Claude Code.
+The codebase keeps agent code and eval cases in one repository, and the local runtime exposes logs, traces, and live behavior. A coding agent can use this context to create and verify new agents for you.
-Because you're running a unified platform (i.e. code, data and logs live in one place), coding agents can manage it end-to-end. The codebase ships five skills that cover the full agent development lifecycle.
+There are two ways to create an agent:
-Let's try `/create-new-agent`.
+| You want | Use |
+|----------|-----|
+| Agent source stored in the repository | `create-new-agent` skill |
+| Agent configuration stored in Postgres | Agent Builder in the AgentOS UI |
## Run the skill
-Open Claude Code (or your favorite coding agent) in your `agent-platform` directory and run:
+Open your coding agent in the `agent-platform` directory and ask it to run:
```text
-/create-new-agent
+Run the create-new-agent skill in .agents/skills.
```
-Claude will ask a few questions and build your agent out.
+Give the coding agent a clear brief and it starts building. For an open-ended goal, it asks for the context it needs to choose the pattern and tools.
-Once the spec is locked in, Claude generates `agents/.py`, registers it in `app/main.py`, adds quick prompts to `app/config.yaml`, restarts the container, and smoke-tests it live.
+Once the specification is clear, it generates `agents/.py`, registers the agent in `app/main.py`, adds quick prompts to `app/config.yaml`, restarts the container, and smoke-tests the live endpoint.
-## Test your agents on the AgentOS UI
+## Test your agent on the AgentOS UI
-Open [os.agno.com](https://os.agno.com), select your new agent in the sidebar, and try a few prompts:
+Open [os.agno.com](https://os.agno.com), click **Refresh**, choose your new agent from the **Agents** dropdown, and try a few prompts:
- **The golden path.** What you built the agent for.
- **Edge cases.** Unusual inputs, ambiguous questions, partial information.
@@ -31,11 +34,11 @@ Open [os.agno.com](https://os.agno.com), select your new agent in the sidebar, a
## Do it manually
-The `/create-new-agent` skill automated the agent creation process. To do it manually:
+The `create-new-agent` skill automates the agent creation process. To do it manually:
- Create a file in `agents/.py`.
- Register the agent in `app/main.py`.
-- Add quick-start prompts in `app/config.yaml`.
+- Add quick prompts in `app/config.yaml`.
The agent file skeleton and the `app/main.py` registration are in [Railway Reference](/deploy/templates/railway/reference), under "Add an agent".
diff --git a/agent-platform/evals.mdx b/agent-platform/evals.mdx
index 5ccb23318..32ea4e911 100644
--- a/agent-platform/evals.mdx
+++ b/agent-platform/evals.mdx
@@ -1,15 +1,13 @@
---
title: Evals
-description: "Lock in agent behavior with regression tests."
+description: "Turn expected agent behavior into repeatable checks for development, CI, and scheduled runs."
---
-Evals are regression tests for your agents. Rerun the same prompts against the same agents and behavior drift becomes visible.
-
-`/improve-agent` generates probes from an agent's instructions to find new weaknesses. Evals preserve known behavior as repeatable cases.
+Probes help you discover weaknesses. Evals turn the behavior you care about into repeatable checks that can run before release, in CI, and on a schedule.
## Cases
-Cases live in `evals/cases.py`. Each case sends one input to an agent (`agent=`) and optionally checks two things:
+Cases live in `evals/cases.py`. Each case sends one input to an agent (`agent=`) and can run up to two checks:
- **judge**: `AgentAsJudgeEval` scores the response against `criteria` (binary pass/fail) using an LLM.
- **reliability**: `ReliabilityEval` checks which tools fired against `expected_tool_calls`.
@@ -46,9 +44,17 @@ Add tags to group your cases into suites. The template uses three tags: `smoke`,
## Run the suite
-The suite runs on the host, calls the model, and logs results to your local Postgres through `eval_db`. Start the platform first (`docker compose up -d`) and make sure `.env` has your `OPENAI_API_KEY`.
+The suite imports agents on the host and writes results to Postgres through `eval_db`. Start the database, activate the local virtual environment, and set `OPENAI_API_KEY` in `.env`.
+
+
+ ```bash
+ docker compose up -d agentos-db
+ ```
+
+
+
The eval suite runs on the host and needs a local virtual environment:
@@ -68,15 +74,18 @@ The suite runs on the host, calls the model, and logs results to your local Post
```bash
- python -m evals --tag smoke # fast suite
- python -m evals # full suite
+ python -m evals --tag smoke # fast checks
+ python -m evals --tag release # pre-release suite
+ python -m evals --tag live # checks that depend on live sources
+ python -m evals # all cases
```
Other options:
```bash
- python -m evals -v # stream the agent run with full panels
- python -m evals --name # single case while iterating
+ python -m evals --name # one case while iterating
+ python -m evals --tag release --json-output out.json
+ python -m evals -v # stream full run panels
```
@@ -85,36 +94,39 @@ The suite runs on the host, calls the model, and logs results to your local Post
Each case prints its response and the verdicts for the checks it defines. The run ends with an `Eval Summary` table.
-Results write to Postgres via `eval_db`. The eval history shows up on [os.agno.com](https://os.agno.com) alongside your sessions and traces, so you can see when a case started failing and what changed.
+Results are written to Postgres via `eval_db`. The eval history appears on [os.agno.com](https://os.agno.com) alongside your sessions and traces, so you can compare inputs, responses, and verdicts across runs.
## Diagnose failures with your coding agent
-Open your coding agent and run:
+Open your coding agent and ask it to run:
```text
-/eval-and-improve
+Run the eval-and-improve skill in .agents/skills.
```
-The coding agent runs the suite, triages every failure (bad criteria, real regression, flaky LLM judge), and proposes in-scope fixes. It edits the agent or the case and re-runs until the suite is green.
+The coding agent runs the suite and classifies failures as bad criteria, real regressions, or unreliable LLM judgments. It proposes scoped fixes, updates the agent or case, and re-runs the affected checks.
+
+## Choose when to run evals
-## When to run evals
+These behavioral checks call models, so choose a cadence that fits the cost and confidence you need.
-| Trigger | Frequency |
-| ------------------------------------- | --------------------- |
-| Before deploying a change to an agent | Every time |
-| As part of CI | Every PR |
-| Against production | On a daily cron |
-| After bumping a model version | Every time |
+| Situation | Suggested run |
+| --------- | ------------- |
+| While changing one behavior | Run the affected case with `--name `. |
+| Before a release | Run the `release` tag when you want broader confidence. |
+| In CI | Use stable `smoke` or `release` cases. Leave `live` cases out. |
+| After changing a model | Run the cases for affected agents. |
+| On a schedule | Run `smoke` cases when recurring model calls are useful. |
-The template ships a `run_evals` workflow for scheduled checks. Set `ENABLE_SCHEDULED_EVALS=True` to run the `smoke`-tagged cases daily. See [scheduling](/features/scheduling) for the cron API.
+The template ships a `run_evals` workflow for scheduled checks. Scheduled evals are off by default because they make model calls. Set `ENABLE_SCHEDULED_EVALS=True` to run the `smoke`-tagged cases daily. See [scheduling](/features/scheduling) for the cron API.
## What good cases look like
- **Specific.** "Returns a JSON object with `ticker` and `price`" beats "Returns the right answer".
-- **Stable.** Avoid prompts whose correct answer changes daily. Use phrasing like "describes a real, recent..." instead of locking in a specific result.
+- **Stable.** Avoid prompts whose correct answer changes daily. Use phrasing like "describes a real, recent..." so the case remains useful as the answer changes.
- **Scoped to one behavior.** One case per behavior makes failures easy to read.
-- **Anchored to tools.** `expected_tool_calls` catches the failure mode where the agent confidently makes things up instead of calling a tool.
+- **Anchored to tools.** `expected_tool_calls` catches responses that skip a required tool call.
## Next
-[Next steps →](/agent-platform/next-steps)
+[Run your platform on Railway →](/agent-platform/run-railway)
diff --git a/agent-platform/improve-agent.mdx b/agent-platform/improve-agent.mdx
index a08da4129..8d8d20bf2 100644
--- a/agent-platform/improve-agent.mdx
+++ b/agent-platform/improve-agent.mdx
@@ -1,45 +1,54 @@
---
title: Improve an Agent
-description: "Run autonomous probe, judge, and edit loops against a live agent."
+description: "Probe a live agent, inspect failures, and verify focused changes."
---
+Once an agent works on its main path, test the edges it promises to handle. The template gives coding agents the instructions, runtime logs, and live endpoint they need to probe behavior and make small verified changes.
+
The template includes two coding-agent skills for changing and testing a live agent:
-- `/improve-agent`. Your coding agent derives probes from the agent's instructions, judges responses, and edits until they pass. **Autonomous.**
-- `/extend-agent`. You drive this one: add a tool, refine a prompt, or fix a bug.
+- `improve-agent` derives probes from the agent's instructions, judges responses, and makes focused edits.
+- `extend-agent` takes a change you specify, such as adding a tool, refining a prompt, or fixing a bug.
-`/improve-agent` edits `agents/.py`. `/extend-agent` can also update registration, quick prompts, and dependencies when the requested change requires them. The local container reloads code edits before the next probe.
+`improve-agent` edits `agents/.py`. `extend-agent` can also update registration, quick prompts, and dependencies when the requested change requires them. The local container reloads code edits before the next probe.
-## Improve: autonomous probe-and-judge
+## Improve: probe, judge, and edit
-Open your coding agent in the `agent-platform` directory and run:
+Open your coding agent in the `agent-platform` directory and ask it to run:
```text
-/improve-agent
+Run the improve-agent skill in .agents/skills.
```
-The coding agent reads the target agent's `INSTRUCTIONS` and typically derives 8-12 probes across four categories: golden path, edge cases, tool selection, and adversarial. For each probe, it calls the live container, reads tool calls from the logs, and judges PASS or FAIL against what the instructions promise. For every failure, it changes one lever: instructions, tools, context provider, model, or `num_history_runs`. It re-runs failed probes and spot-checks previously passing probes for regressions.
+The skill:
+
+1. Reads the target agent's `INSTRUCTIONS` and typically derives 8-12 probes across golden path, edge cases, tool selection, and adversarial behavior.
+2. Runs each probe against the live container, reads tool calls from the logs, and judges the response against what the instructions promise.
+3. Changes one part of the agent for each failure: instructions, tools, context provider, model, or `num_history_runs`.
+4. Re-runs failed probes and spot-checks passing probes for regressions.
+
+If the same probe fails three times or the skill reaches five edit cycles, it stops and reports the blocker.
## Extend: user-driven changes
When you have a specific change in mind, run:
```text
-/extend-agent
+Run the extend-agent skill in .agents/skills.
```
-The coding agent asks what to change. You describe a tool to add, a prompt to refine, or a bug to fix. The agno-docs MCP grounds toolkit and API changes. Each iteration makes and verifies one small change.
+The coding agent asks what to change. You describe a tool to add, a prompt to refine, or a bug to fix. It checks the current Agno documentation before changing toolkit or API usage. Each iteration makes and verifies one small change.
## When to run each
| Situation | Skill |
|-----------|-------|
-| Just created an agent and want to harden it before deploying | `/improve-agent` |
-| Users report the agent is missing the point | `/improve-agent` |
-| You want to add a new tool or knowledge base | `/extend-agent` |
-| You hit a specific bug | `/extend-agent` |
-| You just extended an agent and want to confirm nothing regressed | `/improve-agent` |
+| Just created an agent and want to harden it before deploying | `improve-agent` |
+| Users report the agent is missing the point | `improve-agent` |
+| You want to add a new tool or knowledge base | `extend-agent` |
+| You hit a specific bug | `extend-agent` |
+| You just extended an agent and want to confirm nothing regressed | `improve-agent` |
## Next
-[Run your platform on Railway →](/agent-platform/run-railway)
+[Lock in behavior with evals →](/agent-platform/evals)
diff --git a/agent-platform/next-steps.mdx b/agent-platform/next-steps.mdx
index 77f033e2e..a6a4389e3 100644
--- a/agent-platform/next-steps.mdx
+++ b/agent-platform/next-steps.mdx
@@ -3,11 +3,9 @@ title: Next Steps
description: "Add teams, workflows, scheduled tasks, and interfaces to your agent platform."
---
-You now have a deployed agent platform with evals, JWT auth, and a set of coding-agent skills that cover the full lifecycle: create → improve → evaluate → maintain.
+Your platform now runs locally and on Railway with persisted state, authentication, traces, evals, and a coding-agent development loop. Extend it with teams, workflows, schedules, and the interfaces your users already use.
-The sections below cover the next level: teams and workflows for multi-step logic, scheduled tasks for proactive runs, and interfaces that put your agents where your users are.
-
-## Going beyond agents
+## Add teams and workflows
| Pattern | Use it when | Reference |
| -------------- | ------------------------------------------------------------------------ | ------------------------------------------ |
@@ -30,8 +28,8 @@ The scheduler is on by default in `app/main.py`, and the template prepares two w
| Workflow | What it does when enabled | Toggle |
| -------------------- | ------------------------------------------------------- | -------------------------------------------- |
-| **Deployment check** | Checks daily that the AgentOS is wired correctly. | `ENABLE_DEPLOY_CHECK` (on by default) |
-| **Run evals** | Runs the `smoke` profile eval cases daily. | `ENABLE_SCHEDULED_EVALS` (off by default) |
+| **Deployment check** | Checks daily that AgentOS is wired correctly. | `ENABLE_DEPLOY_CHECK` (on by default) |
+| **Run evals** | Runs the `smoke`-tagged eval cases daily. | `ENABLE_SCHEDULED_EVALS` (off by default) |
Schedule your own agents and workflows the same way:
@@ -75,18 +73,25 @@ agent_os = AgentOS(
| Telegram | [Telegram interface](/agent-os/interfaces/telegram/introduction) |
| WhatsApp | [WhatsApp interface](/agent-os/interfaces/whatsapp/introduction) |
| Custom UI / AG-UI | [AG-UI interface](/agent-os/interfaces/ag-ui/introduction) |
+| MCP clients | [AgentOS MCP interface](/agent-os/mcp/mcp) |
| All interfaces | [Interfaces overview](/agent-os/interfaces/overview) |
## Keep the repo coherent
-As you ship more agents, configuration drifts, env vars rot, and new agents miss imports. The template ships a fifth skill for the recurring sweep:
+As the platform grows, the same agent needs to stay aligned across its source file, `app/main.py`, `app/config.yaml`, environment variables, and documentation. The `review-and-improve` skill checks those files together:
```text
-/review-and-improve
+Run the review-and-improve skill in .agents/skills.
```
-It auto-fixes mechanical drift (stale paths, missing `example.env` entries, agents on disk not registered in `app/main.py`) and surfaces the rest as a punch list. Run it before public releases and periodically during active development.
+It fixes straightforward issues such as stale paths, missing `example.env` entries, and agents that exist on disk but are not registered in `app/main.py`. It returns a list of changes that need your judgment. Run it before a public release or after a refactor.
-## You're done
+## What you have built
-You now have a platform that runs locally and on Railway with JWT auth, persists sessions, memory, and traces in Postgres, supports Postgres-backed knowledge, and includes five coding-agent skills for ongoing development and maintenance.
+| Capability | What is in place |
+|------------|------------------|
+| Runtime | AgentOS running locally and on Railway |
+| State | Postgres for sessions, memory, knowledge, traces, and eval history |
+| Access | REST, MCP, the AgentOS UI, and optional chat interfaces |
+| Security | JWT authorization configured for Railway, with per-user isolation available as an opt-in |
+| Development loop | Six coding-agent skills for setup, creation, extension, improvement, evaluation, and maintenance |
diff --git a/agent-platform/overview.mdx b/agent-platform/overview.mdx
index d52af4717..7573ca9be 100644
--- a/agent-platform/overview.mdx
+++ b/agent-platform/overview.mdx
@@ -4,19 +4,13 @@ sidebarTitle: Overview
description: "Build your own Agent Platform using Agno's AgentOS runtime."
---
-Every company building agents builds the same system from scratch:
+Engineering teams building agents need a shared runtime for runs, sessions, memory, knowledge, authentication, traces, and evals. Building that foundation once gives every agent the same API, state, security, and operating model.
-- A server to run the agents (batch, streaming, or background mode).
-- A database for storing sessions, runs, traces, and memory.
-- Auth and RBAC, validated via JWT or service-account tokens.
+AgentOS runs that foundation as a FastAPI application in your cloud. Every registered agent, team, and workflow gets a REST API, an MCP interface, and a place in the AgentOS UI. Postgres stores runtime state. The Railway starter used in this guide also includes six coding-agent skills for setup, creation, extension, improvement, evaluation, and maintenance.
-This system is called an agent platform and today I'll show you how to build the foundation once so every new agent slots into the same runtime, storage, and connectors.
+## Build with a coding agent
-## Built by coding agents
-
-The best part about building an agent platform is that coding agents can build this entire system for you. Agent code, logs, traces, evals, and the live service live in one place, so a coding agent can set up the platform, then create, improve, and evaluate the agents running on it. It would be surprising if your agent platform wasn't agentic in itself!
-
-I've curated a set of prompts that you can give your coding agent to do exactly that. Pick your cloud, copy the prompt into Claude Code, Cursor or Codex, and it'll take you from zero to a running platform:
+Pick a cloud, then give the setup prompt to your favorite coding agent. The prompt starts the platform and uses the skills in `.agents/skills` to build the first agent.
@@ -59,13 +53,13 @@ I've curated a set of prompts that you can give your coding agent to do exactly
## Build it step by step
-It's true that we only learn when we build things ourselves, the old-fashioned way. So the rest of this guide builds the same platform by hand. We'll use the `AgentOS on Railway` template as our starting point, but you can swap it for your cloud provider just as easily.
+We learn by building, so the rest of this guide walks through each part of the platform using the [AgentOS on Railway template](/deploy/templates/railway/deploy). The development loop is shared across Agno's deployment templates. When it is time to deploy, follow the guide for your cloud provider.
| Step | What happens |
| ---- | ------------ |
-| [Run Locally](/agent-platform/run-local) | Run your agent platform (AgentOS + Postgres) locally using Docker. |
-| [Create an Agent](/agent-platform/create-agent) | Create a new agent with Claude Code. |
-| [Improve an Agent](/agent-platform/improve-agent) | Use Claude Code to read container logs and improve an agent. |
-| [Run on Railway](/agent-platform/run-railway) | Deploy the platform to Railway with JWT auth on. |
-| [Evals](/agent-platform/evals) | Lock in behavior with regression tests. |
-| [Next Steps](/agent-platform/next-steps) | Teams, workflows, scheduling, and Slack interfaces. |
+| [Run Locally](/agent-platform/run-local) | Start AgentOS and Postgres with Docker. |
+| [Create an Agent](/agent-platform/create-agent) | Use a coding-agent skill to add and verify an agent. |
+| [Improve an Agent](/agent-platform/improve-agent) | Probe live behavior and make focused changes. |
+| [Evals](/agent-platform/evals) | Turn expected behavior into regression cases. |
+| [Run on Railway](/agent-platform/run-railway) | Deploy with JWT authorization enabled. |
+| [Next Steps](/agent-platform/next-steps) | Add teams, workflows, schedules, and interfaces. |
diff --git a/agent-platform/run-local.mdx b/agent-platform/run-local.mdx
index f34560a1d..a55215f38 100644
--- a/agent-platform/run-local.mdx
+++ b/agent-platform/run-local.mdx
@@ -23,7 +23,19 @@ Today we're going to run an agent platform made of:
```
- To make this codebase yours, run `rm -rf .git` and push to your own git repo.
+ Make the codebase yours by pushing it to a repository you own. To start with a clean Git history, run these commands inside the cloned `agent-platform` directory:
+
+ ```bash
+ rm -rf .git
+ git init
+ git add .
+ git commit -m "Initial commit"
+ git branch -M main
+ git remote add origin https://github.com/your-org/your-repo.git
+ git push -u origin main
+ ```
+
+ `rm -rf .git` removes the template's Git history. Replace the repository URL before running the final two commands.
@@ -52,11 +64,17 @@ Today we're going to run an agent platform made of:
-
-You now have an agent platform made of AgentOS on FastAPI and Postgres. The AgentOS server exposes 80+ endpoints for runs, sessions, memory, knowledge, and evals.
+
+ ```bash
+ ./scripts/mcp_check.sh
+ ```
+
+ This checks the MCP handshake, tool discovery, and one agent run against the local platform.
+
+
-AgentOS also comes with a UI at [os.agno.com](https://os.agno.com).
+You now have AgentOS on FastAPI with Postgres and pgvector. The API exposes 80+ endpoints for runs, sessions, memory, knowledge, and evals.
## Connect the AgentOS UI
@@ -74,21 +92,23 @@ You should see three agents:
Try a prompt against each:
-> _"Build an agent that tracks AI news and writes a daily brief"_ → **Agent Builder** walks you through the agent development process.
+> _"Build an agent that tracks AI news and writes a daily brief"_ → **Agent Builder** creates the agent through AgentOS Studio.
> _"How healthy is the platform?"_ → **Platform Manager** answers from eval history, deployment checks, and schedules.
> _"What did Anthropic publish about agents recently?"_ → **WebSearch** returns a summary with citations.
-Open **Sessions** and **Traces** in the sidebar. Every run is captured with full message history, tool calls, and timing. This is what powers the iteration loop on the next page.
+After Agent Builder finishes, click **Refresh**, choose the new agent from the **Agents** dropdown, and try it.
-## Summary
+Open **Sessions** and **Traces** in the sidebar. They capture message history, tool calls, and timing so you can inspect behavior and improve your agents.
-We now have a locally running agent platform with:
+## Summary
-- Our agent runtime (AgentOS) running on port 8000 with request isolation, session management, scheduling, and 80+ endpoints.
-- A Postgres database for storing sessions, memory, knowledge, and traces.
-- Five coding-agent skills in `.agents/skills/` covering the agent development lifecycle: create, improve, extend, eval, and review.
+| Capability | What is running |
+|------------|-----------------|
+| Runtime | AgentOS on port 8000 with request isolation, session management, scheduling, MCP, and 80+ REST endpoints |
+| State | Postgres for sessions, memory, knowledge, traces, schedules, and eval history |
+| Development loop | Six skills in `.agents/skills/` for setup, creation, extension, improvement, evaluation, and maintenance |
Hot-reload is on. Edits to Python files in the source (`agents/`, `app/`, `db/`, `evals/`, `workflows/`) are live in ~2s.
diff --git a/agent-platform/run-railway.mdx b/agent-platform/run-railway.mdx
index 7874c0360..53d07a4bc 100644
--- a/agent-platform/run-railway.mdx
+++ b/agent-platform/run-railway.mdx
@@ -1,13 +1,14 @@
---
title: Run on Railway
-description: "Deploy your agent platform to Railway with JWT auth on."
+description: "Deploy AgentOS and Postgres to Railway with JWT authorization and MCP access."
---
-Your company probably has a set way of running software. Follow that. If you're looking for a place to test this out without going through the full DevOps process, Railway is a good option, and the template includes scripts to:
+Your company probably has a standard way to run software. Use it. If you want to deploy this platform without building the cloud infrastructure first, Railway is the quickest path through this guide. The template includes scripts to:
- Deploy to Railway: `./scripts/railway/up.sh`
- Sync environment variables: `./scripts/railway/env-sync.sh`
- Redeploy the app: `./scripts/railway/redeploy.sh`
+- Tear down the Railway project: `./scripts/railway/down.sh`
## Prerequisites
@@ -16,9 +17,9 @@ Your company probably has a set way of running software. Follow that. If you're
## Why JWT is on by default
-Token-Based Authorization is **ON** by default. Without a `JWT_VERIFICATION_KEY` (or `JWT_JWKS_FILE`), the app refuses to serve traffic in production. This is why the deploy script stops and asks you for a key.
+JWT authorization is enabled by default. Production startup requires a `JWT_VERIFICATION_KEY` or `JWT_JWKS_FILE`. During an interactive deploy, the script pauses for a verification key when neither value is configured.
-Token-Based Auth gives you three things:
+JWT authorization provides:
- **Protected application routes.** Requests to agent, team, workflow, and data routes require a valid token.
- **Per-request identity.** Middleware parses the token and exposes `user_id`, `session_id`, and custom claims to protected routes.
@@ -26,18 +27,22 @@ Token-Based Auth gives you three things:
AgentOS leaves its operational and API-documentation routes public: `/`, `/health`, `/info`, `/docs`, `/redoc`, `/openapi.json`, and `/docs/oauth2-redirect`.
+Per-user data isolation is opt-in. Set `authorization_config=AuthorizationConfig(user_isolation=True)` to limit non-admin users to their own sessions, memories, traces, and runs. See [User Isolation](/agent-os/security/authorization/user-isolation).
+
## Deploy your agent platform to Railway
- The deploy and sync scripts read `.env.production`. This keeps local and production values separate: different OpenAI keys with different budgets, production-only credentials, a different Slack workspace.
+ The deploy and sync scripts read `.env.production`. This keeps local and production values separate: different OpenAI keys with different budgets, production-only credentials, or a different Slack workspace.
+
+ Create the file the first time you deploy:
```bash
cp .env .env.production
```
- Edit `.env.production` with a production OpenAI key.
+ Skip this command if `.env.production` already exists. Edit the file with a production OpenAI key.
@@ -53,8 +58,9 @@ AgentOS leaves its operational and API-documentation routes public: `/`, `/healt
2. Provisions a Postgres service (with pgvector) and a persistent volume.
3. Creates the `agent-os` service and forwards the database connection vars.
4. Issues your public Railway domain and sets `AGENTOS_URL` to it, on Railway and in `.env.production`.
- 5. Pauses and asks for a JWT verification key.
- 6. Builds and deploys from the current directory.
+ 5. Generates `MCP_CONNECT_SECRET` for hosted MCP clients and saves it to `.env.production` and Railway.
+ 6. Asks for a JWT verification key when neither JWT setting is configured.
+ 7. Builds and deploys from the current directory.
The domain takes a few minutes to start resolving after the first deploy.
@@ -77,17 +83,30 @@ AgentOS leaves its operational and API-documentation routes public: `/`, `/healt
```bash
- railway logs --service agent-os
+ curl --fail https://.up.railway.app/health
+ curl --silent --output /dev/null --write-out "%{http_code}\n" https://.up.railway.app/agents
+ ```
+
+ The health check should succeed, and the protected `/agents` route should return `401` without a token. Open `https://.up.railway.app/docs` to inspect the deployed API. Use `railway logs --service agent-os` if either check fails.
+
+
+
+
+
+ Register the deployed AgentOS with supported local clients:
+
+ ```bash
+ uvx agno connect --url https://.up.railway.app
```
- Once you see successful requests, open `https://.up.railway.app/docs` and you're live.
+ For ChatGPT or Claude on the web, add `https://.up.railway.app/mcp` as a custom connector. Enter the `MCP_CONNECT_SECRET` stored in `.env.production` on the consent page.
## Auto-deploys from GitHub
-By default every code update needs `./scripts/railway/redeploy.sh`. To auto-deploy on every push to `main`:
+Until GitHub auto-deploy is connected, redeploy code changes with `./scripts/railway/redeploy.sh`. To deploy on every push to `main`:
1. Open the Railway dashboard → your project → the `agent-os` service → **Settings**.
2. Under **Source**, click **Connect Repo** and pick your repo.
@@ -95,13 +114,15 @@ By default every code update needs `./scripts/railway/redeploy.sh`. To auto-depl
Push to `main` now triggers a build and deploy. `./scripts/railway/env-sync.sh` is still how you push env changes.
-## Opting out of JWT (not recommended)
+## External authentication boundary
+
+If a private network or trusted gateway already blocks unauthenticated traffic, set `authorization=False` in `app/main.py`. JWT middleware still validates tokens while `JWT_VERIFICATION_KEY` or `JWT_JWKS_FILE` remains configured. Remove those values from `.env.production` and the Railway `agent-os` service, then redeploy. `MCP_CONNECT_SECRET` controls the separate OAuth flow for MCP clients. Remove it from both places too if the gateway should protect `/mcp`. Keep AgentOS authorization enabled for internet-accessible deployments and services that hold user data.
-If you must run production without auth (inside a private VPC behind another auth layer), set `authorization=False` in `app/main.py` and redeploy. Keep authorization on for any deploy holding real data. Without it, anyone who guesses your Railway domain can read your sessions and run your agents.
+`./scripts/railway/env-sync.sh` updates variables present in `.env.production`; it does not remove variables you deleted from the file.
## Scaling
-The default deploy is one replica with 4 GiB of memory and 2 vCPU. Change `numReplicas` and `limits` in `railway.json` as your load and availability requirements grow.
+The starter is configured for one replica with 4 GiB of memory and 2 vCPU. Adjust the resource limits in `railway.json` as load grows. Validate schedules and long-lived MCP connections with your workload before increasing `numReplicas`.
## Operations
@@ -112,12 +133,14 @@ The default deploy is one replica with 4 GiB of memory and 2 vCPU. Change `numRe
| Run a command with production env vars | `railway run --service agent-os ` |
| Push env changes | `./scripts/railway/env-sync.sh` |
| Redeploy without git push | `./scripts/railway/redeploy.sh` |
-| Tear everything down | Delete the project in the Railway dashboard |
+| Tear everything down | `./scripts/railway/down.sh` |
Deleting the Railway project removes the app, the database, and all data.
+See [Railway Reference](/deploy/templates/railway/reference) for environment variables, customization, and troubleshooting.
+
## Next
-[Lock in behavior with evals →](/agent-platform/evals)
+[Next steps →](/agent-platform/next-steps)
diff --git a/cli/connect.mdx b/cli/connect.mdx
index edefa716c..510489f45 100644
--- a/cli/connect.mdx
+++ b/cli/connect.mdx
@@ -8,7 +8,7 @@ description: "Connect Claude Code, Claude Desktop, Codex, and Cursor to a runnin
agno connect
```
-`agno connect` finds your running AgentOS, mints one service-account token per coding agent when the AgentOS has authorization enabled, writes each client's MCP configuration, and verifies every entry with a real MCP handshake. Your coding agents can then run your agents, teams, and workflows through the [AgentOS MCP server](/agent-os/mcp/mcp).
+`agno connect` finds your running AgentOS, configures authentication for each client, writes the client's MCP configuration, and verifies entries it can authenticate immediately. Token-protected endpoints use service-account tokens. OAuth endpoints use client sign-in. Your coding agents can then run your agents, teams, and workflows through the [AgentOS MCP server](/agent-os/mcp/mcp).
The AgentOS must have its MCP server enabled:
@@ -25,11 +25,11 @@ agent_os = AgentOS(
## The Execution Flow
-1. **Discover.** Resolve the AgentOS from `--url`, `AGENTOS_URL` (the environment variable, or a project `.env.production` / `.env` file), or a localhost probe, then read its version, MCP path, and auth mode from `GET /info`.
-2. **Authenticate.** When authorization is enabled, resolve an admin credential from `AGNO_ADMIN_TOKEN` or `OS_SECURITY_KEY`, or prompt for it.
-3. **Mint.** When authorization is enabled, create one service account per client (named `claude-code`, `cursor`, and so on) with the server's default run and read scopes and a 90-day expiry. An unsecured AgentOS connects without credentials.
+1. **Discover.** An interactive run offers a choice across live env-file, localhost, and previously configured AgentOS URLs. `--url`, an exported `AGENTOS_URL`, and non-interactive runs select one deterministic target. The CLI then reads its version, MCP path, and auth mode from `GET /info`.
+2. **Choose authentication.** OAuth-protected MCP endpoints write tokenless entries for one-time client sign-in. Service-account mode resolves an admin credential from `AGNO_ADMIN_TOKEN` or `OS_SECURITY_KEY`, or prompts for it.
+3. **Mint when needed.** Service-account mode creates one account per client (named `claude-code`, `cursor`, and so on) with the server's default run and read scopes and a 90-day expiry. An unsecured AgentOS connects without credentials. Pass `--pat` to use service-account tokens with an OAuth-protected endpoint.
4. **Write.** Add an MCP server entry, named after your AgentOS (`agentos` when it has no name), to each client's own config file.
-5. **Verify.** Read the entry back the way the client would resolve it, then complete an MCP `initialize` and `tools/list` call against the AgentOS with the configured token.
+5. **Verify.** Read the entry back the way the client would resolve it. Service-account and unsecured entries complete an MCP `initialize` and `tools/list` call. OAuth entries report `sign in` for the client to complete.
6. **Report.** Print per-client results: `connected`, `sign in`, `already ok`, `skipped`, `action needed`, or `failed`.
When the MCP endpoint is OAuth-protected, nothing is minted: entries are written without tokens and each app completes a one-time sign-in (`sign in` in the report). Pass `--pat` to mint tokens anyway, for headless clients.
@@ -54,7 +54,7 @@ agno connect --clients claude-code,cursor
| ChatGPT | `chatgpt` | None. Prints manual Connector setup steps. |
-Claude Desktop speaks MCP over stdio only, so its entry launches the `mcp-remote` proxy with `npx`. Node.js must be installed for that entry to start.
+The Claude Desktop entry written by `agno connect` launches the `mcp-remote` bridge over stdio. Node.js must be installed for that entry to start.
## claude.ai and ChatGPT
@@ -68,8 +68,8 @@ agno connect --clients claude-ai,chatgpt
Requirements:
- The AgentOS must be on a public HTTPS URL. A local AgentOS is unreachable from the apps' clouds; deploy it or expose it through a tunnel first.
-- Both apps' Connectors UIs authenticate with OAuth, not bearer tokens, so the AgentOS must be public or OAuth-enabled. A token-protected AgentOS cannot be added from the UI yet.
-- In the app, go to Settings -> Connectors -> Add custom connector and paste the printed MCP URL. Custom connectors need a paid plan.
+- The MCP endpoint must either allow unauthenticated access or expose OAuth. These hosted UIs do not accept an Agno service-account bearer token.
+- Paste the printed MCP URL into the app's custom connector or custom app flow. Menu names, plan requirements, and workspace controls vary by provider. Follow the current [Claude custom connector guide](https://support.claude.com/en/articles/11175166-get-started-with-custom-connectors-using-remote-mcp) or [ChatGPT MCP app guide](https://help.openai.com/en/articles/12584461-developer-mode-and-full-mcp-connectors-in-chatgpt-beta).
When discovery lands on a public HTTPS AgentOS with authorization disabled, or with an OAuth-protected MCP endpoint, `connect` prints these steps automatically, without `--clients`.
@@ -118,7 +118,7 @@ agno disconnect
## Scripting
-`--json` prints one JSON document with the discovered OS, per-client results, and the exit code. Exit codes: `0` all connected, `1` nothing connected, `2` usage error, `3` partial success. In `--json` mode the CLI never prompts, so set `AGNO_ADMIN_TOKEN` before you run it.
+After command-line parsing succeeds, `--json` prints one JSON document with the discovered OS, per-client results, and the exit code. Exit codes: `0` all connected, `1` nothing connected, `2` usage error, `3` partial success. Typer parse errors write to stderr without JSON. JSON mode never prompts. When a run needs to mint or rotate service accounts, export `AGNO_ADMIN_TOKEN` or `OS_SECURITY_KEY` first.
## Developer Resources
diff --git a/cli/overview.mdx b/cli/overview.mdx
index 6baac3c2c..ae00500b5 100644
--- a/cli/overview.mdx
+++ b/cli/overview.mdx
@@ -12,7 +12,9 @@ agno up
agno connect
```
-The `agno` command scaffolds AgentOS projects, runs them with Docker Compose, connects your coding agents over MCP, and manages service-account tokens. Every command takes `--json` and emits a single JSON document on stdout, so coding agents and scripts can drive it.
+This quickstart assumes `agno` 2.7 or later is installed. The `agno` command scaffolds AgentOS projects, runs them with Docker Compose, connects your coding agents over MCP, and manages service-account tokens.
+
+Every subcommand listed below accepts `--json` and emits one JSON document for command-level results after argument parsing succeeds. Typer usage errors exit with code `2`, write diagnostics to stderr, and do not emit JSON.
## Install
@@ -22,7 +24,7 @@ The CLI ships with the SDK, so installing `agno` 2.7 or later puts the `agno` co
pip install -U agno
```
-The CLI is also published standalone as `agnoctl`. It depends on `typer`, `rich`, and `httpx` only, so it runs on machines without the SDK:
+The CLI is also published standalone as `agnoctl`. It depends on `typer`, `rich`, and `httpx`, plus `tomli` on Python versions below 3.11, so it runs on machines without the SDK:
```bash
uvx agnoctl connect
@@ -43,7 +45,7 @@ uvx agnoctl connect
## How the CLI Finds Your AgentOS
-`connect`, `status`, and `tokens` need a running AgentOS. They resolve its URL in this order:
+`status`, `tokens`, and non-interactive `connect` runs need a running AgentOS. They resolve one target in this order:
| Priority | Source | Example |
|----------|--------|---------|
@@ -54,6 +56,8 @@ uvx agnoctl connect
The probe covers `AgentOS.serve()`'s default port (7777), common bump-up ports, and a bare uvicorn setup (8000). If your AgentOS runs on any other host or port, point the CLI at it with `--url` or `AGENTOS_URL`.
+Interactive `agno connect` behaves differently when neither `--url` nor an exported `AGENTOS_URL` selects one target. It probes every live env-file and localhost candidate, adds AgentOS URLs found in existing client configurations, and asks you which one to connect. `--json` and other non-interactive runs use the deterministic priority order above.
+
## Developer Resources
- [agnoctl reference](/reference/cli/agnoctl): full flag tables, environment variables, exit codes, and JSON output schemas
diff --git a/deploy/introduction.mdx b/deploy/introduction.mdx
index c018eeffa..8355033f8 100644
--- a/deploy/introduction.mdx
+++ b/deploy/introduction.mdx
@@ -1,86 +1,68 @@
---
title: "AgentOS Templates"
sidebarTitle: "Introduction"
-description: "Pre-built starter templates for running AgentOS in your cloud."
+description: "Choose an AgentOS starter or application template to run in your cloud."
mode: "wide"
---
-The Agno team provides a number of starter templates for running AgentOS, and agentic applications built on top of it, in your cloud of choice. We provide two kinds of templates:
+Start from an **AgentOS Starter** when you have your own agent use case. Start from an **Application Template** when you want a working agent product to fork and adapt.
-1. **AgentOS Starters:** clean AgentOS installations, one per platform: Railway, AWS, Fly, GCP and more.
-2. **Application Blueprints:** ready-to-use agentic solutions that you can deploy today.
+Both give you an AgentOS codebase that runs locally and can deploy to infrastructure you control.
-## What's inside every Starter
+## Application Templates
+
+Application Templates are complete agent products with agents, tools, storage, interfaces, evals, and deployment scripts already connected.
+
+
+
+ For data teams that need SQL answers grounded in schemas, business definitions, validated queries, and prior corrections.
+
+
+ For engineering teams that want code search, PR review, issue triage, and implementation support inside Slack.
+
+
+ For teams that need an agent to navigate live company context across Slack, Drive, wikis, the web, and MCP sources.
+
+
+ For founders and operators who want a private CRM and knowledge base that their AI tools can share over MCP.
+
+
+
+## AgentOS Starters
+
+Starters provide the same AgentOS foundation with deployment scripts for different infrastructure.
-Every starter template comes with a common platform core, along with cloud-specific deploy instructions.
+| Starter | Best for | Deployment shape |
+|---------|----------|------------------|
+| [Railway](/deploy/templates/railway/deploy) | Teams that want a managed application and database with minimal infrastructure setup | Railway service and managed PostgreSQL |
+| [Docker](/deploy/templates/docker/deploy) | Teams that want to run AgentOS on infrastructure they control | Docker Compose on your host |
+| [AWS](/deploy/templates/aws/deploy) | Teams that already operate in AWS | ECS Express Mode and RDS PostgreSQL |
+| [Fly.io](/deploy/templates/fly/deploy) | Teams that want a single always-on Fly Machine | Fly Machine and Fly Postgres |
+| [Google Cloud](/deploy/templates/gcp/deploy) | Teams that already operate in GCP | Cloud Run and Cloud SQL |
+| [Kubernetes](/deploy/templates/helm/deploy) | Platform teams that already run Kubernetes | Helm chart with in-cluster or external PostgreSQL |
+| [Azure](/deploy/templates/azure/deploy) | Teams that already operate in Azure | Container Apps and Flexible Server for PostgreSQL |
+| [Render](/deploy/templates/render/deploy) | Teams that want a Blueprint-driven deployment | Render web service and managed PostgreSQL |
+| [Modal](/deploy/templates/modal/deploy) | Python teams that already use Modal | Always-warm Modal container with Neon or external PostgreSQL with pgvector |
+
+## What's inside every Starter
| Component | What it does |
|-----------|--------------|
-| **Two platform agents** | _**Agent Builder**_ creates agents, teams, and workflows. _**Platform Manager**_ helps manage the platform. |
-| **Two workflows** | _**Deployment Check**_ checks platform health and _**Run Evals**_ runs the eval suite. |
-| **MCP server** | Makes your platform available to any AI app or MCP client. |
-| **Coding-agent skills** | Manage your platform using skills like `/create-new-agent`, `/improve-agent` and more. |
-| **Eval suite** | Full AgentAsJudge and Reliability eval suite, ready to catch regressions. |
-| **PostgreSQL** | Sessions, memory, knowledge, and traces all stored in your database. |
+| **AgentOS API** | Serves agents, teams, and workflows to products, the AgentOS UI, coding agents, and MCP clients. |
+| **Two platform agents** | **Agent Builder** creates agents, teams, and workflows. **Platform Manager** inspects and explains the platform. |
+| **Two workflows** | **Deployment Check** reports platform health. **Run Evals** runs the eval suite. |
+| **Six coding-agent skills** | Sets up the Starter, creates and extends agents, improves behavior, runs evals, and reviews project drift. |
+| **Eval suite** | Runs AgentAsJudge and Reliability evals and records results in PostgreSQL. |
+| **PostgreSQL** | Stores sessions, memory, knowledge, traces, and eval results. |
+
+## Build with your Starter
+
+Every deploy guide includes a prompt for setting up the Starter locally with Claude Code, Codex, or Cursor. The coding agent starts AgentOS, verifies the MCP endpoint, and builds your first agent. The same guide then covers production deployment for that provider.
+
+After AgentOS is running, connect it to the coding agents on your machine:
-## Get started
+```bash
+uvx agno connect
+```
-
-
-
-
-
-
- Run AgentOS and PostgreSQL on Railway.
-
-
- Run locally or self-host anywhere Docker runs.
-
-
- ECS Express Mode with RDS PostgreSQL.
-
-
- A single always-on machine on Fly.io.
-
-
- Cloud Run with Cloud SQL.
-
-
- A Helm chart for any cluster: EKS, GKE, AKS.
-
-
- Container Apps with PostgreSQL.
-
-
- A Blueprint with managed PostgreSQL.
-
-
- Modal + Neon Postgres.
-
-
-
-
-
-
- Self-learning data agent with 6 layers of context.
-
-
- Code companion that lives in Slack.
-
-
- Company brain across Slack, Drive, and wikis.
-
-
- Self-hosted context manager: a private CRM and knowledge base your AI tools share.
-
-
-
-
-
-
- Each Starter comes with a setup prompt you can give to coding agents like Claude Code, Cursor, or Codex. The agent clones the repo and sets everything up. Every template also comes with manual steps, but we recommend using coding agents for setup.
-
-
- Connect your AgentOS to the [AgentOS UI](https://os.agno.com) with **Connect OS**, and to coding agents on your machine by running `uvx agno connect`. You can also use the AgentOS MCP server (`https:///mcp`) to connect your AgentOS to the Claude and ChatGPT apps.
-
-
+See [Build with Coding Agents](/deploy/templates/improve-agents) for the complete development loop.
diff --git a/deploy/templates/aws/deploy.mdx b/deploy/templates/aws/deploy.mdx
index 7a59279c1..6b62d823c 100644
--- a/deploy/templates/aws/deploy.mdx
+++ b/deploy/templates/aws/deploy.mdx
@@ -4,18 +4,17 @@ sidebarTitle: "Deploy"
description: "Run AgentOS locally using Docker and deploy to production on AWS."
---
-AgentOS is a secure, scalable platform for running agents. The [agentos-aws](https://github.com/agno-agi/agentos-aws) codebase runs AgentOS locally using Docker and deploys to production on AWS. It comes with:
+Choose AWS when your team wants AgentOS, PostgreSQL, secrets, logs, and networking in its own AWS account. The [agentos-aws](https://github.com/agno-agi/agentos-aws) template uses Docker locally and deploys AgentOS with ECS Express Mode and RDS for production.
-- **2 platform agents** that build and run the platform for you. **Agent Builder** creates agents, teams, and workflows. **Platform Manager** understands, monitors, and explains the platform.
-- **5 [skills](/deploy/templates/improve-agents)** that let coding agents build, test, and improve the platform for you.
+- **Agent Builder**, which creates agents, teams, and workflows when prompted.
+- **Platform Manager**, which inspects registered agents, eval history, deployment checks, and schedules.
+- **Six [skills](/deploy/templates/improve-agents)**. `setup-platform` configures the local platform. Five lifecycle skills create, extend, improve, evaluate, and review it.
-Because the trace data, agent code, evals, and system logs all live in one place, the platform can inspect and improve itself automatically.
-
-Production runs in your own AWS account: the deploy scripts use ECS Express Mode for the service and RDS for Postgres.
+Coding agents can use the repository skills, live AgentOS API, evals, and container logs to inspect and improve the platform.
## Get started
-The fastest way to get started is using a coding agent. Copy the prompt below into Claude Code, Cursor or Codex and it'll take you from zero to a running platform.
+Copy the prompt below into Claude Code, Cursor, or Codex to clone the template, start AgentOS locally, and build your first agent.
@@ -79,7 +78,12 @@ Prints `MCP OK` with the tool count and a real agent answer through the MCP endp
## Deploy to production
-**Prerequisites:** [AWS CLI v2](https://docs.aws.amazon.com/cli/latest/userguide/getting-started-install.html) recent enough for ECS Express Mode (`aws ecs create-express-gateway-service help` must work), credentials configured (`aws sts get-caller-identity` succeeds), and Docker running. The image is built locally and pushed to ECR.
+**Prerequisites:**
+
+- [AWS CLI v2](https://docs.aws.amazon.com/cli/latest/userguide/getting-started-install.html) recent enough for ECS Express Mode. `aws ecs create-express-gateway-service help` must work.
+- Configured AWS credentials. `aws sts get-caller-identity` must succeed. The AWS principal needs permission to create and pass IAM roles and manage ECS Express Mode, ECR, RDS, Secrets Manager, EC2 networking, and CloudWatch logs.
+- A default VPC in the target region with subnets in at least two Availability Zones. Find the VPC with `aws ec2 describe-vpcs --filters Name=is-default,Values=true --query 'Vpcs[0].VpcId' --output text --region `. Then run `aws ec2 describe-subnets --filters Name=vpc-id,Values= --query 'Subnets[].AvailabilityZone' --output text --region ` and confirm that it returns at least two distinct zones.
+- Docker running. The script builds the image locally and pushes it to ECR.
@@ -95,9 +99,11 @@ Edit `.env.production` with production values: a different OpenAI key, productio
./scripts/aws/up.sh
```
-Provisions an ECR repo, a private RDS PostgreSQL 17 instance, and Secrets Manager secrets, then makes one `aws ecs create-express-gateway-service` call. That call brings the Fargate service, an ALB with HTTPS, security groups, autoscaling, CloudWatch logs and alarms, and a public URL (`https://ag-.ecs..on.aws`, generated per service). The script pins scaling to a single always-on task so the in-process scheduler never double-fires, and sets `AGENTOS_URL` to the generated URL so scheduled jobs reach the platform. It also generates `MCP_CONNECT_SECRET` into `.env.production` when it's missing, so chat apps can connect over OAuth from the first deploy.
+Provisions an ECR repo, a private RDS PostgreSQL 17 instance, and Secrets Manager secrets, then makes one `aws ecs create-express-gateway-service` call. That call brings the Fargate service, an ALB with HTTPS, security groups, autoscaling, CloudWatch logs and alarms, and a public URL (`https://ag-.ecs..on.aws`, generated per service). The script pins scaling to a single always-on task and sets `AGENTOS_URL` to the generated URL so scheduled jobs reach the platform. It also generates `MCP_CONNECT_SECRET` into `.env.production` when it's missing, so chat apps can connect over OAuth from the first deploy.
-The first run takes 30-45 minutes end to end. Certificate and DNS provisioning is the long pole, and the script waits until the gateway actually answers before declaring success. Redeploys take minutes. Region comes from `AWS_REGION` (default `us-east-1`).
+The first run takes 30-45 minutes end to end. Certificate and DNS provisioning takes most of that time, and the script waits until the gateway answers before declaring success. Redeploys take minutes. Region comes from `AWS_REGION` (default `us-east-1`).
+
+The template has been validated with one ECS task. AgentOS claims due schedules through PostgreSQL. Simultaneous schedule registration and long-lived MCP streams still need validation before you scale the service.
This stack idles at roughly $100-110/month: about $70/mo for Fargate (2 vCPU/4 GB), $17-25/mo for the ALB (shared across up to 25 Express services), and $14/mo for the RDS db.t4g.micro. AWS bills idle resources. Tear down what you don't use with `./scripts/aws/down.sh`.
@@ -126,10 +132,13 @@ For claude.ai and ChatGPT on the web: add `https:///mcp` as a custo
```bash
-aws logs tail /ecs/agent-os --follow
+curl -o /dev/null -w '%{http_code}\n' "https:///health" # 200
+curl -o /dev/null -w '%{http_code}\n' "https:///agents" # 401
+
+aws logs tail /ecs/agent-os --region --follow
```
-The app finishes rolling out behind the gateway; first boot pulls the image and waits for the database. Open `https:///docs` to confirm the API is serving.
+The app finishes rolling out behind the gateway; first boot pulls the image and waits for the database. `/health` and `/docs` remain public. Protected AgentOS routes such as `/agents` require a valid token.
diff --git a/deploy/templates/aws/reference.mdx b/deploy/templates/aws/reference.mdx
index 5be0235d0..871fb8949 100644
--- a/deploy/templates/aws/reference.mdx
+++ b/deploy/templates/aws/reference.mdx
@@ -4,7 +4,7 @@ sidebarTitle: "Reference"
description: "Commands, customization, environment variables, and troubleshooting for the AWS template."
---
-The template names the Express service `agent-os`, the ECR repo `agentos`, and the RDS instance `agentos-db`. Secrets live under `agentos/*` in Secrets Manager, and the scripts record the service ARN and region in `tmp/agentos-aws.state`.
+The template names the Express service `agent-os`, the ECR repo `agentos`, and the RDS instance `agentos-db`. Secrets live under `agentos/*` in Secrets Manager, and the scripts record the service ARN and region in `tmp/agentos-aws.state`. Start with [Deploy AgentOS on AWS](/deploy/templates/aws/deploy) for prerequisites and the first deployment.
## Manage
@@ -12,25 +12,23 @@ The template names the Express service `agent-os`, the ECR repo `agentos`, and t
|------|---------|
| Deploy code changes | `./scripts/aws/redeploy.sh` |
| Sync env variables | `./scripts/aws/env-sync.sh` (defaults to `.env.production`; pass `.env` to sync that instead) |
-| Tail logs | `aws logs tail /ecs/agent-os --follow` |
+| Tail logs | `aws logs tail /ecs/agent-os --region --follow` (use the region in `tmp/agentos-aws.state`) |
| Watch a rollout | `aws ecs monitor-express-gateway-service --region --service-arn ` |
| Tear down | `./scripts/aws/down.sh` (add `--yes` to skip the confirmation) |
## Production auth
-Token-Based Authorization is on by default. Production startup requires `JWT_VERIFICATION_KEY` or a readable JWKS file at the container path in `JWT_JWKS_FILE`; otherwise the process exits.
+Token-Based Authorization protects AgentOS routes by default in production. Startup requires `JWT_VERIFICATION_KEY` or a readable JWKS file at the container path in `JWT_JWKS_FILE`; otherwise the process exits.
Token-Based Auth gives you three things:
-1. **No public access.** The server rejects requests without a valid token.
+1. **Protected API access.** Requests to protected AgentOS routes require a valid token. `/`, `/health`, `/info`, `/docs`, `/redoc`, `/openapi.json`, and `/docs/oauth2-redirect` remain public.
2. **Per-request identity.** Middleware validates the token and exposes its `user_id`, optional `session_id`, scopes, and claims to the request.
3. **Scope-based permissions.** Token scopes control access to AgentOS routes and resources.
The templates do not enable per-user data isolation. To scope non-admin session, memory, trace, and run access to the JWT subject, pass `authorization_config=AuthorizationConfig(user_isolation=True)` to `AgentOS`. See [User Isolation](/agent-os/security/authorization/user-isolation).
-`/health` stays open. AgentOS serves it unauthenticated even in production, so the ALB health checks pass.
-
-To opt out (not recommended), set `authorization=False` in `app/main.py` and redeploy. Use this only inside a private VPC behind another auth layer. Without it, anyone who guesses your service URL can access your platform.
+To disable JWT authentication, set `authorization=False` in `app/main.py`, remove `JWT_VERIFICATION_KEY` and `JWT_JWKS_FILE` from the production env file, and redeploy. `authorization=False` disables AgentOS scope enforcement. Configured JWT environment variables continue to enable JWT validation. MCP OAuth remains active when `MCP_CONNECT_SECRET` is set. Only do this when another layer protects the service.
## Customize
@@ -76,6 +74,8 @@ Local containers hot-reload on save. For production, run `./scripts/aws/redeploy
+Complete the first AWS deployment with the default OpenAI model. The current `up.sh` requires `OPENAI_API_KEY` and only injects that model secret during initial provisioning.
+
`app/settings.py` defines `default_model()`, used by every agent. Change it in one place:
```python
@@ -85,13 +85,13 @@ def default_model():
return Claude(id="claude-sonnet-5")
```
-Add `anthropic` to `pyproject.toml`, set the provider key in your env, and regenerate pins:
+Add `anthropic` to `pyproject.toml`. Set `ANTHROPIC_API_KEY` in `.env` for local runs and `.env.production` for production, then regenerate pins:
```bash
./scripts/generate_requirements.sh
```
-Rebuild locally with `docker compose up -d --build`. For production:
+For the existing deployment, add `ANTHROPIC_API_KEY` to the `is_secret_key()` allowlist in `scripts/aws/env-sync.sh`. This stores the key in Secrets Manager and keeps it out of the ECS task definition. Then rebuild and deploy:
```bash
./scripts/aws/redeploy.sh
@@ -161,7 +161,7 @@ source .venv/bin/activate
| Variable | Required | Default | Description |
|----------|----------|---------|-------------|
| `OPENAI_API_KEY` | Yes | - | Models and embeddings. |
-| `RUNTIME_ENV` | No | `prd` | `dev` disables JWT. Compose sets it for local. Never put it in an env file that syncs to AWS, or production deploys unauthenticated. |
+| `RUNTIME_ENV` | No | `prd` | `dev` sets `authorization=False`, which disables AgentOS scope enforcement. Configured JWT environment variables continue to enable JWT validation. Compose sets `dev` locally; keep `prd` on AWS. |
| `JWT_VERIFICATION_KEY` | Production | - | Public key from os.agno.com. Quote the value so the multi-line PEM parses as one variable. |
| `JWT_JWKS_FILE` | Production | - | Path inside the running container to a JWKS JSON file. The scripts set only this path. Add the file to the image build context, rebuild, and redeploy the image, or configure a platform mount and roll the service. |
| `MCP_CONNECT_SECRET` | No | generated by `up.sh` | OAuth consent secret (16+ chars) for connecting claude.ai and ChatGPT to `/mcp`. `up.sh` generates one on deploy and writes it to `.env.production`. |
@@ -195,21 +195,28 @@ The RDS instance deploys into the region's default VPC. Create one with `aws ec2
Expected. Mint the key at [os.agno.com](https://os.agno.com): connect your OS (**Connect OS** → **Live**, enter your service URL), then turn on **Token-Based Authorization (JWT)** under **Settings** → **OS & Security** and paste the full PEM. To add a PEM later, set `JWT_VERIFICATION_KEY` and run `./scripts/aws/env-sync.sh`. To use JWKS, add the file to the image build context and rebuild, or configure a mount. Set `JWT_JWKS_FILE` to its container path, then redeploy or roll the service. Env sync alone only updates the path.
-JWT auth is on whenever `RUNTIME_ENV` is not `dev`. Set `JWT_VERIFICATION_KEY` and sync. For JWKS, verify the file exists inside the container at `JWT_JWKS_FILE`; changing the variable alone does not deliver it. To opt out inside a private VPC behind another auth layer, set `authorization=False` in `app/main.py`.
+AgentOS scope enforcement is on whenever `RUNTIME_ENV` is not `dev`. Set `JWT_VERIFICATION_KEY` and sync. For JWKS, verify the file exists inside the container at `JWT_JWKS_FILE`; changing the variable alone does not deliver it. To disable JWT, set `authorization=False` in `app/main.py`, remove both JWT variables from the production env file, and redeploy. MCP OAuth remains active when `MCP_CONNECT_SECRET` is set.
First-time provisioning of the ALB, certificate, and DNS takes 10-25 minutes; `up.sh` waits through it. Past that window, the known first-run cause is freshly created IAM roles: Express's async infrastructure calls get denied before the role policies propagate, and ECS never retries. `up.sh` detects this and recreates the service once; the second attempt provisions reliably. If it still stalls, inspect with `aws ecs monitor-express-gateway-service --region --service-arn `, look for an AccessDenied `CreateLoadBalancer` event in CloudTrail, then delete the service and re-run `./scripts/aws/up.sh`.
-The gateway is up; the app is still starting. First boot pulls the image and waits for the database. Wait a few minutes and check `aws logs tail /ecs/agent-os --follow`.
+The gateway is up; the app is still starting. First boot pulls the image and waits for the database. Wait a few minutes and check `aws logs tail /ecs/agent-os --region --follow`. The deployed region is recorded in `tmp/agentos-aws.state`.
`AGENTOS_URL` is still the localhost default. `up.sh` sets it to your service URL automatically; for a custom domain or tunnel, set it by hand and run `./scripts/aws/env-sync.sh`.
-The scripts resolve the service ARN from `tmp/agentos-aws.state` first, then from a `SERVICE_ARN=` line in `.env.production` or `.env`. On a fresh clone or a new machine, write the ARN of your Express service into the state file: `printf 'SERVICE_ARN=arn:aws:ecs:...' > tmp/agentos-aws.state`.
+The scripts resolve the service ARN from `tmp/agentos-aws.state` first, then from a `SERVICE_ARN=` line in `.env.production` or `.env`. On a fresh clone or a new machine, restore the service ARN and deployment region:
+
+```bash
+mkdir -p tmp
+printf 'SERVICE_ARN=%s\nREGION=%s\n' \
+ 'arn:aws:ecs:...' \
+ '' > tmp/agentos-aws.state
+```
-
+
The commands are hitting the wrong region. The scripts use `AWS_REGION` if set, then the region recorded in `tmp/agentos-aws.state`, then `us-east-1`. Set `AWS_REGION` to the region you deployed to and re-run `./scripts/aws/down.sh`.
diff --git a/deploy/templates/azure/deploy.mdx b/deploy/templates/azure/deploy.mdx
index 84ada58c7..66b86c8c8 100644
--- a/deploy/templates/azure/deploy.mdx
+++ b/deploy/templates/azure/deploy.mdx
@@ -4,18 +4,19 @@ sidebarTitle: "Deploy"
description: "Run AgentOS locally using Docker and deploy to production on Azure Container Apps."
---
-AgentOS is a secure, scalable platform for running agents. The [agentos-azure](https://github.com/agno-agi/agentos-azure) codebase runs AgentOS locally using Docker and deploys to production on Azure Container Apps. It comes with:
+Choose Azure when your team wants AgentOS deployment resources and persisted platform data in its own Azure subscription. The [agentos-azure](https://github.com/agno-agi/agentos-azure) template uses Docker locally and provisions Container Apps, Flexible Server for PostgreSQL, ACR, and networking for production.
-- **2 platform agents** that build and run the platform for you. **Agent Builder** creates agents, teams, and workflows. **Platform Manager** understands, monitors, and explains the platform.
-- **5 [skills](/deploy/templates/improve-agents)** that let coding agents build, test, and improve the platform for you.
+- **Agent Builder**, which creates agents, teams, and workflows when prompted.
+- **Platform Manager**, which inspects registered agents, eval history, deployment checks, and schedules.
+- **Six [skills](/deploy/templates/improve-agents)**. `setup-platform` configures the local platform. Five lifecycle skills create, extend, improve, evaluate, and review it.
-Because the trace data, agent code, evals, and system logs all live in one place, the platform can inspect and improve itself automatically.
+Coding agents can use the repository skills, live AgentOS API, evals, and container logs to inspect and improve the platform.
-Everything runs in your own Azure subscription, and one script provisions the network, database, registry, and app into a single resource group.
+The deployment resources live in one Azure resource group. Model calls and optional interfaces use the providers you configure.
## Get started
-The fastest way to get started is using a coding agent. Copy the prompt below into Claude Code, Cursor or Codex and it'll take you from zero to a running platform.
+Copy the prompt below into Claude Code, Cursor, or Codex to clone the template, start AgentOS locally, and build your first agent.
@@ -81,6 +82,8 @@ Prints `MCP OK` with the tool count and a real agent answer through the MCP endp
**Prerequisites:** [Azure CLI](https://learn.microsoft.com/cli/azure/install-azure-cli) installed and `az login` completed. Docker running; the image is built locally.
+Use a new, dedicated `AZURE_RESOURCE_GROUP`. `down.sh` deletes the entire selected group, including unrelated resources if you point it at a shared group.
+
```bash
@@ -95,7 +98,7 @@ Edit `.env.production` with production values: a different OpenAI key, productio
./scripts/azure/up.sh
```
-The first run takes 15-20 minutes (Postgres Flexible Server is the long pole) and creates everything inside one dedicated resource group, `agentos` by default: a VNet with private DNS, a container registry with the locally built image, PostgreSQL 17 Flexible Server with private access and pgvector allowlisted, the Container Apps environment, and the `agent-os` app pinned to exactly one replica so the in-process scheduler never runs twice. The app URL is only known after create. Once the app is up, the script writes `AGENTOS_URL` back to your env file so scheduled jobs reach the platform. It also generates `MCP_CONNECT_SECRET`, the OAuth consent secret for connecting chat apps, into the same file.
+The first run takes 15-20 minutes. PostgreSQL Flexible Server takes most of that time. The script creates everything inside the selected resource group, `agentos` by default: a VNet with private DNS, a container registry with the locally built image, PostgreSQL 17 Flexible Server with private access and pgvector allowlisted, the Container Apps environment, and the `agent-os` app pinned to one replica. The app URL is only known after create. Once the app is up, the script writes `AGENTOS_URL` back to your env file so scheduled jobs reach the platform. It also generates `MCP_CONNECT_SECRET`, the OAuth consent secret for connecting chat apps, into the same file.
@@ -105,7 +108,7 @@ The script pauses for a `JWT_VERIFICATION_KEY`. Token-Based Authorization is on
2. Go to **Settings** → **OS & Security** and turn on **Token-Based Authorization (JWT)**.
3. Copy the public key and paste the full PEM into the `up.sh` prompt. The script saves it to your env file, stores it as a Container Apps secret, and applies it together with `AGENTOS_URL` in a second revision.
-If your env file already sets `JWT_JWKS_FILE`, the script skips the pause, but it only applies the path. Bake or mount the file before deployment. If you skip the prompt, add `JWT_VERIFICATION_KEY` to `.env.production` and run `./scripts/azure/env-sync.sh`. Adding JWKS later requires an image rebuild or mount plus a redeploy. Env sync alone is insufficient.
+If your env file already sets `JWT_JWKS_FILE`, the script skips the pause and applies the path. Bake or mount the file before deployment. If you skip the prompt, add `JWT_VERIFICATION_KEY` to `.env.production` and run `./scripts/azure/env-sync.sh`. Adding JWKS later requires an image rebuild or mount plus a redeploy. Env sync applies only the path.
Live AgentOS connections are a paid feature. Use code `PLATFORM30` for one month off.
@@ -122,10 +125,13 @@ For claude.ai and ChatGPT on the web: add `https:///mcp` a
```bash
-az containerapp logs show -g agentos -n agent-os --follow
+curl -o /dev/null -w '%{http_code}\n' "https:///health" # 200
+curl -o /dev/null -w '%{http_code}\n' "https:///agents" # 401
+
+az containerapp logs show -g "${AZURE_RESOURCE_GROUP:-agentos}" -n agent-os --follow
```
-The script prints your app URL. Give the revision a couple of minutes to converge, then open `https:///docs` to confirm the API is serving.
+The script prints your app URL. Give the revision a couple of minutes to converge. `/health` and `/docs` remain public. Protected AgentOS routes such as `/agents` require a valid token.
diff --git a/deploy/templates/azure/reference.mdx b/deploy/templates/azure/reference.mdx
index 50ef14be9..9abda4741 100644
--- a/deploy/templates/azure/reference.mdx
+++ b/deploy/templates/azure/reference.mdx
@@ -4,7 +4,7 @@ sidebarTitle: "Reference"
description: "Commands, customization, environment variables, and troubleshooting for the Azure Container Apps template."
---
-The deploy scripts put everything in one resource group, `agentos` by default, and the container app is named `agent-os`. Override the group and region with `AZURE_RESOURCE_GROUP` and `AZURE_LOCATION` (default `eastus`).
+The deploy scripts put everything in one resource group, `agentos` by default, and the container app is named `agent-os`. Override the group and region with `AZURE_RESOURCE_GROUP` and `AZURE_LOCATION` (default `eastus`). Start with [Deploy AgentOS on Azure](/deploy/templates/azure/deploy) for prerequisites and the first deployment.
## Manage
@@ -12,26 +12,28 @@ The deploy scripts put everything in one resource group, `agentos` by default, a
|------|---------|
| Deploy code changes | `./scripts/azure/redeploy.sh` |
| Sync env variables | `./scripts/azure/env-sync.sh` (defaults to `.env.production`; pass `.env` to sync that instead) |
-| Tail logs | `az containerapp logs show -g agentos -n agent-os --follow` |
+| Tail logs | `az containerapp logs show -g "${AZURE_RESOURCE_GROUP:-agentos}" -n agent-os --follow` |
| Tear down | `./scripts/azure/down.sh` (add `--yes` to skip the confirmation) |
`env-sync.sh` turns secret-shaped keys (`OPENAI_API_KEY`, `DB_PASS`, `JWT_VERIFICATION_KEY`, `MCP_CONNECT_SECRET`, `AGENTOS_MCP_SIGNING_KEY`, `PARALLEL_API_KEY`, `SLACK_*`) into Container Apps secrets and everything else into plain env vars, then applies it all in one revision roll. It skips `AZURE_*` keys; those configure the scripts, not the app.
-The app is pinned to one replica (`--min-replicas 1 --max-replicas 1`). Min 1 keeps the in-process scheduler and MCP streams alive; max 1 stops Azure from running two schedulers. Leave both pins in place.
+The app is pinned to one replica (`--min-replicas 1 --max-replicas 1`). Min 1 keeps the service available for scheduled work and MCP streams. The template has been validated with this single-process topology. Validate schedule registration and MCP streams before changing the maximum.
+
+Use a dedicated `AZURE_RESOURCE_GROUP`. `down.sh` deletes the entire selected group and every resource in it.
## Production auth
-Token-Based Authorization is on by default. Production startup requires `JWT_VERIFICATION_KEY` or a readable JWKS file at the container path in `JWT_JWKS_FILE`; otherwise the process exits.
+Token-Based Authorization protects AgentOS routes by default in production. Startup requires `JWT_VERIFICATION_KEY` or a readable JWKS file at the container path in `JWT_JWKS_FILE`; otherwise the process exits.
Token-Based Auth gives you three things:
-1. **No public access.** The server rejects requests without a valid token.
+1. **Protected API access.** Requests to protected AgentOS routes require a valid token. `/`, `/health`, `/info`, `/docs`, `/redoc`, `/openapi.json`, and `/docs/oauth2-redirect` remain public.
2. **Per-request identity.** Middleware validates the token and exposes its `user_id`, optional `session_id`, scopes, and claims to the request.
3. **Scope-based permissions.** Token scopes control access to AgentOS routes and resources.
The templates do not enable per-user data isolation. To scope non-admin session, memory, trace, and run access to the JWT subject, pass `authorization_config=AuthorizationConfig(user_isolation=True)` to `AgentOS`. See [User Isolation](/agent-os/security/authorization/user-isolation).
-To opt out (not recommended), set `authorization=False` in `app/main.py` and redeploy. Use this only inside a private VPC behind another auth layer. Without it, anyone who guesses your Container Apps domain can access your platform.
+To disable JWT authentication, set `authorization=False` in `app/main.py`, remove `JWT_VERIFICATION_KEY` and `JWT_JWKS_FILE` from the Container App, and redeploy. `authorization=False` disables AgentOS scope enforcement. Configured JWT environment variables continue to enable JWT validation. MCP OAuth remains active when `MCP_CONNECT_SECRET` is set. Only do this when another layer protects the service.
## Customize
@@ -86,13 +88,13 @@ def default_model():
return Claude(id="claude-sonnet-5")
```
-Add `anthropic` to `pyproject.toml`, set the provider key in your env, and regenerate pins:
+Add `anthropic` to `pyproject.toml`. Set `ANTHROPIC_API_KEY` in `.env` for local runs and `.env.production` for production, then regenerate pins:
```bash
./scripts/generate_requirements.sh
```
-Rebuild locally with `docker compose up -d --build`. For production:
+Before production sync, add `ANTHROPIC_API_KEY` to the `is_secret_key()` allowlist in `scripts/azure/env-sync.sh`. This stores the key as a Container Apps secret. Then rebuild and deploy:
```bash
./scripts/azure/env-sync.sh
@@ -157,7 +159,7 @@ source .venv/bin/activate
| Variable | Required | Default | Description |
|----------|----------|---------|-------------|
| `OPENAI_API_KEY` | Yes | - | Models and embeddings. |
-| `RUNTIME_ENV` | No | `prd` | `dev` disables JWT. Compose sets it for local. Never put it in an env file that syncs to Azure, or production deploys unauthenticated. |
+| `RUNTIME_ENV` | No | `prd` | `dev` sets `authorization=False`, which disables AgentOS scope enforcement. Configured JWT environment variables continue to enable JWT validation. Compose sets `dev` locally; keep `prd` on Azure. |
| `JWT_VERIFICATION_KEY` | Production | - | Public key from os.agno.com. Quote the value so the multi-line PEM parses as one variable. |
| `JWT_JWKS_FILE` | Production | - | Path inside the running container to a JWKS JSON file. The scripts set only this path. Add the file to the image build context, rebuild, and redeploy the image, or configure a platform mount and roll the service. |
| `MCP_CONNECT_SECRET` | No | generated by `up.sh` | OAuth consent secret (16+ chars) for connecting claude.ai and ChatGPT to `/mcp`. `up.sh` generates one on deploy and writes it to `.env.production`. |
@@ -174,7 +176,7 @@ source .venv/bin/activate
| `DB_HOST` / `DB_PORT` / `DB_USER` / `DB_PASS` / `DB_DATABASE` | No | matches compose | Postgres connection. `up.sh` wires them to the Flexible Server. |
| `DB_DRIVER` | No | `postgresql+psycopg` | SQLAlchemy driver. |
| `AGNO_DEBUG` | No | `False` | Verbose Agno logs. Compose sets it for dev. |
-| `WAIT_FOR_DB` | No | `False` | If `True`, the entrypoint blocks on the database before starting. Compose sets it. |
+| `WAIT_FOR_DB` | No | `False` | If `True`, the entrypoint blocks on the database before starting. Compose and the production deploy set it to `True`. |
| `AZURE_RESOURCE_GROUP` | No | `agentos` | Resource group every deploy script targets. Never synced to the app. |
| `AZURE_LOCATION` | No | `eastus` | Region for the first `up.sh` run. Never synced to the app. |
| `AZURE_ACR_NAME` | No | generated by `up.sh` | Registry name. Minted once and saved to your env file so re-runs reuse it. |
@@ -195,13 +197,13 @@ The image is built locally and pushed to your registry, so both scripts need Doc
Expected. Mint the key at [os.agno.com](https://os.agno.com): connect your OS (**Connect OS** → **Live**, enter your Container Apps URL), then turn on **Token-Based Authorization (JWT)** under **Settings** → **OS & Security** and paste the full PEM. To add a PEM later, set `JWT_VERIFICATION_KEY` and run `./scripts/azure/env-sync.sh`. To use JWKS, add the file to the image build context and rebuild, or configure a mount. Set `JWT_JWKS_FILE` to its container path, then redeploy or roll the service. Env sync alone only updates the path.
-JWT auth is on whenever `RUNTIME_ENV` is not `dev`. Set `JWT_VERIFICATION_KEY` and sync. For JWKS, verify the file exists inside the container at `JWT_JWKS_FILE`; changing the variable alone does not deliver it. To opt out inside a private VPC behind another auth layer, set `authorization=False` in `app/main.py`.
+AgentOS scope enforcement is on whenever `RUNTIME_ENV` is not `dev`. Set `JWT_VERIFICATION_KEY` and sync. For JWKS, verify the file exists inside the container at `JWT_JWKS_FILE`; changing the variable alone does not deliver it. To disable JWT, set `authorization=False` in `app/main.py`, remove both JWT variables from the Container App, and redeploy. MCP OAuth remains active when `MCP_CONNECT_SECRET` is set.
-The revision is still converging. Wait a couple of minutes and check `az containerapp logs show -g agentos -n agent-os --follow`.
+The revision is still converging. Wait a couple of minutes and check `az containerapp logs show -g "${AZURE_RESOURCE_GROUP:-agentos}" -n agent-os --follow`.
-Run it again. The generated names (`AZURE_ACR_NAME`, `AZURE_PG_NAME`) and `DB_PASS` persist in your env file, so re-runs reuse the same registry and Postgres server instead of minting new ones.
+Run it again. The generated names (`AZURE_ACR_NAME`, `AZURE_PG_NAME`) and `DB_PASS` persist in your env file, so re-runs use the same registry and Postgres server.
`AGENTOS_URL` is still the localhost default. `up.sh` sets it to your Container Apps URL automatically; for a custom domain or tunnel, set it by hand and run `./scripts/azure/env-sync.sh`.
diff --git a/deploy/templates/coda/overview.mdx b/deploy/templates/coda/overview.mdx
index 1d8373bed..4e940b70c 100644
--- a/deploy/templates/coda/overview.mdx
+++ b/deploy/templates/coda/overview.mdx
@@ -1,61 +1,17 @@
---
title: "Coda"
-sidebarTitle: "Coda"
-description: "A code companion that lives in Slack. It reviews PRs, triages issues, and answers architecture questions."
+sidebarTitle: "Coda: Code Agent"
+description: "Slack-based engineering companion that reviews PRs, triages issues, answers architecture questions, and prepares code changes."
---
-**Coda is a code companion that lives in Slack.**
+**Coda gives engineering teams a Slack-based companion for work that spans source code, pull requests, and issues.**
-Coding agents help us write code faster, but most engineering work is understanding how things work, reviewing PRs, figuring out what broke and why, triaging the backlog, and deciding what's safe to change. That work happens in Slack and GitHub, not in an editor.
+Engineers spend much of their time tracing code, reviewing changes, diagnosing failures, and deciding what to tackle next. Coda brings that work into the Slack threads where the team is already coordinating.
-Coda fills that gap. It answers architecture questions like "how does auth work" or "where is the model API call". It reviews PRs and open branches, diffs them against your conventions, and leaves comments. It reads open issues and flags the urgent ones worth tackling next. And it does all of this in Slack, alongside your team.
+Coda uses an Agno team to route each request to a specialist, carries stored conventions into later runs with the Learning Machine, and runs scheduled repo syncs and digests through AgentOS. Start it against one repository, then ask where authentication is implemented or request a review of an open PR.
The code is public at [agno-agi/coda](https://github.com/agno-agi/coda).
-## How it works
-
-Coda is a team of five specialist agents coordinated by a leader:
-
-| Agent | Role |
-|-------|------|
-| **Explorer** | Searches code, answers architecture questions, reviews PRs (read-only) |
-| **Coder** | Writes code in isolated worktrees, opens PRs |
-| **Planner** | Breaks features into ordered GitHub issues |
-| **Triager** | Labels, comments on, and closes issues based on code analysis |
-| **Researcher** | Searches the web for docs, APIs, and error messages |
-
-Coda writes code in git worktrees on `coda/*` branches, so your main branch is never touched. It opens PRs; a human merges them. And it runs in your infrastructure, so your code stays on your machines. The only external calls go to your configured LLM provider.
-
-Between them, the agents cover:
-
-| Capability | What it does |
-|------------|--------------|
-| **Architecture Q&A** | Answers "how does auth work" with file paths and line numbers |
-| **PR reviews** | Pulls the diff, checks it against your conventions, leaves inline comments |
-| **Issue triage** | Categorizes, labels, flags duplicates, closes junk |
-| **Planning** | Turns a feature request into ordered, well-scoped GitHub issues |
-| **Web research** | Brings back framework docs, library APIs, and error explanations with sources |
-| **Code writing** | Ships changes from isolated worktrees as PRs |
-
-### Scheduled tasks
-
-Coda also shows up on its own. Two background tasks register at startup:
-
-| Task | What it does |
-|------|--------------|
-| **Daily digest** | Posts a morning summary: what merged, what needs review, what went stale |
-| **Repo sync** | Pulls the latest changes from configured repos every 5 minutes |
-
-Repo sync always runs. The daily digest only registers when both `DIGEST_CHANNEL` and `SLACK_TOKEN` are set in `.env`. Set `DIGEST_CHANNEL` to the Slack channel ID the summary should post to (right-click a channel in Slack, then View details to copy the ID).
-
-### Self-learning
-
-Coda gets sharper the more you use it. It picks up your coding standards, conventions, and patterns. The learning is powered by Agno's [Learning Machines](/learning/overview):
-
-| Week 1 | Week 4 |
-|--------|--------|
-| Writes working code using generic patterns | Follows your service layer conventions, uses your team's error handling pattern, matches your naming style |
-
## Run locally
The [Coda README](https://github.com/agno-agi/coda#readme) walks through this in more detail.
@@ -67,7 +23,7 @@ cp example.env .env
# Edit .env: add OPENAI_API_KEY and GITHUB_ACCESS_TOKEN
```
-`OPENAI_API_KEY` comes from [platform.openai.com](https://platform.openai.com/api-keys). For `GITHUB_ACCESS_TOKEN`, create a fine-grained Personal Access Token with Contents (read and write), Pull requests (read and write), Issues (read and write), and Metadata (read). The full walkthrough is in [docs/GITHUB_ACCESS.md](https://github.com/agno-agi/coda/blob/main/docs/GITHUB_ACCESS.md). `PARALLEL_API_KEY` (from [parallel.ai](https://parallel.ai)) is optional; it enables the Researcher agent. Without it the team runs with no web research.
+`OPENAI_API_KEY` comes from [platform.openai.com](https://platform.openai.com/api-keys). For `GITHUB_ACCESS_TOKEN`, create a fine-grained Personal Access Token with Contents (read and write), Pull requests (read and write), Issues (read and write), and Metadata (read). The full walkthrough is in [docs/GITHUB_ACCESS.md](https://github.com/agno-agi/coda/blob/main/docs/GITHUB_ACCESS.md). `PARALLEL_API_KEY` (from [parallel.ai](https://parallel.ai)) adds the optional Researcher agent.
Tell Coda which repos to learn by editing `repos.yaml`:
@@ -77,7 +33,7 @@ repos:
branch: main
```
-The agno repo makes a good starting point, so you have some test questions to play around with.
+Use the Agno repository as a test target if you need one.
Then start Coda (Docker needs to be running):
@@ -94,6 +50,37 @@ Confirm it's up at [localhost:8000/docs](http://localhost:8000/docs).
This gives you a web UI to chat with Coda directly, plus sessions, traces, metrics, memory, and evaluations.
+## How it works
+
+Coda coordinates four core specialists and an optional Researcher:
+
+| Agent | Role |
+|-------|------|
+| **Explorer** | Searches code, answers architecture questions, reviews PRs (read-only) |
+| **Coder** | Writes code in isolated worktrees, opens PRs |
+| **Planner** | Breaks features into ordered GitHub issues |
+| **Triager** | Labels, comments on, and closes issues based on code analysis |
+| **Researcher** | Searches the web for docs, APIs, and error messages when `PARALLEL_API_KEY` is set |
+
+Coda's instructions direct the Coder to use git worktrees on `coda/*` branches. Its git tool refuses to push any other branch, and a human merges the resulting PR. Worktree use for local edits remains an agent instruction, so review each diff and PR before merging.
+
+Coda runs in your infrastructure and connects to services you configure. These can include your model provider, GitHub, Slack, and Parallel for optional web research. Review those services' data-handling settings before connecting private repositories.
+
+### Scheduled tasks
+
+Coda also shows up on its own. Two background tasks register at startup:
+
+| Task | What it does |
+|------|--------------|
+| **Daily digest** | Posts a morning summary: what merged, what needs review, what went stale |
+| **Repo sync** | Pulls the latest changes from configured repos every 5 minutes |
+
+Repo sync always runs. The daily digest only registers when both `DIGEST_CHANNEL` and `SLACK_TOKEN` are set in `.env`. Set `DIGEST_CHANNEL` to the Slack channel ID the summary should post to (right-click a channel in Slack, then View details to copy the ID).
+
+### Self-learning
+
+Each specialist uses Agno's [Learning Machine](/learning/overview) to store reusable conventions and add them to later context. These learnings can cover service-layer patterns, error handling, and naming rules. Review stored learnings as you would other generated project knowledge.
+
## Deploy to Railway
You'll need the [Railway CLI](https://docs.railway.app/guides/cli) installed and `railway login` completed.
diff --git a/deploy/templates/context/overview.mdx b/deploy/templates/context/overview.mdx
index 1f6f0694b..a39d38606 100644
--- a/deploy/templates/context/overview.mdx
+++ b/deploy/templates/context/overview.mdx
@@ -1,43 +1,74 @@
---
title: "Context"
-sidebarTitle: "Context"
-description: "Self-hosted context manager that organizes your work into a private CRM and knowledge base your AI tools share over MCP."
+sidebarTitle: "Context: Multiplayer Agent"
+description: "Self-hosted multiplayer context agent with a private CRM, knowledge base, teammate inbox, and read-only MCP surface."
---
-**@context is a self-hosted context manager. It organizes your work context into a private CRM and knowledge base and helps you stay on top of things.**
+**@context gives one owner a private work context that teammates can contribute to and AI apps can read through a constrained surface.**
-It plugs into clients like Claude, ChatGPT, Claude Code, Codex, and Cursor, and gives them a single source of context about your work. Anyone can write to your context. Only you can read it or act through it.
+It is for founders, managers, and operators whose contacts, decisions, reminders, messages, and project knowledge are spread across systems. Teammates can submit updates and check their own receipts. Only verified owner identities receive the private CRM, knowledge, retrieval, and action surfaces.
-@context is an [App](/deploy/introduction): a complete agent product you fork, run on your own infrastructure, and adapt. See the [repo](https://github.com/agno-agi/context) for the source.
+Agno selects tools from the caller's identity before the model runs, loads owner-only playbooks at runtime, and exposes one read-only MCP tool to Claude, ChatGPT, Claude Code, Codex, Cursor, and other clients. Run it locally, connect the AgentOS UI, then capture a contact or ask for your daily rundown. The [source](https://github.com/agno-agi/context) is public.
-## How it works
+## Run locally
+
+**Prerequisites:** [Docker](https://www.docker.com/get-started/) and an [OpenAI API key](https://platform.openai.com).
+
+```bash
+git clone https://github.com/agno-agi/context.git && cd context
+
+cp example.env .env
+# Set OPENAI_API_KEY, OWNER_ID, OWNER_NAME, and OWNER_TIMEZONE in .env
-@context is one Agno agent that captures, files, and retrieves your working context across many sources. In production, AgentOS verifies HTTP identities from JWTs. Slack verifies signed events and maps their authors to user IDs. Local HTTP requests trust the caller-supplied `user_id`, so run them only on a trusted machine. @context assigns tools from that identity:
+docker compose up -d --build
+curl http://localhost:8000/health
+```
-1. **Owner mode.** You get every tool. Capture context (*"met Kyle from Agno, follow up next week"*), retrieve context (*"give me a rundown of my day"*), and prepare context (*"process today"*).
-2. **Guest mode.** Teammates and their agents can leave updates in your queue and check their own submissions. When Calendar is configured, they can also ask `owner_availability` for your open windows. It returns free/busy intervals without event details. You get briefed when you ask for a rundown.
+Open the API at [localhost:8000/docs](http://localhost:8000/docs). `OWNER_ID` decides who receives the private owner surface. In AgentOS and private Slack DMs, every other verified caller receives the private guest surface.
-### Five jobs
+### Connect the AgentOS UI
-1. **Maintain a CRM.** Share *"met Kyle from Agno, wants a partnership, follow up next week"*, and @context stores a contact, a note, and a dated reminder without you picking forms or fields.
-2. **Maintain a knowledge base.** @context writes product specs, parses customer interview notes, manages project briefs, and runs deep research, then keeps it all organized in one place.
-3. **Run your day, plan your week, prep ahead.** @context runs repeatable playbooks to make things easier. A few come built in, and you should customize them and add your own.
-4. **Represent you.** A teammate types *"@your-context my claude fixed the auth bug"*, and it lands in your queue and surfaces in your next rundown. It works outbound too. @context can message people and channels on Slack on your behalf, and @-mention a teammate's @context to drop an update in their queue. That's how a team's contexts talk to each other (the [context network](https://github.com/agno-agi/context/blob/main/docs/NETWORK.md)).
-5. **Draft and schedule.** Connect Gmail and Calendar, and @context reads your real inbox and calendar, drafts your follow-ups straight into Gmail for you to send, and sends calendar changes to your approvals queue.
+1. Open [os.agno.com](https://os.agno.com) and sign in with an identity listed in `OWNER_ID`.
+2. Choose **Connect OS** → **Local**.
+3. Enter `http://localhost:8000`, name it **Local Context**, and connect.
+4. Open **Context** under Agents and try a prompt from the examples below.
-The built-in playbooks:
+### Connect MCP clients
+
+The MCP endpoint exposes one tool, `use_context`, for retrieving and preparing the owner's private context. Filing, learning, acknowledgement, drafts, Slack sends, and other mutations are absent from this surface.
+
+```bash
+uvx agno connect
+```
+
+The command detects supported local clients, preserves their other MCP entries, registers `http://localhost:8000/mcp`, and verifies the connection. Undo the registrations with `uvx agno disconnect`.
+
+Local MCP is keyless in development. Anything that can reach the port can read the owner's context through `use_context`. Keep it on a trusted machine and network. See [docs/MCP.md](https://github.com/agno-agi/context/blob/main/docs/MCP.md) for production OAuth and per-client setup.
+
+## How it works
+
+@context is one Agno agent that captures, files, retrieves, and prepares working context. In production, AgentOS verifies HTTP identities from JWTs. Slack verifies signed events and maps their authors to user IDs. Explicit local development trusts the caller-supplied `user_id`.
+
+| Caller | Effective surface |
+|--------|-------------------|
+| Owner in AgentOS or a private Slack DM | Full configured Context surface |
+| Guest in a private run or DM | `submit_update`, caller-scoped `my_updates`, and caller-scoped learning |
+| Anyone in a shared Slack room | `submit_update` only |
+| Owner-approved MCP client | Fresh, private, read-only `use_context` calls |
+
+The built-in playbooks help the owner retrieve and prepare context:
| Playbook | Ask | What you get |
|----------|-----|--------------|
-| **Rundown** | "What's on today?" | One digest instead of five apps: the updates teammates left in your queue, reminders that are due, today's meetings, the emails you missed, and the Slack threads worth a look |
+| **Rundown** | "What's on today?" | Queued teammate updates, due reminders, stored meetings, and relevant Gmail or Slack context when configured |
| **Week plan** | "What's my week?" | Priorities for the week. When Slack is configured, runs Sunday evening and lands in your Slack DMs |
| **Prep** | "Prep for my 2pm with Kyle" | A pre-meeting brief: who they are, notes, past threads, what's still open, and public background for contacts you don't know yet |
-@context runs these on demand. When Slack is configured, the scheduled daily rundown and weekly plan DM the brief straight to you. Playbooks live in `skills/`, one `SKILL.md` per folder, alongside `process-today`, `research`, and `knowledge-review`.
+Playbooks live in `skills/`, one `SKILL.md` per folder. The shipped set also includes `process-today`, `research`, and `knowledge-review`. When Slack is configured, scheduled daily and weekly playbooks DM their results to the owner.
### Context sources
-Most sources are sub-agents behind at most two tools: `query_` to read and `update_` to write. The workspace source is the exception; it exposes its read tools (`list_files`, `search_content`, `read_file`) directly to the agent.
+Most sources use Agno context providers that expose `query_` for reads and a source-scoped update tool where writes are enabled. The workspace source exposes `list_files`, `search_content`, and `read_file` directly.
| Source | Access | Enabled by |
|--------|--------|------------|
@@ -45,64 +76,18 @@ Most sources are sub-agents behind at most two tools: `query_` to read and `
| `knowledge` | Read and write | Always on |
| `workspace` | Read | Always on |
| `web` | Read | Always on |
-| `slack` | Read and write | `SLACK_BOT_TOKEN` |
-| `gmail` | Read and write; writes are drafts only | `GOOGLE_*` credentials |
-| `calendar` | Read and write; writes pause for approval | `GOOGLE_*` credentials |
+| `slack` | Read; owner-confirmed sends | `SLACK_BOT_TOKEN` |
+| `gmail` | Read; draft create and update only | Google OAuth credentials and a Gmail token |
-The `crm` source is the structured store: contacts, projects, meetings, reminders, notes, and queued updates in the `crm` Postgres schema. Writes are confined to that schema and every row is scoped to your `user_id`, so a guest can't see this data. The `knowledge` source is the prose store for specs and research notes. It lives on the filesystem by default and can use a private Git repository in production.
+The `crm` source stores contacts, projects, meetings, reminders, notes, and queued updates in Postgres. The `knowledge` source stores specs and research notes on the filesystem by default and can use a private Git repository in production.
### Security
-@context is an alter ego with access to a lot of sensitive information, so the security boundaries need to be airtight. The toolset is chosen in code from the request identity before the model runs. Production HTTP requests use verified JWT identities, and Slack events use signed author identities. Local HTTP development trusts the caller-supplied identity. The owner gets the full surface. A guest gets `submit_update` to append to your queue, `my_updates` to see only their own submissions, and `owner_availability` when Calendar is configured. The availability tool returns free/busy intervals without event details. Guests cannot access your CRM, knowledge base, inbox, or calendar events. Each caller gets separate user memory.
-
-The Slack, Calendar, and Gmail write tools are owner-only. `update_slack` sends messages immediately. `update_calendar` pauses for your explicit approval before it changes the calendar. `update_gmail` creates a draft for you to review and send. It never sends email.
-
-@context runs locally or in your own cloud. Its CRM and inbound queue live in Postgres. Its knowledge base lives on the filesystem by default and can use a private Git repository in production. Slack, Gmail, Calendar, and web are external sources accessed through provider APIs. See [docs/SECURITY.md](https://github.com/agno-agi/context/blob/main/docs/SECURITY.md).
-
-## Run locally
-
-**Prerequisites:** [Docker](https://www.docker.com/get-started/) installed and running. An [OpenAI API key](https://platform.openai.com).
+The toolset is chosen in code from the request identity before the model runs. A private guest can append to the owner's queue with `submit_update` and read only their own receipts with `my_updates`. Shared Slack rooms expose only `submit_update`. Guests cannot access the owner's CRM, knowledge base, inbox, queue, or action tools. Each caller's memory is scoped to their verified identity.
-```bash
-git clone https://github.com/agno-agi/context.git
-cd context
-
-cp example.env .env
-# Open .env: set OPENAI_API_KEY, and set OWNER_ID to the email you sign in to os.agno.com with
-
-docker compose up -d --build
-```
-
-Confirm it is live at [localhost:8000/docs](http://localhost:8000/docs).
-
-`OWNER_ID` decides who counts as the owner. Set it to your email; anyone else gets the capture-only guest tools. `OWNER_NAME` is an optional display name.
-
-### Connect the AgentOS UI
-
-AgentOS comes with a web UI for managing and monitoring @context. Use it to chat with @context, view sessions, and approve actions.
-
-1. Open [os.agno.com](https://os.agno.com) and sign in with the email you set as `OWNER_ID`.
-2. Click **Connect AgentOS** → **Local**, enter `http://localhost:8000`, and name it **Local Context**.
-3. Open the chat under Context and try one of the quick prompts.
-
-### Connect MCP clients
+Owner actions are narrow. `update_slack` sends exact text only after explicit approval. `update_gmail` can create or update a draft and has no send capability. After a provider, workspace, or rundown read, the current run becomes read-only. Make any follow-up mutation as a fresh private request.
-The main way to use @context is from an MCP client like Claude Code, Codex, Claude, Cursor, or ChatGPT. The local server runs at `http://localhost:8000/mcp` with keyless-as-owner access. With `OWNER_ID` configured, every client that can reach the endpoint is treated as that owner and receives the full read, write, and action surface. Keep the development endpoint on a trusted machine. One command adds @context to every MCP client on your machine:
-
-```bash
-python scripts/connect.py
-```
-
-The script finds Claude Code, Codex, Claude Desktop, and Cursor, and registers @context with each. Use `--dry-run` to preview and `--remove` to undo.
-
-To register the CLI clients by hand:
-
-```bash
-claude mcp add -s user --transport http context http://localhost:8000/mcp
-codex mcp add --url http://localhost:8000/mcp context
-```
-
-Claude Desktop and Cursor take config-file entries. See [docs/MCP.md](https://github.com/agno-agi/context/blob/main/docs/MCP.md) for both.
+@context runs locally or in your own cloud. Its CRM and inbound queue live in Postgres, and its knowledge base lives on the filesystem or in a private Git repository. Prompts and retrieved material are processed by the model and provider services you configure. See [docs/SECURITY.md](https://github.com/agno-agi/context/blob/main/docs/SECURITY.md).
## Deploy to Railway
@@ -130,7 +115,7 @@ The script creates your public domain, then pauses and waits while you mint the
Token-Based Authorization is on by default. Without a `JWT_VERIFICATION_KEY` in `.env.production`, the AgentOS will not serve traffic. That is the safe default for an agent that holds your work context. You can also [issue and verify your own JWT](/agent-os/security/authorization/self-hosted).
-1. Open [os.agno.com](https://os.agno.com), click **Connect AgentOS** → **Live**, and paste the domain the script printed.
+1. Open [os.agno.com](https://os.agno.com), click **Connect OS** → **Live**, and paste the domain the script printed.
2. Turn on **Token-Based Authorization** and click **Connect**.
3. Copy the public key into `.env.production` as `JWT_VERIFICATION_KEY`.
4. Back in the terminal, press Enter. The script reads the key and deploys the service.
@@ -149,15 +134,13 @@ If you add or update values in `.env.production`, sync them with `./scripts/rail
### Point MCP clients at production
-Production connections ride MCP OAuth. Setting `MCP_CONNECT_SECRET` turns the deployment into its own OAuth 2.1 authorization server on `/mcp`: a client connects by URL, and you approve it once on a consent page by typing the secret. `up.sh` already generated the secret on deploy. If you deployed before it existed, one command arms everything:
+Production connections use MCP OAuth. `scripts/railway/up.sh` generates `MCP_CONNECT_SECRET` when it is missing. A client connects by URL, and you approve it once on a consent page by entering that secret.
```bash
-./scripts/setup_context.sh
+uvx agno connect --url https://
```
-`setup_context.sh` makes sure `MCP_CONNECT_SECRET` and `AGENTOS_MCP_SIGNING_KEY` exist in `.env.production` (generating them when missing), syncs the env to Railway, runs an explicit code and image redeploy, and prints the connector recipe with your real domain and secret. Add `--no-redeploy` to skip the explicit `railway up` redeploy. Environment sync can still trigger a Railway redeploy when it pushes changed variables.
-
-Then connect your clients. In claude.ai or ChatGPT, add `https:///mcp` as a custom connector, leave the OAuth client ID and secret fields empty, and approve the consent page with the secret. For the CLI clients, `uvx agno connect --url https://` wires Claude Code, Codex, Cursor, and Claude Desktop and prints each client's sign-in step. The AgentOS UI keeps working alongside; it authenticates with the os.agno.com JWT, a separate door from MCP OAuth. Rotating `AGENTOS_MCP_SIGNING_KEY` revokes every issued token, and rotating `MCP_CONNECT_SECRET` only gates future consents.
+The command wires Claude Code, Codex, Cursor, and Claude Desktop and prints each client's sign-in step. In claude.ai or ChatGPT, add `https:///mcp` through the app's custom connector flow, leave optional OAuth client credentials empty, and approve the consent page with `MCP_CONNECT_SECRET`. The AgentOS UI uses its separate control-plane JWT. Rotating `AGENTOS_MCP_SIGNING_KEY` revokes every issued token; rotating `MCP_CONNECT_SECRET` gates future consents.
See [docs/MCP.md](https://github.com/agno-agi/context/blob/main/docs/MCP.md#production-mcp-oauth) for the consent flow, per-client specifics, and ChatGPT and Claude on the web.
@@ -183,29 +166,34 @@ With Slack configured, teammates can @-mention @context to leave you updates, yo
Local runs need a public URL for Slack's callbacks, so use an ngrok tunnel. Once you deploy, repoint the app's `/slack/events` and `/slack/interactions` request URLs at your Railway domain.
-## Connect Gmail and Calendar
+## Connect Gmail
-Connect Gmail and Calendar to ground the rundown and meeting prep in your real inbox and calendar. Set `GOOGLE_CLIENT_ID`, `GOOGLE_CLIENT_SECRET`, and `GOOGLE_PROJECT_ID`, then mint the consent tokens once with `python scripts/google_mint_tokens.py`. See [docs/GOOGLE.md](https://github.com/agno-agi/context/blob/main/docs/GOOGLE.md).
+Connect Gmail to ground rundowns and preparation in your inbox. Set `GOOGLE_CLIENT_ID`, `GOOGLE_CLIENT_SECRET`, and `GOOGLE_PROJECT_ID`, then mint the consent token once with `python scripts/google_mint_tokens.py`. See [docs/GOOGLE.md](https://github.com/agno-agi/context/blob/main/docs/GOOGLE.md).
## Example prompts
-Try these from the AgentOS UI, Slack, or an MCP client:
+Use the AgentOS UI or a private Slack DM for prompts that write context:
- Add Dana Reyes, Head of Platform at Acme, dana@acme.com. Remind me to send her the integration spec next Tuesday.
+- Write up a decision: we're standardizing on Agno.
+
+Use any connected interface for retrieval and preparation:
+
- Who do I know at Acme?
- What's on today?
-- Prep for my 2pm with Kyle
-- Write up a decision: we're standardizing on Agno
+- Prep for my 2pm with Kyle.
- What in my knowledge base needs attention?
## Run evals
-@context comes with an eval suite ([`evals/`](https://github.com/agno-agi/context/tree/main/evals)) for regression testing the security model. It tests the claim that anyone can write and only you can read: deterministic gates check that a guest's toolset stays capture-only and the MCP server stays owner-only, and an adversarial guest arc tries to break the boundary.
+@context comes with model-backed behavioral evals in [`evals/`](https://github.com/agno-agi/context/tree/main/evals). They exercise guest boundaries and adversarial attempts to reach owner data. Deterministic policy and authorization checks live in `tests/`.
```bash
-python -m evals # run the full suite
-python -m evals -v # stream the full agent run
-python -m evals --case # one case
+./scripts/venv_setup.sh
+
+.venv/bin/python -m evals --tag smoke
+.venv/bin/python -m evals --tag release
+.venv/bin/python -m evals --name guest_cannot_read_the_crm
```
## Source
@@ -215,10 +203,10 @@ The [GitHub repo](https://github.com/agno-agi/context) has the full detail:
| Guide | Covers |
|-------|--------|
| [`AGENTS.md`](https://github.com/agno-agi/context/blob/main/AGENTS.md) | Architecture, key files, and conventions for coding agents |
-| [`docs/SECURITY.md`](https://github.com/agno-agi/context/blob/main/docs/SECURITY.md) | The owner/guest model, act tools, and the approval gate |
+| [`docs/SECURITY.md`](https://github.com/agno-agi/context/blob/main/docs/SECURITY.md) | The owner/guest model, read boundary, and action controls |
| [`docs/MCP.md`](https://github.com/agno-agi/context/blob/main/docs/MCP.md) | Per-client MCP setup and production MCP OAuth |
| [`docs/SLACK.md`](https://github.com/agno-agi/context/blob/main/docs/SLACK.md) | The app manifest, identity resolution, and moving to production |
| [`docs/KNOWLEDGE.md`](https://github.com/agno-agi/context/blob/main/docs/KNOWLEDGE.md) | The knowledge base and Git backing |
| [`docs/CRM.md`](https://github.com/agno-agi/context/blob/main/docs/CRM.md) | The `crm` schema, filing rules, and the write boundary |
-| [`docs/GOOGLE.md`](https://github.com/agno-agi/context/blob/main/docs/GOOGLE.md) | Gmail and Calendar setup |
+| [`docs/GOOGLE.md`](https://github.com/agno-agi/context/blob/main/docs/GOOGLE.md) | Gmail setup |
| [`docs/NETWORK.md`](https://github.com/agno-agi/context/blob/main/docs/NETWORK.md) | How a team's contexts talk to each other |
diff --git a/deploy/templates/dash/overview.mdx b/deploy/templates/dash/overview.mdx
index 22dc968d7..ff3284802 100644
--- a/deploy/templates/dash/overview.mdx
+++ b/deploy/templates/dash/overview.mdx
@@ -1,52 +1,16 @@
---
title: "Dash"
-sidebarTitle: "Dash"
-description: "Self-learning data agent that grounds answers in six layers of context and improves with every query."
+sidebarTitle: "Dash: Data Agent"
+description: "Self-hosted data agent that grounds SQL answers in six layers of company context and stores reusable fixes."
---
-**Dash is a self-learning data agent built with systems engineering principles. It grounds answers in six layers of context and improves with every query.**
+**Dash gives data teams a self-hosted agent for answering business questions against company databases.**
-Ask a question in English and get a correct, meaningful answer. That's the goal. But raw LLMs writing SQL hit a wall fast: schemas lack meaning, types are misleading, tribal knowledge is missing, there's no way to learn from mistakes, and results lack interpretation. The root cause is missing context and missing memory. Dash solves this with six layers of grounded context, a self-learning loop that captures every fix, and a focus on delivering insights you can act on.
+Database schemas rarely contain metric definitions, proven query patterns, or the reasons a past query failed. Dash combines that company context with live schema inspection so its SQL and explanations reflect how your organization uses its data.
-Chat with Dash in Slack, the terminal, or the [AgentOS UI](https://os.agno.com). The code is public at [agno-agi/dash](https://github.com/agno-agi/dash).
-
-## How it works
-
-Dash runs as an Agno team in coordinate mode, with a leader that routes each request to two specialists:
-
-| Agent | Role |
-|-------|------|
-| **Analyst** | Reads company data (read-only), generates SQL, interprets results |
-| **Engineer** | Builds reusable views and summary tables in the `dash` schema |
-| **Leader** | Routes queries, coordinates the team, posts to Slack |
-
-**Schema boundaries:** Company data lives in the `public` schema; agent-created views and summary tables live in the `dash` schema. The Analyst connects with `default_transaction_read_only=on`, so PostgreSQL rejects any write it attempts. A SQLAlchemy event listener blocks Engineer writes that target `public`. These guardrails live in the infrastructure, so they hold regardless of what the model generates.
-
-### Six layers of context
-
-| Layer | Purpose | Source |
-|-------|---------|--------|
-| **Table Usage** | Schema, columns, relationships | `knowledge/tables/*.json` |
-| **Human Annotations** | Metrics, definitions, business rules | `knowledge/business/*.json` |
-| **Query Patterns** | SQL that is known to work | `knowledge/queries/*.sql` |
-| **Institutional Knowledge** | Docs, wikis, external references | MCP (optional) |
-| **Learnings** | Error patterns and discovered fixes | Agno `Learning Machine` |
-| **Runtime Context** | Live schema changes | `introspect_schema` tool |
-
-### Self-learning
-
-Every query retrieves knowledge and learnings before generating SQL. When a query fails, Dash diagnoses the error, fixes it, and saves the fix as a learning. Two complementary systems make this work:
-
-| System | Stores | How it evolves |
-|--------|--------|----------------|
-| **Knowledge** | Validated queries, table schemas, business rules | Curated by you and refined by Dash |
-| **Learnings** | Error patterns and discovered fixes | Managed automatically by the Learning Machine |
-
-When a churn query returns wrong numbers because it filtered on the `status` column instead of `ended_at IS NULL`, Dash saves the fix and doesn't make that mistake again. When your team defines MRR as the sum of active subscriptions excluding trials, that rule lives in `knowledge/business/` and every future query respects it.
-
-### Insights you can act on
+Agno coordinates an Analyst and Engineer, keeps curated knowledge and learned fixes available across runs, and serves the team through AgentOS. Run Dash against the included SaaS dataset, then ask it for your current MRR or highest-churn plan.
-Dash reasons about what makes an answer useful. Ask "Which plan has the highest churn rate?" and you get the number, the comparison across plans, the trend behind it, and any caveats from your business rules.
+Chat with Dash in Slack, the terminal, or the [AgentOS UI](https://os.agno.com). The code is public at [agno-agi/dash](https://github.com/agno-agi/dash).
## Run locally
@@ -86,6 +50,40 @@ Confirm Dash is running at [http://localhost:8000/docs](http://localhost:8000/do
Dash is running locally.
+## How it works
+
+Dash runs as an Agno team in coordinate mode, with a leader that routes each request to two specialists:
+
+| Agent | Role |
+|-------|------|
+| **Analyst** | Reads company data (read-only), generates SQL, interprets results |
+| **Engineer** | Builds reusable views and summary tables in the `dash` schema |
+| **Leader** | Routes queries, coordinates the team, posts to Slack |
+
+**Schema boundaries:** Company data lives in the `public` schema; agent-created views and summary tables live in the `dash` schema. The Analyst connects with `default_transaction_read_only=on`, so PostgreSQL rejects its writes. The Engineer is instructed to write only to `dash`, and a SQLAlchemy event listener rejects DDL and DML that explicitly targets `public`. PostgreSQL enforces the Analyst boundary. The Engineer boundary depends on the application listener and model instructions.
+
+### Six layers of context
+
+| Layer | Purpose | Source |
+|-------|---------|--------|
+| **Table Usage** | Schema, columns, relationships | `knowledge/tables/*.json` |
+| **Human Annotations** | Metrics, definitions, business rules | `knowledge/business/*.json` |
+| **Query Patterns** | SQL that is known to work | `knowledge/queries/*.sql` |
+| **Institutional Knowledge** | Docs, wikis, external references | MCP (optional) |
+| **Learnings** | Error patterns and discovered fixes | Agno `Learning Machine` |
+| **Runtime Context** | Live schema changes | `introspect_schema` tool |
+
+### Self-learning
+
+The Analyst searches knowledge and learnings before generating SQL. Its workflow tells it to inspect the live schema after an error and call `save_learning` after discovering a reusable fix. Agno's Learning Machine makes those saved fixes available to later runs.
+
+| System | Stores | How it evolves |
+|--------|--------|----------------|
+| **Knowledge** | Validated queries, table schemas, business rules | Curated by you; Dash can propose reusable queries |
+| **Learnings** | Error patterns and discovered fixes | Saved by the agents through the Learning Machine |
+
+When a churn query filters on `status` and should use `ended_at IS NULL`, Dash can save that correction for later runs to retrieve. When your team defines MRR as the sum of active subscriptions excluding trials, the rule lives in `knowledge/business/` alongside the queries that use it.
+
## Deploy to Railway
Railway deployment uses `.env.production` to keep production credentials separate from local dev.
diff --git a/deploy/templates/docker/deploy.mdx b/deploy/templates/docker/deploy.mdx
index 554f8ccd0..c355a646d 100644
--- a/deploy/templates/docker/deploy.mdx
+++ b/deploy/templates/docker/deploy.mdx
@@ -4,11 +4,11 @@ sidebarTitle: "Deploy"
description: "Run AgentOS locally using Docker and deploy to production on self-hosted Docker."
---
-The [agentos-docker](https://github.com/agno-agi/agentos-docker) template runs AgentOS locally and in production with Docker Compose. It includes:
+Choose self-hosted Docker when you want the same Compose stack locally and in production on infrastructure you control. The [agentos-docker](https://github.com/agno-agi/agentos-docker) template runs AgentOS and PostgreSQL with Docker Compose.
- **Agent Builder**, which creates agents, teams, and workflows when prompted.
- **Platform Manager**, which inspects and explains registered agents, eval history, deployment checks, and schedules.
-- **Five [skills](/deploy/templates/improve-agents)** that coding agents can invoke to build, test, and improve the project.
+- **Six [skills](/deploy/templates/improve-agents)**. `setup-platform` configures the local platform. Five lifecycle skills create, extend, improve, evaluate, and review it.
Agent code, evals, traces, and logs stay in one project so users and coding agents can inspect them together.
@@ -16,7 +16,7 @@ Production uses the local Docker Compose configuration plus one override file on
## Get started
-Copy the prompt below into Claude Code, Cursor, or Codex to configure and run the template with a coding agent.
+Copy the prompt below into Claude Code, Cursor, or Codex to clone the template, start AgentOS locally, and build your first agent.
@@ -153,10 +153,12 @@ For claude.ai and ChatGPT on the web: add `https:///mcp` as a c
```bash
-curl https:///health # 200: /health and /docs stay public
-curl https:///agents # 401: everything else wants a token
+curl -o /dev/null -w '%{http_code}\n' "https:///health" # 200
+curl -o /dev/null -w '%{http_code}\n' "https:///agents" # 401
```
+`/health` and `/docs` remain public. Protected AgentOS routes such as `/agents` require a valid token.
+
Logs, when something looks off:
```bash
diff --git a/deploy/templates/docker/reference.mdx b/deploy/templates/docker/reference.mdx
index 7c86ff375..2cd2bcfaa 100644
--- a/deploy/templates/docker/reference.mdx
+++ b/deploy/templates/docker/reference.mdx
@@ -18,17 +18,17 @@ The Compose services are `agentos-api` (the app) and `agentos-db` (Postgres with
## Production auth
-Token-Based Authorization is on by default. Production startup requires `JWT_VERIFICATION_KEY` or a readable JWKS file at the container path in `JWT_JWKS_FILE`; otherwise the process exits.
+Token-Based Authorization protects AgentOS routes by default in production. Startup requires `JWT_VERIFICATION_KEY` or a readable JWKS file at the container path in `JWT_JWKS_FILE`; otherwise the process exits.
Token-Based Auth gives you three things:
-1. **No public access.** The server rejects requests without a valid token.
+1. **Protected API access.** Requests to protected AgentOS routes require a valid token. `/`, `/health`, `/info`, `/docs`, `/redoc`, `/openapi.json`, and `/docs/oauth2-redirect` remain public.
2. **Per-request identity.** Middleware validates the token and exposes its `user_id`, optional `session_id`, scopes, and claims to the request.
3. **Scope-based permissions.** Token scopes control access to AgentOS routes and resources.
The templates do not enable per-user data isolation. To scope non-admin session, memory, trace, and run access to the JWT subject, pass `authorization_config=AuthorizationConfig(user_isolation=True)` to `AgentOS`. See [User Isolation](/agent-os/security/authorization/user-isolation).
-To opt out (not recommended), set `authorization=False` in `app/main.py` and restart. Use this only inside a private network behind another auth layer. Without it, anyone who finds your public URL can access your platform.
+To disable JWT authentication, set `authorization=False` in `app/main.py`, remove `JWT_VERIFICATION_KEY` and `JWT_JWKS_FILE` from the production env file, and recreate the container. `authorization=False` disables AgentOS scope enforcement. Configured JWT environment variables continue to enable JWT validation. MCP OAuth remains active when `MCP_CONNECT_SECRET` is set. Only do this when another layer protects the service.
## Customize
@@ -83,7 +83,7 @@ def default_model():
return Claude(id="claude-sonnet-5")
```
-Add `anthropic` to `pyproject.toml`, set the provider key in your env, and regenerate pins:
+Add `anthropic` to `pyproject.toml`, set `ANTHROPIC_API_KEY` in `.env`, and regenerate pins:
```bash
./scripts/generate_requirements.sh
@@ -153,7 +153,7 @@ source .venv/bin/activate
| Variable | Required | Default | Description |
|----------|----------|---------|-------------|
| `OPENAI_API_KEY` | Yes | - | Models and embeddings. |
-| `RUNTIME_ENV` | No | `prd` | `dev` disables JWT. `compose.yaml` sets `dev` for local; `compose.prod.yaml` sets `prd`. Never hand-set `dev` on a production host, or the platform serves unauthenticated. |
+| `RUNTIME_ENV` | No | `prd` | `dev` sets `authorization=False`, which disables AgentOS scope enforcement. Configured JWT environment variables continue to enable JWT validation. `compose.yaml` sets `dev` locally; `compose.prod.yaml` sets `prd`. |
| `JWT_VERIFICATION_KEY` | Production | - | Public key from os.agno.com. Quote the value so the multi-line PEM parses as one variable. |
| `JWT_JWKS_FILE` | Production | - | Path inside the container to a JWKS file. Production Compose does not mount this file. Add a read-only bind mount, or bake the file into the image and rebuild. |
| `MCP_CONNECT_SECRET` | No | - | OAuth consent secret (16+ chars) for connecting claude.ai and ChatGPT to `/mcp`. Set it yourself in `.env`, e.g. `openssl rand -base64 32`. Dev reads the same file, so it gates the local `/mcp` too. |
@@ -182,7 +182,7 @@ The first build takes a few minutes. Read `docker compose logs agentos-api` and
The production override uses Compose merge tags that need Docker Compose v2.24.4 or newer. Upgrade Docker Compose and rerun.
-JWT auth is on whenever `RUNTIME_ENV` is not `dev`. Set `JWT_VERIFICATION_KEY` in `.env` and recreate the container. For `JWT_JWKS_FILE`, first add a read-only production bind mount and point the variable at its container path, or bake the file into the image and recreate with `--build`. To opt out inside a private network behind another auth layer, set `authorization=False` in `app/main.py`.
+AgentOS scope enforcement is on whenever `RUNTIME_ENV` is not `dev`. Set `JWT_VERIFICATION_KEY` in `.env` and recreate the container. For `JWT_JWKS_FILE`, first add a read-only production bind mount and point the variable at its container path, or bake the file into the image and recreate with `--build`. To disable JWT, set `authorization=False` in `app/main.py`, remove both JWT variables from the production env file, and recreate the container. MCP OAuth remains active when `MCP_CONNECT_SECRET` is set.
Postgres reads the password only when the `pgdata` volume is first initialized. On a host that already ran the dev Compose, the database keeps the old password and the API blocks waiting for it. Change the password in place and set `.env` to match:
diff --git a/deploy/templates/fly/deploy.mdx b/deploy/templates/fly/deploy.mdx
index e3ad11a71..66ab4f269 100644
--- a/deploy/templates/fly/deploy.mdx
+++ b/deploy/templates/fly/deploy.mdx
@@ -4,16 +4,17 @@ sidebarTitle: "Deploy"
description: "Run AgentOS locally using Docker and deploy to production on Fly.io."
---
-AgentOS is a secure, scalable platform for running agents. The [agentos-fly](https://github.com/agno-agi/agentos-fly) codebase runs AgentOS locally using Docker and deploys to production on Fly.io. It comes with:
+Choose Fly.io when you want an always-on AgentOS Machine and PostgreSQL on Fly's private network. The [agentos-fly](https://github.com/agno-agi/agentos-fly) template uses Docker locally and provisions both Fly apps for production.
-- **2 platform agents** that build and run the platform for you. **Agent Builder** creates agents, teams, and workflows. **Platform Manager** understands, monitors, and explains the platform.
-- **5 [skills](/deploy/templates/improve-agents)** that let coding agents build, test, and improve the platform for you.
+- **Agent Builder**, which creates agents, teams, and workflows when prompted.
+- **Platform Manager**, which inspects registered agents, eval history, deployment checks, and schedules.
+- **Six [skills](/deploy/templates/improve-agents)**. `setup-platform` configures the local platform. Five lifecycle skills create, extend, improve, evaluate, and review it.
-Because the trace data, agent code, evals, and system logs all live in one place, the platform can inspect and improve itself automatically.
+Coding agents can use the repository skills, live AgentOS API, evals, and container logs to inspect and improve the platform.
## Get started
-The fastest way to get started is using a coding agent. Copy the prompt below into Claude Code, Cursor or Codex and it'll take you from zero to a running platform.
+Copy the prompt below into Claude Code, Cursor, or Codex to clone the template, start AgentOS locally, and build your first agent.
@@ -95,9 +96,9 @@ Edit `.env.production` with production values: a different OpenAI key, productio
Provisions the app and an unmanaged Fly Postgres on the same private network, pushes your credentials as Fly secrets, and deploys a single always-on machine. Fly app names are global, so the script generates `agentos-` and records it in `fly.toml`. It also sets `AGENTOS_URL` to `https://.fly.dev` before the first deploy so scheduled jobs reach the platform, and generates `MCP_CONNECT_SECRET`, the OAuth consent secret for chat apps, into `.env.production` when it's missing.
-Deploys use `fly deploy --ha=false` on purpose: the Fly default creates two machines, which doubles cost and runs two in-process schedulers double-firing every cron. Default sizing is `shared-cpu-2x` with 4 GB (~$21/mo) plus a small Postgres machine (~$4/mo). For dedicated cores, switch the size to `performance-2x` (~$62/mo) in `fly.toml`.
+Deploys use `fly deploy --ha=false` because the Fly default creates two machines and doubles the application cost. The template has been validated with one always-on machine. Default sizing is `shared-cpu-2x` with 4 GB (~$21/mo) plus a small Postgres machine (~$4/mo). For dedicated cores, switch the size to `performance-2x` (~$62/mo) in `fly.toml`.
-Fly's stock `postgres-flex` image does not ship pgvector: sessions and memory work out of the box, but knowledge bases (RAG) need the extension. Set `FLY_PG_IMAGE` to a `postgres-flex` derivative with pgvector installed before running `up.sh`. Without it, the script prints a warning and everything except knowledge bases works. See [Enable pgvector](/deploy/templates/fly/reference#customize).
+Fly's stock `postgres-flex` image supports sessions and memory. Knowledge bases require a pgvector-enabled derivative. Set `FLY_PG_IMAGE` before running `up.sh`. The script warns when the stock image is selected. See [Enable pgvector](/deploy/templates/fly/reference#customize).
@@ -124,10 +125,13 @@ For claude.ai and ChatGPT on the web: add `https://.fly.dev/mcp` as a custo
```bash
+curl -o /dev/null -w '%{http_code}\n' "https://.fly.dev/health" # 200
+curl -o /dev/null -w '%{http_code}\n' "https://.fly.dev/agents" # 401
+
fly logs
```
-The app name comes from `fly.toml`, so no `--app` flag is needed. Open `https://.fly.dev/docs` to confirm the API is serving.
+The app name comes from `fly.toml`, so no `--app` flag is needed. `/health` and `/docs` remain public. Protected AgentOS routes such as `/agents` require a valid token.
diff --git a/deploy/templates/fly/reference.mdx b/deploy/templates/fly/reference.mdx
index d57c4a8b4..15c58e3fd 100644
--- a/deploy/templates/fly/reference.mdx
+++ b/deploy/templates/fly/reference.mdx
@@ -4,7 +4,7 @@ sidebarTitle: "Reference"
description: "Commands, customization, environment variables, and troubleshooting for the Fly.io template."
---
-Fly app names are global, so `up.sh` generates a unique name (`agentos-`), records it in `fly.toml`, and pairs it with a Postgres app named `-db`. Later `fly` commands read the app name from `fly.toml`, so no `--app` flag is needed.
+Fly app names are global, so `up.sh` generates a unique name (`agentos-`), records it in `fly.toml`, and pairs it with a Postgres app named `-db`. Later `fly` commands read the app name from `fly.toml`, so no `--app` flag is needed. Start with [Deploy AgentOS on Fly.io](/deploy/templates/fly/deploy) for prerequisites and the first deployment.
## Manage
@@ -16,21 +16,21 @@ Fly app names are global, so `up.sh` generates a unique name (`agentos-`
| Resize the machine | Edit `[[vm]]` in `fly.toml`, then `./scripts/fly/redeploy.sh` |
| Tear down | `./scripts/fly/down.sh` (add `--yes` to skip the confirmation) |
-The platform runs one machine by design. Both deploy scripts pass `fly deploy --ha=false` because the Fly default creates two machines, which doubles cost and runs two in-process schedulers double-firing every cron. `fly.toml` keeps the machine warm with `auto_stop_machines = "off"` and `min_machines_running = 1`; with scale-to-zero, scheduled jobs silently stop firing.
+The platform runs one machine by default. Both deploy scripts pass `fly deploy --ha=false` because Fly otherwise creates two machines and doubles the application cost. `fly.toml` keeps the machine warm with `auto_stop_machines = "off"` and `min_machines_running = 1`; scheduled jobs stop when no machine is running. Validate schedule registration and MCP streams before adding machines.
## Production auth
-Token-Based Authorization is on by default. Production startup requires `JWT_VERIFICATION_KEY` or a readable JWKS file at the container path in `JWT_JWKS_FILE`; otherwise the process exits.
+Token-Based Authorization protects AgentOS routes by default in production. Startup requires `JWT_VERIFICATION_KEY` or a readable JWKS file at the container path in `JWT_JWKS_FILE`; otherwise the process exits.
Token-Based Auth gives you three things:
-1. **No public access.** The server rejects requests without a valid token.
+1. **Protected API access.** Requests to protected AgentOS routes require a valid token. `/`, `/health`, `/info`, `/docs`, `/redoc`, `/openapi.json`, and `/docs/oauth2-redirect` remain public.
2. **Per-request identity.** Middleware validates the token and exposes its `user_id`, optional `session_id`, scopes, and claims to the request.
3. **Scope-based permissions.** Token scopes control access to AgentOS routes and resources.
The templates do not enable per-user data isolation. To scope non-admin session, memory, trace, and run access to the JWT subject, pass `authorization_config=AuthorizationConfig(user_isolation=True)` to `AgentOS`. See [User Isolation](/agent-os/security/authorization/user-isolation).
-To opt out (not recommended), set `authorization=False` in `app/main.py` and redeploy. Use this only inside a private network behind another auth layer. Without it, anyone who guesses your Fly URL can access your platform.
+To disable JWT authentication, set `authorization=False` in `app/main.py`, remove `JWT_VERIFICATION_KEY` and `JWT_JWKS_FILE` from the Fly secrets, and redeploy. `authorization=False` disables AgentOS scope enforcement. Configured JWT environment variables continue to enable JWT validation. MCP OAuth remains active when `MCP_CONNECT_SECRET` is set. Only do this when another layer protects the service.
## Customize
@@ -85,7 +85,7 @@ def default_model():
return Claude(id="claude-sonnet-5")
```
-Add `anthropic` to `pyproject.toml`, set the provider key in your env, and regenerate pins:
+Add `anthropic` to `pyproject.toml`. Set `ANTHROPIC_API_KEY` in `.env` for local runs and `.env.production` for production, then regenerate pins:
```bash
./scripts/generate_requirements.sh
@@ -134,14 +134,25 @@ The deployment check runs daily by default (`ENABLE_DEPLOY_CHECK=True`); it is d
-Fly's stock `postgres-flex` image does not ship pgvector, so sessions and memory work but knowledge bases (RAG) fail at `CREATE EXTENSION` time. The fix is a two-line Dockerfile:
+Fly's stock `postgres-flex` image supports sessions and memory. Knowledge bases fail at `CREATE EXTENSION` until the database image includes pgvector. Build a derivative and publish it to a registry Fly can pull from. The commands below use a public Docker Hub repository:
-```dockerfile
+```bash
+mkdir -p postgres-pgvector
+cat > postgres-pgvector/Dockerfile <<'EOF'
FROM flyio/postgres-flex:17
RUN apt-get install -y postgresql-17-pgvector
+EOF
+
+docker login
+export PG_IMAGE="/agentos-postgres-pgvector:17"
+docker buildx build --platform linux/amd64 --push \
+ -t "$PG_IMAGE" postgres-pgvector
+
+export FLY_PG_IMAGE="$PG_IMAGE"
+./scripts/fly/up.sh
```
-Set `FLY_PG_IMAGE` to that image before running `./scripts/fly/up.sh`. The image applies when the Postgres cluster is created; `up.sh` reuses an existing cluster, so switching later means tearing down with `./scripts/fly/down.sh` and provisioning fresh.
+`FLY_PG_IMAGE` applies when the Postgres cluster is created. `up.sh` reuses an existing cluster, so switching later requires `./scripts/fly/down.sh`, which deletes the app, database, and all stored data. Then export `FLY_PG_IMAGE` and provision again.
@@ -167,7 +178,7 @@ source .venv/bin/activate
| Variable | Required | Default | Description |
|----------|----------|---------|-------------|
| `OPENAI_API_KEY` | Yes | - | Models and embeddings. |
-| `RUNTIME_ENV` | No | `prd` | `dev` disables JWT. Compose sets it for local. Never put it in an env file that syncs to Fly, or production deploys unauthenticated. |
+| `RUNTIME_ENV` | No | `prd` | `dev` sets `authorization=False`, which disables AgentOS scope enforcement. Configured JWT environment variables continue to enable JWT validation. Compose sets `dev` locally; keep `prd` on Fly. |
| `JWT_VERIFICATION_KEY` | Production | - | Public key from os.agno.com. Quote the value so the multi-line PEM parses as one variable. |
| `JWT_JWKS_FILE` | Production | - | Path inside the Fly Machine to a JWKS file. The Fly scripts sync only this path. Bake the file into the image or configure a Fly mount before deploying. |
| `MCP_CONNECT_SECRET` | No | generated by `up.sh` | OAuth consent secret (16+ chars) for connecting claude.ai and ChatGPT to `/mcp`. `up.sh` generates one on deploy and writes it to `.env.production`. |
@@ -207,7 +218,7 @@ Expected. Mint the key at [os.agno.com](https://os.agno.com): connect your OS (*
The script only manages names it generated. A different name means continuing would overwrite `fly.toml` and abandon that app. Restore the `agentos` placeholder (or an `agentos-*` name from a previous run), or tear down first with `./scripts/fly/down.sh`.
-JWT auth is on whenever `RUNTIME_ENV` is not `dev`. Set `JWT_VERIFICATION_KEY` and sync. To use `JWT_JWKS_FILE`, first bake or mount a readable JWKS file at that container path, then sync the variable. `env-sync.sh` does not upload the file. To opt out inside a private network behind another auth layer, set `authorization=False` in `app/main.py`.
+AgentOS scope enforcement is on whenever `RUNTIME_ENV` is not `dev`. Set `JWT_VERIFICATION_KEY` and sync. To use `JWT_JWKS_FILE`, first bake or mount a readable JWKS file at that container path, then sync the variable. `env-sync.sh` does not upload the file. To disable JWT, set `authorization=False` in `app/main.py`, remove both JWT variables from the Fly secrets, and redeploy. MCP OAuth remains active when `MCP_CONNECT_SECRET` is set.
The stock `postgres-flex` image has no pgvector; sessions and memory are unaffected. Set `FLY_PG_IMAGE` to a pgvector-enabled image and recreate the cluster. `up.sh` reuses an existing cluster, so tear down first with `./scripts/fly/down.sh`. See [Enable pgvector for knowledge bases](#customize).
@@ -215,7 +226,7 @@ The stock `postgres-flex` image has no pgvector; sessions and memory are unaffec
`AGENTOS_URL` may still be the localhost default. `up.sh` sets it to `https://.fly.dev` automatically; for a custom domain or tunnel, set it by hand and run `./scripts/fly/env-sync.sh`. Re-running `up.sh` resets a hand-set value to the generated fly.dev URL, so re-pin it afterwards. The other cause is the machine scaling to zero: keep `auto_stop_machines = "off"` and `min_machines_running = 1` in `fly.toml`.
-
-A plain `fly deploy` created a second machine, and each runs its own scheduler. Deploy with the scripts; they pass `--ha=false`.
+
+A plain `fly deploy` enables Fly's default HA topology. Deploy with the scripts to keep one machine; they pass `--ha=false`. AgentOS claims due schedules through PostgreSQL. This template has not been validated for simultaneous schedule registration and MCP streams across multiple machines.
diff --git a/deploy/templates/gcp/deploy.mdx b/deploy/templates/gcp/deploy.mdx
index c9a412678..e306738c7 100644
--- a/deploy/templates/gcp/deploy.mdx
+++ b/deploy/templates/gcp/deploy.mdx
@@ -4,18 +4,19 @@ sidebarTitle: "Deploy"
description: "Run AgentOS locally using Docker and deploy to production on Google Cloud Run."
---
-AgentOS is a secure, scalable platform for running agents. The [agentos-gcp](https://github.com/agno-agi/agentos-gcp) codebase runs AgentOS locally using Docker and deploys to production on Google Cloud Run. It comes with:
+Choose Google Cloud when your team wants the AgentOS service and persisted platform data in its own GCP project. The [agentos-gcp](https://github.com/agno-agi/agentos-gcp) template uses Docker locally and deploys Cloud Run with a private Cloud SQL database for production.
-- **2 platform agents** that build and run the platform for you. **Agent Builder** creates agents, teams, and workflows. **Platform Manager** understands, monitors, and explains the platform.
-- **5 [skills](/deploy/templates/improve-agents)** that let coding agents build, test, and improve the platform for you.
+- **Agent Builder**, which creates agents, teams, and workflows when prompted.
+- **Platform Manager**, which inspects registered agents, eval history, deployment checks, and schedules.
+- **Six [skills](/deploy/templates/improve-agents)**. `setup-platform` configures the local platform. Five lifecycle skills create, extend, improve, evaluate, and review it.
-Because the trace data, agent code, evals, and system logs all live in one place, the platform can inspect and improve itself automatically.
+Coding agents can use the repository skills, live AgentOS API, evals, and container logs to inspect and improve the platform.
-Everything runs in your own Google Cloud project: Cloud Run serves the platform and Cloud SQL holds your data.
+Cloud Run, Cloud SQL, Artifact Registry, and deployment secrets live in your GCP project. Model calls and optional interfaces use the providers you configure.
## Get started
-The fastest way to get started is using a coding agent. Copy the prompt below into Claude Code, Cursor or Codex and it'll take you from zero to a running platform.
+Copy the prompt below into Claude Code, Cursor, or Codex to clone the template, start AgentOS locally, and build your first agent.
@@ -97,7 +98,7 @@ Edit `.env.production` with production values: a different OpenAI key, productio
Enables the required APIs, creates an Artifact Registry repo and pushes a locally-built image to it, provisions Cloud SQL Postgres on a private IP, stores your keys in Secret Manager, and deploys the `agent-os` Cloud Run service. The first run takes 15-20 minutes: the one-time VPC peering is about 5 minutes and the Cloud SQL instance another 5-10. Once the service URL exists, the script sets `AGENTOS_URL` to it in a second revision so scheduled jobs reach the platform, and generates `MCP_CONNECT_SECRET`, the OAuth consent secret for chat apps, into `.env.production`.
-Always-on Cloud Run at this template's sizing (2 vCPU / 4 GiB, min 1 instance, no CPU throttling) is ≈$110/mo list price. The budget knob is 1 vCPU / 2 GiB at ≈$58/mo: edit the `--cpu`/`--memory` flags in `scripts/gcp/up.sh`. Cloud SQL `db-g1-small` adds ≈$25-35/mo.
+One always-on Cloud Run instance at this template's sizing (2 vCPU / 4 GiB, min 1 instance, no CPU throttling) is ≈$110/mo list price. The budget knob is 1 vCPU / 2 GiB at ≈$58/mo: edit the `--cpu`/`--memory` flags in `scripts/gcp/up.sh`. Cloud SQL `db-g1-small` adds ≈$25-35/mo. The template does not set a maximum instance count, so Cloud Run can add instances under load. Add `--max-instances 1` until you have validated schedule registration and MCP streams under scale-out.
@@ -124,10 +125,15 @@ For claude.ai and ChatGPT on the web: add `https:///mcp` as a cus
```bash
-gcloud run services logs read agent-os --region us-central1 --limit 100
+gcloud run services logs read agent-os \
+ --project "${GCP_PROJECT_ID:-$(gcloud config get-value project)}" \
+ --region "${GCP_REGION:-us-central1}" --limit 100
+
+curl -o /dev/null -w '%{http_code}\n' "https:///health" # 200
+curl -o /dev/null -w '%{http_code}\n' "https:///agents" # 401
```
-Open `https:///docs` to confirm the API is serving.
+`/health` and `/docs` remain public. Protected AgentOS routes such as `/agents` require a valid token.
diff --git a/deploy/templates/gcp/reference.mdx b/deploy/templates/gcp/reference.mdx
index 5bc381857..7672b33f2 100644
--- a/deploy/templates/gcp/reference.mdx
+++ b/deploy/templates/gcp/reference.mdx
@@ -4,7 +4,7 @@ sidebarTitle: "Reference"
description: "Commands, customization, environment variables, and troubleshooting for the Google Cloud Run template."
---
-The Cloud Run service is `agent-os`, the Cloud SQL instance is `agentos-db`, and the Artifact Registry repo is `agentos`. The scripts target the current gcloud project and `us-central1`; override them with `GCP_PROJECT_ID` and `GCP_REGION`.
+The Cloud Run service is `agent-os`, the Cloud SQL instance is `agentos-db`, and the Artifact Registry repo is `agentos`. The scripts target the current gcloud project and `us-central1`; override them with `GCP_PROJECT_ID` and `GCP_REGION`. Start with [Deploy AgentOS on Google Cloud](/deploy/templates/gcp/deploy) for prerequisites and the first deployment. Export overrides before running direct `gcloud` commands; the template scripts also read them from the selected env file.
## Manage
@@ -12,23 +12,25 @@ The Cloud Run service is `agent-os`, the Cloud SQL instance is `agentos-db`, and
|------|---------|
| Deploy code changes | `./scripts/gcp/redeploy.sh` |
| Sync env variables | `./scripts/gcp/env-sync.sh` (defaults to `.env.production`; pass `.env` to sync that instead) |
-| Tail logs | `gcloud run services logs read agent-os --region us-central1 --limit 100` |
+| Tail logs | `gcloud run services logs read agent-os --project "${GCP_PROJECT_ID:-$(gcloud config get-value project)}" --region "${GCP_REGION:-us-central1}" --limit 100` |
| Resize the service | Edit the `--cpu`/`--memory` flags in `scripts/gcp/up.sh` and rerun it |
| Tear down | `./scripts/gcp/down.sh` (add `--yes` to skip the confirmation) |
+`up.sh` sets one minimum instance and no maximum. Cloud Run can add instances under load. AgentOS claims due schedules through PostgreSQL. Simultaneous schedule registration and long-lived MCP streams still need validation. Add `--max-instances 1` to the Cloud Run deploy command when you need a single-process topology.
+
## Production auth
-Token-Based Authorization is on by default. Production startup requires `JWT_VERIFICATION_KEY` or a readable JWKS file at the container path in `JWT_JWKS_FILE`; otherwise the process exits.
+Token-Based Authorization protects AgentOS routes by default in production. Startup requires `JWT_VERIFICATION_KEY` or a readable JWKS file at the container path in `JWT_JWKS_FILE`; otherwise the process exits.
Token-Based Auth gives you three things:
-1. **No public access.** The server rejects requests without a valid token.
+1. **Protected API access.** Requests to protected AgentOS routes require a valid token. `/`, `/health`, `/info`, `/docs`, `/redoc`, `/openapi.json`, and `/docs/oauth2-redirect` remain public.
2. **Per-request identity.** Middleware validates the token and exposes its `user_id`, optional `session_id`, scopes, and claims to the request.
3. **Scope-based permissions.** Token scopes control access to AgentOS routes and resources.
The templates do not enable per-user data isolation. To scope non-admin session, memory, trace, and run access to the JWT subject, pass `authorization_config=AuthorizationConfig(user_isolation=True)` to `AgentOS`. See [User Isolation](/agent-os/security/authorization/user-isolation).
-To opt out (not recommended), set `authorization=False` in `app/main.py` and redeploy. Use this only inside a private VPC behind another auth layer. Without it, anyone who guesses your Cloud Run URL can access your platform.
+To disable JWT authentication, set `authorization=False` in `app/main.py`, remove `JWT_VERIFICATION_KEY` and `JWT_JWKS_FILE` from the Cloud Run service, and redeploy. `authorization=False` disables AgentOS scope enforcement. Configured JWT environment variables continue to enable JWT validation. MCP OAuth remains active when `MCP_CONNECT_SECRET` is set. Only do this when another layer protects the service.
## Customize
@@ -83,13 +85,13 @@ def default_model():
return Claude(id="claude-sonnet-5")
```
-Add `anthropic` to `pyproject.toml`, set the provider key in your env, and regenerate pins:
+Add `anthropic` to `pyproject.toml`. Set `ANTHROPIC_API_KEY` in `.env` for local runs and `.env.production` for production, then regenerate pins:
```bash
./scripts/generate_requirements.sh
```
-Rebuild locally with `docker compose up -d --build`. For production:
+Before production sync, add `ANTHROPIC_API_KEY` to the `is_secret_key()` allowlist in `scripts/gcp/env-sync.sh`. This stores the key in Secret Manager. Then rebuild and deploy:
```bash
./scripts/gcp/env-sync.sh
@@ -154,7 +156,7 @@ source .venv/bin/activate
| Variable | Required | Default | Description |
|----------|----------|---------|-------------|
| `OPENAI_API_KEY` | Yes | - | Models and embeddings. |
-| `RUNTIME_ENV` | No | `prd` | `dev` disables JWT. Compose sets it for local. Never put it in an env file that syncs to Cloud Run, or production deploys unauthenticated. |
+| `RUNTIME_ENV` | No | `prd` | `dev` sets `authorization=False`, which disables AgentOS scope enforcement. Configured JWT environment variables continue to enable JWT validation. Compose sets `dev` locally; keep `prd` on Cloud Run. |
| `JWT_VERIFICATION_KEY` | Production | - | Public key from os.agno.com. Quote the value so the multi-line PEM parses as one variable. |
| `JWT_JWKS_FILE` | Production | - | Path to a JWKS file inside the container. The scripts set only this environment variable. Add the file to the image build context, rebuild, and redeploy the image, or configure a mount and roll the service. |
| `MCP_CONNECT_SECRET` | No | generated by `up.sh` | OAuth consent secret (16+ chars) for connecting claude.ai and ChatGPT to `/mcp`. `up.sh` generates one on deploy and writes it to `.env.production`. |
@@ -172,7 +174,7 @@ source .venv/bin/activate
| `DB_HOST` / `DB_PORT` / `DB_USER` / `DB_PASS` / `DB_DATABASE` | No | matches compose | Postgres connection. |
| `DB_DRIVER` | No | `postgresql+psycopg` | SQLAlchemy driver. |
| `AGNO_DEBUG` | No | `False` | Verbose Agno logs. Compose sets it for dev. |
-| `WAIT_FOR_DB` | No | `False` | If `True`, the entrypoint blocks on the database before starting. Compose sets it. |
+| `WAIT_FOR_DB` | No | `False` | If `True`, the entrypoint blocks on the database before starting. Compose and the production deploy set it to `True`. |
## Troubleshooting
@@ -184,13 +186,13 @@ Install the [Google Cloud SDK](https://cloud.google.com/sdk/docs/install), then
Expected. The script deploys first because Cloud Run only reveals the URL once the service exists, then pauses so you can mint the key against it. Mint the key at [os.agno.com](https://os.agno.com): connect your OS (**Connect OS** → **Live**, enter your Cloud Run URL), then turn on **Token-Based Authorization (JWT)** under **Settings** → **OS & Security** and paste the full PEM. To add a PEM later, set `JWT_VERIFICATION_KEY` in `.env.production` and run `./scripts/gcp/env-sync.sh`. To use `JWT_JWKS_FILE`, add the file to the image build context and run `./scripts/gcp/redeploy.sh`, or configure a mount. Then add the container path to `.env.production` and run `./scripts/gcp/env-sync.sh`. The scripts do not upload or mount the file.
-JWT auth is on whenever `RUNTIME_ENV` is not `dev`. Set `JWT_VERIFICATION_KEY` and sync. For JWKS, add the file to the image build context and run `./scripts/gcp/redeploy.sh`, or configure a mount. Then set `JWT_JWKS_FILE` to its container path in `.env.production` and run `./scripts/gcp/env-sync.sh`. To opt out inside a private VPC behind another auth layer, set `authorization=False` in `app/main.py`.
+AgentOS scope enforcement is on whenever `RUNTIME_ENV` is not `dev`. Set `JWT_VERIFICATION_KEY` and sync. For JWKS, add the file to the image build context and run `./scripts/gcp/redeploy.sh`, or configure a mount. Then set `JWT_JWKS_FILE` to its container path in `.env.production` and run `./scripts/gcp/env-sync.sh`. To disable JWT, set `authorization=False` in `app/main.py`, remove both JWT variables from the Cloud Run service, and redeploy. MCP OAuth remains active when `MCP_CONNECT_SECRET` is set.
Your organization likely enforces Domain Restricted Sharing (`constraints/iam.allowedPolicyMemberDomains`), which silently rejects the `allUsers` binding that `--allow-unauthenticated` needs. The deploy still succeeds; the service just ships private. `up.sh` prints a warning when it detects this. Grant `roles/run.invoker` to specific principals, or ask an org admin for an `allUsers` exception.
-Check that billing is enabled on the project. `up.sh` warns when it can't confirm billing; Cloud SQL and Cloud Run creation both fail without it.
+Check that billing is enabled on the project. `up.sh` warns when it can't confirm billing. Cloud SQL and Cloud Run creation require billing.
`AGENTOS_URL` is still the localhost default. `up.sh` sets it to your Cloud Run URL automatically; for a custom domain or tunnel, set it by hand and run `./scripts/gcp/env-sync.sh`.
diff --git a/deploy/templates/helm/deploy.mdx b/deploy/templates/helm/deploy.mdx
index 75c0d6952..39ceb71ba 100644
--- a/deploy/templates/helm/deploy.mdx
+++ b/deploy/templates/helm/deploy.mdx
@@ -4,18 +4,19 @@ sidebarTitle: "Deploy"
description: "Run AgentOS locally using Docker and deploy to production on Kubernetes."
---
-AgentOS is a secure, scalable platform for running agents. The [agentos-helm](https://github.com/agno-agi/agentos-helm) codebase runs AgentOS locally using Docker and deploys to production on Kubernetes. It comes with:
+Choose Kubernetes when your platform team already operates a cluster and wants Helm-managed control over the image, ingress, and database topology. The [agentos-helm](https://github.com/agno-agi/agentos-helm) template uses Docker locally and deploys AgentOS through the Helm chart in `charts/agentos`.
-- **2 platform agents** that build and run the platform for you. **Agent Builder** creates agents, teams, and workflows. **Platform Manager** understands, monitors, and explains the platform.
-- **5 [skills](/deploy/templates/improve-agents)** that let coding agents build, test, and improve the platform for you.
+- **Agent Builder**, which creates agents, teams, and workflows when prompted.
+- **Platform Manager**, which inspects registered agents, eval history, deployment checks, and schedules.
+- **Six [skills](/deploy/templates/improve-agents)**. `setup-platform` configures the local platform. Five lifecycle skills create, extend, improve, evaluate, and review it.
-Because the trace data, agent code, evals, and system logs all live in one place, the platform can inspect and improve itself automatically.
+Coding agents can use the repository skills, live AgentOS API, evals, and container logs to inspect and improve the platform.
-The Helm chart in `charts/agentos` deploys to any Kubernetes cluster, cloud-managed (EKS, GKE, AKS) or your own.
+The chart runs one AgentOS replica by default and supports in-cluster or external PostgreSQL. It can run on managed clusters such as EKS, GKE, and AKS or on a cluster you operate.
## Get started
-The fastest way to get started is using a coding agent. Copy the prompt below into Claude Code, Cursor or Codex and it'll take you from zero to a running platform.
+Copy the prompt below into Claude Code, Cursor, or Codex to clone the template, start AgentOS locally, and build your first agent.
@@ -79,7 +80,7 @@ Prints `MCP OK` with the tool count and a real agent answer through the MCP endp
## Deploy to production
-**Prerequisites:** [kubectl](https://kubernetes.io/docs/tasks/tools/) pointed at your cluster, [Helm](https://helm.sh/docs/intro/install/) 3+, and a container registry the cluster can pull from.
+**Prerequisites:** [kubectl](https://kubernetes.io/docs/tasks/tools/) pointed at your cluster and [Helm](https://helm.sh/docs/intro/install/) 3+. The cluster must be able to pull the selected image. The default image is public; custom builds need a reachable registry.
@@ -107,7 +108,7 @@ Testing on a local [kind](https://kind.sigs.k8s.io) cluster instead? Run `docker
IMAGE_REPOSITORY=/agentos IMAGE_TAG=v1 ./scripts/k8s/up.sh # your own build
```
-Helm-installs the chart into the `agentos` namespace of your current kubectl context (the script shows the context and asks first): the API deployment at one replica by design, since the in-process scheduler must not run twice, plus in-cluster Postgres with pgvector and its volume. The script also generates a `DB_PASS` and saves it to your env file. Keep it; the Postgres volume reads the password only on first initialization.
+Helm installs the chart into the `agentos` namespace of your current kubectl context. The script shows the context and asks first. The default topology is one AgentOS replica plus in-cluster PostgreSQL with pgvector and a persistent volume. The script also generates a `DB_PASS` and saves it to your env file. Keep it; the Postgres volume reads the password only on first initialization.
To publish behind your ingress controller, add `INGRESS_HOST=os.example.com` (and optionally `INGRESS_CLASS=nginx`). `AGENTOS_URL` then points at that host; otherwise the scheduler uses the in-cluster service DNS, which works out of the box. When the deploy has a public URL (`INGRESS_HOST` or an explicit `AGENTOS_URL`), the script also generates `MCP_CONNECT_SECRET`, the OAuth consent secret for connecting chat apps, and saves it to your env file.
@@ -138,14 +139,33 @@ For claude.ai and ChatGPT on the web: add `https:///mcp` as
```bash
-kubectl rollout status deployment/agentos -n agentos
-kubectl logs deploy/agentos -n agentos -f
+AGENTOS_NAMESPACE="${AGENTOS_NAMESPACE:-agentos}"
+AGENTOS_RELEASE="${AGENTOS_RELEASE:-agentos}"
+AGENTOS_NAME="$AGENTOS_RELEASE"
+[[ "$AGENTOS_NAME" == *agentos* ]] || AGENTOS_NAME="${AGENTOS_NAME}-agentos"
+
+kubectl rollout status "deployment/$AGENTOS_NAME" -n "$AGENTOS_NAMESPACE"
+```
+
+With an ingress, verify the public health route and a protected route:
+
+```bash
+curl -o /dev/null -w '%{http_code}\n' "https:///health" # 200
+curl -o /dev/null -w '%{http_code}\n' "https:///agents" # 401
+```
+
+No ingress yet? Start a port-forward, keep it running, and run the same checks against `http://localhost:8000` from another terminal:
+
+```bash
+kubectl port-forward "svc/$AGENTOS_NAME" 8000:8000 -n "$AGENTOS_NAMESPACE"
```
-With an ingress, open `https:///docs` to confirm the API is serving. No ingress yet? Port-forward and open [localhost:8000/docs](http://localhost:8000/docs):
+`/health` and `/docs` remain public. Protected AgentOS routes such as `/agents` require a valid token.
+
+Tail logs when a check fails:
```bash
-kubectl port-forward svc/agentos 8000:8000 -n agentos
+kubectl logs "deployment/$AGENTOS_NAME" -n "$AGENTOS_NAMESPACE" -f
```
@@ -154,13 +174,19 @@ kubectl port-forward svc/agentos 8000:8000 -n agentos
### Redeploy after code changes
-Build and push a new tag, then roll the release to it:
+Build and push a new tag. If the release already uses your repository, roll it to the new tag:
```bash
docker build -t /agentos:v2 . && docker push /agentos:v2
IMAGE_TAG=v2 ./scripts/k8s/redeploy.sh
```
+Switch a release from the official image to your repository with both values:
+
+```bash
+IMAGE_REPOSITORY=/agentos IMAGE_TAG=v2 ./scripts/k8s/up.sh
+```
+
Immutable tags keep rollbacks one `helm rollback` away. Running `./scripts/k8s/redeploy.sh` without `IMAGE_TAG` restarts the pods in place; that only picks up a re-pushed tag if the new image actually reached the cluster.
### Sync environment variables
diff --git a/deploy/templates/helm/reference.mdx b/deploy/templates/helm/reference.mdx
index 7fb5476c7..a2e7003fb 100644
--- a/deploy/templates/helm/reference.mdx
+++ b/deploy/templates/helm/reference.mdx
@@ -4,33 +4,33 @@ sidebarTitle: "Reference"
description: "Commands, customization, environment variables, and troubleshooting for the Kubernetes template."
---
-The scripts install the Helm release `agentos` into the `agentos` namespace. Override with `AGENTOS_RELEASE` and `AGENTOS_NAMESPACE`.
+The scripts install the Helm release `agentos` into the `agentos` namespace. Override with `AGENTOS_RELEASE` and `AGENTOS_NAMESPACE`. Start with [Deploy AgentOS on Kubernetes](/deploy/templates/helm/deploy) for prerequisites and the first deployment.
## Manage
| Task | Command |
|------|---------|
-| Roll to a new image tag | `IMAGE_TAG=v2 ./scripts/k8s/redeploy.sh` (build and push the tag first) |
+| Roll to a new image tag | `IMAGE_TAG=v2 ./scripts/k8s/redeploy.sh` after the release points at your registry |
| Restart pods in place | `./scripts/k8s/redeploy.sh` |
| Sync supported env variables | `./scripts/k8s/env-sync.sh` (updates nonempty values from a fixed allowlist that includes `RUNTIME_ENV`; defaults to `.env.production`, or pass `.env`) |
-| Tail logs | `kubectl logs deploy/agentos -n agentos -f` |
-| Port-forward the API | `kubectl port-forward svc/agentos 8000:8000 -n agentos` |
-| Roll back a release | `helm rollback agentos -n agentos` |
+| Tail logs | Run the override-aware `kubectl logs` command printed by `up.sh` (default: `kubectl logs deploy/agentos -n agentos -f`) |
+| Port-forward the API | Run the override-aware command printed by `up.sh` (default: `kubectl port-forward svc/agentos 8000:8000 -n agentos`) |
+| Roll back a release | `helm rollback "${AGENTOS_RELEASE:-agentos}" -n "${AGENTOS_NAMESPACE:-agentos}"` |
| Tear down | `./scripts/k8s/down.sh` (add `--yes` to skip the confirmation) |
## Production auth
-Token-Based Authorization is on by default. Production startup requires `JWT_VERIFICATION_KEY` or a readable JWKS file at the pod path in `JWT_JWKS_FILE`; otherwise the process exits.
+Token-Based Authorization protects AgentOS routes by default in production. Startup requires `JWT_VERIFICATION_KEY` or a readable JWKS file at the pod path in `JWT_JWKS_FILE`; otherwise the process exits.
Token-Based Auth gives you three things:
-1. **No public access.** The server rejects requests without a valid token.
+1. **Protected API access.** Requests to protected AgentOS routes require a valid token. `/`, `/health`, `/info`, `/docs`, `/redoc`, `/openapi.json`, and `/docs/oauth2-redirect` remain public.
2. **Per-request identity.** Middleware validates the token and exposes its `user_id`, optional `session_id`, scopes, and claims to the request.
3. **Scope-based permissions.** Token scopes control access to AgentOS routes and resources.
The templates do not enable per-user data isolation. To scope non-admin session, memory, trace, and run access to the JWT subject, pass `authorization_config=AuthorizationConfig(user_isolation=True)` to `AgentOS`. See [User Isolation](/agent-os/security/authorization/user-isolation).
-To opt out (not recommended), set `authorization=False` in `app/main.py`, then build and push a new image tag and roll to it with `IMAGE_TAG= ./scripts/k8s/redeploy.sh`. Use this only inside a private VPC behind another auth layer. Without it, anyone who guesses your AgentOS URL can access your platform.
+To disable JWT authentication, set `authorization=False` in `app/main.py`, clear `secrets.jwtVerificationKey` and `jwtJwksFile` in the Helm release, then build and roll out the new image. `authorization=False` disables AgentOS scope enforcement. Configured JWT values continue to enable JWT validation. MCP OAuth remains active when `MCP_CONNECT_SECRET` is set. Only do this when another layer protects the service.
## Customize
@@ -85,20 +85,41 @@ def default_model():
return Claude(id="claude-sonnet-5")
```
-Add `anthropic` to `pyproject.toml`, set the provider key in your env, and regenerate pins:
+Add `anthropic` to `pyproject.toml`, set `ANTHROPIC_API_KEY` in `.env` for local runs, and regenerate pins:
```bash
./scripts/generate_requirements.sh
```
-Rebuild locally with `docker compose up -d --build`. For production, build and push a new tag, then roll to it:
+Rebuild locally with `docker compose up -d --build`. For production, export `ANTHROPIC_API_KEY`, build and push a new tag, create a Kubernetes Secret, and add it through `extraEnv` in a small values file:
```bash
docker build -t /agentos:v2 . && docker push /agentos:v2
-IMAGE_TAG=v2 ./scripts/k8s/redeploy.sh
+kubectl create secret generic agentos-anthropic \
+ --from-literal=ANTHROPIC_API_KEY="$ANTHROPIC_API_KEY" \
+ -n "${AGENTOS_NAMESPACE:-agentos}" \
+ --dry-run=client -o yaml | kubectl apply -f -
```
-`env-sync.sh` uses a fixed allowlist that includes `RUNTIME_ENV`, `AGENTOS_URL`, the `JWT_JWKS_FILE` path, the template's supported secrets, and `DB_PASS`. It does not deliver the referenced JWKS file or sync a new provider key such as `ANTHROPIC_API_KEY`. Provide the JWKS file through a custom image or chart volume. Deliver a new provider key via `extraEnv` and `helm upgrade`.
+```yaml anthropic-values.yaml
+image:
+ repository: /agentos
+ tag: v2
+extraEnv:
+ - name: ANTHROPIC_API_KEY
+ valueFrom:
+ secretKeyRef:
+ name: agentos-anthropic
+ key: ANTHROPIC_API_KEY
+```
+
+```bash
+helm upgrade "${AGENTOS_RELEASE:-agentos}" charts/agentos \
+ -n "${AGENTOS_NAMESPACE:-agentos}" --reuse-values \
+ -f anthropic-values.yaml
+```
+
+`env-sync.sh` does not deliver arbitrary provider keys or the referenced JWKS file. Provide new provider keys through a Kubernetes Secret as shown above. Provide a JWKS file through a custom image or chart volume.
@@ -160,7 +181,7 @@ source .venv/bin/activate
| Variable | Required | Default | Description |
|----------|----------|---------|-------------|
| `OPENAI_API_KEY` | Yes | - | Models and embeddings. |
-| `RUNTIME_ENV` | No | `prd` | `dev` disables JWT. Compose sets it for local. Never put it in an env file that syncs to a real cluster, or production deploys unauthenticated. |
+| `RUNTIME_ENV` | No | `prd` | `dev` sets `authorization=False`, which disables AgentOS scope enforcement. Configured JWT values continue to enable JWT validation. Compose sets `dev` locally; keep `prd` on a production cluster. |
| `JWT_VERIFICATION_KEY` | Production | - | Public key from os.agno.com. Quote the value so the multi-line PEM parses as one variable. |
| `JWT_JWKS_FILE` | Production | - | Path inside the pod to a JWKS file. `up.sh` and `env-sync.sh` set only the `jwtJwksFile` path. The current chart does not mount the file. |
| `MCP_CONNECT_SECRET` | No | - | OAuth consent secret (16+ chars) for connecting claude.ai and ChatGPT to `/mcp`. `up.sh` generates it into `.env.production` when the deploy has a public URL (`INGRESS_HOST` or `AGENTOS_URL`); set it by hand otherwise. |
@@ -199,7 +220,7 @@ Install [kubectl](https://kubernetes.io/docs/tasks/tools/) and [Helm](https://he
Expected. Mint the key at [os.agno.com](https://os.agno.com): connect your OS (**Connect OS** → **Live**, enter your AgentOS URL), then turn on **Token-Based Authorization (JWT)** under **Settings** → **OS & Security** and paste the full PEM. To add a PEM later, set `JWT_VERIFICATION_KEY` and run `./scripts/k8s/env-sync.sh`. To use JWKS, first provide the file through a custom image or chart volume, then set `JWT_JWKS_FILE` to its pod path and sync.
-JWT auth is on whenever `RUNTIME_ENV` is not `dev`. Set `JWT_VERIFICATION_KEY` and sync. `JWT_JWKS_FILE` works only when a custom image or chart mount already provides a readable file at that pod path. To opt out inside a private VPC behind another auth layer, set `authorization=False` in `app/main.py` and roll out your own image build.
+AgentOS scope enforcement is on whenever `RUNTIME_ENV` is not `dev`. Set `JWT_VERIFICATION_KEY` and sync. `JWT_JWKS_FILE` works only when a custom image or chart mount already provides a readable file at that pod path. To disable JWT, set `authorization=False` in `app/main.py`, clear `secrets.jwtVerificationKey` and `jwtJwksFile` in the Helm release, and roll out your image. MCP OAuth remains active when `MCP_CONNECT_SECRET` is set.
The cluster can't pull the image. Confirm the tag was pushed and the cluster has access to your registry; for private registries, set `imagePullSecrets` in `charts/agentos/values.yaml`. On kind, `kind load docker-image` the tag and deploy with `IMAGE_PULL_POLICY=Never`.
diff --git a/deploy/templates/improve-agents.mdx b/deploy/templates/improve-agents.mdx
index c89d84e88..e14611aec 100644
--- a/deploy/templates/improve-agents.mdx
+++ b/deploy/templates/improve-agents.mdx
@@ -1,49 +1,67 @@
---
title: "Build with Coding Agents"
sidebarTitle: "Coding Agents"
-description: "Bundled skills that let Claude Code, Codex, and Cursor create, improve, evaluate, and maintain your agents."
+description: "Use bundled skills to set up, build, evaluate, and maintain agents inside an AgentOS Starter."
---
-Every template is designed for coding agents to drive the full agent-development lifecycle: create, improve, evaluate, maintain.
+Run the setup skill inside a freshly cloned [Starter](/deploy/introduction):
-Everything on this page runs inside a cloned template. If you don't have one running yet, [pick a Starter](/deploy/introduction) first.
+```text
+/setup-platform
+```
+
+The coding agent configures the local environment, starts AgentOS with Docker, verifies the MCP endpoint, builds your first agent, and helps you connect the AgentOS UI.
-The skills live in `.agents/skills/`. Claude Code picks them up on clone through a committed `.claude/skills` symlink; other harnesses like Codex and Cursor can symlink the same folder. Invoke a skill by name (`/create-new-agent`) or describe the task and the coding agent matches it.
+Each Starter gives coding agents access to the project, live AgentOS API, evals, traces in PostgreSQL, and container logs. They can use that context to diagnose behavior, edit the implementation, and verify the result.
## Skills
-| Skill | What it does | Who drives |
-|-------|--------------|------------|
-| `/create-new-agent` | Scaffolds an agent, registers it in `app/main.py`, smoke-tests it live. | You + the agent |
-| `/extend-agent` | Adds a tool or capability, refines instructions, fixes a known bug. | You |
-| `/improve-agent` | Derives probes from the agent's `INSTRUCTIONS`, judges responses, edits until they pass. | The agent |
-| `/eval-and-improve` | Runs the eval suite, diagnoses failures, fixes in scope until green. | The agent |
-| `/review-and-improve` | Sweeps for drift between docs, code, and config. Auto-fixes mechanical drift. | The agent |
+The skills live in `.agents/skills/`. Claude Code discovers them through the committed `.claude/skills` symlink. Codex and Cursor can use the same folder. Invoke a skill by name or describe the task and let the coding agent select it.
-## Your platform as an MCP tool
+| Skill | What it does | Use when |
+|-------|--------------|----------|
+| `/setup-platform` | Configures a fresh clone, starts AgentOS locally, verifies MCP, and builds the first agent. | Starting with a new Starter |
+| `/create-new-agent` | Scaffolds an agent, registers it in `app/main.py`, and smoke-tests it live. | Adding a new agent |
+| `/extend-agent` | Adds a tool or capability, refines instructions, or fixes a known bug. | The required change is already clear |
+| `/improve-agent` | Derives probes from the agent's `INSTRUCTIONS`, judges responses, makes focused edits, and reruns affected probes. | Improving behavior through simulations and probes |
+| `/eval-and-improve` | Runs the eval suite, classifies failures, proposes scoped fixes, and reruns affected cases. | Resolving an eval regression |
+| `/review-and-improve` | Checks documentation, code, and configuration together and fixes straightforward inconsistencies. | Maintaining the project after changes |
-Coding agents edit the platform's code and call its live agents over MCP. Register your AgentOS with the MCP clients on your machine:
+## Connect the live platform
+
+Coding agents can edit the project and call its live agents over MCP. Register the local AgentOS with supported clients:
```bash
uvx agno connect
```
-It auto-detects Claude Code, Claude Desktop, Codex, and Cursor and registers `http://localhost:8000/mcp`. To check the connection, open one of those apps and ask: "can you access my agentos mcp?". Your coding agent can then call `run_agent`, `run_team`, and `run_workflow` against the live platform.
+The command detects Claude Code, Claude Desktop, Codex, and Cursor and registers `http://localhost:8000/mcp`. Your coding agent can then call `run_agent`, `run_team`, and `run_workflow` against the running platform.
+
+For a deployed platform, pass its URL:
+
+```bash
+uvx agno connect --url https://
+```
-For a deployed platform, point the same command at your domain: `uvx agno connect --url https://`.
+| AgentOS configuration | What `agno connect` does |
+|-----------------------|--------------------------|
+| MCP without authentication | Writes a tokenless client entry |
+| Token-protected AgentOS with an admin credential | Mints a scoped service-account token for each client |
+| MCP OAuth | Writes the connection and prints the client sign-in step |
+| Headless client using MCP OAuth | Use `--pat` with an admin credential or existing admin PAT |
-`agno connect` writes client credentials according to the endpoint's authentication. It writes tokenless entries for an unauthenticated MCP endpoint. It mints scoped service-account tokens (`agno_pat_...`) for a token-protected endpoint when the AgentOS has a REST admin credential that can authorize the mint. For an OAuth-enabled endpoint, it writes tokenless entries and prints one-time browser sign-in steps for supported clients. Use `--pat` when a headless client needs a service-account token on an OAuth-enabled AgentOS; minting still requires a REST admin credential or an existing admin PAT. With the built-in OAuth provider, `MCP_CONNECT_SECRET` is the secret entered on the AgentOS consent page. Coding clients use OAuth tokens from that flow or a separately minted PAT.
+See [`agno connect`](/cli/connect) for client configuration, credential requirements, and conflict handling.
## Evals
-Lock in agent behavior with the eval suite in `evals/`. The evals run on the host machine, so set up the venv once:
+The eval suite lives in `evals/`. Set up the host environment once:
```bash
./scripts/venv_setup.sh
source .venv/bin/activate
```
-Then run:
+Run the suite by scope:
```bash
python -m evals --tag smoke # fast checks of the self-driving surfaces
@@ -52,36 +70,36 @@ python -m evals --name # one case while iterating
python -m evals -v # stream the full run with rich panels
```
-Cases wrap [AgentAsJudgeEval](/evals/agent-as-judge/overview) (LLM judge, binary pass/fail) and [ReliabilityEval](/evals/reliability/overview) (tool-call assertions). Results log to Postgres, so run history shows up at [os.agno.com](https://os.agno.com) next to sessions and traces.
+Cases use [AgentAsJudgeEval](/evals/agent-as-judge/overview) for model-judged behavior and [ReliabilityEval](/evals/reliability/overview) for tool-call assertions. Results are stored in PostgreSQL and appear in the [AgentOS UI](https://os.agno.com) beside sessions and traces.
If a case fails, run `/eval-and-improve`.
## Agent patterns
-The bundled agents demonstrate three patterns to copy:
+The bundled agents demonstrate three patterns:
| Pattern | Example | When to use |
|---------|---------|-------------|
| Direct tools | `agents/web_search.py` | The agent needs fine-grained control over each tool call. |
-| Context provider | `agents/platform_manager.py` | You want many tools collapsed into one `query_` interface that hands off to a sub-agent. |
-| Studio builder | `agents/agent_builder.py` | Users create and refine components from chat; deletes keep a confirmation gate. |
+| Context provider | `agents/platform_manager.py` | Several tools can sit behind one `query_` interface managed by a sub-agent. |
+| Studio builder | `agents/agent_builder.py` | Users create and refine components from chat with confirmation gates for destructive actions. |
## Teams and workflows
| Pattern | When to use |
|---------|-------------|
-| [Teams](/teams/overview) | Route to specialists, coordinate parallel work, synthesize results. |
-| [Workflows](/workflows/overview) | Processes with defined, repeatable control flow. |
+| [Teams](/teams/overview) | Route to specialists, coordinate parallel work, and synthesize results. |
+| [Workflows](/workflows/overview) | Run a process with defined, repeatable control flow. |
-Agents for open questions, teams for routing, workflows for processes.
+Use agents for open questions, teams for routing, and workflows for processes.
## Scheduled tasks
-The scheduler is on by default. Two reference workflows are registered out of the box:
+The scheduler is enabled by default. Two reference workflows are registered:
| Workflow | What it does | Default |
|----------|--------------|---------|
-| Deployment check | Daily readiness report: database, auth, scheduler, MCP, Slack config. Fixed checks, no LLM calls. | On. Disable with `ENABLE_DEPLOY_CHECK=False`. |
-| Run evals | Daily smoke-tag eval run. Uses model calls. | Off. Enable with `ENABLE_SCHEDULED_EVALS=True`. |
+| Deployment Check | Runs a daily readiness report for the database, authentication, scheduler, MCP, and Slack configuration. It uses fixed checks with no model calls. | On. Disable with `ENABLE_DEPLOY_CHECK=False`. |
+| Run Evals | Runs the smoke-tag eval suite daily and uses model calls. | Off. Enable with `ENABLE_SCHEDULED_EVALS=True`. |
See [Scheduler](/agent-os/scheduler/overview) for the cron API.
diff --git a/deploy/templates/modal/deploy.mdx b/deploy/templates/modal/deploy.mdx
index 446ff3a1d..f23ecc419 100644
--- a/deploy/templates/modal/deploy.mdx
+++ b/deploy/templates/modal/deploy.mdx
@@ -4,17 +4,17 @@ sidebarTitle: "Deploy"
description: "Run AgentOS locally using Docker and deploy to production on Modal."
---
-The [agentos-modal](https://github.com/agno-agi/agentos-modal) template runs AgentOS locally with Docker and deploys it to Modal. It includes:
+Choose Modal when your Python team wants to run AgentOS as one always-warm Modal container. The [agentos-modal](https://github.com/agno-agi/agentos-modal) template uses Docker locally and connects production to a provisioned Neon database or an existing PostgreSQL database with pgvector.
- **Agent Builder**, which creates agents, teams, and workflows.
- **Platform Manager**, which reports on evals, deployment checks, and schedules.
-- **5 [skills](/deploy/templates/improve-agents)** for coding-agent development and validation.
+- **Six [skills](/deploy/templates/improve-agents)**. `setup-platform` configures the local platform. Five lifecycle skills create, extend, improve, evaluate, and review it.
-The template keeps agent code, evals, traces, and system logs in one project.
+Coding agents can use the repository skills, live AgentOS API, evals, traces in PostgreSQL, and Modal logs to inspect and improve the platform.
## Get started
-Copy the prompt below into Claude Code, Cursor, or Codex to set up the template with a coding agent.
+Copy the prompt below into Claude Code, Cursor, or Codex to clone the template, start AgentOS locally, and build your first agent.
@@ -80,6 +80,8 @@ Prints `MCP OK` with the tool count and a real agent answer through the MCP endp
**Prerequisites:** Python 3 and OpenSSL. [Modal CLI](https://modal.com/docs/guide) installed with `modal token new` completed. [neonctl](https://neon.tech/docs/reference/neon-cli) installed with `neonctl auth` completed.
+The current script checks Neon authentication even when you supply an external database. External database deployments still need `neonctl auth` until that preflight is conditional.
+
```bash
@@ -94,7 +96,7 @@ Edit `.env.production` with production values: a different OpenAI key, productio
./scripts/modal/up.sh
```
-Reuses the `DB_HOST` and `DB_PASS` in your env file when both are set. Otherwise, it creates a Neon Postgres project and saves its connection details. The script writes your config into the `agentos-secrets` Modal secret and deploys `modal_app.py` as one always-warm container. It then sets `AGENTOS_URL` to the stable `https://--agentos.modal.run` URL and generates `MCP_CONNECT_SECRET` when your env file does not have one.
+When `DB_HOST` and `DB_PASS` are set, the script reuses the external database. Supply `DB_HOST`, `DB_USER`, `DB_PASS`, and `DB_DATABASE`; `DB_PORT` defaults to `5432`. The database must support pgvector and TLS. When the host or password is missing, the script creates a Neon Postgres project and saves its connection details. The script writes your config into the `agentos-secrets` Modal secret and deploys `modal_app.py` as one always-warm container. It then sets `AGENTOS_URL` to the stable `https://--agentos.modal.run` URL and generates `MCP_CONNECT_SECRET` when your env file does not have one.
@@ -121,9 +123,12 @@ For claude.ai and ChatGPT on the web: add `https://--agentos.modal.ru
```bash
modal app logs agentos
+
+curl -o /dev/null -w '%{http_code}\n' "https://--agentos.modal.run/health" # 200
+curl -o /dev/null -w '%{http_code}\n' "https://--agentos.modal.run/agents" # 401
```
-Open `https://--agentos.modal.run/docs` to confirm the API is serving.
+`/health` and `/docs` remain public. Protected AgentOS routes such as `/agents` require a valid token.
diff --git a/deploy/templates/modal/reference.mdx b/deploy/templates/modal/reference.mdx
index 4e67c8dab..8a0326a58 100644
--- a/deploy/templates/modal/reference.mdx
+++ b/deploy/templates/modal/reference.mdx
@@ -4,7 +4,7 @@ sidebarTitle: "Reference"
description: "Commands, customization, environment variables, and troubleshooting for the Modal template."
---
-The Modal app is `agentos`, served as one always-warm container. Configuration lives in the `agentos-secrets` Modal secret, and the database is a Neon Postgres project named `agentos`.
+The Modal app is `agentos`, served as one always-warm container. Configuration lives in the `agentos-secrets` Modal secret. The scripts provision a Neon Postgres project named `agentos` by default. An external database requires `DB_HOST`, `DB_USER`, `DB_PASS`, and `DB_DATABASE`; `DB_PORT` defaults to `5432`. It must support pgvector and TLS. The current `up.sh` still checks `neonctl` authentication before reusing those values. Start with [Deploy AgentOS on Modal](/deploy/templates/modal/deploy) for prerequisites and the first deployment.
## Manage
@@ -21,22 +21,22 @@ The Modal app is `agentos`, served as one always-warm container. Configuration l
-`modal_app.py` pins `min_containers=1` and `max_containers=1`. The always-warm container keeps the in-process scheduler and MCP streams alive, and the cap stops two schedulers from double-firing every cron. Keep both settings.
+`modal_app.py` pins `min_containers=1` and `max_containers=1`. The always-warm container keeps scheduled work and MCP streams available. The template has been validated with this single-container topology. Validate schedule registration and MCP streams before changing the maximum.
## Production auth
-Token-Based Authorization is on by default. Production startup requires `JWT_VERIFICATION_KEY` or a readable JWKS file at the container path in `JWT_JWKS_FILE`; otherwise the process exits.
+Token-Based Authorization protects AgentOS routes by default in production. Startup requires `JWT_VERIFICATION_KEY` or a readable JWKS file at the container path in `JWT_JWKS_FILE`; otherwise the process exits.
Token-Based Auth gives you three things:
-1. **No public access.** The server rejects requests without a valid token.
+1. **Protected API access.** Requests to protected AgentOS routes require a valid token. `/`, `/health`, `/info`, `/docs`, `/redoc`, `/openapi.json`, and `/docs/oauth2-redirect` remain public.
2. **Per-request identity.** Middleware validates the token and exposes its `user_id`, optional `session_id`, scopes, and claims to the request.
3. **Scope-based permissions.** Token scopes control access to AgentOS routes and resources.
The templates do not enable per-user data isolation. To scope non-admin session, memory, trace, and run access to the JWT subject, pass `authorization_config=AuthorizationConfig(user_isolation=True)` to `AgentOS`. See [User Isolation](/agent-os/security/authorization/user-isolation).
-To opt out (not recommended), set `authorization=False` in `app/main.py` and redeploy. Use this only inside a private VPC behind another auth layer. Without it, anyone who guesses your modal.run URL can access your AgentOS backend.
+To disable JWT authentication, set `authorization=False` in `app/main.py`, remove `JWT_VERIFICATION_KEY` and `JWT_JWKS_FILE` from the production env file, and run `./scripts/modal/env-sync.sh`. `authorization=False` disables AgentOS scope enforcement. Configured JWT environment variables continue to enable JWT validation. MCP OAuth remains active when `MCP_CONNECT_SECRET` is set. Only do this when another layer protects the service.
## Customize
@@ -91,7 +91,7 @@ def default_model():
return Claude(id="claude-sonnet-5")
```
-Add `anthropic` to `pyproject.toml`, set the provider key in your env, and regenerate pins:
+Add `anthropic` to `pyproject.toml`. Set `ANTHROPIC_API_KEY` in `.env` for local runs and `.env.production` for production, then regenerate pins:
```bash
./scripts/generate_requirements.sh
@@ -163,7 +163,7 @@ source .venv/bin/activate
| Variable | Required | Default | Description |
|----------|----------|---------|-------------|
| `OPENAI_API_KEY` | Yes | - | Models and embeddings. |
-| `RUNTIME_ENV` | No | `prd` | `dev` disables JWT. Compose sets it for local. Never put it in an env file that syncs to Modal, or production deploys unauthenticated. |
+| `RUNTIME_ENV` | No | `prd` | `dev` sets `authorization=False`, which disables AgentOS scope enforcement. Configured JWT environment variables continue to enable JWT validation. Compose sets `dev` locally; keep `prd` on Modal. |
| `JWT_VERIFICATION_KEY` | Production | - | Public key from os.agno.com. Quote the value so the multi-line PEM parses as one variable. |
| `JWT_JWKS_FILE` | Production | - | Path inside the Modal container to a JWKS file. The scripts put only this path into `agentos-secrets`. Put the file in the Docker build context or add an explicit Modal mount before deploying. |
| `MCP_CONNECT_SECRET` | No | generated by `up.sh` | OAuth consent secret (16+ chars) for connecting claude.ai and ChatGPT to `/mcp`. `up.sh` generates one on deploy and writes it to `.env.production`. |
@@ -201,7 +201,7 @@ Neon projects are org-scoped, so `neonctl projects create` asks which organizati
Expected. Mint the key at [os.agno.com](https://os.agno.com): connect your OS (**Connect OS** → **Live**, enter your modal.run URL), then turn on **Token-Based Authorization (JWT)** under **Settings** → **OS & Security** and paste the full PEM. To add a PEM later, set `JWT_VERIFICATION_KEY` and run `./scripts/modal/env-sync.sh`. To use JWKS, add the file to the Docker build context or configure a Modal mount, set `JWT_JWKS_FILE` to its container path, then deploy.
-JWT auth is on whenever `RUNTIME_ENV` is not `dev`. Set `JWT_VERIFICATION_KEY` and sync. For `JWT_JWKS_FILE`, first make the file available inside the Modal image or through a mount, then set its container path and sync. To opt out inside a private VPC behind another auth layer, set `authorization=False` in `app/main.py`.
+AgentOS scope enforcement is on whenever `RUNTIME_ENV` is not `dev`. Set `JWT_VERIFICATION_KEY` and sync. For `JWT_JWKS_FILE`, first make the file available inside the Modal image or through a mount, then set its container path and sync. To disable JWT, set `authorization=False` in `app/main.py`, remove both JWT variables from the production env file, and sync. MCP OAuth remains active when `MCP_CONNECT_SECRET` is set.
Secrets are read at container start, so rewriting the secret alone changes nothing. `./scripts/modal/env-sync.sh` does both steps: it rewrites `agentos-secrets` and redeploys to roll the container.
@@ -210,7 +210,7 @@ Secrets are read at container start, so rewriting the secret alone changes nothi
`AGENTOS_URL` is still the localhost default. `up.sh` sets it to your modal.run URL automatically; for a custom domain or tunnel, set it by hand and run `./scripts/modal/env-sync.sh`.
-`down.sh` deletes the Neon project but leaves `NEON_PROJECT_ID` and the `DB_*` values in your env file, so `up.sh` thinks a database still exists. Delete those lines and re-run `./scripts/modal/up.sh` to provision a fresh one.
+`down.sh` deletes the Neon project and leaves `NEON_PROJECT_ID` and the `DB_*` values in your env file. Delete those lines and re-run `./scripts/modal/up.sh` to provision a fresh one.
The script only declares success once the app no longer shows as running in `modal app list` and the project is gone from `neonctl projects list`. Check both, then re-run it or finish by hand: `modal app stop agentos` and `neonctl projects delete `.
diff --git a/deploy/templates/railway/deploy.mdx b/deploy/templates/railway/deploy.mdx
index 326f26a64..e691e8f18 100644
--- a/deploy/templates/railway/deploy.mdx
+++ b/deploy/templates/railway/deploy.mdx
@@ -4,16 +4,17 @@ sidebarTitle: "Deploy"
description: "Run AgentOS locally using Docker and deploy to production on Railway."
---
-The [agentos-railway](https://github.com/agno-agi/agentos-railway) template runs AgentOS locally with Docker and deploys it to Railway. It includes:
+Choose Railway when you want Railway to run AgentOS and PostgreSQL without managing a host. The [agentos-railway](https://github.com/agno-agi/agentos-railway) template uses Docker locally and provisions both services on Railway for production.
-- **2 platform agents** that build and run the platform for you. **Agent Builder** creates agents, teams, and workflows. **Platform Manager** understands, monitors, and explains the platform.
-- **5 [skills](/deploy/templates/improve-agents)** that let coding agents build, test, and improve the platform for you.
+- **Agent Builder**, which creates agents, teams, and workflows when prompted.
+- **Platform Manager**, which inspects registered agents, eval history, deployment checks, and schedules.
+- **Six [skills](/deploy/templates/improve-agents)**. `setup-platform` configures the local platform. Five lifecycle skills create, extend, improve, evaluate, and review it.
Coding agents can use the repository skills, live AgentOS API, evals, and container logs to inspect and improve the platform.
## Get started
-Copy the prompt below into Claude Code, Cursor, or Codex to clone, configure, and start the platform.
+Copy the prompt below into Claude Code, Cursor, or Codex to clone the template, start AgentOS locally, and build your first agent.
@@ -120,10 +121,13 @@ For claude.ai and ChatGPT on the web: add `https:///mcp` as a cu
```bash
+curl -o /dev/null -w '%{http_code}\n' "https:///health" # 200
+curl -o /dev/null -w '%{http_code}\n' "https:///agents" # 401
+
railway logs --service agent-os
```
-Open `https:///docs` to confirm the API is serving.
+`/health` and `/docs` remain public. Protected AgentOS routes such as `/agents` require a valid token.
diff --git a/deploy/templates/railway/reference.mdx b/deploy/templates/railway/reference.mdx
index c8d1335c2..0ca26361f 100644
--- a/deploy/templates/railway/reference.mdx
+++ b/deploy/templates/railway/reference.mdx
@@ -4,6 +4,8 @@ sidebarTitle: "Reference"
description: "Commands, customization, environment variables, and troubleshooting for the Railway template."
---
+Start with [Deploy AgentOS on Railway](/deploy/templates/railway/deploy) for local setup and the first production deployment.
+
## Manage
| Task | Command |
@@ -26,17 +28,17 @@ Push to `main` triggers a build and rolling deploy. `./scripts/railway/env-sync.
## Production auth
-Token-Based Authorization is on by default. Production startup requires `JWT_VERIFICATION_KEY` or a readable JWKS file at the container path in `JWT_JWKS_FILE`; otherwise the process exits.
+Token-Based Authorization protects AgentOS routes by default in production. Startup requires `JWT_VERIFICATION_KEY` or a readable JWKS file at the container path in `JWT_JWKS_FILE`; otherwise the process exits.
Token-Based Auth gives you three things:
-1. **No public access.** The server rejects requests without a valid token.
+1. **Protected API access.** Requests to protected AgentOS routes require a valid token. `/`, `/health`, `/info`, `/docs`, `/redoc`, `/openapi.json`, and `/docs/oauth2-redirect` remain public.
2. **Per-request identity.** Middleware validates the token and exposes its `user_id`, optional `session_id`, scopes, and claims to the request.
3. **Scope-based permissions.** Token scopes control access to AgentOS routes and resources.
The templates do not enable per-user data isolation. To scope non-admin session, memory, trace, and run access to the JWT subject, pass `authorization_config=AuthorizationConfig(user_isolation=True)` to `AgentOS`. See [User Isolation](/agent-os/security/authorization/user-isolation).
-To opt out (not recommended), set `authorization=False` in `app/main.py` and redeploy. Use this only inside a private VPC behind another auth layer. Without it, anyone who guesses your Railway domain can access your platform.
+To disable JWT authentication, set `authorization=False` in `app/main.py`, remove `JWT_VERIFICATION_KEY` and `JWT_JWKS_FILE` from the Railway service, and redeploy. `authorization=False` disables AgentOS scope enforcement. Configured JWT environment variables continue to enable JWT validation. MCP OAuth remains active when `MCP_CONNECT_SECRET` is set. Only do this when another layer protects the service.
## Customize
@@ -91,7 +93,7 @@ def default_model():
return Claude(id="claude-sonnet-5")
```
-Add `anthropic` to `pyproject.toml`, set the provider key in your env, and regenerate pins:
+Add `anthropic` to `pyproject.toml`. Set `ANTHROPIC_API_KEY` in `.env` for local runs and `.env.production` for production, then regenerate pins:
```bash
./scripts/generate_requirements.sh
@@ -162,7 +164,7 @@ source .venv/bin/activate
| Variable | Required | Default | Description |
|----------|----------|---------|-------------|
| `OPENAI_API_KEY` | Yes | - | Models and embeddings. |
-| `RUNTIME_ENV` | No | `prd` | `dev` disables JWT. Compose sets it for local. Never put it in an env file that syncs to Railway, or production deploys unauthenticated. |
+| `RUNTIME_ENV` | No | `prd` | `dev` sets `authorization=False`, which disables AgentOS scope enforcement. Configured JWT environment variables continue to enable JWT validation. Compose sets `dev` locally; keep `prd` on Railway. |
| `JWT_VERIFICATION_KEY` | Production | - | Public key from os.agno.com. Quote the value so the multi-line PEM parses as one variable. |
| `JWT_JWKS_FILE` | Production | - | Path inside the running container to a JWKS JSON file. The scripts set only this path. Add the file to the image build context, rebuild, and redeploy the image, or configure a platform mount and roll the service. |
| `MCP_CONNECT_SECRET` | No | generated by `up.sh` | OAuth consent secret (16+ chars) for connecting claude.ai and ChatGPT to `/mcp`. `up.sh` generates one on deploy and writes it to `.env.production`. |
@@ -191,7 +193,7 @@ Install the CLI with `brew install railway` or `npm install -g @railway/cli`, th
Expected. Mint the key at [os.agno.com](https://os.agno.com): connect your OS (**Connect OS** → **Live**, enter your Railway domain), then turn on **Token-Based Authorization (JWT)** under **Settings** → **OS & Security** and paste the full PEM. To add a PEM later, set `JWT_VERIFICATION_KEY` and run `./scripts/railway/env-sync.sh`. To use JWKS, add the file to the image build context and rebuild, or configure a mount. Set `JWT_JWKS_FILE` to its container path, then redeploy or roll the service. Env sync alone only updates the path.
-JWT auth is on whenever `RUNTIME_ENV` is not `dev`. Set `JWT_VERIFICATION_KEY` and sync. For JWKS, verify the file exists inside the container at `JWT_JWKS_FILE`; changing the variable alone does not deliver it. To opt out inside a private VPC behind another auth layer, set `authorization=False` in `app/main.py`.
+AgentOS scope enforcement is on whenever `RUNTIME_ENV` is not `dev`. Set `JWT_VERIFICATION_KEY` and sync. For JWKS, verify the file exists inside the container at `JWT_JWKS_FILE`; changing the variable alone does not deliver it. To disable JWT, set `authorization=False` in `app/main.py`, remove both JWT variables from the Railway service, and redeploy. MCP OAuth remains active when `MCP_CONNECT_SECRET` is set.
The container is still starting. Wait 1-2 minutes and check `railway logs --service agent-os`.
diff --git a/deploy/templates/render/deploy.mdx b/deploy/templates/render/deploy.mdx
index a4af94f39..13c150f5b 100644
--- a/deploy/templates/render/deploy.mdx
+++ b/deploy/templates/render/deploy.mdx
@@ -4,18 +4,19 @@ sidebarTitle: "Deploy"
description: "Run AgentOS locally using Docker and deploy to production on Render."
---
-AgentOS is a secure, scalable platform for running agents. The [agentos-render](https://github.com/agno-agi/agentos-render) codebase runs AgentOS locally using Docker and deploys to production on Render. It comes with:
+Choose Render when your team wants a Blueprint-driven AgentOS deployment with managed PostgreSQL. The [agentos-render](https://github.com/agno-agi/agentos-render) template uses Docker locally and deploys one paid, always-on web service for production.
-- **2 platform agents** that build and run the platform for you. **Agent Builder** creates agents, teams, and workflows. **Platform Manager** understands, monitors, and explains the platform.
-- **5 [skills](/deploy/templates/improve-agents)** that let coding agents build, test, and improve the platform for you.
+- **Agent Builder**, which creates agents, teams, and workflows when prompted.
+- **Platform Manager**, which inspects registered agents, eval history, deployment checks, and schedules.
+- **Six [skills](/deploy/templates/improve-agents)**. `setup-platform` configures the local platform. Five lifecycle skills create, extend, improve, evaluate, and review it.
-Because the trace data, agent code, evals, and system logs all live in one place, the platform can inspect and improve itself automatically.
+Coding agents can use the repository skills, live AgentOS API, evals, and container logs to inspect and improve the platform.
Deployment is Blueprint-driven: Render provisions everything from `render.yaml` when you connect your repo, and one wiring script finishes the setup.
## Get started
-The fastest way to get started is using a coding agent. Copy the prompt below into Claude Code, Cursor or Codex and it'll take you from zero to a running platform.
+Copy the prompt below into Claude Code, Cursor, or Codex to clone the template, start AgentOS locally, and build your first agent.
@@ -79,7 +80,7 @@ Prints `MCP OK` with the tool count and a real agent answer through the MCP endp
## Deploy to production
-**Prerequisites:** A [Render](https://render.com) account with your copy of the repo reachable from Render. A `RENDER_API_KEY` (dashboard → **Account Settings** → **API Keys**) for the scripts.
+**Prerequisites:** Python 3 and OpenSSL. A [Render](https://render.com) account with your copy of the repo reachable from Render. A `RENDER_API_KEY` (dashboard → **Account Settings** → **API Keys**) for the scripts.
@@ -93,7 +94,7 @@ Edit `.env.production` with production values: a different OpenAI key, productio
Open [dashboard.render.com](https://dashboard.render.com) → **New +** → **Blueprint**, connect your copy of the repo, and apply. Render reads `render.yaml`, prompts for `OPENAI_API_KEY`, builds the Dockerfile, and creates the `basic-256mb` Postgres. The first build takes about 10 minutes.
-The web service runs on the `starter` plan, the cheapest that never sleeps, which the in-process scheduler and MCP streams require. It runs as a single instance by design; two instances double-fire every cron.
+The web service runs on the `starter` plan, the cheapest that never sleeps. This keeps scheduled work and MCP streams available. The template uses one instance and has been validated with that topology. Validate schedule registration and MCP streams before scaling it.
@@ -127,7 +128,12 @@ For claude.ai and ChatGPT on the web: add `https:///mcp` as a c
-The script prints your service URL. Open `https:///docs` to confirm the API is serving. Logs live in the dashboard: `agent-os` → **Logs**.
+```bash
+curl -o /dev/null -w '%{http_code}\n' "https:///health" # 200
+curl -o /dev/null -w '%{http_code}\n' "https:///agents" # 401
+```
+
+The script prints your service URL. `/health` and `/docs` remain public. Protected AgentOS routes such as `/agents` require a valid token. Logs live in the dashboard: `agent-os` → **Logs**.
diff --git a/deploy/templates/render/reference.mdx b/deploy/templates/render/reference.mdx
index 15818ac41..cea3c411a 100644
--- a/deploy/templates/render/reference.mdx
+++ b/deploy/templates/render/reference.mdx
@@ -4,7 +4,7 @@ sidebarTitle: "Reference"
description: "Commands, customization, environment variables, and troubleshooting for the Render template."
---
-The web service is `agent-os` and the database is `agentos-db`. Every command in `scripts/render/` drives the Render API and needs `RENDER_API_KEY` in your environment or env file.
+The web service is `agent-os` and the database is `agentos-db`. Every command in `scripts/render/` drives the Render API and needs `RENDER_API_KEY` in your environment or env file. Start with [Deploy AgentOS on Render](/deploy/templates/render/deploy) for prerequisites and the first deployment.
## Manage
@@ -36,7 +36,7 @@ Token-Based Auth gives you three things:
The templates do not enable per-user data isolation. To scope non-admin session, memory, trace, and run access to the JWT subject, pass `authorization_config=AuthorizationConfig(user_isolation=True)` to `AgentOS`. See [User Isolation](/agent-os/security/authorization/user-isolation).
-To disable JWT authentication, set `authorization=False` in `app/main.py`, remove `JWT_VERIFICATION_KEY` and `JWT_JWKS_FILE` from the Render service, and push. Use this only inside a private VPC behind another auth layer. `authorization=False` disables AgentOS scope enforcement, while configured JWT environment variables still enable JWT validation. MCP OAuth remains active when `MCP_CONNECT_SECRET` is set.
+To disable JWT authentication, set `authorization=False` in `app/main.py`, remove `JWT_VERIFICATION_KEY` and `JWT_JWKS_FILE` from the Render service, and push. `authorization=False` disables AgentOS scope enforcement. Configured JWT environment variables continue to enable JWT validation. MCP OAuth remains active when `MCP_CONNECT_SECRET` is set. Only do this after placing the public service behind another authentication or network boundary.
## Customize
@@ -91,7 +91,7 @@ def default_model():
return Claude(id="claude-sonnet-5")
```
-Add `anthropic` to `pyproject.toml`, set the provider key in your env, and regenerate pins:
+Add `anthropic` to `pyproject.toml`. Set `ANTHROPIC_API_KEY` in `.env` for local runs and `.env.production` for production, then regenerate pins:
```bash
./scripts/generate_requirements.sh
@@ -101,6 +101,8 @@ Rebuild locally with `docker compose up -d --build`. For production, sync the en
```bash
./scripts/render/env-sync.sh
+git add app/settings.py pyproject.toml requirements.txt
+git commit -m "Use Anthropic model"
git push
```
@@ -195,7 +197,7 @@ Create one in the dashboard under **Account Settings** → **API Keys**, then ex
Expected. Mint the key at [os.agno.com](https://os.agno.com): connect your OS (**Connect OS** → **Live**, enter your onrender.com URL), then turn on **Token-Based Authorization (JWT)** under **Settings** → **OS & Security** and paste the full PEM. To add a PEM later, set `JWT_VERIFICATION_KEY` and run `./scripts/render/env-sync.sh`. To use JWKS, commit and push the file into the image build context, or configure a mount. Set `JWT_JWKS_FILE` to its container path, then let auto-deploy rebuild or roll the service. Env sync alone only updates the path.
-JWT scope enforcement is on whenever `RUNTIME_ENV` is not `dev`. Set `JWT_VERIFICATION_KEY` and sync. For JWKS, verify the file exists inside the container at `JWT_JWKS_FILE`; changing the variable alone does not deliver it. To disable JWT inside a private VPC behind another auth layer, set `authorization=False` in `app/main.py` and remove both JWT environment variables from the Render service. MCP OAuth remains active when `MCP_CONNECT_SECRET` is set.
+JWT scope enforcement is on whenever `RUNTIME_ENV` is not `dev`. Set `JWT_VERIFICATION_KEY` and sync. For JWKS, verify the file exists inside the container at `JWT_JWKS_FILE`; changing the variable alone does not deliver it. To disable JWT, set `authorization=False` in `app/main.py`, remove both JWT environment variables from the Render service, and place the public service behind another authentication or network boundary. MCP OAuth remains active when `MCP_CONNECT_SECRET` is set.
Render builds the pushed branch, so local uncommitted changes stay on your machine. Commit, push to your deploy branch, and let `autoDeploy` rebuild. `redeploy.sh` warns when it finds uncommitted changes.
diff --git a/deploy/templates/scout/overview.mdx b/deploy/templates/scout/overview.mdx
index d2e1d9cdb..0473faacf 100644
--- a/deploy/templates/scout/overview.mdx
+++ b/deploy/templates/scout/overview.mdx
@@ -1,12 +1,35 @@
---
title: "Scout"
-sidebarTitle: "Scout"
+sidebarTitle: "Scout: Knowledge Agent"
description: "Open-source company intelligence agent that navigates web, Slack, Drive, and MCP sources and builds its own wiki and CRM as it learns about your company."
---
-**Scout is an open-source company intelligence agent.** It navigates live information sources (web, Slack, Drive, wiki, CRM, MCP servers) to assemble context on demand, and it builds its own wiki and CRM as it learns about your company. The code is public at [agno-agi/scout](https://github.com/agno-agi/scout).
+**Scout gives teams an open-source company intelligence agent for finding answers across web, Slack, Drive, wiki, CRM, and MCP sources.**
-The default move when working with knowledge sources is to ingest everything into a vector database, chunk, embed, and pray. Coding agents figured out the right approach. They navigate: `ls`, `grep`, open the file, follow the import. Scout does the same thing across Slack, Drive, and the rest. It searches the channel, opens the doc, expands the thread, and assembles context at question time from the live source.
+Company knowledge changes across systems with different search APIs and access rules. Scout navigates those live sources at request time: it searches a channel, opens a document, expands a thread, and assembles the relevant context for the answer.
+
+Agno context providers give each source its own sub-agent and expose a small query or update interface to Scout. Run it locally, then ask a question that requires information from two configured sources. The code is public at [agno-agi/scout](https://github.com/agno-agi/scout).
+
+## Run locally
+
+You need [Docker Desktop](https://docs.docker.com/desktop/) installed and running.
+
+```bash
+git clone https://github.com/agno-agi/scout && cd scout
+
+cp example.env .env
+# set OPENAI_API_KEY in .env
+
+docker compose up -d --build
+```
+
+Scout is now running at `http://localhost:8000`. The [Scout README](https://github.com/agno-agi/scout#quick-start) has the full walkthrough.
+
+### Chat with Scout
+
+1. Open [os.agno.com](https://os.agno.com) and log in.
+2. Click **Connect OS**, choose **Local**, enter `http://localhost:8000`, then **Connect**.
+3. Try the pre-configured prompts.
## How it works
@@ -26,7 +49,7 @@ A sub-agent behind each provider owns the source's quirks. Scout sees `query_sla
| **MCP** | Registered in `scout/contexts.py` | One `query_mcp_` per server. |
- Scout intends Slack access to be read-only, but the pinned template does not pass `write=False` when it creates `SlackContextProvider`. Configuring Slack currently exposes `update_slack`. Leave write scopes ungranted until the template enforces its intended boundary.
+ Configuring Slack currently exposes both `query_slack` and `update_slack`. The Slack interface needs `chat:write` to reply, so removing write scopes does not provide a practical boundary. Set `write=False` on `SlackContextProvider` in `scout/contexts.py` before connecting a workspace that should remain read-only.
Setup for each provider is covered in the Scout README's [Context Providers](https://github.com/agno-agi/scout#context-providers) section.
@@ -42,27 +65,6 @@ Most information Scout learns from working with you is perfect for a wiki and a
Both start empty and grow with use. Mention that Josh from Anthropic shared a new RLM paper, and Scout adds Josh to the CRM, parses the paper into the wiki, and links them. See [How Scout works](https://github.com/agno-agi/scout#how-scout-works) in the README for how both systems work.
-## Run locally
-
-You need [Docker Desktop](https://docs.docker.com/desktop/) installed and running.
-
-```bash
-git clone https://github.com/agno-agi/scout && cd scout
-
-cp example.env .env
-# set OPENAI_API_KEY in .env
-
-docker compose up -d --build
-```
-
-Scout is now running at `http://localhost:8000`. The [Scout README](https://github.com/agno-agi/scout#quick-start) has the full walkthrough.
-
-### Chat with Scout
-
-1. Open [os.agno.com](https://os.agno.com) and log in.
-2. Click **Add OS**, choose **Local**, enter `http://localhost:8000`, then **Connect**.
-3. Try the pre-configured prompts.
-
## Deploy to Railway
Scout runs on any cloud provider. We provide scripts for Railway.
@@ -83,7 +85,7 @@ The `up.sh` script provisions PostgreSQL and the `scout` service, then creates y
Your first deploy will fail. That's expected. Production endpoints require RBAC authorization by default, and without a `JWT_VERIFICATION_KEY` the app refuses to serve traffic. Scout's job is to keep your company data off the public web. To get your key:
-1. Open [os.agno.com](https://os.agno.com), click **Add OS** → **Live**, and enter your Railway domain.
+1. Open [os.agno.com](https://os.agno.com), click **Connect OS** → **Live**, and enter your Railway domain.
2. Enable **Token Based Authorization**.
3. Paste the public key into `.env.production` as `JWT_VERIFICATION_KEY` (the full PEM block, no surrounding quotes).
4. Sync the env. Railway auto-deploys when values change.
diff --git a/docs.json b/docs.json
index be79f9dc6..c6914715e 100644
--- a/docs.json
+++ b/docs.json
@@ -95,8 +95,8 @@
"agent-platform/run-local",
"agent-platform/create-agent",
"agent-platform/improve-agent",
- "agent-platform/run-railway",
"agent-platform/evals",
+ "agent-platform/run-railway",
"agent-platform/next-steps"
]
}
@@ -107,9 +107,11 @@
"pages": [
"features/sdk",
"features/runtime",
+ "features/control-plane",
"features/api",
"features/storage",
"features/observability",
+ "features/evaluation",
"features/security-and-auth",
"features/interfaces",
"features/scheduling"
@@ -118,18 +120,6 @@
{
"group": "Use Cases",
"pages": [
- {
- "group": "Data Labeling",
- "pages": [
- "use-cases/data-labeling/overview",
- "use-cases/data-labeling/structured-extraction",
- "use-cases/data-labeling/classification",
- "use-cases/data-labeling/llm-as-judge",
- "use-cases/data-labeling/preference-data",
- "use-cases/data-labeling/multimodal-inputs",
- "use-cases/data-labeling/quality-pipeline"
- ]
- },
{
"group": "Product Copilots & Agents",
"pages": [
@@ -140,8 +130,25 @@
"use-cases/product-agents/interfaces"
]
},
+ "use-cases/workflow-automation",
{
- "group": "Data & Analytics Agents",
+ "group": "Data Labeling & Classification",
+ "pages": [
+ "use-cases/data-labeling/overview",
+ "use-cases/data-labeling/image-search",
+ "use-cases/data-labeling/structured-extraction",
+ "use-cases/data-labeling/classification",
+ "use-cases/data-labeling/multimodal-inputs",
+ "use-cases/data-labeling/llm-as-judge",
+ "use-cases/data-labeling/preference-data",
+ "use-cases/data-labeling/quality-pipeline"
+ ]
+ },
+ "use-cases/customer-support",
+ "use-cases/knowledge-agents",
+ "use-cases/coding-agents",
+ {
+ "group": "Data & Analytics",
"pages": [
"use-cases/data-agents/overview",
"use-cases/data-agents/querying-your-data",
@@ -153,7 +160,7 @@
]
},
{
- "group": "Deep Research & Analysis",
+ "group": "Deep Research",
"pages": [
"use-cases/deep-research/overview",
"use-cases/deep-research/orchestration-patterns",
diff --git a/features/api.mdx b/features/api.mdx
index 30c8f8d3b..320609957 100644
--- a/features/api.mdx
+++ b/features/api.mdx
@@ -1,16 +1,9 @@
---
title: Agent API
-description: "REST API and optional MCP server for agents, teams, and workflows in AgentOS."
+description: "Run and manage agents, teams, and workflows through REST, SSE, and MCP."
---
-Shipping an agent needs more than a `/run` endpoint. A live agent needs an API that can:
-
-- Run agents in streaming mode and as background jobs
-- Manage the sessions, memory, and learnings your agents accumulate
-- Inspect runs, traces, and metrics
-- Schedule recurring work
-- Gate sensitive tool calls on human approval
-- Resume paused runs once that approval comes back
+Agent-backed products need an API that covers the state and controls around every run. AgentOS provides REST endpoints for agents, teams, and workflows, plus sessions, memory, knowledge, traces, evaluations, schedules, approvals, and versioned components.
AgentOS registers run routes for your agents, teams, and workflows. Database-backed routes and opt-in features such as scheduling, tracing, and MCP depend on the AgentOS configuration. Browse the live API at `/docs` or fetch the spec from `/openapi.json`.
@@ -25,7 +18,7 @@ AgentOS registers run routes for your agents, teams, and workflows. Database-bac
## Interfaces
-Agents need to be reachable over more than one interface. Define an agent once and AgentOS can expose it over any interface you opt into. REST and SSE are on by default; add an MCP server, A2A, or a Slack interface as needed. The agent code stays the same; only the interface layer changes.
+AgentOS can expose the same registered component through several interfaces. REST and SSE are on by default; add an MCP server, A2A, or a Slack interface as needed. Each interface uses the same registered agent.
## The surface area
@@ -73,7 +66,7 @@ Pass `stream=true` for Server-Sent Events. Pass `background=true` to run async a
## Adding your own routes
-AgentOS is built on FastAPI. Register additional routes for webhooks, custom dashboards, integrations:
+AgentOS is built on FastAPI. Register additional routes for webhooks, dashboards, and integrations:
```python
# `agent_os` is your AgentOS instance; `agent` is an Agent registered with it
@@ -95,3 +88,10 @@ The agent is a regular Python object. Call `agent.run(...)` or `await agent.arun
When `authorization=True`, central REST routes require a valid JWT in the `Authorization: Bearer ...` header except for the public routes (`/`, `/health`, `/info`, and API docs routes such as `/docs` and `/openapi.json`). AgentOS validates the token, extracts claims, and applies RBAC scopes before agent code runs. Self-authenticating interfaces such as Slack, Telegram, and WhatsApp verify requests through their own interface middleware.
See [Security & Auth](/features/security-and-auth) for the details.
+
+## Developer Resources
+
+- [AgentOS API guide](/agent-os/using-the-api)
+- [AgentOS API reference](/reference-api/overview)
+- [AgentOS MCP interface](/agent-os/mcp/mcp)
+- [AgentOS client](/agent-os/client/overview)
diff --git a/features/control-plane.mdx b/features/control-plane.mdx
new file mode 100644
index 000000000..ecc6e5fb8
--- /dev/null
+++ b/features/control-plane.mdx
@@ -0,0 +1,102 @@
+---
+title: AgentOS Control Plane
+sidebarTitle: AgentOS Control Plane
+description: "Test, inspect, and operate AgentOS runtimes from one web interface."
+---
+
+The AgentOS Control Plane gives developers one place to run, inspect, and improve the agents, teams, and workflows served by AgentOS. Connect a local or deployed runtime, test real inputs, follow each run through its session and trace, and manage the knowledge, memory, evaluations, approvals, and schedules behind the system.
+
+
+
+
+
+## From first run to production
+
+Test a component, inspect the run, manage the state around it, and repeat against local or deployed runtimes.
+
+| Stage | Work in the Control Plane |
+|-------|---------------------------|
+| Build | Compose and version agents, teams, and workflows in Studio from registered models, tools, databases, schemas, and knowledge |
+| Test | Run agents and teams, execute workflows, select component versions, and follow streamed output |
+| Debug | Open session history and inspect trace trees for instrumented model calls, tool calls, team delegation, workflow steps, token use, latency, and errors |
+| Improve | Search knowledge, review or update user memories, and inspect stored evaluations and aggregate usage metrics |
+| Operate | Resolve approvals, create or trigger schedules, and switch between local and deployed runtimes |
+
+## Follow every run
+
+Open a session and follow the execution behind its response. Trace trees show the model calls, tool inputs and outputs, team delegation, and workflow steps recorded for the run. Spans show status and timing. Model spans also include token metrics when available.
+
+
+
+
+
+Use the trace to move from an unexpected result to the model call, tool argument, member response, or workflow step that produced it.
+
+## Manage the system behind each run
+
+
+
+ Compose components from your Registry, save drafts, publish versions, and choose the version served by the API.
+
+
+ Search knowledge content and review or update the user memories exposed by the connected runtime.
+
+
+ Review stored evaluation results and aggregate runtime usage from the configured database.
+
+
+ Inspect tool arguments, approve or reject paused executions, and follow resolution history.
+
+
+ Create recurring runs, trigger them manually, and inspect their execution history.
+
+
+ Follow a first run, review runtime requirements, and open deeper guides.
+
+
+
+## Connect your runtimes
+
+Add local, staging, and production AgentOS endpoints to the Control Plane. Select a runtime from the header to change the system you are working on.
+
+The browser sends requests to the selected AgentOS endpoint. That runtime executes components, applies its authorization configuration, and reads or writes the state shown in the UI.
+
+| Layer | Role |
+|-------|------|
+| Control Plane | Provides the browser interface and calls the AgentOS endpoint you select |
+| AgentOS runtime | Runs agents, teams, and workflows, exposes their APIs, and enforces runtime authorization |
+| Configured databases | Store sessions, memories, traces, evaluations, approvals, schedules, metrics, and Studio component versions |
+| External services | Models, tools, interfaces, telemetry, and custom exporters follow their own configuration and data paths |
+
+
+Serve production runtimes over HTTPS and configure [Security & Auth](/agent-os/security/overview) before connecting them.
+
+
+## Runtime setup
+
+Each Control Plane view depends on capabilities exposed by the connected runtime.
+
+| Capability | Runtime setup |
+|------------|---------------|
+| Chat and workflow runs | Agents, teams, or workflows registered with AgentOS |
+| Sessions, memories, metrics, and evaluations | An AgentOS database |
+| Traces | `tracing=True` and a database available to AgentOS tracing |
+| Studio | A `Registry` and a synchronous AgentOS `db` |
+| Approvals | An AgentOS `db` and approval-enabled tools |
+| Scheduled execution | An AgentOS `db` and `scheduler=True` |
+
+## Developer Resources
+
+- [AgentOS overview](/agent-os/introduction)
+- [AgentOS API surface](/features/api)
+- [Control Plane guide](/agent-os/control-plane)
+- [AgentOS tracing](/agent-os/tracing/overview)
+- [Security & Auth](/agent-os/security/overview)
diff --git a/features/evaluation.mdx b/features/evaluation.mdx
new file mode 100644
index 000000000..dace778e5
--- /dev/null
+++ b/features/evaluation.mdx
@@ -0,0 +1,73 @@
+---
+title: Agent Evaluation
+description: "Catch regressions in response quality, tool use, latency, and memory."
+---
+
+Changes to models, instructions, tools, and knowledge can introduce regressions. Agno evals turn response criteria and expected tool use into executable cases. Run them during development, gate CI with their exit code, and evaluate selected production outputs through hooks.
+
+```python evals.py
+import sys
+
+from agno.agent import Agent
+from agno.eval import Case, cli
+from agno.tools.calculator import CalculatorTools
+
+calculator = Agent(
+ id="calculator",
+ model="openai:gpt-5.5",
+ tools=[CalculatorTools()],
+ instructions="Use the calculator tools for every calculation.",
+)
+
+CASES = (
+ Case(
+ name="factorial_uses_calculator",
+ agent=calculator,
+ input="What is 10 factorial?",
+ criteria="States that 10 factorial equals 3,628,800.",
+ expected_tool_calls=("factorial",),
+ ),
+)
+
+if __name__ == "__main__":
+ sys.exit(cli(CASES))
+```
+
+Create a virtual environment, install the OpenAI integration, and set `OPENAI_API_KEY` before running the suite:
+
+```bash
+uv venv --python 3.12
+uv pip install -U "agno[openai]"
+```
+
+```bash
+uv run python evals.py --json-output tmp/evals.json
+```
+
+Each case runs the component once and applies the configured judge and reliability checks to the same output. The CLI returns a nonzero exit code when a case fails, so the suite can gate CI.
+
+## Evaluation types
+
+| Type | Measures | Guide |
+|------|----------|-------|
+| Accuracy | Correctness against an expected answer | [Accuracy evals](/evals/accuracy/overview) |
+| Agent as judge | Custom quality criteria scored by an evaluator model | [Agent-as-judge evals](/evals/agent-as-judge/overview) |
+| Reliability | Expected tool calls and arguments | [Reliability evals](/evals/reliability/overview) |
+| Performance | Runtime latency and memory use | [Performance evals](/evals/performance/overview) |
+
+## Where evals run
+
+| Stage | Pattern |
+|-------|---------|
+| Local development | Run one case while changing an agent. |
+| CI | Run tagged [eval suites](/evals/suite/overview) and keep the JSON report. |
+| Production | Evaluate selected outputs with a synchronous or [background post-hook](/agent-os/usage/background-output-evaluation). |
+| AgentOS | Store eval results in a configured database and manage them through the AgentOS API. |
+
+## Next steps
+
+| Task | Guide |
+|------|-------|
+| Build an eval suite | [Eval suites](/evals/suite/overview) |
+| Add evals to an agent platform | [Agent platform evals](/agent-platform/evals) |
+| Inspect the API surface | [Agent API](/features/api) |
diff --git a/features/interfaces.mdx b/features/interfaces.mdx
index dbad95f5d..330378929 100644
--- a/features/interfaces.mdx
+++ b/features/interfaces.mdx
@@ -1,11 +1,11 @@
---
title: Interfaces
-description: "Slack, Telegram, WhatsApp, Discord, plus protocol interfaces for agents and browsers."
+description: "Connect agents to chat channels, browser applications, and agent protocols."
---
-An interface is an adapter between AgentOS and a surface where users already are. It receives events from Slack, Telegram, WhatsApp, or other channels, maps them onto AgentOS's run and session model, and routes responses back to the right thread, channel, or user.
+Product and support teams can expose the same component in an application, team chat, and customer channels. AgentOS interfaces connect components to Slack, Telegram, WhatsApp, A2A, and AG-UI. Each interface handles surface-specific routing and session IDs. Chat interfaces verify their own webhooks; protocol interfaces use AgentOS authorization when it is enabled.
-The agent doesn't change. The same agent definition answers a Slack DM, a Telegram message, and an AG-UI browser stream. Memory follows the user across surfaces when the interfaces resolve to the same `user_id`.
+Session history stays tied to each surface's `session_id`.
## Available interfaces
@@ -74,19 +74,11 @@ Every interface maps surface state to AgentOS sessions, so a conversation in Sla
| A2A | A2A context ID | JWT subject, or request metadata when anonymous |
| AG-UI | Client thread ID | JWT subject, or client-supplied when anonymous |
-### Resolving Slack user IDs
-
-By default Slack hands you opaque user IDs like `U07ABCXYZ`. Set `resolve_user_identity=True` to use the member's email as `user_id` when Slack provides one:
-
-```python
-Slack(agent=agent, token=..., signing_secret=..., resolve_user_identity=True)
-```
-
-The interface calls `users.info`, uses the returned email as `user_id`, and adds the display name to run metadata. It falls back to the Slack user ID when no email is available. This option is off by default and adds a Slack API call per message.
+Slack can resolve a member's email as `user_id` when `resolve_user_identity=True`. See the [Slack interface guide](/agent-os/interfaces/slack/introduction) for identity and permission setup.
## One agent, many surfaces
-A single agent can answer on every surface at once. Memory follows the user across surfaces, provided you can map their Slack ID to the same `user_id` the AG-UI client passes:
+A single agent can answer on every surface at once:
```python
agent_os = AgentOS(
@@ -101,11 +93,11 @@ agent_os = AgentOS(
)
```
-The questions the agent answered in Slack last week show up in its memory when the user opens the AG-UI widget on your website. Session history stays scoped to each surface's `session_id`, and interfaces pass surface context along with the run, like the Slack channel name.
+When user memory is enabled and each interface resolves the same person to the same `user_id`, stored memories are available across surfaces. Session history stays scoped to each surface's `session_id`, and interfaces pass surface context along with the run, such as the Slack channel name.
## Conditional registration
-Don't register interfaces you don't have credentials for:
+Register optional interfaces only when their credentials are available:
```python
interfaces = []
@@ -119,13 +111,13 @@ if TELEGRAM_TOKEN:
agent_os = AgentOS(agents=[agent], db=db, interfaces=interfaces)
```
-The [Scout](/deploy/templates/scout/overview), [Dash](/deploy/templates/dash/overview), and [Coda](/deploy/templates/coda/overview) apps use this pattern. Slack only loads when both env vars are set, so dev runs without credentials don't crash.
+The [Scout](/deploy/templates/scout/overview), [Dash](/deploy/templates/dash/overview), and [Coda](/deploy/templates/coda/overview) apps use this pattern. The Slack interface loads when both environment variables are set, which keeps development runs working before optional channel credentials are configured.
## Custom interfaces and one-off webhooks
-The interface API is small. Subclass `BaseInterface`, return your routes from `get_router`, and dispatch incoming messages to the agent. See [BaseInterface](https://github.com/agno-agi/agno/blob/main/libs/agno/agno/os/interfaces/base.py) for the full surface.
+Subclass `BaseInterface`, return your routes from `get_router`, and dispatch incoming messages to the agent. See [BaseInterface](https://github.com/agno-agi/agno/blob/main/libs/agno/agno/os/interfaces/base.py) for the full surface.
-For one-off webhooks (a CRM event, a GitHub action, a custom dashboard), don't write an interface. Add a route directly to the FastAPI app:
+Add a route directly to the FastAPI app for an application-specific webhook such as a CRM event, GitHub action, or custom dashboard:
```python
app = agent_os.get_app()
@@ -136,4 +128,7 @@ async def handle_stripe(event: dict):
return {"ok": True, "response": response.content}
```
-A custom interface is for surfaces you'll reuse across agents and OS instances. A direct route is for one-off integrations.
+| Need | Pattern |
+|------|---------|
+| Reusable surface shared across AgentOS applications | Subclass `BaseInterface` |
+| One application-specific event source | Add a FastAPI route |
diff --git a/features/observability.mdx b/features/observability.mdx
index dd1d7a961..d64f8045a 100644
--- a/features/observability.mdx
+++ b/features/observability.mdx
@@ -1,9 +1,9 @@
---
title: Agent Observability
-description: "Store OpenTelemetry traces and spans in your configured database."
+description: "Trace agent, team, and workflow runs across models, tools, and steps."
---
-AgentOS comes with a built-in tracing provider that routes every run to your own database. There's no observability service to sign up for and no tracing API key to manage.
+A production agent run can cross models, tools, team members, and workflow steps. Platform teams use traces to explain an unexpected answer, locate a slow call, and follow a failure to its source. AgentOS instruments those runs with OpenTelemetry, stores trace data in your configured database, and renders the same trace tree in the Control Plane.
```python
from agno.os import AgentOS
@@ -15,7 +15,7 @@ agent_os = AgentOS(
)
```
-`tracing=True` turns on OpenTelemetry instrumentation for agent, team, and workflow runs. Every run produces a trace tree: spans for the LLM call, each tool, team delegation, and workflow step. The database exporter writes the aggregate trace to `agno_traces` and individual spans to `agno_spans`.
+`tracing=True` instruments supported agent, team, and workflow operations. Each instrumented run produces spans for model calls, tool executions, team coordination, and workflow steps. AgentOS writes the aggregate trace to `agno_traces` and individual spans to `agno_spans`.
## Where trace data goes
diff --git a/features/runtime.mdx b/features/runtime.mdx
index 2e28c3699..12f9662c4 100644
--- a/features/runtime.mdx
+++ b/features/runtime.mdx
@@ -1,15 +1,9 @@
---
title: "Agent Runtime"
-description: "Serve agents through a stateless FastAPI runtime with database persistence and optional auth."
+description: "Run agents, teams, and workflows through FastAPI with persistence, streaming, authorization, and observability."
---
-AgentOS runs agents, teams, and workflows as an API service. A production runtime needs to:
-
-1. Run components on demand through API requests or interfaces such as Slack and Telegram.
-2. Maintain sessions across minutes, days, or weeks.
-3. Preserve state across restarts, replicas, and infrastructure failures.
-4. Protect application routes from unauthenticated access.
-5. Record runs and actions for monitoring.
+Platform teams use AgentOS to turn agents into services that handle concurrent requests, preserve state across replicas, and expose production controls from one runtime. AgentOS runs agents, teams, and workflows through FastAPI with streaming, background execution, persistence, auth, tracing, scheduling, and chat or protocol interfaces.
AgentOS serves native Agno components and adapters for the Claude Agent SDK, LangGraph, DSPy, and Antigravity.
diff --git a/features/scheduling.mdx b/features/scheduling.mdx
index 034103f9a..414afaaa1 100644
--- a/features/scheduling.mdx
+++ b/features/scheduling.mdx
@@ -1,11 +1,9 @@
---
title: Scheduling
-description: "Built-in cron for triggering recurring tasks."
+description: "Run agents, teams, and workflows on recurring schedules with persisted history and retry controls."
---
-AgentOS comes with a built-in cron-style scheduler. Use it to run morning briefings, daily triage, weekly digests, hourly health checks. Agents can also manage their own schedules through tool calls.
-
-Registered schedules live in the AgentOS database (`agno_schedules` table). The scheduler runs in the same FastAPI process as your agents. No separate worker.
+Recurring work such as daily briefs, queue triage, repository syncs, health checks, and reports should use the same runtime as on-demand runs. AgentOS stores schedules and run history in the platform database, invokes existing agent, team, or workflow endpoints, and lets agents manage schedules through `SchedulerTools`.
```python
from agno.os import AgentOS
@@ -18,7 +16,7 @@ agent_os = AgentOS(
)
```
-The scheduler polls `agno_schedules` every `scheduler_poll_interval` seconds, fires due jobs, retries failures up to each schedule's `max_retries`, and persists state.
+The scheduler runs inside the AgentOS process and polls `agno_schedules` every `scheduler_poll_interval` seconds. Keep at least one scheduler-enabled runtime running continuously. Due jobs retry failures up to each schedule's `max_retries`, and every attempt is persisted.
The scheduler fires a due job by calling its endpoint over HTTP, against `http://127.0.0.1:7777` by default. That matches the default `serve()` port. Set `scheduler_base_url` to match when you serve on a different host or port; otherwise schedules fire against the wrong URL.
@@ -79,59 +77,18 @@ async def lifespan(app):
agent_os = AgentOS(agents=[agent], db=db, scheduler=True, lifespan=lifespan)
```
-`if_exists="update"` makes the call idempotent. Re-running on restart updates the existing schedule rather than raising or duplicating. Pass `"skip"` if you want to leave manually-edited schedules alone, or `"raise"` (the default) to surface accidental name collisions. This is the pattern Coda uses for [daily digest and repo sync](/deploy/templates/coda/overview).
-
-## Workflows for multi-step jobs
-
-Schedules fire single endpoints. When the work is multi-step (research, then outline, then draft, then review), you reach for a workflow. Workflows are a separate primitive, but they're the most common thing a schedule fires.
-
-A workflow is a typed pipeline whose steps run in order. Use `Parallel` for concurrent steps, `Loop` for repetition, and `Router` to select one branch.
-
-```python
-from agno.workflow import Loop, Step, Workflow
-
-workflow = Workflow(
- name="content_pipeline",
- steps=[
- Step(name="research", agent=researcher),
- Step(name="outline", agent=outliner),
- Loop(
- name="draft_review",
- steps=[
- Step(name="draft", agent=writer),
- Step(name="review", agent=editor),
- ],
- end_condition='last_step_content.contains("APPROVED")',
- max_iterations=3,
- ),
- ],
-)
-```
-
-`Loop.end_condition` accepts a CEL expression string (as above) or a callable that takes the iteration's step outputs and returns a bool. `Condition` is a separate primitive for if/else branching inside a workflow.
-
-
-CEL string conditions need the optional `cel-python` dependency: `pip install cel-python` or `pip install 'agno[cel]'`. Without it, the expression logs an error, evaluates to `False`, and the loop runs to `max_iterations`. The callable form has no extra dependency.
-
-
-Registered workflows get a `POST /workflows//runs` endpoint and can be scheduled. Session history is persisted when the workflow has a database. Traces are stored when AgentOS tracing is enabled.
+`if_exists="update"` makes restarts idempotent by updating the existing schedule. Pass `"skip"` to preserve manually edited schedules or `"raise"` (the default) to surface accidental name collisions. This is the pattern Coda uses for [daily digest and repo sync](/deploy/templates/coda/overview).
-| Pattern | Use when |
-|---------|----------|
-| **Sequential** | Steps depend on each other |
-| **Parallel** | Steps are independent and you want fanout |
-| **Loop with condition** | Quality threshold or max iterations |
-| **Router + Condition** | Dynamic branching on input |
-| **Cross-modal chaining** | Output of one agent is input to a different modality (text → speech, code → narration) |
+## Schedule a workflow
-For worked examples, see [Demo OS](https://github.com/agno-agi/demo-os).
+Schedules invoke endpoints. Point a schedule at `/workflows//runs` when recurring work has multiple steps, branches, or review loops. See [Workflow Automation](/use-cases/workflow-automation) and [Workflows](/workflows/overview).
## Schedule runs and observability
When a schedule fires, AgentOS:
-1. Looks up the schedule in `agno_schedules` and claims it via a row-level lease.
-2. Calls the configured endpoint (`POST /agents//runs` or `POST /workflows//runs`) over HTTP via `httpx.AsyncClient`. This is the same path an external caller would take, including auth headers.
+1. Looks up the schedule in `agno_schedules` and claims it through a database-backed lease.
+2. Calls the configured endpoint (`POST /agents//runs`, `POST /teams//runs`, or `POST /workflows//runs`) over HTTP via `httpx.AsyncClient`. This is the same path an external caller would take, including auth headers.
3. Records the schedule attempt in `agno_schedule_runs` with status, timings, the underlying `run_id` and `session_id` when returned, and any error. The target component persists its run according to its database configuration. Traces require tracing to be enabled.
Schedule runs are queryable from `agno_schedule_runs`. When the target component persists sessions and AgentOS tracing is enabled, the linked run also appears in session and trace views. This Postgres query lists runs fired in the last 24 hours:
@@ -152,6 +109,6 @@ The `ai.` prefix is the schema `PostgresDb` creates its tables in by default (ov
## Scheduler in HA
-Every replica can run the scheduler loop safely on the backends that implement the scheduler's claim methods (Postgres, SQLite, and MongoDB). Due schedules are claimed via a row-level lease (`locked_by`, `locked_at` on `agno_schedules`). The first replica to claim a due job runs it; the others skip. No leader election needed.
+Every replica can run the scheduler loop safely on the backends that implement the scheduler's claim methods: Postgres, SQLite, and MongoDB. Due schedules are claimed through an atomic database-backed lease. The first replica to claim a due job runs it; the others skip.
-If you'd rather keep scheduler polling off your hot request path, pin it to a dedicated replica via deployment config. See [Scheduler](/agent-os/scheduler/overview) for tuning details.
+Deployment configuration can pin scheduler polling to a dedicated replica. See [Scheduler](/agent-os/scheduler/overview) for tuning details.
diff --git a/features/sdk.mdx b/features/sdk.mdx
index 946e59a5c..fe47fc8d6 100644
--- a/features/sdk.mdx
+++ b/features/sdk.mdx
@@ -1,9 +1,9 @@
---
title: Agent SDK
-description: "Build your agent platform in pure Python."
+description: "Build agents, teams, and workflows in Python with composable models, tools, memory, knowledge, and guardrails."
---
-Agno is a Python SDK for building agents and multi-agent systems. It provides three primitives (agents, teams, and workflows) plus capabilities such as storage, memory, knowledge, learning, and compression. A primitive and its capabilities form a component in your agent platform. Everything is pure Python. No new DSL to learn, no YAML to manage.
+The Agno SDK gives engineering teams Python primitives for agents, multi-agent teams, and explicit workflows, plus composable models, tools, memory, knowledge, learning, and guardrails. Each configured primitive remains a regular Python object that can run directly or be served through AgentOS.
```bash
uv pip install -U "agno[openai,sqlite]"
@@ -26,7 +26,7 @@ workbench = Agent(
workbench.print_response("Inventory this folder.")
```
-An agent (the primitive) with a model, tools, storage, and session history (the capabilities) is a component you can serve on the AgentOS runtime.
+`workbench` is a component: an agent primitive configured with a model, tools, storage, and session history. AgentOS serves the same object as a runtime component.
## Primitives
@@ -73,16 +73,14 @@ An agent (the primitive) with a model, tools, storage, and session history (the
| Capability | What it adds |
|------------|--------------|
-| [Background execution](/background-execution/overview) | Long-running runs that don't block your API |
+| [Background execution](/background-execution/overview) | Continue long-running work after the initial API request returns |
| [Evals](/evals/overview) | Measure accuracy, performance, and reliability; agent-as-judge |
| [Observability](/observability/overview) | Tracing with Langfuse, Logfire, Arize, The Context Company, and 12+ providers |
| [Scheduler](/scheduler/overview) | Run agents, teams, and workflows on recurring schedules |
## Components
-A primitive + capabilities + configuration becomes a live **component** of your agent platform.
-
-You can create components in code, through a no-code UI, or via the AgentOS API. Change code-defined components in Python. Components created via the API or no-code UI have draft and published configuration versions that you can promote or roll back. The `/components` API lets you build, version, and operate components over HTTP.
+Agents, teams, and workflows become runnable **components** once you add their models, tools, state, and configuration. Code-defined components stay in Python. Components created in Studio or through the `/components` API use draft and published versions, with a `current` version that you can promote or roll back.
### Versioned components
diff --git a/features/security-and-auth.mdx b/features/security-and-auth.mdx
index 61819a605..7b84c2a99 100644
--- a/features/security-and-auth.mdx
+++ b/features/security-and-auth.mdx
@@ -1,9 +1,17 @@
---
title: Security & Auth
-description: "Configure JWT authentication, RBAC scopes, request isolation, and per-user data isolation."
+description: "Protect AgentOS APIs with JWT verification, scoped permissions, request isolation, and per-user data boundaries."
---
-AgentOS security works in layers: JWT authentication at the edge, scope-based authorization per endpoint, per-request component copies, and opt-in per-user data isolation. Network controls and database permissions cover the rest.
+Teams serving agents to employees or customers need identity, permissions, and user data boundaries at the runtime. AgentOS verifies JWTs, enforces scopes per endpoint, creates a fresh component copy for core run endpoints, and can scope persistent user data to the JWT subject. Tokens can come from the Control Plane, your backend, or an external identity provider.
+
+| Boundary | Control |
+|----------|---------|
+| Caller identity | JWT signature verification; set `verify_audience=True` to enforce the `aud` claim |
+| API access | Scopes enforced per endpoint |
+| Run state | Fresh component copy for core run endpoints, with some resources shared by reference |
+| Persistent user data | Opt-in reads, writes, and ownership checks scoped to the JWT subject |
+| Network and database | Reverse proxy controls and database permissions configured by the deployment |
@@ -36,7 +44,7 @@ A small set of public routes are exempt from the JWT requirement: `/`, `/health`
- Open [os.agno.com](https://os.agno.com) → **Add OS** → **Live** → paste your URL. Enable JWT authorization when connecting a new AgentOS, or later from the OS Settings page.
+ Open [os.agno.com](https://os.agno.com) → **Connect OS** → **Live** → paste your URL. Enable JWT authorization when connecting a new AgentOS, or later from the OS Settings page.
@@ -103,11 +111,11 @@ The AgentOS control plane mints each token with the appropriate scopes. Scopes a
## Request isolation
-Each run request gets a fresh copy of the agent, team, or workflow it's hitting. AgentOS calls `deep_copy()` on the registered component before the run, so mutable per-run state (session-scoped variables, tool execution context, run metadata) never bleeds between concurrent calls.
+Core run endpoints start each run from a fresh copy of the registered agent, team, or workflow. AgentOS calls `deep_copy()` and copies mutable fields when possible.
-Heavy resources (the database connection, the model client, MCP tool handles) are shared by reference; only the mutable per-run state is isolated. You get cheap concurrency without two requests racing on the same in-memory agent instance.
+Models, databases, knowledge resources, MCP tool handles, and some tools are shared by reference so their connections and pools remain available. A field that cannot be copied also falls back to the original value. Custom tools and objects shared this way must be safe for concurrent use.
-This is on by default for run endpoints. There's nothing to configure.
+The copy happens automatically on core run endpoints. Review mutable state in custom tools and objects before serving concurrent traffic.
## User isolation
diff --git a/features/storage.mdx b/features/storage.mdx
index 0eedb0cfd..01a7c938c 100644
--- a/features/storage.mdx
+++ b/features/storage.mdx
@@ -1,11 +1,11 @@
---
title: "Agent Storage"
-description: "Store sessions, memory, knowledge, and traces in a supported database backend."
+description: "Persist agent sessions, memory, knowledge, traces, approvals, schedules, evaluations, and metrics."
---
-Agents persist the data they generate and use in a database, set by the `db` param: sessions, memory, knowledge metadata, traces, schedules, approvals, learnings, and usage metrics.
+Agent state has to remain available across conversations, restarts, and replicas. Agents, teams, workflows, and AgentOS share a `db` interface for sessions, memory, learnings, knowledge metadata, traces, schedules, approvals, evaluations, and metrics.
-The primitives (agents, teams, workflows) and the AgentOS accept a `db` param. Pick from JSON files (local or cloud), embedded (SQLite), relational (Postgres, MySQL), document (MongoDB, Firestore), key-value (Redis, Valkey, DynamoDB), or distributed (SingleStore).
+The `db` parameter accepts JSON file, embedded, relational, document, key-value, and distributed backends.
```python
from agno.db.postgres import PostgresDb
@@ -31,8 +31,7 @@ AgentOS creates the tables and indexes on first boot. Set `auto_provision_dbs=Fa
| `agno_schedules`, `agno_schedule_runs` | Cron jobs |
| `agno_metrics`, `agno_eval_runs` | Metrics and eval results |
-- Backend-specific names may vary.
-- Schema changes are generally additive.
+Backend-specific table and collection names may vary.
## Pick a backend
@@ -40,16 +39,16 @@ Most tutorials use `PostgresDb`. Pair it with `PgVector` when you want relationa
| Backend | When to use |
|---------|-------------|
-| [`PostgresDb`](/database/providers/postgres/overview) | Production. Vector + relational on one box. |
+| [`PostgresDb`](/database/providers/postgres/overview) | Production runtime state; pair with `PgVector` for embeddings |
| [`SqliteDb`](/database/providers/sqlite/overview) | Local dev, single-user demos, edge deployments |
| [`MongoDb`](/database/providers/mongo/overview) | Already on Mongo |
| [`MySQLDb`](/database/providers/mysql/overview) | Already on MySQL |
-| [`SingleStoreDb`](/database/providers/singlestore/overview) | Vector + analytics on one engine, high-throughput |
-| [`RedisDb`](/database/providers/redis/overview) | Cache-friendly, ephemeral sessions |
-| [`ValkeyDb`](/database/providers/valkey/overview) | Cache-friendly, ephemeral sessions |
+| [`SingleStoreDb`](/database/providers/singlestore/overview) | Existing SingleStore infrastructure and high-throughput runtime state |
+| [`RedisDb`](/database/providers/redis/overview) | Existing Redis infrastructure and high-throughput key-value access |
+| [`ValkeyDb`](/database/providers/valkey/overview) | Existing Valkey infrastructure and high-throughput key-value access |
| [`DynamoDb`](/database/providers/dynamodb/overview) | AWS-native, serverless |
| [`FirestoreDb`](/database/providers/firestore/overview) | GCP-native, serverless |
-| [`JsonDb`](/database/providers/json/overview) | Local JSON files, no server to run |
+| [`JsonDb`](/database/providers/json/overview) | Local JSON file storage |
| [`GcsJsonDb`](/database/providers/gcs/overview) | JSON-backed records in Google Cloud Storage |
| [`InMemoryDb`](/database/providers/in-memory/overview) | Tests, ephemeral demos |
@@ -57,7 +56,7 @@ Postgres-compatible managed services like [Neon](/database/providers/neon/overvi
## Vector storage
-Knowledge needs a vector store, and Agno supports 15+ vector databases out of the box.
+Knowledge uses a vector store for embedding search.
```python
from agno.knowledge import Knowledge
@@ -78,7 +77,7 @@ agent = Agent(
Other options: LanceDB, Qdrant, Weaviate, Pinecone, Chroma, MongoDB Atlas, Cosmos, Cassandra, ClickHouse, SurrealDB, Milvus. See [Vector Stores](/knowledge/vector-stores/index).
-For most production AgentOS deployments, **PgVector + PostgresDb on the same Postgres** is the right default: one database with hybrid search and transactional reads, and no extra service to operate.
+For production deployments already using Postgres, pair `PostgresDb` with `PgVector` to keep runtime state and hybrid search in one Postgres service.
## Splitting concerns across databases
@@ -103,4 +102,10 @@ Common splits include separate tenant databases, a high-traffic agent on its own
## File and blob storage
-For media that doesn't belong in the relational store (generated images, audio, large PDFs), store them in object storage and reference paths in `agno_knowledge` or `agno_sessions`.
+Store generated images, audio, and large PDFs in object storage, then reference their paths in `agno_knowledge` or `agno_sessions`.
+
+## Developer Resources
+
+- [Database overview](/database/overview)
+- [Vector stores](/knowledge/vector-stores/index)
+- [Database migrations](/agent-os/usage/database-migrations)
diff --git a/index.mdx b/index.mdx
index 81bb5bac3..241f033ff 100644
--- a/index.mdx
+++ b/index.mdx
@@ -52,18 +52,7 @@ AgentOS runs your agent platform as a FastAPI application in your cloud. The fas
-## Common use cases
+Get started
-| Team | Use cases |
-|------|-----------|
-| Product | Product copilots, chatbots, and agentic application features |
-| ML and AI | Data labeling, extraction, classification, synthetic data, and eval generation |
-| Data science | Data enrichment, segmentation, and training data curation |
-| Data engineering | Data quality audits, failure analysis, and recurring reports |
-
-## Get started
-
-| Task | Guide |
-|------|-------|
-| Build your first agent | [First Agent](/first-agent) |
-| Build an agent platform with a coding agent | [Agent Platform](/agent-platform/overview) |
+- [Build your first agent](/first-agent) with the Agno SDK.
+- [Build your agent platform](/agent-platform/overview) with a coding agent.
diff --git a/use-cases/coding-agents.mdx b/use-cases/coding-agents.mdx
new file mode 100644
index 000000000..1edb4a24e
--- /dev/null
+++ b/use-cases/coding-agents.mdx
@@ -0,0 +1,139 @@
+---
+title: Coding Agents
+sidebarTitle: Coding Agents
+description: "Build coding agents that inspect repositories, edit files, run commands, and verify changes."
+---
+
+Coding agents handle repository work that starts with reading the project and ends with verified changes. Agno gives engineering teams scoped workspaces, command boundaries, approval gates, background runs, and a production API for these agents.
+
+```python coding_agent.py
+import tempfile
+from pathlib import Path
+
+from agno.agent import Agent
+from agno.tools.coding import CodingTools
+
+project = Path(tempfile.mkdtemp(prefix="coding-agent-"))
+
+(project / "math_utils.py").write_text(
+ "def factorial(n: int) -> int:\n"
+ " return 1 if n <= 1 else n * factorial(n - 1)\n"
+)
+
+(project / "test_math_utils.py").write_text(
+ "import unittest\n\n"
+ "from math_utils import factorial\n\n\n"
+ "class TestFactorial(unittest.TestCase):\n"
+ " def test_factorial(self):\n"
+ " self.assertEqual(factorial(5), 120)\n\n\n"
+ "if __name__ == '__main__':\n"
+ " unittest.main()\n"
+)
+
+coding_agent = Agent(
+ name="Coding Agent",
+ model="openai:gpt-5.5",
+ tools=[
+ CodingTools(
+ base_dir=project,
+ restrict_to_base_dir=True,
+ all=True,
+ allowed_commands=["python3"],
+ )
+ ],
+ instructions=[
+ "Read existing files before changing them.",
+ "Make focused edits.",
+ "Run the test suite after every change.",
+ "Report the files changed and the final test result.",
+ ],
+)
+
+coding_agent.print_response(
+ "Update factorial() to reject negative inputs, add a regression test, "
+ "then run python3 -m unittest -v.",
+ stream=True,
+)
+```
+
+Create a virtual environment, install the OpenAI integration, and set `OPENAI_API_KEY` before running the agent:
+
+```bash
+uv venv --python 3.12
+uv pip install -U "agno[openai]"
+export OPENAI_API_KEY="your_openai_api_key"
+uv run python coding_agent.py
+```
+
+The example creates a fresh fixture on every run. `base_dir` scopes file operations to that directory. `allowed_commands` limits shell entry points to `python3`.
+
+
+`base_dir` limits file paths. The process still inherits the host environment, network access, and operating-system permissions. Run untrusted code inside a dedicated container, virtual machine, or remote sandbox.
+
+
+
+To give Codex, Claude Code, Cursor, or another client access to Agno documentation, see [Connect your coding agent](/coding-agents).
+
+
+## Common patterns
+
+| Pattern | Agent task |
+|---------|------------|
+| Repository onboarding | Map the project and answer questions with file references. |
+| Bug fixing | Reproduce a failure, make a focused change, and rerun the failing tests. |
+| Code review | Inspect a diff, run targeted checks, and return prioritized findings. |
+| Dependency upgrades | Update a dependency, resolve compatibility failures, and run the project gates. |
+| CI remediation | Read failure logs, reproduce the failure, patch the cause, and verify the fix. |
+| Migrations | Apply repeatable changes across files and report unresolved cases. |
+
+## Choose the execution boundary
+
+| Requirement | Use |
+|-------------|-----|
+| Compact tools for a trusted local project | [`CodingTools`](/tools/toolkits/local/coding) with a scoped `base_dir` and narrow `allowed_commands`. |
+| Read-only repository analysis | [`Workspace`](/tools/toolkits/local/workspace) with `allowed=["read", "list", "search"]`. |
+| Approval before edits or shell commands | `Workspace` with its default confirmation policy and `require_read_before_write=True`. |
+| Execute untrusted code remotely | [Daytona](/tools/toolkits/others/daytona) or [E2B](/tools/toolkits/others/e2b). |
+| Execute untrusted code on your infrastructure | Run the agent inside a dedicated container or virtual machine. |
+
+## Define the engineering loop
+
+| Stage | Boundary |
+|-------|----------|
+| Understand | Read and search the relevant files before proposing a change. |
+| Change | Keep edits focused and require confirmation when the workspace is not disposable. |
+| Verify | Run the repository's tests, lint, type checks, and build inside the execution environment. |
+| Review | Return changed files, command results, and unresolved risks. |
+| Publish | Keep commits, pushes, pull requests, and deployments outside the default loop or expose them as separately gated tools. |
+
+## Production path
+
+| Need | Agno capability |
+|------|-----------------|
+| Serve coding tasks through an API | Register the agent with [AgentOS](/agent-os/overview). |
+| Continue after the client disconnects | Use [background execution](/background-execution/overview). |
+| Pause before edits or shell commands | Use `Workspace` confirmation with [AgentOS HITL](/agent-os/usage/hitl). |
+| Authenticate CI and machine callers | Mint a scoped [service account](/agent-os/security/authorization/service-accounts). |
+| Inspect model calls, tool arguments, and failures | Configure a database and enable [observability](/features/observability). |
+| Catch behavioral regressions | Run coding tasks against fresh fixture repositories with an [eval suite](/evals/suite/overview). |
+
+## Evaluate coding agents
+
+| Quality layer | Check |
+|---------------|-------|
+| Project gates | Compile the project and run its unit, integration, lint, and type checks inside the execution environment. |
+| Reliability | Verify required tool calls such as reading the target file and running the test command. |
+| Agent as judge | Score whether the change follows the request, stays in scope, and explains its verification. |
+| Performance | Track end-to-end runtime and memory use. |
+
+Restore the fixture before every eval case so one run cannot affect the next.
+
+## Next steps
+
+| Task | Guide |
+|------|-------|
+| Configure the compact coding toolkit | [CodingTools](/tools/toolkits/local/coding) |
+| Add confirmation-gated workspace access | [Workspace](/tools/toolkits/local/workspace) |
+| Isolate remote execution | [Daytona](/tools/toolkits/others/daytona) or [E2B](/tools/toolkits/others/e2b) |
+| Add behavioral regression cases | [Agent Evaluation](/features/evaluation) |
+| Serve the agent in production | [Agent API](/features/api) |
diff --git a/use-cases/customer-support.mdx b/use-cases/customer-support.mdx
new file mode 100644
index 000000000..a72b7e37b
--- /dev/null
+++ b/use-cases/customer-support.mdx
@@ -0,0 +1,114 @@
+---
+title: Customer Support Agents
+sidebarTitle: Customer Support
+description: "Resolve customer requests with specialist routing, product knowledge, controlled actions, and human escalation."
+---
+
+Support and product teams use agents when resolving a request requires conversation history, approved product knowledge, live customer data, or actions in another system. Agno combines persistent sessions, specialist teams, tools, approval gates, and human escalation in one runtime.
+
+```python support_team.py
+from agno.agent import Agent
+from agno.db.sqlite import SqliteDb
+from agno.team import Team
+
+model = "openai:gpt-5.5"
+
+billing = Agent(
+ name="Billing Support",
+ role="Answer questions about invoices, payments, subscriptions, and refunds.",
+ model=model,
+)
+
+technical = Agent(
+ name="Technical Support",
+ role="Diagnose product errors and provide troubleshooting steps.",
+ model=model,
+)
+
+support_team = Team(
+ name="Customer Support",
+ model=model,
+ members=[billing, technical],
+ db=SqliteDb(db_file="tmp/support.db"),
+ add_history_to_context=True,
+ num_history_runs=5,
+ instructions=[
+ "Route each request to the relevant specialist.",
+ "Consult both specialists when an issue crosses billing and product behavior.",
+ ],
+)
+
+support_team.print_response(
+ "My card was charged twice after checkout returned HTTP 500.",
+ user_id="customer-42",
+ session_id="ticket-1842",
+)
+```
+
+Create a virtual environment, install the OpenAI and SQLite integrations, and set `OPENAI_API_KEY` before running the team:
+
+```bash
+uv venv --python 3.12
+uv pip install -U "agno[openai,sqlite]"
+uv run python support_team.py
+```
+
+The team can consult both specialists for this request. Reuse the `session_id` for later messages on the same ticket and the `user_id` for the same customer. Add confirmation-required tools before permitting account changes or refunds.
+
+## Build the resolution path
+
+| Stage | Agno capability | Purpose |
+|-------|-----------------|---------|
+| Receive | [AgentOS API](/features/api) or [interfaces](/features/interfaces) | Accept requests from a product, Slack, WhatsApp, or another service. |
+| Identify | [Sessions](/sessions/overview) and [authorization](/agent-os/security/overview) | Associate the request with a customer, preserve its conversation history, and establish the caller's identity. |
+| Ground | [Knowledge](/knowledge/overview) and [context providers](/context-providers/overview) | Search approved product content and retrieve current account or order data. |
+| Route | [Teams](/teams/overview) or [workflows](/workflows/overview) | Select a specialist or follow a fixed triage policy. |
+| Act | [Tools](/tools/overview) and [human-in-the-loop](/hitl/overview) | Create tickets, update records, or request approval for sensitive work. |
+| Improve | [Learning](/learning/overview), [evaluation](/features/evaluation), and [observability](/features/observability) | Reuse resolved cases, measure quality, and inspect failures. |
+
+## Choose the execution model
+
+| Requirement | Use |
+|-------------|-----|
+| One support policy and one set of tools | [Agent](/agents/overview) |
+| Dynamic routing among billing, technical, and account specialists | [Team](/teams/overview) |
+| Deterministic triage, service-level rules, or escalation steps | [Workflow](/workflows/overview) |
+
+Teams let the model choose the relevant specialist. Workflows encode branches and required steps in code. A support system can use a workflow for intake and escalation, with a team inside a step for specialist investigation.
+
+## Set action boundaries
+
+| Action | Boundary |
+|--------|----------|
+| Answer from approved product documentation | Give the agent read-only knowledge. |
+| Read an order, subscription, or account | Establish the caller's identity, enforce account-level access inside the provider or tool, and keep it read-only. |
+| Change a plan, issue a refund, or cancel an order | Require [confirmation](/hitl/user-confirmation) before the tool runs. |
+| Create an engineering ticket with missing fields | Request [user input](/hitl/user-input) before the tool runs. |
+| Send an external message | Gate the send tool and record the action in the run history. |
+
+## Serve support channels
+
+| Channel | Guide |
+|---------|-------|
+| Product UI or backend | [Serve as an API](/use-cases/product-agents/serve-as-an-api) |
+| Slack | [Support team](/agent-os/usage/interfaces/slack/support-team) |
+| WhatsApp | [WhatsApp interface](/agent-os/interfaces/whatsapp/introduction) |
+| Custom clients | [AgentOS client](/agent-os/client/overview) |
+
+## Improve from resolved requests
+
+| Goal | Pattern |
+|------|---------|
+| Preserve the current ticket | Reuse its `session_id` and store session history. |
+| Remember customer preferences | Store user-scoped [memory](/memory/overview). |
+| Reuse successful resolutions | Start with the [support learning pattern](/examples/learning/patterns/support-agent). Configure a tenant-scoped namespace for every shared production store. |
+| Monitor response quality | Run [background output evaluation](/agent-os/usage/background-output-evaluation). |
+| Prevent regressions | Add support conversations to an [eval suite](/evals/suite/overview). |
+
+## Next steps
+
+| Task | Guide |
+|------|-------|
+| Route technical and general requests through fixed branches | [Conditional workflow example](/examples/workflows/conditional-execution/condition-with-else) |
+| Collect ticket fields from a Slack requester | [Human input example](/examples/agent-os/interfaces/slack/hitl-user-input) |
+| Connect live customer systems | [Connecting your data](/use-cases/product-agents/connecting-your-data) |
diff --git a/use-cases/data-agents/grounding-in-context.mdx b/use-cases/data-agents/grounding-in-context.mdx
index 7ced6daca..6eb779465 100644
--- a/use-cases/data-agents/grounding-in-context.mdx
+++ b/use-cases/data-agents/grounding-in-context.mdx
@@ -3,7 +3,7 @@ title: "Grounding in context"
description: "Ground every query in validated SQL, table metadata, and business rules."
---
-A model knows SQL but it does not know that `revenue` was replaced by `revenue_v2` last March, that "active" excludes trialing accounts, or that MRR is computed net of credits. Grounding provides the missing context. The agent retrieves the relevant context for each question before it writes a line of SQL.
+Data agents need your table history and business definitions to write reliable SQL. Add validated queries, table metadata, and business rules to the agent's knowledge. The agent retrieves the relevant context before writing SQL.
```bash
uv pip install "agno[openai,pgvector,psycopg,sql]"
@@ -39,9 +39,9 @@ agent = Agent(
agent.print_response("How many active subscriptions are on the Pro plan?")
```
-With `knowledge` attached, the agent searches it per question and pulls only the matching context, instead of carrying the entire data dictionary in every prompt. Knowledge search is on by default. Set `search_knowledge=False` to turn it off.
+With `knowledge` attached, the agent searches it for each question and retrieves the matching context. Knowledge search is on by default. Set `search_knowledge=False` to turn it off.
-## The layers worth curating
+## Context to curate
A production data agent grounds each answer in several layers. The first set is curated and stored in a vector database. The rest are live.
@@ -54,18 +54,18 @@ A production data agent grounds each answer in several layers. The first set is
| Learnings | Fixes the agent captured from past errors | Live, see [Self-correcting agents](/use-cases/data-agents/self-correcting-agents) |
| Runtime schema | `describe_table` at query time | Live |
-## Validated queries are the highest-leverage layer
+## Start with validated queries
-One known-good query for "monthly recurring revenue" is worth more than a page of schema notes. When the agent retrieves a validated query for a similar question, it adapts a correct shape instead of inventing one. Seed the store with the queries your analysts already trust: the question, the SQL, the tables used, and any data-quality notes.
+Validated queries give the agent a trusted starting point for recurring questions such as monthly recurring revenue. For a related request, the agent can retrieve a known-good query and adapt its structure. Store the question, SQL, tables used, and data-quality notes for queries your analysts already trust.
## Grounding vs raw text-to-SQL
| Raw text-to-SQL | Grounded data agent |
|-----------------|---------------------|
| Guesses column meaning from names | Reads curated table metadata |
-| Reinvents each query from scratch | Adapts a validated query |
-| "Active" means whatever the model assumes | "Active" means what your business rule says |
-| Wrong in a way that looks right | Wrong in a way you can trace to a missing rule |
+| Generates each query from schema alone | Adapts a validated query when one matches |
+| Infers business meaning | Applies curated business definitions |
+| Depends on implicit assumptions | Uses retrieved rules and query patterns |
## Next steps
diff --git a/use-cases/data-agents/materialization.mdx b/use-cases/data-agents/materialization.mdx
index 0e599d4e0..ef2c46ae9 100644
--- a/use-cases/data-agents/materialization.mdx
+++ b/use-cases/data-agents/materialization.mdx
@@ -3,17 +3,17 @@ title: "Materialization"
description: "Turn validated recurring queries into reusable views in an agent-owned schema."
---
-The third time someone asks "what's MRR by plan," the agent should be reading a view it built the first time. Materialization is the data agent turning recurring questions into durable, reusable structure in a schema it owns.
+Materialization turns recurring, validated queries into reusable views in an agent-owned schema. Later requests can read the same view and use consistent query logic.
## The pattern
-A recurring question is a signal. The agent promotes it from an ad-hoc query to a view in an agent-managed schema, then answers from the view.
+A recurring question is a candidate for a view. The agent promotes the validated query to an agent-managed schema and answers future requests from that view.
1. A question repeats, or a query gets validated as correct.
2. The agent proposes the view and a human approves the write.
3. The Engineer builds the view in its own schema (for example `dash`), never in `public`.
4. The new object's schema and an example query go into knowledge, so later runs can discover it.
-5. The next ask reads the view directly, which is faster, cheaper, and consistent across users.
+5. The next request reads the view directly and uses the same query logic across users.
```bash
uv pip install "agno[openai,psycopg,sql]"
@@ -42,35 +42,35 @@ engineer = Agent(
Configure `dash_writer` as a non-owner role with read access to source data and write access only to `dash`. `requires_confirmation_tools` pauses every `run_sql_query` call. After the client continues the run with approval, `SQLTools` executes the statement. The role's grants must enforce the schema boundary because `SQLTools` does not restrict SQL by schema.
-After creation, add the object's columns, purpose, and example queries to the agent's knowledge, so later runs discover the view instead of rebuilding the query. Attach the `knowledge` store from [grounding](/use-cases/data-agents/grounding-in-context) to the Engineer and set `update_knowledge=True`. That gives the agent an `add_to_knowledge` tool, which writes the description back into the same store it searches.
+After creation, add the object's columns, purpose, and example queries to the agent's knowledge so later runs can discover the view. Attach the `knowledge` store from [grounding](/use-cases/data-agents/grounding-in-context) to the Engineer and set `update_knowledge=True`. That gives the agent an `add_to_knowledge` tool, which writes the description back into the same store it searches.
## Why an agent-owned schema
-The agent writes structure, so that structure needs a sandbox. A dedicated schema keeps generated views away from the tables your product depends on.
+Give generated views a dedicated schema. This keeps them separate from the tables your product depends on.
| | `public` (your data) | `dash` (agent-owned) |
|--|----------------------|----------------------|
| Who writes | Your application and pipelines | The Engineer agent only |
| Holds | Source tables | Generated views and summary tables |
-| Blast radius of a bad write | Catastrophic | Contained, droppable, rebuildable |
+| Effect of an incorrect write | Production tables may be affected | Limited to generated objects; the schema can be rebuilt |
-Because the schema is disposable, a wrong view is a cheap mistake. Drop it and let the agent rebuild.
+Treat the agent-owned schema as rebuildable. Review and drop incorrect views, then generate them again.
## Materialize from validated queries
-The best materialization candidates are the validated queries from [grounding](/use-cases/data-agents/grounding-in-context). A query analysts already trust, asked often, is exactly what should become a view. Review the generated DDL before approving the write.
+Validated queries from [grounding](/use-cases/data-agents/grounding-in-context) are good materialization candidates. A frequently requested query that analysts already trust can become a view. Review the generated DDL before approving the write.
A regular view evaluates its query when read. Summary tables and materialized views need explicit refresh logic; this example does not schedule that work.
-## How it compounds
+## Reuse validated work
-Each repeat question promoted to a view is one less query generated from scratch:
+Reusable views reduce repeated query generation:
- Captured corrections inform later runs ([self-correction](/use-cases/data-agents/self-correcting-agents)).
- Validated query shapes sit in the knowledge stores ([grounding](/use-cases/data-agents/grounding-in-context)).
-- The agent-owned schema accumulates the views your team relies on, with no hand-written migration.
+- The agent-owned schema stores reusable views for recurring questions.
-Repeated work becomes structure instead of recomputation, so the agent gets faster and more consistent the more it is used.
+Each approved view gives later runs a consistent query path for the same question.
## Next steps
diff --git a/use-cases/data-agents/overview.mdx b/use-cases/data-agents/overview.mdx
index a2c0c0a28..fd51ca71f 100644
--- a/use-cases/data-agents/overview.mdx
+++ b/use-cases/data-agents/overview.mdx
@@ -1,10 +1,10 @@
---
title: "Data and analytics agents"
sidebarTitle: "Overview"
-description: "Agents that work on your data, grounded in business context."
+description: "Build agents that query operational data, apply business definitions, and return the SQL behind each answer."
---
-Data agents query operational data, apply business definitions, and can return the SQL behind an answer. Reliable implementations combine curated context, captured corrections, and database-enforced write boundaries.
+Data and analytics teams use agents to make operational data accessible through plain-language questions and keep business definitions consistent across teams. Agno combines SQL tools, curated context, reusable corrections, and database-enforced access boundaries so each answer can include its query and apply the same definitions.
## Where to start
diff --git a/use-cases/data-agents/querying-your-data.mdx b/use-cases/data-agents/querying-your-data.mdx
index c9303582b..c78832e5a 100644
--- a/use-cases/data-agents/querying-your-data.mdx
+++ b/use-cases/data-agents/querying-your-data.mdx
@@ -40,7 +40,7 @@ The agent's `db` and the `SQLTools` connection are separate. `db` stores the age
## Introspect before generating
-A data agent that guesses column names is wrong confidently. `SQLTools` ships `list_tables` and `describe_table` so the agent grounds SQL in the real schema. The instruction to introspect first is what makes it reliable.
+`SQLTools` provides `list_tables` and `describe_table` so the agent can read the current schema before generating SQL. The instruction above makes schema introspection part of each request.
| Tool | Use |
|------|-----|
diff --git a/use-cases/data-agents/safe-data-access.mdx b/use-cases/data-agents/safe-data-access.mdx
index b20aeacd5..f81bb2b21 100644
--- a/use-cases/data-agents/safe-data-access.mdx
+++ b/use-cases/data-agents/safe-data-access.mdx
@@ -3,7 +3,7 @@ title: "Safe data access"
description: "Enforce read and write boundaries with database permissions and transaction settings."
---
-A prompt that says "only run SELECT" is a suggestion. A connection that cannot write is a guarantee. A production data agent answers from a read-only connection and isolates any writes to a schema it owns. The boundary holds even when the model goes off-script.
+Enforce read-only access with database roles and grants. Use a separate connection with schema-scoped permissions for approved write operations. These controls remain in effect when model output is unexpected.
```bash
uv pip install "agno[openai,psycopg,sql]"
@@ -28,11 +28,11 @@ analyst = Agent(
)
```
-Create the `readonly` role without write grants before using this connection. The `default_transaction_read_only=on` setting blocks ordinary write statements, but it is a configurable session default. Database ownership and grants remain the security boundary.
+Create the `readonly` role without write grants before using this connection. The `default_transaction_read_only=on` setting blocks ordinary write statements. This setting is a configurable session default. Database ownership and grants remain the security boundary.
## Split the roles
-Most data-agent questions are read-only. Writes (building a summary table, recording a correction) are rarer and riskier. Separate them into different agents on different connections.
+Most data-agent questions are read-only. Separate approved writes, such as building a summary table or recording a correction, into agents with dedicated connections.
| Member | Connection | Can do | Cannot do |
|--------|-----------|--------|-----------|
@@ -56,7 +56,7 @@ def materialize_view(name: str, sql: str) -> str:
...
```
-For a dedicated writer built on `SQLTools`, set `requires_confirmation_tools=["run_sql_query"]`. That pauses every call to the tool, reads included, so a narrow custom write tool gives finer control. Gate the irreversible actions and leave reads ungated, so approval fatigue does not set in.
+For a dedicated writer built on `SQLTools`, set `requires_confirmation_tools=["run_sql_query"]`. This pauses every call to the tool, including reads. A narrow custom write tool gives finer control. Gate irreversible actions and leave reads ungated so approval fatigue does not set in.
## Layers of defense
diff --git a/use-cases/data-agents/serve-and-embed.mdx b/use-cases/data-agents/serve-and-embed.mdx
index abdd2b28e..14dab61d6 100644
--- a/use-cases/data-agents/serve-and-embed.mdx
+++ b/use-cases/data-agents/serve-and-embed.mdx
@@ -1,9 +1,9 @@
---
title: "Serve and embed"
-description: "Put the data agent behind an API so a dashboard, a Slack channel, or a product widget can ask it questions."
+description: "Serve a data agent through AgentOS for use in dashboards, Slack, and product interfaces."
---
-A data agent that only runs in a notebook helps one analyst. Behind an API, it answers questions from a Slack channel, a BI dashboard's natural-language box, or an "explain this metric" widget in your product. `AgentOS` turns the agent into that API.
+`AgentOS` exposes the data agent through a FastAPI application. Slack, BI dashboards, scheduled jobs, and product widgets can call the same agent endpoint.
```python data_agent.py
from agno.agent import Agent
@@ -37,7 +37,7 @@ curl -X POST http://localhost:7777/agents/data-agent/runs \
-F 'stream=false'
```
-## Surfaces a data agent lives on
+## Where to use a data agent
| Surface | Shape |
|---------|-------|
@@ -46,7 +46,7 @@ curl -X POST http://localhost:7777/agents/data-agent/runs \
| Scheduled digest | A cron job runs the agent and posts "yesterday's numbers" every morning |
| Backend check | A pipeline calls the agent to sanity-check a metric before publishing |
-The serving model is identical to a [product agent](/use-cases/product-agents/serve-as-an-api). The difference is what the agent does, not how it is served. `user_id` and `session_id` select the conversation history for a run.
+Data agents use the same serving model as [product agents](/use-cases/product-agents/serve-as-an-api). `user_id` and `session_id` select the conversation history for a run.
This example leaves AgentOS authorization disabled. Callers can supply their own user and session identifiers. Enable AgentOS authorization before network exposure, and connect `SQLTools` with a database role that enforces read-only access.
@@ -54,7 +54,7 @@ The serving model is identical to a [product agent](/use-cases/product-agents/se
## Shared learnings, separate sessions
-A data agent's value compounds when corrections are shared across the team. Conversation threads stay scoped by `user_id` and `session_id`. `learning=True` only enables the per-user profile and memory stores, so to share what the agent learns, pass a knowledge base to `LearningMachine` instead. That enables the [Learned Knowledge store](/learning/stores/learned-knowledge), whose namespace defaults to `"global"`, so a fix triggered by one analyst's question helps everyone.
+Share diagnosed warehouse corrections across the team while keeping conversation threads scoped by `user_id` and `session_id`. `learning=True` enables the per-user profile and memory stores. To share corrections, pass a knowledge base to `LearningMachine`. This enables the [Learned Knowledge store](/learning/stores/learned-knowledge), whose namespace defaults to `"global"`.
```python
from agno.knowledge import Knowledge
diff --git a/use-cases/data-labeling/classification.mdx b/use-cases/data-labeling/classification.mdx
index 4d09e5063..823892f80 100644
--- a/use-cases/data-labeling/classification.mdx
+++ b/use-cases/data-labeling/classification.mdx
@@ -3,7 +3,7 @@ title: "Classification and span labeling"
description: "Assign one label, a set of labels, a taxonomy path, or marked spans."
---
-Classification is extraction where the schema is a closed set. Use a `Literal` for one label, a `List[Literal]` for many.
+Use a `Literal` for one label and a `List[Literal]` for multiple labels.
```python
from typing import Literal
@@ -29,7 +29,7 @@ result = agent.run("It works as described, nothing special.").content
# Classification(label='neutral')
```
-The `Literal` constrains the model to the closed set. There is no invalid label to clean up downstream.
+The `Literal` constrains the result to the labels defined in the schema.
## Multi-label
@@ -51,7 +51,7 @@ class Tagging(BaseModel):
## Hierarchical
-For a taxonomy, return the path instead of a flat label.
+For a taxonomy, return the parent and child path.
```python
from typing import List, Literal
@@ -138,7 +138,7 @@ Image, audio, video, and document classification follow the same schema pattern
| Task | Guide |
|------|-------|
-| Extract fields instead of labels | [Data extraction](/use-cases/data-labeling/structured-extraction) |
+| Extract typed fields | [Data extraction](/use-cases/data-labeling/structured-extraction) |
| Score outputs against a rubric | [LLM as judge](/use-cases/data-labeling/llm-as-judge) |
| Add reviewer agreement | [Quality pipeline](/use-cases/data-labeling/quality-pipeline) |
diff --git a/use-cases/data-labeling/image-search.mdx b/use-cases/data-labeling/image-search.mdx
new file mode 100644
index 000000000..4b3b3c641
--- /dev/null
+++ b/use-cases/data-labeling/image-search.mdx
@@ -0,0 +1,100 @@
+---
+title: "Build an image search application"
+sidebarTitle: "Image Search"
+description: "Describe images with an agent, index the descriptions in PgVector, and search the collection from a browser UI."
+---
+
+Run the complete Image Search application from the Agno repository:
+
+```bash
+uv venv .venvs/image_search --python 3.12
+source .venvs/image_search/bin/activate
+uv pip install -e "libs/agno[os,google]" "fastapi[standard]" pgvector "psycopg[binary]"
+./cookbook/scripts/run_pgvector.sh
+export GOOGLE_API_KEY="..."
+fastapi dev cookbook/data_labeling/image_search/run.py --port 7777
+```
+
+Open [http://localhost:7777/ui](http://localhost:7777/ui), then click **Reindex** to label and index the configured images.
+
+## Application structure
+
+The application registers one `Knowledge` instance and one ingest workflow with AgentOS. A small FastAPI route serves the browser UI.
+
+```python
+from agno.os import AgentOS
+from db import get_knowledge
+from fastapi import FastAPI
+from workflows.ingest import ingest_workflow
+
+
+base_app = FastAPI(title="Image Search")
+
+agent_os = AgentOS(
+ id="image_search",
+ name="Image Search",
+ knowledge=[get_knowledge()],
+ workflows=[ingest_workflow],
+ base_app=base_app,
+)
+
+app = agent_os.get_app()
+```
+
+| Part | Implementation |
+|------|----------------|
+| Label | A Gemini agent returns an `ImageDescription` with a caption, subjects, scene, visual style, and tags. |
+| Index | `to_searchable_text()` flattens those fields into the text sent to `GeminiEmbedder`. |
+| Search | `PgVector` combines vector and keyword search with `SearchType.hybrid`. |
+| Metadata | `Knowledge` stores the image URL and structured description for the gallery. |
+| Ingest | A `Workflow` downloads each image, creates a searchable description, and stores the embedded description, structured metadata, and source URL. |
+| UI | A single HTML file renders the gallery, search results, and reindex status. |
+
+## Search-tuned labels
+
+The schema separates fields that help with different queries:
+
+```python
+from typing import List
+
+from pydantic import BaseModel, Field
+
+
+class ImageDescription(BaseModel):
+ caption: str
+ subjects: List[str] = Field(default_factory=list)
+ scene: str
+ visual_style: str
+ tags: List[str] = Field(default_factory=list)
+```
+
+The caption captures a natural description. Subjects and tags add the concrete terms users search for. Scene and visual style support queries about setting, lighting, mood, and composition.
+
+## Reindex behavior
+
+Reindexing performs a full rebuild. The workflow removes the existing knowledge content, then processes every URL in `IMAGE_URLS` with a bounded thread pool. This makes prompt and schema changes visible across the complete demo collection.
+
+The workflow uses `PostgresDb` so AgentOS can persist background workflow runs. The same Postgres instance stores knowledge content, while PgVector stores embeddings and serves hybrid search.
+
+## Routes
+
+| Action | Route |
+|--------|-------|
+| Open the UI | `GET /ui` |
+| List gallery content | `GET /knowledge/content` |
+| Search the image index | `POST /knowledge/search` |
+| Start a reindex run | `POST /workflows/image-ingest/runs` |
+
+## Next steps
+
+| Task | Guide |
+|------|-------|
+| Build the minimal extract-and-index pipeline | [Data extraction](/use-cases/data-labeling/structured-extraction#extract-then-index) |
+| Define a different media schema | [Multimodal inputs](/use-cases/data-labeling/multimodal-inputs) |
+| Configure knowledge search | [Knowledge](/knowledge/overview) |
+
+## Developer Resources
+
+- [Image Search source](https://github.com/agno-agi/agno/tree/main/cookbook/data_labeling/image_search)
+- [Image extraction to vector database cookbook](https://github.com/agno-agi/agno/tree/main/cookbook/data_labeling/_09_image_extraction_to_vectordb)
+- [AgentOS](/agent-os/introduction)
diff --git a/use-cases/data-labeling/llm-as-judge.mdx b/use-cases/data-labeling/llm-as-judge.mdx
index ecab5487f..147ed4d9d 100644
--- a/use-cases/data-labeling/llm-as-judge.mdx
+++ b/use-cases/data-labeling/llm-as-judge.mdx
@@ -73,11 +73,11 @@ class RubricScore(BaseModel):
| One quality number | `int` with `ge=1, le=5` |
| Number plus justification | Add a `rationale` field |
| Per-criterion breakdown | One bounded `int` field per dimension |
-| A vs B instead of a score | [Preference data](/use-cases/data-labeling/preference-data) |
+| Pairwise comparison | [Preference data](/use-cases/data-labeling/preference-data) |
## Relationship to evals
-This is the same primitive as single-label classification, pointed at model outputs instead of raw data. When the judge is the deliverable, it lives here. When it scores a system under test, see [Evals](/evals/overview).
+This applies a classification schema to model outputs. When the judge is the deliverable, it lives here. When it scores a system under test, see [Evals](/evals/overview).
## Next steps
diff --git a/use-cases/data-labeling/multimodal-inputs.mdx b/use-cases/data-labeling/multimodal-inputs.mdx
index 71598e7a5..04a600de4 100644
--- a/use-cases/data-labeling/multimodal-inputs.mdx
+++ b/use-cases/data-labeling/multimodal-inputs.mdx
@@ -3,7 +3,7 @@ title: "Multimodal inputs"
description: "Feed images, audio, video, and PDFs into any labeling or extraction agent."
---
-Every labeler on the other pages takes text. To label other modalities, change the input argument and the model. The schema and the `output_schema` pattern stay the same.
+Pass media through the matching `Agent.run()` argument and choose a model that supports the input modality. The `output_schema` pattern stays the same.
```python
from typing import Literal
@@ -89,7 +89,7 @@ class BoundingBox(BaseModel):
```
-The per-field `description` on `x`, `y`, `width`, and `height` is load-bearing. Without it, and without the `[0, 1]` convention spelled out in the instructions, models return degenerate boxes (all-zero or whole-image). Spell out the coordinate system in both places.
+State the `[0, 1]` coordinate system in both the field descriptions and the agent instructions. This keeps the four values consistent across images.
The [bounding boxes cookbook](https://github.com/agno-agi/agno/tree/main/cookbook/data_labeling/_08_image_bounding_boxes) has runnable single-object, multi-object, and per-box confidence variants.
diff --git a/use-cases/data-labeling/overview.mdx b/use-cases/data-labeling/overview.mdx
index 59cef9628..b704278e3 100644
--- a/use-cases/data-labeling/overview.mdx
+++ b/use-cases/data-labeling/overview.mdx
@@ -1,27 +1,15 @@
---
title: "Data labeling and classification"
sidebarTitle: "Overview"
-description: "Label and classify text, images, audio, video, and PDFs."
+description: "Classify data, extract records, build preference datasets, and review labels with agents."
---
-Agents can:
-
-- Turn text, images, audio, video, and PDFs into structured records.
-- Assign labels, label sets, taxonomy paths, and labeled spans.
-- Score and rank model outputs for evals and preference data.
-- Add a reviewer and an adjudicator when label quality matters.
-
-Each task follows a similar pattern: an agent with an `output_schema`.
-
-`Agent.run()` accepts text and media inputs. Set `output_schema` to validate the response against a Pydantic model.
-
-## Example
+ML and data teams use agents to turn large collections of unstructured inputs into datasets for training, evaluation, search, and automation. Agno applies the same Pydantic schema pattern across text, images, audio, video, and PDFs, with workflows for parallel labeling, review, and conditional adjudication.
```python
from typing import Literal
from agno.agent import Agent
-from agno.models.google import Gemini
from pydantic import BaseModel, Field
@@ -32,7 +20,7 @@ class Classification(BaseModel):
agent = Agent(
- model=Gemini(id="gemini-3.5-flash"),
+ model="google:gemini-3.5-flash",
instructions="You classify product reviews by sentiment.",
output_schema=Classification,
)
@@ -41,68 +29,41 @@ result = agent.run("Broken on arrival, total waste of money.").content
# Classification(label='negative')
```
-Swap the schema and instructions and the same pattern covers data extraction, span labeling, scoring, and preference ranking.
-
-
+`Agent.run()` validates the response against the Pydantic model. Change the schema and instructions to extract fields, label spans, score responses, or rank preferences.
-If you're looking to jump straight into code, the [data labeling cookbook](https://github.com/agno-agi/agno/tree/main/cookbook/data_labeling) contains 40+ runnable recipes across 18 data labeling patterns.
+## What you can build
-
+| Outcome | Input | Pattern |
+|---------|-------|---------|
+| Classify feedback, support requests, or documents | Text or files | [Classification](/use-cases/data-labeling/classification) |
+| Extract contacts, line items, action items, or attributes | Any supported modality | [Data extraction](/use-cases/data-labeling/structured-extraction) |
+| Detect entities and PII spans | Text | [Classification and span labeling](/use-cases/data-labeling/classification) |
+| Search an image library in natural language | Images | [Image Search](/use-cases/data-labeling/image-search) |
+| Build pairwise preference datasets | Prompt and two responses | [Preference data](/use-cases/data-labeling/preference-data) |
+| Score generated responses against a rubric | Prompt and response | [LLM as judge](/use-cases/data-labeling/llm-as-judge) |
+| Review and adjudicate important labels | Any labeling task | [Quality pipeline](/use-cases/data-labeling/quality-pipeline) |
+| Label images, audio, video, and PDFs | Media or files | [Multimodal inputs](/use-cases/data-labeling/multimodal-inputs) |
-## Data labeling workflows
+The [data labeling cookbook](https://github.com/agno-agi/agno/tree/main/cookbook/data_labeling) contains 18 labeling patterns and a complete Image Search application. The patterns cover text, image, audio, video, and document inputs.
-Pick the page that matches what you need.
+## Run the examples
-| Workload | Input | Output | Page |
-|----------|-------|--------|------|
-| Data extraction | Any modality | Typed Pydantic object | [Data extraction](/use-cases/data-labeling/structured-extraction) |
-| Classification | Any modality | One label, label set, or spans | [Classification](/use-cases/data-labeling/classification) |
-| Scoring / evaluation | Prompt + response | Rubric scores | [LLM as judge](/use-cases/data-labeling/llm-as-judge) |
-| Preference ranking | Prompt + two responses | Winner + rationale | [Preference data](/use-cases/data-labeling/preference-data) |
-| Non-text input | Image, audio, video, PDF | Any of the above | [Multimodal inputs](/use-cases/data-labeling/multimodal-inputs) |
-| Reviewed labels | Any input | Adjudicated label + audit trail | [Quality pipeline](/use-cases/data-labeling/quality-pipeline) |
-
-## Model choice
-
-The cookbooks use `gemini-3.5-flash` for text, image, audio, video, and PDF examples. A replacement model must support the input modality and structured output used by the recipe.
-
-To run the examples, install the Google provider and set your API key:
+Create an environment and install the Google provider:
```bash
-pip install -U "agno[google]"
-export GOOGLE_API_KEY=***
+uv venv .venv --python 3.12
+source .venv/bin/activate
+uv pip install "agno[google]"
+export GOOGLE_API_KEY="..."
```
-The [Quality pipeline](/use-cases/data-labeling/quality-pipeline) runs its second labeler, reviewer, and adjudicator on Anthropic for provider diversity. That page needs a second provider and key:
+The quality review workflow also uses Anthropic:
```bash
-pip install -U "agno[anthropic]"
-export ANTHROPIC_API_KEY=***
+uv pip install "agno[anthropic]"
+export ANTHROPIC_API_KEY="..."
```
-## Explore
-
-
-
- Turn any modality into a typed object, with optional per-field confidence.
-
-
- Single-label, multi-label, hierarchical, and span labeling.
-
-
- Score outputs against a rubric. The same machinery, used for evals.
-
-
- Rank A vs B for RLHF and DPO datasets.
-
-
- Feed images, audio, video, and PDFs into any labeler.
-
-
- Two labelers, a reviewer, and an adjudicator with an audit trail.
-
-
-
## Developer Resources
- [Data labeling cookbook](https://github.com/agno-agi/agno/tree/main/cookbook/data_labeling)
diff --git a/use-cases/data-labeling/quality-pipeline.mdx b/use-cases/data-labeling/quality-pipeline.mdx
index afdd69b26..f1737429f 100644
--- a/use-cases/data-labeling/quality-pipeline.mdx
+++ b/use-cases/data-labeling/quality-pipeline.mdx
@@ -1,122 +1,101 @@
---
-title: "Quality pipeline"
-description: "Two labelers from different providers, a reviewer that diffs them, and an adjudicator that resolves disagreement."
+title: "Quality review pipeline"
+description: "Run two labelers concurrently, persist each workflow run, and adjudicate disagreements."
---
-Run two labelers from different providers, compare their outputs, and adjudicate where they disagree. Persist the disagreement report when you need an audit trail.
+Use a `Workflow` to run two labelers in parallel, review their outputs, and call an adjudicator when the reviewer finds a disagreement. The [complete cookbook](https://github.com/agno-agi/agno/blob/main/cookbook/data_labeling/_18_quality_review/basic.py) defines the schemas, agents, and executor functions used in this workflow composition:
```python
-from typing import List, Optional
-
-from agno.agent import Agent
-from agno.models.anthropic import Claude
-from agno.models.google import Gemini
-from pydantic import BaseModel, Field
-
-
-class Contact(BaseModel):
- name: Optional[str] = None
- email: Optional[str] = None
- company: Optional[str] = None
-
-
-class FieldDisagreement(BaseModel):
- field: str = Field(..., description="Top-level Contact field name")
- value_a: Optional[str] = None
- value_b: Optional[str] = None
- reason: str = Field(..., description="Why this field needs adjudication")
-
-
-class DisagreementReport(BaseModel):
- disagreements: List[FieldDisagreement] = Field(default_factory=list)
- needs_adjudication: bool = Field(..., description="True if any field disagrees")
-
-
-class FinalLabel(BaseModel):
- contact: Contact
- notes: Optional[str] = None
-
-
-LABELER = "Extract contact info. Use exactly what the text shows. Null if missing."
-
-labeler_a = Agent(model=Gemini(id="gemini-3.5-flash"), instructions=LABELER, output_schema=Contact)
-labeler_b = Agent(model=Claude(id="claude-opus-4-7"), instructions=LABELER, output_schema=Contact)
-
-reviewer = Agent(
- model=Claude(id="claude-opus-4-7"),
- instructions=(
- "Compare two labelers' Contact outputs field by field. A field "
- "needs adjudication whenever the values differ, including when one "
- "value is null. Set "
- "needs_adjudication=true if any field does."
- ),
- output_schema=DisagreementReport,
+from agno.db.sqlite import SqliteDb
+from agno.workflow import Step, Workflow
+from agno.workflow.condition import Condition
+from agno.workflow.parallel import Parallel
+
+
+label_a = Step(name="Labeler A", agent=labeler_a)
+label_b = Step(name="Labeler B", agent=labeler_b)
+review = Step(name="Reviewer", executor=run_reviewer)
+adjudicate = Step(name="Adjudicator", executor=run_adjudicator)
+
+workflow = Workflow(
+ name="Quality review labeling",
+ db=SqliteDb(db_file="tmp/labeling.db"),
+ steps=[
+ Parallel(label_a, label_b, name="Label"),
+ review,
+ Condition(
+ name="Adjudicate",
+ evaluator=has_disagreement,
+ steps=[adjudicate],
+ ),
+ ],
)
+```
-adjudicator = Agent(
- model=Claude(id="claude-opus-4-7"),
- instructions=(
- "Re-read the original text and resolve every reported "
- "disagreement. Return a FinalLabel with the correct values."
- ),
- output_schema=FinalLabel,
-)
+## Execution flow
+| Step | What it does |
+|------|--------------|
+| `Parallel` | Runs a Google labeler and an Anthropic labeler concurrently against the same input. |
+| `Reviewer` | Reads both step outputs and returns a typed `DisagreementReport`. |
+| `Condition` | Reads `needs_adjudication` from the reviewer output. |
+| `Adjudicator` | Receives the original input, both labels, and the disagreement report. It runs only when the condition passes. |
+| `SqliteDb` | Persists workflow runs in `tmp/labeling.db`. |
-def label_with_quality_review(text: str) -> FinalLabel:
- a = labeler_a.run(text).content
- b = labeler_b.run(text).content
+The cookbook reviewer flags a field when both labelers return non-null, different values. Change the reviewer instructions if a null value and a populated value should also trigger adjudication.
- report = reviewer.run(
- f"Labeler A:\n{a.model_dump_json()}\n\nLabeler B:\n{b.model_dump_json()}"
- ).content
+## Pass step outputs to the reviewer
- if not report.needs_adjudication:
- return FinalLabel(contact=a, notes="Labelers agreed.")
+`StepInput.get_step_output()` finds named steps inside the `Parallel` block. The reviewer executor uses those outputs to build its prompt.
- return adjudicator.run(
- f"Original input:\n{text}\n\n"
- f"Labeler A:\n{a.model_dump_json()}\n\n"
- f"Labeler B:\n{b.model_dump_json()}\n\n"
- f"Reviewer report:\n{report.model_dump_json()}"
- ).content
+```python
+from agno.workflow.types import StepInput, StepOutput
+
+
+def run_reviewer(step_input: StepInput) -> StepOutput:
+ a = step_input.get_step_output("Labeler A").content
+ b = step_input.get_step_output("Labeler B").content
+ prompt = (
+ f"Labeler A:\n{a.model_dump_json(indent=2)}\n\n"
+ f"Labeler B:\n{b.model_dump_json(indent=2)}"
+ )
+ report = reviewer.run(prompt).content
+ return StepOutput(content=report)
```
-## The flow
+The condition reads the reviewer output from `previous_step_content`:
-1. **Two labelers, two providers.** Provider disagreement identifies records that need review.
-2. **Reviewer diffs them.** It emits one `FieldDisagreement` per conflicting field and a single `needs_adjudication` flag. Agreement short-circuits the expensive step.
-3. **Adjudicator runs only on disagreement.** It re-reads the original input with both labels and the reviewer's report, then returns the final record.
-
-Agreement does not prove that a label is correct. Measure this pipeline on a labeled validation set. Persisted disagreement rates by field, provider, and prompt version can identify areas for review.
-
-## Production composition
+```python
+def has_disagreement(step_input: StepInput) -> bool:
+ report = step_input.previous_step_content
+ return bool(report and getattr(report, "needs_adjudication", False))
+```
-The example above runs the agents sequentially so the pattern is readable. For a million-document job, wrap labelers in a `Parallel` step and gate the adjudicator behind a `Condition` in a `Workflow`. See [parallel workflows](/workflows/workflow-patterns/parallel-workflow) and [conditional workflows](/workflows/workflow-patterns/conditional-workflow).
+## Run the workflow
-## Production checklist
+From the Agno repository root:
-Agno gives you the orchestration primitives. These concerns are yours to add.
+```bash
+uv venv .venv --python 3.12
+source .venv/bin/activate
+uv pip install "agno[google,anthropic]"
+export GOOGLE_API_KEY="..."
+export ANTHROPIC_API_KEY="..."
+python cookbook/data_labeling/_18_quality_review/basic.py
+```
-| Concern | What to add |
-|---------|-------------|
-| Rate limiting | Wrap the agent call with a per-provider limiter, or front it with a gateway. Agno does not throttle outbound calls. |
-| Bounded concurrency | An `asyncio.Semaphore` around the batch fan-out. |
-| Dead-letter queue | Record failed item IDs and re-run them through a stricter pass. |
-| Idempotency | A deterministic item ID and an output-store lookup before each run. Store results by item ID and prompt version. |
-| Provider Batch APIs | Call provider batch endpoints directly when the workload needs them. Agno does not wrap these APIs. |
-| Prompt versioning | Track a `prompt_version` in run metadata so historical labels stay joinable. |
-| Authoritative cost | `RunMetrics.cost` is populated only when the provider returns it. Attach a token-rate table downstream if you need exact numbers. |
+Test the workflow against a labeled validation set before using its output. Track reviewer decisions and final labels by prompt and model version so changes remain measurable.
## Next steps
| Task | Guide |
|------|-------|
-| Build the labelers | [Data extraction](/use-cases/data-labeling/structured-extraction) |
-| Compose as a workflow | [Workflows](/workflows/overview) |
-| Run agents concurrently | [Async execution](/agents/running-agents) |
+| Define the label schema | [Data extraction](/use-cases/data-labeling/structured-extraction) |
+| Inspect workflow patterns | [Workflows](/workflows/overview) |
+| Run independent branches | [Parallel workflows](/workflows/workflow-patterns/parallel-workflow) |
+| Gate a step on a result | [Conditional workflows](/workflows/workflow-patterns/conditional-workflow) |
## Developer Resources
- [Quality review cookbook](https://github.com/agno-agi/agno/tree/main/cookbook/data_labeling/_18_quality_review)
-- [Workflows overview](/workflows/overview)
+- [Workflow reference](/reference/workflows/workflow)
diff --git a/use-cases/data-labeling/structured-extraction.mdx b/use-cases/data-labeling/structured-extraction.mdx
index c23b6b718..5d975f24c 100644
--- a/use-cases/data-labeling/structured-extraction.mdx
+++ b/use-cases/data-labeling/structured-extraction.mdx
@@ -5,10 +5,6 @@ description: "Extract typed Pydantic objects from text, images, audio, video, an
Define the schema, pass the input, get a validated object back.
-
-Use a fast, low-cost model like `gemini-3.5-flash` for high-volume extraction.
-
-
```python
from typing import Optional
@@ -42,7 +38,7 @@ result = agent.run(
# phone='+1-555-0102', company='Acme Corp.', title='VP of Marketing')
```
-The hard part is getting missing fields back as `null` instead of a hallucinated value. Spell it out in the instructions: "If a field is missing, leave it null. Do not guess."
+Tell the agent how to handle missing fields: "If a field is missing, leave it null. Do not guess."
## Nested objects
@@ -108,11 +104,7 @@ confidence_agent = Agent(
)
```
-Define the levels in the instructions. Without a rubric the model has nothing to anchor `high` against `medium`, and the confidence values come back arbitrary.
-
-
-OpenAI strict structured output rejects a `description` on a field whose type is itself a referenced model. Keep `Field(..., description=...)` off fields typed as a sub-model; put the explanation in a comment or the instructions instead.
-
+Define each confidence level in the instructions so labels use the same criteria across records.
## Any modality, same pattern
@@ -126,21 +118,24 @@ The input argument changes per modality. Use a model that supports both that mod
| Video | `videos=[Video(content=..., format="mp4")]` | [video_extraction](https://github.com/agno-agi/agno/tree/main/cookbook/data_labeling/_14_video_extraction) |
| PDF | `files=[File(url=...)]` | [document_extraction](https://github.com/agno-agi/agno/tree/main/cookbook/data_labeling/_16_document_extraction) |
-## Extract then embed
+## Extract then index
-`image_extraction_to_vectordb` extends extraction with an embed-and-store step: describe each image into a typed object, flatten it to a searchable string, embed it, and store it in LanceDb for similarity search. See the [cookbook](https://github.com/agno-agi/agno/tree/main/cookbook/data_labeling/_09_image_extraction_to_vectordb).
+The [image extraction to vector database cookbook](https://github.com/agno-agi/agno/tree/main/cookbook/data_labeling/_09_image_extraction_to_vectordb) is the minimal pipeline. It describes each image as a typed object, flattens the object into searchable text, embeds it, and stores it in LanceDb.
This recipe needs LanceDb on top of the Google provider:
```bash
-pip install lancedb tantivy
+uv pip install lancedb tantivy
```
+The [Image Search application](/use-cases/data-labeling/image-search) expands the same pattern into an ingest workflow, PgVector hybrid search, AgentOS endpoints, and a browser UI.
+
## Next steps
| Task | Guide |
|------|-------|
-| Assign labels instead of fields | [Classification](/use-cases/data-labeling/classification) |
+| Assign labels | [Classification](/use-cases/data-labeling/classification) |
+| Build a searchable image library | [Image Search](/use-cases/data-labeling/image-search) |
| Feed non-text input | [Multimodal inputs](/use-cases/data-labeling/multimodal-inputs) |
| Add a reviewer and adjudicator | [Quality pipeline](/use-cases/data-labeling/quality-pipeline) |
diff --git a/use-cases/deep-research/grounding-research.mdx b/use-cases/deep-research/grounding-research.mdx
index 7cb197631..b6859951b 100644
--- a/use-cases/deep-research/grounding-research.mdx
+++ b/use-cases/deep-research/grounding-research.mdx
@@ -1,9 +1,9 @@
---
title: "Grounding research"
-description: "Ground every agent in a mandate, a research library, and prior work, so conclusions are defensible."
+description: "Give each research agent a mandate, a shared research library, and access to prior work."
---
-Ungrounded research is confident and wrong. A research agent needs to know the rules it operates under, the body of knowledge it can draw on, and what was decided before. Agno layers these so each agent carries the right context without carrying everything.
+Ground each research agent with three forms of context: rules in the prompt, shared source material in a knowledge base, and complete prior work in an archive. Each layer supports a distinct part of the review.
| Layer | Holds | Mechanism |
|-------|-------|-----------|
@@ -13,7 +13,7 @@ Ungrounded research is confident and wrong. A research agent needs to know the r
## Layer 1: static context in the prompt
-Rules that apply to every question belong in the prompt, not in retrieval. Load them once and inject them into every agent.
+Place rules that apply to every question in the prompt. Load them once and inject them into every agent.
```python
from pathlib import Path
@@ -64,7 +64,7 @@ reply = analyst.run("What does our research say about semiconductor supply?").co
# The instruction tells the analyst to search and cite retrieved material.
```
-`search_knowledge` is on by default. The agent pulls the relevant profiles and analyses per question instead of carrying the whole library in context.
+`search_knowledge` is on by default. The agent retrieves relevant profiles and analyses for each question, which keeps the full library out of the prompt.
## Layer 3: prior work on disk
@@ -92,17 +92,17 @@ archivist = Agent(
)
```
-The agent that writes new memos gets write access; this one only receives read and search tools. Keep sensitive files outside `memos_dir` because every file under the tool's base directory may be readable.
+Give the memo writer write access. This archival agent receives read and search tools. Keep sensitive files outside `memos_dir` because every file under the tool's base directory may be readable.
-## Why three layers, not one
+## What each layer contributes
-| Without | You would lose |
-|---------|----------------|
-| The prompt | Instructions and context shared across queries |
-| RAG | A corpus too large to inline |
-| The archive | The reasoning trail behind past decisions |
+| Layer | Contribution |
+|-------|--------------|
+| Prompt | Instructions and context shared across queries |
+| RAG | Retrieval from a corpus too large to inline |
+| Archive | The reasoning trail behind past decisions |
-Each layer answers a different question: what are the rules, what do we know, what did we decide.
+Together, the layers cover operating rules, available research, and prior decisions.
## Next steps
diff --git a/use-cases/deep-research/institutional-learning.mdx b/use-cases/deep-research/institutional-learning.mdx
index a99b25468..49123ef5b 100644
--- a/use-cases/deep-research/institutional-learning.mdx
+++ b/use-cases/deep-research/institutional-learning.mdx
@@ -1,9 +1,9 @@
---
title: "Institutional learning"
-description: "Share what every review learns so the next one starts from the team's accumulated judgment."
+description: "Share reviewed insights across agents and teams through a global learning namespace."
---
-A research team that does not learn re-derives the same conclusions and repeats the same mistakes. The value compounds when an insight from one review is available to every agent on the next. Agno's `LearningMachine` with a shared store and a global namespace puts every agent's learning in one place the whole team reads from.
+Use a shared learning store to carry reviewed insights from one research cycle into the next. Agno's `LearningMachine` with a global namespace makes those learnings available to every agent and team that uses the store.
```python
from agno.agent import Agent
@@ -58,7 +58,7 @@ risk_officer.print_response(
analyst.learning_machine.learned_knowledge_store.print(query="estimate lag")
```
-The learning is available to every agent and team sharing the store. In Agentic mode, retrieve it with `search_learnings`. The `Knowledge` instance is required. Without it, saves and searches log a warning and do nothing.
+The learning is available to every agent and team sharing the store. In Agentic mode, retrieve it with `search_learnings`. A configured `Knowledge` instance backs the store. Missing knowledge configuration causes saves and searches to log a warning; state remains unchanged.
## Per-agent vs institutional
@@ -66,17 +66,17 @@ The learning is available to every agent and team sharing the store. In Agentic
|--|------------------|------------------------|
| Scope | One user across agents sharing the database | Every agent and team that shares the store |
| Namespace | Scoped by `user_id` | `"global"` |
-| Effect | The user's preferences and facts follow them | The committee remembers |
+| Effect | User preferences and facts remain available across sessions | Reviewed insights remain available across research cycles |
-For deep research, institutional is the point. The team's judgment should outlive any single review.
+Use institutional learning to keep reviewed team judgment available across research cycles.
## What to capture
-| Worth a learning | Not worth a learning |
-|------------------|----------------------|
-| "Analyst estimates lag this sector by a quarter" | A one-off number from a single query |
-| "This data source double-counts renewals" | A restatement of the mandate |
-| A correction to a conclusion that was wrong | A summary of what was already in the library |
+| Save to shared learning | Keep in context or source data |
+|-------------------------|--------------------------------|
+| "Analyst estimates lag this sector by a quarter" | One-off query results stay with the run |
+| "This data source double-counts renewals" | The mandate stays in static context |
+| A correction to a conclusion that was wrong | Source summaries stay in the research library |
Capture corrections and transferable insights. Leave durable facts to the [research library](/use-cases/deep-research/grounding-research) and rules to the static context.
@@ -88,7 +88,7 @@ Capture corrections and transferable insights. Leave durable facts to the [resea
| `AGENTIC` | The agent decides what is worth keeping | Research, where signal-to-noise matters |
| `PROPOSE` | The model proposes a learning and asks before saving; approval is prompt-based | Low-risk review where soft approval is sufficient |
-This is the same machine the [data agent uses to self-correct](/use-cases/data-agents/self-correcting-agents), pointed at a shared store instead of a per-warehouse one.
+The [data agent self-correction pattern](/use-cases/data-agents/self-correcting-agents) uses the same machine with a per-warehouse store. This research pattern uses the shared institutional store.
## Next steps
diff --git a/use-cases/deep-research/orchestration-patterns.mdx b/use-cases/deep-research/orchestration-patterns.mdx
index 367da0b6f..a7beeb3ba 100644
--- a/use-cases/deep-research/orchestration-patterns.mdx
+++ b/use-cases/deep-research/orchestration-patterns.mdx
@@ -1,11 +1,11 @@
---
title: "Orchestration patterns"
-description: "Route, coordinate, broadcast, task, or an explicit pipeline. Pick the shape the research question needs."
+description: "Choose a Team mode or Workflow based on ownership, execution order, and review requirements."
---
-A research question has a shape. A factual lookup wants one specialist. A high-stakes decision wants every specialist at once. A standardized review wants the same auditable steps every time. Agno gives you a Team mode or a Workflow for each.
+Choose the orchestration primitive from the research flow. Route a factual lookup to one specialist, broadcast a high-stakes decision to every specialist, and use a Workflow for a standardized review with an explicit step graph.
-## Pick the shape
+## Choose an orchestration pattern
| Pattern | Primitive | Best for |
|---------|-----------|----------|
@@ -42,7 +42,7 @@ answer = response.content
# response.member_responses holds each consulted member's run.
```
-The instruction asks the lead to consult the Risk Officer, but model instructions do not enforce that invariant. Put mandatory review in a `Workflow` step or an application-side gate.
+The lead receives an instruction to consult the Risk Officer. Enforce mandatory review with a `Workflow` step or an application-side gate.
## Broadcast: independent evaluations, one synthesis
@@ -65,7 +65,7 @@ broadcast_team = Team(
Set `store_member_responses=True` to persist each member's run with the team's run record.
-## Pipeline: the same steps, every time
+## Pipeline: explicit execution order
When a review needs an explicit execution path, a `Workflow` fixes the step graph. Each step's output feeds the next; independent steps run in [parallel](/use-cases/deep-research/parallel-investigation).
diff --git a/use-cases/deep-research/overview.mdx b/use-cases/deep-research/overview.mdx
index ed30f7a19..e6f7b9694 100644
--- a/use-cases/deep-research/overview.mdx
+++ b/use-cases/deep-research/overview.mdx
@@ -4,7 +4,7 @@ sidebarTitle: "Overview"
description: "Combine Team modes, Workflow steps, grounding, and typed research outputs."
---
-The gap between an agent using tools and a deep research system is orchestration, grounding, and inspectable deliverables. Agno Workflows define an explicit step graph. Run steps in parallel, in loops, or one after the other.
+Research, strategy, and investment teams use deep research systems when a question requires several independent investigations and a decision-ready deliverable. Agno combines specialist teams, explicit workflows, parallel execution, knowledge, and typed outputs so each stage and final result can be inspected.
```python
from agno.workflow import Parallel, Step, Workflow
@@ -32,28 +32,28 @@ result = investment_workflow.run("Run a full investment review on NVDA")
# result.step_results holds the output from each outer step.
```
-That is a five-step review with a parallel deep-dive. The same shape holds for other research mandates: swap the agents and the prompt. Attach a database to the Workflow to keep each run's input, step outputs, and final result.
+This review has five stages, with fundamental and technical analysis running in parallel. Replace the investment agents and prompt to apply the pattern to another research mandate. Attach a database to the Workflow to keep each run's input, step outputs, and final result.
-## Learn How To
+## Deep research patterns
Route, coordinate, broadcast, task, and explicit Workflow pipelines.
- Fan specialists out at once, synthesize the results.
+ Run independent specialists concurrently, then synthesize their results.
- Mandate in the prompt, a library in RAG, prior work on disk.
+ Give each specialist a mandate, a research library, and access to prior work.
- Return a typed decision and preserve the supporting memo.
+ Return a typed decision and preserve its supporting memo.
Share reviewed learnings through a common store and namespace.
- Put the pipeline behind an API for Slack, cron, and dashboards.
+ Expose the pipeline through AgentOS for applications, schedules, and dashboards.
diff --git a/use-cases/deep-research/parallel-investigation.mdx b/use-cases/deep-research/parallel-investigation.mdx
index 0ba820306..c1def76f2 100644
--- a/use-cases/deep-research/parallel-investigation.mdx
+++ b/use-cases/deep-research/parallel-investigation.mdx
@@ -1,9 +1,9 @@
---
title: "Parallel investigation"
-description: "Run independent specialists at the same time, then synthesize, so deep research stays fast."
+description: "Run independent specialist steps concurrently, then synthesize their results."
---
-Most research work is independent. The fundamental analyst does not need the technical analyst's output to do its job. Run them at the same time. A `Parallel` block in a Workflow does exactly that: every step inside it runs concurrently, and the pipeline waits for all of them before moving on.
+Place independent specialist steps in a Workflow `Parallel` block. Each step in the block runs concurrently, and the Workflow waits for the block to finish before continuing. In this review, fundamental and technical analysis both start after market assessment and complete before risk assessment.
```python
from agno.workflow import Parallel, Step, Workflow
@@ -33,7 +33,7 @@ final = result.content # the last step's output
# StepOutput("Risk Assessment") ]
```
-The market assessment runs first because risk and the deep dive depend on it. Fundamental and technical analysis have no dependency on each other, so they run together. Risk waits for both.
+Market assessment runs first. Fundamental and technical analysis both use that market context, so they run together. Risk assessment starts after both analyses finish.
## Two ways to fan out
@@ -44,20 +44,20 @@ The market assessment runs first because risk and the deep dive depend on it. Fu
A Broadcast team is the adaptive version: every member evaluates the same question simultaneously and the lead reconciles them. See [Orchestration patterns](/use-cases/deep-research/orchestration-patterns#broadcast-independent-evaluations-one-synthesis).
-## Sequence only what depends
+## Model the dependencies
-The skill is dependency analysis, not maximum parallelism. Put a step in `Parallel` only when it does not read another step's output. Keep the genuine dependencies sequential.
+Use the step graph to express data dependencies. Group steps that share the same prerequisite in `Parallel`. Place downstream steps after the block.
| Step | Depends on | Runs |
|------|-----------|------|
-| Market assessment | Nothing | First, alone |
+| Market assessment | Research request | First, alone |
| Fundamental analysis | Market context | In parallel with technical |
| Technical analysis | Market context | In parallel with fundamental |
| Risk assessment | Both analyses | After the parallel block |
-## Why this matters for deep research
+## Reduce research latency
-Deep research is slow because it is thorough. Parallelism keeps thoroughness affordable in wall-clock time: the two analyses above finish in roughly the time of the slower one rather than the sum of both.
+Running independent analyses concurrently reduces wall-clock latency while preserving each specialist's full analysis.
## Next steps
diff --git a/use-cases/deep-research/serve-and-embed.mdx b/use-cases/deep-research/serve-and-embed.mdx
index f18d79ca1..eac52a80d 100644
--- a/use-cases/deep-research/serve-and-embed.mdx
+++ b/use-cases/deep-research/serve-and-embed.mdx
@@ -1,9 +1,9 @@
---
title: "Serve and embed"
-description: "Put the research team and pipeline behind an API so anyone, and any schedule, can ask for a review."
+description: "Serve research agents, teams, and workflows through one AgentOS API."
---
-A research system that only runs from a script helps the person at the keyboard. Behind an API it answers from Slack, runs as a nightly review, and feeds a dashboard. `AgentOS` serves agents, teams, and workflows on the same contract.
+Serve the research workflow with AgentOS to make it available to Slack, scheduled jobs, dashboards, and backend services. Register the individual analysts, research teams, and workflow in one runtime.
```python
from agno.os import AgentOS
@@ -29,7 +29,7 @@ curl -X POST http://localhost:8000/workflows/investment-workflow/runs \
-F 'stream=false'
```
-## Where a research system lives
+## Delivery surfaces
| Surface | Shape |
|---------|-------|
@@ -38,9 +38,9 @@ curl -X POST http://localhost:8000/workflows/investment-workflow/runs \
| Dashboard | A widget triggers a review and renders the structured decision |
| Backend gate | A pipeline calls the workflow before a position changes and blocks on a PASS |
-The serving model is identical to a [product agent](/use-cases/product-agents/serve-as-an-api) and a [data agent](/use-cases/data-agents/serve-and-embed). The difference is what runs behind the endpoint, not how it is served.
+[Product agents](/use-cases/product-agents/serve-as-an-api), [data agents](/use-cases/data-agents/serve-and-embed), and research systems use the same AgentOS run endpoints. Each surface selects the registered component that matches the request.
-## Pick the entry point per request
+## Choose an entry point
| Caller wants | Hit |
|--------------|-----|
@@ -52,7 +52,7 @@ One AgentOS exposes all three. The surface chooses the shape per request.
## Scheduled research
-A scheduled workflow runs the review without anyone asking. Every morning the watchlist is reviewed, the memos are written, and the decisions are waiting.
+Use an AgentOS schedule to run a watchlist review at a fixed interval. Each run produces the workflow's memos and decisions for the team.
AgentOS ships the scheduler. Start it with `AgentOS(..., scheduler=True)` and register a cron against the workflow's run endpoint with `ScheduleManager`. See [Scheduling](/features/scheduling).
diff --git a/use-cases/deep-research/structured-deliverable.mdx b/use-cases/deep-research/structured-deliverable.mdx
index 1881da383..9c067ac27 100644
--- a/use-cases/deep-research/structured-deliverable.mdx
+++ b/use-cases/deep-research/structured-deliverable.mdx
@@ -1,9 +1,9 @@
---
title: "Structured deliverable"
-description: "End the pipeline in a typed decision: the call, the conviction, the rationale, and the citations."
+description: "Return a typed decision with the call, conviction, allocation, rationale, and citations."
---
-Research that ends in prose is hard to act on and harder to audit. The last step of a research pipeline should produce a decision with a fixed shape: the call, the conviction, the reasoning, and what it was based on. Give the final agent an `output_schema` and it returns a validated object.
+Make the final pipeline step return a typed decision that downstream code can validate and use. Define the call, conviction, allocation, rationale, and citations in a Pydantic schema, then pass it as the final agent's `output_schema`.
```python
from typing import List, Literal
@@ -43,11 +43,11 @@ result = chair.run(briefing(market, fundamentals, technicals, risk)).content
# citations=['memo:NVDA-2024Q3', 'research:semiconductors'])
```
-Because `output_schema=Decision`, the run returns a validated `Decision`. Downstream code reads `result.call` and `result.allocation_usd` without parsing text. If the model's output fails validation, Agno logs a warning and `content` stays a string, so check the type before acting on it.
+Because `output_schema=Decision`, the run returns a validated `Decision`. Downstream code reads `result.call` and `result.allocation_usd` directly. If the model's output fails validation, Agno logs a warning and `content` stays a string, so check the type before acting on it.
-The chair takes no tools. Its only job is to weigh the specialists' inputs and commit to a call.
+The chair weighs the specialists' inputs and commits to a call. Its configuration omits tools so every conclusion comes from the supplied briefing.
-## Two artifacts, two purposes
+## Decision and memo
A research system usually produces both a machine-actionable decision and a human-readable memo.
@@ -58,19 +58,19 @@ A research system usually produces both a machine-actionable decision and a huma
The memo is written by a dedicated agent with file tools and a fixed template, then archived. The next review reads it back as [prior work](/use-cases/deep-research/grounding-research). The decision is the row you store and act on.
-## Make it auditable
+## Required decision fields
-| Field | Why it earns its place |
-|-------|------------------------|
+| Field | Purpose |
+|-------|---------|
| `conviction` | Lets you threshold: act on high, queue medium for review |
-| `rationale` | The reasoning trail, required not optional |
+| `rationale` | Records the reasoning trail for review and audit |
| `citations` | Carries source identifiers for downstream verification |
-A decision without its citations is unverifiable. Require them in the schema and the instructions.
+Require citations in the schema and instructions so each decision carries source identifiers for verification.
-## Gate the irreversible
+## Add approval for consequential actions
-When a decision triggers a real action (moving capital, publishing a number), put a human in the loop on that step. Approve the call, then let automation act. See [human approval](/hitl/overview).
+When a decision triggers a real action, such as moving capital or publishing a number, add human approval before the action executes. See [human approval](/hitl/overview).
## Next steps
diff --git a/use-cases/document-processing/contracts.mdx b/use-cases/document-processing/contracts.mdx
index 5276e61d8..ac2686ef6 100644
--- a/use-cases/document-processing/contracts.mdx
+++ b/use-cases/document-processing/contracts.mdx
@@ -3,7 +3,7 @@ title: "Contracts"
description: "Parties, dates, and a clause-level breakdown for legal review queues."
---
-Contracts are denser than invoices. A header (parties, effective date, term) plus a clause list with stable categories that downstream review tooling can filter on.
+Extract parties, effective dates, terms, and clauses into a typed structure for downstream review. Use stable clause categories so review tools can filter the result.
```python
from typing import List, Literal, Optional
@@ -97,7 +97,7 @@ def route_for_review(contract: Contract) -> dict[str, list[Clause]]:
return buckets
```
-The agent does the extraction. The routing is plain Python, against a typed object. The split is auditable because each clause keeps its verbatim `text` and `page`.
+`route_for_review` operates on the typed result. Each clause retains its verbatim `text` and `page` for review.
## Diff against a template
diff --git a/use-cases/document-processing/forms-and-intake.mdx b/use-cases/document-processing/forms-and-intake.mdx
index 59bcd63dc..21ebe38fe 100644
--- a/use-cases/document-processing/forms-and-intake.mdx
+++ b/use-cases/document-processing/forms-and-intake.mdx
@@ -1,9 +1,9 @@
---
title: "Forms and intake"
-description: "Resumes, applications, KYC. Lists inside lists, same File() plumbing."
+description: "Extract nested fields from resumes, applications, and KYC documents."
---
-Forms and intake documents bring a different shape: a person's identity at the top, then several parallel lists (employment, education, skills, references). The agent fills out the nested structure in one pass.
+Forms and intake documents often combine identity fields with repeated sections such as employment, education, skills, and references. A nested Pydantic schema captures this structure in one run.
Place the resume to extract at `resume.pdf` in the directory where you run this code.
@@ -69,7 +69,7 @@ resume = agent.run(
# skills=['Python', 'PostgreSQL', 'Kubernetes', 'Terraform'])
```
-The same shape covers job applications and KYC intake. Swap the schema's outer model and the instructions; the `File()` plumbing and the agent definition do not change.
+Adapt the outer model and instructions for job applications and KYC intake. Reuse the `File` input and `Agent` configuration.
## KYC intake
@@ -134,7 +134,7 @@ class References(BaseModel):
| Resume | Identity, headline | Parallel lists: employment, education, skills | Preserve candidate wording |
| KYC | Identity | Few sub-lists; conservative typing | Keep IDs as strings |
-The agent code is the same across all four. The schema decides the workload.
+Reuse the `Agent` setup across these workloads and change `output_schema` for the document structure.
## Next steps
diff --git a/use-cases/document-processing/human-routing-and-eval.mdx b/use-cases/document-processing/human-routing-and-eval.mdx
index 1b4a0d1e4..c1f250e12 100644
--- a/use-cases/document-processing/human-routing-and-eval.mdx
+++ b/use-cases/document-processing/human-routing-and-eval.mdx
@@ -1,9 +1,9 @@
---
title: "Human routing and eval"
-description: "Confidence-gated approval and accuracy tracking against a golden set."
+description: "Route low-confidence fields for approval and track extraction accuracy against a golden set."
---
-Two production concerns the labeling docs leave open: routing low-confidence fields to a human, and tracking accuracy as the system runs over time. Both are short patterns on top of the same extraction agent.
+Document processing pipelines need a review path for low-confidence fields and a way to measure extraction quality over time. Add both to the same extraction agent.
## Per-field confidence
@@ -55,7 +55,7 @@ invoice = agent.run(
## Route on low confidence
-The trigger is plain Python. Walk the fields, find anything below threshold, and decide what to do with it.
+Walk the extracted fields, find values below the confidence threshold, and route the document in application code.
```python
def low_confidence_fields(invoice: Invoice) -> list[str]:
@@ -73,11 +73,11 @@ else:
write_to_database(invoice)
```
-The model returns confidence. Your code decides the threshold and the action.
+Treat confidence as an agent-provided routing signal. Application code sets the threshold and chooses the action.
## Gate the next action with `requires_confirmation`
-For a tighter loop, wrap the downstream action (the database write, the ERP push) in a tool that requires approval. Every call to the tool pauses the run until a human confirms it, so nothing posts to the ERP without sign-off.
+Wrap a downstream action, such as a database write or ERP push, in a tool that requires approval. Every call pauses the run until a human confirms it. This places approval at the system boundary.
```python
from agno.agent import Agent
@@ -124,7 +124,7 @@ The pause is persisted in `db`. A different process can reconstruct the same Age
## Accuracy against a golden set
-Confidence routes individual documents. A representative golden set lets you compare extraction behavior across prompt or model changes.
+A representative golden set compares extraction behavior across prompt or model changes.
```python
from agno.agent import Agent
@@ -187,7 +187,7 @@ for doc in golden_set:
Passing `db=db` stores each evaluation result. Compare model-judge scores across repeated runs with a fixed judge configuration, and add deterministic field checks for invoice numbers, dates, totals, and line items. See the [evals cookbook](https://github.com/agno-agi/agno/tree/main/cookbook/09_evals/accuracy) for database logging and the team variant.
-## Three patterns, one job
+## Review controls
| Pattern | What it answers | When it fires |
|---------|------------------|---------------|
@@ -195,7 +195,7 @@ Passing `db=db` stores each evaluation result. Compare model-judge scores across
| Approval-gated tools | "Should we let the agent take the next action?" | At a specific tool boundary |
| AccuracyEval over a golden set | "How does a model judge compare these outputs?" | After a prompt or model change, or on a schedule |
-The first two gate a single document. The third records a model-judge signal for comparing configurations.
+Confidence routing and approval-gated tools act on one document. `AccuracyEval` records a model-judge signal for comparing configurations.
## Next steps
diff --git a/use-cases/document-processing/invoices-and-receipts.mdx b/use-cases/document-processing/invoices-and-receipts.mdx
index 95c6845f9..d7a572024 100644
--- a/use-cases/document-processing/invoices-and-receipts.mdx
+++ b/use-cases/document-processing/invoices-and-receipts.mdx
@@ -3,7 +3,7 @@ title: "Invoices and receipts"
description: "Header fields, line items, and the path from PDF to a database row."
---
-The shape AP teams need: a header (vendor, totals, dates) and a list of line items. The schema is the contract with downstream systems.
+Accounts payable systems usually need invoice header fields and a list of line items. Define that contract as a Pydantic schema before writing the result downstream.
```python
from typing import List, Optional
@@ -54,11 +54,11 @@ invoice = agent.run(
# quantity=12, unit_price=99.0, amount=1188.0), LineItem(...)])
```
-The hard part is the missing-field discipline. A hallucinated `total` corrupts the AP ledger. Two lines in the instructions carry that discipline: "Null for missing fields" and "Do not invent line items". Without them, a model asked for a complete object tends to fill the gaps in a noisy scan with plausible values.
+Handle missing fields explicitly. The instructions tell the agent to return `null` for absent values and prohibit invented line items. Check the resulting `None` values before writing the invoice to the AP ledger.
## Persist the row
-The agent's job ends at a validated `Invoice`. The next step is a normal INSERT. Pydantic `.model_dump()` gives you a dict you can hand to any driver.
+A validated `Invoice` is ready for persistence. Pydantic `.model_dump()` gives you a dictionary you can pass to any database driver.
```python
from sqlalchemy import create_engine, text
@@ -89,11 +89,11 @@ with engine.begin() as conn:
)
```
-One insert for the header and one per line item. The schema decides the table layout; the agent decides the values.
+Insert the header once, then insert each line item with the returned invoice ID. The schema maps cleanly to separate header and line tables.
## Receipts
-Receipts are invoices with a thinner header: merchant, purchase date, currency, total. Keep the same line-item shape. The same agent and the same instructions work; only `output_schema` changes.
+For receipts, use a smaller header with the merchant, purchase date, currency, and total. Keep the same line-item shape and change `output_schema` to `Receipt`.
```python
class Receipt(BaseModel):
diff --git a/use-cases/document-processing/overview.mdx b/use-cases/document-processing/overview.mdx
index e7b4f3ab0..bb48e3f77 100644
--- a/use-cases/document-processing/overview.mdx
+++ b/use-cases/document-processing/overview.mdx
@@ -4,9 +4,9 @@ sidebarTitle: "Overview"
description: "Turn PDFs and scanned documents into typed rows for your production systems."
---
-Every business runs on documents. Invoices land in AP, contracts go to legal, claims hit operations, and resumes route to recruiting. Agno turns each of those into a typed Python object you can persist, route, or hand to the next system.
+Operations teams use document processing agents to move information from invoices, contracts, forms, and scans into databases, ERPs, and review queues. Agno returns validated Pydantic objects from files and images. Workflows add approvals, batch execution, retries, and schedules.
-Define the schema, pass the PDF, and get a validated object back.
+Define a Pydantic schema and pass the document through `File`. The agent returns a validated instance of that schema.
```python
from typing import List, Optional
@@ -55,7 +55,7 @@ result = agent.run(
# currency='USD', lines=[LineItem(...), LineItem(...)])
```
-`result` is a validated `Invoice`. The next line in your code is an `INSERT`, an ERP call, or a queue message. The model has done its job.
+`result` is a validated `Invoice` ready for an `INSERT`, an ERP call, or a queue message.
## Workloads
@@ -84,7 +84,7 @@ result = agent.run(
Parties, dates, and a clause-level breakdown for review queues.
- Resumes, applications, KYC. Lists inside lists, same `File()` plumbing.
+ Extract nested employment, education, skills, and identity fields.
Workflows over a folder, background runs, scheduled jobs with retries.
diff --git a/use-cases/knowledge-agents.mdx b/use-cases/knowledge-agents.mdx
new file mode 100644
index 000000000..9ba05e9c3
--- /dev/null
+++ b/use-cases/knowledge-agents.mdx
@@ -0,0 +1,112 @@
+---
+title: Knowledge Agents
+description: "Build agents that answer from indexed content with controlled ingestion, retrieval, filtering, and source updates."
+---
+
+Engineering and operations teams use knowledge agents to answer questions from product documentation, policies, and internal procedures. Agno provides ingestion, retrieval, metadata filtering, corpus isolation, and source updates. AgentOS exposes the knowledge base through its API and Control Plane.
+
+```python knowledge_agent.py
+from agno.agent import Agent
+from agno.knowledge.embedder.openai import OpenAIEmbedder
+from agno.knowledge.knowledge import Knowledge
+from agno.vectordb.chroma import ChromaDb
+from agno.vectordb.search import SearchType
+
+knowledge = Knowledge(
+ name="Company handbook",
+ vector_db=ChromaDb(
+ collection="company_handbook",
+ path="tmp/chromadb",
+ persistent_client=True,
+ search_type=SearchType.hybrid,
+ embedder=OpenAIEmbedder(id="text-embedding-3-small"),
+ ),
+)
+
+knowledge.insert(
+ name="Travel policy",
+ text_content=(
+ "Domestic travel under $2,000 requires manager approval. "
+ "International travel and travel costing $2,000 or more require VP approval."
+ ),
+ skip_if_exists=True,
+)
+
+agent = Agent(
+ name="Policy Agent",
+ model="openai:gpt-5.5",
+ knowledge=knowledge,
+ search_knowledge=True,
+ instructions=[
+ "Use the knowledge base for policy questions.",
+ "Say when the answer is not in the knowledge base.",
+ ],
+)
+
+agent.print_response("When does travel need VP approval?", stream=True)
+```
+
+Create a virtual environment, install the OpenAI and ChromaDB integrations, and set `OPENAI_API_KEY` before running the agent:
+
+```bash
+uv venv --python 3.12
+uv pip install -U "agno[chromadb,openai]"
+export OPENAI_API_KEY="your_openai_api_key"
+uv run python knowledge_agent.py
+```
+
+The agent decides when to search the indexed policy. ChromaDB persists the embedded content under `tmp/chromadb` for later runs.
+
+## Choose the information path
+
+| Information | Pattern |
+|-------------|---------|
+| Policies, manuals, and product documentation | Index the corpus with [Knowledge](/knowledge/overview). |
+| Current account, order, or operational data | Query a [context provider](/context-providers/overview), tool, or MCP server at run time. |
+| Policies plus current records | Retrieve the rules from Knowledge, then call a tool for the current record. |
+| Typed fields extracted from incoming files | Use [Document Processing](/use-cases/document-processing/overview). |
+
+Knowledge owns indexed content and retrieval. Context providers and tools query live systems. Product agents add sessions, authentication, and interfaces around either pattern.
+
+## Choose retrieval behavior
+
+| Behavior | Configuration | Use when |
+|----------|---------------|----------|
+| Agentic search | `search_knowledge=True` | The agent may need several searches or no search. |
+| Automatic context | `add_knowledge_to_context=True`, `search_knowledge=False` | Each string input should receive retrieved context before the model runs. |
+| Custom retrieval | Set a custom `knowledge_retriever` | An existing search service owns query rewriting, ranking, or access checks. |
+
+Start with agentic search. Add automatic context when each string input depends on the corpus. Use a custom retriever when retrieval policy lives outside Agno.
+
+## Protect corpus boundaries
+
+| Requirement | Control |
+|-------------|---------|
+| Several named corpora share one vector database | Give each `Knowledge` instance a unique name and set [`isolate_vector_search=True`](/knowledge/concepts/isolate-vector-search). |
+| Results should match document attributes | Insert metadata and apply [knowledge filters](/knowledge/concepts/filters/overview). |
+| Tenant or user authorization | Authenticate and authorize the caller before retrieval. Apply metadata filters from the verified identity to narrow results. |
+| Users can submit remote URLs | Configure reader `allowed_hosts` and follow the [SSRF hardening pattern](/examples/knowledge/production/ssrf-allowed-hosts). |
+
+Reindex older content before enabling isolated vector search if its vectors do not contain `linked_to` metadata.
+
+## Production path
+
+| Need | Guide |
+|------|-------|
+| Ingest files, URLs, and text | [Knowledge quickstart](/knowledge/quickstart) |
+| Track content state and updates | [Contents database](/knowledge/concepts/contents-db) and [knowledge lifecycle example](/examples/knowledge/production/knowledge-lifecycle) |
+| Choose a production vector database | [Vector stores](/knowledge/vector-stores/index) |
+| Choose vector, keyword, or hybrid retrieval | [Search and retrieval](/knowledge/concepts/search-and-retrieval/overview) |
+| Tune how documents are split | [Chunking](/knowledge/concepts/chunking/overview) |
+| Isolate customer corpora | [Multi-tenant example](/examples/knowledge/production/multi-tenant) |
+| Manage content through AgentOS | [Manage knowledge](/agent-os/knowledge/manage-knowledge) |
+| Catch retrieval or answer regressions | [Agent Evaluation](/features/evaluation) |
+
+## Next steps
+
+| Task | Guide |
+|------|-------|
+| Build your first indexed agent | [Knowledge quickstart](/knowledge/quickstart) |
+| Combine several source types | [Multi-source RAG](/examples/knowledge/production/multi-source-rag) |
+| Share retrieval across specialists | [Knowledge for teams](/knowledge/teams/overview) |
+| Query live systems instead of an index | [Connecting your data](/use-cases/product-agents/connecting-your-data) |
diff --git a/use-cases/product-agents/connecting-your-data.mdx b/use-cases/product-agents/connecting-your-data.mdx
index aadca5510..a32b32849 100644
--- a/use-cases/product-agents/connecting-your-data.mdx
+++ b/use-cases/product-agents/connecting-your-data.mdx
@@ -3,6 +3,8 @@ title: "Connecting your data"
description: "Give agents access to external sources using context providers."
---
+Product agents that work with live business state need current records and product actions. Context providers connect them to sources such as web search, files, databases, Slack, Google Drive, and MCP servers.
+
In default mode, context providers expose a source through `query_` and, where enabled, `update_`. The query surface can delegate source-specific work to a sub-agent. Set `mode=ContextMode.tools` when the calling agent should receive the provider's underlying tools directly.
```python
diff --git a/use-cases/product-agents/interfaces.mdx b/use-cases/product-agents/interfaces.mdx
index 44ef9b1cc..8872b3131 100644
--- a/use-cases/product-agents/interfaces.mdx
+++ b/use-cases/product-agents/interfaces.mdx
@@ -1,9 +1,9 @@
---
title: "Interfaces"
-description: "Slack, Telegram, WhatsApp, and browser surfaces, all through the AgentOS."
+description: "Connect agents to Slack, Telegram, WhatsApp, and browser clients through AgentOS."
---
-Interfaces plug your agent into Slack, Telegram, WhatsApp, and browser clients.
+The same agent backend can serve Slack, Telegram, WhatsApp, browser clients, and agent-to-agent systems. AgentOS interface adapters map each surface onto the same run and session model.
```python
from agno.agent import Agent
@@ -53,7 +53,7 @@ For Telegram and WhatsApp, `/new` preserves earlier sessions and creates a sessi
Stored memory can follow a user across surfaces when the interfaces resolve to the same `user_id` and use the same agent database and memory configuration. Session history remains scoped to each interface-generated `session_id`. Interfaces can add surface metadata and dependencies to a run.
-## One agent, every surface
+## Register several interfaces
```python
from agno.os.interfaces.a2a import A2A
diff --git a/use-cases/product-agents/overview.mdx b/use-cases/product-agents/overview.mdx
index 598f6955e..f23868a37 100644
--- a/use-cases/product-agents/overview.mdx
+++ b/use-cases/product-agents/overview.mdx
@@ -1,10 +1,10 @@
---
title: "Product Copilots & Agents"
sidebarTitle: "Overview"
-description: "Serve agents across product surfaces with shared database-backed sessions and memory."
+description: "Embed agents in your product with REST endpoints, persistent user state, knowledge, and interfaces."
---
-A product agent can serve chat, inline actions, background jobs, and messaging interfaces from one AgentOS. Configure a shared database when those surfaces need the same sessions or user memories.
+Product engineering teams embed agents so customers can ask questions, work with their data, and take action inside the application. AgentOS gives these teams 80+ REST endpoints for running agents and managing sessions, memory, knowledge, traces, evaluations, and approvals. The same backend can power chat, inline actions, background jobs, and messaging interfaces while keeping user state in one database.
```python copilot.py
from agno.agent import Agent
@@ -32,7 +32,7 @@ if __name__ == "__main__":
This configuration provides an HTTP API, persistent multi-turn history, and per-user memory. Authentication is disabled until you enable it. See [Serve as an API](/use-cases/product-agents/serve-as-an-api#auth) for JWT authorization and opt-in per-user isolation.
-## The mental model
+## How product surfaces connect
The agent runs in your AgentOS as a service. Every product surface is a client that calls it over HTTP.
@@ -45,13 +45,14 @@ The agent runs in your AgentOS as a service. Every product surface is a client t
Stored memory can follow a user when surfaces call the same agent with the same `user_id` and database. Session history continues only when they also reuse the same `session_id`. Messaging interfaces usually create surface-specific session IDs.
-## Guided paths
+## Choose a path
| You have | You want | Start with |
|----------|----------|------------|
| A B2B SaaS product | JWT authentication and opt-in per-user isolation | [Serve as an API](/use-cases/product-agents/serve-as-an-api) |
| Users in Slack or the browser | The same agent where they already work | [Interfaces](/use-cases/product-agents/interfaces) |
-| Internal docs, Drive, databases | An agent grounded in external company data | [Connecting your data](/use-cases/product-agents/connecting-your-data) |
+| An indexed document corpus | Answers grounded in retrieved content | [Knowledge agents](/use-cases/knowledge-agents) |
+| Live systems such as Slack, Drive, or databases | Current records queried at run time | [Connecting your data](/use-cases/product-agents/connecting-your-data) |
| Multi-day user relationships | Memory that persists per user across surfaces | [Sessions and memory](/use-cases/product-agents/sessions-and-memory) |
## Explore
diff --git a/use-cases/product-agents/serve-as-an-api.mdx b/use-cases/product-agents/serve-as-an-api.mdx
index a085475b7..90bba3765 100644
--- a/use-cases/product-agents/serve-as-an-api.mdx
+++ b/use-cases/product-agents/serve-as-an-api.mdx
@@ -3,7 +3,7 @@ title: "Serve as an API"
description: "Turn agents into an HTTP service with streaming, sessions, and auth."
---
-`AgentOS` serves registered agents through a FastAPI application. Run routes are component-specific, while database-backed session and memory routes operate across the AgentOS. Your product surfaces call those endpoints.
+Product teams can connect web, mobile, and server-side clients to the same AgentOS backend. Registered agents become FastAPI services with streaming run routes, while AgentOS manages sessions, memory, knowledge, traces, evaluations, and approvals through the same API.
```python copilot.py
from agno.agent import Agent
@@ -119,14 +119,18 @@ async function askCopilot(message, threadId, jwt) {
| Long job, poll later | `background=true` and `stream=false` |
| User and thread attribution | `user_id` and a per-thread `session_id` |
-## What you get without building it
+## AgentOS endpoints
| Endpoint group | Covers |
|-----------------|--------|
| Runs | Create, stream, cancel, run in background, resume disconnected streams |
| Sessions | Create, list, rename, delete, and pull every run in a session. Per-user enforcement requires user isolation. |
| Memory | Create, update, delete, search user memories |
+| Knowledge | Add, update, search, and delete indexed content |
| Traces and metrics | Per-run spans when tracing is enabled, plus token usage and model metrics |
+| Evaluations | Run and retrieve agent and team evaluation results |
+| Approvals | List and resolve paused approval requests |
+| Schedules | Create, update, trigger, enable, disable, and delete recurring runs |
Browse the live OpenAPI spec at the `/docs` endpoint of your running AgentOS.
diff --git a/use-cases/workflow-automation.mdx b/use-cases/workflow-automation.mdx
new file mode 100644
index 000000000..f8b278f93
--- /dev/null
+++ b/use-cases/workflow-automation.mdx
@@ -0,0 +1,79 @@
+---
+title: Workflow Automation
+description: "Run repeatable processes with workflows, background execution, human review, and schedules."
+---
+
+Engineering and operations teams use workflows to automate processes that need consistent execution and a traceable result. Agno combines model-driven steps with branches, loops, parallel work, approval gates, background execution, schedules, and persisted run history.
+
+```python incident_workflow.py
+from agno.agent import Agent
+from agno.db.sqlite import SqliteDb
+from agno.workflow import Workflow
+
+triage = Agent(
+ name="Triage",
+ model="openai:gpt-5.5",
+ instructions="Extract the issue, severity, and responsible team.",
+)
+
+action_plan = Agent(
+ name="Action Plan",
+ model="openai:gpt-5.5",
+ instructions="Turn the triage result into a short action plan.",
+)
+
+incident_workflow = Workflow(
+ name="Incident Triage",
+ steps=[triage, action_plan],
+ db=SqliteDb(db_file="tmp/workflows.db"),
+)
+
+incident_workflow.print_response(
+ "Checkout requests return HTTP 500 after the latest deployment."
+)
+```
+
+Create a virtual environment, install the OpenAI, AgentOS, and SQLite integrations, and set `OPENAI_API_KEY` before running the workflow:
+
+```bash
+uv venv --python 3.12
+uv pip install -U "agno[openai,os,sqlite]"
+uv run python incident_workflow.py
+```
+
+Each step receives the previous step's output. The database stores workflow runs so they can be inspected after execution.
+
+## Choose the control model
+
+| Requirement | Use |
+|-------------|-----|
+| One model-driven task | [Agent](/agents/overview) |
+| Dynamic delegation among specialists | [Team](/teams/overview) |
+| Fixed steps, branches, loops, or parallel groups | [Workflow](/workflows/overview) |
+
+## Production building blocks
+
+| Need | Capability |
+|------|------------|
+| Continue work after the client disconnects | [Background execution](/background-execution/overview) |
+| Pause before sensitive or irreversible work | [Human-in-the-loop workflows](/workflows/hitl/overview) |
+| Run recurring jobs | [Scheduling](/features/scheduling) |
+| Trigger work from another service | [Agent API](/features/api) |
+| Inspect runs, latency, and failures | [Observability](/features/observability) |
+
+## Common patterns
+
+| Pattern | Workflow shape |
+|---------|----------------|
+| Intake and triage | Extract input, classify it, route it, and request review when needed. |
+| Data enrichment | Fetch records, enrich them in parallel, validate output, and persist results. |
+| Recurring reports | Collect data, analyze it, render a report, and run on a schedule. |
+| Long-running research | Start in the background, persist events, and reconnect to the stream. |
+
+## Next steps
+
+| Task | Guide |
+|------|-------|
+| Define workflow steps | [Building workflows](/workflows/building-workflows) |
+| Choose an orchestration pattern | [Workflow patterns](/workflows/workflow-patterns/overview) |
+| Run a workflow through AgentOS | [Using the AgentOS API](/agent-os/using-the-api) |