toon-memory 1.7.0 → 1.8.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +270 -34
- package/dist/cli/setup.js +409 -96
- package/mcp/server.js +156 -10
- package/package.json +9 -1
- package/skills/toon-memory.md +25 -14
- package/src/cli/setup.ts +650 -335
- package/src/mcp/server.ts +192 -9
- package/uninstall.sh +33 -5
package/mcp/server.js
CHANGED
|
@@ -27644,10 +27644,11 @@ import { dirname, join } from "path";
|
|
|
27644
27644
|
import { fileURLToPath } from "url";
|
|
27645
27645
|
import { randomBytes, createCipheriv, createDecipheriv } from "crypto";
|
|
27646
27646
|
var __dirname = dirname(fileURLToPath(import.meta.url));
|
|
27647
|
-
var MEMORY_DIR = join(process.cwd(), ".
|
|
27647
|
+
var MEMORY_DIR = join(process.cwd(), ".toon-memory", "memory");
|
|
27648
27648
|
var MEMORY_FILE = join(MEMORY_DIR, "data.toon");
|
|
27649
27649
|
var ARCHIVE_FILE = join(MEMORY_DIR, "archive.toon");
|
|
27650
27650
|
var CONFIG_FILE = join(MEMORY_DIR, "config.json");
|
|
27651
|
+
var MAX_ENTRIES = 100;
|
|
27651
27652
|
var ARCHIVE_DAYS = 30;
|
|
27652
27653
|
var ALGORITHM = "aes-256-gcm";
|
|
27653
27654
|
function loadConfig() {
|
|
@@ -27673,7 +27674,7 @@ function ensureMemoryDir() {
|
|
|
27673
27674
|
function ensureMemoryFile() {
|
|
27674
27675
|
ensureMemoryDir();
|
|
27675
27676
|
if (!existsSync(MEMORY_FILE)) {
|
|
27676
|
-
writeFileSync(MEMORY_FILE, "version: 1\nentries[0|]{id|category|key|content|file|tags|date}:\n");
|
|
27677
|
+
writeFileSync(MEMORY_FILE, "version: 1\nentries[0|]{id|category|key|content|file|tags|date|ttl}:\n");
|
|
27677
27678
|
}
|
|
27678
27679
|
}
|
|
27679
27680
|
function encrypt(text, key) {
|
|
@@ -27726,6 +27727,75 @@ function writeMemory(content) {
|
|
|
27726
27727
|
function generateId() {
|
|
27727
27728
|
return randomBytes(4).toString("hex");
|
|
27728
27729
|
}
|
|
27730
|
+
function parseTTL(ttl) {
|
|
27731
|
+
if (!ttl || !ttl.trim()) return "";
|
|
27732
|
+
const trimmed = ttl.trim();
|
|
27733
|
+
const dayMatch = trimmed.match(/^(\d+)d$/);
|
|
27734
|
+
if (dayMatch) {
|
|
27735
|
+
const days = parseInt(dayMatch[1]);
|
|
27736
|
+
const d = /* @__PURE__ */ new Date();
|
|
27737
|
+
d.setDate(d.getDate() + days);
|
|
27738
|
+
return d.toISOString().split("T")[0];
|
|
27739
|
+
}
|
|
27740
|
+
if (/^\d{4}-\d{2}-\d{2}$/.test(trimmed)) return trimmed;
|
|
27741
|
+
return "";
|
|
27742
|
+
}
|
|
27743
|
+
function isExpired(ttl) {
|
|
27744
|
+
if (!ttl) return false;
|
|
27745
|
+
const ttlDate = parseTTL(ttl) || ttl;
|
|
27746
|
+
const today = (/* @__PURE__ */ new Date()).toISOString().split("T")[0];
|
|
27747
|
+
return ttlDate <= today;
|
|
27748
|
+
}
|
|
27749
|
+
var TAG_VOCABULARY = {
|
|
27750
|
+
"redis": ["redis", "cache", "caching", "memcached"],
|
|
27751
|
+
"auth": ["auth", "authentication", "authorization", "login", "token", "jwt", "session", "oauth"],
|
|
27752
|
+
"api": ["api", "endpoint", "rest", "graphql", "route", "router", "controller"],
|
|
27753
|
+
"db": ["database", "db", "sql", "postgres", "mysql", "mongo", "query", "migration", "schema"],
|
|
27754
|
+
"security": ["security", "encrypt", "decrypt", "vulnerability", "xss", "csrf", "cors", "sanitiz"],
|
|
27755
|
+
"test": ["test", "testing", "vitest", "jest", "spec", "mock", "assert", "coverage"],
|
|
27756
|
+
"deploy": ["deploy", "docker", "ci/cd", "github actions", "pipeline", "kubernetes", "k8s"],
|
|
27757
|
+
"config": ["config", "configuration", "settings", "env", "environment", "dotenv"],
|
|
27758
|
+
"performance": ["performance", "optimize", "benchmark", "latency", "throughput", "cache"],
|
|
27759
|
+
"refactor": ["refactor", "cleanup", "restructure", "reorganize", "rework"],
|
|
27760
|
+
"error": ["error", "exception", "throw", "catch", "handling", "retry", "fallback"],
|
|
27761
|
+
"logging": ["log", "logging", "logger", "debug", "trace", "monitor", "observability"],
|
|
27762
|
+
"types": ["typescript", "types", "type", "interface", "generic", "enum", "zod", "schema"],
|
|
27763
|
+
"async": ["async", "await", "promise", "concurrent", "parallel", "worker", "queue"],
|
|
27764
|
+
"state": ["state", "store", "redux", "context", "reducer", "action", "observable"],
|
|
27765
|
+
"ui": ["ui", "component", "render", "dom", "css", "style", "layout", "responsive"],
|
|
27766
|
+
"storage": ["storage", "file", "filesystem", "s3", "blob", "upload", "download"],
|
|
27767
|
+
"email": ["email", "mail", "smtp", "sendgrid", "newsletter", "notification"],
|
|
27768
|
+
"payment": ["payment", "stripe", "billing", "invoice", "checkout", "subscription"],
|
|
27769
|
+
"webhook": ["webhook", "callback", "event", "listener", "hook"]
|
|
27770
|
+
};
|
|
27771
|
+
function inferTags(content, key) {
|
|
27772
|
+
const text = `${key} ${content}`.toLowerCase();
|
|
27773
|
+
const matched = [];
|
|
27774
|
+
for (const [tag, keywords] of Object.entries(TAG_VOCABULARY)) {
|
|
27775
|
+
if (keywords.some((kw) => text.includes(kw))) {
|
|
27776
|
+
matched.push(tag);
|
|
27777
|
+
}
|
|
27778
|
+
}
|
|
27779
|
+
return matched.join(";");
|
|
27780
|
+
}
|
|
27781
|
+
function parseRelativeDate(since) {
|
|
27782
|
+
const trimmed = since.trim();
|
|
27783
|
+
const hourMatch = trimmed.match(/^(\d+)h$/);
|
|
27784
|
+
if (hourMatch) {
|
|
27785
|
+
const d = /* @__PURE__ */ new Date();
|
|
27786
|
+
d.setHours(d.getHours() - parseInt(hourMatch[1]));
|
|
27787
|
+
return d.toISOString().split("T")[0];
|
|
27788
|
+
}
|
|
27789
|
+
const dayMatch = trimmed.match(/^(\d+)d$/);
|
|
27790
|
+
if (dayMatch) {
|
|
27791
|
+
const d = /* @__PURE__ */ new Date();
|
|
27792
|
+
d.setDate(d.getDate() - parseInt(dayMatch[1]));
|
|
27793
|
+
return d.toISOString().split("T")[0];
|
|
27794
|
+
}
|
|
27795
|
+
if (/^\d{4}-\d{2}-\d{2}$/.test(trimmed)) return trimmed;
|
|
27796
|
+
const today = (/* @__PURE__ */ new Date()).toISOString().split("T")[0];
|
|
27797
|
+
return today;
|
|
27798
|
+
}
|
|
27729
27799
|
function archiveOldEntries() {
|
|
27730
27800
|
const data = readMemory();
|
|
27731
27801
|
const lines = data.split("\n");
|
|
@@ -27742,7 +27812,10 @@ function archiveOldEntries() {
|
|
|
27742
27812
|
const parts = line.trim().split("|");
|
|
27743
27813
|
if (parts.length >= 7) {
|
|
27744
27814
|
const date5 = parts[6];
|
|
27745
|
-
|
|
27815
|
+
const ttl = parts[7] || "";
|
|
27816
|
+
const isOld = date5 < cutoffStr;
|
|
27817
|
+
const isTtlExpired = ttl && isExpired(ttl);
|
|
27818
|
+
if (isOld || isTtlExpired) {
|
|
27746
27819
|
toArchive.push(line.trim());
|
|
27747
27820
|
} else {
|
|
27748
27821
|
toKeep.push(line.trim());
|
|
@@ -27792,10 +27865,11 @@ server.registerTool(
|
|
|
27792
27865
|
key: external_exports.string().describe("T\xEDtulo corto en kebab-case (ej: risk-engine-prioridad)"),
|
|
27793
27866
|
content: external_exports.string().describe("Contenido detallado del hecho"),
|
|
27794
27867
|
file: external_exports.string().optional().default("").describe("Archivo o l\xEDnea relacionada (ej: spec.md:145)"),
|
|
27795
|
-
tags: external_exports.string().optional().default("").describe("Tags separados por punto y coma (ej: risk;spec)")
|
|
27868
|
+
tags: external_exports.string().optional().default("").describe("Tags separados por punto y coma (ej: risk;spec)"),
|
|
27869
|
+
ttl: external_exports.string().optional().default("").describe("Time to live (ej: 7d, 2026-07-17). Vac\xEDo = sin expiraci\xF3n")
|
|
27796
27870
|
}
|
|
27797
27871
|
},
|
|
27798
|
-
async ({ category, key, content, file: file2, tags }) => {
|
|
27872
|
+
async ({ category, key, content, file: file2, tags, ttl }) => {
|
|
27799
27873
|
const data = readMemory();
|
|
27800
27874
|
const newId = generateId();
|
|
27801
27875
|
const date5 = (/* @__PURE__ */ new Date()).toISOString().split("T")[0];
|
|
@@ -27819,8 +27893,11 @@ server.registerTool(
|
|
|
27819
27893
|
}
|
|
27820
27894
|
}
|
|
27821
27895
|
const entryId = existingIdx !== -1 ? existingId : newId;
|
|
27822
|
-
const
|
|
27896
|
+
const resolvedTtl = parseTTL(ttl);
|
|
27897
|
+
const resolvedTags = tags ? tags : inferTags(content, key);
|
|
27898
|
+
const newEntry = `${entryId}|${category}|${key}|${content}|${file2 || ""}|${resolvedTags}|${date5}|${resolvedTtl}`;
|
|
27823
27899
|
let action = "Guardado";
|
|
27900
|
+
const tagsInferred = !tags && resolvedTags ? true : false;
|
|
27824
27901
|
if (existingIdx !== -1) {
|
|
27825
27902
|
lines[existingIdx] = ` ${newEntry}`;
|
|
27826
27903
|
action = "Actualizado";
|
|
@@ -27831,9 +27908,23 @@ server.registerTool(
|
|
|
27831
27908
|
lines[headerIdx] = lines[headerIdx].replace(/\[\d+\|/, `[${count + 1}|`);
|
|
27832
27909
|
}
|
|
27833
27910
|
writeMemory(lines.join("\n"));
|
|
27911
|
+
const headerMatch = lines[headerIdx].match(/\[(\d+)\|/);
|
|
27912
|
+
const entryCount = headerMatch ? parseInt(headerMatch[1]) : 0;
|
|
27913
|
+
let archiveMsg = "";
|
|
27914
|
+
if (entryCount > MAX_ENTRIES) {
|
|
27915
|
+
const result = archiveOldEntries();
|
|
27916
|
+
if (result.archived > 0) {
|
|
27917
|
+
archiveMsg = `
|
|
27918
|
+
\u{1F4E6} Auto-archived ${result.archived} old entries (${result.kept} kept)`;
|
|
27919
|
+
}
|
|
27920
|
+
}
|
|
27921
|
+
const ttlMsg = resolvedTtl ? `
|
|
27922
|
+
\u23F0 TTL: ${resolvedTtl}` : "";
|
|
27923
|
+
const inferredMsg = tagsInferred ? `
|
|
27924
|
+
\u{1F3F7}\uFE0F Tags inferidos: ${resolvedTags}` : "";
|
|
27834
27925
|
return {
|
|
27835
27926
|
content: [{ type: "text", text: `\u{1F9E0} ${action}: ${category}/${key} (${entryId})
|
|
27836
|
-
${content}` }]
|
|
27927
|
+
${content}${ttlMsg}${inferredMsg}${archiveMsg}` }]
|
|
27837
27928
|
};
|
|
27838
27929
|
}
|
|
27839
27930
|
);
|
|
@@ -27858,10 +27949,11 @@ server.registerTool(
|
|
|
27858
27949
|
const trimmed = line.trim();
|
|
27859
27950
|
const parts = trimmed.split("|");
|
|
27860
27951
|
if (parts.length < 7) return null;
|
|
27861
|
-
const [id, cat, key, content, file2, tags, date5] = parts;
|
|
27952
|
+
const [id, cat, key, content, file2, tags, date5, ttl] = parts;
|
|
27862
27953
|
if (category && cat !== category) return null;
|
|
27863
27954
|
if (from_date && date5 < from_date) return null;
|
|
27864
27955
|
if (to_date && date5 > to_date) return null;
|
|
27956
|
+
if (ttl && isExpired(ttl)) return null;
|
|
27865
27957
|
const searchStr = normalize(`${id} ${cat} ${key} ${content} ${file2} ${tags}`);
|
|
27866
27958
|
if (!queryTokens.every((token) => searchStr.includes(token))) return null;
|
|
27867
27959
|
return { id, cat, key, content, file: file2, tags, date: date5 };
|
|
@@ -27919,12 +28011,14 @@ server.registerTool(
|
|
|
27919
28011
|
const lines = data.split("\n").filter((l) => l.startsWith(" ") && l.includes("|") && !l.startsWith(" summaries:"));
|
|
27920
28012
|
const entries = lines.map((l) => {
|
|
27921
28013
|
const parts = l.trim().split("|");
|
|
27922
|
-
return { category: parts[1] || "unknown" };
|
|
28014
|
+
return { category: parts[1] || "unknown", ttl: parts[7] || "" };
|
|
27923
28015
|
});
|
|
27924
28016
|
const byCategory = {};
|
|
27925
28017
|
for (const e of entries) {
|
|
27926
28018
|
byCategory[e.category] = (byCategory[e.category] || 0) + 1;
|
|
27927
28019
|
}
|
|
28020
|
+
const withTtl = entries.filter((e) => e.ttl).length;
|
|
28021
|
+
const expired = entries.filter((e) => e.ttl && isExpired(e.ttl)).length;
|
|
27928
28022
|
const summaryLines = data.split("\n").filter((l) => l.includes(":") && !l.startsWith(" ") && !l.startsWith("version") && !l.startsWith("entries") && !/^\[\d+\|]/.test(l));
|
|
27929
28023
|
const stats = [
|
|
27930
28024
|
`Entradas totales: ${entries.length}`,
|
|
@@ -27933,15 +28027,67 @@ server.registerTool(
|
|
|
27933
28027
|
"Por categor\xEDa:",
|
|
27934
28028
|
...Object.entries(byCategory).map(([k, v]) => ` ${k}: ${v}`),
|
|
27935
28029
|
"",
|
|
28030
|
+
`TTL: ${withTtl} con expiraci\xF3n, ${expired} expiradas`,
|
|
28031
|
+
"",
|
|
27936
28032
|
`\xDAltimas 5 entradas:`,
|
|
27937
28033
|
...lines.slice(-5).map((l) => {
|
|
27938
28034
|
const parts = l.trim().split("|");
|
|
27939
|
-
|
|
28035
|
+
const ttlInfo = parts[7] ? ` | TTL: ${parts[7]}` : "";
|
|
28036
|
+
return ` [${parts[1]}] ${parts[2]} (${parts[0]})${ttlInfo}`;
|
|
27940
28037
|
})
|
|
27941
28038
|
];
|
|
27942
28039
|
return { content: [{ type: "text", text: stats.join("\n") }] };
|
|
27943
28040
|
}
|
|
27944
28041
|
);
|
|
28042
|
+
server.registerTool(
|
|
28043
|
+
"memory_diff",
|
|
28044
|
+
{
|
|
28045
|
+
title: "Memory Diff",
|
|
28046
|
+
description: "Muestra qu\xE9 cambi\xF3 en la memoria desde una fecha. \xDAtil para saber qu\xE9 se aprendi\xF3 desde la \xFAltima sesi\xF3n.",
|
|
28047
|
+
inputSchema: {
|
|
28048
|
+
since: external_exports.string().describe("Desde cu\xE1ndo mostrar cambios (ej: 24h, 7d, 2026-07-10)"),
|
|
28049
|
+
type: external_exports.enum(["all", "created", "updated"]).optional().default("all").describe("Filtrar por tipo de cambio")
|
|
28050
|
+
}
|
|
28051
|
+
},
|
|
28052
|
+
async ({ since, type }) => {
|
|
28053
|
+
const sinceDate = parseRelativeDate(since);
|
|
28054
|
+
const today = (/* @__PURE__ */ new Date()).toISOString().split("T")[0];
|
|
28055
|
+
const data = readMemory();
|
|
28056
|
+
const lines = data.split("\n").filter((l) => l.startsWith(" ") && l.includes("|") && !l.startsWith(" summaries:"));
|
|
28057
|
+
const results = lines.map((line) => {
|
|
28058
|
+
const trimmed = line.trim();
|
|
28059
|
+
const parts = trimmed.split("|");
|
|
28060
|
+
if (parts.length < 7) return null;
|
|
28061
|
+
const [id, cat, key, content, file2, tags, date5] = parts;
|
|
28062
|
+
if (date5 < sinceDate) return null;
|
|
28063
|
+
const changeType = date5 === today ? "created" : "updated";
|
|
28064
|
+
if (type !== "all" && changeType !== type) return null;
|
|
28065
|
+
return { id, cat, key, content, file: file2, tags, date: date5, changeType };
|
|
28066
|
+
}).filter(Boolean);
|
|
28067
|
+
if (results.length === 0) {
|
|
28068
|
+
return { content: [{ type: "text", text: `No hay cambios desde ${sinceDate}` }] };
|
|
28069
|
+
}
|
|
28070
|
+
const created = results.filter((r) => r.changeType === "created");
|
|
28071
|
+
const updated = results.filter((r) => r.changeType === "updated");
|
|
28072
|
+
const sections = [`\u{1F4CB} Cambios desde ${sinceDate}:`, ""];
|
|
28073
|
+
if (created.length > 0 && (type === "all" || type === "created")) {
|
|
28074
|
+
sections.push(`\u2795 Nuevas (${created.length}):`);
|
|
28075
|
+
for (const r of created) {
|
|
28076
|
+
sections.push(` [${r.cat}] ${r.key} (${r.id})
|
|
28077
|
+
${r.content}`);
|
|
28078
|
+
}
|
|
28079
|
+
sections.push("");
|
|
28080
|
+
}
|
|
28081
|
+
if (updated.length > 0 && (type === "all" || type === "updated")) {
|
|
28082
|
+
sections.push(`\u270F\uFE0F Actualizadas (${updated.length}):`);
|
|
28083
|
+
for (const r of updated) {
|
|
28084
|
+
sections.push(` [${r.cat}] ${r.key} (${r.id}) \u2014 ${r.date}`);
|
|
28085
|
+
}
|
|
28086
|
+
sections.push("");
|
|
28087
|
+
}
|
|
28088
|
+
return { content: [{ type: "text", text: sections.join("\n") }] };
|
|
28089
|
+
}
|
|
28090
|
+
);
|
|
27945
28091
|
server.registerTool(
|
|
27946
28092
|
"memory_summary",
|
|
27947
28093
|
{
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "toon-memory",
|
|
3
|
-
"version": "1.
|
|
3
|
+
"version": "1.8.0",
|
|
4
4
|
"description": "Persistent memory system for AI coding agents using TOON format (40% fewer tokens than JSON)",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"bin": {
|
|
@@ -45,6 +45,14 @@
|
|
|
45
45
|
"windsurf",
|
|
46
46
|
"cline",
|
|
47
47
|
"continue",
|
|
48
|
+
"codex",
|
|
49
|
+
"gemini",
|
|
50
|
+
"zed",
|
|
51
|
+
"antigravity",
|
|
52
|
+
"aider",
|
|
53
|
+
"kilocode",
|
|
54
|
+
"openclaw",
|
|
55
|
+
"kiro",
|
|
48
56
|
"ai-agent",
|
|
49
57
|
"memory",
|
|
50
58
|
"toon",
|
package/skills/toon-memory.md
CHANGED
|
@@ -6,16 +6,23 @@ A persistent memory system for AI coding agents. It remembers decisions, pattern
|
|
|
6
6
|
|
|
7
7
|
## Supported Agents
|
|
8
8
|
|
|
9
|
-
| Agent | Config File | Format |
|
|
10
|
-
|
|
11
|
-
| OpenCode | `.opencode/opencode.json` | MCP server |
|
|
12
|
-
| VS Code / Copilot | `.vscode/mcp.json` | MCP server |
|
|
13
|
-
| Claude | `.claude/settings.json` | MCP server |
|
|
14
|
-
| Cursor | `.cursor/mcp.json` | MCP server |
|
|
15
|
-
| Windsurf |
|
|
16
|
-
| Cline | `.cline/mcp.json` | MCP server |
|
|
17
|
-
| Continue | `.continue/config.json` | MCP server |
|
|
18
|
-
|
|
|
9
|
+
| Agent | Config File | Format | Hooks |
|
|
10
|
+
|-------|-------------|--------|-------|
|
|
11
|
+
| OpenCode | `.opencode/opencode.json` | MCP server | — |
|
|
12
|
+
| VS Code / Copilot | `.vscode/mcp.json` | MCP server | — |
|
|
13
|
+
| Claude Code | `.claude/settings.json` | MCP server | SessionStart |
|
|
14
|
+
| Cursor | `.cursor/mcp.json` | MCP server | — |
|
|
15
|
+
| Windsurf | `~/.codeium/windsurf/mcp_config.json` | MCP server | — |
|
|
16
|
+
| Cline | `.cline/mcp.json` | MCP server | — |
|
|
17
|
+
| Continue | `.continue/config.json` | MCP server | — |
|
|
18
|
+
| Codex CLI | `.codex/config.toml` | TOML | SessionStart |
|
|
19
|
+
| Gemini CLI | `.gemini/settings.json` | MCP server | SessionStart |
|
|
20
|
+
| Zed | `~/.config/zed/settings.json` | JSONC | — |
|
|
21
|
+
| Antigravity | `.gemini/config/mcp_config.json` | MCP server | SessionStart |
|
|
22
|
+
| Aider | — | Instructions only | — |
|
|
23
|
+
| KiloCode | `~/.kilocode/mcp_settings.json` | MCP server | — |
|
|
24
|
+
| OpenClaw | `.openclaw.json` | MCP server | — |
|
|
25
|
+
| Kiro | `.kiro/settings/mcp.json` | MCP server | — |
|
|
19
26
|
|
|
20
27
|
## Tools
|
|
21
28
|
|
|
@@ -26,6 +33,9 @@ A persistent memory system for AI coding agents. It remembers decisions, pattern
|
|
|
26
33
|
| `memory_forget` | Remove an entry by key or id |
|
|
27
34
|
| `memory_stats` | View memory state |
|
|
28
35
|
| `memory_summary` | Save/retrieve file summaries |
|
|
36
|
+
| `memory_archive` | Archive old entries |
|
|
37
|
+
| `memory_encrypt` | Enable encryption |
|
|
38
|
+
| `memory_decrypt` | Disable encryption |
|
|
29
39
|
|
|
30
40
|
## Installation
|
|
31
41
|
|
|
@@ -37,8 +47,9 @@ npx toon-memory
|
|
|
37
47
|
|
|
38
48
|
This will:
|
|
39
49
|
1. Detect installed agents
|
|
40
|
-
2.
|
|
41
|
-
3.
|
|
50
|
+
2. Let you select which agents to configure
|
|
51
|
+
3. Ask for local or global installation
|
|
52
|
+
4. Configure MCP server, instructions, and hooks automatically
|
|
42
53
|
|
|
43
54
|
### Manual installation
|
|
44
55
|
|
|
@@ -71,7 +82,7 @@ Add to your agent's MCP config:
|
|
|
71
82
|
### When exploring the project
|
|
72
83
|
|
|
73
84
|
1. First: `memory_recall(query="what you need to know")`
|
|
74
|
-
2. If no result: use
|
|
85
|
+
2. If no result: use grep or search tools
|
|
75
86
|
3. Only if both fail: read files directly
|
|
76
87
|
|
|
77
88
|
### At the END of every session
|
|
@@ -91,7 +102,7 @@ Add to your agent's MCP config:
|
|
|
91
102
|
|
|
92
103
|
## File format
|
|
93
104
|
|
|
94
|
-
Data is stored in `.
|
|
105
|
+
Data is stored in `.toon-memory/memory/data.toon` using TOON (Token-Oriented Object Notation):
|
|
95
106
|
|
|
96
107
|
```
|
|
97
108
|
version: 1
|