This is a very naive and beginner way to just get the thing done in the most easy and raw way possible, I won’t be using any specific library or complex code for this project, this is just an exploration code.

Ok, so I am a beginner coder, currently in my sophomore year of college, and recently I got super obsessed with running local AI models on my laptop using Ollama.

But there is a huge, annoying problem with local LLMs: They are basically goldfish.

Every time you restart your python script, the AI forgets who you are, what you like, and what you talked about yesterday. I wanted to code a simple, human-like memory for my AI from scratch.

I started with a really basic idea, hit a bunch of walls, and finally built something that actually works like a human brain. Here is my exact thinking process, all the logic explained simply, and the raw Python code to do it yourself.


The Brainstorming & Fixing My Dumb Logic

Alright, so let’s begin with the thinking. My very first draft was simple: Just maintain a JSON file, dump all the chat history in it, and send the whole file to the AI every time I type a message.

Q: Wait, that sounds easy! Why is that a bad idea? A: Because of the Token Limit (Context Window). Imagine the AI’s brain has a tiny RAM size of 4,000 words. If I keep shoving our entire 6-month chat history into every single prompt, the AI will crash or completely forget the actual question I just asked.

Q: Okay, so we can’t save the whole chat. What if we divide it? Keep old chats in a folder, and only give the AI the current chat? A: Better! But what if I ask, “Hey, what was that movie I told you I liked last week?” If the AI only has the current chat in its RAM, it can’t answer.

Q: So how do human brains do it? A: Exactly! Humans don’t remember every single word of a conversation. We remember Facts, Intents, and Emotions. If I tell you, “I went to the park yesterday and I was looking at a golden retriever and suddenly some stupid just entered the park with his motor bike and almost hit me, I got startled and jumped in the water” you don’t memorize the sentence. Your brain just extracts: [friend jumped in pool when a bike came unexpectedly to hit him in the park yesterday].

We also forget things over time to keep our brains fast and clutter-free.

So, my final logic for the JSON file was just a list of extracted Facts with a Strength Score.


The Raw Code & Core Logic

Let’s build the basic engine…

First, let’s setup our brain.json structure. It looks like this:

{
  "short_term": [],
  "long_term": [
    {
      "memory": "Eshan loves coding in Python",
      "strength": 10,
      "last_mentioned": "2024-10-25"
    }
  ]
}

Now, let’s write the code to talk to Ollama and inject only the relevant memories.

import json
import requests
from datetime import datetime
import os

BASE_DIR = os.path.dirname(os.path.abspath(__file__))
BRAIN_FILE = os.path.join(BASE_DIR, 'brain.json')


def load_brain():
    try:
        with open(BRAIN_FILE, 'r') as f:
            return json.load(f)
    except FileNotFoundError:
        return {"short_term": [], "long_term": []}


def save_brain(brain_data):
    with open(BRAIN_FILE, 'w') as f:
        json.dump(brain_data, f, indent=4)


def ask_ollama(prompt, system_prompt="You are a helpful AI."):
    url = "http://localhost:11434/api/generate"
    payload = {
        "model": "gemma2:2b",
        "prompt": prompt,
        "system": system_prompt,
        "stream": False
    }
    response = requests.post(url, json=payload)
    return response.json()['response']


def chat_with_ai(user_input):
    brain = load_brain()

    # --- Build context from long term memory ---
    # Just grab all memories and pass them so AI knows who user is
    long_term_text = ""
    if brain["long_term"]:
        long_term_text = "What you remember about this person:\n"
        for m in brain["long_term"]:
            long_term_text += f"- {m['memory']}\n"

    # --- Build context from short term (current session conversation) ---
    # This is so AI remembers what was JUST said in this conversation
    short_term_text = ""
    for turn in brain["short_term"]:
        short_term_text += f"User: {turn['user']}\nAI: {turn['ai']}\n"

    system_prompt = f"""You are a personal AI assistant who remembers the user.

{long_term_text}

Conversation so far today:
{short_term_text}"""

    # Get AI response
    ai_response = ask_ollama(user_input, system_prompt)

    # Save this turn to short term
    brain["short_term"].append({
        "user": user_input,
        "ai": ai_response
    })

    save_brain(brain)
    print("AI:", ai_response)

Q: Wait, where does the long_term list come from? How does the AI extract the facts? A: I’m so glad you asked. That brings us to the next level.


The “Sleep Cycle” & Forgetting Curve

If we force the AI to extract facts while we are chatting, the chat will lag. It will take 10 seconds to reply.

Q: So when does it learn? A: When it sleeps! Or, in computer terms, when we stop typing.

I wrote a background function called consolidate_memory(). You run this function when the chat session ends (like when the user types “bye”). It takes the short_term buffer, asks Ollama to extract the hard facts, moves them to long_term, and clears the buffer.

