Explicit Recall Surface Alignment
Problem
Signet’s TypeScript recall behavior is split across too many surfaces that share some plumbing but diverge in orchestration and presentation:
/api/memory/recallexposes the richest retrieval path throughhybridRecall().handleUserPromptSubmit()uses recall differently because prompt-submit is a hot-path injection surface with confidence gates, dedup, and fallback channels./api/hooks/recallis a harness-oriented recall surface that currently wraps the same engine but still acts like a separate product boundary.- CLI, MCP, and connector consumers flatten results differently and often throw away metadata such as source labels, scores, type, and provenance.
platform/daemon/src/hooks.tsstill contains an olderhandleRecall()helper that appears to be legacy logic instead of a live source of truth.
The result is not six different retrieval engines, but it is still a fragmented recall product:
- one strong engine,
- one prompt-submit orchestration path,
- several renderers and wrappers,
- at least one likely-dead helper,
- too many places where useful metadata gets discarded.
This makes recall harder to evolve because every improvement risks landing in the wrong layer.
Goals
- Establish one canonical TypeScript explicit recall engine.
- Establish one canonical explicit recall response contract.
- Keep prompt-submit recall intentionally small, fast, and distinct from explicit recall.
- Reduce or remove duplicate helper logic that does not own real product behavior.
- Make explicit recall consumers preserve useful metadata instead of turning rich results into anonymous bullet lists.
Non-goals
- No Rust parity work in this spec.
- No retrieval-model redesign, re-ranking redesign, or graph search redesign.
- No attempt to make prompt-submit into a rich query product.
- No new memory types, schema changes, or pipeline extraction changes.
- No deep-memory-search or LLM-escalation work.
Current surface inventory
Keep as primary building blocks
| Surface | File | Role |
|---|---|---|
hybridRecall() | platform/daemon/src/memory-search.ts | Canonical explicit recall engine |
| prompt-submit orchestration | platform/daemon/src/hooks.ts | Hot-path injection control flow, not a rich query surface |
| temporal fallback helpers | platform/daemon/src/temporal-fallback.ts | Supporting continuity fallback |
| transcript fallback helpers | platform/daemon/src/session-transcripts.ts | Supporting continuity fallback |
/api/memory/recall | platform/daemon/src/daemon.ts | Canonical explicit recall API |
Keep, but thin down
| Surface | File | Current issue |
|---|---|---|
/api/hooks/recall | platform/daemon/src/daemon.ts | Useful harness entry point, but should remain a thin wrapper |
CLI signet recall | surfaces/cli/src/commands/memory.ts | Loses too much structure in display |
MCP memory_search | platform/daemon/src/mcp/tools.ts | Returns raw text payload without a stronger recall contract |
OpenClaw /recall rendering | integrations/openclaw/connector/src/index.ts | Flattens results into plain content bullets |
Likely remove or collapse
| Surface | File | Current issue |
|---|---|---|
handleRecall() | platform/daemon/src/hooks.ts | Looks like legacy standalone recall logic rather than a live source of truth |
| ad hoc formatter duplication | multiple consumers | Rich metadata is repeatedly discarded in slightly different ways |
Proposed architecture
1) Canonical explicit recall engine
platform/daemon/src/memory-search.ts remains the only retrieval engine for
explicit TypeScript recall.
hybridRecall() already owns:
- keyword + vector merge,
- filtering,
- scoping,
- reranking hooks,
- graph/traversal support,
- supplementary context,
- expansion behavior.
This spec does not replace that engine. It treats it as the source of truth.
2) Canonical explicit recall API
/api/memory/recall becomes the canonical API surface for explicit recall.
Other explicit recall surfaces should:
- wrap it,
- render it,
- or constrain it for a specific caller,
but should not grow separate retrieval behavior unless that difference is required by an explicit contract.
3) Prompt-submit remains separate
Prompt-submit recall stays in handleUserPromptSubmit() and remains a
distinct product boundary:
- lightweight injection only,
- confidence-gated,
- fallback-friendly,
- deduplicated,
- budget-limited.
Prompt-submit is not the place for the richer “query product” behavior. It is allowed to use recall, but it should not become recall’s main presentation layer.
4) Fallbacks remain supporting channels
Temporal and transcript fallbacks remain valuable, but only as fallback
channels when structured memory is weak or missing. They should not grow
into peer retrieval engines that compete with hybridRecall().
Contract decisions
A) Retrieval source of truth
- Source of truth:
hybridRecall() - Not a source of truth: CLI formatting, MCP formatting, connector formatting, prompt-submit injection formatting
B) Explicit recall source of truth
- Source of truth:
/api/memory/recall - Thin wrapper candidate:
/api/hooks/recall - Alias only:
/api/memory/search
C) Prompt-submit source of truth
- Source of truth:
handleUserPromptSubmit() - It may call
hybridRecall(), but it is not responsible for becoming the canonical explicit recall experience.
Consolidation plan
Phase 1, dead-weight audit
- Confirm whether
handleRecall()inplatform/daemon/src/hooks.tsis actually used anywhere meaningful. - Remove it if dead, or demote it to a thin wrapper if it still serves a compatibility role.
- Document any remaining call sites that still bypass the canonical recall path.
Phase 2, explicit recall response contract
Define a canonical response contract for explicit recall that all TypeScript consumers can rely on. This does not require changing the retrieval engine, only tightening the product contract around it.
The contract should preserve at least:
- result ordering,
- score,
- source,
- type,
- date/provenance,
- supplementary-result distinction,
- no-hit behavior.
The contract may later grow richer shaped sections for explicit recall, but that presentation belongs outside prompt-submit.
Phase 3, consumer alignment
Refit the following consumers to preserve useful metadata and stop flattening everything into anonymous snippets:
- CLI
signet recall - MCP
memory_search - OpenClaw
/recall - any harness-oriented recall formatting that currently strips source and provenance
Phase 4, wrapper discipline
Keep /api/hooks/recall only if it has a real harness-oriented purpose:
- different auth/session behavior,
- stricter wrapper semantics,
- harness compatibility surface.
If it does not need its own contract, it should stay visibly thin.
Validation
handleRecall()is either removed or proven necessary with documented call sites./api/memory/recallremains the authoritative explicit recall endpoint./api/hooks/recalldoes not diverge into its own retrieval engine.- CLI, MCP, and connector recall displays expose source labels and preserve useful metadata from the canonical response.
- Prompt-submit injection remains lightweight and separate from explicit recall shaping.
Success metrics
- One obvious TypeScript engine owns explicit recall behavior.
- One obvious TypeScript API owns explicit recall response semantics.
- Prompt-submit stays fast and small.
- Consumer surfaces stop collapsing recall into metadata-free bullets.
- Future recall changes can be made in one place and seen predictably across wrappers.
Open decisions
- Whether
/api/hooks/recallshould remain a public compatibility surface long-term or collapse entirely into/api/memory/recall. - Whether the canonical explicit recall response contract should stay raw JSON-first or also define a higher-level shaped presentation contract for CLI/MCP consumers.
- Whether explicit recall should expose a first-class “summary / sources / gaps / no-hit” product contract at the API layer or only in selected renderers.