Sadiq Jaffer's blog

Posted Fri 27 June 2025

Letting Claude Code check with Gemini

gemini-cli was released a few days ago with a very ample free tier that gives access to Gemini 2.5 Pro, a model with a million token context window. I'm already a user of Claude Code so I wondered if I could have the two talk to each other. Enter check-with-gemini which is a simple mcp server and lets Claude Code call Gemini to help analyse codebases or check plans.

The MCP server has a single tool check_with_gemini which takes a prompt and content. Here's some examples of it in use.

Examples

I asked Claude Code to explain a codebase to me without Gemini:

> Analyse this codebase in depth. Produce a short two paragraph summary for a potential new contributor.

 I'll analyze this codebase to understand its structure and purpose, then provide a summary for potential contributors.

 Task(Analyze codebase structure)
    Done (10 tool uses · 44.6k tokens · 1m 28.6s)                                                                                                                                                                  

 This codebase is an AI Pipeline Visualization project that creates an interactive 3D visualization of academic papers and their hierarchical clustering relationships. Built with C++20 and OpenGL 4.1, it renders
   thousands of papers as animated points in 3D space, grouped into transparent convex hull clusters representing semantic topics. The system loads paper data from CSV files containing titles, coordinates, and
  cluster assignments at multiple hierarchical depths (4-64 clusters), then provides real-time animation showing paper exploration progress with interactive camera controls and dynamic statistics.

  For contributors, the project follows a clean architecture with clear separation of concerns: PaperLoader handles data parsing, ClusterRenderer manages 3D visualization, and the OpenGL framework provides
  efficient instanced rendering. The build system uses CMake with dependencies on GLFW3, GLM, FreeType2, and Assimp. Key areas for contribution include improving Windows platform support (currently incomplete),
  optimizing rendering performance for larger datasets, extending the UI with additional visualization modes, or enhancing the clustering algorithms. The codebase is well-structured with logical file organization
   under src/ for core components and data/ for assets, making it approachable for developers familiar with modern C++ and OpenGL programming.

Now with check_with_gemini:

