← Back to 20250617

06 THREE TIER

Documentation for 06_THREE_TIER from the Ds ex repository.

Excellent question for clarification. This is where the strategic view becomes absolutely critical. Let me clear up the confusion and propose a concrete, powerful relationship between these three projects.

You are right to seek clarity. The way you structure the relationship between ElixirScope, DSPEx, and Foundation will determine the success and maintainability of your entire ecosystem.

Based on your project descriptions, here is the most logical and powerful relationship:

ElixirScope is the Application. DSPEx is a core Engine within that Application. Foundation is the Platform on which the Application runs.

Let’s break this down visually and conceptually.

The Three-Tier Architecture

Think of it as a three-tier stack. Each layer has a distinct purpose and depends on the layer below it.

graph TD subgraph "Your End-User Product" A[ElixirScope Application] end subgraph "Your Core Logic Libraries" B[DSPEx Engine] C[Other ElixirScope Engines
(AST, Graph, CPG, etc.)] end subgraph "Your Platform Library" D[Foundation Platform] end A --> B A --> C B --> D C --> D style A fill:#cce5ff,stroke:#333,stroke-width:2px style B fill:#d4edda,stroke:#333,stroke-width:2px style C fill:#f8d7da,stroke:#333,stroke-width:2px style D fill:#fff3cd,stroke:#333,stroke-width:2px

Let’s detail what each layer means in practice:


1. Foundation (The Platform)

  • Purpose: To provide robust, generic, and AI-aware infrastructure services for building high-level Elixir applications. It is your internal “Heroku” or “AWS” for the BEAM.
  • Key Identity: It knows nothing about ElixirScope or DSPEx specifically. It only knows about general application patterns and, as per our last discussion, specialized AI application patterns.
  • Core Modules (after refactoring):
    • Foundation.AppConfig: Manages application configuration.
    • Foundation.AI.Client: Handles resilient LLM API calls (circuit breakers, caching).
    • Foundation.AI.Observability: Provides domain-specific telemetry (track_llm_call, etc.).
    • Foundation.Schema: The Ecto-based “Exdantic” for structured data.
    • Foundation.EventStore, Foundation.ProcessRegistry, etc.
  • Dependency: It has zero dependencies on DSPEx or ElixirScope. It should be publishable to Hex as a standalone, powerful toolkit.

2. DSPEx (The Engine)

  • Purpose: To be the Elixir implementation of the DSPy methodology. It is a library for building, optimizing, and composing programs that are powered by LLMs. It is the heart of ElixirScope’s “Intelligence Layer”.
  • Key Identity: It knows nothing about ElixirScope. It is a general-purpose library for AI programming. However, it is built on top of Foundation. It expects the services that Foundation provides to be available.
  • Dependency: DSPEx depends on Foundation. Its mix.exs would contain {:foundation, "~> 0.2.0"} (assuming a new version after refactoring).
  • How it uses Foundation:
    • Instead of implementing its own ClientManager, DSPEx.Predict directly calls Foundation.AI.Client.request(...).
    • DSPEx.TelemetrySetup is removed. Telemetry calls are made directly to Foundation.AI.Observability.track....
    • The use DSPEx.Signature macro might internally call use Foundation.Schema to get structured data capabilities.

By doing this, DSPEx becomes much leaner. It focuses purely on the logic of Predict, ChainOfThought, BEACON, SIMBA, etc., while offloading all the complex infrastructure concerns to Foundation.


3. ElixirScope (The Application)

  • Purpose: To be the end-user product. It is a highly specialized application for AST-based debugging and code intelligence. It is the consumer of both the DSPEx engine and the other ElixirScope engines (AST, Graph, CPG).
  • Key Identity: It knows everything about its own domain. It composes the various engines to deliver features to the user.
  • Dependency: ElixirScope depends on both DSPEx and Foundation. Its mix.exs would contain {:dspex, "~> 0.1.0"} and {:foundation, "~> 0.2.0"}.
  • How it uses DSPEx:
    • The ElixirScope.Intelligence.InsightGenerator module might define a DSPEx program:
      defmodule ElixirScope.Intelligence.RefactoringSignature do
          # This uses the new Foundation.Schema under the hood via DSPEx!
          use DSPEx.Signature, "code_snippet:string, anti_pattern:string -> suggestion:string"
      end
      
      def generate_suggestion(snippet, pattern) do
          # DSPEx provides the engine for the AI call
          program = DSPEx.Predict.new(RefactoringSignature)
          DSPEx.Program.forward(program, %{code_snippet: snippet, anti_pattern: pattern})
      end
      
    • ElixirScope.Debugger might use a DSPEx teleprompter to optimize its AI-powered suggestions over time based on user feedback.

Yes, but in a clean, hierarchical way. ElixirScope is a user of DSPEx. DSPEx is a powerful engine that ElixirScope leverages for its AI features.

Think of another analogy:

  • PostgreSQL is the Platform (like Foundation).
  • Ecto is the Engine/Library for database access (like DSPEx).
  • MyWebApp is the Application that uses Ecto to talk to Postgres (like ElixirScope).

MyWebApp and Ecto are related, but Ecto doesn’t know or care that MyWebApp exists. It just provides a general-purpose service.

The Actionable Plan

  1. Refactor Foundation First: Focus on building out the Foundation.AI.* modules and Foundation.Schema. This is your base. Make it powerful and standalone. This library provides the runtime.
  2. Refactor DSPEx Next: Rip out the fragile, custom-built infrastructure code (ClientManager, the complex TelemetrySetup, etc.). Replace it with clean, direct calls to the new, robust Foundation services. DSPEx becomes the AI programming model.
  3. Build ElixirScope Last: With a solid platform and a powerful AI engine, you can now build the ElixirScope application layers on top. ElixirScope focuses on its unique business logic (AST, CPG, Debugging) and uses DSPEx whenever it needs to “talk to an LLM.”

This layered approach gives you the best of all worlds:

  • Clear Separation of Concerns: Each library has a single, well-defined responsibility.
  • High Reusability: You could, in theory, use DSPEx to build a completely different AI application, as long as you also include its Foundation dependency.
  • Maintainability: When you need to improve circuit breaking, you work on Foundation. When you want to improve the BEACON algorithm, you work on DSPEx. When you want to add a new debugging feature, you work on ElixirScope.

You are not building one giant monolith. You are building a small ecosystem of three interconnected but cleanly separated projects. This is a very strong and scalable architecture.