# Neo Cortex v3.0 — Architecture

> Standalone Memory Server · Python 3.12 · Port 5074 · 268 memories

## System Overview

```mermaid
graph TB
    subgraph CLIENTS["CLIENTS — HTTP → port 5074"]
        MCP["Python MCP<br/>:5071"]
        CSHARP["C# Client<br/>neo-reloaded :5070<br/>NEXT"]
        FUTURE["Future Clients"]
    end

    subgraph SERVER["FastAPI Server — server.py"]
        INGEST_EP["POST /api/ingest"]
        QUERY_EP["GET /api/query"]
        DREAM_EP["POST /api/dream"]
        STATS_EP["GET /api/stats"]
        TIMELINE_EP["GET /api/timeline"]
    end

    subgraph CORTEX["CortexService — cortex.py"]
        INGEST_FN["ingest()"]
        RECALL_FN["recall()"]
        DREAM_FN["dream()"]
        STATS_FN["stats()"]
        TIMELINE_FN["timeline()"]
    end

    subgraph COMPONENTS["Components"]
        STORE["MemoryStore<br/>store.py ~160 LOC"]
        EMBEDDER["JinaEmbedder<br/>embedder.py ~45 LOC"]
        CLASSIFIER["GroqClassifier<br/>classifier.py ~140 LOC"]
    end

    subgraph EXTERNAL["External Services"]
        CHROMADB[("ChromaDB<br/>~/neo-ram/cortex_db/<br/>268 memories")]
        JINA["Jina AI API<br/>jina-embeddings-v3<br/>1024 dim"]
        GROQ["Groq API<br/>llama-3.3-70b"]
    end

    MCP -->|HTTP| INGEST_EP
    MCP -->|HTTP| QUERY_EP
    CSHARP -.->|HTTP| INGEST_EP
    CSHARP -.->|HTTP| QUERY_EP
    FUTURE -.->|HTTP| QUERY_EP

    INGEST_EP --> INGEST_FN
    QUERY_EP --> RECALL_FN
    DREAM_EP --> DREAM_FN
    STATS_EP --> STATS_FN
    TIMELINE_EP --> TIMELINE_FN

    INGEST_FN --> STORE
    INGEST_FN --> EMBEDDER
    INGEST_FN --> CLASSIFIER
    RECALL_FN --> STORE
    RECALL_FN --> EMBEDDER
    RECALL_FN --> CLASSIFIER
    DREAM_FN --> STORE
    STATS_FN --> STORE
    TIMELINE_FN --> STORE

    STORE --> CHROMADB
    EMBEDDER --> JINA
    CLASSIFIER --> GROQ
```

## Ingest Flow

Quando arriva un messaggio: filtro rumore → embedding → classificazione → salvataggio.

```mermaid
flowchart LR
    REQ["IngestRequest"] --> T1

    subgraph NOISE["Noise Filter"]
        T1{"Tier 1: Static<br/>ciao, ok, /clear<br/>free, instant"} -->|pass| T2
        T1 -->|noise| SKIP1["skip"]
        T2{"Tier 2: Groq LLM<br/>only if ≤50 chars"} -->|pass| OK["signal"]
        T2 -->|noise| SKIP2["skip"]
    end

    OK --> EMBED["Jina: embed<br/>combined Q+A<br/>→ 1024-dim"]
    OK --> CLASS["Groq: classify<br/>→ project<br/>→ topic<br/>→ activity"]

    EMBED --> SAVE["ChromaDB insert"]
    CLASS --> SAVE
    SAVE --> ID["v3_XXXX_N_NNNNN"]
```

## Recall Flow

Due modalità: **basic** (solo vector search) e **smart** (analisi query + filtri + MBEL).

```mermaid
flowchart TB
    QUERY["query + n + smart?"] --> DECIDE{smart?}

    DECIDE -->|basic| B_EMBED["Jina: embed_query"]
    B_EMBED --> B_SEARCH["ChromaDB: cosine search top N"]
    B_SEARCH --> B_RESULT["RecallResult"]

    DECIDE -->|smart| ANALYZE["Groq: analyze_query<br/>→ project, time_hint,<br/>refined_query"]
    ANALYZE --> S_EMBED["Jina: embed refined_query"]
    S_EMBED --> S_SEARCH["ChromaDB: filtered search<br/>where = project, time<br/>fetch 3x candidates"]
    S_SEARCH --> FEW{"< 2 results?"}
    FEW -->|yes| RETRY["Retry without filters"]
    FEW -->|no| AGG
    RETRY --> AGG["Groq: aggregate_to_mbel<br/>→ compressed MBEL block"]
    AGG --> S_RESULT["RecallResult + MBEL"]
```

## Dream Cycle

Simula il consolidamento della memoria: rinforza i ricordi forti, decadono gli altri.

```mermaid
flowchart LR
    ALL["get_all_metadata"] --> SEED["Find highest-energy<br/>memory = seed"]
    SEED --> CLUSTER["Build cluster:<br/>energy ≥ seed × 0.8"]
    CLUSTER --> BOOST["Cluster:<br/>energy += 0.1<br/>max 1.0"]
    CLUSTER --> DECAY["Others:<br/>energy -= 0.03<br/>min 0.05"]
    BOOST --> SAVE["update_energy"]
    DECAY --> SAVE
    SAVE --> DONE["DreamResult"]
```

## Data Model

```mermaid
classDiagram
    class MemoryRecord {
        +str id
        +str session_id
        +float timestamp
        +int turn_number
        +str question
        +str answer_preview
        +str document
        +str project
        +str topic
        +Activity activity
        +MemoryType memory_type
        +float energy
        +str model
        +str source
        +list tools_used
    }

    class Activity {
        <<enum>>
        bugfix
        feature
        debug
        config
        deploy
        research
        discussion
        learning
        identity
        behavior
        growth
    }

    class MemoryType {
        <<enum>>
        episodic
        semantic
        procedural
        emotional
        relational
        tension
    }

    MemoryRecord --> Activity
    MemoryRecord --> MemoryType
```

## Port Allocation

| Port | Service | Status |
|------|---------|--------|
| 5070 | neo-reloaded (dotnet, SignalR) | active |
| 5071 | neo-mcp (Python MCP, primary) | active |
| 5072 | neo-mcp #2 (old) | decommission |
| 5073 | neo-mcp #3 (old) | decommission |
| **5074** | **neo-cortex (THIS)** | **active** |

## File Structure

| File | LOC | Role |
|------|-----|------|
| `models.py` | ~80 | Pydantic v2 typed records + enums |
| `config.py` | ~30 | API keys, paths, ports |
| `store.py` | ~160 | ChromaDB wrapper, CRUD |
| `embedder.py` | ~45 | Jina v3 async httpx |
| `classifier.py` | ~140 | Groq LLM (4 methods) |
| `cortex.py` | ~175 | Orchestrator |
| `server.py` | ~90 | FastAPI endpoints |
| **Total** | **~720** | |

## Tests: 54 GREEN

| Test File | Tests | Approach |
|-----------|-------|----------|
| `test_store.py` | 11 | Real ChromaDB, tmp dir |
| `test_embedder.py` | 6 | Mocked HTTP |
| `test_classifier.py` | 14 | Mocked HTTP + fallbacks |
| `test_cortex.py` | 14 | Real ChromaDB + mocked HTTP |
| `test_server.py` | 9 | TestClient + injected cortex |