def consolidate_memory():
    brain = load_brain()

    if len(brain["short_term"]) == 0:
        print("Nothing to remember. Goodnight!")
        return

    print("Processing memories...")
    today = str(datetime.now().date())

    for turn in brain["short_term"]:
        user_message = turn["user"]

        # IMPROVEMENT 1: Added explicit instructions to ignore questions
        prompt = f"""Extract facts about the user from this message.
Rules:
1. If the message is a question, contains no facts, or is conversational filler, return: NOTHING
2. Only extract stated personal facts (hobbies, preferences, name, job, etc).
3. Do not output sentences, just raw facts joined by |||.

Message: "{user_message}"
Output:"""

        result = ask_ollama(prompt, "You are a data extractor. Return 'NOTHING' for questions or filler.")
        result = result.strip()

        if not result or result.upper() == "NOTHING" or len(result) < 5:
            continue

        facts = [f.strip() for f in result.split("|||") if len(f.strip()) > 5]

        for fact in facts:
            # IMPROVEMENT 2: Check for duplicates to increase strength
            found_existing = False
            for existing in brain["long_term"]:
                # Logic for overlap detection
                existing_words = set(existing["memory"].lower().split())
                new_words = set(fact.lower().split())
                overlap = len(existing_words & new_words)

                # If they are very similar (more than 60% overlap)
                if overlap / max(len(new_words), 1) > 0.6:
                    existing["strength"] += 2
                    print(f"  Strengthened: {existing['memory']} (Strength: {existing['strength']})")
                    found_existing = True
                    break

            # IMPROVEMENT 3: Only add new if it wasn't found
            if not found_existing:
                brain["long_term"].append(
                    {"memory": fact, "last_mentioned": today, "strength": 10}
                )
                print(f"  New memory saved: {fact}")

    brain["short_term"] = []
    save_brain(brain)
    print("Done! Goodnight!")

Q: That’s so cool! But wait, you said human memory forgets stuff to keep the brain fast. How does the AI forget? A: Good catch! That’s exactly why we added that "strength": 10 variable in the JSON. Right now, our code only adds memories. If we don’t delete the useless ones, our JSON file will explode, and the token limit will crash again.

Here is the raw logic for forgetting: Every time you run the python script, a small function checks the dates. For every day that passes, the memory loses 1 strength point. If the strength hits 0, it vanishes (or gets moved to a cold_storage.json just in case we ever want to read old logs).

But, if you mention the memory again during a chat, remember in Level 2 we wrote item["strength"] += 2? That pushes the memory back up! Just like real life: if you don’t play guitar for a year, you forget it. If you practice every day, the memory stays strong.

Let’s write that quick forgetting function:

def clean_up_memories():
    """Prunes memories based on strength decay over time."""
    brain = load_brain()
    today = datetime.now().date()
    surviving_memories = []

    for item in brain["long_term"]:
        # Ensure last_mentioned exists, fallback to today if missing
        last_date_str = item.get("last_mentioned", str(today))
        last_date = datetime.strptime(last_date_str, "%Y-%m-%d").date()
        days_passed = (today - last_date).days

        # Reduce strength by days passed
        current_strength = item["strength"] - days_passed

        if current_strength > 0:
            item["strength"] = current_strength
            item["last_mentioned"] = str(today)
            surviving_memories.append(item)
        else:
            print(f"  Memory faded away: {item['memory']}")

    brain["long_term"] = surviving_memories
    save_brain(brain)
    print("  Memory cleanup complete.")

Touching Perfection (And The Future)

Q: Okay, so this is perfect now? A: Well, it’s perfect for a beginner project, but there is one final hurdle if you use this for years.

Right now, my logic is super raw: I am just dumping the entire long_term list into every prompt. As the list grows, we’ll hit the token limit again!

To fix that, you’d eventually need to write a search function to only grab relevant memories (like if word in user_input:). But basic keyword searching is flawed. If I type “I love dogs,” a keyword search looks for the exact word “dogs.” What if I type “I love puppies”? The code won’t find the “dogs” memory. Humans don’t work like that. We understand vibes and context, not just exact words.

The Level-Up: Vector Databases (ChromaDB) To make this 100% perfect, you would replace the JSON search with something called a Vector Database (like ChromaDB). I won’t code it here to keep things simple, but basically, ChromaDB turns words into numbers. So “Dog” and “Puppy” are stored right next to each other mathematically.

If you use ChromaDB, you don’t search by words, you search by meaning. That’s how ChatGPT’s actual memory works.

Final Thoughts

This whole project started because I wanted my AI to feel a little more human. I wanted it to say, “Hey Sam, how was your Python exam yesterday?” without me having to remind it that I even had an exam.

By just using a few basic lists, a JSON file, and some clever background prompts, we built a digital brain. It has a short-term memory (active chat), a sleep cycle (extraction), and a forgetting curve (strength decay).

The best part? It runs completely offline on your own laptop with Ollama. No subscriptions, no data stealing, just you and your code.

If you want to try this, copy the functions above, put them in a main.py file, loop an input() for the chat, and let me know on my GitHub what the first thing your AI remembered about you was!

Peace out, keep coding. ✌️

Here is the complete JSON-based code so far.


The Complete JSON Memory Script (Version 1.0)

If you just want the raw, working code we’ve built so far using just JSON and Python, here is the entire script. Put this in a file called main.py, make sure Ollama is running in the background, and run it!

import json
import requests
from datetime import datetime
import os

