Skip to content

Commit 4e8a62b

Browse files
phernandezclaude
andcommitted
Remove workspace param from CLI tool commands, fix formatting
The CLI tool commands still passed workspace= to MCP tool functions after the workspace parameter was removed from all MCP tool signatures. Also removes the workspace passthrough test and applies ruff formatting. Signed-off-by: phernandez <paul@basicmemory.com> Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com> Signed-off-by: phernandez <paul@basicmachines.co>
1 parent 4915e13 commit 4e8a62b

14 files changed

Lines changed: 21 additions & 101 deletions

src/basic_memory/cli/commands/db.py

Lines changed: 2 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -99,9 +99,7 @@ def _abort_if_mcp_processes_alive() -> None:
9999
if not zombies:
100100
return
101101

102-
console.print(
103-
"[red]Refusing to reset:[/red] basic-memory MCP processes are still running."
104-
)
102+
console.print("[red]Refusing to reset:[/red] basic-memory MCP processes are still running.")
105103
console.print(
106104
"[yellow]On macOS/Linux these would keep reading the deleted memory.db inode "
107105
"and return phantom search results (see #765).[/yellow]"
@@ -117,9 +115,7 @@ def _abort_if_mcp_processes_alive() -> None:
117115
"Where-Object {$_.CommandLine -like '*basic-memory*mcp*'}[/green]"
118116
)
119117
else:
120-
console.print(
121-
" 2. Verify nothing remains: [green]pgrep -fa 'basic-memory mcp'[/green]"
122-
)
118+
console.print(" 2. Verify nothing remains: [green]pgrep -fa 'basic-memory mcp'[/green]")
123119
console.print(" 3. Re-run [green]bm reset[/green].")
124120
raise typer.Exit(1)
125121

src/basic_memory/cli/commands/tool.py

