---
"@remnic/core": patch
---

Tool-scoped shared-namespace promotion guard (#2183). A fact that references a specific tool or command, or whose structured procedure steps invoke a tool, and was produced by a known integration (`sourceConnector`) is no longer promoted to the shared namespace by ANY path — a different integration exposing a same-named but incompatible tool (Pi `search` = repo code search vs OpenClaw `search` = web search) would otherwise consume it.

Detection is the pure predicate `referencesAgentSpecificTool` (bounded, backtracking-safe regexes; keywords and generic names are word-anchored so `tooling`/`commander` and the `search` inside `research` do not match; it catches tool/command keyword adjacency, imperative invocations `Use \`search\`` / `Run \`rg\`` and unquoted forms `Use search when…` / `Run rg before…` gated by a clause boundary, and slash commands `Use /search`; slash detection names a generic tool only, so absolute paths like `/etc/remnic/config.json` and endpoints like `/health` never fire). The tool-scope decision has exactly ONE definition — `withholdToolScopedFromSharedNamespace({ content, sourceConnector, procedureSteps? })` (a whitespace-only connector is treated as unattributed; the text AND `procedureSteps[].toolCall.kind` are both consulted, so a portable-titled procedure with tool-bearing steps is withheld) — consulted by every shared-namespace promotion path: `shouldPromoteGlobalFactToShared` (composed; gates the pre-judge namespace prediction AND the write-loop scope-routing block, with `procedureSteps` threaded through both) and the primitive itself (gates the post-write `promoteMemoryToShared`, covering both chunked and non-chunked call sites by construction). Every site is gated by the existing `extractionScopeClassificationEnabled` capability, so disabling scope classification makes the whole feature inert on every path (escape hatch). Unattributed or portable facts, and the disabled-capability case, are byte-identical to before.
