Skip to main content

Documentation Index

Fetch the complete documentation index at: https://mintlify.com/QwenLM/qwen-code/llms.txt

Use this file to discover all available pages before exploring further.

Memory System

Qwen Code’s memory system allows the AI to remember important facts, preferences, and context across sessions, providing personalized and context-aware assistance.

Overview

The memory system consists of:
  • Global Memory: User-level facts shared across all projects (~/.qwen/QWEN.md)
  • Project Memory: Project-specific context (.qwen/QWEN.md or QWEN.md in project root)
  • Hierarchical Loading: Automatic discovery from workspace root to current directory
  • Import System: Include external files and organize memory content

Memory Files

File Locations

From packages/core/src/tools/memoryTool.ts:77:
export const QWEN_CONFIG_DIR = '.qwen';
export const DEFAULT_CONTEXT_FILENAME = 'QWEN.md';
export const AGENT_CONTEXT_FILENAME = 'AGENTS.md';
export const MEMORY_SECTION_HEADER = '## Qwen Added Memories';
Global memory:
~/.qwen/QWEN.md
~/.qwen/AGENTS.md
Project memory:
/path/to/project/QWEN.md
/path/to/project/.qwen/QWEN.md
/path/to/project/AGENTS.md

File Format

Memory files are Markdown documents with optional structure:
# Project Context

This is a Next.js application using TypeScript and Tailwind CSS.

## Architecture

- Frontend: React components in `src/components/`
- Backend: API routes in `src/pages/api/`
- Database: PostgreSQL with Prisma ORM

## Qwen Added Memories

- User prefers functional components over class components
- Always use `const` instead of `let` when possible
- API endpoints should return JSON with snake_case keys
- Tests use Vitest instead of Jest

Memory Tool

The save_memory tool allows Qwen Code to store facts for future reference.

Tool Schema

From memoryTool.ts:31:
interface SaveMemoryParams {
  fact: string;                // Required: The fact to remember
  scope?: 'global' | 'project'; // Optional: Where to save
  modified_by_user?: boolean;   // Internal: User edited content
  modified_content?: string;    // Internal: Modified content
}

Usage Examples

Save to Global Memory

{
  fact: "User prefers TypeScript for new projects",
  scope: "global"
}
This appends to ~/.qwen/QWEN.md:
## Qwen Added Memories
- User prefers TypeScript for new projects

Save to Project Memory

{
  fact: "API uses OAuth2 with client credentials flow",
  scope: "project"
}
This appends to project’s QWEN.md:
## Qwen Added Memories
- API uses OAuth2 with client credentials flow

Interactive Scope Selection

If scope is omitted, user is prompted to choose:
{ fact: "Database credentials in 1Password vault" }
User sees:
Choose where to save this memory:

"Database credentials in 1Password vault"

Options:
- Global: ~/.qwen/QWEN.md (shared across all projects)
- Project: /path/to/project/QWEN.md (current project only)

Tool Behavior

From memoryTool.ts:165:
/**
 * Computes the new content that would result from adding a memory entry
 */
function computeNewContent(currentContent: string, fact: string): string {
  let processedText = fact.trim();
  processedText = processedText.replace(/^(-+\s*)+/, '').trim();
  const newMemoryItem = `- ${processedText}`;

  const headerIndex = currentContent.indexOf(MEMORY_SECTION_HEADER);

  if (headerIndex === -1) {
    // Header not found, append header and then the entry
    const separator = ensureNewlineSeparation(currentContent);
    return (
      currentContent +
      `${separator}${MEMORY_SECTION_HEADER}\n${newMemoryItem}\n`
    );
  } else {
    // Header found, append to section
    const startOfSectionContent = headerIndex + MEMORY_SECTION_HEADER.length;
    let endOfSectionIndex = currentContent.indexOf(
      '\n## ',
      startOfSectionContent,
    );
    if (endOfSectionIndex === -1) {
      endOfSectionIndex = currentContent.length;
    }

    const beforeSectionMarker = currentContent
      .substring(0, startOfSectionContent)
      .trimEnd();
    let sectionContent = currentContent
      .substring(startOfSectionContent, endOfSectionIndex)
      .trimEnd();
    const afterSectionMarker = currentContent.substring(endOfSectionIndex);

    sectionContent += `\n${newMemoryItem}`;
    return (
      `${beforeSectionMarker}\n${sectionContent.trimStart()}\n${afterSectionMarker}`.trimEnd() +
      '\n'
    );
  }
}
Key behaviors:
  • Creates ## Qwen Added Memories section if it doesn’t exist
  • Appends new facts as bullet points
  • Strips leading dashes from fact text
  • Maintains proper spacing

Hierarchical Memory Loading

Qwen Code automatically discovers and loads memory files in a hierarchical manner.

Discovery Process

