MCP lets Claude Code reach ChatCrystal, but tool access does not mean every new conversation will recall automatically, and a writeback is not proof that the current project has validated the lesson. A reliable workflow separates recall, fact checking, quality preflight, and persistence while retaining the source.
This article follows the ChatCrystal MCP setup, the memory schema, and the recall service at fixed commit 7642768.
Make the recall input specific
recall_for_task accepts a goal, task kind, project identity, directory, branch, touched files, and error signatures. mode can be task or debug; the default project limit is 5 and the global supplement limit is 3. include_relations defaults to true and controls one-hop expansion of semantic results; matched notes still return related_note_ids when it is false. Without a project identity, the service warns and returns only global matches. When semantic search is unavailable, it returns a warning instead of inventing an answer.
The service first runs a bounded semantic search across the library, then filters candidates by project identity and global scope. It does not restrict retrieval to the project first, so a project memory may never enter the candidate set. Check warnings and source material when results are empty; emptiness does not establish that no history exists.
The timeout issue below is constructed. Build actual inputs from the current task:
{
"mode": "debug",
"task": {
"goal": "Find the cause of intermittent API timeouts",
"task_kind": "debug",
"project_key": "example-service",
"files_touched": ["src/server.ts"],
"error_signatures": ["ETIMEDOUT", "upstream reset"]
},
"options": { "project_limit": 5, "global_limit": 3, "include_relations": true }
}
Treat returned titles, summaries, and related note IDs as candidate evidence. Recall does not return a separate error_signatures field. Open the note details, then compare the input error signatures against the original conversation, dependency versions, and current code. Recall is not an approved fix.
Run a side-effect-free preflight before writing
validate_task_memory accepts the same request shape as writeback but only returns acceptance, reasons, warnings, and the materialized note fields. Durable material usually needs a specific title, a substantive summary, a cause or resolution, and an outcome such as pitfall, fix, pattern, or decision. Auto mode skips one-time environment states, version reports, progress logs, and vague claims that code should be “more robust.” Manual mode still checks structure but can accept readable titles, summaries, and conclusions with quality warnings. See the quality decision implementation for this exception.
Finish the task → collect cause, change, and verification evidence
→ validate_task_memory
→ call write_task_memory only if accepted
Acceptance is a quality decision, not a truth proof. Put commands, affected scope, and unverified conditions in the summary or conclusions so the next recall can reassess them.
Control scope and idempotency
write_task_memory uses auto or manual mode. Auto writeback requires source_run_key for an idempotent receipt and cannot select global scope. Manual mode can explicitly choose project or global; a global lesson should truly transfer across projects.
This auto-writeback candidate continues the constructed scenario; it is not a reported incident or measured fix. It demonstrates quality rejection: the side-effect-free preflight at the fixed commit returns accepted: false, reason: "low-note-quality", and a durable_reusable_lesson warning. Do not pass it directly to write_task_memory. Add real reusable evidence and rerun preflight; do not invent a fix or switch to manual mode merely to bypass warnings. Replace source_run_key with a unique identifier for the current logical run. Keep it for retries of that run and use a different value for another task. Receipts are deduplicated by source_agent and this key together.
{
"mode": "auto",
"source_run_key": "run-2026-10-03-timeout",
"task": {
"goal": "Find API timeouts",
"task_kind": "debug",
"project_key": "example-service",
"source_agent": "claude"
},
"memory": {
"title": "Leaked connections in an error path caused proxy timeouts",
"summary": "In the constructed scenario, src/server.ts skips returning a connection after an exception, exhausting the pool and producing ETIMEDOUT. Wrap the database call in try/finally so both normal returns and exceptions release the connection. Check both paths separately. Only the memory preflight is validated here; this is not a measured service fix.",
"outcome_type": "fix",
"root_cause": "src/server.ts skips returning a connection after an exception, leaving later requests waiting for an exhausted pool",
"resolution": "Wrap the database call in try/finally to release the connection, then test both normal returns and exceptions",
"error_signatures": ["ETIMEDOUT"],
"key_conclusions": [
"Wrap database calls in try/finally so exceptions release connections; verify connection return before changing timeout values"
]
}
}
The service creates or merges the memory note, saves it with an auto-mode receipt, and synchronously awaits vector generation; it does not merely enqueue indexing. If embedding fails, the note may already be persisted while the receipt’s index status remains pending. Retrying with the same source_agent and source_run_key continues indexing that target. A normal response has no separate index-status field: read the note using note_id or merged_into_note_id and validate retrieval. See the writeback implementation for this order.
Turn automation into an auditable sequence
Project rules should state four things: recall at the start and show its sources; verify current conditions before applying a historical fix; write only durable conclusions at the end; report tool warnings instead of pretending there was no history. Keep records for no matches, false matches, and rejected writebacks.
That produces a reviewable memory workflow rather than a promise that every conversation remembers. See the semantic search and relation context guide for expansion boundaries and the MCP setup guide for the connection layer.