diff --git a/docs/dotnet/user-guide/core-user-guide/defining-message-types.md b/docs/dotnet/user-guide/core-user-guide/defining-message-types.md
new file mode 100644
index 000000000000..9d7a130574b3
--- /dev/null
+++ b/docs/dotnet/user-guide/core-user-guide/defining-message-types.md
@@ -0,0 +1,30 @@
+# Defining Message Types
+
+Messages are currently required to be Protocol Buffers. To define them, it is necessary to include the Protocol Buffers compiler, through the `Grpc.Tools` package. In your `.csproj` file, add/edit:
+
+```xml
+
+```
+
+Then create an include a `.proto` file in the project:
+
+```xml
+
+
+
+```
+
+Then define your messages as specified in the [Protocol Buffers Language Guide](https://protobuf.dev/programming-guides/proto3/)
+
+```proto
+syntax = "proto3";
+
+package HelloAgents;
+
+option csharp_namespace = "AgentsProtocol";
+
+message TextMessage {
+ string Source = 1;
+ string Content = 2;
+}
+```
\ No newline at end of file
diff --git a/docs/dotnet/user-guide/core-user-guide/differences-python.md b/docs/dotnet/user-guide/core-user-guide/differences-python.md
new file mode 100644
index 000000000000..d5e43b9e32e9
--- /dev/null
+++ b/docs/dotnet/user-guide/core-user-guide/differences-python.md
@@ -0,0 +1,46 @@
+# Differences from Python
+
+## Agents Self-Interact
+
+When an agent sends a message of a type to which it also listens:
+
+```csharp
+[TopicSubscription("default")]
+public class MyAgent(
+ IAgentWorker worker,
+ [FromKeyedServices("EventTypes")] EventTypes typeRegistry
+ ) :
+ Agent(worker, typeRegistry),
+ IHandle
+{
+ async Task SomeInternalFunctionAsync()
+ {
+ Message m;
+
+ // ...
+
+ await this.PublishMessageAsync(m);
+ }
+
+ public async Task Handle(Message message)
+ {
+ // will receive messages sent by SomeInternalFunctionAsync()
+ }
+}
+```
+
+Tracked by [#4998](https://github.com/microsoft/autogen/issues/4998)
+
+## 'Local' Runtime is Multithreaded
+
+Unlike the `single_threaded_runtime`, the InProcess (`local: true`) runtime for .NET is multi-threaded, so messages will process in arbitrary order across agents. This means that an agent may process messages sent after the termination request has been made unless checking for termination using the `IHostApplicationLifecycle` service.
+
+## No equivalent to 'stop_when_idle()'
+
+Agents need to request termination explicitly, as there is no meaningful 'idle' state.
+
+## All message types need to be Protocol Buffers
+
+See (linkto: defining-message-types.md) for instructions on defining messages
+
+Tracked by [#4695](https://github.com/microsoft/autogen/issues/4695)
\ No newline at end of file
diff --git a/docs/dotnet/user-guide/core-user-guide/getting-started.md b/docs/dotnet/user-guide/core-user-guide/getting-started.md
new file mode 100644
index 000000000000..9e91b14d1cb3
--- /dev/null
+++ b/docs/dotnet/user-guide/core-user-guide/getting-started.md
@@ -0,0 +1,143 @@
+# Quick Start
+
+Before diving into the core APIs, let’s start with a simple example of two agents that count down from 10 to 1.
+
+We first define the agent classes and their respective procedures for handling messages. We create two agent classes: `Modifier` and `Checker`. The `Modifier` agent modifies a number that is given and the `Check` agent checks the value against a condition. We also define a pair of
+messages in a .proto file which will be generated into the message types that will be passed
+between the agents.
+
+```proto
+syntax = "proto3";
+
+package HelloAgents;
+
+option csharp_namespace = "Microsoft.Autogen.Samples.CountAgent.Protocol";
+
+message CountMessage {
+ int32 Content = 1;
+}
+
+message CountUpdate {
+ int32 NewCount = 1;
+}
+```
+
+We create two messages to ensure we have tick-tock behaviour between the agents; if we used a single type, then both agents would receive the other agents' message as well as self-sent messages. (Note: this is a behaviour difference from Python; Issue#4998)
+
+In the project file, we add
+
+```xml
+
+
+
+
+
+
+
+```
+
+This will ensure the message classes are available for our agents to send/receive.
+
+Now we will define the agents:
+
+```csharp
+[TopicSubscription("default")]
+public class Modifier(
+ IAgentWorker worker,
+ [FromKeyedServices("EventTypes")] EventTypes typeRegistry,
+ ModifyF modifyFunc
+ ) :
+ Agent(worker, typeRegistry),
+ IHandle
+{
+ public async Task Handle(CountMessage item)
+ {
+ // handling code
+ }
+}
+```
+
+The `TopicSubscription` attribute defines the set of topics the agents will listen to. Topics (see here) are useful for separaating different logical chains of agent communications.
+
+The first two parameters to the constructor, `IAgentWorker` and `EventTypes` are automatically made available through dependency injection to the workers. (We do not allow direct construction of workers in Autogen.Core: see here for FAQ), and need to be passed on to the base class.
+
+Other parameters are also made available through dependency injection (see here).
+
+Agents register for messages by implementing the `IHandle` interface:
+
+```csharp
+ public async Task Handle(CountMessage item)
+ {
+ int newValue = modifyFunc(item.Content);
+ Console.WriteLine($"{SEPARATOR_LINE}\nModifier:\nModified {item.Content} to {newValue}");
+
+ CountUpdate updateMessage = new CountUpdate { NewCount = newValue };
+
+ await this.PublishMessageAsync(updateMessage);
+ }
+```
+
+The `Modifier` agent receives a `CountMessage` indicating the current count, modifies it using the injected `ModifyF modifyFunc`, and publishes the `CountUpdate` message.
+
+The `Checker` agent is defines similarly:
+
+```csharp
+[TopicSubscription("default")]
+public class Checker(
+ IAgentWorker worker,
+ [FromKeyedServices("EventTypes")] EventTypes typeRegistry,
+ IHostApplicationLifetime hostApplicationLifetime,
+ TerminationF runUntilFunc
+ ) :
+ Agent(worker, typeRegistry),
+ IHandle
+{
+ public Task Handle(CountUpdate item)
+ {
+ if (!runUntilFunc(item.NewCount))
+ {
+ Console.WriteLine($"{SEPARATOR_LINE}\nChecker:\n{item.NewCount} passed the check, continue.");
+ await this.PublishMessageAsync(new CountMessage { Content = item.NewCount });
+ }
+ else
+ {
+ Console.WriteLine($"{SEPARATOR_LINE}\nChecker:\n{item.NewCount} failed the check, stopping.");
+ hostApplicationLifetime.StopApplication();
+ }
+ }
+}
+```
+
+The `Checker` continues the count when `runUntilFunc` has not triggered by publishing a new `CountMessage` with the updated count; if termination is desired, it will request it by calling `hostApplicationLifetime.StopApplication()`.
+
+You might have already noticed, the agents’ logic, whether it is using model or code executor, is completely decoupled from how messages are delivered. This is the core idea: the framework provides a communication infrastructure, and the agents are responsible for their own logic. We call the communication infrastructure an Agent Runtime.
+
+Agent runtime is a key concept of this framework. Besides delivering messages, it also manages agents’ lifecycle. So the creation of agents are handled by the runtime.
+
+The following code shows how to register and run the agents using the local (InProcess) runtime:
+
+```csharp
+// Define the counting logic
+using ModifyF = System.Func;
+using TerminationF = System.Func;
+
+ModifyF modifyFunc = (int x) => x - 1;
+TerminationF runUntilFunc = (int x) =>
+{
+ return x <= 1;
+};
+
+// Register the services
+WebApplicationBuilder? builder = WebApplication.CreateBuilder(args);
+builder.Services.AddSingleton(modifyFunc);
+builder.Services.AddSingleton(runUntilFunc);
+
+// Send the initial count to the agents app, running on the `local` runtime, and pass through the registered services via the application `builder`
+var app = await AgentsApp.PublishMessageAsync("default", new CountMessage
+{
+ Content = 10
+}, local: true, builder: builder).ConfigureAwait(false);
+
+// Run until application shutdown
+await app.WaitForShutdownAsync();
+```
\ No newline at end of file
diff --git a/docs/dotnet/user-guide/core-user-guide/installation.md b/docs/dotnet/user-guide/core-user-guide/installation.md
new file mode 100644
index 000000000000..270bcd659db6
--- /dev/null
+++ b/docs/dotnet/user-guide/core-user-guide/installation.md
@@ -0,0 +1,33 @@
+# Installation
+
+## Add via ``
+
+```
+
+
+```
+
+
+
+## These will only work after we release the package:
+
+## Install via `.NET cli`
+
+```
+> dotnet add package Microsoft.AutoGen.Contracts --version 0.4.0
+> dotnet add package Microsoft.AutoGen.Core --version 0.4.0
+```
+
+## Install via `Package Manager`
+
+```
+PM> NuGet\Install-Package Microsoft.AutoGen.Contracts -Version 0.4.0
+PM> NuGet\Install-Package Microsoft.AutoGen.Core -Version 0.4.0
+```
+
+## Add via ``
+
+```
+
+
+```