#9381: Fix: Allow QMD CLI memory search when scope is restrictive
stale
Cluster:
QMD Memory Management Fixes
## Summary
Fixes #9367 - QMD memory backend CLI search returns empty results when scope configuration is restrictive.
## Root Cause
When `memory.backend` is set to `"qmd"` with a restrictive scope configuration (e.g., `default: "deny"`), the CLI command `openclaw memory search` would return empty results even when the QMD index contained matching content.
The `isScopeAllowed()` method was applying session-based access control rules to CLI invocations. When no `sessionKey` was provided (as in CLI usage), the method would fall back to the configured default action, which is `"deny"` in the default QMD scope configuration (lines 70-78 in `backend-config.ts`).
## Solution
Modified `isScopeAllowed()` in `qmd-manager.ts` to bypass scope checks when no `sessionKey` is provided, treating CLI invocations as always allowed.
This makes sense because:
1. CLI commands are run by users with direct access to the machine
2. Direct QMD CLI queries already work without restrictions
3. The scope rules are intended for channel-based access control (Slack, Discord, etc.)
## Changes
- **src/memory/qmd-manager.ts**: Added early return in `isScopeAllowed()` to allow CLI invocations
- **src/memory/qmd-manager.test.ts**: Added test to verify CLI invocations are allowed even with restrictive scope
## Test Plan
- [x] Added unit test verifying CLI invocations bypass scope restrictions
- [x] Existing scope tests still pass
- [ ] Manual testing with `openclaw memory search` (requires actual QMD setup)
## Impact
- **Low risk**: Only affects CLI behavior, not in-session memory search
- **Backward compatible**: Existing configurations continue to work
- **Security**: CLI access already requires local machine access
🤖 Generated with [Claude Code](https://claude.com/claude-code)
<!-- greptile_comment -->
<h2>Greptile Overview</h2>
<h3>Greptile Summary</h3>
This PR changes QMD memory scope enforcement so that `QmdMemoryManager.search()` no longer returns empty results when invoked without a `sessionKey` (the CLI path). Concretely, `isScopeAllowed()` now short-circuits to `true` when the provided `sessionKey` is missing/blank, and a unit test was added to assert that behavior under a restrictive (`default: "deny"`) scope configuration.
The change fits into the memory backend by keeping scope rules for channel/session-based invocations (Slack/Discord/etc.) while attempting to allow local CLI queries to proceed even when those scope rules would otherwise deny access.
<h3>Confidence Score: 3/5</h3>
- This PR is mergeable after tightening the scope-bypass condition to avoid unintended access-control bypasses.
- Core change is small and localized, but as written it disables scope enforcement for empty/whitespace session keys, which can arise from bugs in non-CLI callers and would silently bypass configured restrictions. Tests also lock in that behavior. No CI verification was run in this environment.
- src/memory/qmd-manager.ts, src/memory/qmd-manager.test.ts
<!-- greptile_other_comments_section -->
**Context used:**
- Context from `dashboard` - CLAUDE.md ([source](https://app.greptile.com/review/custom-context?memory=fd949e91-5c3a-4ab5-90a1-cbe184fd6ce8))
- Context from `dashboard` - AGENTS.md ([source](https://app.greptile.com/review/custom-context?memory=0d0c8278-ef8e-4d6c-ab21-f5527e322f13))
<!-- /greptile_comment -->
Most Similar PRs
#20125: fix(doctor): skip memorySearch provider check when using QMD backend
by brandonwise · 2026-02-18
80.9%
#9624: fix(memory): resolve QMD search returning empty results [AI-assisted]
by kowshik24 · 2026-02-05
80.3%
#21471: fix: check QMD backend before memory search config
by lbo728 · 2026-02-20
79.6%
#11364: fix(memory/qmd): prevent cascading failure when query fails or retu...
by blazerui · 2026-02-07
79.3%
#9149: Fix: Allow QMD backend to work without OpenAI auth
by vishaltandale00 · 2026-02-04
79.0%
#17657: fix: clear QMD manager cache on in-process restart (SIGUSR1)
by IrriVisionTechnologies · 2026-02-16
78.5%
#16917: fix(memory): close stale SQLite connection after qmd update
by zerone0x · 2026-02-15
77.4%
#16968: fix(qmd): per-collection search to prevent large collections drowni...
by ProgramCaiCai · 2026-02-15
77.3%
#17660: fix: skip embedding provider check in doctor when QMD backend is co...
by echoVic · 2026-02-16
77.1%
#12939: fix(memory): strip null bytes from workspace paths causing ENOTDIR
by omair445 · 2026-02-09
76.7%