diff --git a/dotnet/agent-framework-dotnet.slnx b/dotnet/agent-framework-dotnet.slnx
index 628bcaafa58..0b980a7510b 100644
--- a/dotnet/agent-framework-dotnet.slnx
+++ b/dotnet/agent-framework-dotnet.slnx
@@ -205,6 +205,7 @@
+
diff --git a/dotnet/eng/verify-samples/AgentsSamples.cs b/dotnet/eng/verify-samples/AgentsSamples.cs
index 512ce660276..b19217230ae 100644
--- a/dotnet/eng/verify-samples/AgentsSamples.cs
+++ b/dotnet/eng/verify-samples/AgentsSamples.cs
@@ -510,6 +510,28 @@ internal static class AgentsSamples
SkipReason = "Requires a running Neo4j instance; standalone sample outside the repo's CPM build.",
},
+ new SampleDefinition
+ {
+ Name = "AgentWithMemory_Step07_FileMemoryProvider",
+ ProjectPath = "samples/02-agents/AgentWithMemory/AgentWithMemory_Step07_FileMemoryProvider",
+ RequiredEnvironmentVariables = ["FOUNDRY_PROJECT_ENDPOINT"],
+ OptionalEnvironmentVariables = ["FOUNDRY_MODEL"],
+ MustContain =
+ [
+ "Memory files will be written to:",
+ "=== First conversation ===",
+ "=== Memory files on disk ===",
+ "=== Second conversation (new session) ===",
+ ],
+ ExpectedOutputDescription =
+ [
+ "The output should acknowledge that the user is vegetarian and travels with a dog, indicating the agent stored these preferences.",
+ "The memory files section should list at least one memory file written by the agent, such as a file about the user's preferences.",
+ "The second conversation should recommend a hotel and a restaurant in Paris that are consistent with the remembered preferences, for example a pet-friendly hotel and a restaurant with vegetarian options, even though it is a new session.",
+ "The output should not contain error messages or stack traces.",
+ ],
+ },
+
// ── AgentWithRAG ────────────────────────────────────────────────────
new SampleDefinition
diff --git a/dotnet/samples/02-agents/AgentWithMemory/AgentWithMemory_Step07_FileMemoryProvider/AgentWithMemory_Step07_FileMemoryProvider.csproj b/dotnet/samples/02-agents/AgentWithMemory/AgentWithMemory_Step07_FileMemoryProvider/AgentWithMemory_Step07_FileMemoryProvider.csproj
new file mode 100644
index 00000000000..129c9026a2b
--- /dev/null
+++ b/dotnet/samples/02-agents/AgentWithMemory/AgentWithMemory_Step07_FileMemoryProvider/AgentWithMemory_Step07_FileMemoryProvider.csproj
@@ -0,0 +1,19 @@
+
+
+
+ Exe
+ net10.0
+
+ enable
+ enable
+
+
+
+
+
+
+
+
+
+
+
diff --git a/dotnet/samples/02-agents/AgentWithMemory/AgentWithMemory_Step07_FileMemoryProvider/Program.cs b/dotnet/samples/02-agents/AgentWithMemory/AgentWithMemory_Step07_FileMemoryProvider/Program.cs
new file mode 100644
index 00000000000..1a9dbdc1703
--- /dev/null
+++ b/dotnet/samples/02-agents/AgentWithMemory/AgentWithMemory_Step07_FileMemoryProvider/Program.cs
@@ -0,0 +1,98 @@
+// Copyright (c) Microsoft. All rights reserved.
+
+// This sample shows how to give an agent file-based memory using the FileMemoryProvider.
+// The FileMemoryProvider exposes a set of tools to the agent (write, read, delete, list, grep and replace)
+// that allow it to store memories as individual files in an AgentFileStore.
+// Because the files are stored outside of the conversation, the agent can recall them
+// in later conversations, even after the original chat history is gone.
+//
+// The sample also shows how to control the folder that memory files are written to,
+// by supplying a state initializer callback that sets the working folder for each session.
+
+#pragma warning disable MAAI001 // AgentFileStore and its implementations are experimental.
+
+using Azure.AI.Projects;
+using Azure.Identity;
+using Microsoft.Agents.AI;
+
+var endpoint = Environment.GetEnvironmentVariable("FOUNDRY_PROJECT_ENDPOINT") ?? throw new InvalidOperationException("FOUNDRY_PROJECT_ENDPOINT is not set.");
+var deploymentName = Environment.GetEnvironmentVariable("FOUNDRY_MODEL") ?? "gpt-5.4-mini";
+
+// The id of the user that we are storing memories for.
+// It is used below to give each user their own memory folder.
+const string UserId = "UID1";
+
+// Create the file store that the FileMemoryProvider will use to persist memory files.
+// Here we use a file system backed store rooted at a local folder called "agent-memory",
+// but any AgentFileStore implementation can be used, e.g. InMemoryAgentFileStore or a custom
+// implementation backed by blob storage.
+var memoryRoot = Path.Combine(AppContext.BaseDirectory, "agent-memory");
+var fileStore = new FileSystemAgentFileStore(memoryRoot);
+
+// The working folder that memories for this user will be written to, relative to the store root.
+// The folder you choose determines the scope and lifetime of the memories:
+// - A stable folder, like the per-user one below, gives you durable memories that are shared by
+// every session for that user. That is what allows the second conversation further down to
+// recall what the user said in the first.
+// - A unique folder per session gives you memories that are isolated to a single session, e.g.
+// generate one in the state initializer callback below:
+// _ => new FileMemoryState { WorkingFolder = Guid.NewGuid().ToString() }
+var workingFolder = $"users/{UserId}";
+
+Console.WriteLine($"Memory files will be written to: {Path.Combine(memoryRoot, workingFolder)}");
+Console.WriteLine();
+
+// Create the file memory provider.
+// The second parameter is a state initializer callback that is invoked whenever the provider
+// cannot find existing state in a session, i.e. typically the first time it is used with a new session.
+// It allows us to configure the folder that memory files for that session are written to.
+// If no callback is supplied, the working folder defaults to the root of the store,
+// which means all sessions share a single, flat set of memory files.
+using var fileMemoryProvider = new FileMemoryProvider(
+ fileStore,
+ _ => new FileMemoryState { WorkingFolder = workingFolder });
+
+// Create the agent and attach the FileMemoryProvider so that the agent gets the file memory tools.
+AIAgent agent = new AIProjectClient(
+ new Uri(endpoint),
+ // WARNING: DefaultAzureCredential is convenient for development but requires careful consideration in production.
+ // In production, consider using a specific credential (e.g., ManagedIdentityCredential) to avoid
+ // latency issues, unintended credential probing, and potential security risks from fallback mechanisms.
+ new DefaultAzureCredential())
+ .AsAIAgent(new ChatClientAgentOptions
+ {
+ ChatOptions = new()
+ {
+ ModelId = deploymentName,
+ Instructions = "You are a helpful travel assistant. Remember what the user tells you about themselves so that you can give better recommendations later."
+ },
+ Name = "TravelAssistant",
+ AIContextProviders = [fileMemoryProvider],
+ });
+
+// First conversation: tell the agent something worth remembering.
+// The agent should use the file_memory_write tool to store it as a file in the working folder.
+AgentSession firstSession = await agent.CreateSessionAsync();
+Console.WriteLine("=== First conversation ===");
+Console.WriteLine(await agent.RunAsync(
+ "I'm vegetarian and I always travel with my dog. Please remember this for future trips.",
+ firstSession));
+Console.WriteLine();
+
+// Show the memory files that the agent created on disk.
+Console.WriteLine("=== Memory files on disk ===");
+foreach (var file in Directory.EnumerateFiles(Path.Combine(memoryRoot, workingFolder)))
+{
+ Console.WriteLine(Path.GetFileName(file));
+}
+
+Console.WriteLine();
+
+// Second conversation: a brand new session with no chat history from the first conversation.
+// The provider surfaces the memory index to the agent, and the agent can read the memory files
+// using the file_memory_read tool, so it can still recall the user's preferences.
+AgentSession secondSession = await agent.CreateSessionAsync();
+Console.WriteLine("=== Second conversation (new session) ===");
+Console.WriteLine(await agent.RunAsync(
+ "Suggest a hotel and a restaurant for my trip to Paris next week.",
+ secondSession));
diff --git a/dotnet/samples/02-agents/AgentWithMemory/AgentWithMemory_Step07_FileMemoryProvider/README.md b/dotnet/samples/02-agents/AgentWithMemory/AgentWithMemory_Step07_FileMemoryProvider/README.md
new file mode 100644
index 00000000000..23d4d2434ee
--- /dev/null
+++ b/dotnet/samples/02-agents/AgentWithMemory/AgentWithMemory_Step07_FileMemoryProvider/README.md
@@ -0,0 +1,68 @@
+# File Based Memory with FileMemoryProvider
+
+This sample demonstrates how to give an agent file-based memory using the `FileMemoryProvider`.
+
+The `FileMemoryProvider` is an `AIContextProvider` that exposes a set of memory tools to the agent, allowing the agent to decide what to remember and when to recall it. Each memory is stored as an individual file in an `AgentFileStore`, so memories survive beyond the lifetime of a single conversation.
+
+## Concepts
+
+- **`FileMemoryProvider`**: An `AIContextProvider` that adds the following tools to the agent:
+
+ | Tool | Description |
+ |---|---|
+ | `file_memory_write` | Write a memory file with a name, content and optional description. |
+ | `file_memory_read` | Read the content of a memory file by name. |
+ | `file_memory_delete` | Delete a memory file by name. |
+ | `file_memory_ls` | List all memory files with their descriptions. |
+ | `file_memory_grep` | Search memory file contents using a regular expression. |
+ | `file_memory_replace` | Replace occurrences of a substring within a memory file. |
+ | `file_memory_replace_lines` | Replace whole lines within a memory file. |
+
+ The provider also maintains a `memories.md` index file, which it injects into the conversation so the agent knows which memories are available without having to list them first.
+
+- **`AgentFileStore`**: The pluggable storage abstraction used by the provider. This sample uses `FileSystemAgentFileStore` to store memories on the local disk, but `InMemoryAgentFileStore` or a custom implementation (e.g. backed by blob storage) can be used instead.
+
+- **`FileMemoryState`**: The per-session state of the provider. Its `WorkingFolder` property determines the folder, relative to the store root, that memory files are written to.
+
+## Configuring the memory folder
+
+By default, all sessions share the root folder of the store, which means every session reads and writes the same flat set of memory files.
+
+To scope memories, e.g. per user, per tenant or per session, pass a state initializer callback to the `FileMemoryProvider` constructor. The callback receives the `AgentSession` and is invoked whenever the provider cannot find existing state in that session, i.e. typically the first time the provider is used with a new session:
+
+```csharp
+using var fileMemoryProvider = new FileMemoryProvider(
+ fileStore,
+ session => new FileMemoryState { WorkingFolder = $"users/{userId}" });
+```
+
+In this sample, memories are written to `agent-memory/users/UID1` under the application's base directory. Because the folder is derived from a fixed user id rather than the session, a new session for the same user picks up the memories written by earlier sessions.
+
+## Prerequisites
+
+- [.NET 10 SDK](https://dotnet.microsoft.com/download/dotnet/10.0)
+- A Microsoft Foundry project with a chat model deployment
+- Run `az login` to authenticate with `DefaultAzureCredential`
+
+## Configuration
+
+Set the following environment variables:
+
+| Variable | Description | Default |
+|---|---|---|
+| `FOUNDRY_PROJECT_ENDPOINT` | Your Foundry project endpoint | *(required)* |
+| `FOUNDRY_MODEL` | Chat model deployment name | `gpt-5.4-mini` |
+
+## Running the Sample
+
+```bash
+dotnet run
+```
+
+## How it Works
+
+1. A `FileSystemAgentFileStore` is created, rooted at a local `agent-memory` folder.
+2. A `FileMemoryProvider` is created over that store, with a state initializer that puts the memories for the current user in their own working folder.
+3. The provider is attached to the agent via `ChatClientAgentOptions.AIContextProviders`, which gives the agent the `file_memory_*` tools and instructions for using them.
+4. In the first conversation, the user shares some preferences and the agent calls `file_memory_write` to store them as a file in the working folder. The sample then lists the files that were created on disk.
+5. In the second conversation, a brand new session is created with no chat history from the first conversation. The provider injects the memory index into the conversation, and the agent calls `file_memory_read` to recall the stored preferences when making its recommendations.
diff --git a/dotnet/samples/02-agents/AgentWithMemory/README.md b/dotnet/samples/02-agents/AgentWithMemory/README.md
index 752635bbb24..f1dc4064a58 100644
--- a/dotnet/samples/02-agents/AgentWithMemory/README.md
+++ b/dotnet/samples/02-agents/AgentWithMemory/README.md
@@ -10,6 +10,7 @@ These samples show how to create an agent with the Agent Framework that uses Mem
|[Memory with Microsoft Foundry](./AgentWithMemory_Step04_MemoryUsingFoundry/)|This sample demonstrates how to create and run an agent that uses Microsoft Foundry's managed memory service to extract and retrieve individual memories.|
|[Bounded Chat History with Overflow](./AgentWithMemory_Step05_BoundedChatHistory/)|This sample demonstrates how to create a bounded chat history provider that overflows older messages to a vector store and recalls them as memories.|
|[Memory Using AgentMemory](./AgentWithMemory_Step06_MemoryUsingAgentMemory/)|This sample demonstrates a retail shopping assistant built with [`AgentMemory`](https://www.nuget.org/packages/AgentMemory), an unofficial .NET port of the Neo4j Labs graph-memory provider, to learn customer preferences and recommend products via graph traversal.|
+|[File Based Memory](./AgentWithMemory_Step07_FileMemoryProvider/)|This sample demonstrates how to use the `FileMemoryProvider` to give an agent tools for storing and recalling memories as files, and how to configure the folder that those memory files are written to.|
> **See also**: [Memory Search with Foundry Agents](../AgentProviders/foundry/Agent_Step22_MemorySearch/) - demonstrates using the built-in Memory Search tool with Microsoft Foundry agents.
diff --git a/dotnet/src/Microsoft.Agents.AI/Harness/FileAccess/FileAccessProvider.cs b/dotnet/src/Microsoft.Agents.AI/Harness/FileAccess/FileAccessProvider.cs
index afdf4475c67..f42335b7986 100644
--- a/dotnet/src/Microsoft.Agents.AI/Harness/FileAccess/FileAccessProvider.cs
+++ b/dotnet/src/Microsoft.Agents.AI/Harness/FileAccess/FileAccessProvider.cs
@@ -22,7 +22,8 @@ namespace Microsoft.Agents.AI;
///
/// The gives agents the ability to work with files
/// in a folder that the user has granted access to. Unlike ,
-/// which provides session-scoped memory that may be isolated per session,
+/// which provides agent-managed memory files whose scope is determined by the working folder it is
+/// configured with,
/// operates on a shared, persistent folder whose contents are visible across sessions and agents.
/// This makes it suitable for reading input data, writing output artifacts, and working with
/// files that have a lifetime beyond any single agent session.
diff --git a/dotnet/src/Microsoft.Agents.AI/Harness/FileMemory/FileMemoryProvider.cs b/dotnet/src/Microsoft.Agents.AI/Harness/FileMemory/FileMemoryProvider.cs
index b2cf88f9f7c..680fdfcef28 100644
--- a/dotnet/src/Microsoft.Agents.AI/Harness/FileMemory/FileMemoryProvider.cs
+++ b/dotnet/src/Microsoft.Agents.AI/Harness/FileMemory/FileMemoryProvider.cs
@@ -69,8 +69,9 @@ public sealed class FileMemoryProvider : AIContextProvider, IDisposable
private const string DefaultInstructions =
"""
## File Based Memory
- You have access to a session-scoped, file-based memory system via the `file_memory_*` tools for storing and retrieving information across interactions.
- These files act as your working memory for the current session and are isolated from other sessions.
+ You have access to a file-based memory system via the `file_memory_*` tools for storing and retrieving information across interactions.
+ These files act as your working memory and persist beyond the current conversation, so they may already contain memories written earlier,
+ and anything you write now may remain available later.
Use these tools to store plans, memories, processing results, or downloaded data.
- Use descriptive file names (e.g., "projectarchitecture.md", "userpreferences.md").
@@ -507,7 +508,7 @@ private static bool IsInternalFile(string fileName) =>
///
/// Returns if the normalized file name points into a subdirectory.
- /// File memory is a flat, session-scoped space, so nested names are rejected up front.
+ /// File memory is a flat namespace within the working folder, so nested names are rejected up front.
///
private static bool IsNestedPath(string normalizedFileName) =>
normalizedFileName.IndexOf('/') >= 0;