Lines changed: 0 additions & 45 deletions
Original file line numberDiff line numberDiff line change
@@ -62,10 +62,6 @@ def write_note(
6262
help="The project to write to. If not provided, the default project will be used."
6363
),
6464
] = None,
65-
workspace: Annotated[
66-
Optional[str],
67-
typer.Option(help="Cloud workspace tenant ID or unique name to route this request."),
68-
] = None,
6965
local: bool = typer.Option(
7066
False, "--local", help="Force local API routing (ignore cloud mode)"
7167
),
@@ -106,7 +102,6 @@ def write_note(
106102
content=content,
107103
directory=folder,
108104
project=project,
109-
workspace=workspace,
110105
tags=tags,
111106
output_format="json",
112107
)
@@ -132,10 +127,6 @@ def read_note(
132127
Optional[str],
133128
typer.Option(help="The project to use. If not provided, the default project will be used."),
134129
] = None,
135-
workspace: Annotated[
136-
Optional[str],
137-
typer.Option(help="Cloud workspace tenant ID or unique name to route this request."),
138-
] = None,
139130
local: bool = typer.Option(
140131
False, "--local", help="Force local API routing (ignore cloud mode)"
141132
),
@@ -156,7 +147,6 @@ def read_note(
156147
mcp_read_note(
157148
identifier=identifier,
158149
project=project,
159-
workspace=workspace,
160150
include_frontmatter=include_frontmatter,
161151
output_format="json",
162152
)
@@ -195,10 +185,6 @@ def edit_note(
195185
help="The project to edit. If not provided, the default project will be used."
196186
),
197187
] = None,
198-
workspace: Annotated[
199-
Optional[str],
200-
typer.Option(help="Cloud workspace tenant ID or unique name to route this request."),
201-
] = None,
202188
local: bool = typer.Option(
203189
False, "--local", help="Force local API routing (ignore cloud mode)"
204190
),
@@ -222,7 +208,6 @@ def edit_note(
222208
operation=operation,
223209
content=content,
224210
project=project,
225-
workspace=workspace,
226211
section=section,
227212
find_text=find_text,
228213
expected_replacements=expected_replacements,
@@ -260,10 +245,6 @@ def build_context(
260245
Optional[str],
261246
typer.Option(help="The project to use. If not provided, the default project will be used."),
262247
] = None,
263-
workspace: Annotated[
264-
Optional[str],
265-
typer.Option(help="Cloud workspace tenant ID or unique name to route this request."),
266-
] = None,
267248
local: bool = typer.Option(
268249
False, "--local", help="Force local API routing (ignore cloud mode)"
269250
),
@@ -284,7 +265,6 @@ def build_context(
284265
mcp_build_context(
285266
url=url,
286267
project=project,
287-
workspace=workspace,
288268
depth=depth,
289269
timeframe=timeframe,
290270
page=page,
@@ -317,10 +297,6 @@ def recent_activity(
317297
Optional[str],
318298
typer.Option(help="The project to use. If not provided, the default project will be used."),
319299
] = None,
320-
workspace: Annotated[
321-
Optional[str],
322-
typer.Option(help="Cloud workspace tenant ID or unique name to route this request."),
323-
] = None,
324300
local: bool = typer.Option(
325301
False, "--local", help="Force local API routing (ignore cloud mode)"
326302
),
@@ -346,7 +322,6 @@ def recent_activity(
346322
page=page,
347323
page_size=page_size,
348324
project=project,
349-
workspace=workspace,
350325
output_format="json",
351326
)
352327
)
@@ -408,10 +383,6 @@ def search_notes(
408383
Optional[str],
409384
typer.Option(help="The project to use. If not provided, the default project will be used."),
410385
] = None,
411-
workspace: Annotated[
412-
Optional[str],
413-
typer.Option(help="Cloud workspace tenant ID or unique name to route this request."),
414-
] = None,
415386
local: bool = typer.Option(
416387
False, "--local", help="Force local API routing (ignore cloud mode)"
417388
),
@@ -482,7 +453,6 @@ def search_notes(
482453
mcp_search(
483454
query=query or None,
484455
project=project,
485-
workspace=workspace,
486456
search_type=search_type,
487457
output_format="json",
488458
page=page,
@@ -592,10 +562,6 @@ def schema_validate(
592562
Optional[str],
593563
typer.Option(help="The project to use. If not provided, the default project will be used."),
594564
] = None,
595-
workspace: Annotated[
596-
Optional[str],
597-
typer.Option(help="Cloud workspace tenant ID or unique name to route this request."),
598-
] = None,
599565
local: bool = typer.Option(
600566
False, "--local", help="Force local API routing (ignore cloud mode)"
601567
),
@@ -629,7 +595,6 @@ def schema_validate(
629595
note_type=note_type,
630596
identifier=identifier,
631597
project=project,
632-
workspace=workspace,
633598
output_format="json",
634599
)
635600
)
@@ -660,10 +625,6 @@ def schema_infer(
660625
Optional[str],
661626
typer.Option(help="The project to use. If not provided, the default project will be used."),
662627
] = None,
663-
workspace: Annotated[
664-
Optional[str],
665-
typer.Option(help="Cloud workspace tenant ID or unique name to route this request."),
666-
] = None,
667628
local: bool = typer.Option(
668629
False, "--local", help="Force local API routing (ignore cloud mode)"
669630
),
@@ -686,7 +647,6 @@ def schema_infer(
686647
note_type=note_type,
687648
threshold=threshold,
688649
project=project,
689-
workspace=workspace,
690650
output_format="json",
691651
)
692652
)
@@ -714,10 +674,6 @@ def schema_diff(
714674
Optional[str],
715675
typer.Option(help="The project to use. If not provided, the default project will be used."),
716676
] = None,
717-
workspace: Annotated[
718-
Optional[str],
719-
typer.Option(help="Cloud workspace tenant ID or unique name to route this request."),
720-
] = None,
721677
local: bool = typer.Option(
722678
False, "--local", help="Force local API routing (ignore cloud mode)"
723679
),
@@ -738,7 +694,6 @@ def schema_diff(
738694
mcp_schema_diff(
739695
note_type=note_type,
740696
project=project,
741-
workspace=workspace,
742697
output_format="json",
743698
)
744699
)

src/basic_memory/mcp/project_context.py

Lines changed: 1 addition & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -633,9 +633,7 @@ async def resolve_workspace_project_identifier(
633633

634634
if len(matches) > 1:
635635
# Prefer the project in the default workspace when name is ambiguous
636-
default_match = next(
637-
(entry for entry in matches if entry.workspace.is_default), None
638-
)
636+
default_match = next((entry for entry in matches if entry.workspace.is_default), None)
639637
if default_match:
640638
return default_match
641639

src/basic_memory/mcp/tools/edit_note.py

Lines changed: 2 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -176,9 +176,7 @@ async def edit_note(
176176
content: Annotated[
177177
str,
178178
Field(
179-
validation_alias=AliasChoices(
180-
"content", "new_content", "replacement", "replace_with"
181-
)
179+
validation_alias=AliasChoices("content", "new_content", "replacement", "replace_with")
182180
),
183181
],
184182
project: Optional[str] = None,
@@ -196,9 +194,7 @@ async def edit_note(
196194
Optional[str],
197195
Field(
198196
default=None,
199-
validation_alias=AliasChoices(
200-
"find_text", "find", "old_text", "old_content", "search"
201-
),
197+
validation_alias=AliasChoices("find_text", "find", "old_text", "old_content", "search"),
202198
),
203199
] = None,
204200
expected_replacements: Optional[int] = None,

src/basic_memory/mcp/tools/project_management.py

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -24,7 +24,6 @@
2424
# --- Helpers for dual-fetch + merge ---
2525

2626

27-
2827
def _merge_projects(
2928
local_list: ProjectList | None,
3029
cloud_list: ProjectList | None,

src/basic_memory/mcp/tools/search.py

Lines changed: 1 addition & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -358,9 +358,7 @@ async def search_notes(
358358
Optional[float],
359359
Field(
360360
default=None,
361-
validation_alias=AliasChoices(
362-
"min_similarity", "threshold", "similarity_threshold"
363-
),
361+
validation_alias=AliasChoices("min_similarity", "threshold", "similarity_threshold"),
364362
),
365363
] = None,
366364
context: Context | None = None,

src/basic_memory/repository/sqlite_search_repository.py

Lines changed: 1 addition & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -107,8 +107,7 @@ async def init_search_index(self):
107107
await self._ensure_vector_tables()
108108
except SemanticDependenciesMissingError as exc:
109109
logger.warning(
110-
f"Semantic search disabled: {exc}. "
111-
"Falling back to keyword-only search."
110+
f"Semantic search disabled: {exc}. Falling back to keyword-only search."
112111
)
113112
self._semantic_enabled = False
114113

test-int/mcp/test_param_aliases_integration.py

Lines changed: 11 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -489,7 +489,17 @@ async def test_aliases_not_advertised_in_schema(mcp_server, app):
489489
),
490490
"search_notes": (
491491
["query", "page", "page_size", "note_types", "after_date", "min_similarity"],
492-
["q", "search", "offset", "limit", "note_type", "types", "since", "after", "threshold"],
492+
[
493+
"q",
494+
"search",
495+
"offset",
496+
"limit",
497+
"note_type",
498+
"types",
499+
"since",
500+
"after",
501+
"threshold",
502+
],
493503
),
494504
"recent_activity": (
495505
["type", "timeframe", "page", "page_size"],

tests/cli/test_cli_tool_json_output.py

Lines changed: 0 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -167,22 +167,6 @@ def test_read_note_json_output(mock_mcp_read):
167167
assert mock_mcp_read.call_args.kwargs["output_format"] == "json"
168168

169169

170-
@patch(
171-
"basic_memory.cli.commands.tool.mcp_read_note",
172-
new_callable=AsyncMock,
173-
return_value=READ_NOTE_RESULT,
174-
)
175-
def test_read_note_workspace_passthrough(mock_mcp_read):
176-
"""read-note --workspace passes workspace through to the MCP tool call."""
177-
result = runner.invoke(
178-
cli_app,
179-
["tool", "read-note", "test-note", "--workspace", "tenant-123"],
180-
)
181-
182-
assert result.exit_code == 0, f"CLI failed: {result.output}"
183-
assert mock_mcp_read.call_args.kwargs["workspace"] == "tenant-123"
184-
185-
186170
@patch(
187171
"basic_memory.cli.commands.tool.mcp_read_note",
188172
new_callable=AsyncMock,

tests/markdown/test_markdown_plugins.py

Lines changed: 1 addition & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -189,8 +189,7 @@ def test_observation_skips_obsidian_callouts():
189189
t.meta.get("observation")
190190
for t in tokens
191191
if t.type == "inline" and t.meta and t.meta.get("observation")
192-
if t.meta["observation"]["category"]
193-
and t.meta["observation"]["category"].startswith("!")
192+
if t.meta["observation"]["category"] and t.meta["observation"]["category"].startswith("!")
194193
]
195194
assert callout_observations == [], (
196195
f"Obsidian callouts should not produce observations, got: {callout_observations}"

0 commit comments

Comments
 (0)