Skip to content

Commit 8a0ce03

Browse files
phernandezclaude
andcommitted
Remove OpenPanel telemetry
OpenPanel telemetry has been removed due to: - API returning 400 errors - Printing to stdout (noisy) - Hosted version too expensive at scale (500k+ events/month) - Self-hosted version too complex to maintain Changes: - Remove openpanel dependency from pyproject.toml - Delete telemetry.py module and CLI command - Remove track_mcp_tool() calls from all 14 MCP tools - Remove telemetry config fields (telemetry_enabled, telemetry_notice_shown) - Remove telemetry from CLI app callback and MCP server lifespan - Update README and docs to remove telemetry documentation - Delete telemetry tests The `bm telemetry` command is removed. Users who had telemetry disabled via config will see no change in behavior. Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com> Signed-off-by: phernandez <paul@basicmachines.co>
1 parent 671e3d4 commit 8a0ce03

27 files changed

+5
-809
lines changed

README.md

Lines changed: 0 additions & 33 deletions
Original file line numberDiff line numberDiff line change
@@ -466,39 +466,6 @@ tail -f ~/.basic-memory/basic-memory.log
466466
BASIC_MEMORY_CLOUD_MODE=true uvicorn basic_memory.api.app:app
467467
```
468468

469-
## Telemetry
470-
471-
Basic Memory collects anonymous usage statistics to help improve the software. This follows the [Homebrew model](https://docs.brew.sh/Analytics) - telemetry is on by default with easy opt-out.
472-
473-
**What we collect:**
474-
- App version, Python version, OS, architecture
475-
- Feature usage (which MCP tools and CLI commands are used)
476-
- Error types (sanitized - no file paths or personal data)
477-
478-
**What we NEVER collect:**
479-
- Note content, file names, or paths
480-
- Personal information
481-
- IP addresses
482-
483-
**Opting out:**
484-
```bash
485-
# Disable telemetry
486-
basic-memory telemetry disable
487-
488-
# Check status
489-
basic-memory telemetry status
490-
491-
# Re-enable
492-
basic-memory telemetry enable
493-
```
494-
495-
Or set the environment variable:
496-
```bash
497-
export BASIC_MEMORY_TELEMETRY_ENABLED=false
498-
```
499-
500-
For more details, see the [Telemetry documentation](https://basicmemory.com/telemetry).
501-
502469
## Development
503470

504471
### Running Tests

docs/testing-coverage.md

Lines changed: 1 addition & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -8,9 +8,8 @@ To keep the default CI signal **stable and meaningful**, the default `pytest` co
88
- highly environment-dependent (OS/DB tuning)
99
- inherently interactive (CLI)
1010
- background-task orchestration (watchers/sync runners)
11-
- external analytics
1211

13-
### Whats excluded (and why)
12+
### What's excluded (and why)
1413

1514
Coverage excludes are configured in `pyproject.toml` under `[tool.coverage.report].omit`.
1615

@@ -19,7 +18,6 @@ Current exclusions include:
1918
- `src/basic_memory/db.py`: platform/backend tuning paths (SQLite/Postgres/Windows), covered by integration tests and targeted runs.
2019
- `src/basic_memory/services/initialization.py`: startup orchestration/background tasks; covered indirectly by app/MCP entrypoints.
2120
- `src/basic_memory/sync/sync_service.py`: heavy filesystem↔DB integration; validated in integration suite (not enforced in unit coverage).
22-
- `src/basic_memory/telemetry.py`: external analytics; exercised lightly but excluded from strict coverage gate.
2321

2422
### Recommended additional runs
2523

pyproject.toml

Lines changed: 0 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -41,7 +41,6 @@ dependencies = [
4141
"mdformat>=0.7.22",
4242
"mdformat-gfm>=0.3.7",
4343
"mdformat-frontmatter>=2.0.8",
44-
"openpanel>=0.0.1", # Anonymous usage telemetry (Homebrew-style opt-out)
4544
"sniffio>=1.3.1",
4645
"anyio>=4.10.0",
4746
"httpx>=0.28.0",
@@ -143,6 +142,5 @@ omit = [
143142
"*/db.py", # Backend/runtime-dependent (sqlite/postgres/windows tuning); validated via integration tests
144143
"*/services/initialization.py", # Startup orchestration + background tasks (watchers); exercised indirectly in entrypoints
145144
"*/sync/sync_service.py", # Heavy filesystem/db integration; covered by integration suite, not enforced in unit coverage
146-
"*/telemetry.py", # External analytics; tested lightly, excluded from strict coverage target
147145
"*/services/migration_service.py", # Complex migration scenarios
148146
]

src/basic_memory/cli/app.py

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

1111
from basic_memory.cli.container import CliContainer, set_container # noqa: E402
1212
from basic_memory.config import init_cli_logging # noqa: E402
13-
from basic_memory.telemetry import show_notice_if_needed, track_app_started # noqa: E402
1413

1514

1615
def version_callback(value: bool) -> None:
@@ -47,13 +46,6 @@ def app_callback(
4746
container = CliContainer.create()
4847
set_container(container)
4948

50-
# Show telemetry notice and track CLI startup
51-
# Skip for 'mcp' command - it handles its own telemetry in lifespan
52-
# Skip for 'telemetry' command - avoid issues when user is managing telemetry
53-
if ctx.invoked_subcommand not in {"mcp", "telemetry"}:
54-
show_notice_if_needed()
55-
track_app_started("cli")
56-
5749
# Run initialization for commands that don't use the API
5850
# Skip for 'mcp' command - it has its own lifespan that handles initialization
5951
# Skip for API-using commands (status, sync, etc.) - they handle initialization via deps.py

src/basic_memory/cli/commands/__init__.py

Lines changed: 1 addition & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
11
"""CLI commands for basic-memory."""
22

33
from . import status, db, import_memory_json, mcp, import_claude_conversations
4-
from . import import_claude_projects, import_chatgpt, tool, project, format, telemetry
4+
from . import import_claude_projects, import_chatgpt, tool, project, format
55

66
__all__ = [
77
"status",
@@ -14,5 +14,4 @@
1414
"tool",
1515
"project",
1616
"format",
17-
"telemetry",
1817
]

src/basic_memory/cli/commands/command_utils.py

Lines changed: 2 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -14,7 +14,6 @@
1414
from basic_memory.mcp.tools.utils import call_post, call_get
1515
from basic_memory.mcp.project_context import get_active_project
1616
from basic_memory.schemas import ProjectInfoResponse
17-
from basic_memory.telemetry import shutdown_telemetry
1817

1918
console = Console()
2019

@@ -24,8 +23,8 @@
2423
def run_with_cleanup(coro: Coroutine[Any, Any, T]) -> T:
2524
"""Run an async coroutine with proper database cleanup.
2625
27-
This helper ensures database connections and telemetry threads are cleaned up
28-
before the event loop closes, preventing process hangs in CLI commands.
26+
This helper ensures database connections are cleaned up before the
27+
event loop closes, preventing process hangs in CLI commands.
2928
3029
Args:
3130
coro: The coroutine to run
@@ -39,9 +38,6 @@ async def _with_cleanup() -> T:
3938
return await coro
4039
finally:
4140
await db.shutdown_db()
42-
# Shutdown telemetry to stop the OpenPanel background thread
43-
# This prevents hangs on Python 3.14+ during thread shutdown
44-
shutdown_telemetry()
4541

4642
return asyncio.run(_with_cleanup())
4743

src/basic_memory/cli/commands/telemetry.py

Lines changed: 0 additions & 81 deletions
This file was deleted.

src/basic_memory/cli/main.py

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -13,7 +13,6 @@
1313
mcp,
1414
project,
1515
status,
16-
telemetry,
1716
tool,
1817
)
1918

src/basic_memory/config.py

Lines changed: 1 addition & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -221,17 +221,6 @@ class BasicMemoryConfig(BaseSettings):
221221
description="Cloud project sync configuration mapping project names to their local paths and sync state",
222222
)
223223

224-
# Telemetry configuration (Homebrew-style opt-out)
225-
telemetry_enabled: bool = Field(
226-
default=True,
227-
description="Send anonymous usage statistics to help improve Basic Memory. Disable with: bm telemetry disable",
228-
)
229-
230-
telemetry_notice_shown: bool = Field(
231-
default=False,
232-
description="Whether the one-time telemetry notice has been shown to the user",
233-
)
234-
235224
@property
236225
def is_test_env(self) -> bool:
237226
"""Check if running in a test environment.
@@ -241,7 +230,7 @@ def is_test_env(self) -> bool:
241230
- BASIC_MEMORY_ENV environment variable is "test"
242231
- PYTEST_CURRENT_TEST environment variable is set (pytest is running)
243232
244-
Used to disable features like telemetry and file watchers during tests.
233+
Used to disable features like file watchers during tests.
245234
"""
246235
return (
247236
self.env == "test"

src/basic_memory/mcp/server.py

Lines changed: 0 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -10,7 +10,6 @@
1010
from basic_memory import db
1111
from basic_memory.mcp.container import McpContainer, set_container
1212
from basic_memory.services.initialization import initialize_app
13-
from basic_memory.telemetry import show_notice_if_needed, track_app_started
1413

1514

1615
@asynccontextmanager
@@ -19,7 +18,6 @@ async def lifespan(app: FastMCP):
1918
2019
Handles:
2120
- Database initialization and migrations
22-
- Telemetry notice and tracking
2321
- File sync via SyncCoordinator (if enabled and not in cloud mode)
2422
- Proper cleanup on shutdown
2523
"""
@@ -30,10 +28,6 @@ async def lifespan(app: FastMCP):
3028

3129
logger.debug(f"Starting Basic Memory MCP server (mode={container.mode.name})")
3230

33-
# Show telemetry notice (first run only) and track startup
34-
show_notice_if_needed()
35-
track_app_started("mcp")
36-
3731
# Track if we created the engine (vs test fixtures providing it)
3832
# This prevents disposing an engine provided by test fixtures when
3933
# multiple Client connections are made in the same test

0 commit comments

Comments
 (0)