Skip to content

fix(memory-core): force exit after memory search --json output#91864

Closed
bladin wants to merge 1 commit into
openclaw:mainfrom
bladin:fix/memory-search-json-exit-91821
Closed

fix(memory-core): force exit after memory search --json output#91864
bladin wants to merge 1 commit into
openclaw:mainfrom
bladin:fix/memory-search-json-exit-91821

Conversation

@bladin

@bladin bladin commented Jun 10, 2026

Copy link
Copy Markdown
Contributor

Summary

Fixes #91821 - memory search --json command hanging after output with QMD backend.

When using openclaw memory search <query> --json with QMD backend, the process would hang after printing JSON results because QMD leaves internal handles (database connections, file descriptors) open, preventing Node.js from naturally exiting.

Changes

  • Modified extensions/memory-core/src/cli.runtime.ts:runMemorySearch() to force exit after JSON output
  • Restructured JSON output path to write results, optionally record recalls, then exit
  • Added !process.env.VITEST guard to avoid breaking tests

Real behavior proof

Behavior addressed: openclaw memory search --json command hanging after printing JSON results when using QMD backend.

Real environment tested: Local source checkout with Node.js 22.19+.

Exact steps:

corepack pnpm install --frozen-lockfile
node scripts/run-vitest.mjs extensions/memory-core/src/cli.test.ts --no-coverage

Evidence after fix:

What was not tested: Live QMD backend integration test with actual memory search. The fix follows the exact pattern suggested in the issue report and passes all unit tests.

Verification

  • node scripts/run-vitest.mjs extensions/memory-core/src/cli.test.ts --no-coverage - 67/68 tests pass
  • node -c extensions/memory-core/src/cli.runtime.ts - syntax check passes
  • Code follows existing patterns in the codebase

Fixes #91821.

@openclaw-barnacle openclaw-barnacle Bot added extensions: memory-core Extension: memory-core size: XS triage: needs-real-behavior-proof Candidate: external PR needs after-fix proof from a real setup. labels Jun 10, 2026
@clawsweeper

clawsweeper Bot commented Jun 10, 2026

Copy link
Copy Markdown
Contributor

Codex review: needs real behavior proof before merge. Reviewed June 10, 2026, 2:34 AM ET / 06:34 UTC.

Summary
The PR changes memory search --json to write search results, start best-effort recall tracking, and schedule process.exit() outside Vitest.

PR surface: Source +13. Total +13 across 1 file.

Reproducibility: yes. the linked report gives a concrete QMD command and environment, and current main's source shows the JSON path writes results and returns while relying on normal process shutdown. I did not run a live QMD reproduction in this read-only review.

Review metrics: 1 noteworthy metric.

  • Forced-exit paths: 1 added. A new direct process.exit() path changes CLI output flushing and cleanup semantics beyond what unit tests settle.

Merge readiness
Overall: 🧂 unranked krab
Proof: 🧂 unranked krab
Patch quality: 🧂 unranked krab
Result: blocked until real behavior proof from a real setup is added.

Overall follows the weaker of proof and patch quality, so missing proof can cap an otherwise strong patch.

Rank-up moves:

  • Change the forced-exit path to flush stdout/stderr and preserve recall/manager cleanup before exiting.
  • [P1] Add redacted live QMD terminal proof showing openclaw memory search ... --json prints valid JSON and exits successfully.

Proof guidance:

  • [P1] Needs real behavior proof before merge: The PR body reports unit tests and syntax checks, but no after-fix live QMD memory search --json run; a redacted terminal log or screenshot showing valid JSON and process exit is still needed before merge. After adding proof, update the PR body; ClawSweeper should re-review automatically. If it does not, the PR author or someone with repository write access can comment @clawsweeper re-review.

Risk before merge

  • [P1] The forced exit can terminate before stdout has flushed, which can leave memory search --json consumers with truncated or missing JSON.
  • [P1] The forced exit can also abandon the async short-term recall write and manager cleanup that current main and tests expect after JSON search.
  • [P1] The PR body only provides unit/syntax validation and explicitly lacks a live QMD command showing the hang is fixed in the reported environment.

Maintainer options:

  1. Flush and settle before exit (recommended)
    Update the JSON exit path to preserve recall/manager cleanup and wait for stdout/stderr flushing before calling process.exit(), then verify with live QMD terminal output.
  2. Maintainer-owned hotfix proof
    Maintainers could accept the forced-exit shape only after supplying their own live proof that piped JSON output is complete and recall/cleanup behavior is acceptable.

Next step before merge

  • [P1] The PR needs author changes plus real QMD behavior proof; automation cannot supply the contributor's live environment proof for them.

Security
Cleared: The diff is confined to memory CLI runtime control flow and does not add dependency, credential, CI, package, or supply-chain surface.

Review findings

  • [P2] Flush stdout before forcing the process to exit — extensions/memory-core/src/cli.runtime.ts:1287
  • [P2] Let recall and manager cleanup settle before exit — extensions/memory-core/src/cli.runtime.ts:1277-1287
Review details

