---
title: "Claude Code memory workflow: recall, verify, then write back"
description: Use recall_for_task, validate_task_memory, and write_task_memory as an auditable workflow without treating MCP configuration as an automatic-memory guarantee.
image: "https://zengliangyi.com/og/blog/en/claude-code-memory-workflow.png"
---

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](/en/blog/chatcrystal-mcp-setup), the [memory schema](https://github.com/ZengLiangYi/ChatCrystal/blob/764276814e5c5a33ecbfeae63754f74b9261a3a8/server/src/services/memory/schemas.ts), and the [recall service](https://github.com/ZengLiangYi/ChatCrystal/blob/764276814e5c5a33ecbfeae63754f74b9261a3a8/server/src/services/memory/recall.ts) at fixed commit [`7642768`](https://github.com/ZengLiangYi/ChatCrystal/tree/764276814e5c5a33ecbfeae63754f74b9261a3a8).

## 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:



```json
{  
    "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](https://github.com/ZengLiangYi/ChatCrystal/blob/764276814e5c5a33ecbfeae63754f74b9261a3a8/server/src/services/memory/quality.ts) for this exception.



```text
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.



```json
{  
    "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](https://github.com/ZengLiangYi/ChatCrystal/blob/764276814e5c5a33ecbfeae63754f74b9261a3a8/server/src/services/memory/writeback.ts) 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](/en/blog/semantic-search-relation-context) for expansion boundaries and the [MCP setup guide](/en/blog/chatcrystal-mcp-setup) for the connection layer.

Share:

##  Related Posts

[##  Set up ChatCrystal MCP: make Claude Code calls reviewable

Connect ChatCrystal to Claude Code with a project-scoped stdio server, then verify its seven tools, HTTP backend, approvals, and request path.          曾亮懿       October 3, 2026      3 min read

#ChatCrystal

#MCP

#Claude Code](/en/blog/chatcrystal-mcp-setup)    [##  MCP Boundaries: Discovery, Identity, and Call Permissions

Examine Model Context Protocol boundaries: tool discovery, server instance tracking, and execution permissions in reviewable developer environments.          曾亮懿       October 7, 2026      4 min read

#ChatCrystal

#MCP

#Node.js](/en/blog/mcp-protocol-boundaries)    [##  A Minimal MCP Server: Register Tools & Verify Stdio Calls

Build an offline addition tool with TypeScript SDK, verify protocol discovery and calls, and inspect ChatCrystal adapter integration boundaries.          曾亮懿       October 6, 2026      4 min read

#ChatCrystal

#MCP

#Node.js](/en/blog/mcp-server-implementation)

##  From writing to code

Explore ChatCrystal, developer tools and daily learning notes on my GitHub. Questions about the implementation are welcome.

[Visit my GitHub](https://github.com/ZengLiangYi)

```json
{
  "@context": "https://schema.org",
  "@type": "WebSite",
  "name": "ZengLiangYi Blog",
  "alternateName": [
    "Zeng Liangyi",
    "ZengLiangYi",
    "zengliangyi.com"
  ],
  "url": "https://zengliangyi.com",
  "description": "曾亮懿的个人网站。记录 AI Native 探索、开发者工具与全栈产品实践。"
}
{
  "@context": "https://schema.org",
  "@type": "BlogPosting",
  "headline": "Claude Code memory workflow: recall, verify, then write back",
  "description": "Use recall_for_task, validate_task_memory, and write_task_memory as an auditable workflow without treating MCP configuration as an automatic-memory guarantee.",
  "url": "https://zengliangyi.com/en/blog/claude-code-memory-workflow/",
  "image": "https://zengliangyi.com/images/blog/claude-code-memory-workflow.svg",
  "datePublished": "2026-10-03T00:00:00.000Z",
  "dateModified": "2026-10-03T00:00:00.000Z",
  "author": {
    "@type": "Person",
    "name": "曾亮懿",
    "url": "https://zengliangyi.com/en/about"
  },
  "publisher": {
    "@type": "Organization",
    "name": "ZengLiangYi Blog",
    "logo": {
      "@type": "ImageObject",
      "url": "https://zengliangyi.com/favicon-96x96.png"
    }
  },
  "mainEntityOfPage": {
    "@type": "WebPage",
    "@id": "https://zengliangyi.com/en/blog/claude-code-memory-workflow/"
  }
}
{
  "@context": "https://schema.org",
  "@type": "BreadcrumbList",
  "itemListElement": [
    {
      "@type": "ListItem",
      "position": 1,
      "name": "Home",
      "item": "https://zengliangyi.com/en"
    },
    {
      "@type": "ListItem",
      "position": 2,
      "name": "Blog",
      "item": "https://zengliangyi.com/en/blog"
    },
    {
      "@type": "ListItem",
      "position": 3,
      "name": "Claude Code memory workflow: recall, verify, then write back",
      "item": "https://zengliangyi.com/en/blog/claude-code-memory-workflow/"
    }
  ]
}
```