From packages/core/src/utils/memoryDiscovery.ts:24:
async function findProjectRoot(startDir: string): Promise<string | null> {
  let currentDir = path.resolve(startDir);
  while (true) {
    const gitPath = path.join(currentDir, '.git');
    try {
      const stats = await fs.lstat(gitPath);
      if (stats.isDirectory()) {
        return currentDir;
      }
    } catch (error) {
      // Continue searching upward
    }
    const parentDir = path.dirname(currentDir);
    if (parentDir === currentDir) {
      return null; // Reached root
    }
    currentDir = parentDir;
  }
}

Load Order

From memoryDiscovery.ts:68:
export async function getGeminiMdFilePathsInternal(
  currentWorkingDirectory: string,
  includeDirectoriesToReadGemini: readonly string[],
  userHomePath: string,
  fileService: FileDiscoveryService,
  extensionContextFilePaths: string[] = [],
  folderTrust: boolean,
): Promise<string[]> {
  const dirs = new Set<string>([
    ...includeDirectoriesToReadGemini,
    currentWorkingDirectory,
  ]);
  
  // Process directories in parallel with concurrency limit
  const CONCURRENT_LIMIT = 10;
  // ...
}
Memory files are loaded in this order:
  1. Global memory (~/.qwen/QWEN.md)
  2. Project root (found via .git directory)
  3. Intermediate directories (between project root and current directory)
  4. Current directory
  5. Extension context files (if any)
Example for /home/user/projects/myapp/src/components/:
~/.qwen/QWEN.md                           # Global
/home/user/projects/myapp/QWEN.md         # Project root
/home/user/projects/myapp/src/QWEN.md     # Subdirectory
/home/user/projects/myapp/src/components/QWEN.md  # Current dir

Content Concatenation

From memoryDiscovery.ts:282:
function concatenateInstructions(
  instructionContents: GeminiFileContent[],
  currentWorkingDirectoryForDisplay: string,
): string {
  return instructionContents
    .filter((item) => typeof item.content === 'string')
    .map((item) => {
      const trimmedContent = (item.content as string).trim();
      if (trimmedContent.length === 0) {
        return null;
      }
      const displayPath = path.isAbsolute(item.filePath)
        ? path.relative(currentWorkingDirectoryForDisplay, item.filePath)
        : item.filePath;
      return `--- Context from: ${displayPath} ---\n${trimmedContent}\n--- End of Context from: ${displayPath} ---`;
    })
    .filter((block): block is string => block !== null)
    .join('\n\n');
}
Final memory content:
--- Context from: ../.qwen/QWEN.md ---
# Global Context
- User works with TypeScript
--- End of Context from: ../.qwen/QWEN.md ---

--- Context from: QWEN.md ---
# Project Context
- Next.js application
--- End of Context from: QWEN.md ---

--- Context from: src/QWEN.md ---
# Source Directory
- Components use Tailwind
--- End of Context from: src/QWEN.md ---

Import System

Memory files support importing other files.

Import Syntax

From packages/core/src/utils/memoryImportProcessor.ts:
<!-- @import: path/to/file.md -->
<!-- @import: ../docs/api-guide.md -->
<!-- @import: ~/.config/coding-standards.md -->

Import Formats

Tree Format (default):
<imported from="docs/setup.md">
# Setup Guide
...
</imported>
Flat Format:
# Setup Guide
...
Configuration:
import { loadServerHierarchicalMemory } from '@qwen-code/qwen-code-core';

const { memoryContent } = await loadServerHierarchicalMemory(
  cwd,
  includeDirs,
  fileService,
  extensionContextFilePaths,
  folderTrust,
  'tree'  // or 'flat'
);

Recursive Imports

Imports can be nested:
<!-- File: QWEN.md -->
# Project Context

<!-- @import: docs/architecture.md -->

<!-- File: docs/architecture.md -->
# Architecture

<!-- @import: api/endpoints.md -->

<!-- File: api/endpoints.md -->
# API Endpoints
...

Configuration

Custom Filenames

From memoryTool.ts:90:
export function setGeminiMdFilename(newFilename: string | string[]): void {
  if (Array.isArray(newFilename)) {
    if (newFilename.length > 0) {
      currentGeminiMdFilename = newFilename.map((name) => name.trim());
    }
  } else if (newFilename && newFilename.trim() !== '') {
    currentGeminiMdFilename = newFilename.trim();
  }
}
Usage:
import { setGeminiMdFilename } from '@qwen-code/qwen-code-core';

// Single filename
setGeminiMdFilename('CONTEXT.md');

// Multiple filenames (checked in order)
setGeminiMdFilename(['QWEN.md', 'AGENTS.md', 'CONTEXT.md']);

Folder Trust

Memory loading respects folder trust settings:
const { memoryContent } = await loadServerHierarchicalMemory(
  cwd,
  includeDirs,
  fileService,
  extensionContextFilePaths,
  folderTrust: true  // Enable workspace scanning
);
When folderTrust is false, only global memory and explicitly included directories are loaded.

Best Practices

When to Use Global vs Project Memory

Global Memory (~/.qwen/QWEN.md):
  • Personal preferences and coding style
  • Tool configurations
  • Common patterns across all projects
  • Credential locations (not the credentials themselves!)
