Skip to content

Commit 074af25

Browse files
authored
Merge branch 'main' into claw/cli-promo-analytics
Signed-off-by: Paul Hernandez <60959+phernandez@users.noreply.github.com>
2 parents e7c6d31 + f268329 commit 074af25

73 files changed

Lines changed: 2861 additions & 1297 deletions

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

.github/workflows/test.yml

Lines changed: 35 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -102,6 +102,41 @@ jobs:
102102
uv pip install pytest pytest-cov
103103
just test-postgres
104104
105+
test-semantic:
106+
name: Test Semantic (Python 3.12)
107+
timeout-minutes: 45
108+
runs-on: ubuntu-latest
109+
110+
steps:
111+
- uses: actions/checkout@v4
112+
with:
113+
submodules: true
114+
115+
- name: Set up Python 3.12
116+
uses: actions/setup-python@v4
117+
with:
118+
python-version: "3.12"
119+
cache: "pip"
120+
121+
- name: Install uv
122+
run: |
123+
pip install uv
124+
125+
- uses: extractions/setup-just@v3
126+
127+
- name: Create virtual env
128+
run: |
129+
uv venv
130+
131+
- name: Install dependencies
132+
run: |
133+
uv pip install -e ".[dev,semantic]"
134+
135+
- name: Run tests (Semantic)
136+
run: |
137+
uv pip install pytest pytest-cov
138+
just test-semantic
139+
105140
coverage:
106141
name: Coverage Summary (combined, Python 3.12)
107142
timeout-minutes: 30

README.md

Lines changed: 23 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -344,22 +344,20 @@ basic-memory sync --watch
344344
3. Cloud features (optional, requires subscription):
345345

346346
```bash
347-
# Authenticate with cloud (global cloud mode via OAuth)
347+
# Authenticate with cloud (stores OAuth token locally)
348348
basic-memory cloud login
349349

350-
# Bidirectional sync with cloud
351-
basic-memory cloud sync
350+
# (Optional) install/configure rclone for file sync commands
351+
basic-memory cloud setup
352352

353-
# Verify cloud integrity
354-
basic-memory cloud check
355-
356-
# Mount cloud storage
357-
basic-memory cloud mount
353+
# Check cloud auth + health
354+
basic-memory cloud status
358355
```
359356

360357
**Per-Project Cloud Routing** (API key based):
361358

362-
Individual projects can be routed through the cloud while others stay local. This uses an API key instead of OAuth:
359+
Individual projects can be routed through the cloud while others stay local. This uses an API key for routed
360+
project calls:
363361

364362
```bash
365363
# Save an API key (create one in the web app or via CLI)
@@ -373,25 +371,32 @@ basic-memory project set-cloud research
373371
# Revert a project to local mode
374372
basic-memory project set-local research
375373

376-
# List projects with mode column (local/cloud)
374+
# List projects and route metadata
377375
basic-memory project list
378376
```
379377

380-
**Routing Flags** (for users with global cloud mode):
378+
`basic-memory cloud login` / `basic-memory cloud logout` are authentication commands. They do not change default CLI
379+
routing behavior.
380+
381+
**Routing Flags**:
381382

382-
When global cloud mode is enabled, CLI commands communicate with the cloud API by default. Use routing flags to override this:
383+
Use routing flags to disambiguate command targets:
383384

384385
```bash
385-
# Force local routing (useful for local MCP server while cloud mode is enabled)
386+
# Force local routing for this command
386387
basic-memory status --local
387388
basic-memory project list --local
389+
basic-memory project ls --name main --local
388390

389-
# Force cloud routing (when cloud mode is disabled but you want cloud access)
391+
# Force cloud routing for this command
390392
basic-memory status --cloud
391393
basic-memory project info my-project --cloud
394+
basic-memory project ls --name main --cloud
392395
```
393396

