Rename project to Cortex #1

Merged
Maashkinoozhe merged 1 commits from codex/rename-cortex into main 2026-07-11 13:40:52 +02:00
91 changed files with 432 additions and 409 deletions
+12 -12
View File
@@ -1,13 +1,13 @@
POSTGRES_DB=cerebro
POSTGRES_USER=cerebro
POSTGRES_PASSWORD=cerebro_dev_password
CEREBRO_APP_PORT=5117
CEREBRO_WEB_PORT=5118
CEREBRO_DB_PORT=54329
CEREBRO_EMBEDDINGS_PORT=8088
POSTGRES_DB=cortex
POSTGRES_USER=cortex
POSTGRES_PASSWORD=cortex_dev_password
CORTEX_APP_PORT=5117
CORTEX_WEB_PORT=5118
CORTEX_DB_PORT=54329
CORTEX_EMBEDDINGS_PORT=8088
EMBEDDING_MODEL=BAAI/bge-small-en-v1.5
CEREBRO_TEST_BASE_URL=http://localhost:5217
CEREBRO_TEST_APP_PORT=5217
CEREBRO_TEST_WEB_PORT=5218
CEREBRO_TEST_DB_PORT=54339
CEREBRO_TEST_EMBEDDINGS_PORT=8188
CORTEX_TEST_BASE_URL=http://localhost:5217
CORTEX_TEST_APP_PORT=5217
CORTEX_TEST_WEB_PORT=5218
CORTEX_TEST_DB_PORT=54339
CORTEX_TEST_EMBEDDINGS_PORT=8188
-8
View File
@@ -1,8 +0,0 @@
<Solution>
<Folder Name="/Solution Items/">
<File Path="Directory.Packages.props" />
</Folder>
<Project Path="src/Cerebro.Api/Cerebro.Api.csproj" />
<Project Path="src/Cerebro.Web/Cerebro.Web.csproj" />
<Project Path="tests/Cerebro.IntegrationTests/Cerebro.IntegrationTests.csproj" />
</Solution>
+9
View File
@@ -0,0 +1,9 @@
<Solution>
<Folder Name="/Solution Items/">
<File Path="Directory.Packages.props" />
</Folder>
<Project Path="src/Cortex.Api/Cortex.Api.csproj" />
<Project Path="src/Cortex.Core/Cortex.Core.csproj" />
<Project Path="src/Cortex.Web/Cortex.Web.csproj" />
<Project Path="tests/Cortex.IntegrationTests/Cortex.IntegrationTests.csproj" />
</Solution>
+7 -5
View File
@@ -4,14 +4,16 @@ WORKDIR /src
COPY NuGet.Config ./
COPY Directory.Build.props ./
COPY Directory.Packages.props ./
COPY src/Cerebro.Api/Cerebro.Api.csproj src/Cerebro.Api/
RUN dotnet restore src/Cerebro.Api/Cerebro.Api.csproj --configfile NuGet.Config
COPY src/Cortex.Core/Cortex.Core.csproj src/Cortex.Core/
COPY src/Cortex.Api/Cortex.Api.csproj src/Cortex.Api/
RUN dotnet restore src/Cortex.Api/Cortex.Api.csproj --configfile NuGet.Config
COPY src/Cerebro.Api src/Cerebro.Api
RUN dotnet publish src/Cerebro.Api/Cerebro.Api.csproj -c Release -o /app/publish --no-restore
COPY src/Cortex.Core src/Cortex.Core
COPY src/Cortex.Api src/Cortex.Api
RUN dotnet publish src/Cortex.Api/Cortex.Api.csproj -c Release -o /app/publish --no-restore
FROM mcr.microsoft.com/dotnet/aspnet:10.0 AS runtime
WORKDIR /app
COPY --from=build /app/publish .
EXPOSE 8080
ENTRYPOINT ["dotnet", "Cerebro.Api.dll"]
ENTRYPOINT ["dotnet", "Cortex.Api.dll"]
+7 -7
View File
@@ -4,16 +4,16 @@ WORKDIR /src
COPY NuGet.Config ./
COPY Directory.Build.props ./
COPY Directory.Packages.props ./
COPY src/Cerebro.Api/Cerebro.Api.csproj src/Cerebro.Api/
COPY src/Cerebro.Web/Cerebro.Web.csproj src/Cerebro.Web/
RUN dotnet restore src/Cerebro.Web/Cerebro.Web.csproj --configfile NuGet.Config
COPY src/Cortex.Core/Cortex.Core.csproj src/Cortex.Core/
COPY src/Cortex.Web/Cortex.Web.csproj src/Cortex.Web/
RUN dotnet restore src/Cortex.Web/Cortex.Web.csproj --configfile NuGet.Config
COPY src/Cerebro.Api src/Cerebro.Api
COPY src/Cerebro.Web src/Cerebro.Web
RUN dotnet publish src/Cerebro.Web/Cerebro.Web.csproj -c Release -o /app/publish --no-restore
COPY src/Cortex.Core src/Cortex.Core
COPY src/Cortex.Web src/Cortex.Web
RUN dotnet publish src/Cortex.Web/Cortex.Web.csproj -c Release -o /app/publish
FROM mcr.microsoft.com/dotnet/aspnet:10.0 AS runtime
WORKDIR /app
COPY --from=build /app/publish .
EXPOSE 8080
ENTRYPOINT ["dotnet", "Cerebro.Web.dll"]
ENTRYPOINT ["dotnet", "Cortex.Web.dll"]
+4 -4
View File
@@ -1,10 +1,10 @@
# Cerebro
# Cortex
Cerebro is a local-first memory server exposed through the Model Context Protocol (MCP). It lets an MCP client store and recall project-scoped requirements, locations, todos, and notes.
Cortex is a local-first memory server exposed through the Model Context Protocol (MCP). It lets an MCP client store and recall project-scoped requirements, locations, todos, and notes.
The project is intentionally small and operationally explicit: everything local is run through PowerShell scripts, the app runs in Docker, data lives in PostgreSQL with pgvector, and embeddings are produced by a local container.
## What Cerebro Does
## What Cortex Does
- Stores memories inside explicit projects.
- Supports four categories: `requirement`, `location`, `todo`, and `note`.
@@ -32,7 +32,7 @@ The project is intentionally small and operationally explicit: everything local
| Service | Dev instance | Test instance |
| --- | ---: | ---: |
| Cerebro app | <http://localhost:5117> | <http://localhost:5217> |
| Cortex app | <http://localhost:5117> | <http://localhost:5217> |
| Web UI | <http://localhost:5118> | <http://localhost:5218> |
| MCP endpoint | <http://localhost:5117/mcp> | <http://localhost:5217/mcp> |
| PostgreSQL | `localhost:54329` | `localhost:54339` |
+31 -31
View File
@@ -1,77 +1,77 @@
name: cerebro-test
name: cortex-test
services:
cerebro-test-db:
cortex-test-db:
image: pgvector/pgvector:pg17
container_name: cerebro-test-db
container_name: cortex-test-db
environment:
POSTGRES_DB: cerebro
POSTGRES_USER: cerebro
POSTGRES_PASSWORD: cerebro_dev_password
POSTGRES_DB: cortex
POSTGRES_USER: cortex
POSTGRES_PASSWORD: cortex_dev_password
ports:
- "54339:5432"
volumes:
- cerebro-test-postgres-data:/var/lib/postgresql/data
- cortex-test-postgres-data:/var/lib/postgresql/data
healthcheck:
test: ["CMD-SHELL", "pg_isready -U cerebro -d cerebro"]
test: ["CMD-SHELL", "pg_isready -U cortex -d cortex"]
interval: 5s
timeout: 5s
retries: 20
cerebro-test-embeddings:
cortex-test-embeddings:
image: ghcr.io/huggingface/text-embeddings-inference:cpu-latest
container_name: cerebro-test-embeddings
container_name: cortex-test-embeddings
command: ["--model-id", "BAAI/bge-small-en-v1.5", "--port", "80"]
ports:
- "8188:80"
volumes:
- cerebro-test-embeddings-data:/data
- cortex-test-embeddings-data:/data
cerebro-test-app:
cortex-test-app:
build:
context: .
dockerfile: Dockerfile
image: cerebro-app:test
container_name: cerebro-test-app
image: cortex-app:test
container_name: cortex-test-app
depends_on:
cerebro-test-db:
cortex-test-db:
condition: service_healthy
cerebro-test-embeddings:
cortex-test-embeddings:
condition: service_started
environment:
ASPNETCORE_URLS: http://+:8080
ASPNETCORE_ENVIRONMENT: Development
ConnectionStrings__Cerebro: Host=cerebro-test-db;Port=5432;Database=cerebro;Username=cerebro;Password=cerebro_dev_password;GSS Encryption Mode=Disable
Embedding__BaseUrl: http://cerebro-test-embeddings
ConnectionStrings__Cortex: Host=cortex-test-db;Port=5432;Database=cortex;Username=cortex;Password=cortex_dev_password;GSS Encryption Mode=Disable
Embedding__BaseUrl: http://cortex-test-embeddings
Embedding__Model: BAAI/bge-small-en-v1.5
Cerebro__EmbeddingModel: BAAI/bge-small-en-v1.5
Cerebro__EmbeddingDimensions: 384
Cortex__EmbeddingModel: BAAI/bge-small-en-v1.5
Cortex__EmbeddingDimensions: 384
ports:
- "5217:8080"
cerebro-test-web:
cortex-test-web:
profiles: ["ui"]
build:
context: .
dockerfile: Dockerfile.web
image: cerebro-web:test
container_name: cerebro-test-web
image: cortex-web:test
container_name: cortex-test-web
depends_on:
cerebro-test-db:
cortex-test-db:
condition: service_healthy
cerebro-test-embeddings:
cortex-test-embeddings:
condition: service_started
environment:
ASPNETCORE_URLS: http://+:8080
ASPNETCORE_ENVIRONMENT: Development
ConnectionStrings__Cerebro: Host=cerebro-test-db;Port=5432;Database=cerebro;Username=cerebro;Password=cerebro_dev_password;GSS Encryption Mode=Disable
Embedding__BaseUrl: http://cerebro-test-embeddings
ConnectionStrings__Cortex: Host=cortex-test-db;Port=5432;Database=cortex;Username=cortex;Password=cortex_dev_password;GSS Encryption Mode=Disable
Embedding__BaseUrl: http://cortex-test-embeddings
Embedding__Model: BAAI/bge-small-en-v1.5
Cerebro__EmbeddingModel: BAAI/bge-small-en-v1.5
Cerebro__EmbeddingDimensions: 384
Cortex__EmbeddingModel: BAAI/bge-small-en-v1.5
Cortex__EmbeddingDimensions: 384
ports:
- "5218:8080"
volumes:
cerebro-test-postgres-data:
cerebro-test-embeddings-data:
cortex-test-postgres-data:
cortex-test-embeddings-data:
+31 -31
View File
@@ -1,77 +1,77 @@
name: cerebro
name: cortex
services:
cerebro-db:
cortex-db:
image: pgvector/pgvector:pg17
container_name: cerebro-db
container_name: cortex-db
environment:
POSTGRES_DB: cerebro
POSTGRES_USER: cerebro
POSTGRES_PASSWORD: cerebro_dev_password
POSTGRES_DB: cortex
POSTGRES_USER: cortex
POSTGRES_PASSWORD: cortex_dev_password
ports:
- "54329:5432"
volumes:
- cerebro-postgres-data:/var/lib/postgresql/data
- cortex-postgres-data:/var/lib/postgresql/data
healthcheck:
test: ["CMD-SHELL", "pg_isready -U cerebro -d cerebro"]
test: ["CMD-SHELL", "pg_isready -U cortex -d cortex"]
interval: 5s
timeout: 5s
retries: 20
cerebro-embeddings:
cortex-embeddings:
image: ghcr.io/huggingface/text-embeddings-inference:cpu-latest
container_name: cerebro-embeddings
container_name: cortex-embeddings
command: ["--model-id", "BAAI/bge-small-en-v1.5", "--port", "80"]
ports:
- "8088:80"
volumes:
- cerebro-embeddings-data:/data
- cortex-embeddings-data:/data
cerebro-app:
cortex-app:
build:
context: .
dockerfile: Dockerfile
image: cerebro-app:local
container_name: cerebro-app
image: cortex-app:local
container_name: cortex-app
depends_on:
cerebro-db:
cortex-db:
condition: service_healthy
cerebro-embeddings:
cortex-embeddings:
condition: service_started
environment:
ASPNETCORE_URLS: http://+:8080
ASPNETCORE_ENVIRONMENT: Development
ConnectionStrings__Cerebro: Host=cerebro-db;Port=5432;Database=cerebro;Username=cerebro;Password=cerebro_dev_password;GSS Encryption Mode=Disable
Embedding__BaseUrl: http://cerebro-embeddings
ConnectionStrings__Cortex: Host=cortex-db;Port=5432;Database=cortex;Username=cortex;Password=cortex_dev_password;GSS Encryption Mode=Disable
Embedding__BaseUrl: http://cortex-embeddings
Embedding__Model: BAAI/bge-small-en-v1.5
Cerebro__EmbeddingModel: BAAI/bge-small-en-v1.5
Cerebro__EmbeddingDimensions: 384
Cortex__EmbeddingModel: BAAI/bge-small-en-v1.5
Cortex__EmbeddingDimensions: 384
ports:
- "5117:8080"
cerebro-web:
cortex-web:
profiles: ["ui"]
build:
context: .
dockerfile: Dockerfile.web
image: cerebro-web:local
container_name: cerebro-web
image: cortex-web:local
container_name: cortex-web
depends_on:
cerebro-db:
cortex-db:
condition: service_healthy
cerebro-embeddings:
cortex-embeddings:
condition: service_started
environment:
ASPNETCORE_URLS: http://+:8080
ASPNETCORE_ENVIRONMENT: Development
ConnectionStrings__Cerebro: Host=cerebro-db;Port=5432;Database=cerebro;Username=cerebro;Password=cerebro_dev_password;GSS Encryption Mode=Disable
Embedding__BaseUrl: http://cerebro-embeddings
ConnectionStrings__Cortex: Host=cortex-db;Port=5432;Database=cortex;Username=cortex;Password=cortex_dev_password;GSS Encryption Mode=Disable
Embedding__BaseUrl: http://cortex-embeddings
Embedding__Model: BAAI/bge-small-en-v1.5
Cerebro__EmbeddingModel: BAAI/bge-small-en-v1.5
Cerebro__EmbeddingDimensions: 384
Cortex__EmbeddingModel: BAAI/bge-small-en-v1.5
Cortex__EmbeddingDimensions: 384
ports:
- "5118:8080"
volumes:
cerebro-postgres-data:
cerebro-embeddings-data:
cortex-postgres-data:
cortex-embeddings-data:
+4 -4
View File
@@ -1,11 +1,11 @@
# Architecture
Cerebro is a small domain-specific MCP server.
Cortex is a small domain-specific MCP server.
```mermaid
flowchart LR
Client["MCP client"] -->|Streamable HTTP| App["Cerebro .NET 10 app"]
Browser["Browser"] --> Web["Cerebro Blazor web UI"]
Client["MCP client"] -->|Streamable HTTP| App["Cortex .NET 10 app"]
Browser["Browser"] --> Web["Cortex Blazor web UI"]
Web --> Db
Web --> Embed
App --> Db["PostgreSQL + pgvector"]
@@ -31,7 +31,7 @@ Health is exposed at:
The web UI is a separate Blazor Server project and Docker container. It is optional and not needed for MCP clients.
The UI talks to the same PostgreSQL database and embedding service through the existing Cerebro service layer. It is intended for manual browsing, adding memories, searching, editing, and soft-deleting during local development.
The UI talks to the same PostgreSQL database and embedding service through the existing Cortex service layer. It is intended for manual browsing, adding memories, searching, editing, and soft-deleting during local development.
Dev URL:
+12 -12
View File
@@ -4,7 +4,7 @@
```text
src/
Cerebro.Api/
Cortex.Api/
Contracts/
Data/
Domain/
@@ -12,11 +12,11 @@ src/
Options/
Services/
Tools/
Cerebro.Web/
Cortex.Web/
Components/
wwwroot/
tests/
Cerebro.IntegrationTests/
Cortex.IntegrationTests/
scripts/
docs/
```
@@ -25,19 +25,19 @@ docs/
| File | Purpose |
| --- | --- |
| `src/Cerebro.Api/Program.cs` | App startup, DI, MCP route, migration/seed modes. |
| `src/Cerebro.Api/Tools/CerebroTools.cs` | MCP tool surface. |
| `src/Cerebro.Api/Services/CerebroMemoryService.cs` | Project/item/search behavior. |
| `src/Cerebro.Api/Data/CerebroDbContext.cs` | EF Core model. |
| `src/Cerebro.Web/Components/Pages/Home.razor` | Optional Blazor web UI dashboard. |
| `src/Cerebro.Api/Migrations` | Database schema migrations. |
| `src/Cortex.Api/Program.cs` | App startup, DI, MCP route, migration/seed modes. |
| `src/Cortex.Api/Tools/CortexTools.cs` | MCP tool surface. |
| `src/Cortex.Api/Services/CortexMemoryService.cs` | Project/item/search behavior. |
| `src/Cortex.Api/Data/CortexDbContext.cs` | EF Core model. |
| `src/Cortex.Web/Components/Pages/Home.razor` | Optional Blazor web UI dashboard. |
| `src/Cortex.Api/Migrations` | Database schema migrations. |
| `docker-compose.yml` | Dev stack. |
| `docker-compose.test.yml` | Test stack. |
## Adding a Tool
1. Add a method to `CerebroTools`.
2. Add or update a service method in `CerebroMemoryService`.
1. Add a method to `CortexTools`.
2. Add or update a service method in `CortexMemoryService`.
3. Use `[McpServerTool]` with a stable `Name`.
4. Set `UseStructuredContent = true` when the tool returns structured data.
5. Add an integration test.
@@ -58,7 +58,7 @@ docs/
The current model produces 384-dimensional vectors. If the new model has a different dimension, update:
- `Cerebro:EmbeddingDimensions`
- `Cortex:EmbeddingDimensions`
- migration/schema for `vector(N)`
- indexes
- docs
+1 -1
View File
@@ -1,6 +1,6 @@
{
"servers": {
"cerebro": {
"cortex": {
"type": "http",
"url": "http://localhost:5117/mcp"
}
+1 -1
View File
@@ -1,6 +1,6 @@
{
"servers": {
"cerebro": {
"cortex": {
"type": "http",
"url": "http://localhost:5117/mcp"
}
+1 -1
View File
@@ -1,6 +1,6 @@
{
"servers": {
"cerebro-test": {
"cortex-test": {
"type": "http",
"url": "http://localhost:5217/mcp"
}
+7 -7
View File
@@ -1,6 +1,6 @@
# MCP Tools
Cerebro exposes MCP tools over:
Cortex exposes MCP tools over:
```text
http://localhost:5117/mcp
@@ -27,8 +27,8 @@ Result:
```json
{
"id": "00000000-0000-0000-0000-000000000000",
"name": "Cerebro",
"slug": "cerebro",
"name": "Cortex",
"slug": "cortex",
"createdAt": "2026-07-08T12:00:00Z"
}
```
@@ -45,8 +45,8 @@ Result:
[
{
"id": "00000000-0000-0000-0000-000000000000",
"name": "Cerebro",
"slug": "cerebro",
"name": "Cortex",
"slug": "cortex",
"createdAt": "2026-07-08T12:00:00Z"
}
]
@@ -72,7 +72,7 @@ Example:
```json
{
"project": "cerebro",
"project": "cortex",
"category": "location",
"title": "USB-C charging brick",
"content": "The USB-C charging brick is in the blue backpack.",
@@ -108,7 +108,7 @@ Example:
## UpdateItem
Updates an existing item. If title, content, category, or tags change, Cerebro regenerates the embedding.
Updates an existing item. If title, content, category, or tags change, Cortex regenerates the embedding.
Arguments:
+11 -11
View File
@@ -1,28 +1,28 @@
# Operations Guide
Cerebro local operations are PowerShell-only.
Cortex local operations are PowerShell-only.
## Dev Stack
The dev stack is named `cerebro`.
The dev stack is named `cortex`.
| Container | Purpose |
| --- | --- |
| `cerebro-db` | PostgreSQL with pgvector. |
| `cerebro-embeddings` | Local embedding service. |
| `cerebro-app` | .NET 10 MCP server. |
| `cerebro-web` | Optional Blazor web UI. |
| `cortex-db` | PostgreSQL with pgvector. |
| `cortex-embeddings` | Local embedding service. |
| `cortex-app` | .NET 10 MCP server. |
| `cortex-web` | Optional Blazor web UI. |
## Test Stack
The test stack is named `cerebro-test`.
The test stack is named `cortex-test`.
| Container | Purpose |
| --- | --- |
| `cerebro-test-db` | Isolated PostgreSQL with pgvector. |
| `cerebro-test-embeddings` | Isolated embedding service. |
| `cerebro-test-app` | Isolated MCP server under test. |
| `cerebro-test-web` | Optional isolated Blazor web UI. |
| `cortex-test-db` | Isolated PostgreSQL with pgvector. |
| `cortex-test-embeddings` | Isolated embedding service. |
| `cortex-test-app` | Isolated MCP server under test. |
| `cortex-test-web` | Optional isolated Blazor web UI. |
The test stack uses different ports and a different database volume so it can run beside the dev stack.
+4 -4
View File
@@ -1,6 +1,6 @@
# Setup Guide
This guide gets a local Cerebro dev instance running on Windows.
This guide gets a local Cortex dev instance running on Windows.
## Prerequisites
@@ -25,7 +25,7 @@ This starts:
- PostgreSQL with pgvector
- Hugging Face Text Embeddings Inference
- Cerebro MCP server
- Cortex MCP server
It also applies EF Core migrations before starting the app.
@@ -41,7 +41,7 @@ Expected result:
```json
{
"name": "Cerebro",
"name": "Cortex",
"status": "ok"
}
```
@@ -54,7 +54,7 @@ The timestamp will vary.
.\scripts\seed-db.ps1
```
The seed creates a `Cerebro` project and a couple of starter memories.
The seed creates a `Cortex` project and a couple of starter memories.
## MCP Endpoint
+5 -5
View File
@@ -1,6 +1,6 @@
# Testing Guide
Cerebro has two test modes:
Cortex has two test modes:
- normal tests through `scripts\test.ps1`
- local end-to-end integration tests through `scripts\test-integration.ps1`
@@ -13,7 +13,7 @@ The test stack is isolated from the dev stack.
| Service | Test value |
| --- | --- |
| Compose project | `cerebro-test` |
| Compose project | `cortex-test` |
| App | <http://localhost:5217> |
| MCP endpoint | <http://localhost:5217/mcp> |
| PostgreSQL | `localhost:54339` |
@@ -58,7 +58,7 @@ Or deploy without running tests:
## Run Tests from Visual Studio
1. Open `Cerebro.slnx` in Visual Studio.
1. Open `Cortex.slnx` in Visual Studio.
2. Start the test stack:
```powershell
@@ -66,12 +66,12 @@ Or deploy without running tests:
```
3. Open Test Explorer.
4. Run any test in `Cerebro.IntegrationTests`.
4. Run any test in `Cortex.IntegrationTests`.
The tests use:
```text
CEREBRO_TEST_BASE_URL
CORTEX_TEST_BASE_URL
```
If that environment variable is not set, they default to:
+2 -2
View File
@@ -54,7 +54,7 @@ Check logs:
This is expected when the project does not exist. Create the project first with `CreateProject`.
Cerebro intentionally has no default project.
Cortex intentionally has no default project.
## Search Returns Nothing
@@ -105,7 +105,7 @@ If restore fails:
3. Run restore from a normal PowerShell session:
```powershell
dotnet restore Cerebro.slnx --configfile NuGet.Config
dotnet restore Cortex.slnx --configfile NuGet.Config
```
## Embedding Container Takes a Long Time
+14 -14
View File
@@ -2,8 +2,8 @@
This guide covers two related workflows:
1. Running Cerebro integration tests from Visual Studio Test Explorer.
2. Connecting an MCP-capable Copilot client to the Cerebro MCP server.
1. Running Cortex integration tests from Visual Studio Test Explorer.
2. Connecting an MCP-capable Copilot client to the Cortex MCP server.
## Visual Studio Test Explorer
@@ -11,7 +11,7 @@ Visual Studio can run the integration tests because they are ordinary xUnit test
### Steps
1. Open `Cerebro.slnx`.
1. Open `Cortex.slnx`.
2. Start the isolated test stack:
```powershell
@@ -19,7 +19,7 @@ Visual Studio can run the integration tests because they are ordinary xUnit test
```
3. In Visual Studio, open Test Explorer.
4. Run tests under `Cerebro.IntegrationTests`.
4. Run tests under `Cortex.IntegrationTests`.
The tests connect to:
@@ -30,12 +30,12 @@ http://localhost:5217
Override that by setting:
```powershell
$env:CEREBRO_TEST_BASE_URL = "http://localhost:5217"
$env:CORTEX_TEST_BASE_URL = "http://localhost:5217"
```
## Connecting a Copilot MCP Client
Cerebro uses Streamable HTTP MCP.
Cortex uses Streamable HTTP MCP.
The Blazor web UI is not needed for this. It is only a browser-based helper for local testing and memory inspection.
@@ -60,7 +60,7 @@ If your Visual Studio installation exposes MCP server configuration through GitH
```json
{
"servers": {
"cerebro": {
"cortex": {
"type": "http",
"url": "http://localhost:5117/mcp"
}
@@ -74,7 +74,7 @@ If Visual Studio asks for a URL directly, enter:
http://localhost:5117/mcp
```
If your Visual Studio build does not expose MCP server configuration, use Visual Studio for normal coding and Test Explorer, and use Visual Studio Code or another MCP-capable client for Cerebro tool calls.
If your Visual Studio build does not expose MCP server configuration, use Visual Studio for normal coding and Test Explorer, and use Visual Studio Code or another MCP-capable client for Cortex tool calls.
## Visual Studio Code MCP Setup
@@ -91,7 +91,7 @@ Add:
```json
{
"servers": {
"cerebro": {
"cortex": {
"type": "http",
"url": "http://localhost:5117/mcp"
}
@@ -103,7 +103,7 @@ The same example is available at `docs/examples/vscode-mcp.dev.json`.
Then:
1. Start Cerebro:
1. Start Cortex:
```powershell
.\scripts\deploy-all.ps1
@@ -111,7 +111,7 @@ Then:
2. Open the VS Code command palette.
3. Run `MCP: List Servers`.
4. Start or enable `cerebro`.
4. Start or enable `cortex`.
5. Open Chat and select/configure tools.
For the test instance:
@@ -119,7 +119,7 @@ For the test instance:
```json
{
"servers": {
"cerebro-test": {
"cortex-test": {
"type": "http",
"url": "http://localhost:5217/mcp"
}
@@ -134,7 +134,7 @@ The same example is available at `docs/examples/vscode-mcp.test.json`.
After connecting an MCP client:
```text
Create a Cerebro project named Home.
Create a Cortex project named Home.
```
```text
@@ -151,7 +151,7 @@ Add a todo in the Home project: buy a replacement USB-C cable.
## Trust and Safety
Cerebro is local and currently unauthenticated. Treat the endpoint as trusted-local only:
Cortex is local and currently unauthenticated. Treat the endpoint as trusted-local only:
- Keep it bound to localhost for development.
- Do not expose it to the public internet.
+8 -8
View File
@@ -1,6 +1,6 @@
# Web UI
Cerebro includes an optional Blazor Server web UI for local browsing and testing.
Cortex includes an optional Blazor Server web UI for local browsing and testing.
It is not required for:
@@ -67,22 +67,22 @@ Stop:
The web UI runs as its own Docker container:
```text
cerebro-web
cortex-web
```
It uses the same database and embedding service as the MCP server:
```text
cerebro-db
cerebro-embeddings
cortex-db
cortex-embeddings
```
The test web UI uses:
```text
cerebro-test-web
cerebro-test-db
cerebro-test-embeddings
cortex-test-web
cortex-test-db
cortex-test-embeddings
```
The web UI does not expose MCP. It is a browser interface over the same local memory system.
@@ -100,5 +100,5 @@ The script handles the profile for you:
Manual equivalent:
```powershell
docker compose --project-name cerebro --profile ui up -d --build cerebro-web
docker compose --project-name cortex --profile ui up -d --build cortex-web
```
+6 -6
View File
@@ -1,15 +1,15 @@
. "$PSScriptRoot\lib\common.ps1"
Write-Step "Restoring .NET packages"
Invoke-DotNet restore Cerebro.slnx --configfile NuGet.Config
Invoke-DotNet restore Cortex.slnx --configfile NuGet.Config
Write-Step "Building Cerebro"
Invoke-DotNet build Cerebro.slnx --configuration Release --no-restore
Write-Step "Building Cortex"
Invoke-DotNet build Cortex.slnx --configuration Release --no-restore
Write-Step "Building local Docker image"
Assert-Docker
Invoke-CerebroCompose build cerebro-app
Invoke-CortexCompose build cortex-app
Write-Step "Building optional web UI Docker image"
$webBuildArgs = @("--profile", "ui", "build", "cerebro-web")
Invoke-CerebroCompose @webBuildArgs
$webBuildArgs = @("--profile", "ui", "build", "cortex-web")
Invoke-CortexCompose @webBuildArgs
+7 -7
View File
@@ -1,17 +1,17 @@
. "$PSScriptRoot\lib\common.ps1"
Write-Step "Starting all Cerebro services"
Write-Step "Starting all Cortex services"
Assert-Docker
Invoke-CerebroCompose up -d cerebro-db cerebro-embeddings
Invoke-CortexCompose up -d cortex-db cortex-embeddings
Write-Step "Waiting for embedding model health"
Wait-HttpOk "http://localhost:8088/health" 300
Write-Step "Building Cerebro MCP server image"
Invoke-CerebroCompose build cerebro-app
Write-Step "Building Cortex MCP server image"
Invoke-CortexCompose build cortex-app
Write-Step "Applying database migrations"
Invoke-CerebroCompose run --rm cerebro-app migrate
Invoke-CortexCompose run --rm cortex-app migrate
Write-Step "Starting Cerebro MCP server"
Invoke-CerebroCompose up -d cerebro-app
Write-Step "Starting Cortex MCP server"
Invoke-CortexCompose up -d cortex-app
+3 -3
View File
@@ -1,8 +1,8 @@
. "$PSScriptRoot\lib\common.ps1"
Write-Step "Starting Cerebro app"
Write-Step "Starting Cortex app"
Assert-Docker
Invoke-CerebroCompose up -d cerebro-db cerebro-embeddings
Invoke-CortexCompose up -d cortex-db cortex-embeddings
Write-Step "Waiting for embedding model health"
Wait-HttpOk "http://localhost:8088/health" 300
Invoke-CerebroCompose up -d --build cerebro-app
Invoke-CortexCompose up -d --build cortex-app
+1 -1
View File
@@ -2,4 +2,4 @@
Write-Step "Starting PostgreSQL with pgvector"
Assert-Docker
Invoke-CerebroCompose up -d cerebro-db
Invoke-CortexCompose up -d cortex-db
+1 -1
View File
@@ -2,4 +2,4 @@
Write-Step "Starting local embedding model"
Assert-Docker
Invoke-CerebroCompose up -d cerebro-embeddings
Invoke-CortexCompose up -d cortex-embeddings
+8 -8
View File
@@ -1,21 +1,21 @@
. "$PSScriptRoot\lib\common.ps1"
Write-Step "Starting Cerebro test dependencies for web UI"
Write-Step "Starting Cortex test dependencies for web UI"
Assert-Docker
Invoke-CerebroTestCompose up -d cerebro-test-db cerebro-test-embeddings
Invoke-CortexTestCompose up -d cortex-test-db cortex-test-embeddings
Write-Step "Waiting for test embedding model health"
Wait-HttpOk "http://localhost:8188/health" 300
Write-Step "Building Cerebro test app image for migrations"
Invoke-CerebroTestCompose build cerebro-test-app
Write-Step "Building Cortex test app image for migrations"
Invoke-CortexTestCompose build cortex-test-app
Write-Step "Applying test database migrations"
Invoke-CerebroTestCompose run --rm cerebro-test-app migrate
Invoke-CortexTestCompose run --rm cortex-test-app migrate
Write-Step "Starting optional Cerebro test web UI"
$webUpArgs = @("--profile", "ui", "up", "-d", "--build", "cerebro-test-web")
Invoke-CerebroTestCompose @webUpArgs
Write-Step "Starting optional Cortex test web UI"
$webUpArgs = @("--profile", "ui", "up", "-d", "--build", "cortex-test-web")
Invoke-CortexTestCompose @webUpArgs
Write-Step "Waiting for test web UI health"
Wait-HttpOk "http://localhost:5218/health" 120
+7 -7
View File
@@ -1,20 +1,20 @@
. "$PSScriptRoot\lib\common.ps1"
Write-Step "Starting Cerebro test database and embedding model"
Write-Step "Starting Cortex test database and embedding model"
Assert-Docker
Invoke-CerebroTestCompose up -d cerebro-test-db cerebro-test-embeddings
Invoke-CortexTestCompose up -d cortex-test-db cortex-test-embeddings
Write-Step "Waiting for test embedding model health"
Wait-HttpOk "http://localhost:8188/health" 300
Write-Step "Building Cerebro test app image"
Invoke-CerebroTestCompose build cerebro-test-app
Write-Step "Building Cortex test app image"
Invoke-CortexTestCompose build cortex-test-app
Write-Step "Applying test database migrations"
Invoke-CerebroTestCompose run --rm cerebro-test-app migrate
Invoke-CortexTestCompose run --rm cortex-test-app migrate
Write-Step "Starting Cerebro test MCP server"
Invoke-CerebroTestCompose up -d cerebro-test-app
Write-Step "Starting Cortex test MCP server"
Invoke-CortexTestCompose up -d cortex-test-app
Write-Step "Waiting for test MCP server health"
Wait-HttpOk "http://localhost:5217/health" 180
+8 -8
View File
@@ -1,21 +1,21 @@
. "$PSScriptRoot\lib\common.ps1"
Write-Step "Starting Cerebro dependencies for web UI"
Write-Step "Starting Cortex dependencies for web UI"
Assert-Docker
Invoke-CerebroCompose up -d cerebro-db cerebro-embeddings
Invoke-CortexCompose up -d cortex-db cortex-embeddings
Write-Step "Waiting for embedding model health"
Wait-HttpOk "http://localhost:8088/health" 300
Write-Step "Building Cerebro app image for migrations"
Invoke-CerebroCompose build cerebro-app
Write-Step "Building Cortex app image for migrations"
Invoke-CortexCompose build cortex-app
Write-Step "Applying database migrations"
Invoke-CerebroCompose run --rm cerebro-app migrate
Invoke-CortexCompose run --rm cortex-app migrate
Write-Step "Starting optional Cerebro web UI"
$webUpArgs = @("--profile", "ui", "up", "-d", "--build", "cerebro-web")
Invoke-CerebroCompose @webUpArgs
Write-Step "Starting optional Cortex web UI"
$webUpArgs = @("--profile", "ui", "up", "-d", "--build", "cortex-web")
Invoke-CortexCompose @webUpArgs
Write-Step "Waiting for web UI health"
Wait-HttpOk "http://localhost:5118/health" 120
+4 -4
View File
@@ -1,8 +1,8 @@
$ErrorActionPreference = "Stop"
$Script:RepoRoot = Resolve-Path (Join-Path $PSScriptRoot "..\..")
$Script:ComposeProject = "cerebro"
$Script:TestComposeProject = "cerebro-test"
$Script:ComposeProject = "cortex"
$Script:TestComposeProject = "cortex-test"
$Script:LocalDockerConfig = Join-Path $Script:RepoRoot ".docker"
New-Item -ItemType Directory -Force $Script:LocalDockerConfig | Out-Null
@@ -20,7 +20,7 @@ function Assert-Docker {
}
}
function Invoke-CerebroCompose {
function Invoke-CortexCompose {
$composeArgs = $args
Push-Location $Script:RepoRoot
@@ -35,7 +35,7 @@ function Invoke-CerebroCompose {
}
}
function Invoke-CerebroTestCompose {
function Invoke-CortexTestCompose {
$composeArgs = $args
Push-Location $Script:RepoRoot
+5 -5
View File
@@ -7,10 +7,10 @@ param(
. "$PSScriptRoot\lib\common.ps1"
$serviceName = switch ($Service) {
"app" { "cerebro-app" }
"web" { "cerebro-web" }
"db" { "cerebro-db" }
"embeddings" { "cerebro-embeddings" }
"app" { "cortex-app" }
"web" { "cortex-web" }
"db" { "cortex-db" }
"embeddings" { "cortex-embeddings" }
default { $null }
}
@@ -23,4 +23,4 @@ if ($serviceName) {
$args += $serviceName
}
Invoke-CerebroCompose @args
Invoke-CortexCompose @args
+1 -1
View File
@@ -1,4 +1,4 @@
. "$PSScriptRoot\lib\common.ps1"
Write-Step "Applying EF Core migrations"
Invoke-DotNet run --project src/Cerebro.Api/Cerebro.Api.csproj -- migrate
Invoke-DotNet run --project src/Cortex.Api/Cortex.Api.csproj -- migrate
+5 -5
View File
@@ -3,15 +3,15 @@ param([switch]$Force)
. "$PSScriptRoot\lib\common.ps1"
if (-not $Force) {
throw "This deletes the local Cerebro database volume. Re-run with -Force to continue."
throw "This deletes the local Cortex database volume. Re-run with -Force to continue."
}
Write-Step "Resetting local PostgreSQL data"
Assert-Docker
Invoke-CerebroCompose stop cerebro-app cerebro-db
Invoke-CerebroCompose rm -f cerebro-db
Invoke-CortexCompose stop cortex-app cortex-db
Invoke-CortexCompose rm -f cortex-db
$volumeName = "cerebro_cerebro-postgres-data"
$volumeName = "cortex_cortex-postgres-data"
docker volume inspect $volumeName *> $null
if ($LASTEXITCODE -eq 0) {
docker volume rm $volumeName
@@ -20,4 +20,4 @@ if ($LASTEXITCODE -eq 0) {
}
}
Invoke-CerebroCompose up -d cerebro-db
Invoke-CortexCompose up -d cortex-db
+6 -6
View File
@@ -3,15 +3,15 @@ param([switch]$Force)
. "$PSScriptRoot\lib\common.ps1"
if (-not $Force) {
throw "This deletes the local Cerebro test database volume. Re-run with -Force to continue."
throw "This deletes the local Cortex test database volume. Re-run with -Force to continue."
}
Write-Step "Resetting local Cerebro test database"
Write-Step "Resetting local Cortex test database"
Assert-Docker
Invoke-CerebroTestCompose stop cerebro-test-app cerebro-test-db
Invoke-CerebroTestCompose rm -f cerebro-test-db
Invoke-CortexTestCompose stop cortex-test-app cortex-test-db
Invoke-CortexTestCompose rm -f cortex-test-db
$volumeName = "cerebro-test_cerebro-test-postgres-data"
$volumeName = "cortex-test_cortex-test-postgres-data"
docker volume inspect $volumeName *> $null
if ($LASTEXITCODE -eq 0) {
docker volume rm $volumeName
@@ -20,4 +20,4 @@ if ($LASTEXITCODE -eq 0) {
}
}
Invoke-CerebroTestCompose up -d cerebro-test-db
Invoke-CortexTestCompose up -d cortex-test-db
+1 -1
View File
@@ -1,4 +1,4 @@
. "$PSScriptRoot\lib\common.ps1"
Write-Step "Seeding sample data"
Invoke-DotNet run --project src/Cerebro.Api/Cerebro.Api.csproj -- seed
Invoke-DotNet run --project src/Cortex.Api/Cortex.Api.csproj -- seed
+2 -2
View File
@@ -1,5 +1,5 @@
. "$PSScriptRoot\lib\common.ps1"
Write-Step "Stopping Cerebro services"
Write-Step "Stopping Cortex services"
Assert-Docker
Invoke-CerebroCompose stop
Invoke-CortexCompose stop
+3 -3
View File
@@ -1,6 +1,6 @@
. "$PSScriptRoot\lib\common.ps1"
Write-Step "Stopping optional Cerebro test web UI"
Write-Step "Stopping optional Cortex test web UI"
Assert-Docker
$webStopArgs = @("--profile", "ui", "stop", "cerebro-test-web")
Invoke-CerebroTestCompose @webStopArgs
$webStopArgs = @("--profile", "ui", "stop", "cortex-test-web")
Invoke-CortexTestCompose @webStopArgs
+2 -2
View File
@@ -1,5 +1,5 @@
. "$PSScriptRoot\lib\common.ps1"
Write-Step "Stopping Cerebro test services"
Write-Step "Stopping Cortex test services"
Assert-Docker
Invoke-CerebroTestCompose stop
Invoke-CortexTestCompose stop
+3 -3
View File
@@ -1,6 +1,6 @@
. "$PSScriptRoot\lib\common.ps1"
Write-Step "Stopping optional Cerebro web UI"
Write-Step "Stopping optional Cortex web UI"
Assert-Docker
$webStopArgs = @("--profile", "ui", "stop", "cerebro-web")
Invoke-CerebroCompose @webStopArgs
$webStopArgs = @("--profile", "ui", "stop", "cortex-web")
Invoke-CortexCompose @webStopArgs
+2 -2
View File
@@ -16,9 +16,9 @@ if (-not $NoReset) {
try {
Write-Step "Running integration tests"
$env:CEREBRO_TEST_BASE_URL = "http://localhost:5217"
$env:CORTEX_TEST_BASE_URL = "http://localhost:5217"
$args = @("test", "tests/Cerebro.IntegrationTests/Cerebro.IntegrationTests.csproj", "--configuration", "Release")
$args = @("test", "tests/Cortex.IntegrationTests/Cortex.IntegrationTests.csproj", "--configuration", "Release")
if (-not [string]::IsNullOrWhiteSpace($Filter)) {
$args += @("--filter", $Filter)
}
+1 -1
View File
@@ -1,4 +1,4 @@
. "$PSScriptRoot\lib\common.ps1"
Write-Step "Running tests"
Invoke-DotNet test Cerebro.slnx --configuration Release --filter "Category!=Integration"
Invoke-DotNet test Cortex.slnx --configuration Release --filter "Category!=Integration"
-3
View File
@@ -1,3 +0,0 @@
namespace Cerebro.Web;
public sealed class CerebroWebMarker;
+15
View File
@@ -0,0 +1,15 @@
<Project Sdk="Microsoft.NET.Sdk.Web">
<PropertyGroup>
<TargetFramework>net10.0</TargetFramework>
<Nullable>enable</Nullable>
<ImplicitUsings>enable</ImplicitUsings>
<DockerDefaultTargetOS>Linux</DockerDefaultTargetOS>
</PropertyGroup>
<ItemGroup>
<PackageReference Include="ModelContextProtocol.AspNetCore" />
<PackageReference Include="Npgsql.EntityFrameworkCore.PostgreSQL" />
</ItemGroup>
<ItemGroup>
<ProjectReference Include="..\Cortex.Core\Cortex.Core.csproj" />
</ItemGroup>
</Project>
@@ -1,18 +1,18 @@
using Cerebro.Api.Data;
using Cerebro.Api.Options;
using Cerebro.Api.Services;
using Cortex.Core.Data;
using Cortex.Core.Options;
using Cortex.Core.Services;
using Microsoft.EntityFrameworkCore;
using ModelContextProtocol.Server;
var builder = WebApplication.CreateBuilder(args);
builder.Services.Configure<CerebroOptions>(builder.Configuration.GetSection("Cerebro"));
builder.Services.Configure<CortexOptions>(builder.Configuration.GetSection("Cortex"));
builder.Services.Configure<EmbeddingOptions>(builder.Configuration.GetSection("Embedding"));
builder.Services.AddSingleton<DbClockInterceptor>();
builder.Services.AddDbContext<CerebroDbContext>((services, options) =>
builder.Services.AddDbContext<CortexDbContext>((services, options) =>
{
var connectionString = builder.Configuration.GetConnectionString("Cerebro")
?? throw new InvalidOperationException("Connection string 'Cerebro' is missing.");
var connectionString = builder.Configuration.GetConnectionString("Cortex")
?? throw new InvalidOperationException("Connection string 'Cortex' is missing.");
options.UseNpgsql(connectionString);
options.AddInterceptors(services.GetRequiredService<DbClockInterceptor>());
@@ -24,7 +24,7 @@ builder.Services.AddHttpClient<IEmbeddingClient, TeiEmbeddingClient>((services,
client.BaseAddress = new Uri(options.BaseUrl);
});
builder.Services.AddScoped<ICerebroMemoryService, CerebroMemoryService>();
builder.Services.AddScoped<ICortexMemoryService, CortexMemoryService>();
builder.Services
.AddMcpServer()
@@ -39,7 +39,7 @@ var app = builder.Build();
if (args.Contains("migrate", StringComparer.OrdinalIgnoreCase))
{
await using var scope = app.Services.CreateAsyncScope();
var db = scope.ServiceProvider.GetRequiredService<CerebroDbContext>();
var db = scope.ServiceProvider.GetRequiredService<CortexDbContext>();
await db.Database.MigrateAsync();
return;
}
@@ -54,7 +54,7 @@ if (args.Contains("seed", StringComparer.OrdinalIgnoreCase))
app.MapGet("/", () => Results.Redirect("/health"));
app.MapGet("/health", () => Results.Ok(new
{
name = "Cerebro",
name = "Cortex",
status = "ok",
utc = DateTimeOffset.UtcNow
}));
@@ -1,17 +1,17 @@
using System.ComponentModel;
using Cerebro.Api.Contracts;
using Cerebro.Api.Services;
using Cortex.Core.Contracts;
using Cortex.Core.Services;
using ModelContextProtocol.Server;
namespace Cerebro.Api.Tools;
namespace Cortex.Api.Tools;
[McpServerToolType]
public static class CerebroTools
public static class CortexTools
{
[McpServerTool(Name = "CreateProject", UseStructuredContent = true, Destructive = false)]
[Description("Create a new explicit Cerebro project. Items cannot be added until their project exists.")]
[Description("Create a new explicit Cortex project. Items cannot be added until their project exists.")]
public static Task<ProjectDto> CreateProject(
ICerebroMemoryService memory,
ICortexMemoryService memory,
[Description("Human-readable project name. The stable slug is derived from this name.")] string name,
CancellationToken cancellationToken)
{
@@ -19,9 +19,9 @@ public static class CerebroTools
}
[McpServerTool(Name = "ListProjects", UseStructuredContent = true, ReadOnly = true, Destructive = false)]
[Description("List existing Cerebro projects.")]
[Description("List existing Cortex projects.")]
public static Task<IReadOnlyList<ProjectDto>> ListProjects(
ICerebroMemoryService memory,
ICortexMemoryService memory,
CancellationToken cancellationToken)
{
return memory.ListProjectsAsync(cancellationToken);
@@ -30,7 +30,7 @@ public static class CerebroTools
[McpServerTool(Name = "AddItem", UseStructuredContent = true, Destructive = false)]
[Description("Add a memory item to an existing explicit project.")]
public static Task<MemoryItemDto> AddItem(
ICerebroMemoryService memory,
ICortexMemoryService memory,
[Description("Existing project name or slug. The project must already exist.")] string project,
[Description("One of: requirement, location, todo, note.")] string category,
[Description("Short item title.")] string title,
@@ -46,7 +46,7 @@ public static class CerebroTools
[McpServerTool(Name = "FindItems", UseStructuredContent = true, ReadOnly = true, Destructive = false)]
[Description("Find memory items with hybrid semantic and keyword search.")]
public static Task<IReadOnlyList<SearchResultDto>> FindItems(
ICerebroMemoryService memory,
ICortexMemoryService memory,
[Description("Natural language search query.")] string query,
[Description("Project name or slug. Required unless searchAllProjects is true.")] string? project = null,
[Description("Set true to search across all projects.")] bool searchAllProjects = false,
@@ -60,7 +60,7 @@ public static class CerebroTools
[McpServerTool(Name = "UpdateItem", UseStructuredContent = true, Destructive = true)]
[Description("Update an existing memory item. Content-related changes automatically regenerate the embedding.")]
public static Task<MemoryItemDto> UpdateItem(
ICerebroMemoryService memory,
ICortexMemoryService memory,
[Description("Existing project name or slug.")] string project,
[Description("Memory item id from find results.")] Guid id,
[Description("Optional new category: requirement, location, todo, note.")] string? category = null,
@@ -77,7 +77,7 @@ public static class CerebroTools
[McpServerTool(Name = "DeleteItem", UseStructuredContent = true, Destructive = true)]
[Description("Soft-delete an existing memory item from an explicit project.")]
public static Task<MemoryItemDto> DeleteItem(
ICerebroMemoryService memory,
ICortexMemoryService memory,
[Description("Existing project name or slug.")] string project,
[Description("Memory item id from find results.")] Guid id,
CancellationToken cancellationToken)
@@ -1,9 +1,9 @@
{
"AllowedHosts": "localhost;127.0.0.1;cerebro-app",
"AllowedHosts": "localhost;127.0.0.1;cortex-app",
"ConnectionStrings": {
"Cerebro": "Host=localhost;Port=54329;Database=cerebro;Username=cerebro;Password=cerebro_dev_password;GSS Encryption Mode=Disable"
"Cortex": "Host=localhost;Port=54329;Database=cortex;Username=cortex;Password=cortex_dev_password;GSS Encryption Mode=Disable"
},
"Cerebro": {
"Cortex": {
"EmbeddingModel": "BAAI/bge-small-en-v1.5",
"EmbeddingDimensions": 384
},
@@ -1,6 +1,6 @@
using Cerebro.Api.Domain;
using Cortex.Core.Domain;
namespace Cerebro.Api.Contracts;
namespace Cortex.Core.Contracts;
public sealed record ProjectDto(Guid Id, string Name, string Slug, DateTimeOffset CreatedAt);
@@ -1,16 +1,14 @@
<Project Sdk="Microsoft.NET.Sdk.Web">
<Project Sdk="Microsoft.NET.Sdk">
<PropertyGroup>
<TargetFramework>net10.0</TargetFramework>
<Nullable>enable</Nullable>
<ImplicitUsings>enable</ImplicitUsings>
<DockerDefaultTargetOS>Linux</DockerDefaultTargetOS>
</PropertyGroup>
<ItemGroup>
<PackageReference Include="Microsoft.EntityFrameworkCore.Design">
<PrivateAssets>all</PrivateAssets>
<IncludeAssets>runtime; build; native; contentfiles; analyzers; buildtransitive</IncludeAssets>
</PackageReference>
<PackageReference Include="ModelContextProtocol.AspNetCore" />
<PackageReference Include="Npgsql.EntityFrameworkCore.PostgreSQL" />
</ItemGroup>
</Project>
@@ -1,9 +1,9 @@
using Cerebro.Api.Domain;
using Cortex.Core.Domain;
using Microsoft.EntityFrameworkCore;
namespace Cerebro.Api.Data;
namespace Cortex.Core.Data;
public sealed class CerebroDbContext(DbContextOptions<CerebroDbContext> options) : DbContext(options)
public sealed class CortexDbContext(DbContextOptions<CortexDbContext> options) : DbContext(options)
{
public DbSet<Project> Projects => Set<Project>();
public DbSet<MemoryItem> MemoryItems => Set<MemoryItem>();
@@ -1,8 +1,8 @@
using Cerebro.Api.Domain;
using Cortex.Core.Domain;
using Microsoft.EntityFrameworkCore;
using Microsoft.EntityFrameworkCore.Diagnostics;
namespace Cerebro.Api.Data;
namespace Cortex.Core.Data;
public sealed class DbClockInterceptor : SaveChangesInterceptor
{
@@ -1,25 +1,26 @@
using Cerebro.Api.Services;
using Cortex.Core.Services;
using Microsoft.EntityFrameworkCore;
using Microsoft.Extensions.DependencyInjection;
namespace Cerebro.Api.Data;
namespace Cortex.Core.Data;
public static class SeedData
{
public static async Task SeedAsync(IServiceProvider services, CancellationToken cancellationToken)
{
var db = services.GetRequiredService<CerebroDbContext>();
var db = services.GetRequiredService<CortexDbContext>();
await db.Database.MigrateAsync(cancellationToken);
var memory = services.GetRequiredService<ICerebroMemoryService>();
var memory = services.GetRequiredService<ICortexMemoryService>();
var projects = await memory.ListProjectsAsync(cancellationToken);
if (projects.All(project => project.Slug != "cerebro"))
if (projects.All(project => project.Slug != "cortex"))
{
await memory.CreateProjectAsync("Cerebro", cancellationToken);
await memory.CreateProjectAsync("Cortex", cancellationToken);
}
var existing = await memory.FindItemsAsync(
new FindMemoryItemsRequest("Cerebro MCP server", "cerebro", false, null, 1),
new FindMemoryItemsRequest("Cortex MCP server", "cortex", false, null, 1),
cancellationToken);
if (existing.Count > 0)
@@ -29,10 +30,10 @@ public static class SeedData
await memory.AddItemAsync(
new AddMemoryItemRequest(
"cerebro",
"cortex",
"requirement",
"Cerebro runs as an HTTP MCP server",
"The Cerebro MCP server is a .NET 10 ASP.NET Core app hosted by Kestrel and deployed locally with Docker.",
"Cortex runs as an HTTP MCP server",
"The Cortex MCP server is a .NET 10 ASP.NET Core app hosted by Kestrel and deployed locally with Docker.",
["mcp", "dotnet", "docker"],
"""{"source":"seed"}""",
"active"),
@@ -40,7 +41,7 @@ public static class SeedData
await memory.AddItemAsync(
new AddMemoryItemRequest(
"cerebro",
"cortex",
"note",
"Embedding model choice",
"Use BAAI/bge-small-en-v1.5 through a local Hugging Face Text Embeddings Inference container. The vector size is 384.",
@@ -1,4 +1,4 @@
namespace Cerebro.Api.Domain;
namespace Cortex.Core.Domain;
public interface ITimestampedEntity
{
@@ -1,4 +1,4 @@
namespace Cerebro.Api.Domain;
namespace Cortex.Core.Domain;
public enum MemoryCategory
{
@@ -1,4 +1,4 @@
namespace Cerebro.Api.Domain;
namespace Cortex.Core.Domain;
public sealed class MemoryItem : ITimestampedEntity
{
@@ -1,4 +1,4 @@
namespace Cerebro.Api.Domain;
namespace Cortex.Core.Domain;
public sealed class Project : ITimestampedEntity
{
@@ -1,12 +1,12 @@
using Cerebro.Api.Data;
using Cortex.Core.Data;
using Microsoft.EntityFrameworkCore.Infrastructure;
using Microsoft.EntityFrameworkCore.Migrations;
#nullable disable
namespace Cerebro.Api.Migrations;
namespace Cortex.Core.Migrations;
[DbContext(typeof(CerebroDbContext))]
[DbContext(typeof(CortexDbContext))]
[Migration("20260708124000_InitialCreate")]
public partial class InitialCreate : Migration
{
@@ -1,15 +1,15 @@
using Cerebro.Api.Data;
using Cerebro.Api.Domain;
using Cortex.Core.Data;
using Cortex.Core.Domain;
using Microsoft.EntityFrameworkCore;
using Microsoft.EntityFrameworkCore.Infrastructure;
using Microsoft.EntityFrameworkCore.Storage.ValueConversion;
#nullable disable
namespace Cerebro.Api.Migrations;
namespace Cortex.Core.Migrations;
[DbContext(typeof(CerebroDbContext))]
public sealed class CerebroDbContextModelSnapshot : ModelSnapshot
[DbContext(typeof(CortexDbContext))]
public sealed class CortexDbContextModelSnapshot : ModelSnapshot
{
protected override void BuildModel(ModelBuilder modelBuilder)
{
@@ -17,7 +17,7 @@ public sealed class CerebroDbContextModelSnapshot : ModelSnapshot
.HasAnnotation("ProductVersion", "10.0.0")
.HasPostgresExtension("vector");
modelBuilder.Entity("Cerebro.Api.Domain.Project", entity =>
modelBuilder.Entity("Cortex.Core.Domain.Project", entity =>
{
entity.Property<Guid>("Id").HasColumnName("id").HasColumnType("uuid");
entity.Property<DateTimeOffset>("CreatedAt").HasColumnName("created_at").HasColumnType("timestamp with time zone");
@@ -29,7 +29,7 @@ public sealed class CerebroDbContextModelSnapshot : ModelSnapshot
entity.ToTable("projects");
});
modelBuilder.Entity("Cerebro.Api.Domain.MemoryItem", entity =>
modelBuilder.Entity("Cortex.Core.Domain.MemoryItem", entity =>
{
entity.Property<Guid>("Id").HasColumnName("id").HasColumnType("uuid");
entity.Property<MemoryCategory>("Category").HasColumnName("category").HasMaxLength(40).HasConversion<string>();
@@ -46,12 +46,12 @@ public sealed class CerebroDbContextModelSnapshot : ModelSnapshot
entity.HasKey("Id");
entity.HasIndex("DeletedAt");
entity.HasIndex("ProjectId", "Category");
entity.HasOne("Cerebro.Api.Domain.Project", "Project").WithMany("Items").HasForeignKey("ProjectId").OnDelete(DeleteBehavior.Cascade).IsRequired();
entity.HasOne("Cortex.Core.Domain.Project", "Project").WithMany("Items").HasForeignKey("ProjectId").OnDelete(DeleteBehavior.Cascade).IsRequired();
entity.Navigation("Project");
entity.ToTable("memory_items");
});
modelBuilder.Entity("Cerebro.Api.Domain.Project", entity =>
modelBuilder.Entity("Cortex.Core.Domain.Project", entity =>
{
entity.Navigation("Items");
});
@@ -1,6 +1,6 @@
namespace Cerebro.Api.Options;
namespace Cortex.Core.Options;
public sealed class CerebroOptions
public sealed class CortexOptions
{
public string EmbeddingModel { get; set; } = "BAAI/bge-small-en-v1.5";
public int EmbeddingDimensions { get; set; } = 384;
@@ -1,4 +1,4 @@
namespace Cerebro.Api.Options;
namespace Cortex.Core.Options;
public sealed class EmbeddingOptions
{
@@ -1,25 +1,26 @@
using System.Data;
using System.Text.Json;
using Cerebro.Api.Contracts;
using Cerebro.Api.Data;
using Cerebro.Api.Domain;
using Cerebro.Api.Options;
using Cortex.Core.Contracts;
using Cortex.Core.Data;
using Cortex.Core.Domain;
using Cortex.Core.Options;
using Microsoft.EntityFrameworkCore;
using Microsoft.Extensions.Configuration;
using Microsoft.Extensions.Options;
using Npgsql;
using NpgsqlTypes;
namespace Cerebro.Api.Services;
namespace Cortex.Core.Services;
public sealed class CerebroMemoryService(
CerebroDbContext db,
public sealed class CortexMemoryService(
CortexDbContext db,
IEmbeddingClient embeddings,
IOptions<CerebroOptions> options,
IConfiguration configuration) : ICerebroMemoryService
IOptions<CortexOptions> options,
IConfiguration configuration) : ICortexMemoryService
{
private readonly CerebroOptions _options = options.Value;
private readonly string _connectionString = configuration.GetConnectionString("Cerebro")
?? throw new InvalidOperationException("Connection string 'Cerebro' is missing.");
private readonly CortexOptions _options = options.Value;
private readonly string _connectionString = configuration.GetConnectionString("Cortex")
?? throw new InvalidOperationException("Connection string 'Cortex' is missing.");
public async Task<ProjectDto> CreateProjectAsync(string name, CancellationToken cancellationToken)
{
@@ -1,8 +1,8 @@
using Cerebro.Api.Contracts;
using Cortex.Core.Contracts;
namespace Cerebro.Api.Services;
namespace Cortex.Core.Services;
public interface ICerebroMemoryService
public interface ICortexMemoryService
{
Task<ProjectDto> CreateProjectAsync(string name, CancellationToken cancellationToken);
Task<IReadOnlyList<ProjectDto>> ListProjectsAsync(CancellationToken cancellationToken);
@@ -1,4 +1,4 @@
namespace Cerebro.Api.Services;
namespace Cortex.Core.Services;
public interface IEmbeddingClient
{
@@ -1,7 +1,7 @@
using System.Text;
using System.Text.RegularExpressions;
namespace Cerebro.Api.Services;
namespace Cortex.Core.Services;
public static partial class Slug
{
@@ -1,9 +1,9 @@
using System.Net.Http.Json;
using System.Text.Json.Serialization;
using Cerebro.Api.Options;
using Cortex.Core.Options;
using Microsoft.Extensions.Options;
namespace Cerebro.Api.Services;
namespace Cortex.Core.Services;
public sealed class TeiEmbeddingClient(HttpClient httpClient, IOptions<EmbeddingOptions> options) : IEmbeddingClient
{
@@ -1,6 +1,6 @@
using System.Globalization;
namespace Cerebro.Api.Services;
namespace Cortex.Core.Services;
public static class VectorLiteral
{
@@ -1,10 +1,10 @@
@page "/Error"
<PageTitle>Error - Cerebro</PageTitle>
<PageTitle>Error - Cortex</PageTitle>
<main class="shell">
<section class="workspace">
<h1>Something went wrong</h1>
<p class="muted">Check the Cerebro web container logs for details.</p>
<p class="muted">Check the Cortex web container logs for details.</p>
</section>
</main>
@@ -1,19 +1,19 @@
@page "/"
@rendermode InteractiveServer
@using Cerebro.Api.Contracts
@using Cerebro.Api.Domain
@using Cerebro.Api.Services
@inject ICerebroMemoryService Memory
@inject CerebroUiQueries Queries
@using Cortex.Core.Contracts
@using Cortex.Core.Domain
@using Cortex.Core.Services
@inject ICortexMemoryService Memory
@inject CortexUiQueries Queries
<PageTitle>Cerebro</PageTitle>
<PageTitle>Cortex</PageTitle>
<main class="app-shell">
<aside class="sidebar">
<div class="brand">
<span class="brand-mark">C</span>
<div>
<h1>Cerebro</h1>
<h1>Cortex</h1>
<p>Project memory</p>
</div>
</div>
@@ -1,15 +1,15 @@
<Router AppAssembly="@typeof(Cerebro.Web.CerebroWebMarker).Assembly">
<Router AppAssembly="@typeof(Cortex.Web.CortexWebMarker).Assembly">
<Found Context="routeData">
<RouteView RouteData="@routeData" DefaultLayout="@typeof(Layout.MainLayout)" />
<FocusOnNavigate RouteData="@routeData" Selector="h1" />
</Found>
<NotFound>
<PageTitle>Not found - Cerebro</PageTitle>
<PageTitle>Not found - Cortex</PageTitle>
<LayoutView Layout="@typeof(Layout.MainLayout)">
<main class="shell">
<section class="workspace">
<h1>Not found</h1>
<p class="muted">That Cerebro page does not exist.</p>
<p class="muted">That Cortex page does not exist.</p>
</section>
</main>
</LayoutView>
@@ -8,7 +8,11 @@
</PropertyGroup>
<ItemGroup>
<ProjectReference Include="..\Cerebro.Api\Cerebro.Api.csproj" />
<PackageReference Include="Npgsql.EntityFrameworkCore.PostgreSQL" />
</ItemGroup>
<ItemGroup>
<ProjectReference Include="..\Cortex.Core\Cortex.Core.csproj" />
</ItemGroup>
</Project>
@@ -1,10 +1,10 @@
using Cerebro.Api.Data;
using Cerebro.Api.Domain;
using Cortex.Core.Data;
using Cortex.Core.Domain;
using Microsoft.EntityFrameworkCore;
namespace Cerebro.Web;
namespace Cortex.Web;
public sealed class CerebroUiQueries(CerebroDbContext db)
public sealed class CortexUiQueries(CortexDbContext db)
{
public async Task<IReadOnlyList<ProjectSummary>> GetProjectSummariesAsync(CancellationToken cancellationToken)
{
+3
View File
@@ -0,0 +1,3 @@
namespace Cortex.Web;
public sealed class CortexWebMarker;
@@ -1,8 +1,8 @@
using Cerebro.Api.Data;
using Cerebro.Api.Options;
using Cerebro.Api.Services;
using Cerebro.Web;
using Cerebro.Web.Components;
using Cortex.Core.Data;
using Cortex.Core.Options;
using Cortex.Core.Services;
using Cortex.Web;
using Cortex.Web.Components;
using Microsoft.EntityFrameworkCore;
var builder = WebApplication.CreateBuilder(args);
@@ -10,13 +10,13 @@ var builder = WebApplication.CreateBuilder(args);
builder.Services.AddRazorComponents()
.AddInteractiveServerComponents();
builder.Services.Configure<CerebroOptions>(builder.Configuration.GetSection("Cerebro"));
builder.Services.Configure<CortexOptions>(builder.Configuration.GetSection("Cortex"));
builder.Services.Configure<EmbeddingOptions>(builder.Configuration.GetSection("Embedding"));
builder.Services.AddSingleton<DbClockInterceptor>();
builder.Services.AddDbContext<CerebroDbContext>((services, options) =>
builder.Services.AddDbContext<CortexDbContext>((services, options) =>
{
var connectionString = builder.Configuration.GetConnectionString("Cerebro")
?? throw new InvalidOperationException("Connection string 'Cerebro' is missing.");
var connectionString = builder.Configuration.GetConnectionString("Cortex")
?? throw new InvalidOperationException("Connection string 'Cortex' is missing.");
options.UseNpgsql(connectionString);
options.AddInterceptors(services.GetRequiredService<DbClockInterceptor>());
@@ -28,8 +28,8 @@ builder.Services.AddHttpClient<IEmbeddingClient, TeiEmbeddingClient>((services,
client.BaseAddress = new Uri(options.BaseUrl);
});
builder.Services.AddScoped<ICerebroMemoryService, CerebroMemoryService>();
builder.Services.AddScoped<CerebroUiQueries>();
builder.Services.AddScoped<ICortexMemoryService, CortexMemoryService>();
builder.Services.AddScoped<CortexUiQueries>();
var app = builder.Build();
@@ -40,10 +40,11 @@ if (!app.Environment.IsDevelopment())
app.UseStaticFiles();
app.UseAntiforgery();
app.MapStaticAssets();
app.MapGet("/health", () => Results.Ok(new
{
name = "Cerebro Web",
name = "Cortex Web",
status = "ok",
utc = DateTimeOffset.UtcNow
}));
@@ -1,6 +1,6 @@
{
"profiles": {
"Cerebro.Web": {
"Cortex.Web": {
"commandName": "Project",
"launchBrowser": true,
"environmentVariables": {
@@ -1,9 +1,9 @@
{
"AllowedHosts": "localhost;127.0.0.1;cerebro-web",
"AllowedHosts": "localhost;127.0.0.1;cortex-web",
"ConnectionStrings": {
"Cerebro": "Host=localhost;Port=54329;Database=cerebro;Username=cerebro;Password=cerebro_dev_password;GSS Encryption Mode=Disable"
"Cortex": "Host=localhost;Port=54329;Database=cortex;Username=cortex;Password=cortex_dev_password;GSS Encryption Mode=Disable"
},
"Cerebro": {
"Cortex": {
"EmbeddingModel": "BAAI/bge-small-en-v1.5",
"EmbeddingDimensions": 384
},
@@ -1,9 +0,0 @@
using Xunit;
namespace Cerebro.IntegrationTests.Fixtures;
[CollectionDefinition(Name)]
public sealed class CerebroTestCollection : ICollectionFixture<CerebroTestFixture>
{
public const string Name = "Cerebro test instance";
}
@@ -0,0 +1,9 @@
using Xunit;
namespace Cortex.IntegrationTests.Fixtures;
[CollectionDefinition(Name)]
public sealed class CortexTestCollection : ICollectionFixture<CortexTestFixture>
{
public const string Name = "Cortex test instance";
}
@@ -3,15 +3,15 @@ using ModelContextProtocol.Client;
using ModelContextProtocol.Protocol;
using Xunit;
namespace Cerebro.IntegrationTests.Fixtures;
namespace Cortex.IntegrationTests.Fixtures;
public sealed class CerebroTestFixture : IAsyncLifetime
public sealed class CortexTestFixture : IAsyncLifetime
{
private static readonly JsonSerializerOptions JsonOptions = new(JsonSerializerDefaults.Web);
private readonly HttpClient _healthClient = new();
public Uri BaseUrl { get; } = new(
Environment.GetEnvironmentVariable("CEREBRO_TEST_BASE_URL") ?? "http://localhost:5217");
Environment.GetEnvironmentVariable("CORTEX_TEST_BASE_URL") ?? "http://localhost:5217");
public Uri McpEndpoint => new(BaseUrl, "/mcp");
@@ -25,7 +25,7 @@ public sealed class CerebroTestFixture : IAsyncLifetime
catch (Exception ex)
{
throw new InvalidOperationException(
$"Cerebro test instance is not reachable at {BaseUrl}. Run .\\scripts\\deploy-test.ps1 first, or use .\\scripts\\test-integration.ps1.",
$"Cortex test instance is not reachable at {BaseUrl}. Run .\\scripts\\deploy-test.ps1 first, or use .\\scripts\\test-integration.ps1.",
ex);
}
}
@@ -1,6 +1,6 @@
using System.Text.Json.Serialization;
namespace Cerebro.IntegrationTests.Support;
namespace Cortex.IntegrationTests.Support;
public sealed record ProjectDto(
[property: JsonPropertyName("id")] Guid Id,
@@ -1,7 +1,7 @@
using ModelContextProtocol.Client;
using ModelContextProtocol.Protocol;
namespace Cerebro.IntegrationTests.Support;
namespace Cortex.IntegrationTests.Support;
public static class McpTestClientExtensions
{
@@ -1,12 +1,12 @@
using Cerebro.IntegrationTests.Fixtures;
using Cerebro.IntegrationTests.Support;
using Cortex.IntegrationTests.Fixtures;
using Cortex.IntegrationTests.Support;
using Xunit;
namespace Cerebro.IntegrationTests.Tests;
namespace Cortex.IntegrationTests.Tests;
[Collection(CerebroTestCollection.Name)]
[Collection(CortexTestCollection.Name)]
[Trait("Category", "Integration")]
public sealed class MemoryItemTests(CerebroTestFixture fixture)
public sealed class MemoryItemTests(CortexTestFixture fixture)
{
[Fact]
public async Task Add_item_fails_when_project_is_missing()
@@ -29,7 +29,7 @@ public sealed class MemoryItemTests(CerebroTestFixture fixture)
var projectName = fixture.NewProjectName("items");
_ = await client.CreateProjectAsync(projectName);
var added = CerebroTestFixture.ReadStructuredContent<MemoryItemDto>(
var added = CortexTestFixture.ReadStructuredContent<MemoryItemDto>(
await client.AddItemAsync(
projectName,
"todo",
@@ -41,7 +41,7 @@ public sealed class MemoryItemTests(CerebroTestFixture fixture)
Assert.Equal("Todo", added.Category);
Assert.Equal("BAAI/bge-small-en-v1.5", added.EmbeddingModel);
var updated = CerebroTestFixture.ReadStructuredContent<MemoryItemDto>(
var updated = CortexTestFixture.ReadStructuredContent<MemoryItemDto>(
await client.UpdateItemAsync(
projectName,
added.Id,
@@ -51,12 +51,12 @@ public sealed class MemoryItemTests(CerebroTestFixture fixture)
Assert.Contains("width", updated.Content);
Assert.True(updated.UpdatedAt >= added.UpdatedAt);
var deleted = CerebroTestFixture.ReadStructuredContent<MemoryItemDto>(
var deleted = CortexTestFixture.ReadStructuredContent<MemoryItemDto>(
await client.DeleteItemAsync(projectName, added.Id));
Assert.Equal("deleted", deleted.Status);
var searchAfterDelete = CerebroTestFixture.ReadStructuredContent<SearchResultDto[]>(
var searchAfterDelete = CortexTestFixture.ReadStructuredContent<SearchResultDto[]>(
await client.FindItemsAsync("cabinet opening shelves", projectName));
Assert.DoesNotContain(searchAfterDelete, item => item.Id == added.Id);
@@ -1,12 +1,12 @@
using Cerebro.IntegrationTests.Fixtures;
using Cerebro.IntegrationTests.Support;
using Cortex.IntegrationTests.Fixtures;
using Cortex.IntegrationTests.Support;
using Xunit;
namespace Cerebro.IntegrationTests.Tests;
namespace Cortex.IntegrationTests.Tests;
[Collection(CerebroTestCollection.Name)]
[Collection(CortexTestCollection.Name)]
[Trait("Category", "Integration")]
public sealed class ProjectTests(CerebroTestFixture fixture)
public sealed class ProjectTests(CortexTestFixture fixture)
{
[Fact]
public async Task Create_project_then_list_projects()
@@ -14,13 +14,13 @@ public sealed class ProjectTests(CerebroTestFixture fixture)
await using var client = await fixture.CreateClientAsync();
var projectName = fixture.NewProjectName("project");
var created = CerebroTestFixture.ReadStructuredContent<ProjectDto>(
var created = CortexTestFixture.ReadStructuredContent<ProjectDto>(
await client.CreateProjectAsync(projectName));
Assert.Equal(projectName, created.Name);
Assert.StartsWith("it-project-", created.Slug);
var listed = CerebroTestFixture.ReadStructuredContent<ProjectDto[]>(
var listed = CortexTestFixture.ReadStructuredContent<ProjectDto[]>(
await client.CallToolAsync("ListProjects", new Dictionary<string, object?>()));
Assert.Contains(listed, project => project.Id == created.Id);
@@ -1,12 +1,12 @@
using Cerebro.IntegrationTests.Fixtures;
using Cerebro.IntegrationTests.Support;
using Cortex.IntegrationTests.Fixtures;
using Cortex.IntegrationTests.Support;
using Xunit;
namespace Cerebro.IntegrationTests.Tests;
namespace Cortex.IntegrationTests.Tests;
[Collection(CerebroTestCollection.Name)]
[Collection(CortexTestCollection.Name)]
[Trait("Category", "Integration")]
public sealed class SearchTests(CerebroTestFixture fixture)
public sealed class SearchTests(CortexTestFixture fixture)
{
[Fact]
public async Task Project_scoped_search_does_not_leak_between_projects()
@@ -18,12 +18,12 @@ public sealed class SearchTests(CerebroTestFixture fixture)
_ = await client.CreateProjectAsync(alpha);
_ = await client.CreateProjectAsync(beta);
var alphaItem = CerebroTestFixture.ReadStructuredContent<MemoryItemDto>(
var alphaItem = CortexTestFixture.ReadStructuredContent<MemoryItemDto>(
await client.AddItemAsync(alpha, "location", "Charging brick", "The USB-C charging brick is in the blue backpack."));
_ = await client.AddItemAsync(beta, "location", "Charging brick", "The spare USB-C charging brick is in the garage drawer.");
var alphaResults = CerebroTestFixture.ReadStructuredContent<SearchResultDto[]>(
var alphaResults = CortexTestFixture.ReadStructuredContent<SearchResultDto[]>(
await client.FindItemsAsync("where is the charging brick", alpha));
Assert.Contains(alphaResults, result => result.Id == alphaItem.Id);
@@ -38,12 +38,12 @@ public sealed class SearchTests(CerebroTestFixture fixture)
_ = await client.CreateProjectAsync(projectName);
var note = CerebroTestFixture.ReadStructuredContent<MemoryItemDto>(
var note = CortexTestFixture.ReadStructuredContent<MemoryItemDto>(
await client.AddItemAsync(projectName, "note", "Shelf idea", "Use oak shelves for the reading nook."));
_ = await client.AddItemAsync(projectName, "todo", "Buy shelf brackets", "Buy black metal brackets for the oak shelves.");
var allProjects = CerebroTestFixture.ReadStructuredContent<SearchResultDto[]>(
var allProjects = CortexTestFixture.ReadStructuredContent<SearchResultDto[]>(
await client.FindItemsAsync("oak shelves reading nook", searchAllProjects: true, category: "note"));
Assert.Contains(allProjects, result => result.Id == note.Id);
@@ -1,11 +1,11 @@
using Cerebro.IntegrationTests.Fixtures;
using Cortex.IntegrationTests.Fixtures;
using Xunit;
namespace Cerebro.IntegrationTests.Tests;
namespace Cortex.IntegrationTests.Tests;
[Collection(CerebroTestCollection.Name)]
[Collection(CortexTestCollection.Name)]
[Trait("Category", "Integration")]
public sealed class SmokeTests(CerebroTestFixture fixture)
public sealed class SmokeTests(CortexTestFixture fixture)
{
[Fact]
public async Task Health_endpoint_is_available()