A Crystal Code external tool set that lets the agent remember durable facts across sessions.
This is a native dotnet tool set for Crystal Code. It keeps short notes in two scopes: global notes live in the set's global runtime-data directory and are shared across workspaces; project notes live in the set's project runtime-data directory under the current workspace and stay off until the operator enables them. The model chooses a slug name, a title, and a body; it never chooses a filesystem path.
Features · Tools · Configuration · Prompt attachment · Install · Build from source
- Two scopes.
memory_listandmemory_readjoin Plan and Work;memory_writeandmemory_forgetjoin Work. Every call takesscope—global(default) orproject. - Host-owned runtime data. The host resolves and creates both data directories; the set derives no path itself. Global data is
{home}/data/tools/<directory>and project data is<workspace>/.crystal/data/tools/<directory>, where<directory>is the tool set's install directory name. Both are separate from the install tree. - Project is opt-in and off by default. Project notes belong to one workspace and are available only when that workspace's project data directory holds a
memory.jsonmanifest with"enabled": true. - Model-chosen content. The model supplies a slug name, a title, and a body. A write replaces the whole note. Names are 1 to 64 characters of lowercase letters, digits, and hyphens; titles are 1 to 200 characters; bodies are at most 8000 characters; a store holds at most 200 notes.
- Safe storage. Writes go to a temporary file and replace the target atomically. Files are created owner-only where the OS allows it, and symbolic links are refused.
- Approval fits the host. Reads declare
approval: alwaysand follow the author policy when the source does. Writes and deletes useapproval: inherit, so the host approval mode still applies.
| Tool | Catalog | What it does |
|---|---|---|
memory_list |
Plan, Work | List the notes in one scope with their first-line preview |
memory_read |
Plan, Work | Read one note by its slug name |
memory_write |
Work | Save or replace one note |
memory_forget |
Work | Delete one note by its slug name |
Every tool takes an optional scope:
| Value | Meaning |
|---|---|
global (default) |
The set's global data directory, shared across workspaces |
project |
The set's project data directory under the current workspace, available only when project memory is enabled |
memory_read and memory_forget require name. memory_write requires name, title, and body. A call with an unknown property or an unknown scope fails with a plain-English message.
Project memory is off until the workspace opts in. Create <workspace>/.crystal/data/tools/<directory>/memory.json:
{
"enabled": true
}<directory> is the tool set's install directory name — the directory under ~/.crystal/tools or <workspace>/.crystal/tools that holds tools.json and the assembly. It follows the extension directory-name rule: 1 to 64 characters, a letter first, then letters, digits, ., _, or -. The host creates the data directory on the first call, so the operator only adds the manifest.
Any other value, an unreadable file, or a missing file leaves project memory off. A global call is unaffected. When project memory is off, a project call returns Project memory is not enabled for this workspace. When the host supplies no data directories, a global call returns Memory is unavailable in this host. and a project call returns Project memory is unavailable in this host.
Runtime-data directories are ordinary writable directories, not a secret store. Do not write credentials there, and do not store secrets, passwords, tokens, or credentials in a note. Project notes are workspace content; commit them to share project knowledge or add them to .gitignore when they are local only.
The tools only help when the model knows to use them. This repository ships a prompt attachment under prompt-attachments/crystal-memory/ with work.md and plan.md. Copy it to ~/.crystal/prompt-attachments/crystal-memory/ so Work and Plan text tells the agent when to read, write, and delete notes and how the scopes differ.
The attachment ships disabled, matching Crystal Code's rule that a discovered attachment stays off until it is enabled. Turn it on with /promptattach enable crystal-memory inside a session, or crystal prompt-attachments enable crystal-memory outside one; both write "enabled": true to its prompt.json. A workspace copy at <workspace>/.crystal/prompt-attachments/crystal-memory/ replaces the Home copy for that workspace.
The attachment is separate from the tool set. Install the tools or the attachment independently, but the guidance refers to tools that only exist when the set is installed.
Publish the set and place the published files, including tools.json, in one directory under ~/.crystal/tools:
dotnet publish CrystalCode.Memory/CrystalCode.Memory.csproj -c Release -o ~/.crystal/tools/memoryCopy the prompt attachment alongside the other attachments:
cp -r prompt-attachments/crystal-memory ~/.crystal/prompt-attachments/Restart the session, or run /tools reload, to load the set. A project set at <workspace>/.crystal/tools/<directory>/ replaces the home set for that workspace. Notes live in the host-managed data directories, so publishing or replacing the install tree never removes them.
You need the .NET 10 SDK and sibling checkouts of Crystal at ../Crystal and Crystal Code at ../CrystalCode. The set reads its workspace and runtime-data directories from CrystalCode.Tools.IHostTool, so it references CrystalCode.Tools as a sibling source project.
dotnet build CrystalCode.Memory.sln
dotnet test CrystalCode.Memory.sln
dotnet publish CrystalCode.Memory/CrystalCode.Memory.csprojCrystal.Tools and CrystalCode.Tools are referenced as sibling source projects. The production project adds no NuGet packages; the test project uses xUnit and Microsoft.NET.Test.Sdk only. The four tool types are public IHostTool implementations listed in tools.json; the host loads this class library in one isolated load context and wraps every call with its own approval, output truncation, and timeout.