# --- Configuration ---
BASE_DIR = os.path.dirname(os.path.abspath(__file__))
BRAIN_FILE = os.path.join(BASE_DIR, 'brain.json')


# --- Memory File Management ---
def load_brain():
    try:
        with open(BRAIN_FILE, 'r') as f:
            return json.load(f)
    except FileNotFoundError:
        # Automatically creates the corrrect structure if file doesn't exist
        return {"short_term": [], "long_term":[]}


def save_brain(brain_data):
    with open(BRAIN_FILE, 'w') as f:
        json.dump(brain_data, f, indent=4)


# --- Core AI Communication ---
def ask_ollama(prompt, system_prompt="You are a helpful AI."):
    url = "http://localhost:11434/api/generate"
    payload = {
        "model": "gemma2:2b", # Make sure you have this model pulled in Ollama!
        "prompt": prompt,
        "system": system_prompt,
        "stream": False
    }
    try:
        response = requests.post(url, json=payload)
        return response.json()['response']
    except requests.exceptions.ConnectionError:
        return "Error: Could not connect to Ollama. Is it running?"


# --- Chat Logic ---
def chat_with_ai(user_input):
    brain = load_brain()

    # --- Build context from long term memory ---
    long_term_text = ""
    if brain["long_term"]:
        long_term_text = "What you remember about this person:\n"
        for m in brain["long_term"]:
            long_term_text += f"- {m['memory']}\n"

    # --- Build context from short term (current session conversation) ---
    short_term_text = ""
    for turn in brain["short_term"]:
        short_term_text += f"User: {turn['user']}\nAI: {turn['ai']}\n"

    system_prompt = f"""You are a personal AI assistant who remembers the user.

{long_term_text}

Conversation so far today:
{short_term_text}"""

    # Get AI response
    ai_response = ask_ollama(user_input, system_prompt)

    # Save this turn to short term buffer
    brain["short_term"].append({
        "user": user_input,
        "ai": ai_response
    })

    save_brain(brain)
    print("\nAI:", ai_response)


# --- Sleep Cycle: Memory Consolidation ---
def consolidate_memory():
    brain = load_brain()

    if len(brain["short_term"]) == 0:
        print("Nothing to remember. Goodnight!")
        return

    print("\nProcessing memories...")
    today = str(datetime.now().date())

    for turn in brain["short_term"]:
        user_message = turn["user"]

        prompt = f"""Extract facts about the user from this message.
Rules:
1. If the message is a question, contains no facts, or is conversational filler, return: NOTHING
2. Only extract stated personal facts (hobbies, preferences, name, job, etc).
3. Do not output sentences, just raw facts joined by |||.

Message: "{user_message}"
Output:"""

        result = ask_ollama(prompt, "You are a data extractor. Return 'NOTHING' for questions or filler.")
        result = result.strip()

        if not result or result.upper() == "NOTHING" or len(result) < 5:
            continue

        facts =[f.strip() for f in result.split("|||") if len(f.strip()) > 5]

        for fact in facts:
            found_existing = False
            for existing in brain["long_term"]:
                # Logic for overlap detection
                existing_words = set(existing["memory"].lower().split())
                new_words = set(fact.lower().split())
                overlap = len(existing_words & new_words)

                # If they are very similar (more than 60% overlap)
                if overlap / max(len(new_words), 1) > 0.6:
                    existing["strength"] += 2
                    print(f"  Strengthened: {existing['memory']} (Strength: {existing['strength']})")
                    found_existing = True
                    break

            # Add new memory if it wasn't found (Using the 'last_mentioned' fix)
            if not found_existing:
                brain["long_term"].append(
                    {"memory": fact, "last_mentioned": today, "strength": 10}
                )
                print(f"  New memory saved: {fact}")

    # Clear the buffer
    brain["short_term"] =[]
    save_brain(brain)
    print("Done! Goodnight!")


# --- Forgetting Curve: Memory Cleanup ---
def clean_up_memories():
    """Prunes memories based on strength decay over time."""
    brain = load_brain()
    today = datetime.now().date()
    surviving_memories = []

    for item in brain["long_term"]:
        last_date_str = item.get("last_mentioned", str(today))
        last_date = datetime.strptime(last_date_str, "%Y-%m-%d").date()
        days_passed = (today - last_date).days

        # Reduce strength by days passed
        current_strength = item["strength"] - days_passed

        if current_strength > 0:
            item["strength"] = current_strength
            item["last_mentioned"] = str(today)
            surviving_memories.append(item)
        else:
            print(f"  Memory faded away: {item['memory']}")

    brain["long_term"] = surviving_memories
    save_brain(brain)
    print("Memory cleanup complete.")


# --- Main Application Loop ---
def main():
    print("--- Waking up AI ---")
    clean_up_memories()
    print("AI is ready! (Type 'bye' to sleep and save memoriies)\n")

    while True:
        user_input = input("You: ")

        if user_input.lower() in ["bye", "exit", "quit"]:
            print("\nAI: Goodbye! Going to sleep now...")
            consolidate_memory()
            break

        chat_with_ai(user_input)

if __name__ == "__main__":
    main()