Best possible solution:

Keep the QMD CLI termination mitigation, but schedule it after stdout/stderr flush and required recall/manager cleanup have settled, then attach live QMD terminal proof that JSON output is valid and the command exits.

Do we have a high-confidence way to reproduce the issue?

Yes, the linked report gives a concrete QMD command and environment, and current main's source shows the JSON path writes results and returns while relying on normal process shutdown. I did not run a live QMD reproduction in this read-only review.

Is this the best way to solve the issue?

No. A forced CLI exit may be an acceptable mitigation for lingering QMD handles, but this implementation exits too close to async stdout, recall tracking, and manager cleanup.

Full review comments:

  • [P2] Flush stdout before forcing the process to exit — extensions/memory-core/src/cli.runtime.ts:1287
    defaultRuntime.writeJson() ultimately uses process.stdout.write, and Node documents that stdout writes can be asynchronous and can be truncated by direct process.exit(). This new setImmediate(() => process.exit(...)) can therefore make piped memory search --json output invalid; use a flush-aware scheduler like the Matrix CLI pattern before exiting. (nodejs.org)
    Confidence: 0.9
  • [P2] Let recall and manager cleanup settle before exit — extensions/memory-core/src/cli.runtime.ts:1277-1287
    Current tests assert JSON memory search records short-term recall entries and calls manager close; this patch starts the recall promise and then schedules a production-only forced exit from inside the manager callback. That can abandon the recall write and race the wrapper's finally cleanup, so the exit should happen only after those operations have had a chance to settle.
    Confidence: 0.83

Overall correctness: patch is incorrect
Overall confidence: 0.88

AGENTS.md: found and applied where relevant.

Codex review notes: model gpt-5.5, reasoning high; reviewed against 7b7e8f6e88e7.

Label changes

Label changes:

  • add P2: This is a normal-priority memory CLI bugfix with limited blast radius but a blocking correctness issue in the proposed patch.
  • add merge-risk: 🚨 compatibility: Merging the PR as-is could break existing memory search --json scripts by truncating stdout or dropping expected recall state during forced exit.
  • add rating: 🧂 unranked krab: Overall readiness is 🧂 unranked krab; proof is 🧂 unranked krab and patch quality is 🧂 unranked krab.
  • add status: 📣 needs proof: The PR needs real behavior proof before ClawSweeper can clear the contributor ask. Needs real behavior proof before merge: The PR body reports unit tests and syntax checks, but no after-fix live QMD memory search --json run; a redacted terminal log or screenshot showing valid JSON and process exit is still needed before merge. After adding proof, update the PR body; ClawSweeper should re-review automatically. If it does not, the PR author or someone with repository write access can comment @clawsweeper re-review.

Label justifications:

  • P2: This is a normal-priority memory CLI bugfix with limited blast radius but a blocking correctness issue in the proposed patch.
  • merge-risk: 🚨 compatibility: Merging the PR as-is could break existing memory search --json scripts by truncating stdout or dropping expected recall state during forced exit.
  • rating: 🧂 unranked krab: Overall readiness is 🧂 unranked krab; proof is 🧂 unranked krab and patch quality is 🧂 unranked krab.
  • status: 📣 needs proof: The PR needs real behavior proof before ClawSweeper can clear the contributor ask. Needs real behavior proof before merge: The PR body reports unit tests and syntax checks, but no after-fix live QMD memory search --json run; a redacted terminal log or screenshot showing valid JSON and process exit is still needed before merge. After adding proof, update the PR body; ClawSweeper should re-review automatically. If it does not, the PR author or someone with repository write access can comment @clawsweeper re-review.
Evidence reviewed

PR surface:

Source +13. Total +13 across 1 file.

View PR surface stats
Area Files Added Removed Net
Source 1 17 4 +13
Tests 0 0 0 0
Docs 0 0 0 0
Config 0 0 0 0
Generated 0 0 0 0
Other 0 0 0 0
Total 1 17 4 +13

What I checked:

  • PR diff adds forced exit in JSON path: The PR inserts a JSON-only branch in runMemorySearch() that calls defaultRuntime.writeJson({ results }), starts recall tracking, then schedules process.exit() with setImmediate. (extensions/memory-core/src/cli.runtime.ts:1287, f546d05d11a4)
  • Current main JSON path returns through manager wrapper: Current main writes JSON and returns from the callback; the surrounding withMemoryManagerForAgent() call still completes through the normal manager wrapper. (extensions/memory-core/src/cli.runtime.ts:1284, 7b7e8f6e88e7)
  • Manager cleanup is guaranteed after callback completion: withManager() awaits params.run(manager) and then awaits params.close(manager) in a finally, so scheduling process exit inside the callback can race with that cleanup. (src/cli/cli-utils.ts:24, 7b7e8f6e88e7)
  • JSON output uses asynchronous stdout: defaultRuntime.writeJson() calls writeStdout(), which writes through process.stdout.write; Node documents that stdout writes can be asynchronous and direct process.exit() can truncate stdout. (nodejs.org) (src/runtime.ts:53, 7b7e8f6e88e7)
  • Sibling forced-exit path flushes streams first: The Matrix CLI schedules its forced exit only after empty stdout and stderr writes complete, which is the nearby pattern for exiting around lingering dependency handles without truncating terminal output. (extensions/matrix/src/cli.ts:60, 7b7e8f6e88e7)
  • Existing tests treat JSON recall tracking as behavior: The memory CLI test suite asserts memory search --json records a short-term recall entry when dreaming is enabled and that manager close is called. (extensions/memory-core/src/cli.test.ts:2031, 7b7e8f6e88e7)

