From a0e754b7aee195df0cf4ddf28ab1ff4480f45ae7 Mon Sep 17 00:00:00 2001 From: phernandez Date: Mon, 2 Feb 2026 19:54:34 -0600 Subject: [PATCH] fix: restore legacy /projects/projects endpoint for older CLI versions Older versions of basic-memory CLI (v0.17.4 and earlier) call GET /projects/projects to list projects. This endpoint was removed when we migrated to v2 routers. Add explicit route at /projects/projects (without trailing slash) to avoid 307 redirects that the cloud proxy doesn't follow. Co-Authored-By: Claude Opus 4.5 Signed-off-by: phernandez --- src/basic_memory/api/app.py | 8 ++++++++ tests/api/v2/test_project_router.py | 26 ++++++++++++++++++++++++++ 2 files changed, 34 insertions(+) diff --git a/src/basic_memory/api/app.py b/src/basic_memory/api/app.py index 71641321..bdc6e4b3 100644 --- a/src/basic_memory/api/app.py +++ b/src/basic_memory/api/app.py @@ -4,6 +4,7 @@ from contextlib import asynccontextmanager from fastapi import FastAPI, HTTPException from fastapi.exception_handlers import http_exception_handler +from fastapi.routing import APIRouter from loguru import logger from basic_memory import __version__ as version @@ -18,6 +19,7 @@ from basic_memory.api.v2.routers import ( prompt_router as v2_prompt, importer_router as v2_importer, ) +from basic_memory.api.v2.routers.project_router import list_projects from basic_memory.config import init_api_logging from basic_memory.services.initialization import initialize_app @@ -82,6 +84,12 @@ app.include_router(v2_project, prefix="/v2") # Legacy web app proxy paths (compat with /proxy/projects/projects) app.include_router(v2_project, prefix="/proxy/projects") +# Legacy v1 compat: older CLI versions call GET /projects/projects (without trailing slash) +# Using router mount causes 307 redirect which proxy doesn't follow, so add explicit route +legacy_router = APIRouter(tags=["legacy"]) +legacy_router.add_api_route("/projects/projects", list_projects, methods=["GET"]) +app.include_router(legacy_router) + # V2 routers are the only public API surface diff --git a/tests/api/v2/test_project_router.py b/tests/api/v2/test_project_router.py index 9e10f6fa..ea77f34a 100644 --- a/tests/api/v2/test_project_router.py +++ b/tests/api/v2/test_project_router.py @@ -340,3 +340,29 @@ async def test_resolve_project_empty_identifier(client: AsyncClient, v2_projects response = await client.post(f"{v2_projects_url}/resolve", json=resolve_data) assert response.status_code == 422 # Validation error + + +# --- Legacy v1 compatibility tests --- + + +@pytest.mark.asyncio +async def test_legacy_v1_list_projects_endpoint(client: AsyncClient, test_project: Project): + """Test that the legacy /projects/projects endpoint still works for older CLI versions. + + This endpoint was removed when we migrated to v2 but older versions of + basic-memory-cloud CLI still call it for `bm project list`. + + Note: The route must be without trailing slash to avoid 307 redirects + that the cloud proxy doesn't follow. + """ + # The legacy v1 endpoint was at /projects/projects (no trailing slash) + response = await client.get("/projects/projects") + + assert response.status_code == 200 + data = response.json() + assert "projects" in data + assert "default_project" in data + + # Verify the test project is in the list + project_names = [p["name"] for p in data["projects"]] + assert test_project.name in project_names