> ## Documentation Index
> Fetch the complete documentation index at: https://agno-v2.mintlify.site/llms.txt
> Use this file to discover all available pages before exploring further.

# Manage Learnings

> Read and manage learning records through the AgentOS /learnings endpoints.

AgentOS exposes `/learnings` REST endpoints for CRUD over the `agno_learnings` table, the table that backs the `user_profile`, `user_memory`, `session_context`, `entity_memory`, and `decision_log` stores (`learned_knowledge` lives in the knowledge base instead). Enable learning on an agent and serve it with AgentOS, and the endpoints are available automatically.

## Prerequisites

* A supported database: PostgreSQL, SQLite, or MongoDB. Other databases return `501`.
* An agent with learning enabled (see the [Learning quickstart](https://agno-v2.mintlify.site/learning/quickstart.md)).

## Example

```python learnings_with_agentos.py theme={null}
from agno.agent import Agent
from agno.db.sqlite import SqliteDb
from agno.learn import LearningMachine
from agno.models.openai import OpenAIResponses
from agno.os import AgentOS

db = SqliteDb(id="learnings-os-demo", db_file="tmp/learnings_os_demo.db")

learning = LearningMachine(
    db=db,
    model=OpenAIResponses(id="gpt-5.4"),
    user_profile=True,
    user_memory=True,
    namespace="global",
)

assistant = Agent(
    name="Assistant",
    model=OpenAIResponses(id="gpt-5.4"),
    instructions=["You are a helpful assistant. Use what you know about the user."],
    db=db,
    learning=learning,
)

agent_os = AgentOS(agents=[assistant])
app = agent_os.get_app()

if __name__ == "__main__":
    agent_os.serve(app="learnings_with_agentos:app", reload=True)
```

Browse the interactive OpenAPI docs at `http://localhost:7777/docs`.

## Endpoints

| Method | Path | Description |
| - | - | - |
| `GET` | `/learnings` | Paginated list with filters and sorting |
| `POST` | `/learnings` | Create a record |
| `GET` | `/learnings/users` | List users that own learnings, with last-activity timestamps |
| `DELETE` | `/learnings/users/{user_id}` | Delete all of a user's learnings (or one type) |
| `GET` | `/learnings/{learning_id}` | Fetch a single record |
| `PATCH` | `/learnings/{learning_id}` | Update `content` and/or `metadata` |
| `DELETE` | `/learnings/{learning_id}` | Delete a record |

Every endpoint accepts `db_id` and `table` query parameters to target a specific database or table. `table` requires `db_id`.

## Listing and filtering

`GET /learnings` returns a paginated envelope: `data` holds the records and `meta` holds the pagination info (`page`, `limit`, `total_pages`, `total_count`).

```bash theme={null}
curl "http://localhost:7777/learnings?user_id=demo-user&limit=10&page=1"
```

| Parameter | Description |
| - | - |
| `learning_type` | Filter by store (`user_profile`, `user_memory`, etc.) |
| `user_id`, `agent_id`, `team_id`, `session_id` | Filter by owner |
| `namespace`, `entity_id`, `entity_type` | Filter by scope or entity |
| `limit` | Page size (1–1000, default 100) |
| `page` | 1-indexed page number |
| `sort_by` | `created_at` or `updated_at` (default). Unknown fields are ignored |
| `sort_order` | `asc` or `desc` (default) |

For a per-user view, list users with `GET /learnings/users`, then drill into one with `GET /learnings?user_id=...`.

## Creating records

```bash theme={null}
curl -X POST http://localhost:7777/learnings \
  -H "Content-Type: application/json" \
  -d '{
    "learning_type": "user_profile",
    "namespace": "global",
    "user_id": "demo-user",
    "content": {"user_id": "demo-user", "name": "Yash", "preferred_name": "Yash"},
    "metadata": {"source": "rest-api-demo"}
  }'
```

Identity-keyed learning types use deterministic IDs derived from their identity fields. `POST` computes the **same** ID, so a record created through the API reconciles with what the agent reads and writes without creating orphaned or duplicate rows.

| `learning_type` | Derived ID | Required identity fields |
| - | - | - |
| `user_profile` | `user_profile_{user_id}` | `user_id` |
| `user_memory` | `memories_{user_id}` | `user_id` |
| `session_context` | `session_context_{session_id}` | `session_id` |
| `entity_memory` | `entity_{namespace}_{entity_type}_{entity_id}` | `entity_type`, `entity_id` (`namespace` defaults to `global`) |

* Provide the required identity field(s), or the request returns `422`.
* Include the same identity fields inside `content` so the agent's store can deserialize the record.
* An existing record for that identity returns `409`. Use `PATCH` to update it.
* Other types (for example, `decision_log`) get a generated ID, so a user can have many.

## Updating records

`PATCH` replaces `content` and/or `metadata`. Identity fields are immutable.

```bash theme={null}
curl -X PATCH http://localhost:7777/learnings/user_profile_demo-user \
  -H "Content-Type: application/json" \
  -d '{"content": {"user_id": "demo-user", "name": "Yash", "preferred_name": "Yash P."}}'
```

## Deleting records

```bash theme={null}
# Delete a single record
curl -X DELETE http://localhost:7777/learnings/user_profile_demo-user

# Delete all of a user's learnings (add ?learning_type= to restrict to one store)
curl -X DELETE http://localhost:7777/learnings/users/demo-user
```

Both return `204`. The user-level delete never touches records with no owner.

## Authorization and isolation

Scoping follows the framework's opt-in [user isolation](https://agno-v2.mintlify.site/agent-os/security/authorization/user-isolation.md) contract (`AuthorizationConfig(user_isolation=True)`). Admins and requests with isolation disabled are unscoped. Anonymous requests are unscoped only on an open instance. JWT-enabled instances reject missing tokens with `401`, static security-key callers are unscoped, and service-account PATs always self-scope unless they carry the admin scope. For a scoped non-admin caller:

| Operation | Behavior |
| - | - |
| List / list users | Bound to the caller. List also includes records with no owner (`user_id IS NULL`). A different `user_id` returns `403` |
| Create | Body `user_id` must be omitted/null or match the caller, otherwise `403` |
| Delete user | Only the caller's own learnings; a different `user_id` returns `403` |
| Get single record | A cross-user record returns `404` (no existence leak) |
| Patch / delete single record | Cross-user returns `404`. Shared records (`user_id IS NULL`) are readable but admin-only to mutate, so a regular user gets `403` |

When [RBAC](https://agno-v2.mintlify.site/agent-os/security/authorization/scopes.md) is enabled, the routes require the `learnings:read`, `learnings:write`, or `learnings:delete` scopes.

## Developer Resources

* [Learnings API reference](https://agno-v2.mintlify.site/reference-api/schema/learnings/list-learnings.md)
* [Learning overview](https://agno-v2.mintlify.site/learning/overview.md)
* [Learning stores](https://agno-v2.mintlify.site/learning/stores/intro.md)
* [User isolation](https://agno-v2.mintlify.site/agent-os/security/authorization/user-isolation.md)


This documentation is built and hosted on [Mintlify](https://mintlify.com), a developer documentation platform.