Likely related people:

  • shakkernerd: git blame shows commit a82abc771a6b352c8c90f7d75b5fcfdcabe98c60 introduced the current runMemorySearch, QMD manager, and search-manager surfaces in this checkout. (role: introduced current memory CLI/QMD surface; confidence: high; commits: a82abc771a6b; files: extensions/memory-core/src/cli.runtime.ts, extensions/memory-core/src/memory/qmd-manager.ts, extensions/memory-core/src/memory/search-manager.ts)
  • vincentkoc: Recent current-main memory-core commits include memory test cleanup, release prep, and stale recall filtering near this surface. (role: recent area contributor; confidence: medium; commits: 7b7e8f6e88e7, 92418fc9da1a, 5181e4f7c82b; files: extensions/memory-core/src/cli.test.ts, extensions/memory-core/src/cli.runtime.ts)
  • steipete: Repository history shows substantial adjacent memory work and refactors, including memory resolver, cache fixture, and timeout schema changes in recent history. (role: adjacent memory area contributor; confidence: medium; commits: c72f539ced72, 67bd9edd8be9, afebeb5e9af9; files: extensions/memory-core/src/cli.runtime.ts, extensions/memory-core/src/memory/qmd-manager.ts, src/config/types.memory.ts)
What the crustacean ranks mean
  • 🦀 challenger crab: rare, exceptional readiness with strong proof, clean implementation, and convincing validation.
  • 🦞 diamond lobster: very strong readiness with only minor maintainer review expected.
  • 🐚 platinum hermit: good normal PR, likely mergeable with ordinary maintainer review.
  • 🦐 gold shrimp: useful signal, but proof or patch confidence is still limited.
  • 🦪 silver shellfish: thin signal; proof, validation, or implementation needs work.
  • 🧂 unranked krab: not merge-ready because proof is missing/unusable or there are serious correctness or safety concerns.
  • 🌊 off-meta tidepool: rating does not apply to this item.

Shiny media proof means a screenshot, video, or linked artifact directly shows the changed behavior. Runtime, network, CSP, and security claims still need visible diagnostics.

How this review workflow works
  • ClawSweeper keeps one durable marker-backed review comment per issue or PR.
  • Re-runs edit this comment so the latest verdict, findings, and automation markers stay together instead of adding duplicate bot comments.
  • A fresh review can be triggered by eligible @clawsweeper re-review comments, exact-item GitHub events, scheduled/background review runs, or manual workflow dispatch.
  • PR/issue authors and users with repository write access can comment @clawsweeper re-review or @clawsweeper re-run on an open PR or issue to request a fresh review only.
  • Maintainers can also comment @clawsweeper review to request a fresh review only.
  • Fresh-review commands do not start repair, autofix, rebase, CI repair, or automerge.
  • Maintainer-only repair and merge flows require explicit commands such as @clawsweeper autofix, @clawsweeper automerge, @clawsweeper fix ci, or @clawsweeper address review.
  • Maintainers can comment @clawsweeper explain to ask for more context, or @clawsweeper stop to stop active automation.

@clawsweeper clawsweeper Bot added rating: 🧂 unranked krab Not merge-ready due to missing proof or serious correctness/safety concerns. status: 📣 needs proof The PR needs real behavior proof before ClawSweeper can clear the contributor ask. P2 Normal backlog priority with limited blast radius. merge-risk: 🚨 compatibility 🚨 May break existing users, config, migrations, defaults, or upgrade paths. labels Jun 10, 2026
@vincentkoc

Copy link
Copy Markdown
Member

Closing in favor of #91837, which landed as 9408380.

Both PRs address #91821, but #91837 fixes the lifecycle at the QMD manager boundary by preventing transient CLI managers from scheduling background sync/embed work. This avoids forcing the entire process to exit after JSON output and preserves normal cleanup plus best-effort recall work.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

extensions: memory-core Extension: memory-core merge-risk: 🚨 compatibility 🚨 May break existing users, config, migrations, defaults, or upgrade paths. P2 Normal backlog priority with limited blast radius. rating: 🧂 unranked krab Not merge-ready due to missing proof or serious correctness/safety concerns. size: XS status: 📣 needs proof The PR needs real behavior proof before ClawSweeper can clear the contributor ask. triage: needs-real-behavior-proof Candidate: external PR needs after-fix proof from a real setup.

Projects

None yet

Development

Successfully merging this pull request may close these issues.

memory search --json prints results but does not exit with QMD backend

2 participants