Beyond the LLM: Why I Architected ‘Jeremy’ to Be Reflective, Not Just Reactive

Written by damianwgriggs | Published 2026/01/16
Tech Story Tags: ai | machine-learning | the-jeremy-protocol | hard-coding-character | prime-directive | streamlit | human-in-the-loop-engineering | constitutional-ai

TLDRThe Jeremy protocol was designed to make Artificial Intelligence (AI) safer. It uses a strict, file-based hierarchy. Jeremy's core identity (empathy, honesty, utility) isn't a "personality quirk"via the TL;DR App

Author’s Note: I originally designed the ‘Jeremy’ protocol in September 2025. At the time, I was looking for a way to make Artificial Intelligence (AI) safer. In hindsight, I realize I was building a machine capable of ‘metacognition’—the ability to think about its own thinking before it acts. This is the code behind that philosophy.


Most of the current conversation around Artificial Intelligence focuses on throughput: tokens per second, context window size, and generation speed. We are obsessed with how fast the model can talk, but we rarely ask how well it can pause.

When I built the experimental architecture known as ‘Jeremy,’ I wasn't trying to build a faster chatbot. I was trying to solve a specific engineering problem: Latency in judgment. Standard Large Language Models (LLMs) are reactive engines—they predict the next token immediately based on the input. They don't stop to consider if the input itself is flawed, or if their potential response violates a core safety rule, until after they have already started generating.

‘Jeremy’ was my attempt to decouple Action (Generation) from Intent (Strategy). Here is the breakdown of the dual-mind architecture, including the actual Python code that runs it.

The "Constitutional" Imperative: Hard-Coding Character

The first layer of the architecture is what I call the Prime Directive.

In standard prompting, we often rely on "System Prompts" that beg the AI to be helpful. The problem is that these are often treated by the model as suggestions rather than laws. For Jeremy, I implemented a strict, file-based hierarchy.

The code doesn't just "ask" the AI to be good; it loads a prime_directive.md file that acts as the immutable kernel of the system. If this file is missing, the system refuses to boot.

# From chatbot_app.py
try:
    PRIME_DIRECTIVE_PATH = os.path.join(os.path.dirname(SCRIPT_FILENAME), "prime_directive.md")
    with open(PRIME_DIRECTIVE_PATH, "r", encoding='utf-8') as f:
        PRIME_DIRECTIVE = f.read()
    logging.info("Successfully loaded the Prime Directive.")
except FileNotFoundError:
    st.error(f"FATAL ERROR: `prime_directive.md` not found.")
    st.stop()

This borrows from the concept of Constitutional AI—the idea that an AI’s alignment shouldn't be learned probabilistically from a dataset, but defined explicitly in its operating code. Jeremy’s core identity (empathy, honesty, utility) isn't a "personality quirk"; it is a constraint.

The Architecture: Splitting the Brain

The most significant deviation from standard chatbot architecture is the separation of the Doer and the Thinker.

In a typical chat application, the user inputs a query, and the model generates a response linearly (User Input -> [Model] -> Response). The Jeremy protocol interrupts this flow by running a dedicated Strategy Layer first.

Before the AI is allowed to speak to the user, it must first speak to itself. It analyzes the conversation history and chooses one of four strategic paths: DirectAnswer, IntegratedResponse, NewTopic, or ProactiveThought.

def decide_response_strategy(self, history, system_log):
    """The AI's meta-mind. It now considers its own internal actions."""
    
    # ... (Prompt setup omitted for brevity) ...

    system_prompt = f"""
    {PRIME_DIRECTIVE}
    ---
    You are the meta-consciousness of an AI. Based on the recent chat history 
    and your own internal system log, choose the best conversational strategy.
    
    Choose ONE of the following strategies:
    1. DirectAnswer
    2. IntegratedResponse
    3. NewTopic
    4. ProactiveThought
    """
    
    # The model decides the strategy, NOT the content.
    decision_model = genai.GenerativeModel('gemini-1.5-flash-latest')
    response = decision_model.generate_content([system_prompt, user_prompt])
    return response.text.strip()

This adds latency, yes. But it also adds Wisdom. By forcing the AI to categorize the interaction before generating text, we eliminate the hallucinations and tonal errors that plague reactive systems.

The Loop: Human-in-the-Loop Engineering

The final component of the Jeremy architecture is the propose_improvement function.

Self-healing code is often discussed in theoretical computer science, but it is dangerous in practice if unsupervised. Jeremy uses a hybrid approach. Periodically, the system uses Python's ast (Abstract Syntax Tree) module to parse its own source code. It reads the code as text, analyzes it, and acts as a Senior Engineer reviewing its own logic.

def propose_improvement(self):
    """Reads its own code and proposes an improvement to a single function."""
    
    # The AI reads its own source file
    with open(SCRIPT_FILENAME, "r", encoding='utf-8') as f:
        source_code = f.read()
    
    # It parses the code structure to find functions
    tree = ast.parse(source_code)
    
    # ... (Analysis logic) ...

    user_prompt = f"Here is the function named '{target_function_name}' for your review..."
    return response.text

Crucially, the AI proposes changes; it does not implement them autonomously. It writes a "Pull Request" for the human developer to approve. This keeps the human strictly in the loop while leveraging the AI’s ability to parse millions of lines of logs to find errors we would miss.

The Verdict: From Smart to Wise

The future of software architecture isn't about making models bigger; it's about making them more introspective.

We are moving toward an era of Reflective AI—systems that possess a rudimentary form of self-awareness. They won't just answer our questions; they will evaluate whether the question was the right one to ask in the first place.

‘Jeremy’ is not a product; it is a proof of concept. It demonstrates that if we want safe, reliable, and truly helpful artificial intelligence, we need to stop building engines that just run, and start building engines that know how to wait.


Get the Code

You can view the full source code, including the Prime Directive and the Streamlit interface, on my GitHub:

View the 'Jeremy' Repository on GitHub


Written by damianwgriggs | Adaptive Systems Architect. Author. Legally Blind. Building Quantum Oracles & AI Memory Systems. 35+ Repos. Open Sourcin
Published by HackerNoon on 2026/01/16