# Lemon AI Self-Evolving Memory System Architecture: A Technical Deep Dive

> Explore the Lemon AI self-evolving memory architecture. Discover how layered JSON storage refines agent behavior with execution traces and reflection feedback.

- Repository: [hexdocom/lemonai](https://github.com/hexdocom/lemonai)
- Tags: architecture
- Published: 2026-03-03

---

**Lemon AI implements a self-evolving memory architecture that continuously refines agent behavior by persisting execution traces, reflection feedback, and knowledge items across layered JSON storage systems.**

The hexdocom/lemonai repository introduces a modular memory stack designed to overcome the limitations of static LLM context windows. Unlike traditional agent systems that lose state between sessions, this self-evolving architecture combines per-task message logs, long-term knowledge storage, and automated runtime hooks that capture every action outcome. The implementation relies on lightweight JSON-file stores and a reflection engine that feeds evaluation results back into subsequent reasoning cycles.

## Architecture Overview

The Lemon AI self-evolving memory system operates through five distinct layers, each responsible for specific persistence and retrieval functions. The following table maps each layer to its core implementation file and role in the continuous learning loop:

| Layer | Responsibility | Core Implementation | How it fits in the loop |
|-------|----------------|--------------------|------------------------|
| **Per-task message memory** | Stores chronological dialogue between the LLM and user, plus metadata for each action (e.g., whether it should be memorized). | `LocalMemory` – stores a JSON file per task in [`src/agent/memory/LocalMemory.js`](https://github.com/hexdocom/lemonai/blob/main/src/agent/memory/LocalMemory.js) | Each iteration of **code-act** (`completeCodeAct`) loads the file, appends a new message via `memory.addMessage`, and reads the full history via `memory.getMessages` to feed the next LLM prompt. |
| **Long-term knowledge storage** | Persists "memories" that survive across conversations (e.g., discovered snippets, learned facts). Supports CRUD and full-text search. | `MemoryStorage` (abstract) in [`src/knowledge/MemoryStorage.js`](https://github.com/hexdocom/lemonai/blob/main/src/knowledge/MemoryStorage.js) → `FileStorage` (file-based implementation) in [`src/knowledge/FileStorage.js`](https://github.com/hexdocom/lemonai/blob/main/src/knowledge/FileStorage.js) | When a tool marks an action as `memorized`, `DockerRuntime.handle_memory` writes a concise summary into the per-task `LocalMemory`. Higher-level agents can later move interesting entries into `FileStorage` for reuse. |
| **Reflection engine** | Evaluates the result of an action using either a simple status check or a secondary LLM call, then returns structured XML that may trigger new actions. | `reflection` in [`src/agent/reflection/index.js`](https://github.com/hexdocom/lemonai/blob/main/src/agent/reflection/index.js) | After a tool finishes, `code-act` calls `reflection(requirement, action_result, conversation_id)`. The returned `status` and `comments` are logged back into `LocalMemory` and fed into the next LLM thinking round. |
| **Runtime / Execution layer** | Executes concrete tool actions (write files, run terminals, call Docker containers) and forwards their outcomes to memory. | `DockerRuntime` in [`src/runtime/DockerRuntime.js`](https://github.com/hexdocom/lemonai/blob/main/src/runtime/DockerRuntime.js) (also `LocalRuntime` for non-Docker env) | `DockerRuntime.execute_action` runs the tool, then calls `handle_memory(result, action, context.memory)`. The helper builds a `meta` object (including `action_memory`) and stores it via `memory.addMessage`. |
| **Code-Act orchestrator** | The main loop that drives LLM reasoning, parses XML actions, executes them, and decides when to stop or pause. | `completeCodeAct` in [`src/agent/code-act/code-act.js`](https://github.com/hexdocom/lemonai/blob/main/src/agent/code-act/code-act.js) | The orchestrator repeatedly: (1) **think** → (2) **parse** → (3) **execute** → (4) **reflect** → (5) **log**. Each cycle enriches the per-task memory, making the next LLM call "self-evolving". |

## Data Flow in a Single Iteration

Understanding the Lemon AI self-evolving memory architecture requires tracing how data moves through the system during one complete execution cycle. The `completeCodeAct` orchestrator in [`src/agent/code-act/code-act.js`](https://github.com/hexdocom/lemonai/blob/main/src/agent/code-act/code-act.js) drives this process through five distinct phases:

1. **Think** – The `thinking(requirement, context)` function creates a prompt that includes the current `memory` (full message history loaded via `memory.getMessages`) and any prior `reflection` feedback.

2. **Parse** – The `resolveActions` utility turns the LLM's XML output into a structured `action` object containing the tool type and parameters.

3. **Execute** – `runtime.execute_action(action, context, task.id)` runs the tool within the Docker container or local environment.

4. **Handle Memory** – Inside `DockerRuntime.handle_memory` (defined in [`src/runtime/DockerRuntime.js`](https://github.com/hexdocom/lemonai/blob/main/src/runtime/DockerRuntime.js)), the system:
   - Detects if the tool belongs to the `memorized_type` set (`read_file`, `write_code`, `terminal_run`).
   - Calls `tool.resolveMemory` (if provided) to generate a concise XML snippet (`action_memory`).
   - Invokes `memory.addMessage('user', content, action.type, memorized, meta)` to persist the trace.

5. **Reflect** – The `reflection(requirement, action_result, conversation_id)` function (from [`src/agent/reflection/index.js`](https://github.com/hexdocom/lemonai/blob/main/src/agent/reflection/index.js)) evaluates the outcome using either heuristic status checks or secondary LLM calls, returning structured XML containing a `status` field and `comments`.

6. **Log Reflection** – If reflection indicates failure, the orchestrator writes the comment back into `LocalMemory` via `memory.addMessage("user", comments)` and may trigger a retry loop.

Because `memory` persists as a JSON file on disk, the next loop iteration loads the same file, automatically "remembering" everything that occurred earlier. This persistence mechanism forms the core of the **self-evolving** capability.

## Implementation Examples

The following code examples demonstrate how to interact with the memory system components directly, illustrating the practical implementation of the Lemon AI self-evolving memory architecture.

### Using LocalMemory for Per-Task Persistence

The `LocalMemory` class in [`src/agent/memory/LocalMemory.js`](https://github.com/hexdocom/lemonai/blob/main/src/agent/memory/LocalMemory.js) provides the primary interface for storing conversation history and action metadata within a single task context.

```javascript
// Create a task-scoped memory (task id = 42, sub-folder = "a1b2c3")
const LocalMemory = require("@src/agent/memory/LocalMemory");
const memory = new LocalMemory({ memory_dir: "a1b2c3", key: 42 });

// Add a user prompt (memorized = true so it will be stored as action_memory)
await memory.addMessage(
  "user",
  "Create a file named hello.js with console.log('Hi')",
  "write_code",
  true,
  { action: { type: "write_code", params: { path: "hello.js" } } }
);

// Retrieve the whole conversation history
const history = await memory.getMessages();
console.log(history);

```

This example demonstrates how `LocalMemory.addMessage` persists structured data including the action type, memorization flag, and metadata, while `LocalMemory.getMessages` retrieves the complete history for context window construction.

### Storing Long-Term Knowledge with FileStorage

For cross-session persistence, the `FileStorage` implementation in [`src/knowledge/FileStorage.js`](https://github.com/hexdocom/lemonai/blob/main/src/knowledge/FileStorage.js) extends the abstract `MemoryStorage` interface to provide CRUD operations and full-text search capabilities.

```javascript
const FileStorage = require("@src/knowledge/FileStorage");

// Instantiate a knowledge store for the "coding" domain
const knowledgeStore = new FileStorage({ directory: "coding" });

const mem = {
  content: "The Node.js `fs` module provides synchronous and asynchronous file APIs.",
  metadata: { tags: ["node", "fs"], source: "official docs" }
};

// Persist the memory (auto-generates an UUID)
const saved = await knowledgeStore.save(mem);
console.log("Saved memory id:", saved.id);

// Search for all memories containing the word "file"
const results = await knowledgeStore.search("file", { limit: 5 });
console.log("Search hits:", results);

```

The `FileStorage.save` method automatically generates UUIDs for knowledge items, while `FileStorage.search` enables retrieval of relevant historical context based on keyword matching.

### Runtime Automatic Logging

The `DockerRuntime` class in [`src/runtime/DockerRuntime.js`](https://github.com/hexdocom/lemonai/blob/main/src/runtime/DockerRuntime.js) demonstrates how execution results automatically propagate to memory without manual intervention.

```javascript
// Inside a DockerRuntime execution (simplified)
async function demo() {
  const runtime = new DockerRuntime({ user_id: "123" });
  await runtime.connect_container();               // ensures docker_host is available
  const action = { type: "write_code", params: { path: "test.txt", content: "Hello" } };
  const context = { conversation_id: "conv_001", memory: new LocalMemory({ key: "conv_001" }) };

  const result = await runtime.execute_action(action, context, "task-99");
  // After execution, result is already saved to memory:
  //   - result.content => written file content
  //   - context.memory now contains a 'user' message with `action_memory`
}

```

The `DockerRuntime.execute_action` method internally calls `handle_memory`, which constructs metadata objects and persists them via `memory.addMessage`, ensuring complete traceability of agent actions.

### Reflection Feedback Integration

The reflection mechanism in [`src/agent/reflection/index.js`](https://github.com/hexdocom/lemonai/blob/main/src/agent/reflection/index.js) closes the learning loop by evaluating action outcomes and feeding assessments back into memory.

```javascript
const reflect = require("@src/agent/reflection");
const requirement = "Generate a Python script that prints Fibonacci numbers.";
const fakeResult = { status: "success", content: "def fib():\n  ..." };

const { status, comments } = await reflect(requirement, fakeResult, "conv_002");
if (status === "success") {
  console.log("Reflection says everything is fine.");
} else {
  console.error("Reflection error:", comments);
}

```

When reflection detects failures, the orchestrator writes error comments back to `LocalMemory` via `memory.addMessage`, enabling the agent to learn from mistakes in subsequent iterations.

## Summary

- **Lemon AI's self-evolving memory system** combines per-task JSON persistence with long-term knowledge storage to create continuous learning loops that transcend static context windows.
- **`LocalMemory`** ([`src/agent/memory/LocalMemory.js`](https://github.com/hexdocom/lemonai/blob/main/src/agent/memory/LocalMemory.js)) provides the backbone for task-scoped conversation history, storing chronological dialogue and action metadata in individual JSON files per task.
- **`FileStorage`** ([`src/knowledge/FileStorage.js`](https://github.com/hexdocom/lemonai/blob/main/src/knowledge/FileStorage.js)) implements the abstract `MemoryStorage` interface for cross-session knowledge retention, supporting CRUD operations and full-text search across conversation boundaries.
- **`DockerRuntime`** ([`src/runtime/DockerRuntime.js`](https://github.com/hexdocom/lemonai/blob/main/src/runtime/DockerRuntime.js)) automatically logs execution traces through `handle_memory`, ensuring all tool interactions persist without manual intervention via `memory.addMessage`.
- **`reflection`** ([`src/agent/reflection/index.js`](https://github.com/hexdocom/lemonai/blob/main/src/agent/reflection/index.js)) closes the feedback loop by evaluating action outcomes and feeding structured assessments back into the memory stream for iterative improvement.
- The **code-act orchestrator** (`completeCodeAct` in [`src/agent/code-act/code-act.js`](https://github.com/hexdocom/lemonai/blob/main/src/agent/code-act/code-act.js)) drives the think-parse-execute-reflect-log cycle that makes the system truly self-evolving.

## Frequently Asked Questions

### How does Lemon AI decide what to store in long-term memory versus per-task memory?

The system distinguishes between transient conversation context and durable knowledge through the `memorized` flag and tool type detection. In [`src/runtime/DockerRuntime.js`](https://github.com/hexdocom/lemonai/blob/main/src/runtime/DockerRuntime.js), the `handle_memory` method checks if a tool belongs to the `memorized_type` set (including `read_file`, `write_code`, and `terminal_run`). When `memorized` is true, the runtime calls `tool.resolveMemory` to generate a concise XML snippet (`action_memory`) and persists it via `memory.addMessage`. Higher-level agents can later promote significant entries from per-task storage to `FileStorage` for cross-session reuse.

### What file format does Lemon AI use for persistent memory storage?

Lemon AI uses lightweight **JSON files** as its primary persistence mechanism. The `LocalMemory` class in [`src/agent/memory/LocalMemory.js`](https://github.com/hexdocom/lemonai/blob/main/src/agent/memory/LocalMemory.js) creates one JSON file per task (identified by a unique key), storing the chronological message history as an array of objects. Similarly, `FileStorage` in [`src/knowledge/FileStorage.js`](https://github.com/hexdocom/lemonai/blob/main/src/knowledge/FileStorage.js) persists knowledge items as individual JSON files on disk, enabling simple CRUD operations and full-text search without external database dependencies.

### How does the reflection engine contribute to the self-evolving capability?

The reflection engine in [`src/agent/reflection/index.js`](https://github.com/hexdocom/lemonai/blob/main/src/agent/reflection/index.js) serves as the critical feedback mechanism that transforms raw execution logs into learning signals. After each tool execution, the `reflection` function evaluates the `action_result` against the original `requirement` using either heuristic status checks or secondary LLM calls. It returns structured XML containing a `status` field and `comments`. The code-act orchestrator (`completeCodeAct` in [`src/agent/code-act/code-act.js`](https://github.com/hexdocom/lemonai/blob/main/src/agent/code-act/code-act.js)) then writes these assessments back into `LocalMemory` via `memory.addMessage`, ensuring that subsequent LLM prompts include prior failure analysis and corrective context, enabling iterative improvement across conversation turns.

### Can the memory system operate without Docker?

Yes, the memory architecture is runtime-agnostic regarding the execution environment. While `DockerRuntime` in [`src/runtime/DockerRuntime.js`](https://github.com/hexdocom/lemonai/blob/main/src/runtime/DockerRuntime.js) provides containerized execution with automatic memory handling, the system includes `LocalRuntime` for non-Docker environments. Both runtime implementations interact with the same `LocalMemory` interface ([`src/agent/memory/LocalMemory.js`](https://github.com/hexdocom/lemonai/blob/main/src/agent/memory/LocalMemory.js)) through the `handle_memory` pattern, ensuring that execution traces persist regardless of whether tools run inside Docker containers or directly on the host system. The abstract `MemoryStorage` interface ([`src/knowledge/MemoryStorage.js`](https://github.com/hexdocom/lemonai/blob/main/src/knowledge/MemoryStorage.js)) further ensures that long-term knowledge storage can swap between file-based, database, or vector store implementations without changing the core memory logic.