feat: Add display_name and is_private to ProjectItem#574
feat: Add display_name and is_private to ProjectItem#574
Conversation
Add optional cloud-injected metadata fields to ProjectItem schema so the cloud proxy can enrich project list responses with friendly names and privacy indicators for per-user private projects. - display_name: Optional friendly name (e.g. "My Notes") shown instead of the internal slug (e.g. "private-fb83af23") - is_private: Boolean flag indicating the project is private to the user Update list_memory_projects MCP tool to show "display_name (name)" format when display_name is present, so MCP clients see friendly names while still knowing the actual project slug to use in API calls. Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com> Signed-off-by: Joe P <joe@basicmemory.com>
There was a problem hiding this comment.
💡 Codex Review
Here are some automated review suggestions for this pull request.
Reviewed commit: fedcbff3b1
ℹ️ About Codex in GitHub
Codex has been enabled to automatically review pull requests in this repo. Reviews are triggered when you
- Open a pull request for review
- Mark a draft as ready
- Comment "@codex review".
If Codex has suggestions, it will comment; otherwise it will react with 👍.
When you sign up for Codex through ChatGPT, Codex can also answer questions or update the PR, like "@codex address that feedback".
|
|
||
| for project in project_list.projects: | ||
| result += f"• {project.name}\n" | ||
| label = f"{project.display_name} ({project.name})" if project.display_name else project.name |
There was a problem hiding this comment.
Keep project labels resolvable by resolve endpoint
When display_name is set, this tool now publishes display_name (name) as the project label, but project resolution only accepts external ID, permalink, or raw name (see /v2/projects/resolve lookup in project_router.py), so using the displayed label (or the display name alone) as a project argument will fail with “Project not found”. For private cloud projects this breaks the normal list→select→use workflow unless callers manually parse the slug back out of the label.
Useful? React with 👍 / 👎.
ConfigManager.add_project() and ProjectService.move_project() unconditionally called mkdir on the project path. In cloud mode (BASIC_MEMORY_PROJECT_ROOT set), paths resolve under root (/) which is read-only on macOS, crashing local dev. Production Fly.io containers have writable /, so this was never caught there. Skip mkdir when project_root is set since cloud mode uses S3 for file storage. Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com> Signed-off-by: Joe P <joe@basicmemory.com>
phernandez
left a comment
There was a problem hiding this comment.
@claude see my comments about using the FileService instead of Path to create dirs
| Path(resolved_path).mkdir(parents=True, exist_ok=True) | ||
| # Create the new directory if it doesn't exist (skip in cloud mode where storage is S3) | ||
| if not self.config_manager.config.project_root: | ||
| Path(resolved_path).mkdir(parents=True, exist_ok=True) |
There was a problem hiding this comment.
We should use the FileService here (or S3Fileservice in the cloud)
src/basic_memory/config.py
Outdated
| project_path = Path(path) | ||
| project_path.mkdir(parents=True, exist_ok=True) # pragma: no cover | ||
| if not self.config.project_root: | ||
| project_path.mkdir(parents=True, exist_ok=True) # pragma: no cover |
There was a problem hiding this comment.
also here: We should use the FileService here (or S3Fileservice in the cloud)
|
@claude can you resolve this conflict? |
|
Claude finished @phernandez's task in 13m 22s —— View job Resolved Review FeedbackAll tasks completed:
Summary of ChangesAddressed phernandez's review by replacing direct
|
…eation Replace direct Path.mkdir() calls with FileService.ensure_directory() to enable future cloud (S3) compatibility. ConfigManager.add_project() is now pure config management — directory creation is delegated to ProjectService via FileService. - Make FileService.markdown_processor Optional (not needed for ensure_directory) - Add file_service: Optional[FileService] to ProjectService.__init__ - ProjectService.add_project() and move_project() use file_service.ensure_directory() - deps/services.py injects a system-level FileService into ProjectService - Update tests/conftest.py project_service fixture to include file_service - Update test_config.py: test that ConfigManager.add_project() never creates dirs Co-authored-by: Paul Hernandez <phernandez@users.noreply.github.com>
Signed-off-by: phernandez <paul@basicmachines.co>
|
@claude This check is failing. Can you fix it? https://github.com/basicmachines-co/basic-memory/actions/runs/22169948507/job/64182360857?pr=574 |
|
Claude finished @jope-bm's task in 1m 33s —— View job Fixed Failing Type CheckRoot cause: Fix: Added a fail-fast guard before the call ( # markdown_processor is required for entity content reads — fail fast if not configured
if self.markdown_processor is None:
raise ValueError("markdown_processor is required for read_entity_content")After this check Pyright narrows the type to non-
|
Pyright flagged `self.markdown_processor.read_file()` as reportOptionalMemberAccess after markdown_processor was made Optional in the FileService refactor. Added a fail-fast ValueError if markdown_processor is None when read_entity_content is called — consistent with the project's fail-fast principle and allows Pyright to narrow the type for the subsequent call. Co-authored-by: jope-bm <jope-bm@users.noreply.github.com> Signed-off-by: claude[bot] <41898282+claude[bot]@users.noreply.github.com>
fastembed, openai, and sqlite_vec are optional extras that may not be installed at typecheck time. Add type: ignore comments so pyright does not fail on their conditional imports. Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com> Signed-off-by: Joe P <joe@basicmemory.com>
Summary
display_nameandis_privateoptional fields toProjectItemschema for cloud proxy enrichmentlist_memory_projectsMCP tool to show"My Notes (private-fb83af23)"format whendisplay_nameis presentNone/False, no impact on non-cloud usageContext
Basic Memory Cloud is adding per-user private projects ("My Notes") in team workspaces. The cloud proxy enriches the project list API response with
display_nameandis_privatemetadata, but these fields were being silently dropped during Pydantic deserialization becauseProjectItemdidn't declare them.Changes
schemas/project_info.pydisplay_name: Optional[str] = Noneandis_private: bool = FalsetoProjectItemmcp/tools/project_management.pylist_memory_projectsuses"display_name (name)"format whendisplay_nameis settests/schemas/test_schemas.pyProjectItemschema with cloud-injected fieldstests/mcp/test_tool_project_management.pylist_memory_projectsTest plan
🤖 Generated with Claude Code