> Analyse this codebase in depth. Check with Gemini that your understanding is correct. Produce a short two paragraph summary for a potential new contributor.

 I'll analyze this codebase in depth and verify my understanding with Gemini before providing a summary for potential contributors.

 Update Todos
     Explore project structure and identify main components
      Analyze build system (CMakeLists.txt)
      Examine main.cpp and core functionality
      Check with Gemini for understanding verification
      Write contributor summary
      Review recent commits for project direction

 Update Todos
     Explore project structure and identify main components
      Analyze build system (CMakeLists.txt)
      Examine main.cpp and core functionality
      Check with Gemini for understanding verification
      Write contributor summary
      Review recent commits for project direction

 List(.)
    Listed 1119 paths (ctrl+r to expand)

 Search(pattern: "**/*")
    Found 100 files (ctrl+r to expand)

 Read(README.md)
    Read 65 lines (ctrl+r to expand)

 Update Todos
     Explore project structure and identify main components
      Analyze build system (CMakeLists.txt)
      Examine main.cpp and core functionality
      Check with Gemini for understanding verification
      Write contributor summary
      Review recent commits for project direction

 Read(CMakeLists.txt)
    Read 92 lines (ctrl+r to expand)

 Read(main.cpp)
    Read 557 lines (ctrl+r to expand)

 Read(csv_loader.cpp)
    Read 174 lines (ctrl+r to expand)

 Update Todos
     Explore project structure and identify main components
      Analyze build system (CMakeLists.txt)
      Examine main.cpp and core functionality
      Review recent commits for project direction
      Check with Gemini for understanding verification
      Write contributor summary

 Bash(git log --oneline -10)
    903a1c0 Start animation paused
     ab728d8 Reduce vignette
     59cb10e Update README.md
      +7 lines (ctrl+r to expand)

 Read(src/paper_loader.h)
    Read 122 lines (ctrl+r to expand)

 Read(src/clusters.h)
    Read 112 lines (ctrl+r to expand)

 Update Todos
     Explore project structure and identify main components
      Analyze build system (CMakeLists.txt)
      Examine main.cpp and core functionality
      Review recent commits for project direction
      Check with Gemini for understanding verification
      Write contributor summary

 check_with_gemini:check_with_gemini (MCP)(prompt: "Review this analysis of a C++ OpenGL visualization project for scientific papers. Is my understanding correct?\n\nThis is an AI Pipeline Visualization project
                                           that:\n1. Loads scientific paper data from CSV files containing paper titles, inclusion status, 2D/3D positions, and hierarchical cluster assignments (clusters at depths
                                            2-6)\n2. Visualizes papers as instanced 3D cubes using OpenGL with diffuse/ambient lighting\n3. Groups papers into hierarchical clusters represented by transparent
                                           convex hull models\n4. Provides interactive exploration with animation that progresses through papers chronologically\n5. Features include bar charts showing cluster
                                           distributions, viewing mode toggles, and animation speed controls\n6. Uses modern C++ (C++20), CMake build system, and libraries: GLFW3, GLAD, GLM, Assimp, FreeType2,
                                           and convhull_3d\n7. Recent development focused on UI improvements (vignette effects, post-processing) and documentation updates\n\nThe project appears designed for
                                           exploring relationships between scientific papers in a 3D space with hierarchical clustering visualization. Is this assessment accurate?", content: "Key code
                                           structure:\n- main.cpp: Core rendering loop, handles user input, manages animation state\n- paper_loader.h/cpp: Loads paper data from CSV, manages clustering
                                           hierarchy\n- clusters.h/cpp: Renders cluster convex hulls using Assimp-loaded models\n- opengl/: Contains shader management, mesh/model loading, camera, fonts, etc.\n-
                                           CMakeLists.txt: Linux-focused build (Windows build marked as faulty)\n- Data files: CSV with paper metadata, pre-generated cluster models (.obj), shaders, fonts,
                                           textures")
    Yes, your assessment is highly accurate. Based on the file structure and your description, this project is indeed a 3D visualization tool for exploring hierarchically clustered scientific paper data.

     Your breakdown of the components and their functions is spot on:
      +9 lines (ctrl+r to expand)

 Update Todos
     Explore project structure and identify main components
      Analyze build system (CMakeLists.txt)
      Examine main.cpp and core functionality
      Check with Gemini for understanding verification
      Review recent commits for project direction
      Write contributor summary

 This is an OpenGL-based 3D visualization tool for exploring hierarchically clustered scientific paper data from AI research pipelines. The project renders thousands of papers as colored cubes in 3D space, with
  their positions and cluster assignments derived from dimensionality reduction techniques. Papers are grouped into transparent convex hull clusters at multiple hierarchical levels (2-6), allowing researchers to
  explore relationships between papers through interactive navigation with real-time animation that progresses chronologically through the dataset.

  The codebase uses modern C++20 with a CMake build system targeting Linux (Windows support is incomplete). Core dependencies include GLFW3/GLAD for OpenGL context, GLM for 3D math, Assimp for loading cluster
  models, and FreeType2 for text rendering. The architecture cleanly separates concerns: data loading from CSV files, instanced rendering for performance, cluster hull generation/rendering, and UI overlays
  showing statistics like cluster distributions and exploration progress. Recent development has focused on post-processing effects and UI improvements to enhance the visual exploration experience.

 Update Todos
     Explore project structure and identify main components
      Analyze build system (CMakeLists.txt)
      Examine main.cpp and core functionality
      Check with Gemini for understanding verification
      Write contributor summary
      Review recent commits for project direction

We can also have Gemini do the initial work and have Claude Code check it:

> Have Gemini analyse this codebase in depth. Critically evaluate the resutls Gemini gives you and make sure they are correct. Produce a short two paragraph summary for a potential new contributor.

 I'll analyze this codebase using Gemini and provide a comprehensive summary for potential contributors.

 Update Todos
     Explore codebase structure and files             
      Have Gemini analyze the codebase in depth
      Critically evaluate Gemini's analysis
      Create two paragraph summary for new contributors

 Update Todos
     Explore codebase structure and files             
      Have Gemini analyze the codebase in depth
      Critically evaluate Gemini's analysis
      Create two paragraph summary for new contributors

 List(.)
    Listed 1119 paths (ctrl+r to expand)

 Read(CMakeLists.txt)
    Read 92 lines (ctrl+r to expand)

 Read(main.cpp)
    Read 557 lines (ctrl+r to expand)

 Search(pattern: "**/*.{cpp,h,hpp,c,txt,md,json}")
    Found 100 files (ctrl+r to expand)

 Update Todos
     Explore codebase structure and files             
      Have Gemini analyze the codebase in depth
      Critically evaluate Gemini's analysis
      Create two paragraph summary for new contributors

 Read(README.md)
    Read 65 lines (ctrl+r to expand)

 Task(Analyze source files structure)
    Done (15 tool uses · 50.0k tokens · 1m 6.4s)                                                                                                                                                                   

 Now I'll have Gemini analyze the codebase comprehensively:

 check_with_gemini:check_with_gemini (MCP)(prompt: "Please provide a comprehensive analysis of this codebase. This is a 3D visualization application for academic papers that uses OpenGL. I want you to analyze
                                           the code quality, architecture, potential issues, and provide insights about its design patterns and implementation approaches. Consider:\n\n1. Code organization and
                                           structure\n2. OpenGL and graphics programming best practices\n3. Memory management and resource handling\n4. Performance considerations\n5. Error handling and
                                           robustness\n6. Code maintainability and extensibility\n7. Any potential security or stability issues\n8. Overall software engineering quality\n\nBe thorough and critical
                                            in your analysis. Point out both strengths and weaknesses.", content: "This codebase is a 3D visualization application called \"AI Pipeline Visualisation\" that renders
                                            academic papers as cubes in 3D space, organized into clusters. Here's the key information:\n\n## Core Architecture:\n- Built with C++20, OpenGL 4.1, CMake build
                                           system\n- Uses GLFW for windowing, GLAD for OpenGL loading, GLM for math, Assimp for 3D models, FreeType for fonts\n- Main components: App (OpenGL wrapper), PaperLoader
                                           (data management), Clusters (3D cluster visualization), Shader management\n\n## Main Files Structure:\n- main.cpp: Main application loop with animation, rendering, and
                                           UI\n- src/opengl/app.cpp: Core OpenGL application framework\n- src/paper_loader.cpp: Loads papers from CSV, generates clusters\n- src/clusters.cpp: Generates and renders
                                            3D convex hulls for clusters\n- src/opengl/shader.cpp: Shader program management\n\n## Key Code Snippets:\n\n### main.cpp (main loop):\n```cpp\n// Main rendering loop
                                           with instanced paper rendering\nwhile (!app.shouldClose())\n{\n    app.handleInput();\n    app.enablePostProcessing();\n    app.clear();\n    \n    // Render papers as
                                           instanced cubes\n    pointShader.use();\n    pointShader.setMat4(\"projection\", app.getPerspectiveMatrix());\n    pointShader.setMat4(\"view\", app.getViewMatrix());\n
                                              glDrawArraysInstanced(GL_TRIANGLES, 0, 36, static_cast<int>(paperData.size() / 5));\n    \n    // Render transparent clusters with depth sorting\n    std::map<float,
                                           std::pair<int, glm::vec3>> sortedClusters{};\n    for (int c = 0; c < std::pow(2, CLUSTER_DEPTH); ++c) {\n        // Sort clusters by distance for proper transparency\n
                                                  distance = glm::length(app.getCameraPosition() - clusterData->position);\n        sortedClusters[distance] = std::make_pair(c, color);\n    }\n    \n    //
                                           Animation and UI updates\n    animationProgress += ANIMATION_SPEED * app.getDeltaTime();\n}\n```\n\n### src/opengl/app.cpp (OpenGL framework):\n```cpp\nclass App {\n
                                           GLFWwindow* window;\n    Camera camera;\n    PostProcessor* postProcessor;\n    \n    void init(int width, int height, const std::string& title) {\n        if
                                           (!glfwInit()) { /* error handling */ }\n        \n        glfwWindowHint(GLFW_CONTEXT_VERSION_MAJOR, 4);\n        glfwWindowHint(GLFW_CONTEXT_VERSION_MINOR, 1);\n
                                            glfwWindowHint(GLFW_OPENGL_PROFILE, GLFW_OPENGL_CORE_PROFILE);\n        \n        window = glfwCreateWindow(width, height, title.c_str(), nullptr, nullptr);\n        if
                                            (!gladLoadGLLoader((GLADloadproc)glfwGetProcAddress)) {\n            /* error handling */\n        }\n    }\n};\n```\n\n### src/paper_loader.cpp (data
                                           management):\n```cpp\nclass PaperLoader {\n    std::vector<Paper> papers;\n    std::map<int, std::map<int, Cluster>> clusters;\n    \n    void loadFromFile(const
                                           std::string& filename, float scale) {\n        // Parse CSV with wide string support for UTF-8\n        std::wifstream file(filename);\n
                                           file.imbue(std::locale(\"en_US.UTF-8\"));\n        \n        // Process each paper line\n        while (std::getline(file, line)) {\n            Paper paper;\n
                                             // Parse coordinates, title, inclusion status\n            paper.x = std::stof(fields[1]) * scale;\n            paper.y = std::stof(fields[2]) * scale;\n
                                           papers.push_back(paper);\n        }\n    }\n    \n    void generateClusters() {\n        // Generate hierarchical clusters (levels 2-6)\n        for (int level = 2;
                                           level <= 6; ++level) {\n            // Group papers into 2^level clusters\n            clusters[level] = generateClusterLevel(level);\n        }\n    }\n};\n```\n\n###
                                           src/clusters.cpp (3D cluster visualization):\n```cpp\nclass ClusterRenderer {\n    std::map<int, std::map<int, ClusterData>> clusterData;\n    \n    void
                                           generateClusters(const std::map<int, std::map<int, Cluster>>& clusters) {\n        for (const auto& [level, levelClusters] : clusters) {\n            for (const auto&
                                           [id, cluster] : levelClusters) {\n                // Generate convex hull from paper positions\n                ConvexHull hull = convhull_3d_build(cluster.vertices);\n
                                                          \n                // Export as .obj file\n                std::ofstream objFile(\"data/cluster_models/cluster_\" + \n
                                           std::to_string(level) + \"_\" + std::to_string(id) + \".obj\");\n                // Write vertices and faces\n            }\n        }\n    }\n    \n    void
                                           renderCluster(const Shader& shader, const glm::mat4& projection, \n                      const glm::mat4& view, const glm::vec3& color, int level, int id) {\n
                                           ClusterData* data = getClusterData(level, id);\n        shader.setVec3(\"color\", color);\n        shader.setMat4(\"model\", data->modelMatrix);\n
                                           glBindVertexArray(data->VAO);\n        glDrawElements(GL_TRIANGLES, data->indexCount, GL_UNSIGNED_INT, 0);\n    }\n};\n```\n\n### Shader
                                           examples:\n```glsl\n//points.vert - Instanced paper rendering\n#version 410 core\nlayout (location = 0) in vec3 aPos;\nlayout (location = 1) in vec3 aNormal;\nlayout
                                           (location = 2) in vec3 aOffset; // per-instance position\nlayout (location = 3) in float aIncluded; // per-instance inclusion flag\n\nuniform mat4 model, view,
                                           projection;\nout vec3 FragPos, Normal;\nout float Included;\n\nvoid main() {\n    vec3 worldPos = aPos + aOffset;\n    gl_Position = projection * view * model *
                                           vec4(worldPos, 1.0);\n    FragPos = worldPos;\n    Normal = aNormal;\n    Included = aIncluded;\n}\n\n//cluster.frag - Transparent cluster rendering\n#version 410
                                           core\nin vec3 FragPos, Normal;\nuniform vec3 color, CameraPos;\n\nvoid main() {\n    // Blinn-Phong lighting\n    vec3 lightDir = normalize(CameraPos - FragPos);\n
                                           float diff = max(dot(Normal, lightDir), 0.0);\n    vec3 result = (0.3 + 0.7 * diff) * color;\n    gl_FragColor = vec4(result, 0.3); // Semi-transparent\n}\n```\n\n##
                                           CMakeLists.txt build configuration:\n```cmake\nproject(main VERSION 0.2 DESCRIPTION \"AI Pipeline Visualisation\" LANGUAGES CXX)\nset(CMAKE_CXX_STANDARD 20)\n\n#
                                           Cross-platform library linking\nif (CMAKE_SYSTEM MATCHES Linux)\n    set(GL_LIBS GL GLU glfw3 assimp freetype)\n
                                           include_directories(${CMAKE_SOURCE_DIR}/include/linux)\nendif()\n\n# Copy assets and shaders to build directory\nadd_custom_target(copy_assets\n    COMMAND
                                           ${CMAKE_COMMAND} -E copy_directory ${CMAKE_CURRENT_LIST_DIR}/data ${CMAKE_CURRENT_BINARY_DIR}/data)\n```\n\nThe application loads academic papers from CSV, renders them
                                           as animated 3D cubes, groups them into hierarchical clusters with convex hull visualization, and provides interactive controls for exploration.")
    Error: Gemini request timed out after 30 seconds

 Let me try with a more concise analysis request:

 check_with_gemini:check_with_gemini (MCP)(prompt: "Analyze this 3D visualization codebase for code quality, architecture, and potential issues. Focus on OpenGL best practices, memory management, error handling,
                                            and overall software engineering quality. Provide both strengths and weaknesses.", content: "C++ OpenGL 4.1 academic paper visualization app with these key
                                           components:\n\n**Architecture:**\n- App class: OpenGL/GLFW wrapper, handles window, camera, rendering loop\n- PaperLoader: CSV data loading, cluster generation, UTF-8
                                           support  \n- ClusterRenderer: 3D convex hull generation/rendering for clusters\n- Shader management system\n\n**Key Code Patterns:**\n\nMain loop with instanced
                                           rendering:\n```cpp\nwhile (!app.shouldClose()) {\n    app.handleInput();\n    app.clear();\n    \n    // Instanced paper cubes\n    glDrawArraysInstanced(GL_TRIANGLES,
                                           0, 36, paperCount);\n    \n    // Transparent clusters with depth sorting\n    std::map<float, std::pair<int, glm::vec3>> sortedClusters;\n    for (clusters) {\n
                                           distance = glm::length(cameraPos - clusterPos);\n        sortedClusters[distance] = clusterData;\n    }\n    // Render back-to-front\n}\n```\n\nResource
                                           management:\n```cpp\nclass App {\n    GLFWwindow* window;\n    unsigned int framebuffer, colorTexture, depthTexture;\n    \n    ~App() {\n        glDeleteFramebuffers(1,
                                            &framebuffer);\n        glfwTerminate();\n    }\n};\n```\n\nData loading with wide strings:\n```cpp\nvoid PaperLoader::loadFromFile(const std::string& filename, float
                                           scale) {\n    std::wifstream file(filename);\n    file.imbue(std::locale(\"en_US.UTF-8\"));\n    // Parse CSV data, handle UTF-8 paper titles\n}\n```\n\nOpenGL state
                                           management:\n```cpp\nvoid App::enableDepthTesting() {\n    glEnable(GL_DEPTH_TEST);\n    glDepthFunc(GL_LESS);\n}\n\nvoid App::enableBlending() {\n
                                           glEnable(GL_BLEND);\n    glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);\n}\n```\n\n**Libraries:** GLFW, GLAD, GLM, Assimp, FreeType, ConvexHull3D\n**Features:**
                                           Instanced rendering, transparent clusters, post-processing, font rendering, CSV data loading, animation system")
   First, I'll conduct a comprehensive search of the codebase to identify all C++ and header files. This will give me a complete picture of the project's structure and all its components.Okay, that's a lot of fi
    les. Based on your description and the file list, I'll focus on the core application logic in the `src` directory and the root-level `.cpp` files. The `include` and `lib` directories appear to contain third-p
    arty libraries, so I'll exclude those from the primary analysis.
     +57 lines (ctrl+r to expand)



 Update Todos
     Explore codebase structure and files             
      Have Gemini analyze the codebase in depth
      Critically evaluate Gemini's analysis
      Create two paragraph summary for new contributors

 Let me critically evaluate Gemini's analysis by examining specific code examples to verify the claims:

 Read(src/opengl/app.h)
    Read 183 lines (ctrl+r to expand)

 Read(src/opengl/app.cpp)
    Read 100 lines (ctrl+r to expand)

 Search(pattern: "delete|new|malloc|free", include: "*.cpp")
    Found 8 files (ctrl+r to expand)

 Update Todos
     Explore codebase structure and files             
      Have Gemini analyze the codebase in depth
      Critically evaluate Gemini's analysis
      Create two paragraph summary for new contributors

 After critically evaluating Gemini's analysis against the actual codebase, I found it to be largely accurate and insightful. The analysis correctly identifies the use of raw pointers (_defaultShader and
  _postProcessor) in app.h:146 and app.h:151, the memory management issue in wstring2string (main.cpp:500-503), and the hardcoded paths throughout the codebase. The assessment of OpenGL best practices, instanced
  rendering usage, and transparency handling is also correct based on the code structure.

 Update Todos
     Explore codebase structure and files             
      Have Gemini analyze the codebase in depth
      Critically evaluate Gemini's analysis
      Create two paragraph summary for new contributors

 Summary for New Contributors

  This is a sophisticated 3D data visualization application built in C++20 with OpenGL 4.1 that renders academic papers as animated cubes in 3D space, organized into hierarchical clusters with convex hull
  visualizations. The codebase demonstrates solid software engineering practices with clear separation of concerns across its main components: the App class manages OpenGL context and rendering pipeline,
  PaperLoader handles CSV data ingestion with UTF-8 support and cluster generation, ClusterRenderer creates and renders 3D convex hulls using the ConvexHull3D library, and a comprehensive shader management
  system. The application uses modern OpenGL techniques including instanced rendering for performance, proper transparency handling with depth sorting, and post-processing effects, while supporting real-time
  animation controls and interactive 3D navigation.

  The architecture is well-organized with appropriate use of modern C++ features, RAII principles for resource management, and established graphics programming patterns, though it has some areas for improvement
  including inconsistent error handling, occasional use of raw pointers instead of smart pointers, and hardcoded configuration values. New contributors should be comfortable with OpenGL/graphics programming
  concepts, understand 3D mathematics (GLM library), and be familiar with build systems like CMake. The codebase includes comprehensive asset handling (3D models, shaders, fonts, textures), supports
  cross-platform development (Linux focus with Windows compatibility), and implements a complete data pipeline from CSV loading through hierarchical clustering to real-time 3D visualization with interactive
  controls for exploring academic paper datasets.

As you can see one of the downsides is that some of the calls to check_with_gemini take longer than 30 seconds and so timeout.