Example:
## Qwen Added Memories
- User prefers functional programming style
- Always use `const` instead of `let` when possible
- Database credentials stored in 1Password
- Prefer explicit error handling over try-catch
Project Memory (project’s QWEN.md):
  • Project architecture and structure
  • Technology stack and versions
  • Build and deployment processes
  • Team conventions
  • API endpoints and schemas
Example:
## Project Context

Next.js 14 application with App Router.

### Architecture
- `/app`: Next.js App Router pages
- `/components`: Reusable React components
- `/lib`: Utility functions and API clients
- `/prisma`: Database schema and migrations

### Tech Stack
- TypeScript 5.3
- React 18
- Tailwind CSS 3.4
- Prisma 5.x
- PostgreSQL 16

## Qwen Added Memories
- API uses camelCase for request/response
- All components must have PropTypes
- Use React Query for data fetching
- Prefer server components over client components

Memory File Organization

Structure memory files for clarity:
# Project Title

Brief project description.

## Architecture

High-level architecture overview.

## Technology Stack

List of technologies and versions.

## Development Workflow

Build, test, and deployment processes.

## Coding Standards

Team conventions and preferences.

## Qwen Added Memories

- Dynamic facts added by Qwen Code
- User preferences specific to this project

Import Organization

Use imports to keep files manageable:
<!-- Main QWEN.md -->
# Project Context

<!-- @import: docs/architecture.md -->
<!-- @import: docs/api-reference.md -->
<!-- @import: docs/deployment.md -->

## Qwen Added Memories
- (Dynamic content here)
This keeps the main file clean while providing comprehensive context.

Avoid Sensitive Information

Never store sensitive data in memory files: Bad:
- Database password: super_secret_123
- API key: sk-1234567890abcdef
Good:
- Database credentials stored in 1Password vault "Production"
- API keys managed via environment variables in `.env.local`
- Secrets rotation handled by DevOps team quarterly

Advanced Usage

Programmatic Memory Access

import { 
  loadServerHierarchicalMemory,
  FileDiscoveryService 
} from '@qwen-code/qwen-code-core';

const fileService = new FileDiscoveryService();

const { memoryContent, fileCount } = await loadServerHierarchicalMemory(
  process.cwd(),
  ['/additional/path'],
  fileService,
  [],
  true,  // folderTrust
  'tree' // importFormat
);

console.log(`Loaded ${fileCount} memory files`);
console.log(memoryContent);

Memory in Resumable Sessions

Memory content is included in session checkpoints:
// Memory loaded at session start
const initialMemory = await loadServerHierarchicalMemory(...);

// Included in system prompt
const systemPrompt = `
${baseInstructions}

${initialMemory.memoryContent}
`;

// Memory persists across resume
qwen --resume <session-id>
// Same memory context restored

Extension Context Files

Extensions can provide additional context:
const extensionContextPaths = [
  '/path/to/extension/context.md',
  '/another/extension/docs.md'
];

const { memoryContent } = await loadServerHierarchicalMemory(
  cwd,
  includeDirs,
  fileService,
  extensionContextPaths,  // Added to memory
  true
);

Troubleshooting

Memory Not Loading

Problem: Qwen Code doesn’t seem to remember context. Check:
# Verify files exist
ls -la ~/.qwen/QWEN.md
ls -la QWEN.md
ls -la .qwen/QWEN.md

# Check folder trust
qwen config get folderTrust

# Enable if disabled
qwen config set folderTrust true

Import Loops

Problem: Circular imports cause issues. Solution: Imports track visited files to prevent loops:
// From memoryImportProcessor.ts
const visitedFiles = new Set<string>();

if (visitedFiles.has(resolvedPath)) {
  // Skip already imported file
  continue;
}
visitedFiles.add(resolvedPath);
Avoid circular references:
<!-- A.md -->
<!-- @import: B.md -->  ❌ Don't create loops

<!-- B.md -->
<!-- @import: A.md -->  ❌ Don't create loops

Large Memory Files

Problem: Memory files too large, wasting tokens. Solution:
  1. Use imports to split content
  2. Keep only essential information
  3. Archive outdated context
# Move old content to archive
mkdir -p .qwen/archive
mv QWEN.md .qwen/archive/QWEN-$(date +%Y%m%d).md

# Start fresh
cat > QWEN.md << 'EOF'
# Project Context

<!-- @import: .qwen/archive/QWEN-20240315.md -->

## Current Context
(New, relevant information)
EOF

Permission Issues

Problem: Cannot write to global memory file. Solution:
# Check permissions
ls -la ~/.qwen/

# Fix if needed
chmod 755 ~/.qwen
chmod 644 ~/.qwen/QWEN.md

# Create if missing
mkdir -p ~/.qwen
touch ~/.qwen/QWEN.md

Source Code References

  • Memory tool: packages/core/src/tools/memoryTool.ts
  • Memory discovery: packages/core/src/utils/memoryDiscovery.ts
  • Import processor: packages/core/src/utils/memoryImportProcessor.ts
  • Configuration: packages/core/src/config/config.ts:52