Skip to main content
If you have questions during your migration, we can help! See Get Help for more information.
Reference the v3.0 Changelog for the full list of changes.
Want to migrate automatically? Jump to Migrate with AI for a prompt you can paste into Claude, Cursor or any coding agent.

Installing Agno v3

If you are already using Agno, you can upgrade to v3 by running:

Migrating your Agno DB

The built-in migration makes two schema changes:
  1. Session runs move to their own table. In v2, every session row held its full run history as a single JSON blob in the runs column. In v3, each run is its own row in a dedicated runs table (agno_runs by default), which removes the write amplification and unbounded row growth of the blob design.
  2. A user_id column (with index) is added to the evals, components, knowledge, schedules, schedule-runs and metrics tables, for user isolation. The metrics unique key changes from (date, aggregation_period) to include user_id.
One command applies both:
migrate_to_v3.py
Vector databases are migrated separately. If you use per-user knowledge with a vector table created before v3, run the matching script from libs/agno/migrations/v2_to_v3 (migrate_sql_vectordbs.py, migrate_field_vectordbs.py or migrate_sentinel_vectordbs.py, depending on your vector store) to add user_id scoping to existing collections. Un-migrated tables raise a ValueError on user-scoped searches instead of returning empty results. Notes:
  • The migration is non-destructive and idempotent: the legacy runs column is preserved as a backup, and re-running the migration never duplicates runs.
  • Reads keep working before, during and after the migration. Sessions merge the runs table with any legacy blob, so an un-migrated session still shows its history.
  • cleanup_legacy_runs_column() refuses to run while legacy data is present unless you pass force=True. Only pass force=True after Step 2 passes. Cleanup permanently deletes the blob, which is the only copy of your history if the migration did not actually copy it.
  • Supported everywhere sessions are stored: Postgres, MySQL, SQLite, SingleStore (+ async variants), MongoDB, Redis, Valkey, Firestore, DynamoDB, SurrealDB, JSON, and GCS JSON.
For the full storage design and per-adapter details, see the v3 storage migration guide in the repository.

Migrating your Agno code

Each section covers one breaking change, with before and after examples.

1. Sessions and runs (denormalization)

Reading sessions is unchanged. session.runs is still populated, now from the runs table:
v3_sessions.py
If you queried the runs column of the sessions table directly (SQL, dashboards, exports), point those queries at the runs table instead. After cleanup the column no longer exists:

2. Workflow HITL: flat kwargs → HumanReview

Workflow primitives no longer accept flat HITL kwargs. All human-in-the-loop configuration lives in one HumanReview object. This is how it looked in v2:
v2_hitl.py
This is how it looks in v3:
v3_hitl.py
Field mapping: every flat kwarg keeps its name inside HumanReview, except hitl_max_retriesmax_retries and hitl_timeouttimeout. This applies to Step, Steps, Loop, Condition and Router.

3. Removed and renamed parameters

These deprecated parameters have been removed. Update them to their v3 names: Agent and Team constructors:
v3_agent_params.py
continue_run / acontinue_run: the updated_tools parameter is removed. Pass requirements (a list of RunRequirement, available on the paused run output) instead of a modified ToolExecution list:
v3_continue_run.py
JWT middleware and authorization_config: secret_key is removed. Use verification_keys, which takes a list:
v3_jwt.py
MCPToolbox: auth_tokens and auth_headers are removed. Use auth_token_getters (same shape: a mapping of auth source names to token callables).

4. Reasoning requires an explicit model

The reasoning=True shortcut has been removed. Pass a native reasoning model explicitly:
v2_reasoning.py
v3_reasoning.py

5. Team and Workflow constructors are keyword-only

Positional arguments are no longer accepted:
v2_team.py
v3_team.py

6. User isolation: user_id across the platform

With user_isolation enabled on AgentOS, data is now scoped per user across memories, knowledge, evals, metrics, schedules and vector databases, in addition to sessions. What this means for your code and data:
  • user_id columns were added to the schedules, schedule-runs and evals tables; the built-in migration handles this.
  • Metrics aggregate per user: the unique key changed from (date, aggregation_period) to (user_id, date, aggregation_period). Deployments without isolation see the same single-row-per-date shape as before; sessions without a user_id aggregate into a shared bucket.
  • Vector database collections created before v3 have no per-user scoping. When isolation is on, searching them with a user_id raises a ValueError telling you to run the vector database migration. This is deliberate: an un-migrated table fails loudly instead of silently returning empty results.

7. Background execution and durable queues

background=True on AgentOS is rebuilt around a durable job queue. In v2 it spawned an unbounded asyncio.create_task, and a process death silently lost every waiting and in-flight run. In v3:
  • Accepted requests are committed rows that survive crashes, restarts and deploys; any replica’s worker can execute them.
  • Runs are bounded by a concurrency cap; excess submissions wait in the queue in pending status instead of overloading the process.
  • Every run can be watched (stream=true tails), resumed after a disconnect (/resume) and cancelled from any replica.
  • Idempotency-Key headers deduplicate resubmissions.
  • Redis is optional coordination (live event streams, cross-replica cancellation), never truth. A Redis fault degrades the live view; it cannot lose or corrupt a run.
Breaking implications: background execution requires a db on the agent (enforced with a 400), run status now transitions pending → running → completed (poll GET /agents/{id}/runs/{run_id} for the terminal state), and external framework agents (LangGraph, Claude, etc.) stream inline, so their runs are not resumable.

8. Culture feature removed

The experimental culture feature (enable_agentic_culture, add_culture_to_context, CulturalKnowledge, the agno_culture table) has been removed. Remove any references; if you need shared knowledge across users, use Knowledge instead.

9. Smaller changes

  • Async tools run in sync runs: v2’s agent.run() raised when the agent had async tools, forcing arun(). v3 executes them automatically; the guard and its error are gone.
  • Toolkit parameters: enable_* prefixes are dropped (e.g. SlackTools(enable_send_message=True)SlackTools(send_message=True)). v2 names still work with a deprecation warning.
  • AgentOS metadata routes: GET /models was removed (its data moved into GET /config under available_models), and GET / is now a minimal landing response. GET /info is the single unauthenticated metadata endpoint.
  • Toolkits have an id, used by AgentOS to reference tools stably.

Migrate with a Coding Agent

Paste the prompt below into Claude, Cursor, or any coding agent with access to your repository. It applies the mechanical changes and flags everything that needs your judgment.
Copy this prompt
The prompt deliberately refuses to run the destructive cleanup step. Keep it that way: verify your migrated history in the AgentOS UI before reclaiming the legacy storage.