Skip to content

Commit a0e754b

Browse files
phernandezclaude
andcommitted
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 <noreply@anthropic.com> Signed-off-by: phernandez <paul@basicmachines.co>
1 parent 24ca5f6 commit a0e754b

2 files changed

Lines changed: 34 additions & 0 deletions

File tree

src/basic_memory/api/app.py

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,7 @@
44

55
from fastapi import FastAPI, HTTPException
66
from fastapi.exception_handlers import http_exception_handler
7+
from fastapi.routing import APIRouter
78
from loguru import logger
89

910
from basic_memory import __version__ as version
@@ -18,6 +19,7 @@
1819
prompt_router as v2_prompt,
1920
importer_router as v2_importer,
2021
)
22+
from basic_memory.api.v2.routers.project_router import list_projects
2123
from basic_memory.config import init_api_logging
2224
from basic_memory.services.initialization import initialize_app
2325

@@ -82,6 +84,12 @@ async def lifespan(app: FastAPI): # pragma: no cover
8284
# Legacy web app proxy paths (compat with /proxy/projects/projects)
8385
app.include_router(v2_project, prefix="/proxy/projects")
8486

87+
# Legacy v1 compat: older CLI versions call GET /projects/projects (without trailing slash)
88+
# Using router mount causes 307 redirect which proxy doesn't follow, so add explicit route
89+
legacy_router = APIRouter(tags=["legacy"])
90+
legacy_router.add_api_route("/projects/projects", list_projects, methods=["GET"])
91+
app.include_router(legacy_router)
92+
8593
# V2 routers are the only public API surface
8694

8795

tests/api/v2/test_project_router.py

Lines changed: 26 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -340,3 +340,29 @@ async def test_resolve_project_empty_identifier(client: AsyncClient, v2_projects
340340
response = await client.post(f"{v2_projects_url}/resolve", json=resolve_data)
341341

342342
assert response.status_code == 422 # Validation error
343+
344+
345+
# --- Legacy v1 compatibility tests ---
346+
347+
348+
@pytest.mark.asyncio
349+
async def test_legacy_v1_list_projects_endpoint(client: AsyncClient, test_project: Project):
350+
"""Test that the legacy /projects/projects endpoint still works for older CLI versions.
351+
352+
This endpoint was removed when we migrated to v2 but older versions of
353+
basic-memory-cloud CLI still call it for `bm project list`.
354+
355+
Note: The route must be without trailing slash to avoid 307 redirects
356+
that the cloud proxy doesn't follow.
357+
"""
358+
# The legacy v1 endpoint was at /projects/projects (no trailing slash)
359+
response = await client.get("/projects/projects")
360+
361+
assert response.status_code == 200
362+
data = response.json()
363+
assert "projects" in data
364+
assert "default_project" in data
365+
366+
# Verify the test project is in the list
367+
project_names = [p["name"] for p in data["projects"]]
368+
assert test_project.name in project_names

0 commit comments

Comments
 (0)