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
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
The save_memory tool allows Qwen Code to store facts for future reference.
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)
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:
- Global memory (
~/.qwen/QWEN.md)
- Project root (found via
.git directory)
- Intermediate directories (between project root and current directory)
- Current directory
- 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 -->
Tree Format (default):
<imported from="docs/setup.md">
# Setup Guide
...
</imported>
Flat Format:
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.
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:
- Use imports to split content
- Keep only essential information
- 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