Project Data Model#
A project is the primary scoping entity in agenta, grouping apps, test sets, evaluator configs, and other resources under a single tenant boundary. Projects are created and managed entirely on the backend β the frontend has no UI for creating or modifying them.
Data Shape#
The canonical API shape is ProjectsResponse, shared between the backend Pydantic model and the frontend TypeScript interface :
| Field | Type | Notes |
|---|---|---|
project_id | UUID / string | Required. Primary identifier. |
project_name | string | Required. |
workspace_id | UUID (optional) | Associated workspace. |
workspace_name | string (optional) | |
organization_id | UUID (optional) | EE only. |
organization_name | string (optional) | EE only. |
user_role | string (optional) | EE only β user's role in the project. |
is_demo | boolean (optional) | EE only β flags demo/trial projects. |
The database model ProjectDB stores id, project_name, is_default, created_at, updated_at, with optional FK references to workspaces and organizations. It has cascade-delete relationships to AppDB, EvaluatorConfigDB, and TestSetDB, meaning deleting a project removes all dependent resources .
API Layer#
The sole public endpoint is GET /projects, defined in projects_router.py. Its behavior differs by deployment mode:
- OSS: Returns a single-element list for the project associated with
request.state.project_idβ the project ID is injected by middleware, not selected by the user . - EE: Returns all projects the authenticated user is a member of, fetched via
db_manager_ee.fetch_project_memberships_by_user_id.
There are no POST, PUT, or DELETE endpoints in the router β project lifecycle is managed outside this API surface.
Frontend Integration#
The frontend fetches projects via fetchAllProjects(), which issues GET /projects. Results are held in ProjectContext, accessible throughout the app via the useProjectData() hook.
Key context values :
projectβ the currently activeProjectsResponseobject.projectIdβ the active project's UUID; falls back toDEFAULT_UUID("00000000-0000-0000-0000-000000000000") when no project is resolved .isProjectIdβtrueonly when loading is complete and a valid project ID exists .refetch/resetβ used during auth lifecycle events (login, logout, workspace switch).
Project selection logic: In OSS, the first project returned by the API is used. In demo/EE mode, the project is matched by workspace_id against the selected organization's default workspace .
The context re-fetches when doesSessionExist or selectedOrg changes , so project data stays in sync with workspace/org switches.
Limitations#
- No UI for project CRUD. The frontend service layer only exposes
fetchAllProjectsβ there are nocreateProject,updateProject, ordeleteProjectcalls . - OSS is single-project. The OSS backend unconditionally returns one project per request; multi-project support is an EE feature .
projectIdis always present. Components that guard onisProjectId(e.g.,ProtectedRoute,TestsetTable) will block rendering until a project is resolved. Falling back toDEFAULT_UUIDprevents null-safety issues but can mask missing project state.
Key Files#
| File | Purpose |
|---|---|
services/project/types.ts | Frontend ProjectsResponse interface |
services/project/index.ts | fetchAllProjects() API call |
contexts/project.context.tsx | React context, useProjectData hook |
routers/projects_router.py | Backend GET /projects endpoint |
models/db_models.py β ProjectDB | SQLAlchemy ORM model |