394-
The local MCP server (`basic-memory mcp`) automatically uses local routing, so you can use both local Claude Desktop and cloud-based clients simultaneously.
397+
No-flag behavior defaults to local when no project context is present.
398+
399+
The local MCP server (`basic-memory mcp`) always uses local routing (including `--transport stdio`).
395400

396401
**CLI Note Editing (`tool edit-note`):**
397402

@@ -493,7 +498,9 @@ Basic Memory uses [Loguru](https://github.com/Delgan/loguru) for logging. The lo
493498
|----------|---------|-------------|
494499
| `BASIC_MEMORY_LOG_LEVEL` | `INFO` | Log level: DEBUG, INFO, WARNING, ERROR |
495500
| `BASIC_MEMORY_CLOUD_MODE` | `false` | When `true`, API logs to stdout with structured context |
496-
| `BASIC_MEMORY_FORCE_LOCAL` | `false` | When `true`, forces local API routing (ignores cloud mode) |
501+
| `BASIC_MEMORY_FORCE_LOCAL` | `false` | When `true`, forces local API routing |
502+
| `BASIC_MEMORY_FORCE_CLOUD` | `false` | When `true`, forces cloud API routing |
503+
| `BASIC_MEMORY_EXPLICIT_ROUTING` | `false` | When `true`, marks route selection as explicit (`--local`/`--cloud`) |
497504
| `BASIC_MEMORY_ENV` | `dev` | Set to `test` for test mode (stderr only) |
498505

499506
### Examples

docs/ARCHITECTURE.md

Lines changed: 8 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -18,7 +18,7 @@ Each entrypoint uses a **composition root** pattern to manage configuration and
1818
A composition root is the single place in an application where dependencies are wired together. In Basic Memory, each entrypoint has its own composition root that:
1919

2020
1. Reads configuration from `ConfigManager`
21-
2. Resolves runtime mode (cloud/local/test)
21+
2. Resolves runtime mode (local/test)
2222
3. Creates and provides dependencies to downstream code
2323

2424
**Key principle**: Only composition roots read global configuration. All other modules receive configuration explicitly.
@@ -52,10 +52,7 @@ class Container:
5252
def create(cls) -> "Container":
5353
"""Create container by reading ConfigManager."""
5454
config = ConfigManager().config
55-
mode = resolve_runtime_mode(
56-
cloud_mode_enabled=config.cloud_mode_enabled,
57-
is_test_env=config.is_test_env,
58-
)
55+
mode = resolve_runtime_mode(is_test_env=config.is_test_env)
5956
return cls(config=config, mode=mode)
6057

6158
@property
@@ -99,18 +96,19 @@ class RuntimeMode(Enum):
9996
return self == RuntimeMode.TEST
10097
```
10198

102-
Resolution follows this precedence: **TEST > CLOUD > LOCAL**
99+
Resolution follows this precedence in local app flows: **TEST > LOCAL**
103100

104101
```python
105-
def resolve_runtime_mode(cloud_mode_enabled: bool, is_test_env: bool) -> RuntimeMode:
102+
def resolve_runtime_mode(is_test_env: bool) -> RuntimeMode:
106103
if is_test_env:
107104
return RuntimeMode.TEST
108-
if cloud_mode_enabled:
109-
return RuntimeMode.CLOUD
110105
return RuntimeMode.LOCAL
111106
```
112107

113-
**Note**: `RuntimeMode` determines global behavior (e.g., whether to start file sync). Per-project routing is orthogonal — individual projects can be set to `cloud` mode via `ProjectMode` in config, which affects client routing in `get_client(project_name=...)` without changing the global runtime mode.
108+
**Note**: `RuntimeMode` determines global behavior (e.g., whether to start file sync).
109+
Per-project routing is orthogonal: individual projects can be set to `cloud` mode via `ProjectMode`,
110+
which affects client routing in `get_client(project_name=...)` without changing global runtime mode.
111+
`RuntimeMode.CLOUD` may remain for compatibility, but standard local runtime resolution does not select it.
114112

115113
## Dependencies Package
116114

0 commit comments

Comments
 (0)