You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@resilientdb.apache.org by ha...@apache.org on 2026/01/05 02:59:53 UTC

(incubator-resilientdb) branch demo created (now e25688b6)

This is an automated email from the ASF dual-hosted git repository.

harishgokul01 pushed a change to branch demo
in repository https://gitbox.apache.org/repos/asf/incubator-resilientdb.git


      at e25688b6 reverting view change bug fixes and removing reslens-tools-service

This branch includes the following new commits:

     new bdd30c87 Added AI Tools (Beacon and Nexus), Licenses, Beacon workflow (#211)
     new 922d79df renaming tools folder
     new 81148929 Add .env to .gitignore, enable global stats increment in PBFT commitment, update response handling in Stats, and introduce ResLens Flamegraph Analysis Service with Gunicorn configuration and startup scripts.
     new 5f13dd20 view change deadlock bug - temporary hotfix
     new 6fb02357 Implement transaction retrieval with sequence number, integrate LevelDB for summary storage, and update server configuration settings.
     new e25688b6 reverting view change bug fixes and removing reslens-tools-service

The 6 revisions listed above as "new" are entirely new to this
repository and will be described in separate emails.  The revisions
listed as "add" were already present in the repository and have only
been added to this reference.



(incubator-resilientdb) 04/06: view change deadlock bug - temporary hotfix

Posted by ha...@apache.org.
This is an automated email from the ASF dual-hosted git repository.

harishgokul01 pushed a commit to branch demo
in repository https://gitbox.apache.org/repos/asf/incubator-resilientdb.git

commit 5f13dd200fcd2f976aa3b48211df2dee3b88fc5f
Author: harish876 <ha...@gmail.com>
AuthorDate: Sat Dec 20 09:09:36 2025 +0000

    view change deadlock bug - temporary hotfix
---
 .../consensus/ordering/pbft/checkpoint_manager.cpp | 19 +++++++---
 .../consensus/ordering/pbft/response_manager.cpp   | 26 +++++++++++--
 .../consensus/ordering/pbft/viewchange_manager.cpp | 44 ++++++++++++++++++----
 .../ordering/pbft/viewchange_manager_test.cpp      |  9 +++++
 platform/statistic/stats.cpp                       |  4 +-
 service/tools/config/server/server.config          |  7 ++--
 .../kv/server_tools/start_kv_service_monitoring.sh |  8 ++--
 7 files changed, 90 insertions(+), 27 deletions(-)

diff --git a/platform/consensus/ordering/pbft/checkpoint_manager.cpp b/platform/consensus/ordering/pbft/checkpoint_manager.cpp
index a5a24ca8..574128b6 100644
--- a/platform/consensus/ordering/pbft/checkpoint_manager.cpp
+++ b/platform/consensus/ordering/pbft/checkpoint_manager.cpp
@@ -93,8 +93,10 @@ bool CheckPointManager::IsValidCheckpointProof(
   std::string hash = stable_ckpt_.hash();
   std::set<uint32_t> senders;
   for (const auto& signature : stable_ckpt_.signatures()) {
-    if (!verifier_->VerifyMessage(hash, signature)) {
-      return false;
+    if (verifier_ && config_.SignatureVerifierEnabled()) {
+      if (!verifier_->VerifyMessage(hash, signature)) {
+        return false;
+      }
     }
     senders.insert(signature.node_id());
   }
@@ -296,9 +298,14 @@ void CheckPointManager::UpdateCheckPointStatus() {
   while (!stop_) {
     auto request = data_queue_.Pop(timeout_ms);
     if (request == nullptr) {
-      // if (last_seq > 0) {
-      //   TimeoutHandler();
-      // }
+      // If we've processed transactions before and now timing out,
+      // the primary might be faulty - trigger view change
+      {
+        std::lock_guard<std::mutex> lk(lt_mutex_);
+        if (last_seq_ > 0) {
+          TimeoutHandler();
+        }
+      }
       continue;
     }
     std::string hash_ = request->hash();
@@ -359,7 +366,7 @@ CheckPointManager::PopStableSeqHash() {
 }
 
 uint64_t CheckPointManager::GetHighestPreparedSeq() {
-  std::lock_guard<std::mutex> lk(lt_mutex_);
+  // highest_prepared_seq_ is atomic, no lock needed
   return highest_prepared_seq_;
 }
 
diff --git a/platform/consensus/ordering/pbft/response_manager.cpp b/platform/consensus/ordering/pbft/response_manager.cpp
index f490c003..7cfa9abd 100644
--- a/platform/consensus/ordering/pbft/response_manager.cpp
+++ b/platform/consensus/ordering/pbft/response_manager.cpp
@@ -125,7 +125,13 @@ int ResponseManager::ProcessResponseMsg(std::unique_ptr<Context> context,
   // The callback will be triggered if it received f+1 messages.
   if (request->ret() == -2) {
     LOG(ERROR) << "get response fail:" << request->ret();
-    send_num_--;
+    int current = send_num_.load();
+    if (current > 0) {
+      send_num_--;
+    } else {
+      LOG(ERROR) << "send_num_ is already " << current << ", not decrementing";
+      send_num_.store(0);
+    }
     return 0;
   }
   CollectorResultCode ret =
@@ -220,7 +226,13 @@ void ResponseManager::SendResponseToClient(
   } else {
     LOG(ERROR) << "seq:" << local_id << " no resp";
   }
-  send_num_--;
+  int current = send_num_.load();
+  if (current > 0) {
+    send_num_--;
+  } else {
+    LOG(ERROR) << "send_num_ is already " << current << ", not decrementing";
+    send_num_.store(0);
+  }
 
   if (config_.IsPerformanceRunning()) {
     return;
@@ -253,8 +265,14 @@ int ResponseManager::BatchProposeMsg() {
             << " batch num:" << config_.ClientBatchNum();
   std::vector<std::unique_ptr<QueueItem>> batch_req;
   while (!stop_) {
-    if (send_num_ > config_.GetMaxProcessTxn()) {
-      LOG(ERROR) << "send num too high, wait:" << send_num_;
+    int current_send_num = send_num_.load();
+    if (current_send_num < 0) {
+      LOG(ERROR) << "send_num_ is negative (" << current_send_num << "), resetting to 0";
+      send_num_.store(0);
+      current_send_num = 0;
+    }
+    if (current_send_num > config_.GetMaxProcessTxn()) {
+      LOG(ERROR) << "send num too high, wait:" << current_send_num;
       usleep(100);
       continue;
     }
diff --git a/platform/consensus/ordering/pbft/viewchange_manager.cpp b/platform/consensus/ordering/pbft/viewchange_manager.cpp
index 3084c7a1..bed36862 100644
--- a/platform/consensus/ordering/pbft/viewchange_manager.cpp
+++ b/platform/consensus/ordering/pbft/viewchange_manager.cpp
@@ -129,7 +129,14 @@ void ViewChangeManager::MayStart() {
       view_change_counter_++;
     }
     // std::lock_guard<std::mutex> lk(status_mutex_);
-    if (ChangeStatue(ViewChangeStatus::READY_VIEW_CHANGE)) {
+    LOG(ERROR) << "[VIEWCHANGE] Timeout handler triggered - current status: "
+               << status_ << " attempting to change to READY_VIEW_CHANGE";
+    bool changed = ChangeStatue(ViewChangeStatus::READY_VIEW_CHANGE);
+    LOG(ERROR) << "[VIEWCHANGE] ChangeStatue returned: " << changed
+               << " current status: " << status_;
+    if (changed) {
+      LOG(ERROR) << "[VIEWCHANGE] Status changed to READY_VIEW_CHANGE, sending "
+                    "view change msg";
       SendViewChangeMsg();
       auto viewchange_timer = std::make_shared<ViewChangeTimeout>(
           ViewChangeTimerType::TYPE_VIEWCHANGE, system_info_->GetCurrentView(),
@@ -196,10 +203,13 @@ bool ViewChangeManager::IsValidViewChangeMsg(
       }
       std::string data;
       proof.request().SerializeToString(&data);
-      if (!verifier_->VerifyMessage(data, proof.signature())) {
-        LOG(ERROR) << "proof signature not valid";
-        return false;
-      }
+      // Skip signature verification if verifier is null or disabled
+      // if (verifier_ && config_.SignatureVerifierEnabled()) {
+      //   if (!verifier_->VerifyMessage(data, proof.signature())) {
+      //     LOG(ERROR) << "proof signature not valid";
+      //     return false;
+      //   }
+      // }
     }
   }
   return true;
@@ -475,21 +485,35 @@ void ViewChangeManager::SendViewChangeMsg() {
 
   // n (sequence number of the latest checkpoint) and C (proof for the stable
   // checkpoint)
+  LOG(ERROR) << "[VIEWCHANGE] Getting stable checkpoint with votes";
   *view_change_message.mutable_stable_ckpt() =
       checkpoint_manager_->GetStableCheckpointWithVotes();
+  LOG(ERROR) << "[VIEWCHANGE] Got stable checkpoint, seq: "
+             << view_change_message.stable_ckpt().seq();
 
   // P - P is a set containing a set Pm for each request m that prepared at i
   // with a sequence number higher than n.
+  LOG(ERROR) << "[VIEWCHANGE] Getting highest prepared seq";
   int max_seq = checkpoint_manager_->GetHighestPreparedSeq();
-  LOG(INFO) << "Check prepared or committed txns from "
-            << view_change_message.stable_ckpt().seq() + 1 << " to " << max_seq;
-
+  LOG(ERROR) << "[VIEWCHANGE] Got highest prepared seq: " << max_seq;
+  LOG(ERROR) << "[VIEWCHANGE] Check prepared or committed txns from "
+             << view_change_message.stable_ckpt().seq() + 1 << " to "
+             << max_seq;
+
+  LOG(ERROR) << "[VIEWCHANGE] Checking prepared messages from "
+             << (view_change_message.stable_ckpt().seq() + 1) << " to "
+             << max_seq;
   for (int i = view_change_message.stable_ckpt().seq() + 1; i <= max_seq; ++i) {
     // seq i has been prepared or committed.
+    LOG(ERROR) << "[VIEWCHANGE] Checking seq: " << i;
     if (message_manager_->GetTransactionState(i) >=
         TransactionStatue::READY_COMMIT) {
+      LOG(ERROR) << "[VIEWCHANGE] Seq " << i
+                 << " is READY_COMMIT, getting proof";
       std::vector<RequestInfo> proof_info =
           message_manager_->GetPreparedProof(i);
+      LOG(ERROR) << "[VIEWCHANGE] Got proof for seq " << i
+                 << ", size: " << proof_info.size();
       assert(proof_info.size() >= config_.GetMinDataReceiveNum());
       auto txn = view_change_message.add_prepared_msg();
       txn->set_seq(i);
@@ -500,12 +524,16 @@ void ViewChangeManager::SendViewChangeMsg() {
       }
     }
   }
+  LOG(ERROR) << "[VIEWCHANGE] Finished checking prepared messages";
 
   // Broadcast my view change request.
+  LOG(ERROR) << "[VIEWCHANGE] Creating view change request and broadcasting";
   std::unique_ptr<Request> request = NewRequest(
       Request::TYPE_VIEWCHANGE, Request(), config_.GetSelfInfo().id());
   view_change_message.SerializeToString(request->mutable_data());
+  LOG(ERROR) << "[VIEWCHANGE] About to call BroadCast";
   replica_communicator_->BroadCast(*request);
+  LOG(ERROR) << "[VIEWCHANGE] BroadCast called";
 }
 
 void ViewChangeManager::AddComplaintTimer(uint64_t proxy_id, std::string hash) {
diff --git a/platform/consensus/ordering/pbft/viewchange_manager_test.cpp b/platform/consensus/ordering/pbft/viewchange_manager_test.cpp
index 94701535..43b87541 100644
--- a/platform/consensus/ordering/pbft/viewchange_manager_test.cpp
+++ b/platform/consensus/ordering/pbft/viewchange_manager_test.cpp
@@ -33,6 +33,9 @@
 #include "platform/consensus/ordering/pbft/transaction_utils.h"
 #include "platform/networkstrate/mock_replica_communicator.h"
 #include "platform/proto/checkpoint_info.pb.h"
+#include "common/crypto/signature_verifier.h"
+#include <thread>
+#include <chrono>
 
 namespace resdb {
 namespace {
@@ -82,7 +85,13 @@ TEST_F(ViewChangeManagerTest, SendViewChange) {
   manager_->MayStart();
   std::unique_ptr<Request> request = std::make_unique<Request>();
   request->set_seq(1);
+  request->set_data("test_data");
+  request->set_hash(SignatureVerifier::CalculateHash("test_data"));
   checkpoint_manager_->AddCommitData(std::move(request));
+  
+  // Wait a bit for the request to be processed (last_seq_ to be updated)
+  std::this_thread::sleep_for(std::chrono::milliseconds(100));
+  
   std::promise<bool> propose_done;
   std::future<bool> propose_done_future = propose_done.get_future();
   EXPECT_CALL(replica_communicator_, BroadCast)
diff --git a/platform/statistic/stats.cpp b/platform/statistic/stats.cpp
index dfc1957d..2d6099c4 100644
--- a/platform/statistic/stats.cpp
+++ b/platform/statistic/stats.cpp
@@ -422,7 +422,7 @@ void Stats::MonitorGlobal() {
     run_req_num = run_req_num_;
     run_req_run_time = run_req_run_time_;
 
-    LOG(ERROR) << "=========== monitor =========\n"
+    LOG(INFO) << "=========== monitor =========\n"
                << "server call:" << server_call - last_server_call
                << " server process:" << server_process - last_server_process
                << " socket recv:" << socket_recv - last_socket_recv
@@ -472,7 +472,7 @@ void Stats::MonitorGlobal() {
                << " "
                   "\n--------------- monitor ------------";
     if (run_req_num - last_run_req_num > 0) {
-      LOG(ERROR) << "  req client latency:"
+      LOG(INFO) << "  req client latency:"
                  << static_cast<double>(run_req_run_time -
                                         last_run_req_run_time) /
                         (run_req_num - last_run_req_num) / 1000000000.0;
diff --git a/service/tools/config/server/server.config b/service/tools/config/server/server.config
index 8b435651..61c66f04 100644
--- a/service/tools/config/server/server.config
+++ b/service/tools/config/server/server.config
@@ -47,9 +47,10 @@
     block_cache_capacity: 100
   },
   require_txn_validation:true,
-  enable_viewchange:true,
   enable_resview:true,
-  enable_faulty_switch:false,
-  recovery_enabled:false,
+  enable_faulty_switch:true,
+  "enable_viewchange":true,
+  "recovery_enabled":true,
+  "max_client_complaint_num":10
 }
 
diff --git a/service/tools/kv/server_tools/start_kv_service_monitoring.sh b/service/tools/kv/server_tools/start_kv_service_monitoring.sh
index f13845dc..e3657a44 100755
--- a/service/tools/kv/server_tools/start_kv_service_monitoring.sh
+++ b/service/tools/kv/server_tools/start_kv_service_monitoring.sh
@@ -24,10 +24,10 @@ WORK_PATH=$PWD
 CERT_PATH=${WORK_PATH}/service/tools/data/cert/
 GRAFANA_PORT=8090
 
-./service/tools/kv/server_tools/generate_keys_and_certs.sh || {
-  echo "Failed to generate configs/certificates" 1>&2
-  exit 1
-}
+# ./service/tools/kv/server_tools/generate_keys_and_certs.sh || {
+#   echo "Failed to generate configs/certificates" 1>&2
+#   exit 1
+# }
 
 bazel build //service/kv:kv_service --define enable_leveldb=True $@
 nohup $SERVER_PATH $SERVER_CONFIG $CERT_PATH/node1.key.pri $CERT_PATH/cert_1.cert 8090 > server0.log &


(incubator-resilientdb) 01/06: Added AI Tools (Beacon and Nexus), Licenses, Beacon workflow (#211)

Posted by ha...@apache.org.
This is an automated email from the ASF dual-hosted git repository.

harishgokul01 pushed a commit to branch demo
in repository https://gitbox.apache.org/repos/asf/incubator-resilientdb.git

commit bdd30c87554af1ae80276d27baf4976c66c3615b
Author: Bismanpal-Singh <83...@users.noreply.github.com>
AuthorDate: Mon Dec 15 12:43:21 2025 -0800

    Added AI Tools (Beacon and Nexus), Licenses, Beacon workflow (#211)
    
    * Added Apache release files
    
    * Initial commit from Create Next App
    
    * Add utility functions, update configuration, and clean up assets
    
    * Update chat message background color for improved styling
    
    * first commit
    
    * Update Welcome and Placeholder pages with new content and styling enhancements
    
    * Fix import order in button component for consistency
    
    * Refactor Welcome.module.css styles for title: updated color to black, adjusted font size and weight, and modified media query breakpoint.
    
    * Adding Python IDE
    
    * Update PythonPlayground component and styles; refactor code for consistency, enhance output display, and add subtitle styling in Welcome component.
    
    * Refactor PythonPlayground component for improved code formatting and output handling; adjust Welcome component structure to enhance title styling.
    
    * Trying to fix IDE
    
    * Fixed SDK to working model for a KV Txn with ResDB
    
    * Refining it to further mimic the actual SDK
    
    * Finalized the SDK interactive component.
    
    * Add sitemap generation functionality and remove deprecated API version route; clean up documentation references and remove unused content.
    
    * Enhance application with new AI-powered features; integrate FloatingAssistant component for interactive code assistance, update PythonPlayground and TypeScriptPlayground for improved user experience, and refine project structure by adding new GraphQL setup documentation and example templates.
    
    * Update README link in contributing section to point to the correct repository for ResilientDB GraphQL.
    
    * Add GitHub comment system with production safeguards: - Add NextAuth GitHub integration - Implement comment-to-issue conversion - Add rate limiting and security checks - Move auth pages to pages directory - Add production environment checks
    
    * Fix: Remove duplicate API routes from app directory
    
    * Fix: Move AuthProviders to components directory - Remove duplicate providers file from pages - Update import paths in auth pages - Clean up build structure
    
    * Fixed build issues for Vercel deployment
    
    * fix: add missing peer dependencies
    
    * Fixed IDE and Authentication issues
    
    * Remove fallback API key and clean up layout component by removing commented footer
    
    * Add Markdown rendering support and update layout styles
    
    * Add loader component and enhance chat message rendering with loading states
    
    * Enhance MarkdownRenderer with horizontal rule support and improve code block rendering; limit chat source nodes to a maximum of 3
    
    * Add document management API endpoints and update layout styles; enhance .gitignore for parsed documents cache
    
    * Added mongoDB query generator
    
    * Python Cache added
    
    * Added ResDB Node Cache
    
    * Added ResDB ORM, CLI and ResContract
    
    * fixed deployment issue
    
    * Fixed rescontract and added resvault
    
    * Add PocketFlowChatbot component and integrate into layout; update package-lock.json for @codemirror/view and add new dependency
    
    * CSS font size changes
    
    * update notice
    
    * Update .asf.yaml
    
    * update note
    
    * Update .asf.yaml
    
    * Implement ResearchChatPage component for document-based chat functionality; update MainNavBar to link to Researcher page and comment out feature cards in WelcomePage.
    
    * Add HuggingFace integration to document indexing and chat services; update package dependencies for @llamaindex/huggingface
    
    * #6 shadcn
    
    * template #6
    
    * #6 resolve nitpick
    
    * Update card styles in ResearchChatPage and CardHeader for improved UI; adjust background opacity and margin for better layout consistency. #6
    
    * consolidated header size #6
    
    * mv DISCLAIMER-WIP DISCLAIMER
    
    * updatte license
    
    * add license
    
    * update header
    
    * Enhance document handling in ResearchChatPage by adding multi-document selection support; update API endpoints to handle multiple document paths for indexing and querying. Introduce new UI components for document source attribution and multi-document selector. Update package dependencies for @radix-ui/react-tabs and related libraries. #5
    
    * #5 lint
    
    * #5 remove method
    
    * Add comprehensive API and project documentation for ResAI, detailing endpoints, system architecture, and component interactions. This includes new markdown files for API usage, project overview, and system architecture diagrams to enhance understanding of the application structure and functionality. #5
    
    * Refactor PDF preview visibility logic in ResearchChatPage for clarity; update max context length in MultiDocumentQueryEngine to accommodate deepseek requirements and improve separator handling in document truncation logic. #5
    
    * lint #5
    
    * Update system architecture documentation to implement dark mode agnostic styling for improved readability and accessibility across components.
    
    * #9 migrate parsed data to psql; eliminate the file directory dependency for parsed data storage
    
    * #9 reduce line complexity
    
    * #9 lint esline
    
    * #10 code composer
    
    * Refactor code generation handling in ResearchChatPage; introduce new types for Document and CodeGeneration; implement streaming updates for code composer responses; enhance preview panel with separate tabs for code generations and PDF previews; improve accessibility and styling across components.
    
    * Remove unused handleClearTool function from ChatInput component in Research page to streamline code and improve maintainability. #13
    
    * Enhance ChatInput component by adding a vertical separator for improved layout when using the code composer tool. Update language style guide to require pseudocode and implementation sections to be wrapped in triple backticks for clarity and consistency. Introduce ensureCodeBlock function to standardize code block formatting in responses.
    
    * #13 refactor post
    
    * Refactor Tabs component: reorder export statements and add cursor pointer and hover effects to TabsTrigger for improved user interaction and accessibility. #13
    
    * Update package dependencies and integrate React Query: Added @tanstack/react-query to package.json and package-lock.json for improved data fetching capabilities. Refactored document loading in ResearchChatPage to utilize useDocuments hook, enhancing error handling and state management. Removed unused Document interface from types.ts to streamline code. Updated PDFPreviewTab and MultiDocumentSelector components to use the new Document type from useDocuments. Improved accessibility fe [...]
    
    * Enhance CodeReranker class: Add comments to clarify the score enhancement formula, detailing how the original score is boosted based on code relevance and the boost factor.
    
    * Integrate Radix UI Accordion component: Added @radix-ui/react-accordion and @radix-ui/react-collapsible to package.json and package-lock.json. Refactored CodeGenerationTab component to utilize Accordion for displaying plan, pseudocode, and implementation sections, enhancing user experience and accessibility. Implemented copy-to-clipboard functionality for each section with visual feedback. Improved code organization and readability.
    
    * Remove unused extractImplementationCode function from code-composer-prompts.ts to streamline code and improve maintainability.
    
    * Refactor ResearchChatPage and introduce ChatInput component: Streamlined message handling by moving ChatInput logic into a separate component, enhancing code organization and maintainability. Implemented code composer streaming updates and improved accessibility features. Removed unused imports and code segments for cleaner structure. #13
    
    * #13 topics section
    
    * Minor adjustment in code-generation-tab.ts to remove unnecessary whitespace in the AccordionContent component for improved layout.
    
    * Add sources property to CodeGeneration interface and update ResearchChatPage to include source information in code generations. Integrate MultiDocumentSourceBadge in TopicSection for improved source display #13
    
    * #13 major refactor to reranker
    
    * #13 possibly remove reranker
    
    * #13 add agent reranker
    
    * #13 reduce json size
    
    * #13 types
    
    * Update CodeGeneration interface to include 'reading-documents' section, adjust topK value for code composer, and enhance ResearchChatPageContent with early code generation handling. Introduce ReadingDocumentsSection in code-generation-tab for improved user experience during document processing. #13
    
    * #13 update page
    
    * #13 remove reranker
    
    * #13 update gitignore
    
    * #13 refine prompts and generation screen
    
    * Refactor imports to remove type annotations for Document and CodeGeneration, and encapsulate implementation cleanup logic in a new utility function. Update code generation logic to utilize the cleanUpImplementation function for better readability and maintainability. #13
    
    * Refactor ResearchChatPageContent to include handleCloseCodeGeneration function for improved code generation management. Update PreviewPanel to utilize onCloseCodeGeneration prop for handling tab closures. Adjust CodeGenerationTabs to support tab closing functionality and enhance PDF preview tab styling. #13
    
    * #13 remove consts
    
    * Refactor CodeComposerAgent to utilize MAX_TOKENS constant for maxTokens configuration. Update AnalyzedChunk interface to use concise property names (ir, cq, qa, ce, r) for improved clarity. Adjust scoring logic to reflect new property names and enhance readability. #13
    
    * #13 update sources
    
    * upgrade llamaindex
    
    * #13 add comment
    
    * #12 initial commit
    
    * #12 cleanup
    
    * #12 cleanup
    
    * #12 cleanup
    
    * #12 clean up
    
    * #12 cleanup
    
    * #12 new vector stores
    
    * #12 cleanup
    
    * #12 scripts added
    
    * #12 add test
    
    * #12 clean up todo: see if theres a better way to get missing indicies
    
    * #12 update name
    
    * #12 fix pg client leak
    
    * #12 add citations
    
    * #12 the return
    
    * remove unneded code #12
    
    * #12 remove dnc
    
    * #12 remove sceripts
    
    * #12 citations
    
    * #12 delete md
    
    * #12 cleanup
    
    * #12 update name
    
    * #12 update lock
    
    * #12 landing page
    
    * Add TypeScript types for three.js and update package dependencies; remove unused navbar component
    
    * #12 add route back in
    
    * #12 rm parsing cache
    
    * #12 update blob
    
    * #12 cleanup
    
    * #12 env
    
    * embed fix
    
    * #18 add memory
    
    * #18 session manager
    
    * #18 fix performance
    
    * Fixed some build issues for deployment
    
    * #18 fix uuid
    
    * #18 fix storage
    
    * Fixed deployment issues p2
    
    * Some more build issues
    
    * #20 add gemini
    
    * #17 agentic
    
    * #17 add agent class
    
    * fix node modules
    
    * lint
    
    * #remove session manager
    
    * Update README.md
    
    * Update README.md
    
    * Update README.md
    
    * Update README.md
    
    * #17 agent updates
    
    * fix build issue
    
    * #17 remove file
    
    * #17 remove sample
    
    * Updated UI Styling and landing page
    
    * Fixed some build issues
    
    * Fixed internal styling to align with UI
    
    * Fixed UI bugs
    
    * #17 added agent components
    
    * #17 update input
    
    * #17 page updates
    
    * #17 update mode
    
    * #17  update prompt
    
    * #17 padding
    
    * Added Reslens, Updated About page, Updated footer and other UI components, Added license workflow. Pending : License headers
    
    * Added Apache License Headers to all files
    
    * Added Missing headers
    
    * Updated paths-ignore to include .mdx files and declared it in NOTICE as mdx does not support standard licensing
    
    * Fixed the remaining licensing issues
    
    * #17 style update
    
    * #17 update memory configuration and role assignment
    
    * code agent v1 #17
    
    * Refactor chat response handling to improve tool call delimiters and remove sample messages. Updated message state management to prevent display of incomplete control blocks and ensure proper rendering of tool call parts.
    
    * #17 fix tool calls
    
    * major linting to resolve build
    
    * Enhance model selection by disabling the "code" option in production environments to prevent unintended usage.
    
    * #23 add supabase
    
    * #23 add cache
    
    * #23 remove duplicate vall to vector index
    
    * Fixing the UI and making it cleaner
    
    * Added missing header, fixed a UI bug
    
    * #23 update
    
    * remove condition
    
    * Update cache handling in LlamaService to include VERCEL environment check
    
    * Refactor model selection disabling logic to use a boolean check for VERCEL environment variable.
    
    * Refactor model selection disabling logic to check for development environment instead of VERCEL variable.
    
    * REMOVE AUTO REPARSING
    
    * fix streaming
    
    * Refactor code generation logic for code-composer flows, removing unused source info parsing and enhancing phase management. Update UI components to reflect changes in state handling and remove deprecated topic section from code generation tab.
    
    * Update system prompt in CodeAgent to emphasize concise and structured pseudocode creation, enhancing clarity and focus on essential steps for implementation.
    
    * build
    
    * Remove API and documentation files for chat and research endpoints, streamlining the codebase and eliminating outdated references.
    
    * Update blog.md
    
    * implemented cloud storage, files are now read from a google drive folder #26
    
    * got rid of some useless console logs #26
    
    * Enhance landing page with new components and styles; integrate ShaderBackground, Header, HeroContent, and PulsingCircle; update global styles for a sleek design; add framer-motion and @paper-design/shaders-react dependencies.
    
    * Enhance FloatingAssistant component with new settings for highlight mode; update GitHubAuth and PythonPlayground components for improved UI; add postbuild script to package.json for pagefind integration; refine styles across various components for a cohesive design.
    
    * Update next.config.mjs with licensing information and performance optimizations; remove unused search input from Header component; add About section to metadata and create about.mdx file for documentation.
    
    * Remove About section from metadata in _meta.ts
    
    * Integrate Pagefind search functionality; update package dependencies to version 1.4.0; enhance global styles for search components; refactor SearchBar to utilize PagefindSearch component; improve documentation chapter titles for clarity.
    
    * Implement AI search functionality with new API endpoint; enhance Pagefind search component to support agent mode; add document indexing capabilities; update package dependencies; refactor search results display with highlighting; improve user experience with keyboard shortcuts and mode toggling.
    
    * changed file reterival from different folders now, and different sections #26
    
    * Update installation.mdx
    
    * Revise installation guide and prerequisites section
    
    Updated installation instructions and removed unnecessary notes.
    
    * updated the doucment retrival system #26
    
    * feat:improved outliners & dropdowns and prevent tab-traps
    
    * Update index.mdx
    
    * Updated resvault page
    
    * fixed the issues and now the chat works with the pdfs #26
    
    * fixed the PR comments #26
    
    * fixed the lint issues #26
    
    * Refactor document handling in ResearchChatPageContent and add document update functionality in NexusAgent. Updated the way document counts are retrieved and logged agent research prompts. Implemented a new method to add document updates to memory with structured logging for better traceability.
    
    * Add web search preference to chat request handling and update agent prompt logic. Enhanced ResearchChatPageContent to manage web search toggle and integrated contextual query building in agent response handling. Updated AGENT_RESEARCH_PROMPT to reflect new behavior for document and web search prioritization.
    
    * blog update
    
    * Remove incorrect Beacon import
    
    * Remove AI-Tooling folder to reset Beacon import
    
    * Cleanup before correct Beacon import
    
    * Squashed 'ecosystem/AI-Tooling/beacon/' content from commit 1f54f35
    
    git-subtree-dir: ecosystem/AI-Tooling/beacon
    git-subtree-split: 1f54f3566f38b56f64cc218886062c6dac2457d7
    
    * Squashed 'ecosystem/AI-Tooling/nexus/' content from commit 9148a40
    
    git-subtree-dir: ecosystem/AI-Tooling/nexus
    git-subtree-split: 9148a407d227def07651adf99bd79025f024637d
    
    * Cleanup Nexus folder before subtree import
    
    * Squashed 'ecosystem/pocketflow/' content from commit c8a8ca1
    
    git-subtree-dir: ecosystem/pocketflow
    git-subtree-split: c8a8ca17180ca5bd18948e05aa0d2c1920f50363
    
    * Updated license, added automated beacon updation workflow
    
    * fix: update auto-docs workflow configuration
    
    - Fix LLM_PROVIDER to use uppercase GEMINI for Gemini-specific API path
    - Update GEMINI_MODEL to use models/ prefix format (models/gemini-2.5-pro)
    - Ensure all environment variables are properly exported to subprocess calls
    - Test workflow fixes for rescontract documentation generation
    
    * docs: auto-update documentation [skip docs]
    
    * Fixed licensing issues in AI tools, Added more paths to ignore in the workflow for file types whicch do not support comments and headers
    
    * Fixed workflow bug of handling multiple files
    
    ---------
    
    Co-authored-by: Apratim Shukla <ap...@gmail.com>
    Co-authored-by: aibrahim <ab...@fticonsulting.com>
    Co-authored-by: Abdel Ibrahim <ab...@gmail.com>
    Co-authored-by: harish876 <ha...@gmail.com>
    Co-authored-by: Ubuntu <ic...@gmail.com>
    Co-authored-by: abdeliibrahim <82...@users.noreply.github.com>
    Co-authored-by: PNejr10 <pa...@gmail.com>
    Co-authored-by: winter4 <kr...@gmail.com>
    Co-authored-by: Nabeel Hussain M N <68...@users.noreply.github.com>
    Co-authored-by: Abdel <ab...@Abdels-MacBook-Pro.local>
    Co-authored-by: github-actions[bot] <gi...@users.noreply.github.com>
---
 .github/workflows/auto-docs.yml                    |   154 +
 .gitignore                                         |     5 +-
 .licenserc.yaml                                    |    21 +-
 dev/.rat-excludes                                  |     2 +
 ecosystem/AI-Tooling/beacon/.env.local.example     |     9 +
 .../beacon/.github/assets/beacon-hero.png          |   Bin 0 -> 463895 bytes
 .../beacon/.github/workflows/license.yml           |    37 +
 .../AI-Tooling/beacon/.github/workflows/loc.yml    |    61 +
 ecosystem/AI-Tooling/beacon/.gitignore             |   134 +
 .../AI-Tooling/beacon/.licenserc.yaml              |    16 +-
 ecosystem/AI-Tooling/beacon/.npmrc                 |     3 +
 ecosystem/AI-Tooling/beacon/.nvmrc                 |     1 +
 ecosystem/AI-Tooling/beacon/.prettierignore        |     1 +
 .../beacon/.prettierrc.mjs}                        |    72 +-
 ecosystem/AI-Tooling/beacon/.storybook/main.ts     |    35 +
 ecosystem/AI-Tooling/beacon/.storybook/preview.tsx |    52 +
 ecosystem/AI-Tooling/beacon/.stylelintignore       |    21 +
 ecosystem/AI-Tooling/beacon/.stylelintrc.json      |    28 +
 ecosystem/AI-Tooling/beacon/.vscode/settings.json  |     4 +
 ecosystem/AI-Tooling/beacon/CODE_OF_CONDUCT.md     |    95 +
 ecosystem/AI-Tooling/beacon/DISCLAIMER.txt         |    38 +
 ecosystem/AI-Tooling/beacon/LICENSE                |   201 +
 ecosystem/AI-Tooling/beacon/NOTICE                 |    10 +
 ecosystem/AI-Tooling/beacon/README.md              |    67 +
 ecosystem/AI-Tooling/beacon/app/_meta.ts           |    43 +
 .../AI-Tooling/beacon/app/api/ai-search/route.ts   |   556 +
 ecosystem/AI-Tooling/beacon/app/api/chat/route.ts  |   131 +
 .../AI-Tooling/beacon/app/api/compile/route.ts     |   117 +
 .../beacon/app/api/github-releases/route.ts        |    36 +
 .../beacon/app/docs/[[...mdxPath]]/page.tsx        |    43 +
 ecosystem/AI-Tooling/beacon/app/global.css         |   305 +
 ecosystem/AI-Tooling/beacon/app/layout.tsx         |   120 +
 ecosystem/AI-Tooling/beacon/app/lib/constants.ts   |   350 +
 ecosystem/AI-Tooling/beacon/app/lib/utils.ts       |    22 +
 ecosystem/AI-Tooling/beacon/app/page.module.css    |   361 +
 ecosystem/AI-Tooling/beacon/app/page.tsx           |    36 +
 ecosystem/AI-Tooling/beacon/app/providers.tsx      |    26 +
 ecosystem/AI-Tooling/beacon/app/search/page.tsx    |    44 +
 ecosystem/AI-Tooling/beacon/app/sitemap.ts         |    95 +
 ecosystem/AI-Tooling/beacon/asf.yaml               |    42 +
 .../AI-Tooling/beacon/components/AskAIModal.tsx    |   137 +
 .../AI-Tooling/beacon/components/AuthProviders.tsx |    32 +
 .../ColorSchemeControl.module.css                  |    46 +
 .../ColorSchemeControl.story.tsx                   |    26 +
 .../ColorSchemeControl/ColorSchemeControl.tsx      |    49 +
 .../ColorSchemeControl/HeaderControl.module.css    |    50 +
 .../ColorSchemeControl/HeaderControl.tsx           |    51 +
 .../ColorSchemeToggle/ColorSchemeToggle.tsx        |    62 +
 .../beacon/components/CommentSection.tsx           |   133 +
 .../beacon/components/Content/Content.story.tsx    |    28 +
 .../beacon/components/Content/Content.tsx          |    74 +
 .../beacon/components/FloatingAssistant.tsx        |   832 +
 .../AI-Tooling/beacon/components/GitHubAuth.tsx    |   182 +
 .../beacon/components/InstallationForm.tsx         |   128 +
 .../beacon/components/Logo/Logo.story.tsx          |    26 +
 .../AI-Tooling/beacon/components/Logo/Logo.tsx     |    24 +
 .../components/MantineFooter/MantineFooter.tsx     |   403 +
 .../components/MantineNavBar/MantineNavBar.tsx     |    47 +
 .../MantineNextraThemeObserver.tsx                 |    43 +
 .../beacon/components/PocketFlowChatbot.tsx        |   149 +
 .../AI-Tooling/beacon/components/PythonIDE.tsx     |   114 +
 .../beacon/components/PythonPlayground.tsx         |   773 +
 .../components/ReleaseNotes/ReleaseNotes.tsx       |   148 +
 .../beacon/components/ResContractPlayground.tsx    |   316 +
 .../beacon/components/SearchBar/PagefindSearch.tsx |   744 +
 .../beacon/components/SearchBar/SearchBar.tsx      |    26 +
 .../beacon/components/TypeScriptPlayground.tsx     |   800 +
 .../beacon/components/Welcome/Welcome.module.css   |    51 +
 .../beacon/components/Welcome/Welcome.story.tsx    |    26 +
 .../beacon/components/Welcome/Welcome.test.tsx     |    31 +
 .../beacon/components/Welcome/Welcome.tsx          |    91 +
 .../components/cache/NodeConfigGenerator.tsx       |   155 +
 .../beacon/components/cache/NodeQueryBuilder.tsx   |   145 +
 .../components/cache/PythonConfigGenerator.tsx     |   155 +
 .../beacon/components/cache/PythonQueryBuilder.tsx |   164 +
 ecosystem/AI-Tooling/beacon/components/index.ts    |    30 +
 .../beacon/components/landing/Header.tsx           |   239 +
 .../beacon/components/landing/HeroContent.tsx      |   149 +
 .../beacon/components/landing/PulsingCircle.tsx    |    73 +
 .../beacon/components/landing/ShaderBackground.tsx |   155 +
 .../AI-Tooling/beacon/components/ui/terminal.tsx   |    44 +
 .../beacon/components/utils/loadPyodide.ts         |    56 +
 ecosystem/AI-Tooling/beacon/content/_meta.ts       |    68 +
 ecosystem/AI-Tooling/beacon/content/about.mdx      |    53 +
 ecosystem/AI-Tooling/beacon/content/index.mdx      |   114 +
 .../AI-Tooling/beacon/content/installation.mdx     |   224 +
 ecosystem/AI-Tooling/beacon/content/pythonsdk.mdx  |    79 +
 ecosystem/AI-Tooling/beacon/content/rescli.mdx     |   216 +
 .../AI-Tooling/beacon/content/rescontract.mdx      |   205 +
 ecosystem/AI-Tooling/beacon/content/resdb-orm.mdx  |   199 +
 .../beacon/content/resilient-node-cache.mdx        |   225 +
 .../beacon/content/resilient-python-cache.mdx      |   282 +
 .../resilientdb/chapters/01_client_interaction.md  |   284 +
 .../chapters/02_network_communication.md           |   291 +
 .../chapters/03_consensus_management.md            |   214 +
 .../chapters/04_message_transaction_collection.md  |   314 +
 .../chapters/05_transaction_execution.md           |   286 +
 .../resilientdb/chapters/06_storage_layer.md       |   297 +
 .../resilientdb/chapters/07_checkpointing.md       |   440 +
 .../chapters/08_resilientdb_configuration.md       |   356 +
 .../beacon/content/resilientdb/index.mdx           |    50 +
 .../beacon/content/resilientdb_graphql/index.mdx   |   351 +
 .../beacon/content/resilientdb_graphql/setup.mdx   |   123 +
 ecosystem/AI-Tooling/beacon/content/reslens.mdx    |   164 +
 ecosystem/AI-Tooling/beacon/content/resvault.mdx   |   256 +
 ecosystem/AI-Tooling/beacon/eslint.config.mjs      |    30 +
 ecosystem/AI-Tooling/beacon/jest.config.cjs        |    35 +
 ecosystem/AI-Tooling/beacon/jest.setup.cjs         |    46 +
 ecosystem/AI-Tooling/beacon/lib/documentIndexer.ts |   480 +
 ecosystem/AI-Tooling/beacon/mdx-components.ts      |    31 +
 ecosystem/AI-Tooling/beacon/next-env.d.ts          |     6 +
 ecosystem/AI-Tooling/beacon/next.config.mjs        |    58 +
 ecosystem/AI-Tooling/beacon/package-lock.json      | 24910 +++++++++++++++++++
 ecosystem/AI-Tooling/beacon/package.json           |   102 +
 .../beacon/pages/api/auth/[...nextauth].ts         |    83 +
 .../beacon/pages/api/create-github-issue.ts        |   131 +
 ecosystem/AI-Tooling/beacon/pages/auth/_meta.json  |     8 +
 ecosystem/AI-Tooling/beacon/pages/auth/error.tsx   |    50 +
 ecosystem/AI-Tooling/beacon/pages/auth/signin.tsx  |    72 +
 ecosystem/AI-Tooling/beacon/postcss.config.cjs     |    34 +
 ecosystem/AI-Tooling/beacon/public/favicon.svg     |    18 +
 ecosystem/AI-Tooling/beacon/public/lighthouse.png  |   Bin 0 -> 21666 bytes
 ecosystem/AI-Tooling/beacon/public/logo.png        |   Bin 0 -> 8982 bytes
 .../public/mantine+nextjs+nextra-template.png      |   Bin 0 -> 606702 bytes
 ecosystem/AI-Tooling/beacon/public/resdb_sdk.py    |   290 +
 ecosystem/AI-Tooling/beacon/scripts/build-index.js |    47 +
 ecosystem/AI-Tooling/beacon/scripts/build-index.ts |    41 +
 .../beacon/styles/installation.module.css          |    46 +
 ecosystem/AI-Tooling/beacon/test-utils/index.ts    |    35 +
 ecosystem/AI-Tooling/beacon/test-utils/render.tsx  |    30 +
 ecosystem/AI-Tooling/beacon/theme.ts               |    93 +
 ecosystem/AI-Tooling/beacon/tsconfig.json          |    40 +
 .../beacon/types/codemirror__lang-javascript.d.ts  |    27 +
 ecosystem/AI-Tooling/beacon/types/next-auth.d.ts   |    33 +
 .../AI-Tooling/beacon/types/react-markdown.d.ts    |    32 +
 .../beacon/types/react-syntax-highlighter.d.ts     |    37 +
 .../nexus/.github/pull_request_template.md         |    43 +
 ecosystem/AI-Tooling/nexus/.gitignore              |    54 +
 ecosystem/AI-Tooling/nexus/README.md               |   167 +
 ecosystem/AI-Tooling/nexus/RESEARCH_SETUP.md       |   182 +
 ecosystem/AI-Tooling/nexus/components.json         |    21 +
 ecosystem/AI-Tooling/nexus/docs/DB_SETUP.md        |    38 +
 .../AI-Tooling/nexus/docs/SYSTEM_ARCHITECTURE.md   |   142 +
 ecosystem/AI-Tooling/nexus/docs/blog.md            |   227 +
 ecosystem/AI-Tooling/nexus/docs/images/agent.png   |   Bin 0 -> 666638 bytes
 .../AI-Tooling/nexus/docs/images/research.png      |   Bin 0 -> 1518383 bytes
 .../nexus/documents/bchain-transaction-pro.pdf     |   Bin 0 -> 886238 bytes
 ecosystem/AI-Tooling/nexus/documents/rcc.pdf       |   Bin 0 -> 332119 bytes
 .../AI-Tooling/nexus/documents/resilientdb.pdf     |   Bin 0 -> 1145477 bytes
 ecosystem/AI-Tooling/nexus/eslint.config.mjs       |    48 +
 ecosystem/AI-Tooling/nexus/next.config.mjs         |    48 +
 ecosystem/AI-Tooling/nexus/next.config.ts          |    26 +
 ecosystem/AI-Tooling/nexus/package-lock.json       | 12461 ++++++++++
 ecosystem/AI-Tooling/nexus/package.json            |    86 +
 ecosystem/AI-Tooling/nexus/parsing-cache.json      |     1 +
 ecosystem/AI-Tooling/nexus/postcss.config.mjs      |    24 +
 ecosystem/AI-Tooling/nexus/public/expolab-icon.png |   Bin 0 -> 133234 bytes
 ecosystem/AI-Tooling/nexus/public/resdb-logo.svg   |    24 +
 .../AI-Tooling/nexus/public/resilientdb-icon.png   |   Bin 0 -> 4036 bytes
 .../nexus/src/app/api/research/chat/route.ts       |   232 +
 .../nexus/src/app/api/research/documents/route.ts  |    64 +
 .../src/app/api/research/files/[...path]/route.ts  |    80 +
 .../src/app/api/research/prepare-index/route.ts    |   138 +
 ecosystem/AI-Tooling/nexus/src/app/favicon.ico     |   Bin 0 -> 25931 bytes
 ecosystem/AI-Tooling/nexus/src/app/globals.css     |   376 +
 ecosystem/AI-Tooling/nexus/src/app/layout.tsx      |    40 +
 ecosystem/AI-Tooling/nexus/src/app/page.tsx        |    56 +
 .../src/app/research/components/chat-input.tsx     |   209 +
 .../research/components/code-generation-tab.tsx    |   355 +
 .../app/research/components/pdf-preview-tab.tsx    |    79 +
 .../src/app/research/components/preview-panel.tsx  |   199 +
 .../AI-Tooling/nexus/src/app/research/page.tsx     |  1168 +
 .../AI-Tooling/nexus/src/app/research/types.ts     |    75 +
 .../src/components/ai-elements/code-block.tsx      |   175 +
 .../src/components/ai-elements/prompt-input.tsx    |   306 +
 .../nexus/src/components/ai-elements/response.tsx  |   340 +
 .../nexus/src/components/ai-elements/tool.tsx      |   150 +
 .../nexus/src/components/context/ToolContext.tsx   |    42 +
 .../src/components/providers/QueryProvider.tsx     |    47 +
 .../nexus/src/components/ui/accordion.tsx          |    85 +
 .../nexus/src/components/ui/animated-ai-chat.tsx   |   330 +
 .../AI-Tooling/nexus/src/components/ui/badge.tsx   |    65 +
 .../AI-Tooling/nexus/src/components/ui/button.tsx  |    78 +
 .../AI-Tooling/nexus/src/components/ui/card.tsx    |   147 +
 .../nexus/src/components/ui/citation-badge.tsx     |    68 +
 .../nexus/src/components/ui/collapsible.tsx        |    52 +
 .../AI-Tooling/nexus/src/components/ui/dialog.tsx  |   162 +
 .../src/components/ui/document-source-badge.tsx    |   270 +
 .../nexus/src/components/ui/fluid-blob.tsx         |   194 +
 .../AI-Tooling/nexus/src/components/ui/label.tsx   |    43 +
 .../AI-Tooling/nexus/src/components/ui/loader.tsx  |   517 +
 .../nexus/src/components/ui/main-navbar.tsx        |   104 +
 .../src/components/ui/multi-document-selector.tsx  |   396 +
 .../AI-Tooling/nexus/src/components/ui/popover.tsx |    67 +
 .../nexus/src/components/ui/resizable.tsx          |    75 +
 .../nexus/src/components/ui/scroll-area.tsx        |    77 +
 .../AI-Tooling/nexus/src/components/ui/select.tsx  |   204 +
 .../nexus/src/components/ui/separator.tsx          |    47 +
 .../AI-Tooling/nexus/src/components/ui/sheet.tsx   |   158 +
 .../AI-Tooling/nexus/src/components/ui/switch.tsx  |    50 +
 .../AI-Tooling/nexus/src/components/ui/tabs.tsx    |    86 +
 .../nexus/src/components/ui/textarea.tsx           |    37 +
 .../AI-Tooling/nexus/src/components/ui/tooltip.tsx |    80 +
 .../AI-Tooling/nexus/src/config/environment.ts     |    54 +
 .../AI-Tooling/nexus/src/hooks/useDocuments.ts     |    91 +
 ecosystem/AI-Tooling/nexus/src/lib/agent.ts        |   300 +
 .../nexus/src/lib/code-composer-agent.ts           |   381 +
 .../nexus/src/lib/config/llama-settings.ts         |   110 +
 ecosystem/AI-Tooling/nexus/src/lib/constants.ts    |    58 +
 ecosystem/AI-Tooling/nexus/src/lib/google-drive.ts |   178 +
 .../AI-Tooling/nexus/src/lib/llama-service.ts      |   615 +
 .../AI-Tooling/nexus/src/lib/robust-fact-memory.ts |   165 +
 .../AI-Tooling/nexus/src/lib/token-estimator.ts    |    57 +
 ecosystem/AI-Tooling/nexus/src/lib/utils.ts        |    63 +
 .../AI-Tooling/nexus/src/tests/test-router.ts      |   143 +
 ecosystem/AI-Tooling/nexus/tsconfig.json           |    27 +
 ecosystem/deployment/orbit/components.json         |    16 -
 ecosystem/monitoring/reslens/components.json       |    16 -
 ecosystem/pocketflow/.clinerules                   |  1664 ++
 ecosystem/pocketflow/.cursorrules                  |  1664 ++
 ecosystem/pocketflow/.dockerignore                 |    32 +
 ecosystem/pocketflow/.env.sample                   |     5 +
 ecosystem/pocketflow/.gitignore                    |   109 +
 ecosystem/pocketflow/.windsurfrules                |  1664 ++
 ecosystem/pocketflow/AUTOMATED_WORKFLOW.md         |   239 +
 ecosystem/pocketflow/Dockerfile                    |    13 +
 ecosystem/pocketflow/LICENSE                       |    21 +
 ecosystem/pocketflow/README.md                     |   175 +
 ecosystem/pocketflow/assets/banner.png             |   Bin 0 -> 5024749 bytes
 ecosystem/pocketflow/assets/example.png            |   Bin 0 -> 678115 bytes
 ecosystem/pocketflow/assets/youtube_thumbnail.png  |   Bin 0 -> 1118614 bytes
 ecosystem/pocketflow/docs/AutoGen Core/01_agent.md |   288 +
 .../02_messaging_system__topic___subscription_.md  |   274 +
 .../docs/AutoGen Core/03_agentruntime.md           |   356 +
 ecosystem/pocketflow/docs/AutoGen Core/04_tool.md  |   279 +
 .../docs/AutoGen Core/05_chatcompletionclient.md   |   303 +
 .../docs/AutoGen Core/06_chatcompletioncontext.md  |   337 +
 .../pocketflow/docs/AutoGen Core/07_memory.md      |   330 +
 .../pocketflow/docs/AutoGen Core/08_component.md   |   366 +
 ecosystem/pocketflow/docs/AutoGen Core/index.md    |    38 +
 ecosystem/pocketflow/docs/Browser Use/01_agent.md  |   266 +
 .../docs/Browser Use/02_system_prompt.md           |   242 +
 .../docs/Browser Use/03_browsercontext.md          |   302 +
 .../docs/Browser Use/04_dom_representation.md      |   323 +
 .../Browser Use/05_action_controller___registry.md |   347 +
 .../docs/Browser Use/06_message_manager.md         |   393 +
 .../docs/Browser Use/07_data_structures__views_.md |   242 +
 .../docs/Browser Use/08_telemetry_service.md       |   297 +
 ecosystem/pocketflow/docs/Browser Use/index.md     |    43 +
 ecosystem/pocketflow/docs/Celery/01_celery_app.md  |   300 +
 .../pocketflow/docs/Celery/02_configuration.md     |   259 +
 ecosystem/pocketflow/docs/Celery/03_task.md        |   252 +
 .../docs/Celery/04_broker_connection__amqp_.md     |   174 +
 ecosystem/pocketflow/docs/Celery/05_worker.md      |   230 +
 .../pocketflow/docs/Celery/06_result_backend.md    |   325 +
 .../pocketflow/docs/Celery/07_beat__scheduler_.md  |   336 +
 .../Celery/08_canvas__signatures___primitives_.md  |   350 +
 ecosystem/pocketflow/docs/Celery/09_events.md      |   317 +
 ecosystem/pocketflow/docs/Celery/10_bootsteps.md   |   234 +
 ecosystem/pocketflow/docs/Celery/index.md          |    39 +
 .../pocketflow/docs/Click/01_command___group.md    |   204 +
 ecosystem/pocketflow/docs/Click/02_decorators.md   |   285 +
 .../docs/Click/03_parameter__option___argument_.md |   256 +
 ecosystem/pocketflow/docs/Click/04_paramtype.md    |   264 +
 ecosystem/pocketflow/docs/Click/05_context.md      |   278 +
 .../Click/06_term_ui__terminal_user_interface_.md  |   297 +
 .../pocketflow/docs/Click/07_click_exceptions.md   |   258 +
 ecosystem/pocketflow/docs/Click/index.md           |    37 +
 .../docs/Codex/01_terminal_ui__ink_components_.md  |   340 +
 .../Codex/02_input_handling__textbuffer_editor_.md |   353 +
 ecosystem/pocketflow/docs/Codex/03_agent_loop.md   |   340 +
 .../docs/Codex/04_approval_policy___security.md    |   236 +
 .../docs/Codex/05_response___tool_call_handling.md |   381 +
 .../Codex/06_command_execution___sandboxing.md     |   360 +
 .../docs/Codex/07_configuration_management.md      |   310 +
 .../pocketflow/docs/Codex/08_single_pass_mode.md   |   313 +
 ecosystem/pocketflow/docs/Codex/index.md           |    37 +
 .../docs/Crawl4AI/01_asynccrawlerstrategy.md       |   249 +
 .../pocketflow/docs/Crawl4AI/02_asyncwebcrawler.md |   346 +
 .../docs/Crawl4AI/03_crawlerrunconfig.md           |   284 +
 .../docs/Crawl4AI/04_contentscrapingstrategy.md    |   328 +
 .../docs/Crawl4AI/05_relevantcontentfilter.md      |   432 +
 .../docs/Crawl4AI/06_extractionstrategy.md         |   449 +
 .../pocketflow/docs/Crawl4AI/07_crawlresult.md     |   348 +
 .../docs/Crawl4AI/08_deepcrawlstrategy.md          |   385 +
 .../docs/Crawl4AI/09_cachecontext___cachemode.md   |   353 +
 .../pocketflow/docs/Crawl4AI/10_basedispatcher.md  |   394 +
 ecosystem/pocketflow/docs/Crawl4AI/index.md        |    40 +
 ecosystem/pocketflow/docs/CrewAI/01_crew.md        |   214 +
 ecosystem/pocketflow/docs/CrewAI/02_agent.md       |   185 +
 ecosystem/pocketflow/docs/CrewAI/03_task.md        |   279 +
 ecosystem/pocketflow/docs/CrewAI/04_tool.md        |   280 +
 ecosystem/pocketflow/docs/CrewAI/05_process.md     |   304 +
 ecosystem/pocketflow/docs/CrewAI/06_llm.md         |   337 +
 ecosystem/pocketflow/docs/CrewAI/07_memory.md      |   223 +
 ecosystem/pocketflow/docs/CrewAI/08_knowledge.md   |   273 +
 ecosystem/pocketflow/docs/CrewAI/index.md          |    36 +
 .../pocketflow/docs/DSPy/01_module___program.md    |   270 +
 ecosystem/pocketflow/docs/DSPy/02_signature.md     |   208 +
 ecosystem/pocketflow/docs/DSPy/03_example.md       |   236 +
 ecosystem/pocketflow/docs/DSPy/04_predict.md       |   256 +
 .../docs/DSPy/05_lm__language_model_client_.md     |   311 +
 .../docs/DSPy/06_rm__retrieval_model_client_.md    |   352 +
 ecosystem/pocketflow/docs/DSPy/07_evaluate.md      |   322 +
 .../docs/DSPy/08_teleprompter___optimizer.md       |   321 +
 ecosystem/pocketflow/docs/DSPy/09_adapter.md       |   369 +
 ecosystem/pocketflow/docs/DSPy/10_settings.md      |   374 +
 ecosystem/pocketflow/docs/DSPy/index.md            |    46 +
 .../FastAPI/01_fastapi_application___routing.md    |   233 +
 .../02_path_operations___parameter_declaration.md  |   400 +
 ...3_data_validation___serialization__pydantic_.md |   351 +
 .../docs/FastAPI/04_openapi___automatic_docs.md    |   285 +
 .../docs/FastAPI/05_dependency_injection.md        |   303 +
 .../pocketflow/docs/FastAPI/06_error_handling.md   |   333 +
 .../docs/FastAPI/07_security_utilities.md          |   362 +
 .../pocketflow/docs/FastAPI/08_background_tasks.md |   187 +
 ecosystem/pocketflow/docs/FastAPI/index.md         |    38 +
 .../docs/Flask/01_application_object___flask__.md  |   162 +
 .../pocketflow/docs/Flask/02_routing_system.md     |   213 +
 .../docs/Flask/03_request_and_response_objects.md  |   264 +
 .../Flask/04_templating__jinja2_integration_.md    |   328 +
 ...s___current_app____request____session____g__.md |   318 +
 .../docs/Flask/06_configuration___config__.md      |   363 +
 .../Flask/07_application_and_request_contexts.md   |   209 +
 ecosystem/pocketflow/docs/Flask/08_blueprints.md   |   288 +
 ecosystem/pocketflow/docs/Flask/index.md           |    37 +
 .../pocketflow/docs/Google A2A/01_agent_card.md    |   169 +
 ecosystem/pocketflow/docs/Google A2A/02_task.md    |   215 +
 .../Google A2A/03_a2a_protocol___core_types.md     |   244 +
 .../Google A2A/04_a2a_server_implementation.md     |   248 +
 .../Google A2A/05_a2a_client_implementation.md     |   265 +
 .../06_task_handling_logic__server_side_.md        |   294 +
 .../Google A2A/07_streaming_communication__sse_.md |   379 +
 .../08_multi_agent_orchestration__host_agent_.md   |   251 +
 .../Google A2A/09_demo_ui_application___service.md |   257 +
 ecosystem/pocketflow/docs/Google A2A/index.md      |    38 +
 .../docs/LangGraph/01_graph___stategraph.md        |   313 +
 .../docs/LangGraph/02_nodes___pregelnode__.md      |   231 +
 ecosystem/pocketflow/docs/LangGraph/03_channels.md |   433 +
 ...w_primitives___branch____send____interrupt__.md |   615 +
 .../docs/LangGraph/05_pregel_execution_engine.md   |   230 +
 .../06_checkpointer___basecheckpointsaver__.md     |   398 +
 ecosystem/pocketflow/docs/LangGraph/index.md       |    32 +
 .../LevelDB/01_table___sstable___tablecache.md     |   259 +
 ecosystem/pocketflow/docs/LevelDB/02_memtable.md   |   288 +
 ..._write_ahead_log__wal____logwriter_logreader.md |   359 +
 ecosystem/pocketflow/docs/LevelDB/04_dbimpl.md     |   446 +
 ecosystem/pocketflow/docs/LevelDB/05_writebatch.md |   257 +
 .../docs/LevelDB/06_version___versionset.md        |   264 +
 ecosystem/pocketflow/docs/LevelDB/07_iterator.md   |   366 +
 ecosystem/pocketflow/docs/LevelDB/08_compaction.md |   317 +
 .../docs/LevelDB/09_internalkey___dbformat.md      |   320 +
 ecosystem/pocketflow/docs/LevelDB/index.md         |    46 +
 .../docs/MCP Python SDK/01_cli___mcp__command_.md  |   259 +
 .../02_fastmcp_server___fastmcp__.md               |   288 +
 ...cp_resources___resource____resourcemanager__.md |   282 +
 .../04_fastmcp_tools___tool____toolmanager__.md    |   231 +
 ..._fastmcp_prompts___prompt____promptmanager__.md |   304 +
 .../06_fastmcp_context___context__.md              |   322 +
 .../docs/MCP Python SDK/07_mcp_protocol_types.md   |   265 +
 ..._sessions___clientsession____serversession__.md |   312 +
 ...n_transports__stdio__sse__websocket__memory_.md |   324 +
 ecosystem/pocketflow/docs/MCP Python SDK/index.md  |    40 +
 .../NumPy Core/01_ndarray__n_dimensional_array_.md |   249 +
 .../docs/NumPy Core/02_dtype__data_type_object_.md |   220 +
 .../NumPy Core/03_ufunc__universal_function_.md    |   192 +
 .../04_numeric_types___numerictypes__.md           |   252 +
 .../NumPy Core/05_array_printing___arrayprint__.md |   343 +
 .../docs/NumPy Core/06_multiarray_module.md        |   161 +
 .../pocketflow/docs/NumPy Core/07_umath_module.md  |   166 +
 ...unction___protocol___overrides___overrides__.md |   202 +
 ecosystem/pocketflow/docs/NumPy Core/index.md      |    34 +
 ecosystem/pocketflow/docs/OpenManus/01_llm.md      |   209 +
 .../docs/OpenManus/02_message___memory.md          |   327 +
 .../pocketflow/docs/OpenManus/03_baseagent.md      |   235 +
 .../docs/OpenManus/04_tool___toolcollection.md     |   316 +
 ecosystem/pocketflow/docs/OpenManus/05_baseflow.md |   368 +
 ecosystem/pocketflow/docs/OpenManus/06_schema.md   |   247 +
 .../docs/OpenManus/07_configuration__config_.md    |   331 +
 .../pocketflow/docs/OpenManus/08_dockersandbox.md  |   347 +
 .../OpenManus/09_mcp__model_context_protocol_.md   |   424 +
 ecosystem/pocketflow/docs/OpenManus/index.md       |    44 +
 .../01_shared_state___shared__dictionary__.md      |   215 +
 .../02_node___basenode____node____asyncnode___.md  |   252 +
 .../docs/PocketFlow/03_actions___transitions_.md   |   256 +
 .../PocketFlow/04_flow___flow____asyncflow___.md   |   330 +
 ...onous_processing___asyncnode____asyncflow___.md |   245 +
 ...de____batchflow____asyncparallelbatchnode___.md |   328 +
 ...2a__agent_to_agent__communication_framework_.md |   345 +
 ecosystem/pocketflow/docs/PocketFlow/index.md      |    49 +
 .../pocketflow/docs/Pydantic Core/01_basemodel.md  |   277 +
 .../02_fields__fieldinfo___field_function_.md      |   333 +
 ...3_configuration__configdict___configwrapper_.md |   376 +
 ...ustom_logic__decorators___annotated_helpers_.md |   510 +
 .../05_core_schema___validation_serialization.md   |   258 +
 .../docs/Pydantic Core/06_typeadapter.md           |   372 +
 ecosystem/pocketflow/docs/Pydantic Core/index.md   |    30 +
 .../pocketflow/docs/Requests/01_functional_api.md  |   193 +
 .../docs/Requests/02_request___response_models.md  |   240 +
 ecosystem/pocketflow/docs/Requests/03_session.md   |   334 +
 .../pocketflow/docs/Requests/04_cookie_jar.md      |   372 +
 .../docs/Requests/05_authentication_handlers.md    |   428 +
 .../docs/Requests/06_exception_hierarchy.md        |   379 +
 .../docs/Requests/07_transport_adapters.md         |   411 +
 .../pocketflow/docs/Requests/08_hook_system.md     |   348 +
 ecosystem/pocketflow/docs/Requests/index.md        |    38 +
 .../docs/SmolaAgents/01_multistepagent.md          |   268 +
 .../docs/SmolaAgents/02_model_interface.md         |   297 +
 ecosystem/pocketflow/docs/SmolaAgents/03_tool.md   |   299 +
 .../pocketflow/docs/SmolaAgents/04_agentmemory.md  |   364 +
 .../docs/SmolaAgents/05_prompttemplates.md         |   269 +
 .../docs/SmolaAgents/06_pythonexecutor.md          |   375 +
 .../pocketflow/docs/SmolaAgents/07_agenttype.md    |   372 +
 .../docs/SmolaAgents/08_agentlogger___monitor.md   |   371 +
 ecosystem/pocketflow/docs/SmolaAgents/index.md     |    39 +
 ecosystem/pocketflow/docs/_config.yml              |    47 +
 ecosystem/pocketflow/docs/design.md                |   165 +
 ecosystem/pocketflow/docs/index.md                 |    43 +
 ecosystem/pocketflow/flow.py                       |    33 +
 ecosystem/pocketflow/main.py                       |   116 +
 ecosystem/pocketflow/nodes.py                      |  1105 +
 ecosystem/pocketflow/requirements.txt              |     8 +
 .../pocketflow/scripts/detect_changed_tools.py     |   127 +
 ecosystem/pocketflow/scripts/list_gemini_models.py |    34 +
 .../pocketflow/scripts/run_pocketflow_for_tool.py  |   196 +
 ecosystem/pocketflow/scripts/update_mdx_section.py |   140 +
 ecosystem/pocketflow/tool-doc-map.json             |    38 +
 ecosystem/pocketflow/utils/__init__.py             |     0
 ecosystem/pocketflow/utils/call_llm.py             |   185 +
 ecosystem/pocketflow/utils/crawl_github_files.py   |   383 +
 ecosystem/pocketflow/utils/crawl_local_files.py    |   147 +
 ecosystem/smart-contract/rescontract/index.js      |     2 +-
 ecosystem/tools/rescli/.asf.yaml                   |    42 +
 .../tools/rescli/.github/workflows/license.yml     |    37 +
 .../tools/rescli/.github/workflows/make-binary.yml |    80 +
 .../tools/rescli/.github/workflows/release.yml     |    61 +
 .../tools/rescli/.licenserc.yaml                   |    15 +-
 ecosystem/tools/rescli/CODE_OF_CONDUCT.md          |    95 +
 ecosystem/tools/rescli/DISCLAIMER                  |    21 +
 ecosystem/tools/rescli/Gemfile                     |    24 +
 ecosystem/tools/rescli/LICENSE                     |   201 +
 ecosystem/tools/rescli/NOTICE                      |     5 +
 ecosystem/tools/rescli/README.md                   |   109 +
 ecosystem/tools/rescli/Rakefile                    |    23 +
 ecosystem/tools/rescli/config.ini                  |    18 +
 ecosystem/tools/rescli/dev/.rat-excludes           |    19 +
 ecosystem/tools/rescli/dev/check-license           |    86 +
 ecosystem/tools/rescli/lib/res_cli/cli.rb          |   322 +
 ecosystem/tools/rescli/res_cli                     |    27 +
 ecosystem/tools/rescli/res_cli.gemspec             |    32 +
 ecosystem/tools/resvault/public/manifest.json      |    17 -
 451 files changed, 125482 insertions(+), 103 deletions(-)

diff --git a/.github/workflows/auto-docs.yml b/.github/workflows/auto-docs.yml
new file mode 100644
index 00000000..e2f75777
--- /dev/null
+++ b/.github/workflows/auto-docs.yml
@@ -0,0 +1,154 @@
+#
+# Licensed to the Apache Software Foundation (ASF) under one
+# or more contributor license agreements.  See the NOTICE file
+# distributed with this work for additional information
+# regarding copyright ownership.  The ASF licenses this file
+# to you under the Apache License, Version 2.0 (the
+# "License"); you may not use this file except in compliance
+# with the License.  You may obtain a copy of the License at
+#
+#   http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing,
+# software distributed under the License is distributed on an
+# "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+# KIND, either express or implied.  See the License for the
+# specific language governing permissions and limitations
+# under the License.
+#
+
+name: Auto-Generate Documentation
+
+on:
+  push:
+    paths:
+      - 'ecosystem/**'
+    branches:
+      - main
+      - master
+  # Allow manual triggering
+  workflow_dispatch:
+
+jobs:
+  update-docs:
+    runs-on: ubuntu-latest
+    env:
+      # Required by Pocketflow; must be uppercase "GEMINI" to use Gemini-specific path
+      LLM_PROVIDER: GEMINI
+      GEMINI_API_KEY: ${{ secrets.GEMINI_API_KEY }}
+      GEMINI_MODEL: ${{ secrets.GEMINI_MODEL || 'models/gemini-2.5-pro' }}
+    
+    # Skip if commit message contains [skip docs] (only applicable to push events)
+    # github.event.head_commit is null for workflow_dispatch, so guard with event_name and default string
+    if: ${{ github.event_name != 'push' || !contains(github.event.head_commit.message || '', '[skip docs]') }}
+
+    steps:
+      - name: Checkout repository
+        uses: actions/checkout@v4
+        with:
+          fetch-depth: 2  # Need at least 2 commits for diff
+
+      - name: Set up Python
+        uses: actions/setup-python@v5
+        with:
+          python-version: '3.11'
+
+      - name: Install dependencies
+        run: |
+          cd ecosystem/pocketflow
+          pip install -r requirements.txt
+
+      - name: Configure Git
+        run: |
+          git config user.name "github-actions[bot]"
+          git config user.email "github-actions[bot]@users.noreply.github.com"
+
+      - name: Detect changed tools
+        id: detect-tools
+        env:
+          LLM_PROVIDER: GEMINI
+          GEMINI_API_KEY: ${{ secrets.GEMINI_API_KEY }}
+          GEMINI_MODEL: ${{ secrets.GEMINI_MODEL || 'models/gemini-2.5-pro' }}
+        run: |
+          cd ecosystem/pocketflow
+          # Export env vars for Python scripts
+          export GEMINI_API_KEY="$GEMINI_API_KEY"
+          export GEMINI_MODEL="$GEMINI_MODEL"
+          
+          # Detect changed tools
+          CHANGED_TOOLS=$(python3 scripts/detect_changed_tools.py --base-ref HEAD^)
+          
+          if [ -z "$CHANGED_TOOLS" ]; then
+            echo "No tools changed, skipping documentation update"
+            echo "changed=false" >> $GITHUB_OUTPUT
+            exit 0
+          fi
+          
+          # Convert newline-separated list to space-separated for GITHUB_OUTPUT
+          # GITHUB_OUTPUT requires single-line values, so we use spaces as delimiter
+          TOOLS_LIST=$(echo "$CHANGED_TOOLS" | tr '\n' ' ' | sed 's/[[:space:]]*$//')
+          
+          echo "Changed tools: $CHANGED_TOOLS"
+          echo "tools=$TOOLS_LIST" >> $GITHUB_OUTPUT
+          echo "changed=true" >> $GITHUB_OUTPUT
+
+      - name: Generate documentation for changed tools
+        if: steps.detect-tools.outputs.changed == 'true'
+        env:
+          LLM_PROVIDER: GEMINI
+          GEMINI_API_KEY: ${{ secrets.GEMINI_API_KEY }}
+          GEMINI_MODEL: ${{ secrets.GEMINI_MODEL || 'models/gemini-2.5-pro' }}
+        run: |
+          cd ecosystem/pocketflow
+          # Export all env vars to ensure they're available to subprocess calls
+          export LLM_PROVIDER="$LLM_PROVIDER"
+          export GEMINI_API_KEY="$GEMINI_API_KEY"
+          export GEMINI_MODEL="$GEMINI_MODEL"
+          
+          # Read tools from previous step (space-separated)
+          TOOLS="${{ steps.detect-tools.outputs.tools }}"
+          
+          # Process each tool (bash splits on spaces by default)
+          for tool in $TOOLS; do
+            if [ -n "$tool" ]; then
+              echo "Generating documentation for: $tool"
+              python3 scripts/run_pocketflow_for_tool.py \
+                --tool "$tool" \
+                --single-file \
+                --skip-format || echo "Failed to generate docs for $tool"
+            fi
+          done
+
+      - name: Check for changes
+        id: check-changes
+        run: |
+          if [ -n "$(git status --porcelain)" ]; then
+            echo "has_changes=true" >> $GITHUB_OUTPUT
+          else
+            echo "has_changes=false" >> $GITHUB_OUTPUT
+          fi
+
+      - name: Commit changes
+        if: steps.check-changes.outputs.has_changes == 'true'
+        run: |
+          git add ecosystem/AI-Tooling/beacon/content/*.mdx
+          git commit -m "docs: auto-update documentation [skip docs]" || exit 0
+
+      - name: Create Pull Request
+        if: steps.check-changes.outputs.has_changes == 'true'
+        uses: peter-evans/create-pull-request@v5
+        with:
+          token: ${{ secrets.GITHUB_TOKEN }}
+          commit-message: "docs: auto-update documentation [skip docs]"
+          title: "docs: Auto-update documentation"
+          body: |
+            This PR contains automatically generated documentation updates.
+            
+            **Changed tools:**
+            ${{ steps.detect-tools.outputs.tools }}
+            
+            Generated by Pocketflow based on code changes.
+          branch: auto-docs-update
+          delete-branch: true
+          labels: documentation, automated
+
diff --git a/.gitignore b/.gitignore
index e03006b6..acd52c56 100644
--- a/.gitignore
+++ b/.gitignore
@@ -21,4 +21,7 @@ resdb/
 100*_db/
 gmon.out
 .history/
-service/tools/data/cert/
\ No newline at end of file
+service/tools/data/cert/
+# Generated LLM cache and Pocketflow outputs
+llm_cache.json
+ecosystem/pocketflow/.pf-output/
diff --git a/.licenserc.yaml b/.licenserc.yaml
index 46e64591..f50454a9 100644
--- a/.licenserc.yaml
+++ b/.licenserc.yaml
@@ -18,8 +18,25 @@ header:
     - 'dev/.rat-excludes'
     - 'documents/doxygen/.gitignore'
     - 'third_party/loc_script/src/index.js'
-
-
+    # Ecosystem-specific exclusions & Fille types which do not support headers (like JSON, etc.)
+    - 'ecosystem/**/.rat-excludes'
+    - 'ecosystem/**/.gitignore'
+    - 'ecosystem/**/.bazelrc'
+    - 'ecosystem/**/.gitattributes'
+    - 'ecosystem/**/.npmrc'
+    - 'ecosystem/**/.prettierrc'
+    - 'ecosystem/**/.prettierignore'
+    - 'ecosystem/**/.licenserc.yaml'
+    - 'ecosystem/**/*.json'
+    - 'ecosystem/**/.nvmrc'
+    - 'ecosystem/**/.env*'
+    - 'ecosystem/**/*.svg'
+    - 'ecosystem/**/next-env.d.ts'
+    - 'ecosystem/**/.vscode/**'
+    # Beacon content MDX files don't support license headers
+    - 'ecosystem/AI-Tooling/beacon/content/**'
+    # Pocketflow is MIT-licensed third-party code
+    - 'ecosystem/pocketflow/**'
 
   comment: on-failure
 
diff --git a/dev/.rat-excludes b/dev/.rat-excludes
index 44cf521d..b06c98f1 100644
--- a/dev/.rat-excludes
+++ b/dev/.rat-excludes
@@ -24,3 +24,5 @@ ecosystem/.*\.npmrc
 ecosystem/.*\.prettierrc
 ecosystem/.*\.prettierignore
 ecosystem/.*\.licenserc.yaml
+# Pocketflow is MIT-licensed third-party code
+ecosystem/pocketflow
diff --git a/ecosystem/AI-Tooling/beacon/.env.local.example b/ecosystem/AI-Tooling/beacon/.env.local.example
new file mode 100644
index 00000000..ac270344
--- /dev/null
+++ b/ecosystem/AI-Tooling/beacon/.env.local.example
@@ -0,0 +1,9 @@
+NEXT_PUBLIC_RESDB_REST_URL=
+
+# GitHub OAuth App credentials (use your production OAuth App credentials)
+GITHUB_CLIENT_ID=
+GITHUB_CLIENT_SECRET=
+
+# NextAuth configuration
+NEXTAUTH_URL=
+NEXTAUTH_SECRET=
\ No newline at end of file
diff --git a/ecosystem/AI-Tooling/beacon/.github/assets/beacon-hero.png b/ecosystem/AI-Tooling/beacon/.github/assets/beacon-hero.png
new file mode 100644
index 00000000..c25901b1
Binary files /dev/null and b/ecosystem/AI-Tooling/beacon/.github/assets/beacon-hero.png differ
diff --git a/ecosystem/AI-Tooling/beacon/.github/workflows/license.yml b/ecosystem/AI-Tooling/beacon/.github/workflows/license.yml
new file mode 100644
index 00000000..f3d4206d
--- /dev/null
+++ b/ecosystem/AI-Tooling/beacon/.github/workflows/license.yml
@@ -0,0 +1,37 @@
+#
+# Licensed to the Apache Software Foundation (ASF) under one
+# or more contributor license agreements.  See the NOTICE file
+# distributed with this work for additional information
+# regarding copyright ownership.  The ASF licenses this file
+# to you under the Apache License, Version 2.0 (the
+# "License"); you may not use this file except in compliance
+# with the License.  You may obtain a copy of the License at
+#
+#   http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing,
+# software distributed under the License is distributed on an
+# "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+# KIND, either express or implied.  See the License for the
+# specific language governing permissions and limitations
+# under the License.
+#
+
+name: Check Apache License
+
+on:
+  push
+
+jobs:
+  ubuntu-build:
+    name: check license
+    runs-on: ubuntu-latest
+    steps:
+     - name: Checkout
+       uses: actions/checkout@v2
+       with:
+         repository: ${{github.repository}}
+         ref: ${{ env.BRANCH_NAME }}
+
+     - name: Check License Header
+       uses: apache/skywalking-eyes/header@main
\ No newline at end of file
diff --git a/ecosystem/AI-Tooling/beacon/.github/workflows/loc.yml b/ecosystem/AI-Tooling/beacon/.github/workflows/loc.yml
new file mode 100644
index 00000000..37a47eee
--- /dev/null
+++ b/ecosystem/AI-Tooling/beacon/.github/workflows/loc.yml
@@ -0,0 +1,61 @@
+#
+# Licensed to the Apache Software Foundation (ASF) under one
+# or more contributor license agreements.  See the NOTICE file
+# distributed with this work for additional information
+# regarding copyright ownership.  The ASF licenses this file
+# to you under the Apache License, Version 2.0 (the
+# "License"); you may not use this file except in compliance
+# with the License.  You may obtain a copy of the License at
+#
+#   http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing,
+# software distributed under the License is distributed on an
+# "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+# KIND, either express or implied.  See the License for the
+# specific language governing permissions and limitations
+# under the License.
+#
+
+name: LOC
+
+on:
+  push: 
+    branches:
+      - master
+
+jobs:
+  build:
+    runs-on: ubuntu-latest
+
+    steps:
+     - name: Checkout
+       uses: actions/checkout@v2
+       with:
+         repository: ${{github.repository}}
+         ref: ${{ env.BRANCH_NAME }}
+
+     - name: NPM Init
+       run: npm init -y 
+
+     - name: NPM Install
+       run: npm install badgen @actions/core glob-gitignore
+
+     - name: Launch the local action
+       id: badge
+       uses: ./third_party/loc_script/ # Uses an action in the root directory
+       with:
+         debug: true
+         directory: ./
+         patterns: '**/*.h|**/*.cpp'
+         badge: ./output/badge.svg
+         ignore: 'node_modules/|README'
+
+     - name: Deploy to image-data branch
+       uses: peaceiris/actions-gh-pages@v3
+       with:
+         publish_dir: ./output
+         publish_branch: image-data
+         github_token: ${{ secrets.GITHUB_TOKEN }}
+         user_name: 'github-actions[bot]'
+         user_email: 'github-actions[bot]@users.noreply.github.com'
\ No newline at end of file
diff --git a/ecosystem/AI-Tooling/beacon/.gitignore b/ecosystem/AI-Tooling/beacon/.gitignore
new file mode 100644
index 00000000..40b6542c
--- /dev/null
+++ b/ecosystem/AI-Tooling/beacon/.gitignore
@@ -0,0 +1,134 @@
+# Logs
+logs
+*.log
+npm-debug.log*
+yarn-debug.log*
+yarn-error.log*
+lerna-debug.log*
+.pnpm-debug.log*
+
+# Diagnostic reports (https://nodejs.org/api/report.html)
+report.[0-9]*.[0-9]*.[0-9]*.[0-9]*.json
+
+# Runtime data
+pids
+*.pid
+*.seed
+*.pid.lock
+
+# Directory for instrumented libs generated by jscoverage/JSCover
+lib-cov
+
+# Coverage directory used by tools like istanbul
+coverage
+*.lcov
+
+# nyc test coverage
+.nyc_output
+
+# Grunt intermediate storage (https://gruntjs.com/creating-plugins#storing-task-files)
+.grunt
+
+# Bower dependency directory (https://bower.io/)
+bower_components
+
+# node-waf configuration
+.lock-wscript
+
+# Compiled binary addons (https://nodejs.org/api/addons.html)
+build/Release
+
+# Dependency directories
+node_modules/
+jspm_packages/
+
+# Snowpack dependency directory (https://snowpack.dev/)
+web_modules/
+
+# TypeScript cache
+*.tsbuildinfo
+
+# Optional npm cache directory
+.npm
+
+# Optional eslint cache
+.eslintcache
+
+# Optional stylelint cache
+.stylelintcache
+
+# Microbundle cache
+.rpt2_cache/
+.rts2_cache_cjs/
+.rts2_cache_es/
+.rts2_cache_umd/
+
+# Optional REPL history
+.node_repl_history
+
+# Output of 'npm pack'
+*.tgz
+
+# Yarn Integrity file
+.yarn-integrity
+
+# dotenv environment variable files
+.env
+.env.development.local
+.env.test.local
+.env.production.local
+.env.local
+
+# parcel-bundler cache (https://parceljs.org/)
+.cache
+.parcel-cache
+
+# Next.js build output
+.next
+out
+_pagefind/
+
+# Nuxt.js build / generate output
+.nuxt
+dist
+
+# Gatsby files
+.cache/
+# Comment in the public line in if your project uses Gatsby and not Next.js
+# https://nextjs.org/blog/next-9-1#public-directory-support
+# public
+
+# vuepress build output
+.vuepress/dist
+
+# vuepress v2.x temp and cache directory
+.temp
+.cache
+
+# Docusaurus cache and generated files
+.docusaurus
+
+# Serverless directories
+.serverless/
+
+# FuseBox cache
+.fusebox/
+
+# DynamoDB Local files
+.dynamodb/
+
+# TernJS port file
+.tern-port
+
+# Stores VSCode versions used for testing VSCode extensions
+.vscode-test
+
+# yarn v2
+.yarn/cache
+.yarn/unplugged
+.yarn/build-state.yml
+.yarn/install-state.gz
+.pnp.*
+
+.DS_Store
+.history
\ No newline at end of file
diff --git a/.licenserc.yaml b/ecosystem/AI-Tooling/beacon/.licenserc.yaml
similarity index 74%
copy from .licenserc.yaml
copy to ecosystem/AI-Tooling/beacon/.licenserc.yaml
index 46e64591..a54a83fb 100644
--- a/.licenserc.yaml
+++ b/ecosystem/AI-Tooling/beacon/.licenserc.yaml
@@ -4,18 +4,20 @@ header:
     copyright-owner: Apache Software Foundation
 
   paths-ignore:
+    - '**/*.mdx'
     - '.*'
     - '.**/**'
-    - '**/*.sol'
-    - '**/*.config'
+    - 'CNAME'
     - '**/*.conf'
+    - '**/*.config'
     - '**/*.json'
-    - '**/*.prettierrc'
-    - CNAME
-    - DISCLAIMER
-    - LICENSE
-    - NOTICE
+    - '**/*.sol'
+    - '**/*.pri'
+    - '**/*.pub'
     - 'dev/.rat-excludes'
+    - 'DISCLAIMER'
+    - 'NOTICE'
+    - 'LICENSE'
     - 'documents/doxygen/.gitignore'
     - 'third_party/loc_script/src/index.js'
 
diff --git a/ecosystem/AI-Tooling/beacon/.npmrc b/ecosystem/AI-Tooling/beacon/.npmrc
new file mode 100644
index 00000000..bacf9bc0
--- /dev/null
+++ b/ecosystem/AI-Tooling/beacon/.npmrc
@@ -0,0 +1,3 @@
+strict-peer-dependencies=false
+shell-emulator=true
+enable-pre-post-scripts=true
diff --git a/ecosystem/AI-Tooling/beacon/.nvmrc b/ecosystem/AI-Tooling/beacon/.nvmrc
new file mode 100644
index 00000000..bb8c76c6
--- /dev/null
+++ b/ecosystem/AI-Tooling/beacon/.nvmrc
@@ -0,0 +1 @@
+v22.11.0
diff --git a/ecosystem/AI-Tooling/beacon/.prettierignore b/ecosystem/AI-Tooling/beacon/.prettierignore
new file mode 100644
index 00000000..d0d878e4
--- /dev/null
+++ b/ecosystem/AI-Tooling/beacon/.prettierignore
@@ -0,0 +1 @@
+.next
\ No newline at end of file
diff --git a/ecosystem/tools/resvault/public/manifest.json b/ecosystem/AI-Tooling/beacon/.prettierrc.mjs
similarity index 51%
copy from ecosystem/tools/resvault/public/manifest.json
copy to ecosystem/AI-Tooling/beacon/.prettierrc.mjs
index ae564b6e..c73fe392 100644
--- a/ecosystem/tools/resvault/public/manifest.json
+++ b/ecosystem/AI-Tooling/beacon/.prettierrc.mjs
@@ -1,3 +1,4 @@
+//
 // Licensed to the Apache Software Foundation (ASF) under one
 // or more contributor license agreements.  See the NOTICE file
 // distributed with this work for additional information
@@ -6,7 +7,7 @@
 // "License"); you may not use this file except in compliance
 // with the License.  You may obtain a copy of the License at
 //
-//  http://www.apache.org/licenses/LICENSE-2.0
+//   http://www.apache.org/licenses/LICENSE-2.0
 //
 // Unless required by applicable law or agreed to in writing,
 // software distributed under the License is distributed on an
@@ -14,41 +15,40 @@
 // KIND, either express or implied.  See the License for the
 // specific language governing permissions and limitations
 // under the License.
+//
 
-{
-  "short_name": "ResVault",
-  "name": "ResVault",
-  "icons": {
-    "16": "icon-16.png",
-    "32": "icon-32.png",
-    "64": "icon-64.png",
-    "128": "icon-128.png"
-  },
-  "content_scripts": [
+/** @type {import("@ianvs/prettier-plugin-sort-imports").PrettierConfig} */
+const config = {
+  printWidth: 100,
+  singleQuote: true,
+  trailingComma: 'es5',
+  plugins: ['@ianvs/prettier-plugin-sort-imports'],
+  importOrder: [
+    '.*styles.css$',
+    '',
+    'dayjs',
+    '^react$',
+    '^next$',
+    '^next/.*$',
+    '<BUILTIN_MODULES>',
+    '<THIRD_PARTY_MODULES>',
+    '^@mantine/(.*)$',
+    '^@mantinex/(.*)$',
+    '^@mantine-tests/(.*)$',
+    '^@docs/(.*)$',
+    '^@/.*$',
+    '^../(?!.*.css$).*$',
+    '^./(?!.*.css$).*$',
+    '\\.css$',
+  ],
+  overrides: [
     {
-      "matches": ["<all_urls>"],
-      "js": ["content.js"]
-    }
-  ],  
-  "permissions": [
-    "storage",
-    "activeTab",
-    "tabs",
-    "scripting"
+      files: '*.mdx',
+      options: {
+        printWidth: 70,
+      },
+    },
   ],
-  "background": {
-    "service_worker": "background.js"
-  },
-  "manifest_version": 3,
-  "version": "0.0.1",
-  "action": {
-    "default_popup": "index.html",
-    "default_title": "ResVault",
-    "default_icon": {
-      "16": "icon-16.png",
-      "32": "icon-32.png",
-      "64": "icon-64.png",
-      "128": "icon-128.png"
-    }
-  }
-}
+};
+
+export default config;
\ No newline at end of file
diff --git a/ecosystem/AI-Tooling/beacon/.storybook/main.ts b/ecosystem/AI-Tooling/beacon/.storybook/main.ts
new file mode 100644
index 00000000..1900a399
--- /dev/null
+++ b/ecosystem/AI-Tooling/beacon/.storybook/main.ts
@@ -0,0 +1,35 @@
+/*
+* Licensed to the Apache Software Foundation (ASF) under one
+* or more contributor license agreements.  See the NOTICE file
+* distributed with this work for additional information
+* regarding copyright ownership.  The ASF licenses this file
+* to you under the Apache License, Version 2.0 (the
+* "License"); you may not use this file except in compliance
+* with the License.  You may obtain a copy of the License at
+* 
+*   http://www.apache.org/licenses/LICENSE-2.0
+* 
+* Unless required by applicable law or agreed to in writing,
+* software distributed under the License is distributed on an
+* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+* KIND, either express or implied.  See the License for the
+* specific language governing permissions and limitations
+* under the License.
+*/
+
+import type { StorybookConfig } from '@storybook/nextjs';
+
+const config: StorybookConfig = {
+  core: {
+    disableWhatsNewNotifications: true,
+    disableTelemetry: true,
+    enableCrashReports: false,
+  },
+  stories: ['../components/**/*.(stories|story).@(js|jsx|ts|tsx)'],
+  addons: ['storybook-dark-mode'],
+  framework: {
+    name: '@storybook/nextjs',
+    options: {},
+  },
+};
+export default config;
diff --git a/ecosystem/AI-Tooling/beacon/.storybook/preview.tsx b/ecosystem/AI-Tooling/beacon/.storybook/preview.tsx
new file mode 100644
index 00000000..9f27c484
--- /dev/null
+++ b/ecosystem/AI-Tooling/beacon/.storybook/preview.tsx
@@ -0,0 +1,52 @@
+/*
+* Licensed to the Apache Software Foundation (ASF) under one
+* or more contributor license agreements.  See the NOTICE file
+* distributed with this work for additional information
+* regarding copyright ownership.  The ASF licenses this file
+* to you under the Apache License, Version 2.0 (the
+* "License"); you may not use this file except in compliance
+* with the License.  You may obtain a copy of the License at
+* 
+*   http://www.apache.org/licenses/LICENSE-2.0
+* 
+* Unless required by applicable law or agreed to in writing,
+* software distributed under the License is distributed on an
+* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+* KIND, either express or implied.  See the License for the
+* specific language governing permissions and limitations
+* under the License.
+*/
+
+import '@mantine/core/styles.css';
+
+import React, { useEffect } from 'react';
+import { addons } from '@storybook/preview-api';
+import { DARK_MODE_EVENT_NAME } from 'storybook-dark-mode';
+import { MantineProvider, useMantineColorScheme } from '@mantine/core';
+import { theme } from '../theme';
+
+export const parameters = {
+  layout: 'fullscreen',
+  options: {
+    showPanel: false,
+  },
+};
+
+const channel = addons.getChannel();
+
+function ColorSchemeWrapper({ children }: { children: React.ReactNode }) {
+  const { setColorScheme } = useMantineColorScheme();
+  const handleColorScheme = (value: boolean) => setColorScheme(value ? 'dark' : 'light');
+
+  useEffect(() => {
+    channel.on(DARK_MODE_EVENT_NAME, handleColorScheme);
+    return () => channel.off(DARK_MODE_EVENT_NAME, handleColorScheme);
+  }, [channel]);
+
+  return <>{children}</>;
+}
+
+export const decorators = [
+  (renderStory: any) => <ColorSchemeWrapper>{renderStory()}</ColorSchemeWrapper>,
+  (renderStory: any) => <MantineProvider theme={theme}>{renderStory()}</MantineProvider>,
+];
diff --git a/ecosystem/AI-Tooling/beacon/.stylelintignore b/ecosystem/AI-Tooling/beacon/.stylelintignore
new file mode 100644
index 00000000..eef7788b
--- /dev/null
+++ b/ecosystem/AI-Tooling/beacon/.stylelintignore
@@ -0,0 +1,21 @@
+#
+# Licensed to the Apache Software Foundation (ASF) under one
+# or more contributor license agreements.  See the NOTICE file
+# distributed with this work for additional information
+# regarding copyright ownership.  The ASF licenses this file
+# to you under the Apache License, Version 2.0 (the
+# "License"); you may not use this file except in compliance
+# with the License.  You may obtain a copy of the License at
+#
+#   http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing,
+# software distributed under the License is distributed on an
+# "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+# KIND, either express or implied.  See the License for the
+# specific language governing permissions and limitations
+# under the License.
+#
+
+.next
+out
diff --git a/ecosystem/AI-Tooling/beacon/.stylelintrc.json b/ecosystem/AI-Tooling/beacon/.stylelintrc.json
new file mode 100644
index 00000000..4ea6506d
--- /dev/null
+++ b/ecosystem/AI-Tooling/beacon/.stylelintrc.json
@@ -0,0 +1,28 @@
+{
+  "extends": ["stylelint-config-standard-scss"],
+  "rules": {
+    "custom-property-pattern": null,
+    "selector-class-pattern": null,
+    "scss/no-duplicate-mixins": null,
+    "declaration-empty-line-before": null,
+    "declaration-block-no-redundant-longhand-properties": null,
+    "alpha-value-notation": null,
+    "custom-property-empty-line-before": null,
+    "property-no-vendor-prefix": null,
+    "color-function-notation": null,
+    "length-zero-no-unit": null,
+    "selector-not-notation": null,
+    "no-descending-specificity": null,
+    "comment-empty-line-before": null,
+    "scss/at-mixin-pattern": null,
+    "scss/at-rule-no-unknown": null,
+    "value-keyword-case": null,
+    "media-feature-range-notation": null,
+    "selector-pseudo-class-no-unknown": [
+      true,
+      {
+        "ignorePseudoClasses": ["global"]
+      }
+    ]
+  }
+}
diff --git a/ecosystem/AI-Tooling/beacon/.vscode/settings.json b/ecosystem/AI-Tooling/beacon/.vscode/settings.json
new file mode 100644
index 00000000..7dd4ff3a
--- /dev/null
+++ b/ecosystem/AI-Tooling/beacon/.vscode/settings.json
@@ -0,0 +1,4 @@
+{
+    "prettier.configPath": ".prettierrc.mjs",
+    "search.useParentIgnoreFiles": true
+}
\ No newline at end of file
diff --git a/ecosystem/AI-Tooling/beacon/CODE_OF_CONDUCT.md b/ecosystem/AI-Tooling/beacon/CODE_OF_CONDUCT.md
new file mode 100644
index 00000000..5f198c5c
--- /dev/null
+++ b/ecosystem/AI-Tooling/beacon/CODE_OF_CONDUCT.md
@@ -0,0 +1,95 @@
+#
+# Licensed to the Apache Software Foundation (ASF) under one
+# or more contributor license agreements.  See the NOTICE file
+# distributed with this work for additional information
+# regarding copyright ownership.  The ASF licenses this file
+# to you under the Apache License, Version 2.0 (the
+# "License"); you may not use this file except in compliance
+# with the License.  You may obtain a copy of the License at
+#
+#  http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing,
+# software distributed under the License is distributed on an
+# "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+# KIND, either express or implied.  See the License for the
+# specific language governing permissions and limitations
+# under the License.
+#
+
+# Contributor Covenant Code of Conduct
+
+## Our Pledge
+
+In the interest of fostering an open and welcoming environment, we as
+contributors and maintainers pledge to making participation in our project and
+our community a harassment-free experience for everyone, regardless of age, body
+size, disability, ethnicity, sex characteristics, gender identity and expression,
+level of experience, education, socio-economic status, nationality, personal
+appearance, race, religion, or sexual identity and orientation.
+
+## Our Standards
+
+Examples of behavior that contributes to creating a positive environment
+include:
+
+* Using welcoming and inclusive language
+* Being respectful of differing viewpoints and experiences
+* Gracefully accepting constructive criticism
+* Focusing on what is best for the community
+* Showing empathy towards other community members
+
+Examples of unacceptable behavior by participants include:
+
+* The use of sexualized language or imagery and unwelcome sexual attention or
+ advances
+* Trolling, insulting/derogatory comments, and personal or political attacks
+* Public or private harassment
+* Publishing others' private information, such as a physical or electronic
+ address, without explicit permission
+* Other conduct which could reasonably be considered inappropriate in a
+ professional setting
+
+## Our Responsibilities
+
+Project maintainers are responsible for clarifying the standards of acceptable
+behavior and are expected to take appropriate and fair corrective action in
+response to any instances of unacceptable behavior.
+
+Project maintainers have the right and responsibility to remove, edit, or
+reject comments, commits, code, wiki edits, issues, and other contributions
+that are not aligned to this Code of Conduct, or to ban temporarily or
+permanently any contributor for other behaviors that they deem inappropriate,
+threatening, offensive, or harmful.
+
+## Scope
+
+This Code of Conduct applies both within project spaces and in public spaces
+when an individual is representing the project or its community. Examples of
+representing a project or community include using an official project e-mail
+address, posting via an official social media account, or acting as an appointed
+representative at an online or offline event. Representation of a project may be
+further defined and clarified by project maintainers.
+
+## Enforcement
+
+Instances of abusive, harassing, or otherwise unacceptable behavior may be
+reported by contacting the project team at support@resilientdb.com. All
+complaints will be reviewed and investigated and will result in a response that
+is deemed necessary and appropriate to the circumstances. The project team is
+obligated to maintain confidentiality with regard to the reporter of an incident.
+Further details of specific enforcement policies may be posted separately.
+
+Project maintainers who do not follow or enforce the Code of Conduct in good
+faith may face temporary or permanent repercussions as determined by other
+members of the project's leadership.
+
+## Attribution
+
+This Code of Conduct is adapted from the [Contributor Covenant][homepage], version 1.4,
+available at https://www.contributor-covenant.org/version/1/4/code-of-conduct.html
+
+[homepage]: https://www.contributor-covenant.org
+
+For answers to common questions about this code of conduct, see
+https://www.contributor-covenant.org/faq
diff --git a/ecosystem/AI-Tooling/beacon/DISCLAIMER.txt b/ecosystem/AI-Tooling/beacon/DISCLAIMER.txt
new file mode 100644
index 00000000..e03ab51f
--- /dev/null
+++ b/ecosystem/AI-Tooling/beacon/DISCLAIMER.txt
@@ -0,0 +1,38 @@
+# Licensed to the Apache Software Foundation (ASF) under one
+# or more contributor license agreements.  See the NOTICE file
+# distributed with this work for additional information
+# regarding copyright ownership.  The ASF licenses this file
+# to you under the Apache License, Version 2.0 (the
+# "License"); you may not use this file except in compliance
+# with the License.  You may obtain a copy of the License at
+# 
+#   http://www.apache.org/licenses/LICENSE-2.0
+# 
+# Unless required by applicable law or agreed to in writing,
+# software distributed under the License is distributed on an
+# "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+# KIND, either express or implied.  See the License for the
+# specific language governing permissions and limitations
+# under the License.
+
+Apache ResilientDB is an effort undergoing incubation at the Apache Software
+Foundation (ASF), sponsored by the Apache Incubator PMC.
+
+Incubation is required of all newly accepted projects until a further review
+indicates that the infrastructure, communications, and decision making process
+have stabilized in a manner consistent with other successful ASF projects.
+
+While incubation status is not necessarily a reflection of the completeness
+or stability of the code, it does indicate that the project has yet to be
+fully endorsed by the ASF.
+
+Some of the incubating project’s releases may not be fully compliant with ASF policy.
+For example, releases may have incomplete or un-reviewed licensing conditions.
+What follows is a list of known issues the project is currently aware of
+(note that this list, by definition, is likely to be incomplete):
+
+If you are planning to incorporate this work into your product/project, please
+be aware that you will need to conduct a thorough licensing review to determine
+the overall implications of including this work. For the current status of this
+project through the Apache Incubator visit:
+https://incubator.apache.org/projects/resilientdb.html
\ No newline at end of file
diff --git a/ecosystem/AI-Tooling/beacon/LICENSE b/ecosystem/AI-Tooling/beacon/LICENSE
new file mode 100644
index 00000000..f49a4e16
--- /dev/null
+++ b/ecosystem/AI-Tooling/beacon/LICENSE
@@ -0,0 +1,201 @@
+                                 Apache License
+                           Version 2.0, January 2004
+                        http://www.apache.org/licenses/
+
+   TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION
+
+   1. Definitions.
+
+      "License" shall mean the terms and conditions for use, reproduction,
+      and distribution as defined by Sections 1 through 9 of this document.
+
+      "Licensor" shall mean the copyright owner or entity authorized by
+      the copyright owner that is granting the License.
+
+      "Legal Entity" shall mean the union of the acting entity and all
+      other entities that control, are controlled by, or are under common
+      control with that entity. For the purposes of this definition,
+      "control" means (i) the power, direct or indirect, to cause the
+      direction or management of such entity, whether by contract or
+      otherwise, or (ii) ownership of fifty percent (50%) or more of the
+      outstanding shares, or (iii) beneficial ownership of such entity.
+
+      "You" (or "Your") shall mean an individual or Legal Entity
+      exercising permissions granted by this License.
+
+      "Source" form shall mean the preferred form for making modifications,
+      including but not limited to software source code, documentation
+      source, and configuration files.
+
+      "Object" form shall mean any form resulting from mechanical
+      transformation or translation of a Source form, including but
+      not limited to compiled object code, generated documentation,
+      and conversions to other media types.
+
+      "Work" shall mean the work of authorship, whether in Source or
+      Object form, made available under the License, as indicated by a
+      copyright notice that is included in or attached to the work
+      (an example is provided in the Appendix below).
+
+      "Derivative Works" shall mean any work, whether in Source or Object
+      form, that is based on (or derived from) the Work and for which the
+      editorial revisions, annotations, elaborations, or other modifications
+      represent, as a whole, an original work of authorship. For the purposes
+      of this License, Derivative Works shall not include works that remain
+      separable from, or merely link (or bind by name) to the interfaces of,
+      the Work and Derivative Works thereof.
+
+      "Contribution" shall mean any work of authorship, including
+      the original version of the Work and any modifications or additions
+      to that Work or Derivative Works thereof, that is intentionally
+      submitted to Licensor for inclusion in the Work by the copyright owner
+      or by an individual or Legal Entity authorized to submit on behalf of
+      the copyright owner. For the purposes of this definition, "submitted"
+      means any form of electronic, verbal, or written communication sent
+      to the Licensor or its representatives, including but not limited to
+      communication on electronic mailing lists, source code control systems,
+      and issue tracking systems that are managed by, or on behalf of, the
+      Licensor for the purpose of discussing and improving the Work, but
+      excluding communication that is conspicuously marked or otherwise
+      designated in writing by the copyright owner as "Not a Contribution."
+
+      "Contributor" shall mean Licensor and any individual or Legal Entity
+      on behalf of whom a Contribution has been received by Licensor and
+      subsequently incorporated within the Work.
+
+   2. Grant of Copyright License. Subject to the terms and conditions of
+      this License, each Contributor hereby grants to You a perpetual,
+      worldwide, non-exclusive, no-charge, royalty-free, irrevocable
+      copyright license to reproduce, prepare Derivative Works of,
+      publicly display, publicly perform, sublicense, and distribute the
+      Work and such Derivative Works in Source or Object form.
+
+   3. Grant of Patent License. Subject to the terms and conditions of
+      this License, each Contributor hereby grants to You a perpetual,
+      worldwide, non-exclusive, no-charge, royalty-free, irrevocable
+      (except as stated in this section) patent license to make, have made,
+      use, offer to sell, sell, import, and otherwise transfer the Work,
+      where such license applies only to those patent claims licensable
+      by such Contributor that are necessarily infringed by their
+      Contribution(s) alone or by combination of their Contribution(s)
+      with the Work to which such Contribution(s) was submitted. If You
+      institute patent litigation against any entity (including a
+      cross-claim or counterclaim in a lawsuit) alleging that the Work
+      or a Contribution incorporated within the Work constitutes direct
+      or contributory patent infringement, then any patent licenses
+      granted to You under this License for that Work shall terminate
+      as of the date such litigation is filed.
+
+   4. Redistribution. You may reproduce and distribute copies of the
+      Work or Derivative Works thereof in any medium, with or without
+      modifications, and in Source or Object form, provided that You
+      meet the following conditions:
+
+      (a) You must give any other recipients of the Work or
+          Derivative Works a copy of this License; and
+
+      (b) You must cause any modified files to carry prominent notices
+          stating that You changed the files; and
+
+      (c) You must retain, in the Source form of any Derivative Works
+          that You distribute, all copyright, patent, trademark, and
+          attribution notices from the Source form of the Work,
+          excluding those notices that do not pertain to any part of
+          the Derivative Works; and
+
+      (d) If the Work includes a "NOTICE" text file as part of its
+          distribution, then any Derivative Works that You distribute must
+          include a readable copy of the attribution notices contained
+          within such NOTICE file, excluding those notices that do not
+          pertain to any part of the Derivative Works, in at least one
+          of the following places: within a NOTICE text file distributed
+          as part of the Derivative Works; within the Source form or
+          documentation, if provided along with the Derivative Works; or,
+          within a display generated by the Derivative Works, if and
+          wherever such third-party notices normally appear. The contents
+          of the NOTICE file are for informational purposes only and
+          do not modify the License. You may add Your own attribution
+          notices within Derivative Works that You distribute, alongside
+          or as an addendum to the NOTICE text from the Work, provided
+          that such additional attribution notices cannot be construed
+          as modifying the License.
+
+      You may add Your own copyright statement to Your modifications and
+      may provide additional or different license terms and conditions
+      for use, reproduction, or distribution of Your modifications, or
+      for any such Derivative Works as a whole, provided Your use,
+      reproduction, and distribution of the Work otherwise complies with
+      the conditions stated in this License.
+
+   5. Submission of Contributions. Unless You explicitly state otherwise,
+      any Contribution intentionally submitted for inclusion in the Work
+      by You to the Licensor shall be under the terms and conditions of
+      this License, without any additional terms or conditions.
+      Notwithstanding the above, nothing herein shall supersede or modify
+      the terms of any separate license agreement you may have executed
+      with Licensor regarding such Contributions.
+
+   6. Trademarks. This License does not grant permission to use the trade
+      names, trademarks, service marks, or product names of the Licensor,
+      except as required for reasonable and customary use in describing the
+      origin of the Work and reproducing the content of the NOTICE file.
+
+   7. Disclaimer of Warranty. Unless required by applicable law or
+      agreed to in writing, Licensor provides the Work (and each
+      Contributor provides its Contributions) on an "AS IS" BASIS,
+      WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
+      implied, including, without limitation, any warranties or conditions
+      of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A
+      PARTICULAR PURPOSE. You are solely responsible for determining the
+      appropriateness of using or redistributing the Work and assume any
+      risks associated with Your exercise of permissions under this License.
+
+   8. Limitation of Liability. In no event and under no legal theory,
+      whether in tort (including negligence), contract, or otherwise,
+      unless required by applicable law (such as deliberate and grossly
+      negligent acts) or agreed to in writing, shall any Contributor be
+      liable to You for damages, including any direct, indirect, special,
+      incidental, or consequential damages of any character arising as a
+      result of this License or out of the use or inability to use the
+      Work (including but not limited to damages for loss of goodwill,
+      work stoppage, computer failure or malfunction, or any and all
+      other commercial damages or losses), even if such Contributor
+      has been advised of the possibility of such damages.
+
+   9. Accepting Warranty or Additional Liability. While redistributing
+      the Work or Derivative Works thereof, You may choose to offer,
+      and charge a fee for, acceptance of support, warranty, indemnity,
+      or other liability obligations and/or rights consistent with this
+      License. However, in accepting such obligations, You may act only
+      on Your own behalf and on Your sole responsibility, not on behalf
+      of any other Contributor, and only if You agree to indemnify,
+      defend, and hold each Contributor harmless for any liability
+      incurred by, or claims asserted against, such Contributor by reason
+      of your accepting any such warranty or additional liability.
+
+   END OF TERMS AND CONDITIONS
+
+   APPENDIX: How to apply the Apache License to your work.
+
+      To apply the Apache License to your work, attach the following
+      boilerplate notice, with the fields enclosed by brackets "[]"
+      replaced with your own identifying information. (Don't include
+      the brackets!)  The text should be enclosed in the appropriate
+      comment syntax for the file format. We also recommend that a
+      file or class name and description of purpose be included on the
+      same "printed page" as the copyright notice for easier
+      identification within third-party archives.
+
+   Copyright [yyyy] [name of copyright owner]
+
+   Licensed under the Apache License, Version 2.0 (the "License");
+   you may not use this file except in compliance with the License.
+   You may obtain a copy of the License at
+
+       http://www.apache.org/licenses/LICENSE-2.0
+
+   Unless required by applicable law or agreed to in writing, software
+   distributed under the License is distributed on an "AS IS" BASIS,
+   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+   See the License for the specific language governing permissions and
+   limitations under the License.
\ No newline at end of file
diff --git a/ecosystem/AI-Tooling/beacon/NOTICE b/ecosystem/AI-Tooling/beacon/NOTICE
new file mode 100644
index 00000000..0a7c06a9
--- /dev/null
+++ b/ecosystem/AI-Tooling/beacon/NOTICE
@@ -0,0 +1,10 @@
+Apache ResilientDB (Incubating)
+Copyright 2023-2025 The Apache Software Foundation
+
+This product includes software developed at
+The Apache Software Foundation (http://www.apache.org/).
+
+The `.mdx` files under the `/content` directory are documentation sources.
+These files do not contain per-file license headers due to technical limitations
+of the MDX format. However, they are part of this distribution and are
+licensed under the Apache License, Version 2.0.
diff --git a/ecosystem/AI-Tooling/beacon/README.md b/ecosystem/AI-Tooling/beacon/README.md
new file mode 100644
index 00000000..8e9dc583
--- /dev/null
+++ b/ecosystem/AI-Tooling/beacon/README.md
@@ -0,0 +1,67 @@
+<!--
+Licensed to the Apache Software Foundation (ASF) under one
+or more contributor license agreements.  See the NOTICE file
+distributed with this work for additional information
+regarding copyright ownership.  The ASF licenses this file
+to you under the Apache License, Version 2.0 (the
+"License"); you may not use this file except in compliance
+with the License.  You may obtain a copy of the License at
+
+  http://www.apache.org/licenses/LICENSE-2.0
+
+Unless required by applicable law or agreed to in writing,
+software distributed under the License is distributed on an
+"AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+KIND, either express or implied.  See the License for the
+specific language governing permissions and limitations
+under the License.
+-->
+
+# Beacon – Documentation and AI Assistant for the ResilientDB Ecosystem
+
+Beacon is the home for ResilientDB documentation, examples, and learning resources. It brings everything into one place—clear guides, curated ecosystem docs, interactive playgrounds—and adds an AI assistant that helps you find answers faster and build with confidence.
+
+![Beacon hero](./.github/assets/beacon-hero.png)
+
+Visit the live site: https://beacon.resilientdb.com
+
+## What Beacon Does
+
+- Centralizes official docs and ecosystem projects in a single, easy‑to‑navigate site
+- Helps new contributors and users onboard quickly with focused guides and examples
+- Surfaces best practices and reference architectures for building with ResilientDB
+- Provides live demos and playgrounds to learn by doing
+
+## Key Features
+
+- AI Companion and Chatbot
+  - Ask context‑aware questions across docs
+  - Generate examples, commands, and “first steps” checklists
+  - Summarize long pages and compare options
+- Unified Docs & Guides
+  - Clear navigation across core, ecosystem tools, and SDKs
+  - MDX‑based content, diagrams, callouts, and code blocks
+- Interactive Playgrounds
+  - TypeScript and Python examples, terminal‑style demos
+  - Step‑by‑step tutorials that you can follow and modify
+- Powerful Search
+  - Quickly find APIs, guides, and ecosystem resources
+- Thoughtful Design
+  - Consistent light/dark modes, accessible typography, responsive layout
+
+## Getting Started (Local Development)
+
+```bash
+npm i
+npm run dev
+```
+
+Build for production:
+
+```bash
+npm run build
+```
+
+## Contributing
+
+Contributions are welcome! Open an issue or pull request with focused edits. If you’re adding or editing docs, prefer small, incremental changes with clear examples. If you’re enhancing the AI assistant behavior, include a short rationale and a quick way to test.
diff --git a/ecosystem/AI-Tooling/beacon/app/_meta.ts b/ecosystem/AI-Tooling/beacon/app/_meta.ts
new file mode 100644
index 00000000..26e110cc
--- /dev/null
+++ b/ecosystem/AI-Tooling/beacon/app/_meta.ts
@@ -0,0 +1,43 @@
+/*
+* Licensed to the Apache Software Foundation (ASF) under one
+* or more contributor license agreements.  See the NOTICE file
+* distributed with this work for additional information
+* regarding copyright ownership.  The ASF licenses this file
+* to you under the Apache License, Version 2.0 (the
+* "License"); you may not use this file except in compliance
+* with the License.  You may obtain a copy of the License at
+* 
+*   http://www.apache.org/licenses/LICENSE-2.0
+* 
+* Unless required by applicable law or agreed to in writing,
+* software distributed under the License is distributed on an
+* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+* KIND, either express or implied.  See the License for the
+* specific language governing permissions and limitations
+* under the License.
+*/
+
+export default {
+  index: {
+    display: 'hidden',
+  },
+  docs: {
+    type: 'page',
+    title: 'Documentation',
+  },
+  community: {
+    title: 'Community',
+    type: 'menu',
+    items: {
+      blog: {
+        title: 'Blog',
+        href: 'https://blog.resilientdb.com/',
+      },
+    },
+  },
+  about: {
+    type: 'page',
+    title: 'About',
+    href: '/docs/about',
+  },
+};
diff --git a/ecosystem/AI-Tooling/beacon/app/api/ai-search/route.ts b/ecosystem/AI-Tooling/beacon/app/api/ai-search/route.ts
new file mode 100644
index 00000000..e363965e
--- /dev/null
+++ b/ecosystem/AI-Tooling/beacon/app/api/ai-search/route.ts
@@ -0,0 +1,556 @@
+/*
+* Licensed to the Apache Software Foundation (ASF) under one
+* or more contributor license agreements.  See the NOTICE file
+* distributed with this work for additional information
+* regarding copyright ownership.  The ASF licenses this file
+* to you under the Apache License, Version 2.0 (the
+* "License"); you may not use this file except in compliance
+* with the License.  You may obtain a copy of the License at
+* 
+*   http://www.apache.org/licenses/LICENSE-2.0
+* 
+* Unless required by applicable law or agreed to in writing,
+* software distributed under the License is distributed on an
+* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+* KIND, either express or implied.  See the License for the
+* specific language governing permissions and limitations
+* under the License.
+*/
+
+import { NextResponse } from 'next/server';
+import { documentIndexer, DocumentChunk } from '../../../lib/documentIndexer';
+
+interface AISearchResult {
+  id: string;
+  title: string;
+  url: string;
+  excerpt: string;
+  relevanceScore: number;
+  metadata: {
+    description?: string;
+    parent?: string;
+    nav_order?: number;
+    tags?: string[];
+  };
+  matchedContent: string;
+  sections: Array<{
+    id: string;
+    title: string;
+    level: number;
+    content: string;
+    url: string;
+  }>;
+  matchedSection?: {
+    id: string;
+    title: string;
+    level: number;
+    content: string;
+    url: string;
+  };
+}
+
+export async function POST(req: Request) {
+  try {
+    const { query, limit = 10 } = await req.json();
+
+    if (!query || typeof query !== 'string') {
+      return NextResponse.json(
+        { error: 'Query is required and must be a string' },
+        { status: 400 }
+      );
+    }
+
+    // Load or create document index
+    let index = documentIndexer.loadIndex();
+    if (!index || documentIndexer.needsUpdate()) {
+      console.log('Index not found or needs update, creating new index...');
+      index = await documentIndexer.indexDocuments();
+    }
+
+    if (!index || index.documents.length === 0) {
+      return NextResponse.json(
+        { error: 'No documents found in index' },
+        { status: 404 }
+      );
+    }
+
+    // Use hybrid search (AI + keyword)
+    const searchResults = await performHybridSearch(query, index.documents, limit);
+
+    return NextResponse.json({
+      results: searchResults,
+      totalFound: searchResults.length,
+      query,
+      timestamp: new Date().toISOString()
+    });
+
+  } catch (error) {
+    console.error('AI Search API error:', error);
+    return NextResponse.json(
+      { error: 'Failed to perform AI search' },
+      { status: 500 }
+    );
+  }
+}
+
+async function performHybridSearch(
+  query: string, 
+  documents: DocumentChunk[], 
+  limit: number
+): Promise<AISearchResult[]> {
+  
+  // Extract search terms from query
+  const searchTerms = query.toLowerCase()
+    .replace(/[^\w\s-]/g, ' ')
+    .split(/\s+/)
+    .filter(word => word.length > 2);
+  
+  // Get AI-generated search terms
+  const aiTerms = await generateSearchTerms(query);
+  
+  // Combine all search terms
+  const allSearchTerms = Array.from(new Set([...searchTerms, ...aiTerms]));
+  
+  // Get keyword-based scores
+  const keywordResults = scoreDocumentsByKeywords(query, searchTerms, documents);
+  
+  // Get AI-enhanced scores
+  const aiResults = scoreDocumentsByAI(query, allSearchTerms, documents);
+  
+  // Combine scores using weighted average
+  const combinedResults = combineSearchResults(keywordResults, aiResults);
+  
+  // Rank and return top results
+  return combinedResults
+    .sort((a, b) => b.relevanceScore - a.relevanceScore)
+    .slice(0, limit)
+    .map(doc => {
+      // Find the best matching section
+      const matchedSection = findBestMatchingSection(query, allSearchTerms, doc.sections);
+      
+      return {
+        id: doc.id,
+        title: doc.title,
+        url: matchedSection ? matchedSection.url : doc.url,
+        excerpt: doc.excerpt,
+        relevanceScore: doc.relevanceScore,
+        metadata: doc.metadata,
+        matchedContent: doc.matchedContent,
+        sections: doc.sections,
+        matchedSection
+      };
+    });
+}
+
+function findBestMatchingSection(
+  query: string, 
+  searchTerms: string[], 
+  sections: Array<{
+    id: string;
+    title: string;
+    level: number;
+    content: string;
+    url: string;
+  }>
+): any | null {
+  if (!sections || sections.length === 0) return null;
+  
+  let bestSection = null;
+  let bestScore = 0;
+  
+  const queryLower = query.toLowerCase();
+  
+  for (const section of sections) {
+    let score = 0;
+    const titleLower = section.title.toLowerCase();
+    const contentLower = section.content.toLowerCase();
+    
+    // Title matching (highest weight)
+    if (titleLower.includes(queryLower)) {
+      score += 10;
+    }
+    
+    // Search terms in title
+    searchTerms.forEach(term => {
+      if (titleLower.includes(term.toLowerCase())) {
+        score += 5;
+      }
+    });
+    
+    // Search terms in content
+    searchTerms.forEach(term => {
+      const termLower = term.toLowerCase();
+      if (contentLower.includes(termLower)) {
+        score += 3;
+      }
+    });
+    
+    // Word frequency in content
+    const queryWords = queryLower.split(/\s+/);
+    queryWords.forEach(word => {
+      if (word.length > 2) {
+        const contentMatches = (contentLower.match(new RegExp(word, 'g')) || []).length;
+        score += contentMatches;
+      }
+    });
+    
+    // Prefer more specific headings (h2, h3 over h1) for better precision
+    // H1 headings are usually too general, prefer H2 and H3 for specific topics
+    if (section.level === 1) {
+      score -= 2; // Penalize H1 headings as they're usually too general
+    } else if (section.level === 2) {
+      score += 3; // Prefer H2 headings
+    } else if (section.level === 3) {
+      score += 2; // Also good for H3 headings
+    }
+    
+    if (score > bestScore) {
+      bestScore = score;
+      bestSection = section;
+    }
+  }
+  
+  // Only return if score is meaningful and we have a good match
+  // Require higher scores for H1 headings since they're usually too general
+  const minScore = bestSection && bestSection.level === 1 ? 5 : 2;
+  return bestScore > minScore ? bestSection : null;
+}
+
+// Synonym mapping for better search results
+const SYNONYM_MAP: Record<string, string[]> = {
+  'caching': ['cache', 'node cache', 'python cache', 'memory', 'storage', 'performance'],
+  'cache': ['caching', 'node cache', 'python cache', 'memory', 'storage', 'performance'],
+  'storage': ['cache', 'caching', 'database', 'persistence', 'data'],
+  'database': ['storage', 'data', 'persistence', 'resilientdb'],
+  'consensus': ['agreement', 'pbft', 'consensus management', 'voting'],
+  'network': ['communication', 'network communication', 'messaging', 'replica'],
+  'transaction': ['txn', 'transaction execution', 'execution', 'processing'],
+  'client': ['client interaction', 'kv client', 'utxo client', 'contract client'],
+  'configuration': ['config', 'setup', 'resdbconfig', 'settings'],
+  'checkpointing': ['checkpoint', 'recovery', 'backup', 'snapshot'],
+  'graphql': ['resilientdb graphql', 'api', 'query', 'mutation'],
+  'orm': ['resdb orm', 'object relational mapping', 'database orm'],
+  'vault': ['resvault', 'secure storage', 'encryption'],
+  'lens': ['reslens', 'monitoring', 'observability', 'metrics'],
+  'cli': ['rescli', 'command line', 'terminal', 'tools']
+};
+
+function expandSearchTerms(query: string): string[] {
+  const terms = query.toLowerCase().split(/\s+/);
+  const expandedTerms = new Set<string>();
+  
+  // Add original terms
+  terms.forEach(term => expandedTerms.add(term));
+  
+  // Add synonyms
+  terms.forEach(term => {
+    if (SYNONYM_MAP[term]) {
+      SYNONYM_MAP[term].forEach(synonym => expandedTerms.add(synonym));
+    }
+  });
+  
+  // Add partial matches (e.g., "caching" should match "node cache")
+  terms.forEach(term => {
+    Object.keys(SYNONYM_MAP).forEach(key => {
+      if (key.includes(term) || term.includes(key)) {
+        SYNONYM_MAP[key].forEach(synonym => expandedTerms.add(synonym));
+      }
+    });
+  });
+  
+  return Array.from(expandedTerms);
+}
+
+async function generateSearchTerms(query: string): Promise<string[]> {
+  try {
+    // First, expand with synonyms
+    const expandedTerms = expandSearchTerms(query);
+    
+    const response = await fetch('https://api.deepseek.com/v1/chat/completions', {
+      method: 'POST',
+      headers: {
+        'Content-Type': 'application/json',
+        'Authorization': `Bearer ${process.env.DEEPSEEK_API_KEY}`,
+      },
+      body: JSON.stringify({
+        model: 'deepseek-chat',
+        messages: [
+          {
+            role: 'system',
+            content: `You are a search term generator for ResilientDB documentation. Given a user query, generate 5-8 relevant search terms that would help find related documentation content.
+
+Focus on:
+- Technical terms and concepts
+- Related features and components
+- Synonyms and alternative terms
+- Specific ResilientDB terminology
+- Include terms like "node cache", "python cache", "resilientdb graphql", etc.
+
+Return only the search terms, one per line, without any other text.`
+          },
+          {
+            role: 'user',
+            content: `Generate search terms for: "${query}"`
+          }
+        ],
+        max_tokens: 200,
+        temperature: 0.3
+      }),
+    });
+
+    if (!response.ok) {
+      throw new Error('Failed to generate search terms');
+    }
+
+    const data = await response.json();
+    const aiTerms = data.choices[0]?.message?.content
+      ?.split('\n')
+      .map((term: string) => term.trim())
+      .filter((term: string) => term.length > 0) || [];
+
+    // Combine AI terms with expanded terms
+    const allTerms = [...expandedTerms, ...aiTerms];
+    const uniqueTerms = Array.from(new Set(allTerms));
+    
+    return uniqueTerms.slice(0, 12); // Increased limit for better coverage
+  } catch (error) {
+    console.error('Error generating search terms:', error);
+    // Fallback to expanded terms
+    return expandSearchTerms(query);
+  }
+}
+
+function scoreDocumentsByKeywords(
+  query: string, 
+  searchTerms: string[], 
+  documents: DocumentChunk[]
+): (DocumentChunk & { relevanceScore: number; matchedContent: string })[] {
+  
+  const scoredDocs = documents.map(doc => {
+    let score = 0;
+    let matchedContent = '';
+    
+    const queryLower = query.toLowerCase();
+    const contentLower = doc.content.toLowerCase();
+    const titleLower = doc.title.toLowerCase();
+    const urlLower = doc.url.toLowerCase();
+    
+    // Keyword matching (highest priority)
+    searchTerms.forEach(term => {
+      const termLower = term.toLowerCase();
+      
+      // Check if term matches any keyword
+      const keywordMatch = doc.keywords.some(keyword => 
+        keyword.includes(termLower) || termLower.includes(keyword)
+      );
+      
+      if (keywordMatch) {
+        score += 20; // High score for keyword match
+        
+        // Find which keyword matched
+        const matchedKeyword = doc.keywords.find(keyword => 
+          keyword.includes(termLower) || termLower.includes(keyword)
+        );
+        
+        if (matchedKeyword && !matchedContent) {
+          matchedContent = `Keyword match: ${matchedKeyword}`;
+        }
+      }
+      
+      // Exact title match
+      if (titleLower === termLower) {
+        score += 25;
+        matchedContent = doc.title;
+      } else if (titleLower.includes(termLower)) {
+        score += 15;
+        if (!matchedContent) matchedContent = doc.title;
+      }
+      
+      // URL/path matching (e.g., "node cache" in URL)
+      if (urlLower.includes(termLower)) {
+        score += 18;
+        if (!matchedContent) matchedContent = `URL match: ${doc.url}`;
+      }
+      
+      // Content matching
+      if (contentLower.includes(termLower)) {
+        score += 8;
+        
+        if (!matchedContent) {
+          const startIndex = contentLower.indexOf(termLower);
+          matchedContent = doc.content.substring(
+            Math.max(0, startIndex - 50),
+            Math.min(doc.content.length, startIndex + termLower.length + 50)
+          );
+        }
+      }
+    });
+    
+    // Exact phrase matching in title
+    if (titleLower.includes(queryLower)) {
+      score += 30;
+      matchedContent = doc.title;
+    }
+    
+    // Exact phrase matching in content
+    if (contentLower.includes(queryLower)) {
+      score += 12;
+      if (!matchedContent) {
+        const startIndex = contentLower.indexOf(queryLower);
+        matchedContent = doc.content.substring(
+          Math.max(0, startIndex - 50),
+          Math.min(doc.content.length, startIndex + queryLower.length + 50)
+        );
+      }
+    }
+    
+    // Use excerpt if no specific content matched
+    if (!matchedContent) {
+      matchedContent = doc.excerpt;
+    }
+    
+    return {
+      ...doc,
+      relevanceScore: score,
+      matchedContent: matchedContent.trim()
+    };
+  });
+  
+  // Filter out documents with very low scores
+  return scoredDocs.filter(doc => doc.relevanceScore > 0);
+}
+
+function scoreDocumentsByAI(
+  query: string, 
+  searchTerms: string[], 
+  documents: DocumentChunk[]
+): (DocumentChunk & { relevanceScore: number; matchedContent: string })[] {
+  
+  const scoredDocs = documents.map(doc => {
+    let score = 0;
+    let matchedContent = '';
+    
+    const queryLower = query.toLowerCase();
+    const contentLower = doc.content.toLowerCase();
+    const titleLower = doc.title.toLowerCase();
+    const urlLower = doc.url.toLowerCase();
+    
+    // AI-enhanced semantic matching
+    searchTerms.forEach(term => {
+      const termLower = term.toLowerCase();
+      
+      // Semantic similarity scoring (AI-generated terms get higher weight)
+      const isAiTerm = searchTerms.length > 3 && searchTerms.indexOf(term) >= 3; // Assume AI terms come after direct terms
+      
+      // Title semantic matching
+      if (titleLower.includes(termLower)) {
+        score += isAiTerm ? 12 : 8;
+        if (!matchedContent) matchedContent = doc.title;
+      }
+      
+      // URL semantic matching
+      if (urlLower.includes(termLower)) {
+        score += isAiTerm ? 15 : 10;
+        if (!matchedContent) matchedContent = `URL match: ${doc.url}`;
+      }
+      
+      // Content semantic matching
+      if (contentLower.includes(termLower)) {
+        score += isAiTerm ? 6 : 4;
+        
+        if (!matchedContent) {
+          const startIndex = contentLower.indexOf(termLower);
+          matchedContent = doc.content.substring(
+            Math.max(0, startIndex - 50),
+            Math.min(doc.content.length, startIndex + termLower.length + 50)
+          );
+        }
+      }
+      
+      // Keyword semantic matching
+      const keywordMatch = doc.keywords.some(keyword => 
+        keyword.includes(termLower) || termLower.includes(keyword)
+      );
+      
+      if (keywordMatch) {
+        score += isAiTerm ? 10 : 6;
+        if (!matchedContent) {
+          const matchedKeyword = doc.keywords.find(keyword => 
+            keyword.includes(termLower) || termLower.includes(keyword)
+          );
+          matchedContent = `Semantic match: ${matchedKeyword}`;
+        }
+      }
+    });
+    
+    // Exact phrase matching (higher weight for AI)
+    if (titleLower.includes(queryLower)) {
+      score += 20;
+      matchedContent = doc.title;
+    }
+    
+    if (contentLower.includes(queryLower)) {
+      score += 10;
+      if (!matchedContent) {
+        const startIndex = contentLower.indexOf(queryLower);
+        matchedContent = doc.content.substring(
+          Math.max(0, startIndex - 50),
+          Math.min(doc.content.length, startIndex + queryLower.length + 50)
+        );
+      }
+    }
+    
+    // Use excerpt if no specific content matched
+    if (!matchedContent) {
+      matchedContent = doc.excerpt;
+    }
+    
+    return {
+      ...doc,
+      relevanceScore: score,
+      matchedContent: matchedContent.trim()
+    };
+  });
+  
+  return scoredDocs.filter(doc => doc.relevanceScore > 0);
+}
+
+function combineSearchResults(
+  keywordResults: (DocumentChunk & { relevanceScore: number; matchedContent: string })[],
+  aiResults: (DocumentChunk & { relevanceScore: number; matchedContent: string })[]
+): (DocumentChunk & { relevanceScore: number; matchedContent: string })[] {
+  
+  const combinedMap = new Map<string, DocumentChunk & { relevanceScore: number; matchedContent: string }>();
+  
+  // Add keyword results with weight 0.6
+  keywordResults.forEach(doc => {
+    const combined = {
+      ...doc,
+      relevanceScore: doc.relevanceScore * 0.6,
+      matchedContent: doc.matchedContent
+    };
+    combinedMap.set(doc.id, combined);
+  });
+  
+  // Add AI results with weight 0.4, combining scores if document exists
+  aiResults.forEach(doc => {
+    const existing = combinedMap.get(doc.id);
+    if (existing) {
+      // Combine scores
+      existing.relevanceScore += doc.relevanceScore * 0.4;
+      // Prefer more specific matched content
+      if (doc.matchedContent.length > existing.matchedContent.length) {
+        existing.matchedContent = doc.matchedContent;
+      }
+    } else {
+      // Add new result
+      combinedMap.set(doc.id, {
+        ...doc,
+        relevanceScore: doc.relevanceScore * 0.4,
+        matchedContent: doc.matchedContent
+      });
+    }
+  });
+  
+  return Array.from(combinedMap.values());
+}
diff --git a/ecosystem/AI-Tooling/beacon/app/api/chat/route.ts b/ecosystem/AI-Tooling/beacon/app/api/chat/route.ts
new file mode 100644
index 00000000..6f63d145
--- /dev/null
+++ b/ecosystem/AI-Tooling/beacon/app/api/chat/route.ts
@@ -0,0 +1,131 @@
+/*
+* Licensed to the Apache Software Foundation (ASF) under one
+* or more contributor license agreements.  See the NOTICE file
+* distributed with this work for additional information
+* regarding copyright ownership.  The ASF licenses this file
+* to you under the Apache License, Version 2.0 (the
+* "License"); you may not use this file except in compliance
+* with the License.  You may obtain a copy of the License at
+* 
+*   http://www.apache.org/licenses/LICENSE-2.0
+* 
+* Unless required by applicable law or agreed to in writing,
+* software distributed under the License is distributed on an
+* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+* KIND, either express or implied.  See the License for the
+* specific language governing permissions and limitations
+* under the License.
+*/
+
+import { NextResponse } from 'next/server';
+
+export async function POST(req: Request) {
+  try {
+    const { messages, code } = await req.json();
+
+    const systemPrompt = `You are a helpful assistant for ResilientDB documentation. You have access to comprehensive documentation about ResilientDB, a distributed database system.
+
+Your role is to:
+1. Answer questions about ResilientDB concepts, architecture, and usage
+2. Provide accurate information based on the documentation
+3. Explain complex concepts in clear, understandable terms
+4. Offer practical examples and use cases when relevant
+5. Reference specific documentation sections when helpful
+
+Guidelines:
+- Be accurate and factual in your responses
+- Use markdown formatting for better readability
+- Provide detailed explanations for technical concepts
+- Include relevant examples from the documentation
+- If you're unsure about something, say so rather than guessing
+- Focus on helping users understand ResilientDB better
+
+Format your responses with:
+- **Bold** for emphasis
+- \`code blocks\` for technical terms and code
+- Bullet points for lists
+- > for important notes or tips
+- Clear headings for different sections
+
+Always aim to be helpful, accurate, and educational.`;
+
+    const response = await fetch('https://api.deepseek.com/v1/chat/completions', {
+      method: 'POST',
+      headers: {
+        'Content-Type': 'application/json',
+        'Authorization': `Bearer ${process.env.DEEPSEEK_API_KEY}`,
+      },
+      body: JSON.stringify({
+        model: 'deepseek-chat',
+        messages: [
+          { role: 'system', content: systemPrompt },
+          ...messages,
+        ],
+        stream: true,
+      }),
+    });
+
+    if (!response.ok) {
+      return new Response('Error from DeepSeek API', { status: response.status });
+    }
+
+    // Create a TransformStream to process the response
+    const encoder = new TextEncoder();
+    const decoder = new TextDecoder();
+
+    const stream = new ReadableStream({
+      async start(controller) {
+        const reader = response.body?.getReader();
+        if (!reader) {
+          controller.close();
+          return;
+        }
+
+        try {
+          while (true) {
+            const { done, value } = await reader.read();
+            if (done) break;
+
+            const chunk = decoder.decode(value);
+            const lines = chunk.split('\n').filter(line => line.trim() !== '');
+
+            for (const line of lines) {
+              if (line.startsWith('data: ')) {
+                const data = line.slice(6);
+                if (data === '[DONE]') continue;
+
+                try {
+                  const parsed = JSON.parse(data);
+                  const content = parsed.choices[0]?.delta?.content || '';
+                  if (content) {
+                    controller.enqueue(encoder.encode(content));
+                  }
+                } catch (e) {
+                  console.error('Error parsing JSON:', e);
+                }
+              }
+            }
+          }
+        } catch (e) {
+          console.error('Stream processing error:', e);
+          controller.error(e);
+        } finally {
+          controller.close();
+        }
+      },
+    });
+
+    return new Response(stream, {
+      headers: {
+        'Content-Type': 'text/plain; charset=utf-8',
+        'Transfer-Encoding': 'chunked',
+      },
+    });
+  } catch (error) {
+    console.error('Chat API error:', error);
+    return NextResponse.json(
+      { error: 'Failed to process chat request' },
+      { status: 500 }
+    );
+  }
+} 
\ No newline at end of file
diff --git a/ecosystem/AI-Tooling/beacon/app/api/compile/route.ts b/ecosystem/AI-Tooling/beacon/app/api/compile/route.ts
new file mode 100644
index 00000000..8e523c99
--- /dev/null
+++ b/ecosystem/AI-Tooling/beacon/app/api/compile/route.ts
@@ -0,0 +1,117 @@
+/*
+* Licensed to the Apache Software Foundation (ASF) under one
+* or more contributor license agreements.  See the NOTICE file
+* distributed with this work for additional information
+* regarding copyright ownership.  The ASF licenses this file
+* to you under the Apache License, Version 2.0 (the
+* "License"); you may not use this file except in compliance
+* with the License.  You may obtain a copy of the License at
+* 
+*   http://www.apache.org/licenses/LICENSE-2.0
+* 
+* Unless required by applicable law or agreed to in writing,
+* software distributed under the License is distributed on an
+* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+* KIND, either express or implied.  See the License for the
+* specific language governing permissions and limitations
+* under the License.
+*/
+
+import { NextResponse } from 'next/server';
+import solc from 'solc';
+
+interface CompilationInput {
+  language: string;
+  sources: {
+    [key: string]: {
+      content: string;
+    };
+  };
+  settings: {
+    outputSelection: {
+      [key: string]: {
+        [key: string]: string[];
+      };
+    };
+  };
+}
+
+interface CompilationOutput {
+  success: boolean;
+  output: string;
+  abi?: any;
+  bytecode?: string;
+}
+
+export async function POST(request: Request) {
+  try {
+    const { code } = await request.json();
+
+    if (!code || typeof code !== 'string') {
+      return NextResponse.json({
+        success: false,
+        output: 'Invalid contract code provided',
+      });
+    }
+
+    // Configure solc input
+    const input: CompilationInput = {
+      language: 'Solidity',
+      sources: {
+        'contract.sol': {
+          content: code,
+        },
+      },
+      settings: {
+        outputSelection: {
+          '*': {
+            '*': ['*'],
+          },
+        },
+      },
+    };
+
+    // Compile the contract
+    const output = JSON.parse(solc.compile(JSON.stringify(input)));
+
+    // Check for errors
+    if (output.errors) {
+      const errors = output.errors
+        .filter((error: any) => error.severity === 'error')
+        .map((error: any) => error.formattedMessage);
+      
+      if (errors.length > 0) {
+        return NextResponse.json({
+          success: false,
+          output: errors.join('\n'),
+        });
+      }
+    }
+
+    // Get the contract name (assuming it's the first contract in the file)
+    const contractName = Object.keys(output.contracts['contract.sol'])[0];
+    const contract = output.contracts['contract.sol'][contractName];
+
+    if (!contract) {
+      return NextResponse.json({
+        success: false,
+        output: 'No contract found in the provided code',
+      });
+    }
+
+    const response: CompilationOutput = {
+      success: true,
+      output: 'Contract compiled successfully!',
+      abi: contract.abi,
+      bytecode: contract.evm.bytecode.object,
+    };
+
+    return NextResponse.json(response);
+  } catch (error) {
+    console.error('Compilation error:', error);
+    return NextResponse.json({
+      success: false,
+      output: 'Failed to compile contract. Please check your code and try again.',
+    });
+  }
+} 
\ No newline at end of file
diff --git a/ecosystem/AI-Tooling/beacon/app/api/github-releases/route.ts b/ecosystem/AI-Tooling/beacon/app/api/github-releases/route.ts
new file mode 100644
index 00000000..4b741029
--- /dev/null
+++ b/ecosystem/AI-Tooling/beacon/app/api/github-releases/route.ts
@@ -0,0 +1,36 @@
+/*
+* Licensed to the Apache Software Foundation (ASF) under one
+* or more contributor license agreements.  See the NOTICE file
+* distributed with this work for additional information
+* regarding copyright ownership.  The ASF licenses this file
+* to you under the Apache License, Version 2.0 (the
+* "License"); you may not use this file except in compliance
+* with the License.  You may obtain a copy of the License at
+* 
+*   http://www.apache.org/licenses/LICENSE-2.0
+* 
+* Unless required by applicable law or agreed to in writing,
+* software distributed under the License is distributed on an
+* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+* KIND, either express or implied.  See the License for the
+* specific language governing permissions and limitations
+* under the License.
+*/
+
+export async function GET() {
+  const response = await fetch(
+    'https://api.github.com/repos/gfazioli/next-app-nextra-template/releases',
+    {
+      headers: {
+        Accept: 'application/vnd.github+json',
+        // Authorization: `Bearer ${process.env.GITHUB_TOKEN}`, // Optional for rate limit
+      },
+    }
+  );
+  if (!response.ok) {
+    return Response.json({ error: 'Failed to fetch releases' }, { status: 500 });
+  }
+  const releases = await response.json();
+
+  return Response.json({ releases, status: 'ok' });
+}
diff --git a/ecosystem/AI-Tooling/beacon/app/docs/[[...mdxPath]]/page.tsx b/ecosystem/AI-Tooling/beacon/app/docs/[[...mdxPath]]/page.tsx
new file mode 100644
index 00000000..2739d3c6
--- /dev/null
+++ b/ecosystem/AI-Tooling/beacon/app/docs/[[...mdxPath]]/page.tsx
@@ -0,0 +1,43 @@
+/*
+* Licensed to the Apache Software Foundation (ASF) under one
+* or more contributor license agreements.  See the NOTICE file
+* distributed with this work for additional information
+* regarding copyright ownership.  The ASF licenses this file
+* to you under the Apache License, Version 2.0 (the
+* "License"); you may not use this file except in compliance
+* with the License.  You may obtain a copy of the License at
+* 
+*   http://www.apache.org/licenses/LICENSE-2.0
+* 
+* Unless required by applicable law or agreed to in writing,
+* software distributed under the License is distributed on an
+* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+* KIND, either express or implied.  See the License for the
+* specific language governing permissions and limitations
+* under the License.
+*/
+
+import { generateStaticParamsFor, importPage } from 'nextra/pages';
+import { useMDXComponents } from '../../../mdx-components';
+
+export const generateStaticParams = generateStaticParamsFor('mdxPath');
+
+export async function generateMetadata(props: any) {
+  const params = await props.params;
+  const { metadata } = await importPage(params.mdxPath);
+  return metadata;
+}
+
+const Wrapper = useMDXComponents().wrapper;
+
+export default async function Page(props: any) {
+  const params = await props.params;
+  const result = await importPage(params.mdxPath);
+  const { default: MDXContent, toc, metadata } = result;
+
+  return (
+    <Wrapper toc={toc} metadata={metadata}>
+      <MDXContent {...props} params={params} />
+    </Wrapper>
+  );
+}
diff --git a/ecosystem/AI-Tooling/beacon/app/global.css b/ecosystem/AI-Tooling/beacon/app/global.css
new file mode 100644
index 00000000..417db604
--- /dev/null
+++ b/ecosystem/AI-Tooling/beacon/app/global.css
@@ -0,0 +1,305 @@
+/*
+* Licensed to the Apache Software Foundation (ASF) under one
+* or more contributor license agreements.  See the NOTICE file
+* distributed with this work for additional information
+* regarding copyright ownership.  The ASF licenses this file
+* to you under the Apache License, Version 2.0 (the
+* "License"); you may not use this file except in compliance
+* with the License.  You may obtain a copy of the License at
+* 
+*   http://www.apache.org/licenses/LICENSE-2.0
+* 
+* Unless required by applicable law or agreed to in writing,
+* software distributed under the License is distributed on an
+* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+* KIND, either express or implied.  See the License for the
+* specific language governing permissions and limitations
+* under the License.
+*/
+
+@import 'nextra-theme-docs/dist/style.css' layer(nextra);
+
+/**
+ * Custom styles
+ *
+ * You can add your own custom styles here. This file will be imported after the theme styles.
+ * This is a great place to add your own utility classes or override styles.
+ *
+ * In this case we're going to fix a glitch with the text size in the code blocks. 
+ */
+@layer overwrite {
+  :root {
+    /* Force Nextra base background to pure black to match landing */
+    --x-color-nextra-bg: #000;
+    --font-sans: Inter, ui-sans-serif, system-ui, -apple-system, Segoe UI, Roboto, Helvetica, Arial, "Apple Color Emoji", "Segoe UI Emoji";
+  }
+
+  :where(.dark) {
+    --x-color-neutral-800: var(--mantine-color-dark-6);
+  }
+
+  .x\:text-sm {
+    font-size: var(--x-text-sm) !important;
+    line-height: var(--tw-leading, var(--x-text-sm--line-height)) !important;
+  }
+}
+
+@layer components, mantine, nextra, overwrite;
+
+/* Global sleek styles */
+@layer overwrite {
+  html {
+    scroll-behavior: smooth;
+  }
+
+  body {
+    color: var(--mantine-color-text);
+    font-family: var(--font-sans);
+    background:
+      radial-gradient(1200px 600px at 80% -10%, rgba(0, 102, 255, 0.12), transparent 100%),
+      radial-gradient(1000px 500px at -10% 10%, rgba(255, 0, 128, 0.09), transparent 100%),
+      linear-gradient(180deg, rgba(255, 255, 255, 0.02), rgba(255, 255, 255, 0.0)) !important;
+    /* background: #000000; */
+  }
+
+  :where(.dark) body {
+    color: rgba(255, 255, 255, 0.92);
+  }
+
+  h1, h2, h3, h4, h5, h6 {
+    color: inherit;
+    font-family: var(--font-sans);
+  }
+
+  a {
+    color: #1f2937;
+  }
+  :where(.dark) a {
+    color: rgba(255, 255, 255, 0.92) !important;
+  }
+
+  /* Stronger override for Nextra link styling in docs */
+  :where(.dark) .nextra-content a,
+  :where(.dark) .nextra-content a:visited {
+    color: rgba(255, 255, 255, 0.92) !important;
+  }
+  .nextra-content a,
+  .nextra-content a:visited {
+    color: #1f2937 !important;
+  }
+
+  /* Ensure Nextra containers don’t paint a gray background */
+  :where(.nextra-container,
+    .nextra-content,
+    .nextra-sidebar-container,
+    .nx-bg-neutral-900,
+    .nx-bg-gray-900,
+    .nx-bg-black,
+    .nx-bg-dark,
+    .nx-bg-zinc-900,
+    .nx-bg-slate-900) {
+    background-color: transparent !important;
+  }
+
+  /* Make sticky headers/footers transparent and remove borders/shadows */
+  :where(.nx-sticky) {
+    background: transparent !important;
+    box-shadow: none !important;
+    border: none !important;
+  }
+  :where(.nextra-sidebar) header,
+  :where(.nextra-sidebar) footer,
+  :where(.nextra-container > header) {
+    background: transparent !important;
+    border: none !important;
+    box-shadow: none !important;
+  }
+
+  /* Glassmorphism utility */
+  .glass {
+    background: rgba(255, 255, 255, 0.06); 
+    -webkit-backdrop-filter: saturate(120%) blur(10px);
+    backdrop-filter: saturate(120%) blur(10px);
+    border: 1px solid rgba(255, 255, 255, 0.08);
+  }
+
+  code, pre {
+    border-radius: 10px;
+  }
+
+  /* Target article tag for markdown content font styling */
+  article {
+    font-family: 'Inter', system-ui, -apple-system, sans-serif !important;
+    font-weight: 400;
+    line-height: 1.6;
+  }
+
+  /* Specific styling for the main content article */
+  article[data-pagefind-body="true"] {
+    font-family: 'Inter', system-ui, -apple-system, sans-serif !important;
+    font-size: 16px;
+    line-height: 1.7;
+    color: rgba(255, 255, 255, 0.9);
+  }
+
+  /* Override Nextra's default article styling */
+  article.x\:w-full {
+    font-family: 'Inter', system-ui, -apple-system, sans-serif !important;
+  }
+
+  /* Sidebar footer background override */
+  :where(.nextra-sidebar-footer) {
+    background: transparent !important;
+    border-top: none !important;
+    box-shadow: none !important;
+  }
+
+  /* Lightweight parallax blob for landing */
+  .parallax-blob {
+    position: absolute;
+    left: 0;
+    top: 0;
+    width: 55vmax;
+    height: 55vmax;
+    transform: translate(-50%, -50%) scale(0.9);
+    background: radial-gradient(closest-side, rgba(0, 102, 255, 0.18), transparent 72%);
+    pointer-events: none;
+    transition: transform 0.18s ease-out, opacity 300ms ease-out;
+    will-change: transform;
+    filter: blur(12px);
+    opacity: 0;
+  }
+
+  /* Beacon of light effect */
+  @keyframes beamPulse {
+    0%, 100% { opacity: 0.45; transform: translateX(-50%) scaleX(1); }
+    50% { opacity: 0.7; transform: translateX(-50%) scaleX(1.08); }
+  }
+  .beacon-beam {
+    position: absolute;
+    left: 50%;
+    top: -10vh;
+    height: 120vh;
+    width: 2px;
+    transform: translateX(-50%);
+    background: linear-gradient(180deg,
+      rgba(255,255,255,0) 0%,
+      rgba(0, 146, 255, 0.4) 40%,
+      rgba(0, 146, 255, 0.35) 60%,
+      rgba(255,255,255,0) 100%);
+    filter: blur(8px);
+    opacity: 0.55;
+    pointer-events: none;
+    animation: beamPulse 4s ease-in-out infinite;
+  }
+  .beacon-source {
+    position: absolute;
+    left: 50%;
+    bottom: 10vh;
+    width: 36vmin;
+    height: 12vmin;
+    transform: translateX(-50%);
+    background: radial-gradient(closest-side, rgba(0,146,255,0.28), rgba(0,146,255,0.08) 60%, transparent 70%);
+    filter: blur(14px);
+    opacity: 0.6;
+    pointer-events: none;
+  }
+
+  /* Distant beacon cone (perspective beam) */
+  .beacon-cone {
+    position: absolute;
+    left: 50%;
+    bottom: -10vh;
+    transform: translateX(-50%) perspective(800px) rotateX(60deg);
+    width: 4px;
+    height: 130vh;
+    background: linear-gradient(
+      180deg,
+      rgba(0, 146, 255, 0.0) 0%,
+      rgba(0, 146, 255, 0.28) 30%,
+      rgba(0, 146, 255, 0.18) 70%,
+      rgba(0, 146, 255, 0.0) 100%
+    );
+    box-shadow: 0 0 40px 6px rgba(0,146,255,0.18), 0 0 120px 24px rgba(0,146,255,0.10);
+    filter: blur(2px);
+    pointer-events: none;
+    opacity: 0.55;
+  }
+
+  /* Beacon outline (SVG stroke glow) */
+  .beacon-outline {
+    position: absolute;
+    left: 50%;
+    bottom: 6vh;
+    transform: translateX(-50%);
+    width: clamp(120px, 22vmin, 220px);
+    height: auto;
+    opacity: 0.8;
+    pointer-events: none;
+  }
+
+  /* Custom Pagefind Search Styles */
+  .pagefind-search {
+    position: relative;
+    z-index: 10000;
+  }
+
+  .pagefind-search-overlay {
+    position: fixed;
+    top: 0;
+    left: 0;
+    right: 0;
+    bottom: 0;
+    background: rgba(0, 0, 0, 0.8);
+    backdrop-filter: blur(8px);
+    z-index: 10000;
+    display: flex;
+    align-items: flex-start;
+    justify-content: center;
+    padding-top: 10vh;
+  }
+
+  .pagefind-search-container {
+    background: rgba(255, 255, 255, 0.1);
+    border: 1px solid rgba(255, 255, 255, 0.2);
+    border-radius: 12px;
+    backdrop-filter: blur(10px);
+    min-width: 600px;
+    max-width: 90vw;
+    max-height: 80vh;
+    overflow: hidden;
+  }
+
+  .pagefind-search-input {
+    background: transparent;
+    border: none;
+    outline: none;
+    color: rgba(255, 255, 255, 0.9);
+    font-size: 16px;
+    flex: 1;
+    min-width: 0;
+  }
+
+  .pagefind-search-result {
+    padding: 16px 20px;
+    border-bottom: 1px solid rgba(255, 255, 255, 0.05);
+    cursor: pointer;
+    transition: background-color 0.2s ease;
+  }
+
+  .pagefind-search-result:hover {
+    background: rgba(255, 255, 255, 0.1);
+  }
+
+  .pagefind-search-result:last-child {
+    border-bottom: none;
+  }
+
+  /* Universal stronger focus-visible ring*/
+  :focus-visible {
+    outline: none !important; 
+    box-shadow: 0 0 0 2px var(--focus-inner-ring, #000), 0 0 0 4px var(--focus-outer-ring, #fff);
+    /* match the element's radius so rings follow shape */
+    border-radius: inherit;
+  }
+}
diff --git a/ecosystem/AI-Tooling/beacon/app/layout.tsx b/ecosystem/AI-Tooling/beacon/app/layout.tsx
new file mode 100644
index 00000000..a7a63118
--- /dev/null
+++ b/ecosystem/AI-Tooling/beacon/app/layout.tsx
@@ -0,0 +1,120 @@
+/*
+* Licensed to the Apache Software Foundation (ASF) under one
+* or more contributor license agreements.  See the NOTICE file
+* distributed with this work for additional information
+* regarding copyright ownership.  The ASF licenses this file
+* to you under the Apache License, Version 2.0 (the
+* "License"); you may not use this file except in compliance
+* with the License.  You may obtain a copy of the License at
+* 
+*   http://www.apache.org/licenses/LICENSE-2.0
+* 
+* Unless required by applicable law or agreed to in writing,
+* software distributed under the License is distributed on an
+* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+* KIND, either express or implied.  See the License for the
+* specific language governing permissions and limitations
+* under the License.
+*/
+
+import { MantineFooter, MantineNavBar } from '@/components';
+
+import '@gfazioli/mantine-marquee/styles.layer.css';
+import '@gfazioli/mantine-text-animate/styles.layer.css';
+
+import { ColorSchemeScript, mantineHtmlProps, MantineProvider } from '@mantine/core';
+
+import { Layout } from 'nextra-theme-docs';
+import { Banner, Head } from 'nextra/components';
+import { getPageMap } from 'nextra/page-map';
+import { theme } from '../theme';
+import { Inter } from 'next/font/google';
+
+import './global.css';
+
+import { FloatingAssistant } from '@/components/FloatingAssistant';
+import { PocketFlowChatbot } from '@/components/PocketFlowChatbot';
+import { Providers } from './providers';
+
+const inter = Inter({ subsets: ['latin'], variable: '--font-sans' });
+
+export const metadata = {
+  title: {
+    default: 'Beacon - NextGen Docs for Nexres',
+    template: '%s | ResilientDB Documentation',
+  },
+  description:
+    'Official documentation for ResilientDB, a high-performance, scalable blockchain database for mission-critical applications.',
+  metadataBase: new URL('https://resilientdb.com/'),
+  keywords: [
+    'ResilientDB',
+    'Blockchain',
+    'Database',
+    'Distributed Systems',
+    'Consensus',
+    'PBFT',
+    'Next.js',
+    'Mantine',
+    'Nextra',
+    'Documentation',
+  ],
+  generator: 'Next.js',
+  applicationName: 'ResilientDB',
+  appleWebApp: {
+    title: 'ResilientDB',
+  },
+  openGraph: {
+    url: 'https://resilientdb.com/',
+    siteName: 'ResilientDB',
+    locale: 'en_US',
+    type: 'website',
+  },
+  other: {
+    'msapplication-TileColor': '#fff',
+  },
+  twitter: {
+    site: 'https://resilientdb.com/',
+  },
+  alternates: {
+    canonical: 'https://resilientdb.com/',
+  },
+};
+
+export default async function RootLayout({ children }: { children: any }) {
+  const pageMap = await getPageMap();
+
+  return (
+    <html lang="en" dir="ltr" {...mantineHtmlProps} className={`${inter.className} ${inter.variable}`}>
+      <Head>
+        <ColorSchemeScript nonce="8IBTHwOdqNKAWeKl7plt8g==" defaultColorScheme="dark" />
+        <link rel="shortcut icon" href="/favicon.svg" type="image/svg+xml" />
+        <meta
+          name="viewport"
+          content="minimum-scale=1, initial-scale=1, width=device-width, user-scalable=no"
+        />
+      </Head>
+      <body>
+        <Providers>
+          <MantineProvider theme={theme} defaultColorScheme="dark">
+            <Layout
+              // banner={
+              //   <Banner storageKey="mantine-nextjs-nextra">
+              //     ✨ AI powered documentation for ResilientDB Ecosystem and Apps
+              //   </Banner>
+              // }
+              navbar={<MantineNavBar />}
+              pageMap={pageMap}
+              docsRepositoryBase="https://github.com/shuding/nextra/tree/main/docs"
+              footer={<MantineFooter />}
+              sidebar={{ defaultMenuCollapseLevel: 1, toggleButton: true }}
+            >
+              {children}
+            </Layout>
+            <FloatingAssistant />
+            {/* <PocketFlowChatbot /> */}
+          </MantineProvider>
+        </Providers>
+      </body>
+    </html>
+  );
+}
diff --git a/ecosystem/AI-Tooling/beacon/app/lib/constants.ts b/ecosystem/AI-Tooling/beacon/app/lib/constants.ts
new file mode 100644
index 00000000..c46bf8f0
--- /dev/null
+++ b/ecosystem/AI-Tooling/beacon/app/lib/constants.ts
@@ -0,0 +1,350 @@
+/*
+* Licensed to the Apache Software Foundation (ASF) under one
+* or more contributor license agreements.  See the NOTICE file
+* distributed with this work for additional information
+* regarding copyright ownership.  The ASF licenses this file
+* to you under the Apache License, Version 2.0 (the
+* "License"); you may not use this file except in compliance
+* with the License.  You may obtain a copy of the License at
+* 
+*   http://www.apache.org/licenses/LICENSE-2.0
+* 
+* Unless required by applicable law or agreed to in writing,
+* software distributed under the License is distributed on an
+* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+* KIND, either express or implied.  See the License for the
+* specific language governing permissions and limitations
+* under the License.
+*/
+
+export const PYTHON_SDK_EXAMPLE_TEMPLATES = [
+  {
+    value: 'default',
+    label: 'Welcome - Start Here',
+    code: `"""
+Welcome to the ResilientDB Python Playground!
+
+This interactive environment allows you to test and experiment with ResilientDB's key-value store 
+using our Python SDK. The code here matches the patterns used in the official ResilientDB Python SDK.
+
+Available Features:
+1. Basic Transaction Operations
+   - Create simple transactions
+   - Create transactions with metadata
+   - Retrieve transactions by ID
+
+Choose an example from the dropdown menu above to get started!
+
+Note: Each transaction needs a unique ID. Our examples use timestamps to ensure uniqueness.
+"""`,
+  },
+  {
+    value: 'send_transaction',
+    label: 'Send Simple Transaction',
+    code: `"""
+Example: Create and send a simple transaction (without metadata)
+"""
+from resdb_sdk import ResilientDB, Transaction
+import json
+import time
+
+# Initialize ResilientDB client
+client = ResilientDB('https://crow.resilientdb.com')
+
+# Create unique ID using timestamp
+unique_id = f"test_{int(time.time())}"
+
+# Create transaction (without metadata)
+transaction = Transaction(
+    id=unique_id,
+    value="Hello from ResilientDB!"
+)
+
+print(f"Creating transaction with ID: {unique_id}")
+print("Transaction data:")
+print(json.dumps(transaction.to_dict(), indent=2))
+
+print("\\nSending transaction...")
+result = await client.transactions.create(transaction)
+print("Response:")
+print(json.dumps(result, indent=2))`,
+  },
+  {
+    value: 'send_transaction_with_metadata',
+    label: 'Send Transaction with Metadata',
+    code: `"""
+Example: Create and send a transaction with metadata
+"""
+from resdb_sdk import ResilientDB, Transaction, TransactionMetadata
+import json
+import time
+
+# Initialize ResilientDB client
+client = ResilientDB('https://crow.resilientdb.com')
+
+# Create unique ID using timestamp
+unique_id = f"test_{int(time.time())}"
+
+# Create metadata
+metadata = TransactionMetadata(
+    timestamp=time.time(),
+    source="playground",
+    tags=["test", "example"]
+)
+
+# Create transaction with metadata
+transaction = Transaction(
+    id=unique_id,
+    value="Hello from ResilientDB!",
+    metadata=metadata
+)
+
+print(f"Creating transaction with ID: {unique_id}")
+print("Transaction data:")
+print(json.dumps(transaction.to_dict(), indent=2))
+
+print("\\nSending transaction...")
+result = await client.transactions.create(transaction)
+print("Response:")
+print(json.dumps(result, indent=2))`,
+  },
+  {
+    value: 'get_transaction',
+    label: 'Get Transaction',
+    code: `"""
+Example: Retrieve a transaction from ResilientDB
+"""
+from resdb_sdk import ResilientDB
+import json
+
+# Initialize ResilientDB client
+client = ResilientDB('https://crow.resilientdb.com')
+
+# Transaction ID to retrieve
+tx_id = "test_1234567890"
+
+print(f"Retrieving transaction with ID: {tx_id}")
+print("\\nSending GET request...")
+
+result = await client.transactions.retrieve(tx_id)
+print("\\nResponse:")
+print(json.dumps(result, indent=2))`,
+  },
+  {
+    value: 'complete_workflow',
+    label: 'Complete Workflow',
+    code: `"""
+Example: Complete workflow demonstrating transaction creation and retrieval
+"""
+from resdb_sdk import ResilientDB, Transaction, TransactionMetadata
+import json
+import time
+
+# Initialize ResilientDB client
+client = ResilientDB('https://crow.resilientdb.com')
+
+# Step 1: Create and send transaction
+print("Step 1: Creating and sending transaction...")
+
+# Generate unique ID using timestamp
+unique_id = f"test_{int(time.time())}"
+
+# Create metadata
+metadata = TransactionMetadata(
+    timestamp=time.time(),
+    source="playground",
+    workflow="complete_example"
+)
+
+# Create transaction
+transaction = Transaction(
+    id=unique_id,
+    value="Complete workflow test",
+    metadata=metadata
+)
+
+print(f"Transaction ID: {unique_id}")
+print("Transaction data:")
+print(json.dumps(transaction.to_dict(), indent=2))
+
+# Send transaction
+send_result = await client.transactions.create(transaction)
+print("\\nPOST Response:")
+print(json.dumps(send_result, indent=2))
+
+# Step 2: Retrieve the transaction
+print("\\nStep 2: Retrieving the transaction...")
+get_result = await client.transactions.retrieve(unique_id)
+print("GET Response:")
+print(json.dumps(get_result, indent=2))
+
+print("\\nWorkflow complete!")`,
+  },
+];
+
+export const RESILIENTDB_GRAPHQL_EXAMPLE_TEMPLATES = [
+  {
+    value: 'rest_api_examples',
+    label: 'Rest API Examples',
+    code: `
+from pyodide.http import pyfetch
+import json
+
+# Initialize connection
+BASE_URL = 'https://crow.resilientdb.com/v1'
+
+# Set a transaction
+async def set_transaction(key, value):
+    response = await pyfetch(
+        f'{BASE_URL}/transactions/commit',
+        method='POST',
+        headers={'Content-Type': 'application/json'},
+        body=json.dumps({
+            'id': key,
+            'value': value
+        })
+    )
+    return await response.json()
+
+# Get a transaction
+async def get_transaction(key):
+    response = await pyfetch(f'{BASE_URL}/transactions/{key}')
+    return await response.json()
+
+# Example usage
+async def main():
+    # Set a transaction
+    result = await set_transaction('test_key', 'test_value')
+    print('Set result:', result)
+    
+    # Get a transaction
+    value = await get_transaction('test_key')
+    print('Get result:', value)
+
+# Run the example
+await main()
+`,
+  },
+  {
+    value: 'graphql_query_example',
+    label: 'Get Transaction (Query)',
+    code: `
+from pyodide.http import pyfetch
+import json
+
+# GraphQL endpoint
+url = "https://cloud.resilientdb.com/graphql"
+
+# Query and variables
+query = """
+query GetTx($id: ID!) {
+    getTransaction(id: $id) {
+        id
+        version
+        amount
+        uri
+        type
+        publicKey
+        operation
+        metadata
+        asset
+        signerPublicKey
+    }
+}
+"""
+
+variables = {
+    "id": "6358ee73fb6bf5c659676ccc8476ebb6ea738b47a101661697ef379e5ea0212b"
+}
+
+# Prepare the payload
+payload = {
+    "query": query,
+    "variables": variables
+}
+
+async def get_transaction():
+    # Make the request
+    response = await pyfetch(
+        url,
+        method="POST",
+        headers={"Content-Type": "application/json"},
+        body=json.dumps(payload)
+    )
+    
+    # Get and print the response
+    result = await response.json()
+    print(json.dumps(result, indent=2))
+
+# Run the example
+await get_transaction()
+`,
+  },
+  {
+    value: 'graphql_mutation_example',
+    label: 'Create Transaction (Mutation)',
+    code: `
+from pyodide.http import pyfetch
+import json
+
+# GraphQL endpoint
+url = "https://cloud.resilientdb.com/graphql"
+
+# Drawing ID for the asset
+drawing_id = "drawing_testing_random_seed"
+
+# Mutation and variables
+mutation = """
+mutation Test($data: PrepareAsset!) {
+    postTransaction(data: $data) {
+        id
+    }
+}
+"""
+
+variables = {
+    "data": {
+        "operation": "CREATE",
+        "amount": 1,
+        "signerPublicKey": "FbUGKzKnSgh6bKRw8sxdzaCq1NMjGT6FVeAWLot5bCa1",
+        "signerPrivateKey": "5EzirRSQvWHwtekrg4TYtxBbdJbtgvG25pepGZRWJneC",
+        "recipientPublicKey": "FbUGKzKnSgh6bKRw8sxdzaCq1NMjGT6FVeAWLot5bCa1",
+        "asset": {
+            "data": {
+                "drawingId": drawing_id,
+                "color": "#000000",
+                "lineWidth": 5,
+                "pathData": [{"x": 292, "y": 126}],
+                "timestamp": 1746736411543,
+                "user": "appleseed|1746736304144",
+                "brushStyle": "round",
+                "order": 1746736411543
+            }
+        }
+    }
+}
+
+async def create_transaction():
+    # Prepare the payload
+    payload = {
+        "query": mutation,
+        "variables": variables
+    }
+    
+    # Make the request
+    response = await pyfetch(
+        url,
+        method="POST",
+        headers={"Content-Type": "application/json"},
+        body=json.dumps(payload)
+    )
+    
+    # Get and print the response
+    result = await response.json()
+    print(json.dumps(result, indent=2))
+
+# Run the example
+await create_transaction()
+`,
+  },
+];
diff --git a/ecosystem/AI-Tooling/beacon/app/lib/utils.ts b/ecosystem/AI-Tooling/beacon/app/lib/utils.ts
new file mode 100644
index 00000000..09569c07
--- /dev/null
+++ b/ecosystem/AI-Tooling/beacon/app/lib/utils.ts
@@ -0,0 +1,22 @@
+/*
+* Licensed to the Apache Software Foundation (ASF) under one
+* or more contributor license agreements.  See the NOTICE file
+* distributed with this work for additional information
+* regarding copyright ownership.  The ASF licenses this file
+* to you under the Apache License, Version 2.0 (the
+* "License"); you may not use this file except in compliance
+* with the License.  You may obtain a copy of the License at
+* 
+*   http://www.apache.org/licenses/LICENSE-2.0
+* 
+* Unless required by applicable law or agreed to in writing,
+* software distributed under the License is distributed on an
+* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+* KIND, either express or implied.  See the License for the
+* specific language governing permissions and limitations
+* under the License.
+*/
+
+export function cn(...classes: (string | undefined | false | null)[]) {
+  return classes.filter(Boolean).join(' ');
+}
diff --git a/ecosystem/AI-Tooling/beacon/app/page.module.css b/ecosystem/AI-Tooling/beacon/app/page.module.css
new file mode 100644
index 00000000..ca5c4c9d
--- /dev/null
+++ b/ecosystem/AI-Tooling/beacon/app/page.module.css
@@ -0,0 +1,361 @@
+/*
+* Licensed to the Apache Software Foundation (ASF) under one
+* or more contributor license agreements.  See the NOTICE file
+* distributed with this work for additional information
+* regarding copyright ownership.  The ASF licenses this file
+* to you under the Apache License, Version 2.0 (the
+* "License"); you may not use this file except in compliance
+* with the License.  You may obtain a copy of the License at
+* 
+*   http://www.apache.org/licenses/LICENSE-2.0
+* 
+* Unless required by applicable law or agreed to in writing,
+* software distributed under the License is distributed on an
+* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+* KIND, either express or implied.  See the License for the
+* specific language governing permissions and limitations
+* under the License.
+*/
+
+.root {
+  min-height: 100vh;
+  background: linear-gradient(135deg, #1a1b23 0%, #25262b 50%, #1a1b23 100%);
+  transition: background 0.3s ease;
+}
+
+/* Light mode for root */
+:global([data-mantine-color-scheme="light"]) .root {
+  background: linear-gradient(135deg, #f8fafc 0%, #e2e8f0 25%, #cbd5e1 50%, #e2e8f0 75%, #f8fafc 100%);
+}
+  
+  .hero {
+  position: relative;
+  overflow: hidden;
+  padding: 5rem 0;
+  background: linear-gradient(135deg, #1a1b23 0%, #25262b 50%, #1a1b23 100%);
+  transition: background 0.3s ease;
+}
+
+/* Light mode for hero */
+:global([data-mantine-color-scheme="light"]) .hero {
+  background: linear-gradient(135deg, #f1f5f9 0%, #e2e8f0 25%, #cbd5e1 50%, #e2e8f0 75%, #f1f5f9 100%);
+  box-shadow: inset 0 1px 0 rgba(255, 255, 255, 0.8), inset 0 -1px 0 rgba(0, 0, 0, 0.05);
+}
+  
+  .heroGrid {
+    position: absolute;
+    inset: 0;
+    background-image: radial-gradient(circle, rgba(255, 255, 255, 0.02) 1px, transparent 1px);
+    background-size: 50px 50px;
+  }
+  
+  .heroContainer {
+    position: relative;
+    z-index: 1;
+  }
+  
+  .heroTitle {
+    font-size: clamp(3rem, 10vw, 6rem);
+    font-weight: 800;
+    color: white;
+    line-height: 1.1;
+    transition: color 0.3s ease;
+  }
+
+  /* Light mode hero title */
+  :global([data-mantine-color-scheme="light"]) .heroTitle {
+    color: #0f172a !important;
+    text-shadow: 0 2px 4px rgba(0, 0, 0, 0.1) !important;
+  }
+
+  .description {
+    color: rgba(255, 255, 255, 0.8);
+    transition: color 0.3s ease;
+  }
+
+  /* Light mode description */
+  :global([data-mantine-color-scheme="light"]) .description {
+    color: #475057 !important;
+  }
+
+  .cardTitle {
+    color: white;
+    transition: color 0.3s ease;
+  }
+
+  /* Light mode card title */
+  :global([data-mantine-color-scheme="light"]) .cardTitle {
+    color: #0f172a !important;
+  }
+
+  .cardDescription {
+    color: rgba(255, 255, 255, 0.7);
+    transition: color 0.3s ease;
+  }
+
+  /* Light mode card description */
+  :global([data-mantine-color-scheme="light"]) .cardDescription {
+    color: #64748b !important;
+  }
+  
+  .gradientText {
+    background: linear-gradient(45deg, var(--mantine-color-pink-4), var(--mantine-color-red-4), var(--mantine-color-orange-4));
+    background-clip: text;
+    -webkit-background-clip: text;
+    -webkit-text-fill-color: transparent;
+    animation: pulse 2s ease-in-out infinite;
+  }
+  
+  @keyframes pulse {
+  0%, 100% { opacity: 1; }
+  50% { opacity: 0.8; }
+}
+
+.animatedGradient {
+  background: linear-gradient(-45deg, #ee7752, #e73c7e, #23a6d5, #23d5ab);
+  background-size: 400% 400%;
+  background-clip: text;
+  -webkit-background-clip: text;
+  -webkit-text-fill-color: transparent;
+  animation: gradientShift 6s ease infinite, pulse 2s ease-in-out infinite;
+}
+
+@keyframes gradientShift {
+  0% {
+    background-position: 0% 50%;
+  }
+  50% {
+    background-position: 100% 50%;
+  }
+  100% {
+    background-position: 0% 50%;
+  }
+}
+  
+  .link {
+    transition: color 0.2s ease;
+  }
+  
+  .link:hover {
+    color: var(--mantine-color-pink-3) !important;
+  }
+  
+  .primaryButton {
+    transition: all 0.3s ease;
+    border: 1px solid var(--mantine-color-gray-6);
+  }
+  
+  .primaryButton:hover {
+    transform: scale(1.05);
+  }
+  
+  .secondaryButton {
+    background: rgba(var(--mantine-color-dark-8-rgb), 0.5);
+    backdrop-filter: blur(10px);
+    transition: all 0.3s ease;
+  }
+  
+  .secondaryButton:hover {
+    background: var(--mantine-color-dark-7);
+    color: white;
+    border-color: var(--mantine-color-gray-5);
+  }
+  
+  .terminalCard {
+    background: var(--mantine-color-dark-9);
+    border: 1px solid var(--mantine-color-dark-6);
+    max-width: 800px;
+    margin: 0 auto;
+  }
+  
+  .terminalDot {
+    width: 12px;
+    height: 12px;
+    border-radius: 50%;
+  }
+  
+  .terminalContent {
+    color: var(--mantine-color-teal-4);
+    font-family: 'Monaco', 'Menlo', 'Ubuntu Mono', monospace;
+    font-size: 0.875rem;
+    line-height: 1.6;
+    white-space: pre-wrap;
+    height: 250px;
+    max-height: 250px;
+    overflow-y: auto;
+    margin: 0;
+    padding: 1rem;
+    scrollbar-width: thin;
+    scrollbar-color: var(--mantine-color-dark-6) var(--mantine-color-dark-9);
+  }
+
+  /* Custom scrollbar styles for webkit browsers */
+  .terminalContent::-webkit-scrollbar {
+    width: 8px;
+  }
+
+  .terminalContent::-webkit-scrollbar-track {
+    background: var(--mantine-color-dark-9);
+    border-radius: 4px;
+  }
+
+  .terminalContent::-webkit-scrollbar-thumb {
+    background: var(--mantine-color-dark-6);
+    border-radius: 4px;
+  }
+
+  .terminalContent::-webkit-scrollbar-thumb:hover {
+    background: var(--mantine-color-dark-5);
+  }
+  
+  .carouselContainer {
+    position: relative;
+    width: 100%;
+    max-width: 1400px;
+  }
+  
+  .carouselArrow {
+    position: absolute;
+    top: 50%;
+    transform: translateY(-50%);
+    z-index: 20;
+    backdrop-filter: blur(10px);
+    transition: all 0.3s ease;
+  }
+  
+  .leftArrow {
+    left: 1rem;
+  }
+  
+  .rightArrow {
+    right: 1rem;
+  }
+  
+  .arrowActive {
+    background: rgba(var(--mantine-color-dark-8-rgb), 0.9);
+    border-color: var(--mantine-color-gray-6);
+    color: white;
+  }
+  
+  .arrowActive:hover {
+    background: var(--mantine-color-dark-7);
+    border-color: var(--mantine-color-gray-5);
+  }
+  
+  .arrowDisabled {
+    background: rgba(var(--mantine-color-dark-9-rgb), 0.5);
+    border-color: rgba(var(--mantine-color-dark-7-rgb), 0.5);
+    color: var(--mantine-color-gray-7);
+    cursor: not-allowed;
+  }
+  
+  .carouselWrapper {
+    overflow: visible;
+    padding: 0 5rem;
+  }
+  
+  .carouselTrack {
+    transition: transform 0.7s cubic-bezier(0.4, 0, 0.2, 1);
+    justify-content: flex-start;
+  }
+  
+  .cardWrapper {
+    flex-shrink: 0;
+    padding: 0 0.75rem;
+    transition: all 0.5s cubic-bezier(0.4, 0, 0.2, 1);
+  }
+  
+  .projectCard {
+    background: rgba(var(--mantine-color-dark-8-rgb), 0.3);
+    border: 1px solid rgba(var(--mantine-color-gray-6-rgb), 0.5);
+    transition: all 0.5s ease;
+    position: relative;
+  }
+  
+  .projectCard:hover {
+    border-color: var(--mantine-color-gray-5);
+    background: rgba(var(--mantine-color-dark-8-rgb), 0.5);
+  }
+
+  /* Light mode project cards */
+  :global([data-mantine-color-scheme="light"]) .projectCard {
+    background: rgba(15, 23, 42, 0.1) !important;
+    border: 1px solid rgba(15, 23, 42, 0.2) !important;
+    box-shadow: 0 2px 8px rgba(0, 0, 0, 0.1) !important;
+  }
+
+  :global([data-mantine-color-scheme="light"]) .projectCard:hover {
+    background: rgba(15, 23, 42, 0.15) !important;
+    border-color: rgba(15, 23, 42, 0.3) !important;
+    box-shadow: 0 4px 12px rgba(0, 0, 0, 0.15) !important;
+  }
+  
+  .iconWrapper {
+    width: 48px;
+    height: 48px;
+    background: linear-gradient(135deg, var(--mantine-color-gray-6), var(--mantine-color-gray-7));
+    border-radius: var(--mantine-radius-md);
+    display: flex;
+    align-items: center;
+    justify-content: center;
+    color: var(--mantine-color-gray-2);
+    transition: transform 0.3s ease;
+  }
+  
+  .projectCard:hover .iconWrapper {
+    transform: rotate(12deg);
+  }
+
+  /* Light mode icon wrapper */
+  :global([data-mantine-color-scheme="light"]) .iconWrapper {
+    background: linear-gradient(135deg, #475569, #64748b) !important;
+    color: #f8fafc !important;
+    box-shadow: 0 2px 4px rgba(0, 0, 0, 0.1) !important;
+  }
+  
+  .projectButton {
+    border: 1px solid rgba(var(--mantine-color-gray-5-rgb), 0.5);
+    transition: all 0.3s ease;
+  }
+  
+  .projectButton:hover {
+    border-color: var(--mantine-color-gray-4);
+  }
+  
+  .dot {
+    width: 8px;
+    height: 8px;
+    border-radius: 50%;
+    background: var(--mantine-color-gray-6);
+    border: none;
+    cursor: pointer;
+    transition: all 0.3s ease;
+  }
+  
+  .dot:hover {
+    background: var(--mantine-color-gray-5);
+  }
+  
+  .dotActive {
+    background: var(--mantine-color-pink-4);
+    width: 32px;
+    border-radius: 4px;
+  }
+  
+  @media (max-width: 768px) {
+    .hero {
+      padding: 3rem 0;
+    }
+    
+    .heroTitle {
+      font-size: 2.5rem;
+    }
+    
+    .carouselWrapper {
+      padding: 0 3rem;
+    }
+    
+    .carouselArrow {
+      display: none;
+    }
+  }
\ No newline at end of file
diff --git a/ecosystem/AI-Tooling/beacon/app/page.tsx b/ecosystem/AI-Tooling/beacon/app/page.tsx
new file mode 100644
index 00000000..c926fa48
--- /dev/null
+++ b/ecosystem/AI-Tooling/beacon/app/page.tsx
@@ -0,0 +1,36 @@
+/*
+* Licensed to the Apache Software Foundation (ASF) under one
+* or more contributor license agreements.  See the NOTICE file
+* distributed with this work for additional information
+* regarding copyright ownership.  The ASF licenses this file
+* to you under the Apache License, Version 2.0 (the
+* "License"); you may not use this file except in compliance
+* with the License.  You may obtain a copy of the License at
+* 
+*   http://www.apache.org/licenses/LICENSE-2.0
+* 
+* Unless required by applicable law or agreed to in writing,
+* software distributed under the License is distributed on an
+* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+* KIND, either express or implied.  See the License for the
+* specific language governing permissions and limitations
+* under the License.
+*/
+
+import { Container } from '@mantine/core';
+import ShaderBackground from '@/components/landing/ShaderBackground';
+import PulsingCircle from '@/components/landing/PulsingCircle';
+import HeroContent from '@/components/landing/HeroContent';
+import Header from '@/components/landing/Header';
+
+export default function HomePage() {
+  return (
+    <Container p={0} size="100%" style={{ maxWidth: '100%' }}>
+      <ShaderBackground>
+        <Header />
+        <HeroContent />
+        <PulsingCircle />
+      </ShaderBackground>
+    </Container>
+  );
+}
diff --git a/ecosystem/AI-Tooling/beacon/app/providers.tsx b/ecosystem/AI-Tooling/beacon/app/providers.tsx
new file mode 100644
index 00000000..5439fd46
--- /dev/null
+++ b/ecosystem/AI-Tooling/beacon/app/providers.tsx
@@ -0,0 +1,26 @@
+/*
+* Licensed to the Apache Software Foundation (ASF) under one
+* or more contributor license agreements.  See the NOTICE file
+* distributed with this work for additional information
+* regarding copyright ownership.  The ASF licenses this file
+* to you under the Apache License, Version 2.0 (the
+* "License"); you may not use this file except in compliance
+* with the License.  You may obtain a copy of the License at
+* 
+*   http://www.apache.org/licenses/LICENSE-2.0
+* 
+* Unless required by applicable law or agreed to in writing,
+* software distributed under the License is distributed on an
+* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+* KIND, either express or implied.  See the License for the
+* specific language governing permissions and limitations
+* under the License.
+*/
+
+'use client';
+
+import { SessionProvider } from 'next-auth/react';
+
+export function Providers({ children }: { children: React.ReactNode }) {
+  return <SessionProvider>{children}</SessionProvider>;
+}
diff --git a/ecosystem/AI-Tooling/beacon/app/search/page.tsx b/ecosystem/AI-Tooling/beacon/app/search/page.tsx
new file mode 100644
index 00000000..3688da15
--- /dev/null
+++ b/ecosystem/AI-Tooling/beacon/app/search/page.tsx
@@ -0,0 +1,44 @@
+/*
+* Licensed to the Apache Software Foundation (ASF) under one
+* or more contributor license agreements.  See the NOTICE file
+* distributed with this work for additional information
+* regarding copyright ownership.  The ASF licenses this file
+* to you under the Apache License, Version 2.0 (the
+* "License"); you may not use this file except in compliance
+* with the License.  You may obtain a copy of the License at
+* 
+*   http://www.apache.org/licenses/LICENSE-2.0
+* 
+* Unless required by applicable law or agreed to in writing,
+* software distributed under the License is distributed on an
+* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+* KIND, either express or implied.  See the License for the
+* specific language governing permissions and limitations
+* under the License.
+*/
+
+'use client'
+
+import { PagefindSearch } from '../../components/SearchBar/PagefindSearch';
+
+export default function SearchPage() {
+  return (
+    <div style={{ 
+      minHeight: '100vh', 
+      background: 'transparent',
+      padding: '20px'
+    }}>
+      <div style={{ maxWidth: 800, margin: '0 auto' }}>
+        <h1 style={{ 
+          color: 'rgba(255, 255, 255, 0.9)', 
+          marginBottom: '20px',
+          fontSize: '2rem',
+          fontWeight: 600
+        }}>
+          Search Documentation
+        </h1>
+        <PagefindSearch />
+      </div>
+    </div>
+  );
+}
diff --git a/ecosystem/AI-Tooling/beacon/app/sitemap.ts b/ecosystem/AI-Tooling/beacon/app/sitemap.ts
new file mode 100644
index 00000000..2424c800
--- /dev/null
+++ b/ecosystem/AI-Tooling/beacon/app/sitemap.ts
@@ -0,0 +1,95 @@
+/*
+* Licensed to the Apache Software Foundation (ASF) under one
+* or more contributor license agreements.  See the NOTICE file
+* distributed with this work for additional information
+* regarding copyright ownership.  The ASF licenses this file
+* to you under the Apache License, Version 2.0 (the
+* "License"); you may not use this file except in compliance
+* with the License.  You may obtain a copy of the License at
+* 
+*   http://www.apache.org/licenses/LICENSE-2.0
+* 
+* Unless required by applicable law or agreed to in writing,
+* software distributed under the License is distributed on an
+* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+* KIND, either express or implied.  See the License for the
+* specific language governing permissions and limitations
+* under the License.
+*/
+
+import { MetadataRoute } from 'next';
+
+export default function sitemap(): MetadataRoute.Sitemap {
+  const baseUrl = 'https://beacon.resilientdb.com';
+
+  const routes = [
+    {
+      url: baseUrl,
+      lastModified: new Date(),
+      changeFrequency: 'daily' as const,
+      priority: 0.5,
+    },
+    {
+      url: `${baseUrl}/docs`,
+      lastModified: new Date(),
+      changeFrequency: 'weekly' as const,
+      priority: 1,
+    },
+    {
+      url: `${baseUrl}/docs/resilientdb`,
+      lastModified: new Date(),
+      changeFrequency: 'monthly' as const,
+      priority: 1,
+    },
+    {
+      url: `${baseUrl}/docs/resilientdb/chapters/01_client_interaction`,
+      lastModified: new Date(),
+      changeFrequency: 'weekly' as const,
+      priority: 1,
+    },
+    {
+      url: `${baseUrl}/docs/resilientdb/chapters/02_network_communication`,
+      lastModified: new Date(),
+      changeFrequency: 'weekly' as const,
+      priority: 1,
+    },
+    {
+      url: `${baseUrl}/docs/resilientdb/chapters/03_consensus_management`,
+      lastModified: new Date(),
+      changeFrequency: 'weekly' as const,
+      priority: 1,
+    },
+    {
+      url: `${baseUrl}/docs/resilientdb/chapters/04_message_transaction_collection`,
+      lastModified: new Date(),
+      changeFrequency: 'weekly' as const,
+      priority: 1,
+    },
+    {
+      url: `${baseUrl}/docs/resilientdb/chapters/05_transaction_execution`,
+      lastModified: new Date(),
+      changeFrequency: 'weekly' as const,
+      priority: 1,
+    },
+    {
+      url: `${baseUrl}/docs/resilientdb/chapters/06_storage_layer`,
+      lastModified: new Date(),
+      changeFrequency: 'weekly' as const,
+      priority: 1,
+    },
+    {
+      url: `${baseUrl}/docs/resilientdb/chapters/07_checkpointing`,
+      lastModified: new Date(),
+      changeFrequency: 'weekly' as const,
+      priority: 1,
+    },
+    {
+      url: `${baseUrl}/docs/resilientdb/chapters/08_resilientdb_configuration`,
+      lastModified: new Date(),
+      changeFrequency: 'weekly' as const,
+      priority: 1,
+    },
+  ];
+
+  return routes;
+}
diff --git a/ecosystem/AI-Tooling/beacon/asf.yaml b/ecosystem/AI-Tooling/beacon/asf.yaml
new file mode 100644
index 00000000..1d251083
--- /dev/null
+++ b/ecosystem/AI-Tooling/beacon/asf.yaml
@@ -0,0 +1,42 @@
+# Licensed to the Apache Software Foundation (ASF) under one or more
+# contributor license agreements.  See the NOTICE file distributed with
+# this work for additional information regarding copyright ownership.
+# The ASF licenses this file to You under the Apache License, Version 2.0
+# (the "License"); you may not use this file except in compliance with
+# the License.  You may obtain a copy of the License at
+#
+#     http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+#
+
+github:
+  description: Global-Scale Sustainable Blockchain Fabric
+  homepage: https://resilientdb.incubator.apache.org/
+  labels:
+    - crypto 
+    - smart-contracts 
+    - blockchain 
+    - solidity 
+    - distributed-database 
+    - key-value-database 
+    - distributed-ledger 
+    - blockchain-platform
+    - utxo
+  enabled_merge_buttons:
+    squash: true
+    merge: false
+    rebase: false
+  protected_branches:
+    main:
+      required_status_checks:
+        strict: true
+  
+notifications:
+  commits:      commits@resilientdb.apache.org
+  issues:       commits@resilientdb.apache.org
+  pullrequests: commits@resilientdb.apache.org
diff --git a/ecosystem/AI-Tooling/beacon/components/AskAIModal.tsx b/ecosystem/AI-Tooling/beacon/components/AskAIModal.tsx
new file mode 100644
index 00000000..d007f7bf
--- /dev/null
+++ b/ecosystem/AI-Tooling/beacon/components/AskAIModal.tsx
@@ -0,0 +1,137 @@
+/*
+* Licensed to the Apache Software Foundation (ASF) under one
+* or more contributor license agreements.  See the NOTICE file
+* distributed with this work for additional information
+* regarding copyright ownership.  The ASF licenses this file
+* to you under the Apache License, Version 2.0 (the
+* "License"); you may not use this file except in compliance
+* with the License.  You may obtain a copy of the License at
+* 
+*   http://www.apache.org/licenses/LICENSE-2.0
+* 
+* Unless required by applicable law or agreed to in writing,
+* software distributed under the License is distributed on an
+* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+* KIND, either express or implied.  See the License for the
+* specific language governing permissions and limitations
+* under the License.
+*/
+
+'use client'
+
+import { Button, Modal, TextInput, Stack, Text, Divider } from '@mantine/core';
+import { useDisclosure } from '@mantine/hooks';
+import { useEffect, useRef } from 'react';
+import { IconRobot, IconSearch } from '@tabler/icons-react';
+import { useRouter } from 'next/navigation';
+
+export function AskAIModal() {
+  const [opened, { open: openDisclosure, close: closeDisclosure }] = useDisclosure(false);
+  const triggerRef = useRef<HTMLButtonElement | null>(null);
+  const firstInputRef = useRef<HTMLInputElement | null>(null);
+  const lastFocusedRef = useRef<HTMLElement | null>(null);
+
+  const open = (from?: HTMLElement | null) => {
+    lastFocusedRef.current = from ?? (document.activeElement as HTMLElement | null);
+    openDisclosure();
+  };
+
+  const close = () => {
+    closeDisclosure();
+    // return focus to last focused element
+    setTimeout(() => {
+      try {
+        lastFocusedRef.current?.focus?.();
+      } catch (err) {}
+    }, 0);
+  };
+
+  // Add Escape handler while modal is open
+  useEffect(() => {
+    if (!opened) return;
+    const onKey = (e: KeyboardEvent) => {
+      if (e.key === 'Escape') {
+        e.preventDefault();
+        close();
+      }
+    };
+    document.addEventListener('keydown', onKey);
+    // focus first input when opened
+    setTimeout(() => firstInputRef.current?.focus(), 50);
+    return () => document.removeEventListener('keydown', onKey);
+  }, [opened]);
+  const router = useRouter();
+
+  const handleSearch = (query: string) => {
+    // This will navigate to the search page with the query
+    if (query) {
+      router.push(`/?q=${encodeURIComponent(query)}`);
+      close();
+    }
+  };
+
+  return (
+    <>
+      <Button 
+        ref={triggerRef}
+        onClick={(e) => open(e.currentTarget)}
+        onKeyDown={(e) => {
+          if (e.key === 'Enter' || e.key === ' ') {
+            e.preventDefault();
+            open(e.currentTarget as HTMLElement);
+          }
+        }}
+        leftSection={<IconRobot size={20} />}
+        variant="subtle"
+      >
+        Ask AI
+      </Button>
+
+      <Modal 
+        opened={opened} 
+        onClose={close} 
+        title="Ask AI Assistant" 
+        size="lg"
+      >
+        <Stack>
+          <Text size="sm" c="dimmed">
+            Ask me anything about ResilientDB and its ecosystem. I'm here to help!
+          </Text>
+          <TextInput
+            ref={firstInputRef}
+            placeholder="Ask the AI assistant..."
+            size="md"
+            leftSection={<IconRobot size={16} />}
+            onKeyDown={(e) => {
+              if (e.key === 'Enter') {
+                handleSearch((e.target as HTMLInputElement).value);
+              }
+            }}
+          />
+          <Text size="xs" c="dimmed">
+            Coming soon: Integration with ResilientDB's AI assistant for more intelligent responses.
+          </Text>
+
+          <Divider label="Or search the documentation" labelPosition="center" my="md" />
+
+          <Text size="sm" c="dimmed">
+            Search through our comprehensive documentation to find detailed information.
+          </Text>
+          <TextInput
+            placeholder="Search documentation..."
+            size="md"
+            leftSection={<IconSearch size={16} />}
+            onKeyDown={(e) => {
+              if (e.key === 'Enter') {
+                handleSearch((e.target as HTMLInputElement).value);
+              }
+            }}
+          />
+          <Text size="xs" c="dimmed">
+            Press Enter to search through the entire documentation.
+          </Text>
+        </Stack>
+      </Modal>
+    </>
+  );
+} 
\ No newline at end of file
diff --git a/ecosystem/AI-Tooling/beacon/components/AuthProviders.tsx b/ecosystem/AI-Tooling/beacon/components/AuthProviders.tsx
new file mode 100644
index 00000000..b65e224d
--- /dev/null
+++ b/ecosystem/AI-Tooling/beacon/components/AuthProviders.tsx
@@ -0,0 +1,32 @@
+/*
+* Licensed to the Apache Software Foundation (ASF) under one
+* or more contributor license agreements.  See the NOTICE file
+* distributed with this work for additional information
+* regarding copyright ownership.  The ASF licenses this file
+* to you under the Apache License, Version 2.0 (the
+* "License"); you may not use this file except in compliance
+* with the License.  You may obtain a copy of the License at
+* 
+*   http://www.apache.org/licenses/LICENSE-2.0
+* 
+* Unless required by applicable law or agreed to in writing,
+* software distributed under the License is distributed on an
+* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+* KIND, either express or implied.  See the License for the
+* specific language governing permissions and limitations
+* under the License.
+*/
+
+'use client';
+
+import { SessionProvider } from 'next-auth/react';
+import { MantineProvider } from '@mantine/core';
+import { theme } from '../theme';
+
+export function AuthProviders({ children }: { children: React.ReactNode }) {
+  return (
+    <SessionProvider>
+      <MantineProvider theme={theme}>{children}</MantineProvider>
+    </SessionProvider>
+  );
+}
diff --git a/ecosystem/AI-Tooling/beacon/components/ColorSchemeControl/ColorSchemeControl.module.css b/ecosystem/AI-Tooling/beacon/components/ColorSchemeControl/ColorSchemeControl.module.css
new file mode 100644
index 00000000..3a92eae4
--- /dev/null
+++ b/ecosystem/AI-Tooling/beacon/components/ColorSchemeControl/ColorSchemeControl.module.css
@@ -0,0 +1,46 @@
+/*
+* Licensed to the Apache Software Foundation (ASF) under one
+* or more contributor license agreements.  See the NOTICE file
+* distributed with this work for additional information
+* regarding copyright ownership.  The ASF licenses this file
+* to you under the Apache License, Version 2.0 (the
+* "License"); you may not use this file except in compliance
+* with the License.  You may obtain a copy of the License at
+* 
+*   http://www.apache.org/licenses/LICENSE-2.0
+* 
+* Unless required by applicable law or agreed to in writing,
+* software distributed under the License is distributed on an
+* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+* KIND, either express or implied.  See the License for the
+* specific language governing permissions and limitations
+* under the License.
+*/
+
+.icon {
+  width: 22px;
+  height: 22px;
+  transition: opacity 0.2s ease;
+}
+
+.dark {
+  display: block;
+}
+
+.light {
+  display: block;
+}
+
+/* Hide icons based on color scheme */
+:global([data-mantine-color-scheme="light"]) .dark {
+  display: none;
+}
+
+:global([data-mantine-color-scheme="dark"]) .light {
+  display: none;
+}
+
+/* Fallback for when no color scheme is set (default to dark) */
+:global(:root:not([data-mantine-color-scheme])) .light {
+  display: none;
+}
diff --git a/ecosystem/AI-Tooling/beacon/components/ColorSchemeControl/ColorSchemeControl.story.tsx b/ecosystem/AI-Tooling/beacon/components/ColorSchemeControl/ColorSchemeControl.story.tsx
new file mode 100644
index 00000000..01f56202
--- /dev/null
+++ b/ecosystem/AI-Tooling/beacon/components/ColorSchemeControl/ColorSchemeControl.story.tsx
@@ -0,0 +1,26 @@
+/*
+* Licensed to the Apache Software Foundation (ASF) under one
+* or more contributor license agreements.  See the NOTICE file
+* distributed with this work for additional information
+* regarding copyright ownership.  The ASF licenses this file
+* to you under the Apache License, Version 2.0 (the
+* "License"); you may not use this file except in compliance
+* with the License.  You may obtain a copy of the License at
+* 
+*   http://www.apache.org/licenses/LICENSE-2.0
+* 
+* Unless required by applicable law or agreed to in writing,
+* software distributed under the License is distributed on an
+* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+* KIND, either express or implied.  See the License for the
+* specific language governing permissions and limitations
+* under the License.
+*/
+
+import { ColorSchemeControl } from './ColorSchemeControl';
+
+export default {
+  title: 'ColorSchemeControl',
+};
+
+export const Usage = () => <ColorSchemeControl />;
diff --git a/ecosystem/AI-Tooling/beacon/components/ColorSchemeControl/ColorSchemeControl.tsx b/ecosystem/AI-Tooling/beacon/components/ColorSchemeControl/ColorSchemeControl.tsx
new file mode 100644
index 00000000..0eca3c57
--- /dev/null
+++ b/ecosystem/AI-Tooling/beacon/components/ColorSchemeControl/ColorSchemeControl.tsx
@@ -0,0 +1,49 @@
+/*
+* Licensed to the Apache Software Foundation (ASF) under one
+* or more contributor license agreements.  See the NOTICE file
+* distributed with this work for additional information
+* regarding copyright ownership.  The ASF licenses this file
+* to you under the Apache License, Version 2.0 (the
+* "License"); you may not use this file except in compliance
+* with the License.  You may obtain a copy of the License at
+* 
+*   http://www.apache.org/licenses/LICENSE-2.0
+* 
+* Unless required by applicable law or agreed to in writing,
+* software distributed under the License is distributed on an
+* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+* KIND, either express or implied.  See the License for the
+* specific language governing permissions and limitations
+* under the License.
+*/
+
+import { IconMoon, IconSun } from '@tabler/icons-react';
+import cx from 'clsx';
+import { useTheme } from 'nextra-theme-docs';
+import { useComputedColorScheme, useMantineColorScheme } from '@mantine/core';
+import { HeaderControl } from './HeaderControl';
+import classes from './ColorSchemeControl.module.css';
+
+export function ColorSchemeControl() {
+  const { setColorScheme } = useMantineColorScheme();
+  const { setTheme } = useTheme();
+
+  const computedColorScheme = useComputedColorScheme('dark', { getInitialValueInEffect: true });
+
+  const handleColorSchemeChange = () => {
+    const newColorScheme = computedColorScheme === 'light' ? 'dark' : 'light';
+    setColorScheme(newColorScheme);
+    setTheme(newColorScheme);
+  };
+
+  return (
+    <HeaderControl
+      onClick={handleColorSchemeChange}
+      tooltip={`${computedColorScheme === 'dark' ? 'Light' : 'Dark'} mode`}
+      aria-label="Toggle color scheme"
+    >
+      <IconSun className={cx(classes.icon, classes.light)} stroke={1.5} />
+      <IconMoon className={cx(classes.icon, classes.dark)} stroke={1.5} />
+    </HeaderControl>
+  );
+}
diff --git a/ecosystem/AI-Tooling/beacon/components/ColorSchemeControl/HeaderControl.module.css b/ecosystem/AI-Tooling/beacon/components/ColorSchemeControl/HeaderControl.module.css
new file mode 100644
index 00000000..9f0c4210
--- /dev/null
+++ b/ecosystem/AI-Tooling/beacon/components/ColorSchemeControl/HeaderControl.module.css
@@ -0,0 +1,50 @@
+/*
+* Licensed to the Apache Software Foundation (ASF) under one
+* or more contributor license agreements.  See the NOTICE file
+* distributed with this work for additional information
+* regarding copyright ownership.  The ASF licenses this file
+* to you under the Apache License, Version 2.0 (the
+* "License"); you may not use this file except in compliance
+* with the License.  You may obtain a copy of the License at
+* 
+*   http://www.apache.org/licenses/LICENSE-2.0
+* 
+* Unless required by applicable law or agreed to in writing,
+* software distributed under the License is distributed on an
+* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+* KIND, either express or implied.  See the License for the
+* specific language governing permissions and limitations
+* under the License.
+*/
+
+.control {
+  width: 34px;
+  height: 34px;
+  border-radius: var(--mantine-radius-md);
+  border: 1px solid var(--mantine-color-dark-4);
+  display: flex;
+  align-items: center;
+  justify-content: center;
+  transition: all 0.2s ease;
+  cursor: pointer;
+  
+  /* Default dark mode styles */
+  border-color: var(--mantine-color-dark-4);
+  color: var(--mantine-color-white);
+  background-color: var(--mantine-color-dark-6);
+}
+
+.control:hover {
+  background-color: var(--mantine-color-dark-5);
+}
+
+/* Light mode styles */
+:global([data-mantine-color-scheme="light"]) .control {
+  border-color: var(--mantine-color-gray-3);
+  color: var(--mantine-color-gray-7);
+  background-color: var(--mantine-color-white);
+}
+
+:global([data-mantine-color-scheme="light"]) .control:hover {
+  background-color: var(--mantine-color-gray-0);
+}
diff --git a/ecosystem/AI-Tooling/beacon/components/ColorSchemeControl/HeaderControl.tsx b/ecosystem/AI-Tooling/beacon/components/ColorSchemeControl/HeaderControl.tsx
new file mode 100644
index 00000000..ef73e9d3
--- /dev/null
+++ b/ecosystem/AI-Tooling/beacon/components/ColorSchemeControl/HeaderControl.tsx
@@ -0,0 +1,51 @@
+/*
+* Licensed to the Apache Software Foundation (ASF) under one
+* or more contributor license agreements.  See the NOTICE file
+* distributed with this work for additional information
+* regarding copyright ownership.  The ASF licenses this file
+* to you under the Apache License, Version 2.0 (the
+* "License"); you may not use this file except in compliance
+* with the License.  You may obtain a copy of the License at
+* 
+*   http://www.apache.org/licenses/LICENSE-2.0
+* 
+* Unless required by applicable law or agreed to in writing,
+* software distributed under the License is distributed on an
+* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+* KIND, either express or implied.  See the License for the
+* specific language governing permissions and limitations
+* under the License.
+*/
+
+'use client';
+
+import cx from 'clsx';
+import { BoxProps, createPolymorphicComponent, Tooltip, UnstyledButton } from '@mantine/core';
+import classes from './HeaderControl.module.css';
+
+export interface HeaderControlProps extends BoxProps {
+  tooltip: string;
+  'aria-label'?: string;
+  children: React.ReactNode;
+}
+
+function _HeaderControl({
+  tooltip,
+  className,
+  'aria-label': label,
+  ...others
+}: HeaderControlProps) {
+  return (
+    <Tooltip label={tooltip}>
+      <UnstyledButton
+        className={cx(classes.control, className)}
+        aria-label={label || tooltip}
+        {...others}
+      />
+    </Tooltip>
+  );
+}
+
+export const HeaderControl = createPolymorphicComponent<'button', HeaderControlProps>(
+  _HeaderControl
+);
diff --git a/ecosystem/AI-Tooling/beacon/components/ColorSchemeToggle/ColorSchemeToggle.tsx b/ecosystem/AI-Tooling/beacon/components/ColorSchemeToggle/ColorSchemeToggle.tsx
new file mode 100644
index 00000000..0da7fd0b
--- /dev/null
+++ b/ecosystem/AI-Tooling/beacon/components/ColorSchemeToggle/ColorSchemeToggle.tsx
@@ -0,0 +1,62 @@
+/*
+* Licensed to the Apache Software Foundation (ASF) under one
+* or more contributor license agreements.  See the NOTICE file
+* distributed with this work for additional information
+* regarding copyright ownership.  The ASF licenses this file
+* to you under the Apache License, Version 2.0 (the
+* "License"); you may not use this file except in compliance
+* with the License.  You may obtain a copy of the License at
+* 
+*   http://www.apache.org/licenses/LICENSE-2.0
+* 
+* Unless required by applicable law or agreed to in writing,
+* software distributed under the License is distributed on an
+* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+* KIND, either express or implied.  See the License for the
+* specific language governing permissions and limitations
+* under the License.
+*/
+
+'use client';
+
+import { useTheme } from 'next-themes';
+import { Button, Group, useMantineColorScheme } from '@mantine/core';
+
+export function ColorSchemeToggle() {
+  const { setColorScheme } = useMantineColorScheme();
+  const { setTheme } = useTheme();
+
+  /**
+   * You might improve this component. Anyway, it's a good starting point.
+   * As you can see we have to handle both the Mantine and Nextra dark mode.
+   */
+
+  return (
+    <Group justify="center" mt="xl">
+      <Button
+        onClick={() => {
+          setColorScheme('light');
+          setTheme('light');
+        }}
+      >
+        Light
+      </Button>
+      <Button
+        onClick={() => {
+          setColorScheme('dark');
+          setTheme('dark');
+        }}
+      >
+        Dark
+      </Button>
+      <Button
+        onClick={() => {
+          setColorScheme('auto');
+          setTheme('system');
+        }}
+      >
+        Auto
+      </Button>
+    </Group>
+  );
+}
diff --git a/ecosystem/AI-Tooling/beacon/components/CommentSection.tsx b/ecosystem/AI-Tooling/beacon/components/CommentSection.tsx
new file mode 100644
index 00000000..df490bb9
--- /dev/null
+++ b/ecosystem/AI-Tooling/beacon/components/CommentSection.tsx
@@ -0,0 +1,133 @@
+/*
+* Licensed to the Apache Software Foundation (ASF) under one
+* or more contributor license agreements.  See the NOTICE file
+* distributed with this work for additional information
+* regarding copyright ownership.  The ASF licenses this file
+* to you under the Apache License, Version 2.0 (the
+* "License"); you may not use this file except in compliance
+* with the License.  You may obtain a copy of the License at
+* 
+*   http://www.apache.org/licenses/LICENSE-2.0
+* 
+* Unless required by applicable law or agreed to in writing,
+* software distributed under the License is distributed on an
+* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+* KIND, either express or implied.  See the License for the
+* specific language governing permissions and limitations
+* under the License.
+*/
+
+'use client';
+
+import { useState } from 'react';
+import { IconAlertCircle } from '@tabler/icons-react';
+import { Alert, Button, Paper, Stack, Text, Textarea } from '@mantine/core';
+import { GitHubAuth } from './GitHubAuth';
+
+interface GitHubUser {
+  login: string;
+  avatar_url: string;
+  name: string | null;
+}
+
+interface CommentSectionProps {
+  pageTitle: string;
+  pageUrl: string;
+  repoOwner: string;
+  repoName: string;
+  labels?: string[];
+  title?: string;
+}
+
+export function CommentSection({
+  pageTitle,
+  pageUrl,
+  repoOwner,
+  repoName,
+  labels = ['user-feedback', 'documentation'],
+  title = 'Leave a Comment',
+}: CommentSectionProps) {
+  const [comment, setComment] = useState('');
+  const [isSubmitting, setIsSubmitting] = useState(false);
+  const [error, setError] = useState<string | null>(null);
+  const [success, setSuccess] = useState(false);
+  const [user, setUser] = useState<GitHubUser | null>(null);
+
+  const handleSubmit = async () => {
+    if (!user) {
+      setError('Please sign in with GitHub to submit a comment');
+      return;
+    }
+
+    try {
+      setIsSubmitting(true);
+      setError(null);
+
+      const response = await fetch('/api/create-github-issue', {
+        method: 'POST',
+        headers: {
+          'Content-Type': 'application/json',
+        },
+        body: JSON.stringify({
+          title: `Feedback: ${pageTitle}`,
+          body: comment,
+          repoOwner,
+          repoName,
+          labels,
+        }),
+      });
+
+      if (!response.ok) {
+        const errorData = await response.json();
+        throw new Error(errorData.error || 'Failed to create GitHub issue');
+      }
+
+      setSuccess(true);
+      setComment('');
+    } catch (err) {
+      setError(
+        err instanceof Error ? err.message : 'Failed to submit comment. Please try again later.'
+      );
+      console.error('Error creating GitHub issue:', err);
+    } finally {
+      setIsSubmitting(false);
+    }
+  };
+
+  return (
+    <Paper p="md" withBorder>
+      <Stack gap="md">
+        <Text fw={500} size="lg">
+          {title}
+        </Text>
+        <GitHubAuth onAuthStateChange={setUser} returnUrl={pageUrl} />
+        {user && (
+          <>
+            <Textarea
+              required
+              label="Comment"
+              value={comment}
+              onChange={(event) => setComment(event.currentTarget.value)}
+              placeholder="Share your thoughts, suggestions, or report issues..."
+              minRows={3}
+              disabled={isSubmitting}
+            />
+            {error && (
+              <Alert icon={<IconAlertCircle size={16} />} color="red">
+                {error}
+              </Alert>
+            )}
+            {success && (
+              <Alert color="green">
+                Thank you for your feedback! We've created an issue and our team will review it.
+              </Alert>
+            )}
+            <Button onClick={handleSubmit} loading={isSubmitting} disabled={!comment.trim()}>
+              Submit Comment
+            </Button>
+          </>
+        )}
+      </Stack>
+    </Paper>
+  );
+}
diff --git a/ecosystem/AI-Tooling/beacon/components/Content/Content.story.tsx b/ecosystem/AI-Tooling/beacon/components/Content/Content.story.tsx
new file mode 100644
index 00000000..3e7c4154
--- /dev/null
+++ b/ecosystem/AI-Tooling/beacon/components/Content/Content.story.tsx
@@ -0,0 +1,28 @@
+/*
+* Licensed to the Apache Software Foundation (ASF) under one
+* or more contributor license agreements.  See the NOTICE file
+* distributed with this work for additional information
+* regarding copyright ownership.  The ASF licenses this file
+* to you under the Apache License, Version 2.0 (the
+* "License"); you may not use this file except in compliance
+* with the License.  You may obtain a copy of the License at
+* 
+*   http://www.apache.org/licenses/LICENSE-2.0
+* 
+* Unless required by applicable law or agreed to in writing,
+* software distributed under the License is distributed on an
+* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+* KIND, either express or implied.  See the License for the
+* specific language governing permissions and limitations
+* under the License.
+*/
+
+import '@gfazioli/mantine-marquee/styles.layer.css';
+
+import { Content } from './Content';
+
+export default {
+  title: 'Content',
+};
+
+export const Usage = () => <Content />;
diff --git a/ecosystem/AI-Tooling/beacon/components/Content/Content.tsx b/ecosystem/AI-Tooling/beacon/components/Content/Content.tsx
new file mode 100644
index 00000000..52ea8a5e
--- /dev/null
+++ b/ecosystem/AI-Tooling/beacon/components/Content/Content.tsx
@@ -0,0 +1,74 @@
+/*
+* Licensed to the Apache Software Foundation (ASF) under one
+* or more contributor license agreements.  See the NOTICE file
+* distributed with this work for additional information
+* regarding copyright ownership.  The ASF licenses this file
+* to you under the Apache License, Version 2.0 (the
+* "License"); you may not use this file except in compliance
+* with the License.  You may obtain a copy of the License at
+* 
+*   http://www.apache.org/licenses/LICENSE-2.0
+* 
+* Unless required by applicable law or agreed to in writing,
+* software distributed under the License is distributed on an
+* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+* KIND, either express or implied.  See the License for the
+* specific language governing permissions and limitations
+* under the License.
+*/
+
+import { Marquee } from '@gfazioli/mantine-marquee';
+import { Anchor } from 'nextra/components';
+import { Button, Divider, Stack, Title } from '@mantine/core';
+
+export const Content = () => {
+  return (
+    <>
+      <Divider my="md" />
+      <Stack align="center" my={32}>
+        <Title order={1} ta="center">
+          Explore Apps and Ecosystem
+        </Title>
+
+        <Anchor href="https://mantine-extensions.vercel.app/">
+          Visit the ResilientDB Hub for more projects
+        </Anchor>
+
+        <Marquee fadeEdges pauseOnHover>
+          <Button
+            size="xl"
+            component="a"
+            href="https://github.com/apache/incubator-resilientdb"
+            target="_blank"
+          >
+            ResilientDB
+          </Button>
+          <Button
+            size="xl"
+            component="a"
+            href="https://github.com/apache/incubator-resilientdb-graphql"
+            target="_blank"
+          >
+            ResilientDB Graphql
+          </Button>
+          <Button
+            size="xl"
+            component="a"
+            href="https://github.com/apache/incubator-resilientdb-resilient-python-cache"
+            target="_blank"
+          >
+            Resilient-Python-Cache
+          </Button>
+          <Button
+            size="xl"
+            component="a"
+            href="https://github.com/harish876/ResLens"
+            target="_blank"
+          >
+            ResLens
+          </Button>
+        </Marquee>
+      </Stack>
+    </>
+  );
+};
diff --git a/ecosystem/AI-Tooling/beacon/components/FloatingAssistant.tsx b/ecosystem/AI-Tooling/beacon/components/FloatingAssistant.tsx
new file mode 100644
index 00000000..d2e666c8
--- /dev/null
+++ b/ecosystem/AI-Tooling/beacon/components/FloatingAssistant.tsx
@@ -0,0 +1,832 @@
+/*
+* Licensed to the Apache Software Foundation (ASF) under one
+* or more contributor license agreements.  See the NOTICE file
+* distributed with this work for additional information
+* regarding copyright ownership.  The ASF licenses this file
+* to you under the Apache License, Version 2.0 (the
+* "License"); you may not use this file except in compliance
+* with the License.  You may obtain a copy of the License at
+* 
+*   http://www.apache.org/licenses/LICENSE-2.0
+* 
+* Unless required by applicable law or agreed to in writing,
+* software distributed under the License is distributed on an
+* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+* KIND, either express or implied.  See the License for the
+* specific language governing permissions and limitations
+* under the License.
+*/
+
+'use client';
+
+import { ActionIcon, Tooltip, Paper, Text, Group, Box, Modal, Textarea, Button, Stack, Divider, Avatar, Switch, Badge } from '@mantine/core';
+import { IconBrain, IconSend, IconRobot, IconUser, IconHighlight, IconSettings } from '@tabler/icons-react';
+import { useState, useEffect, ReactNode, useCallback, useRef } from 'react';
+import ReactMarkdown from 'react-markdown';
+import { Prism as SyntaxHighlighter } from 'react-syntax-highlighter';
+import { vscDarkPlus } from 'react-syntax-highlighter/dist/cjs/styles/prism';
+
+interface CodeProps {
+  node?: any;
+  inline?: boolean;
+  className?: string;
+  children?: ReactNode;
+  [key: string]: any;
+}
+
+interface MarkdownComponentProps {
+  children: ReactNode;
+}
+
+export function FloatingAssistant() {
+  const [isOpen, setIsOpen] = useState(false);
+  const [selectedText, setSelectedText] = useState('');
+  const [explanation, setExplanation] = useState('');
+  const [isLoading, setIsLoading] = useState(false);
+  const [question, setQuestion] = useState('');
+  const [isAskingQuestion, setIsAskingQuestion] = useState(false);
+  const [debounceTimer, setDebounceTimer] = useState<NodeJS.Timeout | null>(null);
+  const [lastSelection, setLastSelection] = useState('');
+  const [highlightMode, setHighlightMode] = useState(false);
+  const [showSettings, setShowSettings] = useState(false);
+  const triggerRef = useRef<HTMLButtonElement | null>(null);
+  const firstFocusRef = useRef<HTMLTextAreaElement | HTMLButtonElement | null>(null);
+  const lastFocusedRef = useRef<HTMLElement | null>(null);
+  const switchRef = useRef<HTMLInputElement | null>(null);
+
+  // Function to check if element is within a code editor
+  const isWithinCodeEditor = (element: Element | null): boolean => {
+    if (!element) return false;
+    
+    // Check if element is within a code editor
+    if (element.closest('.cm-editor') || 
+        element.closest('.CodeMirror') || 
+        element.closest('pre') || 
+        element.closest('code')) {
+      return true;
+    }
+    
+    // Check parent elements
+    return isWithinCodeEditor(element.parentElement);
+  };
+
+  // Debounced text selection handler
+  const handleTextSelection = useCallback(() => {
+    // Only handle text selection if highlight mode is enabled
+    if (!highlightMode) return;
+
+    // Clear any existing timer
+    if (debounceTimer) {
+      clearTimeout(debounceTimer);
+    }
+
+    // Set new timer
+    const timer = setTimeout(() => {
+      const selection = window.getSelection();
+      const selectedText = selection?.toString().trim() || '';
+      
+      // Don't trigger if:
+      // 1. No text is selected
+      // 2. Selection is within a code editor
+      // 3. Selection is the same as last time
+      if (!selectedText || 
+          isWithinCodeEditor(selection?.anchorNode?.parentElement as Element | null) ||
+          selectedText === lastSelection) {
+        return;
+      }
+
+      setLastSelection(selectedText);
+      setSelectedText(selectedText);
+      setIsOpen(true);
+      getExplanation(selectedText);
+    }, 300); // 300ms debounce delay
+
+    setDebounceTimer(timer);
+  }, [debounceTimer, lastSelection, highlightMode]);
+
+  // Cleanup timer on unmount
+  useEffect(() => {
+    return () => {
+      if (debounceTimer) {
+        clearTimeout(debounceTimer);
+      }
+    };
+  }, [debounceTimer]);
+
+  // Add event listener for text selection
+  useEffect(() => {
+    document.addEventListener('mouseup', handleTextSelection);
+    return () => {
+      document.removeEventListener('mouseup', handleTextSelection);
+    };
+  }, [handleTextSelection]);
+
+  // Reset lastSelection when modal is closed
+  const handleModalClose = () => {
+    setIsOpen(false);
+    setSelectedText('');
+    setExplanation('');
+    setQuestion('');
+    setLastSelection('');
+    // return focus to trigger
+    setTimeout(() => {
+      try {
+        lastFocusedRef.current?.focus?.();
+      } catch (err) {}
+    }, 0);
+  };
+
+  const openModal = (from?: HTMLElement | null) => {
+    lastFocusedRef.current = from ?? (document.activeElement as HTMLElement | null);
+    setIsOpen(true);
+    setTimeout(() => {
+      // focus the textarea input if present
+      const textarea = document.querySelector('textarea[placeholder]') as HTMLTextAreaElement | null;
+      (firstFocusRef.current as HTMLElement | null ?? textarea)?.focus?.();
+    }, 50);
+  };
+
+  // Escape handler while modal is open
+  useEffect(() => {
+    if (!isOpen) return;
+    const onKey = (e: KeyboardEvent) => {
+      if (e.key === 'Escape') {
+        e.preventDefault();
+        handleModalClose();
+      }
+    };
+    document.addEventListener('keydown', onKey);
+    return () => document.removeEventListener('keydown', onKey);
+  }, [isOpen]);
+
+  // Focus the highlight switch when settings panel is opened
+  useEffect(() => {
+    if (!showSettings) return;
+    setTimeout(() => {
+      try {
+        switchRef.current?.focus?.();
+      } catch (err) {}
+    }, 50);
+  }, [showSettings]);
+
+  const getExplanation = async (text: string, customQuestion?: string) => {
+    setIsLoading(true);
+    try {
+      const response = await fetch('/api/chat', {
+        method: 'POST',
+        headers: { 'Content-Type': 'application/json' },
+        body: JSON.stringify({
+          messages: [
+            {
+              role: 'user',
+              content: customQuestion 
+                ? (selectedText 
+                    ? `Regarding this text: "${selectedText}"\n\n${customQuestion}`
+                    : customQuestion)
+                : `Explain the following text or concept in detail:
+${text}
+
+Please:
+1. Break down any complex concepts
+2. Provide examples if relevant
+3. Explain any technical terms
+4. Use markdown formatting for better readability`
+            }
+          ]
+        }),
+      });
+
+      if (!response.ok) throw new Error('Failed to get explanation');
+      
+      const reader = response.body?.getReader();
+      if (!reader) throw new Error('No reader available');
+
+      let explanation = '';
+      while (true) {
+        const { done, value } = await reader.read();
+        if (done) break;
+        
+        const text = new TextDecoder().decode(value);
+        explanation += text;
+        setExplanation(explanation);
+      }
+    } catch (error) {
+      console.error('Error getting explanation:', error);
+      setExplanation('Sorry, there was an error getting the explanation.');
+    } finally {
+      setIsLoading(false);
+      setIsAskingQuestion(false);
+    }
+  };
+
+  const handleAskQuestion = (e: React.FormEvent) => {
+    e.preventDefault();
+    if (!question.trim()) return;
+    
+    setIsAskingQuestion(true);
+    getExplanation(selectedText || '', question);
+    setQuestion('');
+  };
+
+  const handleKeyDown = (e: React.KeyboardEvent<HTMLTextAreaElement>) => {
+    if (e.key === 'Enter' && !e.shiftKey) {
+      e.preventDefault();
+      if (question.trim()) {
+        setIsAskingQuestion(true);
+        getExplanation(selectedText || '', question);
+        setQuestion('');
+      }
+    }
+  };
+
+  return (
+    <>
+      <div
+          style={{
+            position: 'fixed',
+            bottom: '20px',
+            right: '20px',
+            zIndex: 1000,
+          display: 'flex',
+          flexDirection: 'column',
+          gap: 12,
+          alignItems: 'flex-end',
+        }}
+      >
+        {/* Settings Toggle */}
+        <Tooltip 
+          label="AI Assistant Settings"
+          styles={{
+            tooltip: {
+              background: 'rgba(0,0,0,0.8)',
+              backdropFilter: 'blur(8px)',
+              border: '1px solid rgba(255,255,255,0.1)',
+              color: 'rgba(255,255,255,0.9)',
+              fontSize: '12px',
+              fontWeight: 400,
+            }
+          }}
+        >
+          <ActionIcon
+            variant="light"
+            size="md"
+            radius="xl"
+            style={{
+              background: 'rgba(255,255,255,0.05)',
+              backdropFilter: 'blur(8px)',
+              border: '1px solid rgba(255,255,255,0.1)',
+              color: 'rgba(255,255,255,0.7)',
+              transition: 'all 200ms ease',
+            }}
+            onClick={() => setShowSettings((s) => !s)}
+            tabIndex={0}
+            onKeyDown={(e) => {
+              if (e.key === 'Enter' || e.key === ' ') {
+                e.preventDefault();
+                setShowSettings((s) => !s);
+              }
+            }}
+            onFocus={(e) => {
+              // stronger focus ring for keyboard users
+              e.currentTarget.style.boxShadow = '0 0 0 6px rgba(0,191,255,0.18)';
+              e.currentTarget.style.outline = '2px solid rgba(0,191,255,0.18)';
+            }}
+            onBlur={(e) => {
+              e.currentTarget.style.boxShadow = 'none';
+              e.currentTarget.style.outline = 'none';
+            }}
+            onMouseEnter={(e) => {
+              e.currentTarget.style.background = 'rgba(0, 191, 255, 0.1)';
+              e.currentTarget.style.borderColor = 'rgba(0, 191, 255, 0.3)';
+              e.currentTarget.style.color = '#00bfff';
+            }}
+            onMouseLeave={(e) => {
+              e.currentTarget.style.background = 'rgba(255,255,255,0.05)';
+              e.currentTarget.style.borderColor = 'rgba(255,255,255,0.1)';
+              e.currentTarget.style.color = 'rgba(255,255,255,0.7)';
+            }}
+          >
+            <IconSettings size={16} />
+        </ActionIcon>
+      </Tooltip>
+
+        {/* Settings Panel */}
+        {showSettings && (
+          <div
+            style={{
+              background: 'rgba(255,255,255,0.05)',
+              backdropFilter: 'blur(12px)',
+              border: '1px solid rgba(255,255,255,0.1)',
+              borderRadius: 12,
+              padding: 16,
+              minWidth: 200,
+              position: 'relative',
+            }}
+          >
+            <div
+              style={{
+                position: 'absolute',
+                top: 0,
+                left: 0,
+                right: 0,
+                height: 1,
+                background: 'linear-gradient(90deg, transparent, rgba(255,255,255,0.2), transparent)',
+                borderRadius: '12px 12px 0 0',
+              }}
+            />
+            <Stack gap={12}>
+              <Group justify="space-between" align="center">
+                <Group gap={8}>
+                  <IconHighlight size={16} style={{ color: '#00bfff' }} />
+                  <Text size="sm" c="rgba(255,255,255,0.9)" fw={500}>
+                    Highlight Mode
+                  </Text>
+                </Group>
+                <Switch
+                  checked={highlightMode}
+                  onChange={(event) => setHighlightMode(event.currentTarget.checked)}
+                  size="sm"
+                  tabIndex={0}
+                  // Allow Enter to toggle in addition to Space
+                  onKeyDown={(e: React.KeyboardEvent<HTMLInputElement>) => {
+                    if (e.key === 'Enter') {
+                      e.preventDefault();
+                      setHighlightMode((v) => !v);
+                    }
+                  }}
+                  ref={switchRef as any}
+                  styles={{
+                    track: {
+                      backgroundColor: highlightMode ? 'rgba(0, 191, 255, 0.3)' : 'rgba(255,255,255,0.1)',
+                      borderColor: highlightMode ? 'rgba(0, 191, 255, 0.5)' : 'rgba(255,255,255,0.2)',
+                    },
+                    thumb: {
+                      backgroundColor: highlightMode ? '#00bfff' : 'rgba(255,255,255,0.6)',
+                    },
+                  }}
+                />
+              </Group>
+              <Text size="xs" c="rgba(255,255,255,0.6)" style={{ lineHeight: 1.4 }}>
+                {highlightMode 
+                  ? "Select text to automatically get explanations" 
+                  : "Click the AI button to ask questions manually"}
+              </Text>
+              {highlightMode && (
+                <Badge
+                  size="xs"
+                  variant="light"
+                  color="blue"
+                  style={{
+                    background: 'rgba(0, 191, 255, 0.1)',
+                    border: '1px solid rgba(0, 191, 255, 0.2)',
+                    color: '#00bfff',
+                  }}
+                >
+                  Active
+                </Badge>
+              )}
+            </Stack>
+          </div>
+        )}
+
+        {/* Main AI Assistant Button */}
+        <Tooltip 
+          label={highlightMode ? "AI Assistant - Select text to get explanations" : "AI Assistant - Click to ask questions"}
+          styles={{
+            tooltip: {
+              background: 'rgba(0,0,0,0.8)',
+              backdropFilter: 'blur(8px)',
+              border: '1px solid rgba(255,255,255,0.1)',
+              color: 'rgba(255,255,255,0.9)',
+              fontSize: '12px',
+              fontWeight: 400,
+            }
+          }}
+        >
+          <ActionIcon
+            variant="light"
+            size="xl"
+            radius="xl"
+            style={{
+              background: 'rgba(0, 191, 255, 0.1)',
+              backdropFilter: 'blur(12px)',
+              border: '1px solid rgba(0, 191, 255, 0.2)',
+              color: '#00bfff',
+              transition: 'all 200ms ease',
+              position: 'relative',
+              overflow: 'hidden',
+            }}
+            ref={triggerRef}
+            onClick={(e) => openModal(e.currentTarget)}
+            tabIndex={0}
+            onKeyDown={(e) => {
+              if (e.key === 'Enter' || e.key === ' ') {
+                e.preventDefault();
+                openModal(e.currentTarget as HTMLElement);
+              }
+            }}
+            onFocus={(e) => {
+              e.currentTarget.style.boxShadow = '0 0 0 8px rgba(0,191,255,0.16)';
+              e.currentTarget.style.outline = '2px solid rgba(0,191,255,0.16)';
+            }}
+            onBlur={(e) => { e.currentTarget.style.boxShadow = 'none'; e.currentTarget.style.outline = 'none'; }}
+            onMouseEnter={(e) => {
+              e.currentTarget.style.background = 'rgba(0, 191, 255, 0.2)';
+              e.currentTarget.style.borderColor = 'rgba(0, 191, 255, 0.4)';
+              e.currentTarget.style.transform = 'translateY(-2px)';
+              e.currentTarget.style.boxShadow = '0 8px 20px rgba(0, 191, 255, 0.3)';
+            }}
+            onMouseLeave={(e) => {
+              e.currentTarget.style.background = 'rgba(0, 191, 255, 0.1)';
+              e.currentTarget.style.borderColor = 'rgba(0, 191, 255, 0.2)';
+              e.currentTarget.style.transform = 'translateY(0)';
+              e.currentTarget.style.boxShadow = 'none';
+            }}
+          >
+            <div
+              style={{
+                position: 'absolute',
+                top: 0,
+                left: 0,
+                right: 0,
+                height: 1,
+                background: 'linear-gradient(90deg, transparent, rgba(255,255,255,0.3), transparent)',
+                borderRadius: '50% 50% 0 0',
+              }}
+            />
+            <IconBrain size={20} style={{ position: 'relative', zIndex: 1 }} />
+            {highlightMode && (
+              <div
+                style={{
+                  position: 'absolute',
+                  top: -2,
+                  right: -2,
+                  width: 8,
+                  height: 8,
+                  background: '#00ff88',
+                  borderRadius: '50%',
+                  border: '2px solid rgba(0,0,0,0.8)',
+                }}
+              />
+            )}
+          </ActionIcon>
+        </Tooltip>
+      </div>
+
+      <Modal
+        opened={isOpen}
+        onClose={handleModalClose}
+        size="60vw"
+        styles={{
+          content: {
+            display: 'flex',
+            flexDirection: 'column',
+            height: '80vh',
+            padding: 0,
+            background: 'rgba(0,0,0,0.8)',
+            backdropFilter: 'blur(20px)',
+            border: '1px solid rgba(255,255,255,0.1)',
+            borderRadius: 16,
+          },
+          body: {
+            flex: 1,
+            padding: 0,
+            display: 'flex',
+            flexDirection: 'column',
+          },
+          header: {
+            padding: '20px',
+            borderBottom: '1px solid rgba(255,255,255,0.1)',
+            background: 'rgba(255,255,255,0.02)',
+            backdropFilter: 'blur(8px)',
+            borderRadius: '16px 16px 0 0',
+          },
+        }}
+        title={
+          <Group justify="space-between" w="100%">
+            <Group gap={12}>
+              <div
+                style={{
+                  width: 40,
+                  height: 40,
+                  borderRadius: '50%',
+                  background: 'rgba(0, 191, 255, 0.1)',
+                  border: '1px solid rgba(0, 191, 255, 0.2)',
+                  display: 'flex',
+                  alignItems: 'center',
+                  justifyContent: 'center',
+                }}
+              >
+                <IconRobot size={20} style={{ color: '#00bfff' }} />
+              </div>
+              <div>
+                <Text size="sm" fw={500} c="rgba(255,255,255,0.9)">
+                  AI Assistant
+                </Text>
+                <Text size="xs" c="rgba(255,255,255,0.6)">
+                  {highlightMode ? "Highlight mode enabled" : "Manual mode"}
+                </Text>
+              </div>
+            </Group>
+            {selectedText && (
+              <div
+                style={{
+                  background: 'rgba(0, 191, 255, 0.1)',
+                  border: '1px solid rgba(0, 191, 255, 0.2)',
+                  borderRadius: 8,
+                  padding: '8px 12px',
+                  maxWidth: '60%',
+                }}
+              >
+                <Text size="xs" c="#00bfff" fw={500}>
+                Selected: "{selectedText.length > 50 ? selectedText.substring(0, 50) + '...' : selectedText}"
+              </Text>
+              </div>
+            )}
+          </Group>
+        }
+      >
+      <Stack style={{ flex: 1, height: '100%' }} p={0}>
+          {selectedText && (
+            <div
+              style={{
+                padding: '16px 20px',
+                background: 'rgba(255,255,255,0.03)',
+                borderBottom: '1px solid rgba(255,255,255,0.1)',
+                backdropFilter: 'blur(8px)',
+              }}
+            >
+              <Group gap={12}>
+                <div
+                  style={{
+                    width: 32,
+                    height: 32,
+                    borderRadius: '50%',
+                    background: 'rgba(255,255,255,0.05)',
+                    border: '1px solid rgba(255,255,255,0.1)',
+                    display: 'flex',
+                    alignItems: 'center',
+                    justifyContent: 'center',
+                  }}
+                >
+                  <IconUser size={14} style={{ color: 'rgba(255,255,255,0.7)' }} />
+                </div>
+                <Box style={{ flex: 1 }}>
+                  <Text size="sm" fw={500} mb={4} c="rgba(255,255,255,0.9)">
+                    Selected Text
+                  </Text>
+                  <Text size="sm" c="rgba(255,255,255,0.7)" style={{ lineHeight: 1.5 }}>
+                    {selectedText}
+                  </Text>
+                </Box>
+              </Group>
+            </div>
+          )}
+          
+          <Box 
+            style={{ 
+              flex: 1,
+              overflowY: 'auto',
+              padding: '1rem',
+              display: 'flex',
+              flexDirection: 'column',
+              gap: '1rem',
+            }}
+          >
+            {isLoading ? (
+              <Group align="flex-start" gap={12}>
+                <div
+                  style={{
+                    width: 32,
+                    height: 32,
+                    borderRadius: '50%',
+                    background: 'rgba(0, 191, 255, 0.1)',
+                    border: '1px solid rgba(0, 191, 255, 0.2)',
+                    display: 'flex',
+                    alignItems: 'center',
+                    justifyContent: 'center',
+                  }}
+                >
+                  <IconRobot size={16} style={{ color: '#00bfff' }} />
+                </div>
+                <div
+                  style={{
+                    background: 'rgba(255,255,255,0.05)',
+                    border: '1px solid rgba(255,255,255,0.1)',
+                    borderRadius: 12,
+                    padding: 16,
+                    maxWidth: '80%',
+                    backdropFilter: 'blur(8px)',
+                  }}
+                >
+                  <Text size="sm" c="rgba(255,255,255,0.7)">
+                    Generating response...
+                  </Text>
+                </div>
+              </Group>
+            ) : explanation ? (
+              <Group align="flex-start" gap={12}>
+                <div
+                  style={{
+                    width: 32,
+                    height: 32,
+                    borderRadius: '50%',
+                    background: 'rgba(0, 191, 255, 0.1)',
+                    border: '1px solid rgba(0, 191, 255, 0.2)',
+                    display: 'flex',
+                    alignItems: 'center',
+                    justifyContent: 'center',
+                  }}
+                >
+                  <IconRobot size={16} style={{ color: '#00bfff' }} />
+                </div>
+                <div
+                  style={{
+                    background: 'rgba(255,255,255,0.05)',
+                    border: '1px solid rgba(255,255,255,0.1)',
+                    borderRadius: 12,
+                    padding: 16,
+                    maxWidth: '80%',
+                    backdropFilter: 'blur(8px)',
+                  }}
+                >
+                  <ReactMarkdown
+                    components={{
+                      code({ node, inline, className, children, ...props }: CodeProps) {
+                        const match = /language-(\w+)/.exec(className || '');
+                        return !inline && match ? (
+                          <SyntaxHighlighter
+                            style={vscDarkPlus}
+                            language={match[1]}
+                            PreTag="div"
+                            {...props}
+                          >
+                            {String(children).replace(/\n$/, '')}
+                          </SyntaxHighlighter>
+                        ) : (
+                          <code className={className} {...props}>
+                            {children}
+                          </code>
+                        );
+                      },
+                      p: ({ children }: MarkdownComponentProps) => (
+                        <Text size="sm" mb="md" c="rgba(255,255,255,0.9)" style={{ whiteSpace: 'pre-wrap', lineHeight: 1.6 }}>
+                          {children}
+                        </Text>
+                      ),
+                      ul: ({ children }: MarkdownComponentProps) => (
+                        <Box component="ul" mb="md" style={{ paddingLeft: '1.5rem' }}>
+                          {children}
+                        </Box>
+                      ),
+                      ol: ({ children }: MarkdownComponentProps) => (
+                        <Box component="ol" mb="md" style={{ paddingLeft: '1.5rem' }}>
+                          {children}
+                        </Box>
+                      ),
+                      li: ({ children }: MarkdownComponentProps) => (
+                        <Text size="sm" component="li" mb="xs" c="rgba(255,255,255,0.9)">
+                          {children}
+                        </Text>
+                      ),
+                      h1: ({ children }: MarkdownComponentProps) => (
+                        <Text size="xl" fw={700} mb="md" c="rgba(255,255,255,0.9)">
+                          {children}
+                        </Text>
+                      ),
+                      h2: ({ children }: MarkdownComponentProps) => (
+                        <Text size="lg" fw={600} mb="md" c="rgba(255,255,255,0.9)">
+                          {children}
+                        </Text>
+                      ),
+                      h3: ({ children }: MarkdownComponentProps) => (
+                        <Text size="md" fw={600} mb="md" c="rgba(255,255,255,0.9)">
+                          {children}
+                        </Text>
+                      ),
+                      blockquote: ({ children }: MarkdownComponentProps) => (
+                        <div
+                          style={{
+                            padding: 12,
+                            marginBottom: 16,
+                            background: 'rgba(0, 191, 255, 0.05)',
+                            border: '1px solid rgba(0, 191, 255, 0.1)',
+                            borderLeft: '4px solid #00bfff',
+                            borderRadius: 8,
+                          }}
+                        >
+                          {children}
+                        </div>
+                      ),
+                    }}
+                  >
+                    {explanation}
+                  </ReactMarkdown>
+                </div>
+              </Group>
+            ) : (
+              <Group align="flex-start" gap={12}>
+                <div
+                  style={{
+                    width: 32,
+                    height: 32,
+                    borderRadius: '50%',
+                    background: 'rgba(0, 191, 255, 0.1)',
+                    border: '1px solid rgba(0, 191, 255, 0.2)',
+                    display: 'flex',
+                    alignItems: 'center',
+                    justifyContent: 'center',
+                  }}
+                >
+                  <IconRobot size={16} style={{ color: '#00bfff' }} />
+                </div>
+                <div
+                  style={{
+                    background: 'rgba(255,255,255,0.05)',
+                    border: '1px solid rgba(255,255,255,0.1)',
+                    borderRadius: 12,
+                    padding: 16,
+                    maxWidth: '80%',
+                    backdropFilter: 'blur(8px)',
+                  }}
+                >
+                  <Text size="sm" c="rgba(255,255,255,0.7)">
+                    {selectedText 
+                      ? "Select text to get an explanation" 
+                      : "Ask any question or select text to get an explanation"}
+                  </Text>
+                </div>
+              </Group>
+            )}
+          </Box>
+
+          <div
+            style={{ 
+              padding: '20px',
+              borderTop: '1px solid rgba(255,255,255,0.1)',
+              background: 'rgba(255,255,255,0.02)',
+              backdropFilter: 'blur(8px)',
+            }}
+          >
+            <form onSubmit={handleAskQuestion}>
+              <Group gap={12}>
+                <Textarea
+                  ref={firstFocusRef as any}
+                  placeholder={selectedText 
+                    ? "Ask a specific question about the selected text..." 
+                    : "Ask any question..."}
+                  value={question}
+                  onChange={(e: React.ChangeEvent<HTMLTextAreaElement>) => setQuestion(e.target.value)}
+                  onKeyDown={handleKeyDown}
+                  style={{ flex: 1 }}
+                  disabled={isLoading}
+                  autosize
+                  minRows={1}
+                  maxRows={3}
+                  styles={{
+                    input: {
+                      background: 'rgba(255,255,255,0.05)',
+                      border: '1px solid rgba(255,255,255,0.1)',
+                      color: 'rgba(255,255,255,0.9)',
+                      borderRadius: 12,
+                      '&:focus': {
+                        borderColor: 'rgba(0, 191, 255, 0.5)',
+                        background: 'rgba(255,255,255,0.08)',
+                      },
+                      '&::placeholder': {
+                        color: 'rgba(255,255,255,0.5)',
+                      }
+                    }
+                  }}
+                />
+                <Button 
+                  type="submit" 
+                  loading={isAskingQuestion}
+                  disabled={!question.trim()}
+                  leftSection={<IconSend size={14} />}
+                  style={{
+                    background: 'rgba(0, 191, 255, 0.1)',
+                    border: '1px solid rgba(0, 191, 255, 0.3)',
+                    color: '#00bfff',
+                    borderRadius: 12,
+                    transition: 'all 200ms ease',
+                  }}
+                  onMouseEnter={(e) => {
+                    e.currentTarget.style.background = 'rgba(0, 191, 255, 0.2)';
+                    e.currentTarget.style.borderColor = 'rgba(0, 191, 255, 0.5)';
+                  }}
+                  onMouseLeave={(e) => {
+                    e.currentTarget.style.background = 'rgba(0, 191, 255, 0.1)';
+                    e.currentTarget.style.borderColor = 'rgba(0, 191, 255, 0.3)';
+                  }}
+                >
+                  Send
+                </Button>
+              </Group>
+            </form>
+          </div>
+        </Stack>
+      </Modal>
+    </>
+  );
+} 
\ No newline at end of file
diff --git a/ecosystem/AI-Tooling/beacon/components/GitHubAuth.tsx b/ecosystem/AI-Tooling/beacon/components/GitHubAuth.tsx
new file mode 100644
index 00000000..3beb28b7
--- /dev/null
+++ b/ecosystem/AI-Tooling/beacon/components/GitHubAuth.tsx
@@ -0,0 +1,182 @@
+/*
+* Licensed to the Apache Software Foundation (ASF) under one
+* or more contributor license agreements.  See the NOTICE file
+* distributed with this work for additional information
+* regarding copyright ownership.  The ASF licenses this file
+* to you under the Apache License, Version 2.0 (the
+* "License"); you may not use this file except in compliance
+* with the License.  You may obtain a copy of the License at
+* 
+*   http://www.apache.org/licenses/LICENSE-2.0
+* 
+* Unless required by applicable law or agreed to in writing,
+* software distributed under the License is distributed on an
+* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+* KIND, either express or implied.  See the License for the
+* specific language governing permissions and limitations
+* under the License.
+*/
+
+'use client';
+
+import { useState, useEffect } from 'react';
+import { Button, Text, Group, Avatar } from '@mantine/core';
+import { IconBrandGithub } from '@tabler/icons-react';
+import { signIn } from 'next-auth/react';
+
+interface GitHubUser {
+  login: string;
+  avatar_url: string;
+  name: string | null;
+}
+
+interface GitHubAuthProps {
+  onAuthStateChange: (user: GitHubUser | null) => void;
+  returnUrl?: string;
+}
+
+export function GitHubAuth({ onAuthStateChange, returnUrl }: GitHubAuthProps) {
+  const [user, setUser] = useState<GitHubUser | null>(null);
+  const [loading, setLoading] = useState(true);
+
+  useEffect(() => {
+    // Check if user is already authenticated
+    checkAuthStatus();
+  }, []);
+
+  const checkAuthStatus = async () => {
+    try {
+      const response = await fetch('/api/auth/session');
+      const data = await response.json();
+      
+      if (data.user) {
+        setUser(data.user);
+        onAuthStateChange(data.user);
+      }
+    } catch (error) {
+      console.error('Error checking auth status:', error);
+    } finally {
+      setLoading(false);
+    }
+  };
+
+  const handleSignIn = () => {
+    signIn('github', { callbackUrl: returnUrl || window.location.href });
+  };
+
+  const handleSignOut = async () => {
+    try {
+      await fetch('/api/auth/signout', { method: 'POST' });
+      setUser(null);
+      onAuthStateChange(null);
+    } catch (error) {
+      console.error('Error signing out:', error);
+    }
+  };
+
+  if (loading) {
+    return null;
+  }
+
+  if (user) {
+    return (
+      <div
+        style={{
+          display: 'flex',
+          alignItems: 'center',
+          gap: 12,
+          padding: 12,
+          background: 'rgba(255,255,255,0.05)',
+          backdropFilter: 'blur(8px)',
+          border: '1px solid rgba(255,255,255,0.1)',
+          borderRadius: 12,
+        }}
+      >
+        <Avatar 
+          src={user.avatar_url} 
+          alt={user.login} 
+          radius="xl"
+          style={{
+            border: '2px solid rgba(255,255,255,0.2)',
+          }}
+        />
+        <div style={{ flex: 1 }}>
+          <Text size="sm" c="rgba(255,255,255,0.9)" fw={400}>
+            Signed in as <span style={{ color: '#00bfff', fontWeight: 500 }}>{user.name || user.login}</span>
+          </Text>
+        </div>
+        <Button 
+          onClick={handleSignOut} 
+          size="xs"
+          style={{
+            background: 'rgba(255,255,255,0.05)',
+            border: '1px solid rgba(255,255,255,0.1)',
+            color: 'rgba(255,255,255,0.7)',
+            borderRadius: 8,
+            transition: 'all 200ms ease',
+          }}
+          onMouseEnter={(e) => {
+            e.currentTarget.style.background = 'rgba(255, 77, 77, 0.1)';
+            e.currentTarget.style.borderColor = 'rgba(255, 77, 77, 0.3)';
+            e.currentTarget.style.color = '#ff4d4d';
+          }}
+          onMouseLeave={(e) => {
+            e.currentTarget.style.background = 'rgba(255,255,255,0.05)';
+            e.currentTarget.style.borderColor = 'rgba(255,255,255,0.1)';
+            e.currentTarget.style.color = 'rgba(255,255,255,0.7)';
+          }}
+        >
+          Sign Out
+        </Button>
+      </div>
+    );
+  }
+
+  return (
+    <Button
+      leftSection={<IconBrandGithub size={16} />}
+      onClick={handleSignIn}
+      style={{
+        background: 'rgba(255,255,255,0.05)',
+        backdropFilter: 'blur(8px)',
+        border: '1px solid rgba(255,255,255,0.1)',
+        color: 'rgba(255,255,255,0.9)',
+        borderRadius: 12,
+        padding: '12px 20px',
+        fontWeight: 400,
+        transition: 'all 200ms ease',
+        position: 'relative',
+        overflow: 'hidden',
+      }}
+      onMouseEnter={(e) => {
+        e.currentTarget.style.background = 'rgba(0, 191, 255, 0.1)';
+        e.currentTarget.style.borderColor = 'rgba(0, 191, 255, 0.3)';
+        e.currentTarget.style.color = '#00bfff';
+        e.currentTarget.style.transform = 'translateY(-1px)';
+        e.currentTarget.style.boxShadow = '0 4px 12px rgba(0, 191, 255, 0.2)';
+      }}
+      onMouseLeave={(e) => {
+        e.currentTarget.style.background = 'rgba(255,255,255,0.05)';
+        e.currentTarget.style.borderColor = 'rgba(255,255,255,0.1)';
+        e.currentTarget.style.color = 'rgba(255,255,255,0.9)';
+        e.currentTarget.style.transform = 'translateY(0)';
+        e.currentTarget.style.boxShadow = 'none';
+      }}
+    >
+      <div
+        style={{
+          position: 'absolute',
+          top: 0,
+          left: 0,
+          right: 0,
+          height: 1,
+          background: 'linear-gradient(90deg, transparent, rgba(255,255,255,0.2), transparent)',
+          borderRadius: '12px 12px 0 0',
+        }}
+      />
+      <span style={{ position: 'relative', zIndex: 1 }}>
+        Sign in with GitHub to Comment
+      </span>
+    </Button>
+  );
+} 
\ No newline at end of file
diff --git a/ecosystem/AI-Tooling/beacon/components/InstallationForm.tsx b/ecosystem/AI-Tooling/beacon/components/InstallationForm.tsx
new file mode 100644
index 00000000..72581af0
--- /dev/null
+++ b/ecosystem/AI-Tooling/beacon/components/InstallationForm.tsx
@@ -0,0 +1,128 @@
+/*
+* Licensed to the Apache Software Foundation (ASF) under one
+* or more contributor license agreements.  See the NOTICE file
+* distributed with this work for additional information
+* regarding copyright ownership.  The ASF licenses this file
+* to you under the Apache License, Version 2.0 (the
+* "License"); you may not use this file except in compliance
+* with the License.  You may obtain a copy of the License at
+* 
+*   http://www.apache.org/licenses/LICENSE-2.0
+* 
+* Unless required by applicable law or agreed to in writing,
+* software distributed under the License is distributed on an
+* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+* KIND, either express or implied.  See the License for the
+* specific language governing permissions and limitations
+* under the License.
+*/
+
+"use client"
+
+import { useState } from 'react';
+import styles from '../styles/installation.module.css';
+
+const installCommands = {
+  resilientdb: `
+# Install ResilientDB
+echo "Installing ResilientDB..."
+git clone https://github.com/apache/incubator-resilientdb.git /opt/incubator-resilientdb
+cd /opt/incubator-resilientdb
+./INSTALL.sh
+./service/tools/kv/server_tools/start_kv_service.sh
+bazel build service/tools/kv/api_tools/kv_service_tools
+`,
+  pythonsdk: `
+# Install PythonSDK
+echo "Installing PythonSDK..."
+git clone https://github.com/apache/incubator-resilientdb-python-sdk.git /opt/incubator-resilientdb-python-sdk
+cd /opt/incubator-resilientdb-python-sdk
+sh ./INSTALL.sh
+python3.10 -m venv venv
+source venv/bin/activate
+pip install -r requirements.txt
+bazel build service/http_server/crow_service_main
+bazel-bin/service/http_server/crow_service_main service/tools/config/interface/client.config service/http_server/server_config.config
+deactivate
+`,
+  resdborm: `
+# Install ResDBORM
+echo "Installing ResDBORM..."
+git clone https://github.com/ResilientEcosystem/ResDB-ORM.git /opt/ResDB-ORM
+cd /opt/ResDB-ORM
+./INSTALL.sh
+pip install resdb-orm
+`,
+  "smartcontracts-cli": `
+# Install Smart-Contracts CLI
+echo "Installing Smart-Contracts CLI..."
+npm install -g rescontract-cli
+`,
+  "smartcontracts-graphql": `
+# Install Smart-Contracts GraphQL
+echo "Installing Smart-Contracts GraphQL..."
+git clone https://github.com/ResilientEcosystem/smart-contracts-graphql.git /opt/smart-contracts-graphql
+cd /opt/smart-contracts-graphql
+npm install
+`,
+  resvault: `
+# Install ResVault
+echo "Installing ResVault..."
+git clone https://github.com/apache/incubator-resilientdb-resvault.git /opt/ResVault
+cd /opt/ResVault
+npm install
+npm run build
+`
+};
+
+export function InstallationForm() {
+  const [error, setError] = useState('');
+
+  const handleGenerateScript = () => {
+    const selectedApps = Array.from(document.querySelectorAll('input[name="app"]:checked')).map(cb => (cb as HTMLInputElement).value);
+    if (selectedApps.length === 0) {
+      setError("Please select at least one application to install.");
+      return;
+    }
+
+    let scriptContent = "#!/bin/bash\n\n# Check for root privileges\nif [ \"$EUID\" -ne 0 ]; then\n  echo \"Please run as root. Try using 'sudo ./INSTALL.sh'\"\n  exit\nfi\n\n";
+    scriptContent += "echo \"Updating package lists...\"\napt-get update\n";
+    scriptContent += "echo \"Installing dependencies...\"\napt-get install -y git curl build-essential python3 python3-venv python3-pip npm solc\n\n";
+
+    selectedApps.forEach(app => {
+      scriptContent += installCommands[app as keyof typeof installCommands];
+    });
+
+    scriptContent += "\necho \"Installation complete. Please refer to the documentation for usage instructions.\"\n";
+
+    const blob = new Blob([scriptContent], { type: "text/plain" });
+    const link = document.getElementById("download-link");
+    if (link) {
+      link.setAttribute('href', URL.createObjectURL(blob));
+      link.setAttribute('download', "INSTALL.sh");
+      link.style.display = "block";
+      link.textContent = "Download your custom INSTALL.sh";
+    }
+    setError('');
+  };
+
+  return (
+    <div>
+      <form id="install-form">
+        <label><input type="checkbox" name="app" value="resilientdb" /> ResilientDB</label><br/>
+        <label><input type="checkbox" name="app" value="pythonsdk" /> PythonSDK</label><br/>
+        <label><input type="checkbox" name="app" value="resdborm" /> ResDBORM</label><br/>
+        <label><input type="checkbox" name="app" value="smartcontracts-cli" /> Smart-Contracts CLI</label><br/>
+        <label><input type="checkbox" name="app" value="smartcontracts-graphql" /> Smart-Contracts GraphQL</label><br/>
+        <label><input type="checkbox" name="app" value="resvault" /> ResVault</label><br/>
+        {error && <p style={{ color: 'red' }}>{error}</p>}
+        <button type="button" className={styles.generateButton} onClick={handleGenerateScript}>
+          Generate INSTALL.sh
+        </button>
+      </form>
+      <a id="download-link" className={styles.downloadButton} style={{ display: 'none' }}>
+        Download your custom INSTALL.sh
+      </a>
+    </div>
+  );
+} 
\ No newline at end of file
diff --git a/ecosystem/AI-Tooling/beacon/components/Logo/Logo.story.tsx b/ecosystem/AI-Tooling/beacon/components/Logo/Logo.story.tsx
new file mode 100644
index 00000000..1b3007a3
--- /dev/null
+++ b/ecosystem/AI-Tooling/beacon/components/Logo/Logo.story.tsx
@@ -0,0 +1,26 @@
+/*
+* Licensed to the Apache Software Foundation (ASF) under one
+* or more contributor license agreements.  See the NOTICE file
+* distributed with this work for additional information
+* regarding copyright ownership.  The ASF licenses this file
+* to you under the Apache License, Version 2.0 (the
+* "License"); you may not use this file except in compliance
+* with the License.  You may obtain a copy of the License at
+* 
+*   http://www.apache.org/licenses/LICENSE-2.0
+* 
+* Unless required by applicable law or agreed to in writing,
+* software distributed under the License is distributed on an
+* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+* KIND, either express or implied.  See the License for the
+* specific language governing permissions and limitations
+* under the License.
+*/
+
+import { Logo } from './Logo';
+
+export default {
+  title: 'Logo',
+};
+
+export const Usage = () => <Logo />;
diff --git a/ecosystem/AI-Tooling/beacon/components/Logo/Logo.tsx b/ecosystem/AI-Tooling/beacon/components/Logo/Logo.tsx
new file mode 100644
index 00000000..493972a8
--- /dev/null
+++ b/ecosystem/AI-Tooling/beacon/components/Logo/Logo.tsx
@@ -0,0 +1,24 @@
+/*
+* Licensed to the Apache Software Foundation (ASF) under one
+* or more contributor license agreements.  See the NOTICE file
+* distributed with this work for additional information
+* regarding copyright ownership.  The ASF licenses this file
+* to you under the Apache License, Version 2.0 (the
+* "License"); you may not use this file except in compliance
+* with the License.  You may obtain a copy of the License at
+* 
+*   http://www.apache.org/licenses/LICENSE-2.0
+* 
+* Unless required by applicable law or agreed to in writing,
+* software distributed under the License is distributed on an
+* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+* KIND, either express or implied.  See the License for the
+* specific language governing permissions and limitations
+* under the License.
+*/
+
+import Image from 'next/image';
+
+export function Logo() {
+  return <Image src="/lighthouse.png" alt="Logo" width={48} height={48} style={{ marginRight: '12px' }} />;
+}
diff --git a/ecosystem/AI-Tooling/beacon/components/MantineFooter/MantineFooter.tsx b/ecosystem/AI-Tooling/beacon/components/MantineFooter/MantineFooter.tsx
new file mode 100644
index 00000000..2d239c8a
--- /dev/null
+++ b/ecosystem/AI-Tooling/beacon/components/MantineFooter/MantineFooter.tsx
@@ -0,0 +1,403 @@
+/*
+* Licensed to the Apache Software Foundation (ASF) under one
+* or more contributor license agreements.  See the NOTICE file
+* distributed with this work for additional information
+* regarding copyright ownership.  The ASF licenses this file
+* to you under the Apache License, Version 2.0 (the
+* "License"); you may not use this file except in compliance
+* with the License.  You may obtain a copy of the License at
+* 
+*   http://www.apache.org/licenses/LICENSE-2.0
+* 
+* Unless required by applicable law or agreed to in writing,
+* software distributed under the License is distributed on an
+* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+* KIND, either express or implied.  See the License for the
+* specific language governing permissions and limitations
+* under the License.
+*/
+
+'use client';
+
+/**
+ * Sleek footer component matching the landing page design language
+ * Features glassmorphism effects, subtle animations, and modern styling
+ * Uses regular HTML/React components for full width stretching
+ *
+ * @since 1.0.0
+ */
+export const MantineFooter = () => (
+  <footer 
+    style={{ 
+      position: 'relative', 
+      marginTop: 48,
+      width: '100vw',
+      left: '50%',
+      right: '50%',
+      marginLeft: '-50vw',
+      marginRight: '-50vw',
+      padding: '32px 24px',
+      background: 'rgba(255, 255, 255, 0.02)',
+      backdropFilter: 'blur(10px)',
+      borderTop: '1px solid rgba(255, 255, 255, 0.08)',
+      borderBottom: '1px solid rgba(255, 255, 255, 0.08)',
+    }}
+  >
+    <div style={{ maxWidth: '1200px', margin: '0 auto' }}>
+      <div style={{ display: 'flex', flexDirection: 'column', gap: 24 }}>
+        {/* Main footer content */}
+        <div style={{ 
+          display: 'flex', 
+          justifyContent: 'space-between', 
+          alignItems: 'flex-start', 
+          width: '100%',
+          gap: 32,
+          flexWrap: 'wrap'
+        }}>
+          {/* Left section - Brand */}
+          <div style={{ flex: 1, minWidth: 200 }}>
+            <div style={{ display: 'flex', flexDirection: 'column', gap: 12 }}>
+              <div style={{ display: 'flex', alignItems: 'center', gap: 8 }}>
+                <svg
+                  fill="currentColor"
+                  viewBox="0 0 120 32"
+                  xmlns="http://www.w3.org/2000/svg"
+                  style={{ width: 100, height: 24, color: 'rgba(255,255,255,0.9)' }}
+                >
+                  <path d="M8 4 L2 18 L8 28 L14 18 Z" fill="currentColor" opacity="0.9"/>
+                  <path d="M8 6 L4 18 L8 26 L12 18 Z" fill="currentColor" opacity="0.6"/>
+                  <circle cx="8" cy="18" r="1.5" fill="currentColor" opacity="0.8"/>
+                  <text x="20" y="22" fontSize="16" fontWeight="600" fill="currentColor" fontFamily="system-ui, -apple-system, sans-serif">
+                    Beacon
+                  </text>
+                </svg>
+              </div>
+              <p style={{ 
+                fontSize: 14, 
+                color: 'rgba(255,255,255,0.6)', 
+                lineHeight: 1.5, 
+                maxWidth: 280,
+                margin: 0
+              }}>
+                Next generation documentation for ResilientDB ecosystem. 
+                Your gateway to high-performance blockchain infrastructure.
+              </p>
+            </div>
+          </div>
+
+          {/* Center section - Links */}
+          <div style={{ 
+            flex: 1, 
+            display: 'flex', 
+            justifyContent: 'center', 
+            gap: 32,
+            flexWrap: 'wrap'
+          }}>
+            <div style={{ display: 'flex', flexDirection: 'column', gap: 8 }}>
+              <h4 style={{ 
+                fontSize: 14, 
+                fontWeight: 500, 
+                color: 'white', 
+                margin: '0 0 4px 0'
+              }}>
+                Documentation
+              </h4>
+              <div style={{ display: 'flex', flexDirection: 'column', gap: 4 }}>
+                <a 
+                  href="/docs" 
+                  style={{ 
+                    fontSize: 14,
+                    color: 'rgba(255,255,255,0.6)',
+                    transition: 'all 200ms ease',
+                    textDecoration: 'none',
+                    display: 'block',
+                  }}
+                  onMouseEnter={(e) => {
+                    e.currentTarget.style.color = 'rgba(255,255,255,0.9)';
+                    e.currentTarget.style.transform = 'translateX(4px)';
+                  }}
+                  onMouseLeave={(e) => {
+                    e.currentTarget.style.color = 'rgba(255,255,255,0.6)';
+                    e.currentTarget.style.transform = 'translateX(0)';
+                  }}
+                >
+                  Getting Started
+                </a>
+                <a 
+                  href="/docs/installation" 
+                  style={{ 
+                    fontSize: 14,
+                    color: 'rgba(255,255,255,0.6)',
+                    transition: 'all 200ms ease',
+                    textDecoration: 'none',
+                    display: 'block',
+                  }}
+                  onMouseEnter={(e) => {
+                    e.currentTarget.style.color = 'rgba(255,255,255,0.9)';
+                    e.currentTarget.style.transform = 'translateX(4px)';
+                  }}
+                  onMouseLeave={(e) => {
+                    e.currentTarget.style.color = 'rgba(255,255,255,0.6)';
+                    e.currentTarget.style.transform = 'translateX(0)';
+                  }}
+                >
+                  Installation
+                </a>
+                <a 
+                  href="/docs/resilientdb" 
+                  style={{ 
+                    fontSize: 14,
+                    color: 'rgba(255,255,255,0.6)',
+                    transition: 'all 200ms ease',
+                    textDecoration: 'none',
+                    display: 'block',
+                  }}
+                  onMouseEnter={(e) => {
+                    e.currentTarget.style.color = 'rgba(255,255,255,0.9)';
+                    e.currentTarget.style.transform = 'translateX(4px)';
+                  }}
+                  onMouseLeave={(e) => {
+                    e.currentTarget.style.color = 'rgba(255,255,255,0.6)';
+                    e.currentTarget.style.transform = 'translateX(0)';
+                  }}
+                >
+                  ResilientDB
+                </a>
+              </div>
+            </div>
+
+            <div style={{ display: 'flex', flexDirection: 'column', gap: 8 }}>
+              <h4 style={{ 
+                fontSize: 14, 
+                fontWeight: 500, 
+                color: 'white', 
+                margin: '0 0 4px 0'
+              }}>
+                Community
+              </h4>
+              <div style={{ display: 'flex', flexDirection: 'column', gap: 4 }}>
+                <a 
+                  href="https://resilientdb.incubator.apache.org/" 
+                  target="_blank"
+                  rel="noopener noreferrer"
+                  style={{ 
+                    fontSize: 14,
+                    color: 'rgba(255,255,255,0.6)',
+                    transition: 'all 200ms ease',
+                    textDecoration: 'none',
+                    display: 'block',
+                  }}
+                  onMouseEnter={(e) => {
+                    e.currentTarget.style.color = 'rgba(255,255,255,0.9)';
+                    e.currentTarget.style.transform = 'translateX(4px)';
+                  }}
+                  onMouseLeave={(e) => {
+                    e.currentTarget.style.color = 'rgba(255,255,255,0.6)';
+                    e.currentTarget.style.transform = 'translateX(0)';
+                  }}
+                >
+                  Official Site
+                </a>
+                <a 
+                  href="https://blog.resilientdb.com" 
+                  target="_blank"
+                  rel="noopener noreferrer"
+                  style={{ 
+                    fontSize: 14,
+                    color: 'rgba(255,255,255,0.6)',
+                    transition: 'all 200ms ease',
+                    textDecoration: 'none',
+                    display: 'block',
+                  }}
+                  onMouseEnter={(e) => {
+                    e.currentTarget.style.color = 'rgba(255,255,255,0.9)';
+                    e.currentTarget.style.transform = 'translateX(4px)';
+                  }}
+                  onMouseLeave={(e) => {
+                    e.currentTarget.style.color = 'rgba(255,255,255,0.6)';
+                    e.currentTarget.style.transform = 'translateX(0)';
+                  }}
+                >
+                  Blog
+                </a>
+                <a 
+                  href="/docs/about" 
+                  style={{ 
+                    fontSize: 14,
+                    color: 'rgba(255,255,255,0.6)',
+                    transition: 'all 200ms ease',
+                    textDecoration: 'none',
+                    display: 'block',
+                  }}
+                  onMouseEnter={(e) => {
+                    e.currentTarget.style.color = 'rgba(255,255,255,0.9)';
+                    e.currentTarget.style.transform = 'translateX(4px)';
+                  }}
+                  onMouseLeave={(e) => {
+                    e.currentTarget.style.color = 'rgba(255,255,255,0.6)';
+                    e.currentTarget.style.transform = 'translateX(0)';
+                  }}
+                >
+                  About
+                </a>
+              </div>
+            </div>
+          </div>
+
+          {/* Right section - Tech stack */}
+          <div style={{ 
+            flex: 1, 
+            minWidth: 200, 
+            display: 'flex', 
+            flexDirection: 'column', 
+            alignItems: 'flex-end',
+            gap: 12
+          }}>
+            <h4 style={{ 
+              fontSize: 14, 
+              fontWeight: 500, 
+              color: 'white', 
+              margin: 0
+            }}>
+              Built with
+            </h4>
+            <div style={{ display: 'flex', gap: 8, flexWrap: 'wrap' }}>
+              <div
+                style={{
+                  padding: '4px 8px',
+                  borderRadius: 6,
+                  background: 'rgba(255,255,255,0.05)',
+                  border: '1px solid rgba(255,255,255,0.1)',
+                  fontSize: 11,
+                  color: 'rgba(255,255,255,0.7)',
+                  transition: 'all 200ms ease',
+                }}
+                onMouseEnter={(e) => {
+                  e.currentTarget.style.background = 'rgba(255,255,255,0.1)';
+                  e.currentTarget.style.borderColor = 'rgba(255,255,255,0.2)';
+                }}
+                onMouseLeave={(e) => {
+                  e.currentTarget.style.background = 'rgba(255,255,255,0.05)';
+                  e.currentTarget.style.borderColor = 'rgba(255,255,255,0.1)';
+                }}
+              >
+                Next.js
+              </div>
+              <div
+                style={{
+                  padding: '4px 8px',
+                  borderRadius: 6,
+                  background: 'rgba(255,255,255,0.05)',
+                  border: '1px solid rgba(255,255,255,0.1)',
+                  fontSize: 11,
+                  color: 'rgba(255,255,255,0.7)',
+                  transition: 'all 200ms ease',
+                }}
+                onMouseEnter={(e) => {
+                  e.currentTarget.style.background = 'rgba(255,255,255,0.1)';
+                  e.currentTarget.style.borderColor = 'rgba(255,255,255,0.2)';
+                }}
+                onMouseLeave={(e) => {
+                  e.currentTarget.style.background = 'rgba(255,255,255,0.05)';
+                  e.currentTarget.style.borderColor = 'rgba(255,255,255,0.1)';
+                }}
+              >
+                Mantine
+              </div>
+              <div
+                style={{
+                  padding: '4px 8px',
+                  borderRadius: 6,
+                  background: 'rgba(255,255,255,0.05)',
+                  border: '1px solid rgba(255,255,255,0.1)',
+                  fontSize: 11,
+                  color: 'rgba(255,255,255,0.7)',
+                  transition: 'all 200ms ease',
+                }}
+                onMouseEnter={(e) => {
+                  e.currentTarget.style.background = 'rgba(255,255,255,0.1)';
+                  e.currentTarget.style.borderColor = 'rgba(255,255,255,0.2)';
+                }}
+                onMouseLeave={(e) => {
+                  e.currentTarget.style.background = 'rgba(255,255,255,0.05)';
+                  e.currentTarget.style.borderColor = 'rgba(255,255,255,0.1)';
+                }}
+              >
+                Nextra
+              </div>
+            </div>
+          </div>
+        </div>
+
+        {/* Divider */}
+        <div 
+          style={{ 
+            height: 1,
+            margin: '8px 0',
+            background: 'linear-gradient(90deg, transparent, rgba(255,255,255,0.1), transparent)',
+          }} 
+        />
+
+        {/* Bottom section - Copyright */}
+        <div style={{ 
+          display: 'flex', 
+          justifyContent: 'space-between', 
+          alignItems: 'center', 
+          width: '100%',
+          flexWrap: 'wrap',
+          gap: 16
+        }}>
+          <p style={{ 
+            fontSize: 14, 
+            color: 'rgba(255,255,255,0.6)', 
+            margin: 0
+          }}>
+            Apache {new Date().getFullYear()} ©{' '}
+            <a 
+              href="https://resilientdb.incubator.apache.org/" 
+              style={{ 
+                color: 'rgba(255,255,255,0.6)',
+                transition: 'all 200ms ease',
+                textDecoration: 'none',
+              }}
+              onMouseEnter={(e) => {
+                e.currentTarget.style.color = 'rgba(255,255,255,0.9)';
+              }}
+              onMouseLeave={(e) => {
+                e.currentTarget.style.color = 'rgba(255,255,255,0.6)';
+              }}
+            >
+              Apache Software Foundation
+            </a>
+          </p>
+          
+          <div style={{ display: 'flex', gap: 16, alignItems: 'center' }}>
+            <span style={{ 
+              fontSize: 12, 
+              color: 'rgba(255,255,255,0.6)', 
+              opacity: 0.7
+            }}>
+              Licensed under Apache 2.0
+            </span>
+            <div
+              style={{
+                width: 4,
+                height: 4,
+                borderRadius: '50%',
+                background: 'rgba(255,255,255,0.3)',
+                opacity: 0.5,
+              }}
+            />
+            <span style={{ 
+              fontSize: 12, 
+              color: 'rgba(255,255,255,0.6)', 
+              opacity: 0.7
+            }}>
+              Incubating Project
+            </span>
+          </div>
+        </div>
+      </div>
+    </div>
+  </footer>
+);
diff --git a/ecosystem/AI-Tooling/beacon/components/MantineNavBar/MantineNavBar.tsx b/ecosystem/AI-Tooling/beacon/components/MantineNavBar/MantineNavBar.tsx
new file mode 100644
index 00000000..26ebc8a2
--- /dev/null
+++ b/ecosystem/AI-Tooling/beacon/components/MantineNavBar/MantineNavBar.tsx
@@ -0,0 +1,47 @@
+/*
+* Licensed to the Apache Software Foundation (ASF) under one
+* or more contributor license agreements.  See the NOTICE file
+* distributed with this work for additional information
+* regarding copyright ownership.  The ASF licenses this file
+* to you under the Apache License, Version 2.0 (the
+* "License"); you may not use this file except in compliance
+* with the License.  You may obtain a copy of the License at
+* 
+*   http://www.apache.org/licenses/LICENSE-2.0
+* 
+* Unless required by applicable law or agreed to in writing,
+* software distributed under the License is distributed on an
+* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+* KIND, either express or implied.  See the License for the
+* specific language governing permissions and limitations
+* under the License.
+*/
+
+'use client';
+
+import { Box } from '@mantine/core';
+import { usePathname } from 'next/navigation';
+
+import '@mantine/core/styles.css';
+import { MantineNextraThemeObserver } from '../MantineNextraThemeObserver/MantineNextraThemeObserver';
+import Header from '@/components/landing/Header';
+
+/**
+ * You can customize the Nextra NavBar component.
+ * Don't forget to use the MantineProvider and MantineNextraThemeObserver components.
+ *
+ * @since 1.0.0
+ *
+ */
+export const MantineNavBar = () => {
+  const pathname = usePathname();
+  if (pathname === '/') return null;
+  return (
+    <>
+      <MantineNextraThemeObserver />
+      <Box>
+        <Header />
+      </Box>
+    </>
+  );
+};
diff --git a/ecosystem/AI-Tooling/beacon/components/MantineNextraThemeObserver/MantineNextraThemeObserver.tsx b/ecosystem/AI-Tooling/beacon/components/MantineNextraThemeObserver/MantineNextraThemeObserver.tsx
new file mode 100644
index 00000000..d68b170d
--- /dev/null
+++ b/ecosystem/AI-Tooling/beacon/components/MantineNextraThemeObserver/MantineNextraThemeObserver.tsx
@@ -0,0 +1,43 @@
+/*
+* Licensed to the Apache Software Foundation (ASF) under one
+* or more contributor license agreements.  See the NOTICE file
+* distributed with this work for additional information
+* regarding copyright ownership.  The ASF licenses this file
+* to you under the Apache License, Version 2.0 (the
+* "License"); you may not use this file except in compliance
+* with the License.  You may obtain a copy of the License at
+* 
+*   http://www.apache.org/licenses/LICENSE-2.0
+* 
+* Unless required by applicable law or agreed to in writing,
+* software distributed under the License is distributed on an
+* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+* KIND, either express or implied.  See the License for the
+* specific language governing permissions and limitations
+* under the License.
+*/
+
+import { useTheme } from 'nextra-theme-docs';
+import { useMantineColorScheme } from '@mantine/core';
+import { useDidUpdate } from '@mantine/hooks';
+
+/**
+ * This component is responsible for observing the theme changes in Nextra and Mantine.
+ * By using this component, you can ensure that the Mantine theme is always in sync with the Nextra theme.
+ *
+ * This component is used in the MantineNavBar component.
+ *
+ * @since 1.0.0
+ *
+ * @see https://mantine.dev/docs/color-scheme/
+ */
+export function MantineNextraThemeObserver() {
+  const { setColorScheme } = useMantineColorScheme();
+  const { theme } = useTheme();
+
+  useDidUpdate(() => {
+    setColorScheme(theme === 'dark' ? 'dark' : theme === 'system' ? 'auto' : 'light');
+  }, [theme]);
+
+  return null;
+}
diff --git a/ecosystem/AI-Tooling/beacon/components/PocketFlowChatbot.tsx b/ecosystem/AI-Tooling/beacon/components/PocketFlowChatbot.tsx
new file mode 100644
index 00000000..fd3f3761
--- /dev/null
+++ b/ecosystem/AI-Tooling/beacon/components/PocketFlowChatbot.tsx
@@ -0,0 +1,149 @@
+/*
+* Licensed to the Apache Software Foundation (ASF) under one
+* or more contributor license agreements.  See the NOTICE file
+* distributed with this work for additional information
+* regarding copyright ownership.  The ASF licenses this file
+* to you under the Apache License, Version 2.0 (the
+* "License"); you may not use this file except in compliance
+* with the License.  You may obtain a copy of the License at
+* 
+*   http://www.apache.org/licenses/LICENSE-2.0
+* 
+* Unless required by applicable law or agreed to in writing,
+* software distributed under the License is distributed on an
+* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+* KIND, either express or implied.  See the License for the
+* specific language governing permissions and limitations
+* under the License.
+*/
+
+'use client';
+
+import { useEffect, useRef } from 'react';
+
+declare global {
+  interface Window {
+    initializeChatbot: (config: any) => void;
+  }
+}
+
+interface PocketFlowChatbotProps {
+  extraUrls?: string[];
+  prefixes?: string[];
+  chatbotName?: string;
+  wsUrl?: string;
+  instruction?: string;
+  isOpen?: boolean;
+}
+
+export function PocketFlowChatbot({
+  extraUrls = ["https://beacon.resilientdb.com/docs"],
+  prefixes = [],
+  chatbotName = 'Beacon',
+  wsUrl = 'wss://askthispage.com/api/ws/chat',
+  instruction = '',
+  isOpen = false
+}: PocketFlowChatbotProps) {
+  const containerRef = useRef<HTMLDivElement>(null);
+
+  useEffect(() => {
+    // Check if the script is already loaded
+    if (document.querySelector('script[src="https://askthispage.com/embed/chatbot.js"]')) {
+      return;
+    }
+
+    const script = document.createElement("script");
+    script.src = "https://askthispage.com/embed/chatbot.js";
+    script.onload = function() {
+      if (window.initializeChatbot) {
+        window.initializeChatbot({
+          extra_urls: extraUrls,
+          prefixes: prefixes,
+          chatbotName: chatbotName,
+          wsUrl: wsUrl,
+          instruction: instruction,
+          isOpen: isOpen
+        });
+      }
+    };
+    document.head.appendChild(script);
+
+    // Cleanup function
+    return () => {
+      const existingScript = document.querySelector('script[src="https://askthispage.com/embed/chatbot.js"]');
+      if (existingScript) {
+        existingScript.remove();
+      }
+    };
+  }, [extraUrls, prefixes, chatbotName, wsUrl, instruction, isOpen]);
+
+  // Add custom styles after the chatbot loads
+  useEffect(() => {
+    const checkAndStyle = () => {
+      const chatbot = document.querySelector('.askthispage-chatbot') as HTMLElement;
+      if (chatbot) {
+        // Move to left corner
+        chatbot.style.position = 'fixed';
+        chatbot.style.left = '20px';
+        chatbot.style.right = 'auto';
+        chatbot.style.bottom = '20px';
+        chatbot.style.zIndex = '1000';
+
+        // Add experimental badge
+        const badge = document.createElement('div');
+        badge.innerHTML = '🧪 Experimental';
+        badge.style.cssText = `
+          position: absolute;
+          top: -30px;
+          left: 0;
+          background: linear-gradient(45deg, #ff6b6b, #ffa500);
+          color: white;
+          padding: 4px 8px;
+          border-radius: 12px;
+          font-size: 10px;
+          font-weight: bold;
+          text-transform: uppercase;
+          letter-spacing: 0.5px;
+          box-shadow: 0 2px 8px rgba(0,0,0,0.2);
+          z-index: 1001;
+          animation: pulse 2s infinite;
+          white-space: nowrap;
+        `;
+
+        // Add pulse animation
+        const style = document.createElement('style');
+        style.textContent = `
+          @keyframes pulse {
+            0% { opacity: 1; }
+            50% { opacity: 0.7; }
+            100% { opacity: 1; }
+          }
+        `;
+        document.head.appendChild(style);
+
+        chatbot.appendChild(badge);
+      }
+    };
+
+    // Check immediately and then periodically
+    checkAndStyle();
+    const interval = setInterval(checkAndStyle, 1000);
+
+    return () => {
+      clearInterval(interval);
+    };
+  }, []);
+
+  return (
+    <div 
+      ref={containerRef}
+      style={{
+        position: 'fixed',
+        left: '20px',
+        bottom: '20px',
+        zIndex: 1000,
+        pointerEvents: 'none'
+      }}
+    />
+  );
+} 
\ No newline at end of file
diff --git a/ecosystem/AI-Tooling/beacon/components/PythonIDE.tsx b/ecosystem/AI-Tooling/beacon/components/PythonIDE.tsx
new file mode 100644
index 00000000..7bd8a2a9
--- /dev/null
+++ b/ecosystem/AI-Tooling/beacon/components/PythonIDE.tsx
@@ -0,0 +1,114 @@
+/*
+* Licensed to the Apache Software Foundation (ASF) under one
+* or more contributor license agreements.  See the NOTICE file
+* distributed with this work for additional information
+* regarding copyright ownership.  The ASF licenses this file
+* to you under the Apache License, Version 2.0 (the
+* "License"); you may not use this file except in compliance
+* with the License.  You may obtain a copy of the License at
+* 
+*   http://www.apache.org/licenses/LICENSE-2.0
+* 
+* Unless required by applicable law or agreed to in writing,
+* software distributed under the License is distributed on an
+* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+* KIND, either express or implied.  See the License for the
+* specific language governing permissions and limitations
+* under the License.
+*/
+
+"use client"
+import { useEffect, useRef, useState } from "react"
+import { loadPyodideInstance } from "@/components/utils/loadPyodide"
+
+export default function PythonSplitIDE({ defaultCode }: { defaultCode: string }) {
+  const [pyodide, setPyodide] = useState<any>(null)
+  const [output, setOutput] = useState<string[]>(["Initializing Python..."])
+  const [isLoading, setIsLoading] = useState(true)
+  const [isRunning, setIsRunning] = useState(false)
+  const textareaRef = useRef<HTMLTextAreaElement>(null)
+
+  useEffect(() => {
+    async function init() {
+      try {
+        const py = await loadPyodideInstance()
+
+        py.globals.set("js_print", (text: string) => {
+          setOutput(prev => [...prev, text])
+        })
+
+        await py.runPythonAsync(`import builtins\nbuiltins.print = js_print`)
+
+        const sdk = await fetch("/resdb_sdk.py").then(res => res.text())
+        await py.runPythonAsync(sdk)
+
+        setPyodide(py)
+        setOutput(["✅ Python environment loaded."])
+        setIsLoading(false)
+      } catch (e) {
+        console.error(e)
+        setOutput(["❌ Failed to initialize Python."])
+        setIsLoading(false)
+      }
+    }
+
+    init()
+  }, [])
+
+  const runCode = async () => {
+    if (!pyodide || !textareaRef.current) return
+    setIsRunning(true)
+    setOutput(prev => [...prev, "\n▶ Running code..."])
+
+    try {
+      const code = textareaRef.current.value
+      await pyodide.runPythonAsync(code)
+      setOutput(prev => [...prev, "✅ Code execution completed."])
+    } catch (err: any) {
+      setOutput(prev => [...prev, `❌ Error: ${err.message}`])
+    } finally {
+      setIsRunning(false)
+    }
+  }
+
+  return (
+    <div className="flex flex-col md:flex-row gap-4 w-full my-6">
+      {/* Left side: Editor */}
+      <div className="flex-1 bg-black rounded-lg p-4 border border-slate-700">
+        <textarea
+          ref={textareaRef}
+          defaultValue={defaultCode}
+          className="w-full h-[400px] bg-black text-green-200 font-mono text-sm p-4 rounded resize-none border border-slate-600"
+          placeholder="Write your Python code here..."
+          disabled={isLoading}
+        />
+        <div className="mt-4 flex gap-2">
+          <button
+            onClick={runCode}
+            disabled={isLoading || isRunning}
+            className="px-4 py-2 rounded bg-blue-600 text-white text-sm hover:bg-blue-700"
+          >
+            {isRunning ? "Running..." : "Run Code"}
+          </button>
+          <button
+            onClick={() => setOutput([])}
+            className="px-4 py-2 rounded bg-slate-700 text-white text-sm hover:bg-slate-600"
+          >
+            Clear Output
+          </button>
+        </div>
+      </div>
+
+      {/* Right side: Output */}
+      <div className="flex-1 bg-slate-900 text-green-400 font-mono text-sm p-4 border border-slate-700 rounded-lg overflow-auto h-[400px]">
+        {output.length === 0 ? (
+          <div className="text-slate-500">No output yet.</div>
+        ) : (
+          output.map((line, i) => <div key={i}>{line}</div>)
+        )}
+        {isLoading && <div className="text-slate-400">⏳ Loading Python...</div>}
+        {isRunning && <div className="text-slate-400">⚙️ Running...</div>}
+      </div>
+    </div>
+  )
+}
diff --git a/ecosystem/AI-Tooling/beacon/components/PythonPlayground.tsx b/ecosystem/AI-Tooling/beacon/components/PythonPlayground.tsx
new file mode 100644
index 00000000..1a063f5e
--- /dev/null
+++ b/ecosystem/AI-Tooling/beacon/components/PythonPlayground.tsx
@@ -0,0 +1,773 @@
+/*
+* Licensed to the Apache Software Foundation (ASF) under one
+* or more contributor license agreements.  See the NOTICE file
+* distributed with this work for additional information
+* regarding copyright ownership.  The ASF licenses this file
+* to you under the Apache License, Version 2.0 (the
+* "License"); you may not use this file except in compliance
+* with the License.  You may obtain a copy of the License at
+* 
+*   http://www.apache.org/licenses/LICENSE-2.0
+* 
+* Unless required by applicable law or agreed to in writing,
+* software distributed under the License is distributed on an
+* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+* KIND, either express or implied.  See the License for the
+* specific language governing permissions and limitations
+* under the License.
+*/
+
+'use client';
+
+import { useEffect, useState, useRef } from 'react';
+import { python } from '@codemirror/lang-python';
+import { IconPlayerPlay, IconTemplate, IconTrash, IconMessage, IconPlayerStop, IconMaximize, IconMinimize } from '@tabler/icons-react';
+import { vscodeDark } from '@uiw/codemirror-theme-vscode';
+import CodeMirror from '@uiw/react-codemirror';
+import { Box, Button, Group, Paper, Select, Stack, Text, Tooltip, Textarea, ActionIcon, Modal } from '@mantine/core';
+import ReactMarkdown from 'react-markdown';
+import { Prism as SyntaxHighlighter } from 'react-syntax-highlighter';
+import { vscDarkPlus } from 'react-syntax-highlighter/dist/cjs/styles/prism';
+
+declare global {
+  interface Window {
+    loadPyodide: (options: { indexURL: string }) => Promise<any>;
+    pyodide: any;
+  }
+}
+
+interface Template {
+  value: string;
+  label: string;
+  code: string;
+}
+
+interface Message {
+  role: 'user' | 'assistant';
+  content: string;
+}
+
+interface CodeProps {
+  node?: any;
+  inline?: boolean;
+  className?: string;
+  children?: React.ReactNode;
+  [key: string]: any;
+}
+
+const EXAMPLE_TEMPLATES = [
+  {
+    value: 'default',
+    label: 'Instructions',
+    code: `
+      """
+        Instructions
+      """
+    `,
+  },
+  {
+    value: 'solution',
+    label: 'Solution',
+    code: `
+      """
+        Solution
+      """
+`,
+  },
+];
+
+export function PythonPlayground({ templates }: { templates?: Template[] }) {
+  const codeTemplates = templates && Array.isArray(templates) ? templates : EXAMPLE_TEMPLATES;
+  const [code, setCode] = useState<string>(codeTemplates[0].code);
+  const [output, setOutput] = useState<string[]>(['Initializing Python environment...']);
+  const [isLoading, setIsLoading] = useState(true);
+  const [isRunning, setIsRunning] = useState(false);
+  const [showChat, setShowChat] = useState(false);
+  const [messages, setMessages] = useState<Message[]>([]);
+  const [input, setInput] = useState('');
+  const [isAiLoading, setIsAiLoading] = useState(false);
+  const [abortController, setAbortController] = useState<AbortController | null>(null);
+  const [isExpanded, setIsExpanded] = useState(false);
+  const expandTriggerRef = useRef<HTMLButtonElement | null>(null);
+  const lastFocusedRef = useRef<HTMLElement | null>(null);
+
+  const openExpanded = (from?: HTMLElement | null) => {
+    lastFocusedRef.current = from ?? (document.activeElement as HTMLElement | null);
+    setIsExpanded(true);
+    setTimeout(() => {
+      const ta = document.querySelector('textarea') as HTMLElement | null;
+      ta?.focus?.();
+    }, 50);
+  };
+
+  const closeExpanded = () => {
+    setIsExpanded(false);
+    setTimeout(() => {
+      try { lastFocusedRef.current?.focus?.(); } catch (err) {}
+    }, 0);
+  };
+
+  useEffect(() => {
+    if (!isExpanded) return;
+    const onKey = (e: KeyboardEvent) => {
+      if (e.key === 'Escape') {
+        e.preventDefault();
+        closeExpanded();
+      }
+    };
+    document.addEventListener('keydown', onKey);
+    return () => document.removeEventListener('keydown', onKey);
+  }, [isExpanded]);
+
+  const handleSubmit = async (e: React.FormEvent) => {
+    e.preventDefault();
+    if (!input.trim()) return;
+
+    const userMessage: Message = { role: 'user', content: input };
+    setMessages(prev => [...prev, userMessage]);
+    setInput('');
+    setIsAiLoading(true);
+
+    // Create new AbortController for this request
+    const controller = new AbortController();
+    setAbortController(controller);
+
+    try {
+      const response = await fetch('/api/chat', {
+        method: 'POST',
+        headers: { 'Content-Type': 'application/json' },
+        body: JSON.stringify({ messages: [...messages, userMessage], code }),
+        signal: controller.signal
+      });
+
+      if (!response.ok) throw new Error('Failed to get response');
+      
+      const reader = response.body?.getReader();
+      if (!reader) throw new Error('No reader available');
+
+      let assistantMessage = '';
+      while (true) {
+        const { done, value } = await reader.read();
+        if (done) break;
+        
+        const text = new TextDecoder().decode(value);
+        assistantMessage += text;
+        setMessages(prev => {
+          const newMessages = [...prev];
+          const lastMessage = newMessages[newMessages.length - 1];
+          if (lastMessage.role === 'assistant') {
+            lastMessage.content = assistantMessage;
+          } else {
+            newMessages.push({ role: 'assistant', content: assistantMessage });
+          }
+          return newMessages;
+        });
+      }
+    } catch (error) {
+      if (error instanceof Error && error.name === 'AbortError') {
+        setMessages(prev => [...prev, { role: 'assistant', content: 'Response generation stopped.' }]);
+      } else {
+        console.error('Chat error:', error);
+        setMessages(prev => [...prev, { role: 'assistant', content: 'Sorry, there was an error processing your request.' }]);
+      }
+    } finally {
+      setIsAiLoading(false);
+      setAbortController(null);
+    }
+  };
+
+  const handleKeyDown = (e: React.KeyboardEvent<HTMLTextAreaElement>) => {
+    if (e.key === 'Enter' && !e.shiftKey) {
+      e.preventDefault();
+      if (input.trim() && !isAiLoading) {
+        handleSubmit(e as unknown as React.FormEvent);
+      }
+    }
+  };
+
+  const stopGeneration = () => {
+    if (abortController) {
+      abortController.abort();
+      setAbortController(null);
+    }
+  };
+
+  useEffect(() => {
+    const initPython = async () => {
+      try {
+        if (window.pyodide) {
+          setOutput(['✅ Python environment ready']);
+          setIsLoading(false);
+          return;
+        }
+
+        const script = document.createElement('script');
+        script.src = 'https://cdn.jsdelivr.net/pyodide/v0.24.1/full/pyodide.js';
+        document.head.appendChild(script);
+
+        await new Promise((resolve) => {
+          script.onload = resolve;
+        });
+
+        const pyodide = await window.loadPyodide({
+          indexURL: 'https://cdn.jsdelivr.net/pyodide/v0.24.1/full/',
+        });
+
+
+        // Load and register our SDK
+        const sdk = await fetch('/resdb_sdk.py').then((res) => res.text());
+        await pyodide.runPythonAsync(sdk);
+
+        // Register the SDK as a module
+        await pyodide.runPythonAsync(`
+import sys
+import types
+resdb_sdk = types.ModuleType('resdb_sdk')
+resdb_sdk.__dict__.update(globals())
+sys.modules['resdb_sdk'] = resdb_sdk
+        `);
+
+        await pyodide.runPythonAsync(`
+          import sys
+          from io import StringIO
+          sys.stdout = StringIO()
+          sys.stderr = StringIO()
+        `);
+
+        window.pyodide = pyodide;
+        setOutput(['✅ Python environment ready']);
+        setIsLoading(false);
+      } catch (error) {
+        setOutput((prev) => [
+          ...prev,
+          `❌ Error: ${error instanceof Error ? error.message : 'Unknown error'}`,
+        ]);
+        setIsLoading(false);
+      }
+    };
+
+    initPython();
+  }, []);
+
+  const runCode = async () => {
+    if (isLoading || isRunning) {
+      return;
+    }
+    setIsRunning(true);
+    setOutput(['▶ Running code...']);
+
+    try {
+      // Wrap code in async function if it uses await
+      const codeToRun = /\bawait\b/.test(code)
+        ? `
+async def __run():
+${code
+  .split('\n')
+  .map((line: string) => `    ${line}`)
+  .join('\n')}
+
+import asyncio
+loop = asyncio.get_event_loop()
+loop.run_until_complete(__run())
+`
+        : code;
+
+      // Run the code and capture output
+      await window.pyodide.runPythonAsync(codeToRun);
+
+      // Get output
+      const stdout = await window.pyodide.runPythonAsync('sys.stdout.getvalue()');
+      if (stdout) {
+        setOutput((prev) => [...prev, stdout]);
+      }
+
+      setOutput((prev) => [...prev, '✅ Code execution completed']);
+    } catch (error: any) {
+      setOutput((prev) => [...prev, `❌ Error: ${error.message}`]);
+    } finally {
+      // Clear buffers
+      await window.pyodide.runPythonAsync('sys.stdout.truncate(0)\nsys.stdout.seek(0)');
+      setIsRunning(false);
+    }
+  };
+
+  const clearOutput = () => setOutput([]);
+
+  const clearConversation = () => {
+    setMessages([]);
+  };
+
+  return (
+    <div
+      style={{
+        background: 'rgba(255,255,255,0.02)',
+        backdropFilter: 'blur(12px)',
+        border: '1px solid rgba(255,255,255,0.08)',
+        borderRadius: 16,
+        padding: 24,
+        position: 'relative',
+        overflow: 'hidden',
+      }}
+    >
+      {/* Glass effect overlay */}
+      <div style={{ 
+        position: 'absolute', 
+        top: 0, 
+        left: 0, 
+        right: 0, 
+        height: 1, 
+        background: 'linear-gradient(90deg, transparent, rgba(255,255,255,0.2), transparent)', 
+        borderRadius: '16px 16px 0 0' 
+      }} />
+      
+      <Stack gap={20}>
+        <Group justify="space-between" align="center">
+          <div
+            style={{
+              display: 'inline-flex',
+              alignItems: 'center',
+              paddingInline: 12,
+              paddingBlock: 6,
+              borderRadius: 999,
+              background: 'rgba(255,255,255,0.05)',
+              backdropFilter: 'blur(6px)',
+              border: '1px solid rgba(255,255,255,0.1)',
+            }}
+          >
+            <span style={{ color: 'rgba(255,255,255,0.9)', fontSize: 12, fontWeight: 300 }}>
+              🐍 Python Playground
+            </span>
+          </div>
+          
+          <Group gap={8}>
+            <Tooltip label="Load example">
+              <Select
+                size="xs"
+                placeholder="Load example"
+                data={codeTemplates}
+                onChange={(value) =>
+                  value && setCode(codeTemplates.find((t) => t.value === value)?.code || '')
+                }
+                leftSection={<IconTemplate size={14} />}
+                styles={{
+                  input: {
+                    background: 'rgba(255,255,255,0.05)',
+                    border: '1px solid rgba(255,255,255,0.1)',
+                    color: 'rgba(255,255,255,0.9)',
+                    '&:focus': {
+                      borderColor: 'rgba(0, 191, 255, 0.5)',
+                    }
+                  }
+                }}
+              />
+            </Tooltip>
+            <Tooltip label="Ask AI Assistant">
+              <ActionIcon 
+                variant="light" 
+                onClick={() => setShowChat(!showChat)}
+                color={showChat ? "blue" : "gray"}
+                style={{
+                  background: showChat ? 'rgba(0, 191, 255, 0.1)' : 'rgba(255,255,255,0.05)',
+                  border: '1px solid rgba(255,255,255,0.1)',
+                  color: showChat ? '#00bfff' : 'rgba(255,255,255,0.7)',
+                }}
+              >
+                <IconMessage size={14} />
+              </ActionIcon>
+            </Tooltip>
+          </Group>
+        </Group>
+
+        <div
+          style={{
+            background: 'rgba(0,0,0,0.3)',
+            border: '1px solid rgba(255,255,255,0.1)',
+            borderRadius: 12,
+            overflow: 'hidden',
+            position: 'relative',
+          }}
+        >
+          <CodeMirror
+            value={code}
+            height="400px"
+            theme={vscodeDark}
+            extensions={[python()]}
+            onChange={setCode}
+            editable={!isLoading}
+            basicSetup={{
+              lineNumbers: true,
+              highlightActiveLineGutter: true,
+              highlightSpecialChars: true,
+              history: true,
+              foldGutter: true,
+              drawSelection: true,
+              dropCursor: true,
+              allowMultipleSelections: true,
+              indentOnInput: true,
+              syntaxHighlighting: true,
+              bracketMatching: true,
+              closeBrackets: true,
+              autocompletion: true,
+              rectangularSelection: true,
+              crosshairCursor: true,
+              highlightActiveLine: true,
+              highlightSelectionMatches: true,
+              closeBracketsKeymap: true,
+              defaultKeymap: true,
+              searchKeymap: true,
+              historyKeymap: true,
+              foldKeymap: true,
+              completionKeymap: true,
+              lintKeymap: true,
+            }}
+          />
+        </div>
+
+        {showChat && (
+          <>
+            <div
+              style={{
+                background: 'rgba(255,255,255,0.03)',
+                backdropFilter: 'blur(8px)',
+                border: '1px solid rgba(255,255,255,0.08)',
+                borderRadius: 12,
+                padding: 16,
+                position: 'relative',
+              }}
+            >
+              <Stack gap={16}>
+                <Group justify="space-between" align="center">
+                  <div
+                    style={{
+                      display: 'inline-flex',
+                      alignItems: 'center',
+                      paddingInline: 8,
+                      paddingBlock: 4,
+                      borderRadius: 6,
+                      background: 'rgba(0, 191, 255, 0.1)',
+                      border: '1px solid rgba(0, 191, 255, 0.2)',
+                    }}
+                  >
+                    <Text size="xs" fw={500} c="#00bfff">AI Assistant</Text>
+                  </div>
+                  <Group gap={4}>
+                    <Tooltip label={isExpanded ? "Minimize" : "Expand"}>
+                      <ActionIcon 
+                        ref={expandTriggerRef}
+                        variant="light" 
+                        onClick={(e) => openExpanded(e.currentTarget)}
+                        onKeyDown={(e) => {
+                          if (e.key === 'Enter' || e.key === ' ') {
+                            e.preventDefault();
+                            openExpanded(e.currentTarget as HTMLElement);
+                          }
+                        }}
+                        disabled={isExpanded}
+                        style={{
+                          background: 'rgba(255,255,255,0.05)',
+                          border: '1px solid rgba(255,255,255,0.1)',
+                          color: 'rgba(255,255,255,0.7)',
+                        }}
+                      >
+                        <IconMaximize size={14} />
+                      </ActionIcon>
+                    </Tooltip>
+                    <Tooltip label="Clear conversation">
+                      <ActionIcon 
+                        variant="light" 
+                        color="red" 
+                        onClick={clearConversation}
+                        disabled={messages.length === 0}
+                        style={{
+                          background: 'rgba(255,255,255,0.05)',
+                          border: '1px solid rgba(255,255,255,0.1)',
+                          color: 'rgba(255,255,255,0.7)',
+                        }}
+                      >
+                        <IconTrash size={14} />
+                      </ActionIcon>
+                    </Tooltip>
+                  </Group>
+                </Group>
+                <div style={{ maxHeight: '200px', overflowY: 'auto' }}>
+                  {[...messages].reverse().map((message, i) => (
+                    <div
+                      key={i}
+                      style={{
+                        padding: 12,
+                        marginBottom: 8,
+                        borderRadius: 8,
+                        background: message.role === 'user' 
+                          ? 'rgba(0, 191, 255, 0.1)' 
+                          : 'rgba(255,255,255,0.05)',
+                        border: '1px solid rgba(255,255,255,0.08)',
+                        backdropFilter: 'blur(4px)',
+                      }}
+                    >
+                      <Text 
+                        size="sm" 
+                        c={message.role === 'user' ? '#00bfff' : 'rgba(255,255,255,0.9)'}
+                        style={{ lineHeight: 1.5 }}
+                      >
+                        {message.role === 'user' ? (
+                          message.content
+                        ) : (
+                          <ReactMarkdown
+                            components={{
+                              code({ node, inline, className, children, ...props }: CodeProps) {
+                                const match = /language-(\w+)/.exec(className || '');
+                                return !inline && match ? (
+                                  <SyntaxHighlighter
+                                    style={vscDarkPlus}
+                                    language={match[1]}
+                                    PreTag="div"
+                                    {...props}
+                                  >
+                                    {String(children).replace(/\n$/, '')}
+                                  </SyntaxHighlighter>
+                                ) : (
+                                  <code className={className} {...props}>
+                                    {children}
+                                  </code>
+                                );
+                              },
+                            }}
+                          >
+                            {message.content}
+                          </ReactMarkdown>
+                        )}
+                      </Text>
+                    </div>
+                  ))}
+                </div>
+                <form onSubmit={handleSubmit}>
+                  <Group gap={8}>
+                    <Textarea
+                      placeholder="Ask about your code... (Press Enter to send, Shift+Enter for new line)"
+                      value={input}
+                      onChange={(e) => setInput(e.target.value)}
+                      onKeyDown={handleKeyDown}
+                      style={{ flex: 1 }}
+                      disabled={isAiLoading}
+                      autosize
+                      minRows={1}
+                      maxRows={4}
+                      styles={{
+                        input: {
+                          background: 'rgba(255,255,255,0.05)',
+                          border: '1px solid rgba(255,255,255,0.1)',
+                          color: 'rgba(255,255,255,0.9)',
+                          '&:focus': {
+                            borderColor: 'rgba(0, 191, 255, 0.5)',
+                          },
+                          '&::placeholder': {
+                            color: 'rgba(255,255,255,0.5)',
+                          }
+                        }
+                      }}
+                    />
+                    {isAiLoading ? (
+                      <Button 
+                        color="red" 
+                        onClick={stopGeneration}
+                        leftSection={<IconPlayerStop size={14} />}
+                        style={{
+                          background: 'rgba(255, 77, 77, 0.1)',
+                          border: '1px solid rgba(255, 77, 77, 0.3)',
+                          color: '#ff4d4d',
+                        }}
+                      >
+                        Stop
+                      </Button>
+                    ) : (
+                      <Button 
+                        type="submit"
+                        style={{
+                          background: 'rgba(0, 191, 255, 0.1)',
+                          border: '1px solid rgba(0, 191, 255, 0.3)',
+                          color: '#00bfff',
+                        }}
+                      >
+                        Send
+                      </Button>
+                    )}
+                  </Group>
+                </form>
+              </Stack>
+            </div>
+
+            <Modal
+              opened={isExpanded}
+              onClose={() => setIsExpanded(false)}
+              size="xl"
+              title={
+                <Group justify="space-between" w="100%">
+                  <Text size="sm" fw={500}>AI Assistant</Text>
+                  <Group>
+                    <Tooltip label="Minimize">
+                      <ActionIcon 
+                        variant="light" 
+                        onClick={() => setIsExpanded(false)}
+                      >
+                        <IconMinimize size={14} />
+                      </ActionIcon>
+                    </Tooltip>
+                    <Tooltip label="Clear conversation">
+                      <ActionIcon 
+                        variant="light" 
+                        color="red" 
+                        onClick={clearConversation}
+                        disabled={messages.length === 0}
+                      >
+                        <IconTrash size={14} />
+                      </ActionIcon>
+                    </Tooltip>
+                  </Group>
+                </Group>
+              }
+              styles={{
+                title: {
+                  width: '100%',
+                  marginRight: 0,
+                },
+                body: {
+                  height: 'calc(100vh - 200px)',
+                  display: 'flex',
+                  flexDirection: 'column',
+                },
+              }}
+            >
+              <Stack style={{ flex: 1, height: '100%' }}>
+                <Box style={{ flex: 1, overflowY: 'auto' }}>
+                  {[...messages].reverse().map((message, i) => (
+                    <Paper key={i} p="xs" mb="xs" bg={message.role === 'user' ? 'dark.6' : 'dark.7'}>
+                      <Text size="sm" c={message.role === 'user' ? 'blue' : 'white'}>
+                        {message.role === 'user' ? (
+                          message.content
+                        ) : (
+                          <ReactMarkdown
+                            components={{
+                              code({ node, inline, className, children, ...props }: CodeProps) {
+                                const match = /language-(\w+)/.exec(className || '');
+                                return !inline && match ? (
+                                  <SyntaxHighlighter
+                                    style={vscDarkPlus}
+                                    language={match[1]}
+                                    PreTag="div"
+                                    {...props}
+                                  >
+                                    {String(children).replace(/\n$/, '')}
+                                  </SyntaxHighlighter>
+                                ) : (
+                                  <code className={className} {...props}>
+                                    {children}
+                                  </code>
+                                );
+                              },
+                            }}
+                          >
+                            {message.content}
+                          </ReactMarkdown>
+                        )}
+                      </Text>
+                    </Paper>
+                  ))}
+                </Box>
+                <form onSubmit={handleSubmit}>
+                  <Group>
+                    <Textarea
+                      placeholder="Ask about your code... (Press Enter to send, Shift+Enter for new line)"
+                      value={input}
+                      onChange={(e) => setInput(e.target.value)}
+                      onKeyDown={handleKeyDown}
+                      style={{ flex: 1 }}
+                      disabled={isAiLoading}
+                      autosize
+                      minRows={1}
+                      maxRows={4}
+                    />
+                    {isAiLoading ? (
+                      <Button 
+                        color="red" 
+                        onClick={stopGeneration}
+                        leftSection={<IconPlayerStop size={14} />}
+                      >
+                        Stop
+                      </Button>
+                    ) : (
+                      <Button type="submit">
+                        Send
+                      </Button>
+                    )}
+                  </Group>
+                </form>
+              </Stack>
+            </Modal>
+          </>
+        )}
+
+        <Group justify="space-between">
+          <Button
+            onClick={runCode}
+            loading={isRunning}
+            disabled={isLoading}
+            leftSection={<IconPlayerPlay size={14} />}
+            style={{
+              background: 'rgba(0, 191, 255, 0.1)',
+              border: '1px solid rgba(0, 191, 255, 0.3)',
+              color: '#00bfff',
+              borderRadius: 8,
+            }}
+          >
+            {isRunning ? 'Running...' : 'Run'}
+          </Button>
+          <Button
+            onClick={clearOutput}
+            disabled={isLoading || output.length === 0}
+            leftSection={<IconTrash size={14} />}
+            style={{
+              background: 'rgba(255,255,255,0.05)',
+              border: '1px solid rgba(255,255,255,0.1)',
+              color: 'rgba(255,255,255,0.7)',
+              borderRadius: 8,
+            }}
+          >
+            Clear Output
+          </Button>
+        </Group>
+
+        <div
+          style={{
+            background: 'rgba(0,0,0,0.4)',
+            border: '1px solid rgba(255,255,255,0.1)',
+            borderRadius: 12,
+            padding: 16,
+            height: '200px',
+            overflow: 'auto',
+            fontFamily: 'monospace',
+            position: 'relative',
+          }}
+        >
+          {output.map((line, i) => (
+            <Text 
+              key={i} 
+              style={{ 
+                whiteSpace: 'pre-wrap', 
+                color: line.includes('✅') ? '#00ff88' : 
+                       line.includes('❌') ? '#ff4d4d' : 
+                       line.includes('▶') ? '#00bfff' : 
+                       'rgba(255,255,255,0.8)',
+                fontSize: 13,
+                lineHeight: 1.4,
+                display: 'block',
+                marginBottom: 2,
+              }}
+            >
+              {line}
+            </Text>
+          ))}
+        </div>
+      </Stack>
+    </div>
+  );
+}
diff --git a/ecosystem/AI-Tooling/beacon/components/ReleaseNotes/ReleaseNotes.tsx b/ecosystem/AI-Tooling/beacon/components/ReleaseNotes/ReleaseNotes.tsx
new file mode 100644
index 00000000..53845ea4
--- /dev/null
+++ b/ecosystem/AI-Tooling/beacon/components/ReleaseNotes/ReleaseNotes.tsx
@@ -0,0 +1,148 @@
+/*
+* Licensed to the Apache Software Foundation (ASF) under one
+* or more contributor license agreements.  See the NOTICE file
+* distributed with this work for additional information
+* regarding copyright ownership.  The ASF licenses this file
+* to you under the Apache License, Version 2.0 (the
+* "License"); you may not use this file except in compliance
+* with the License.  You may obtain a copy of the License at
+* 
+*   http://www.apache.org/licenses/LICENSE-2.0
+* 
+* Unless required by applicable law or agreed to in writing,
+* software distributed under the License is distributed on an
+* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+* KIND, either express or implied.  See the License for the
+* specific language governing permissions and limitations
+* under the License.
+*/
+
+'use client';
+
+import { useEffect, useState } from 'react';
+import { compileMdx } from 'nextra/compile';
+import { MDXRemote } from 'nextra/mdx-remote';
+import useSWR from 'swr';
+import { Alert, Badge, Group, Loader, Paper, Skeleton, Stack, Text } from '@mantine/core';
+import { useMDXComponents } from '@/mdx-components';
+
+interface Author {
+  login: string;
+  id: number;
+  node_id: string;
+  avatar_url: string;
+  gravatar_id: string;
+  url: string;
+  html_url: string;
+  followers_url: string;
+  following_url: string;
+  gists_url: string;
+  starred_url: string;
+  subscriptions_url: string;
+  organizations_url: string;
+  repos_url: string;
+  events_url: string;
+  received_events_url: string;
+  type: string;
+  user_view_type: string;
+  site_admin: boolean;
+}
+
+interface Release {
+  url: string;
+  assets_url: string;
+  upload_url: string;
+  html_url: string;
+  id: number;
+  author: Author;
+  node_id: string;
+  tag_name: string;
+  target_commitish: string;
+  name: string;
+  draft: boolean;
+  prerelease: boolean;
+  created_at: string;
+  published_at: string;
+  assets: any[];
+  tarball_url: string;
+  zipball_url: string;
+  body: string;
+}
+
+const fetcher = (url: string) => fetch(url).then((res) => res.json());
+
+export function ReleaseNotes() {
+  const { data, error, isLoading } = useSWR<{
+    releases: Release[];
+  }>('/api/github-releases', fetcher);
+  const [compiledReleases, setCompiledReleases] = useState<Release[]>([]);
+
+  const components = useMDXComponents();
+
+  useEffect(() => {
+    if (data) {
+      const fetchReleases = async () => {
+        const releases = await Promise.all(
+          data.releases.map(async (release) => ({
+            ...release,
+            created_at: new Date(release.created_at).toLocaleDateString('en-US', {
+              year: 'numeric',
+              month: 'long',
+              day: 'numeric',
+            }),
+            body: await compileMdx(release.body),
+          }))
+        );
+        setCompiledReleases(releases);
+      };
+      fetchReleases();
+    }
+  }, [data, isLoading, error]); // Add isLoading and error to the dependency array
+
+  if (isLoading || compiledReleases.length === 0) {
+    return (
+      <Stack mt={24} w="100%" align="center">
+        <Group>
+          <Text>Loading releases...</Text>
+          <Loader type="dots" />
+        </Group>
+        <Skeleton height={200} width="100%" radius={12} />
+        <Skeleton height={50} width="100%" radius={12} />
+        <Skeleton height={20} width="100%" radius={12} />
+      </Stack>
+    );
+  }
+
+  if (error) {
+    return (
+      <Alert title="Error" color="red">
+        Failed to load releases
+      </Alert>
+    );
+  }
+
+  if (!data) {
+    return null;
+  }
+
+  if (compiledReleases.length === 0) {
+    return null;
+  }
+
+  return (
+    <Stack mt={24}>
+      {compiledReleases.map((release: Release) => (
+        <Paper key={release.id} withBorder p={24} radius={12} shadow="sm">
+          <Group justify="space-between">
+            <Badge component="a" href={release.html_url} size="xl">
+              {release.name}
+            </Badge>
+            <Text>{release.created_at}</Text>
+          </Group>
+
+          <MDXRemote compiledSource={release.body} components={components} />
+        </Paper>
+      ))}
+    </Stack>
+  );
+}
diff --git a/ecosystem/AI-Tooling/beacon/components/ResContractPlayground.tsx b/ecosystem/AI-Tooling/beacon/components/ResContractPlayground.tsx
new file mode 100644
index 00000000..fa3c5b18
--- /dev/null
+++ b/ecosystem/AI-Tooling/beacon/components/ResContractPlayground.tsx
@@ -0,0 +1,316 @@
+/*
+* Licensed to the Apache Software Foundation (ASF) under one
+* or more contributor license agreements.  See the NOTICE file
+* distributed with this work for additional information
+* regarding copyright ownership.  The ASF licenses this file
+* to you under the Apache License, Version 2.0 (the
+* "License"); you may not use this file except in compliance
+* with the License.  You may obtain a copy of the License at
+* 
+*   http://www.apache.org/licenses/LICENSE-2.0
+* 
+* Unless required by applicable law or agreed to in writing,
+* software distributed under the License is distributed on an
+* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+* KIND, either express or implied.  See the License for the
+* specific language governing permissions and limitations
+* under the License.
+*/
+
+'use client';
+
+import { useState } from 'react';
+import { Box, Tabs, TabsList, TabsTab, TabsPanel, Alert, Button, Paper, Text, Group, Code } from '@mantine/core';
+import { IconInfoCircle, IconPlayerPlay, IconCheck, IconX, IconCopy } from '@tabler/icons-react';
+import CodeMirror from '@uiw/react-codemirror';
+import { javascript } from '@codemirror/lang-javascript';
+import { vscodeDark } from '@uiw/codemirror-theme-vscode';
+
+const DEFAULT_CONTRACT = `// SPDX-License-Identifier: MIT
+pragma solidity ^0.8.0;
+
+contract SimpleToken {
+    string public name;
+    string public symbol;
+    uint256 public totalSupply;
+    mapping(address => uint256) public balanceOf;
+
+    constructor(string memory _name, string memory _symbol, uint256 _totalSupply) {
+        name = _name;
+        symbol = _symbol;
+        totalSupply = _totalSupply;
+        balanceOf[msg.sender] = _totalSupply;
+    }
+
+    function transfer(address _to, uint256 _value) public returns (bool) {
+        require(balanceOf[msg.sender] >= _value, "Insufficient balance");
+        balanceOf[msg.sender] -= _value;
+        balanceOf[_to] += _value;
+        return true;
+    }
+}`;
+
+const EXAMPLE_CONTRACTS = {
+  token: `// Basic ERC-20 Token Contract
+// Try modifying the token name, symbol, or total supply`,
+  voting: `// Voting Contract
+// Experiment with different voting mechanisms`,
+  auction: `// Auction Contract
+// Try implementing different auction types`
+};
+
+const TUTORIAL_STEPS = {
+  step1: `// Step 1: Setup
+// Make sure you have Node.js and solc installed`,
+  step2: `// Step 2: Create Contract
+// Your first smart contract
+// Follow the instructions in the comments`,
+  step3: `// Step 3: Deploy
+// We'll use a test network for this tutorial`,
+  step4: `// Step 4: Interact
+// Try calling different functions
+// Experiment with different parameters`
+};
+
+interface CompilationResult {
+  success: boolean;
+  output: string;
+  abi?: any;
+  bytecode?: string;
+}
+
+export function ResContractPlayground() {
+  const [code, setCode] = useState(DEFAULT_CONTRACT);
+  const [activeTab, setActiveTab] = useState('playground');
+  const [activeExample, setActiveExample] = useState('token');
+  const [activeStep, setActiveStep] = useState('step1');
+  const [compilationResult, setCompilationResult] = useState<CompilationResult | null>(null);
+  const [isCompiling, setIsCompiling] = useState(false);
+
+  const handleCompile = async () => {
+    setIsCompiling(true);
+    setCompilationResult(null);
+    
+    try {
+      const response = await fetch('/api/compile', {
+        method: 'POST',
+        headers: { 'Content-Type': 'application/json' },
+        body: JSON.stringify({ code }),
+      });
+
+      if (!response.ok) {
+        throw new Error('Failed to compile contract');
+      }
+
+      const result = await response.json();
+      setCompilationResult(result);
+    } catch (error) {
+      setCompilationResult({
+        success: false,
+        output: 'Failed to compile contract. Please check your code and try again.',
+      });
+    } finally {
+      setIsCompiling(false);
+    }
+  };
+
+  const copyToClipboard = (text: string) => {
+    navigator.clipboard.writeText(text);
+  };
+
+  return (
+    <Tabs defaultValue="playground" value={activeTab} onChange={(value) => setActiveTab(value as string)}>
+      <TabsList>
+        <TabsTab value="playground">Smart Contract Playground</TabsTab>
+        <TabsTab value="examples">Example Contracts</TabsTab>
+        <TabsTab value="tutorial">Step-by-Step Tutorial</TabsTab>
+      </TabsList>
+
+      <TabsPanel value="playground">
+        <Box my="md">
+          <Alert icon={<IconInfoCircle size={16} />} title="Interactive Playground" color="blue">
+            Experiment with a simple token contract in our interactive playground. Modify the code and see the results instantly.
+          </Alert>
+          <Box mt="md">
+            <CodeMirror
+              value={code}
+              height="400px"
+              theme={vscodeDark}
+              extensions={[javascript()]}
+              onChange={(value) => setCode(value)}
+            />
+          </Box>
+          <Group mt="md" justify="flex-end">
+            <Button
+              leftSection={<IconPlayerPlay size={16} />}
+              onClick={handleCompile}
+              loading={isCompiling}
+            >
+              Compile Contract
+            </Button>
+          </Group>
+          {compilationResult && (
+            <Paper mt="md" p="md" withBorder>
+              <Group mb="xs">
+                {compilationResult.success ? (
+                  <IconCheck size={20} color="green" />
+                ) : (
+                  <IconX size={20} color="red" />
+                )}
+                <Text fw={500}>
+                  {compilationResult.success ? 'Compilation Successful' : 'Compilation Failed'}
+                </Text>
+              </Group>
+              <Text size="sm" style={{ whiteSpace: 'pre-wrap' }}>
+                {compilationResult.output}
+              </Text>
+              {compilationResult.success && (
+                <>
+                  <Box mt="md">
+                    <Group justify="space-between" mb="xs">
+                      <Text size="sm" fw={500}>Contract ABI:</Text>
+                      <Button
+                        variant="subtle"
+                        size="xs"
+                        leftSection={<IconCopy size={14} />}
+                        onClick={() => copyToClipboard(JSON.stringify(compilationResult.abi, null, 2))}
+                      >
+                        Copy
+                      </Button>
+                    </Group>
+                    <CodeMirror
+                      value={JSON.stringify(compilationResult.abi, null, 2)}
+                      height="200px"
+                      theme={vscodeDark}
+                      extensions={[javascript()]}
+                      readOnly
+                    />
+                  </Box>
+                  <Box mt="md">
+                    <Group justify="space-between" mb="xs">
+                      <Text size="sm" fw={500}>Bytecode:</Text>
+                      <Button
+                        variant="subtle"
+                        size="xs"
+                        leftSection={<IconCopy size={14} />}
+                        onClick={() => copyToClipboard(compilationResult.bytecode || '')}
+                      >
+                        Copy
+                      </Button>
+                    </Group>
+                    <Code block>
+                      {compilationResult.bytecode}
+                    </Code>
+                  </Box>
+                </>
+              )}
+            </Paper>
+          )}
+        </Box>
+      </TabsPanel>
+
+      <TabsPanel value="examples">
+        <Box my="md">
+          <Alert icon={<IconInfoCircle size={16} />} title="Example Contracts" color="blue">
+            Explore and learn from these example smart contracts. Each example demonstrates different concepts and patterns.
+          </Alert>
+          <Tabs defaultValue="token" value={activeExample} onChange={(value) => setActiveExample(value as string)}>
+            <TabsList>
+              <TabsTab value="token">Token Contract</TabsTab>
+              <TabsTab value="voting">Voting Contract</TabsTab>
+              <TabsTab value="auction">Auction Contract</TabsTab>
+            </TabsList>
+
+            <TabsPanel value="token">
+              <Box mt="md">
+                <CodeMirror
+                  value={EXAMPLE_CONTRACTS.token}
+                  height="200px"
+                  theme={vscodeDark}
+                  extensions={[javascript()]}
+                  onChange={(value) => setCode(value)}
+                />
+              </Box>
+            </TabsPanel>
+
+            <TabsPanel value="voting">
+              <Box mt="md">
+                <CodeMirror
+                  value={EXAMPLE_CONTRACTS.voting}
+                  height="200px"
+                  theme={vscodeDark}
+                  extensions={[javascript()]}
+                  onChange={(value) => setCode(value)}
+                />
+              </Box>
+            </TabsPanel>
+
+            <TabsPanel value="auction">
+              <Box mt="md">
+                <CodeMirror
+                  value={EXAMPLE_CONTRACTS.auction}
+                  height="200px"
+                  theme={vscodeDark}
+                  extensions={[javascript()]}
+                  onChange={(value) => setCode(value)}
+                />
+              </Box>
+            </TabsPanel>
+          </Tabs>
+        </Box>
+      </TabsPanel>
+
+      <TabsPanel value="tutorial">
+        <Box my="md">
+          <Alert icon={<IconInfoCircle size={16} />} title="Interactive Tutorial" color="blue">
+            Follow this step-by-step tutorial to learn how to create, deploy, and interact with smart contracts.
+          </Alert>
+          <Tabs defaultValue="step1" value={activeStep} onChange={(value) => setActiveStep(value as string)}>
+            <TabsList>
+              <TabsTab value="step1">Step 1: Setup</TabsTab>
+              <TabsTab value="step2">Step 2: Create Contract</TabsTab>
+              <TabsTab value="step3">Step 3: Deploy</TabsTab>
+              <TabsTab value="step4">Step 4: Interact</TabsTab>
+            </TabsList>
+
+            <TabsPanel value="step1">
+              <Alert icon={<IconInfoCircle size={16} />} title="Prerequisites" color="blue" mb="md">
+                Make sure you have Node.js and solc installed before proceeding.
+              </Alert>
+            </TabsPanel>
+
+            <TabsPanel value="step2">
+              <Box mt="md">
+                <CodeMirror
+                  value={TUTORIAL_STEPS.step2}
+                  height="200px"
+                  theme={vscodeDark}
+                  extensions={[javascript()]}
+                  onChange={(value) => setCode(value)}
+                />
+              </Box>
+            </TabsPanel>
+
+            <TabsPanel value="step3">
+              <Alert icon={<IconInfoCircle size={16} />} title="Note" color="blue" mb="md">
+                We'll use a test network for this tutorial.
+              </Alert>
+            </TabsPanel>
+
+            <TabsPanel value="step4">
+              <Box mt="md">
+                <CodeMirror
+                  value={TUTORIAL_STEPS.step4}
+                  height="200px"
+                  theme={vscodeDark}
+                  extensions={[javascript()]}
+                  onChange={(value) => setCode(value)}
+                />
+              </Box>
+            </TabsPanel>
+          </Tabs>
+        </Box>
+      </TabsPanel>
+    </Tabs>
+  );
+} 
\ No newline at end of file
diff --git a/ecosystem/AI-Tooling/beacon/components/SearchBar/PagefindSearch.tsx b/ecosystem/AI-Tooling/beacon/components/SearchBar/PagefindSearch.tsx
new file mode 100644
index 00000000..7b2b21a7
--- /dev/null
+++ b/ecosystem/AI-Tooling/beacon/components/SearchBar/PagefindSearch.tsx
@@ -0,0 +1,744 @@
+/*
+* Licensed to the Apache Software Foundation (ASF) under one
+* or more contributor license agreements.  See the NOTICE file
+* distributed with this work for additional information
+* regarding copyright ownership.  The ASF licenses this file
+* to you under the Apache License, Version 2.0 (the
+* "License"); you may not use this file except in compliance
+* with the License.  You may obtain a copy of the License at
+* 
+*   http://www.apache.org/licenses/LICENSE-2.0
+* 
+* Unless required by applicable law or agreed to in writing,
+* software distributed under the License is distributed on an
+* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+* KIND, either express or implied.  See the License for the
+* specific language governing permissions and limitations
+* under the License.
+*/
+
+'use client'
+
+import { useState, useEffect, useRef } from 'react';
+import { useRouter } from 'next/navigation';
+
+interface SearchResult {
+  id: string;
+  data: () => Promise<{
+    url: string;
+    meta: {
+      title: string;
+      description?: string;
+    };
+    excerpt: string;
+  }>;
+}
+
+interface PagefindSearchProps {
+  onClose?: () => void;
+}
+
+export function PagefindSearch({ onClose }: PagefindSearchProps) {
+  const [query, setQuery] = useState('');
+  const [results, setResults] = useState<SearchResult[]>([]);
+  const [isLoading, setIsLoading] = useState(false);
+  const [isOpen, setIsOpen] = useState(false);
+  const [pagefind, setPagefind] = useState<any>(null);
+  const [mode, setMode] = useState<'search' | 'agent'>('search');
+  const [agentResults, setAgentResults] = useState<any[]>([]);
+  const [isAgentLoading, setIsAgentLoading] = useState(false);
+  const inputRef = useRef<HTMLInputElement>(null);
+  const resultsRef = useRef<HTMLDivElement>(null);
+  const triggerRef = useRef<HTMLButtonElement | null>(null);
+  const lastFocusedRef = useRef<HTMLElement | null>(null);
+  const router = useRouter();
+
+  // Load Pagefind
+  useEffect(() => {
+    async function loadPagefind() {
+      if (typeof window !== 'undefined' && typeof (window as any).pagefind === 'undefined') {
+        try {
+          (window as any).pagefind = await import(
+            // @ts-expect-error pagefind.js generated after build
+            /* webpackIgnore: true */ '/_pagefind/pagefind.js'
+          );
+          setPagefind((window as any).pagefind);
+        } catch (e) {
+          console.log('Pagefind not available in development');
+          // Mock pagefind for development
+          (window as any).pagefind = { 
+            search: () => ({ results: [] }),
+            debouncedSearch: () => ({ results: [] })
+          };
+          setPagefind((window as any).pagefind);
+        }
+      } else if (typeof window !== 'undefined') {
+        setPagefind((window as any).pagefind);
+      }
+    }
+    loadPagefind();
+  }, []);
+
+  // Highlight search terms in text
+  const highlightSearchTerms = (text: string, query: string): string => {
+    if (!query.trim()) return text;
+    
+    const terms = query.toLowerCase().split(/\s+/).filter(term => term.length > 2);
+    let highlightedText = text;
+    
+    terms.forEach(term => {
+      const regex = new RegExp(`(${term})`, 'gi');
+      highlightedText = highlightedText.replace(regex, '<mark style="background: rgba(0, 191, 255, 0.3); color: #00bfff; padding: 1px 2px; border-radius: 2px;">$1</mark>');
+    });
+    
+    return highlightedText;
+  };
+
+  // Handle search
+  const handleSearch = async (searchQuery: string) => {
+    if (!pagefind || !searchQuery.trim()) {
+      setResults([]);
+      return;
+    }
+
+    setIsLoading(true);
+    try {
+      const search = await pagefind.debouncedSearch(searchQuery);
+      const results = search.results || [];
+      
+      // Add highlighting to results
+      const highlightedResults = results.map((result: any) => ({
+        ...result,
+        highlightedExcerpt: highlightSearchTerms(result.excerpt || '', searchQuery)
+      }));
+      
+      setResults(highlightedResults);
+    } catch (error) {
+      console.error('Search error:', error);
+      setResults([]);
+    } finally {
+      setIsLoading(false);
+    }
+  };
+
+  // Handle AI Agent search
+  const handleAgentSearch = async (searchQuery: string) => {
+    if (!searchQuery.trim()) return;
+
+    setIsAgentLoading(true);
+    setAgentResults([]);
+    
+    try {
+      const response = await fetch('/api/ai-search', {
+        method: 'POST',
+        headers: { 'Content-Type': 'application/json' },
+        body: JSON.stringify({
+          query: searchQuery,
+          limit: 10
+        }),
+      });
+
+      if (!response.ok) throw new Error('Failed to perform AI agent search');
+      
+      const data = await response.json();
+      const results = data.results || [];
+      
+      // Add highlighting to agent results
+      const highlightedResults = results.map((result: any) => ({
+        ...result,
+        highlightedExcerpt: highlightSearchTerms(result.excerpt || '', searchQuery)
+      }));
+      
+      setAgentResults(highlightedResults);
+    } catch (error) {
+      console.error('AI Agent search error:', error);
+      setAgentResults([]);
+    } finally {
+      setIsAgentLoading(false);
+    }
+  };
+
+  // Handle Enter key and search button for agent mode
+  const handleSubmit = (e?: React.FormEvent) => {
+    if (e) e.preventDefault();
+    if (query.trim() && mode === 'agent') {
+      handleAgentSearch(query);
+    }
+  };
+
+  // Handle input change with debouncing (only for search mode)
+  useEffect(() => {
+    const timer = setTimeout(() => {
+      if (query && mode === 'search') {
+        handleSearch(query);
+      } else if (mode === 'search') {
+        setResults([]);
+      }
+    }, 300);
+
+    return () => clearTimeout(timer);
+  }, [query, pagefind, mode]);
+
+  // Handle keyboard shortcuts
+  // Global keyboard shortcuts (open/search mode toggle)
+  useEffect(() => {
+    const handleGlobalKeyDown = (e: KeyboardEvent) => {
+      if ((e.metaKey || e.ctrlKey) && e.key === 'k') {
+        e.preventDefault();
+        // remember where focus was and open
+        lastFocusedRef.current = document.activeElement as HTMLElement | null;
+        setIsOpen(true);
+        // focus the input shortly after opening
+        setTimeout(() => inputRef.current?.focus(), 50);
+      }
+      if ((e.metaKey || e.ctrlKey) && e.key === 'j') {
+        e.preventDefault();
+        setMode((m) => (m === 'search' ? 'agent' : 'search'));
+      }
+    };
+
+    document.addEventListener('keydown', handleGlobalKeyDown);
+    return () => document.removeEventListener('keydown', handleGlobalKeyDown);
+  }, []);
+
+  // Add an Escape handler only while the modal is open so it can be removed when closed
+  useEffect(() => {
+    if (!isOpen) return;
+
+    const handleEscape = (e: KeyboardEvent) => {
+      if (e.key === 'Escape') {
+        e.preventDefault();
+        closeModal();
+      }
+    };
+
+    document.addEventListener('keydown', handleEscape);
+    return () => document.removeEventListener('keydown', handleEscape);
+  }, [isOpen]);
+
+  // Open/close helpers that manage focus
+  const openModal = (fromTrigger?: HTMLElement | null) => {
+    lastFocusedRef.current = fromTrigger || (document.activeElement as HTMLElement | null);
+    setIsOpen(true);
+    setTimeout(() => inputRef.current?.focus(), 50);
+  };
+
+  const closeModal = () => {
+    setIsOpen(false);
+    setQuery('');
+    setResults([]);
+    setAgentResults([]);
+    onClose?.();
+    // return focus to trigger if possible
+    setTimeout(() => {
+      try {
+        (lastFocusedRef.current ?? triggerRef.current)?.focus?.();
+      } catch (err) {
+        // ignore
+      }
+    }, 0);
+  };
+
+  // Clean URL by removing .html extension and fixing paths
+  const cleanUrl = (url: string): string => {
+    // Remove .html extension
+    let cleanUrl = url.replace(/\.html$/, '');
+    
+    // Handle index pages - convert /docs/index to /docs
+    if (cleanUrl.endsWith('/index')) {
+      cleanUrl = cleanUrl.replace(/\/index$/, '');
+    }
+    
+    // Ensure URL starts with / if it doesn't already
+    if (!cleanUrl.startsWith('/')) {
+      cleanUrl = '/' + cleanUrl;
+    }
+    
+    return cleanUrl;
+  };
+
+  // Handle result click
+  const handleResultClick = async (result: SearchResult) => {
+    try {
+      const data = await result.data();
+      const cleanPath = cleanUrl(data.url);
+      router.push(cleanPath);
+      setIsOpen(false);
+      setQuery('');
+      setResults([]);
+      onClose?.();
+    } catch (error) {
+      console.error('Error navigating to result:', error);
+    }
+  };
+
+  if (!isOpen) {
+    return (
+      <button
+        ref={triggerRef}
+        onClick={(e) => openModal(e.currentTarget)}
+        onKeyDown={(e) => {
+          if (e.key === 'Enter' || e.key === ' ') {
+            e.preventDefault();
+            openModal(e.currentTarget as HTMLElement);
+          }
+        }}
+        style={{
+          display: 'flex',
+          alignItems: 'center',
+          gap: 8,
+          padding: '8px 16px',
+          background: 'rgba(255, 255, 255, 0.08)',
+          border: '1px solid rgba(255, 255, 255, 0.1)',
+          borderRadius: 24,
+          color: 'rgba(255, 255, 255, 0.7)',
+          fontSize: 14,
+          fontWeight: 400,
+          cursor: 'pointer',
+          transition: 'all 200ms ease',
+          backdropFilter: 'blur(10px)',
+          minWidth: 200,
+          justifyContent: 'flex-start',
+        }}
+        onMouseEnter={(e) => {
+          e.currentTarget.style.background = 'rgba(255, 255, 255, 0.12)';
+          e.currentTarget.style.borderColor = 'rgba(255, 255, 255, 0.2)';
+        }}
+        onMouseLeave={(e) => {
+          e.currentTarget.style.background = 'rgba(255, 255, 255, 0.08)';
+          e.currentTarget.style.borderColor = 'rgba(255, 255, 255, 0.1)';
+        }}
+      >
+        <svg
+          width="16"
+          height="16"
+          fill="currentColor"
+          viewBox="0 0 20 20"
+          style={{ opacity: 0.6, flexShrink: 0 }}
+  >
+          <path
+            fillRule="evenodd"
+            d="M8 4a4 4 0 100 8 4 4 0 000-8zM2 8a6 6 0 1110.89 3.476l4.817 4.817a1 1 0 01-1.414 1.414l-4.816-4.816A6 6 0 012 8z"
+            clipRule="evenodd"
+          />
+        </svg>
+        <span style={{ flex: 1, textAlign: 'left' }}>Search...</span>
+        <div style={{ display: 'flex', alignItems: 'center', gap: 2, opacity: 0.5 }}>
+          <kbd style={{
+            background: 'rgba(255, 255, 255, 0.1)',
+            border: '1px solid rgba(255, 255, 255, 0.2)',
+            borderRadius: 4,
+            padding: '2px 6px',
+            fontSize: 11,
+            fontFamily: 'monospace',
+            color: 'rgba(255, 255, 255, 0.7)',
+          }}>
+            ⌘
+          </kbd>
+          <kbd style={{
+            background: 'rgba(255, 255, 255, 0.1)',
+            border: '1px solid rgba(255, 255, 255, 0.2)',
+            borderRadius: 4,
+            padding: '2px 6px',
+            fontSize: 11,
+            fontFamily: 'monospace',
+            color: 'rgba(255, 255, 255, 0.7)',
+          }}>
+            K
+          </kbd>
+        </div>
+      </button>
+    );
+  }
+
+  return (
+    <div
+      style={{
+        position: 'fixed',
+        top: 0,
+        left: 0,
+        right: 0,
+        bottom: 0,
+        background: 'rgba(0, 0, 0, 0.8)',
+        backdropFilter: 'blur(8px)',
+        zIndex: 10000,
+        display: 'flex',
+        alignItems: 'flex-start',
+        justifyContent: 'center',
+        paddingTop: '10vh',
+      }}
+      onClick={(e) => {
+        if (e.target === e.currentTarget) {
+          setIsOpen(false);
+          setQuery('');
+          setResults([]);
+          onClose?.();
+        }
+      }}
+    >
+      <div
+        style={{
+          background: 'rgba(255, 255, 255, 0.1)',
+          border: '1px solid rgba(255, 255, 255, 0.2)',
+          borderRadius: 12,
+          backdropFilter: 'blur(10px)',
+          minWidth: 600,
+          maxWidth: '90vw',
+          height: '500px',
+          overflow: 'hidden',
+          display: 'flex',
+          flexDirection: 'column',
+        }}
+      >
+        {/* Search Input */}
+        <div style={{ padding: '20px', borderBottom: '1px solid rgba(255, 255, 255, 0.1)' }}>
+          {/* Mode Toggle */}
+          <div style={{ display: 'flex', gap: 8, marginBottom: 12 }}>
+            <button
+              onClick={() => setMode('search')}
+              style={{
+                padding: '6px 12px',
+                borderRadius: 6,
+                border: 'none',
+                background: mode === 'search' ? 'rgba(0, 191, 255, 0.2)' : 'rgba(255, 255, 255, 0.1)',
+                color: mode === 'search' ? '#00bfff' : 'rgba(255, 255, 255, 0.7)',
+                fontSize: 12,
+                fontWeight: 500,
+                cursor: 'pointer',
+                transition: 'all 200ms ease',
+              }}
+            >
+              🔍 Search
+            </button>
+            <button
+              onClick={() => setMode('agent')}
+              style={{
+                padding: '6px 12px',
+                borderRadius: 6,
+                border: 'none',
+                background: mode === 'agent' ? 'rgba(0, 191, 255, 0.2)' : 'rgba(255, 255, 255, 0.1)',
+                color: mode === 'agent' ? '#00bfff' : 'rgba(255, 255, 255, 0.7)',
+                fontSize: 12,
+                fontWeight: 500,
+                cursor: 'pointer',
+                transition: 'all 200ms ease',
+                display: 'flex',
+                alignItems: 'center',
+                gap: 6,
+              }}
+            >
+              <svg width="14" height="14" viewBox="0 0 24 24" fill="currentColor">
+                <path d="M12 2L2 7l10 5 10-5-10-5zM2 17l10 5 10-5M2 12l10 5 10-5"/>
+              </svg>
+              Ask Our Agent
+              <span style={{
+                background: 'rgba(255, 193, 7, 0.2)',
+                color: '#ffc107',
+                fontSize: 10,
+                padding: '2px 4px',
+                borderRadius: 3,
+                fontWeight: 600,
+                textTransform: 'uppercase',
+                letterSpacing: '0.5px'
+              }}>
+                Beta
+              </span>
+            </button>
+          </div>
+          
+          <form onSubmit={handleSubmit} style={{ display: 'flex', alignItems: 'center', gap: 12, width: '100%' }}>
+            {mode === 'search' ? (
+              <svg
+                width="20"
+                height="20"
+                fill="currentColor"
+                viewBox="0 0 20 20"
+                style={{ opacity: 0.6 }}
+              >
+                <path
+                  fillRule="evenodd"
+                  d="M8 4a4 4 0 100 8 4 4 0 000-8zM2 8a6 6 0 1110.89 3.476l4.817 4.817a1 1 0 01-1.414 1.414l-4.816-4.816A6 6 0 012 8z"
+                  clipRule="evenodd"
+                />
+              </svg>
+            ) : (
+              <svg
+                width="20"
+                height="20"
+                fill="currentColor"
+                viewBox="0 0 24 24"
+                style={{ opacity: 0.6 }}
+              >
+                <path d="M12 2L2 7l10 5 10-5-10-5zM2 17l10 5 10-5M2 12l10 5 10-5"/>
+              </svg>
+            )}
+            <input
+              ref={inputRef}
+              type="text"
+              placeholder={
+                mode === 'search' 
+                  ? "Search documentation..." 
+                  : "Ask our agent to find relevant content (e.g., 'storage optimization', 'transaction handling')..."
+              }
+              value={query}
+              onChange={(e) => setQuery(e.target.value)}
+              onKeyDown={(e) => {
+                if (e.key === 'Enter' && mode === 'agent') {
+                  e.preventDefault();
+                  handleSubmit();
+                }
+              }}
+              style={{
+                background: 'transparent',
+                border: 'none',
+                outline: 'none',
+                color: 'rgba(255, 255, 255, 0.9)',
+                fontSize: 16,
+                flex: 1,
+                minWidth: 0,
+              }}
+            />
+            {mode === 'agent' && query.trim() && !isAgentLoading && (
+              <button
+                type="submit"
+                style={{
+                  padding: '8px 16px',
+                  background: 'rgba(0, 191, 255, 0.2)',
+                  border: '1px solid rgba(0, 191, 255, 0.4)',
+                  borderRadius: 8,
+                  color: '#00bfff',
+                  fontSize: 14,
+                  fontWeight: 500,
+                  cursor: 'pointer',
+                  transition: 'all 200ms ease',
+                }}
+                onMouseEnter={(e) => {
+                  e.currentTarget.style.background = 'rgba(0, 191, 255, 0.3)';
+                  e.currentTarget.style.borderColor = 'rgba(0, 191, 255, 0.6)';
+                }}
+                onMouseLeave={(e) => {
+                  e.currentTarget.style.background = 'rgba(0, 191, 255, 0.2)';
+                  e.currentTarget.style.borderColor = 'rgba(0, 191, 255, 0.4)';
+                }}
+              >
+                Ask Our Agent
+              </button>
+            )}
+            {(isLoading || isAgentLoading) && (
+              <div style={{ color: 'rgba(255, 255, 255, 0.6)', fontSize: 14 }}>
+                {mode === 'search' ? 'Searching...' : 'Our agent is searching...'}
+              </div>
+            )}
+          </form>
+          
+          {/* Keyboard shortcuts hint */}
+          <div style={{ 
+            display: 'flex', 
+            gap: 8, 
+            marginTop: 8, 
+            fontSize: 11, 
+            color: 'rgba(255, 255, 255, 0.5)' 
+          }}>
+            <span>⌘K to open</span>
+            <span>⌘J to switch mode</span>
+            {mode === 'agent' && <span>Enter to ask our agent</span>}
+            <span>Esc to close</span>
+          </div>
+        </div>
+
+        {/* Results */}
+        <div 
+          ref={resultsRef}
+          style={{ 
+            flex: 1,
+            overflowY: 'auto',
+            overflowX: 'hidden',
+            minHeight: 0
+          }}
+        >
+          {mode === 'search' ? (
+            // Search Results
+            results.length > 0 ? (
+              results.map((result, index) => (
+                <SearchResultItem
+                  key={result.id}
+                  result={result}
+                  onClick={() => handleResultClick(result)}
+                />
+              ))
+            ) : query && !isLoading ? (
+              <div style={{ padding: '20px', textAlign: 'center', color: 'rgba(255, 255, 255, 0.6)' }}>
+                No results found for "{query}"
+              </div>
+            ) : !query ? (
+              <div style={{ padding: '20px', textAlign: 'center', color: 'rgba(255, 255, 255, 0.6)' }}>
+                Start typing to search...
+              </div>
+            ) : null
+          ) : (
+            // Agent Results
+            agentResults.length > 0 ? (
+              agentResults.map((result, index) => (
+                <div
+                  key={result.id}
+                  onClick={() => {
+                    router.push(result.url);
+                    setIsOpen(false); // Auto-close search bar
+                    setQuery('');
+                    setAgentResults([]);
+                  }}
+                  style={{
+                    padding: '16px 20px',
+                    borderBottom: '1px solid rgba(255, 255, 255, 0.05)',
+                    cursor: 'pointer',
+                    transition: 'background-color 0.2s ease',
+                  }}
+                  onMouseEnter={(e) => {
+                    e.currentTarget.style.background = 'rgba(255, 255, 255, 0.1)';
+                  }}
+                  onMouseLeave={(e) => {
+                    e.currentTarget.style.background = 'transparent';
+                  }}
+                >
+                  <div style={{ 
+                    color: 'rgba(255, 255, 255, 0.9)', 
+                    fontSize: 16, 
+                    fontWeight: 500, 
+                    marginBottom: 8 
+                  }}>
+                    {result.title}
+                    {result.matchedSection && (
+                      <span style={{ 
+                        color: 'rgba(0, 191, 255, 0.8)', 
+                        fontSize: 14, 
+                        fontWeight: 400,
+                        marginLeft: 8
+                      }}>
+                        → {result.matchedSection.title}
+                      </span>
+                    )}
+                  </div>
+                  <div 
+                    style={{ 
+                      color: 'rgba(255, 255, 255, 0.7)', 
+                      fontSize: 14, 
+                      lineHeight: 1.4,
+                      marginBottom: 8
+                    }}
+                    dangerouslySetInnerHTML={{ 
+                      __html: result.highlightedExcerpt || result.excerpt 
+                    }}
+                  />
+                  <div style={{ 
+                    color: 'rgba(0, 191, 255, 0.8)', 
+                    fontSize: 12,
+                    display: 'flex',
+                    alignItems: 'center',
+                    gap: 8
+                  }}>
+                    <div style={{ display: 'flex', alignItems: 'center', gap: 4 }}>
+                      <svg width="12" height="12" viewBox="0 0 24 24" fill="currentColor">
+                        <path d="M12 2L2 7l10 5 10-5-10-5zM2 17l10 5 10-5M2 12l10 5 10-5"/>
+                      </svg>
+                      <span>Ask Our Agent</span>
+                      <span style={{
+                        background: 'rgba(255, 193, 7, 0.2)',
+                        color: '#ffc107',
+                        fontSize: 8,
+                        padding: '1px 3px',
+                        borderRadius: 2,
+                        fontWeight: 600,
+                        textTransform: 'uppercase',
+                        letterSpacing: '0.3px'
+                      }}>
+                        Beta
+                      </span>
+                    </div>
+                    <span>•</span>
+                    <span>{result.url}</span>
+                    <span>•</span>
+                    <span>Score: {result.relevanceScore.toFixed(1)}</span>
+                    {result.matchedSection && (
+                      <>
+                        <span>•</span>
+                        <span>📍 Section match</span>
+                      </>
+                    )}
+                  </div>
+                </div>
+              ))
+            ) : query && !isAgentLoading ? (
+              <div style={{ padding: '20px', textAlign: 'center', color: 'rgba(255, 255, 255, 0.6)' }}>
+                No results found for "{query}"
+              </div>
+            ) : !query ? (
+              <div style={{ padding: '20px', textAlign: 'center', color: 'rgba(255, 255, 255, 0.6)' }}>
+                Start typing to ask our agent...
+              </div>
+            ) : null
+          )}
+        </div>
+      </div>
+    </div>
+  );
+}
+
+function SearchResultItem({ result, onClick }: { result: SearchResult; onClick: () => void }) {
+  const [data, setData] = useState<any>(null);
+
+  useEffect(() => {
+    async function fetchData() {
+      try {
+        const resultData = await result.data();
+        setData(resultData);
+      } catch (error) {
+        console.error('Error fetching result data:', error);
+      }
+    }
+    fetchData();
+  }, [result]);
+
+  if (!data) {
+    return (
+      <div style={{ padding: '16px 20px', color: 'rgba(255, 255, 255, 0.6)' }}>
+        Loading...
+      </div>
+    );
+  }
+
+  return (
+    <div
+      onClick={onClick}
+      style={{
+        padding: '16px 20px',
+        borderBottom: '1px solid rgba(255, 255, 255, 0.05)',
+        cursor: 'pointer',
+        transition: 'background-color 0.2s ease',
+      }}
+      onMouseEnter={(e) => {
+        e.currentTarget.style.background = 'rgba(255, 255, 255, 0.1)';
+      }}
+      onMouseLeave={(e) => {
+        e.currentTarget.style.background = 'transparent';
+      }}
+    >
+      <div style={{ color: 'rgba(255, 255, 255, 0.9)', fontWeight: 600, marginBottom: 4 }}>
+        {data.meta.title}
+      </div>
+      {data.meta.description && (
+        <div style={{ color: 'rgba(255, 255, 255, 0.6)', fontSize: 14, marginBottom: 8 }}>
+          {data.meta.description}
+        </div>
+      )}
+      <div 
+        style={{ color: 'rgba(255, 255, 255, 0.7)', fontSize: 14, lineHeight: 1.4 }}
+        dangerouslySetInnerHTML={{ 
+          __html: data.highlightedExcerpt || data.excerpt 
+        }}
+      />
+      <div style={{ color: 'rgba(255, 255, 255, 0.5)', fontSize: 12, marginTop: 8 }}>
+        {data.url.replace(/\.html$/, '').replace(/\/index$/, '')}
+      </div>
+    </div>
+  );
+}
diff --git a/ecosystem/AI-Tooling/beacon/components/SearchBar/SearchBar.tsx b/ecosystem/AI-Tooling/beacon/components/SearchBar/SearchBar.tsx
new file mode 100644
index 00000000..298441b2
--- /dev/null
+++ b/ecosystem/AI-Tooling/beacon/components/SearchBar/SearchBar.tsx
@@ -0,0 +1,26 @@
+/*
+* Licensed to the Apache Software Foundation (ASF) under one
+* or more contributor license agreements.  See the NOTICE file
+* distributed with this work for additional information
+* regarding copyright ownership.  The ASF licenses this file
+* to you under the Apache License, Version 2.0 (the
+* "License"); you may not use this file except in compliance
+* with the License.  You may obtain a copy of the License at
+* 
+*   http://www.apache.org/licenses/LICENSE-2.0
+* 
+* Unless required by applicable law or agreed to in writing,
+* software distributed under the License is distributed on an
+* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+* KIND, either express or implied.  See the License for the
+* specific language governing permissions and limitations
+* under the License.
+*/
+
+'use client'
+
+import { PagefindSearch } from './PagefindSearch';
+
+export function SearchBar() {
+  return <PagefindSearch />;
+} 
\ No newline at end of file
diff --git a/ecosystem/AI-Tooling/beacon/components/TypeScriptPlayground.tsx b/ecosystem/AI-Tooling/beacon/components/TypeScriptPlayground.tsx
new file mode 100644
index 00000000..7adefc35
--- /dev/null
+++ b/ecosystem/AI-Tooling/beacon/components/TypeScriptPlayground.tsx
@@ -0,0 +1,800 @@
+/*
+* Licensed to the Apache Software Foundation (ASF) under one
+* or more contributor license agreements.  See the NOTICE file
+* distributed with this work for additional information
+* regarding copyright ownership.  The ASF licenses this file
+* to you under the Apache License, Version 2.0 (the
+* "License"); you may not use this file except in compliance
+* with the License.  You may obtain a copy of the License at
+* 
+*   http://www.apache.org/licenses/LICENSE-2.0
+* 
+* Unless required by applicable law or agreed to in writing,
+* software distributed under the License is distributed on an
+* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+* KIND, either express or implied.  See the License for the
+* specific language governing permissions and limitations
+* under the License.
+*/
+
+'use client';
+
+/* TODO BUILD THIS OUT */
+
+import { useEffect, useState, useRef } from 'react';
+import { javascript } from '@codemirror/lang-javascript';
+import { IconPlayerPlay, IconTemplate, IconTrash, IconMessage, IconPlayerStop, IconMaximize, IconMinimize } from '@tabler/icons-react';
+import { vscodeDark } from '@uiw/codemirror-theme-vscode';
+import CodeMirror from '@uiw/react-codemirror';
+import { Box, Button, Group, Paper, Select, Stack, Text, Tooltip, Textarea, ActionIcon, Modal } from '@mantine/core';
+import ReactMarkdown from 'react-markdown';
+import { Prism as SyntaxHighlighter } from 'react-syntax-highlighter';
+import { vscDarkPlus } from 'react-syntax-highlighter/dist/cjs/styles/prism';
+
+interface Template {
+  value: string;
+  label: string;
+  code: string;
+}
+
+interface Message {
+  role: 'user' | 'assistant';
+  content: string;
+}
+
+interface CodeProps {
+  node?: any;
+  inline?: boolean;
+  className?: string;
+  children?: React.ReactNode;
+  [key: string]: any;
+}
+
+const EXAMPLE_TEMPLATES = [
+  {
+    value: 'default',
+    label: 'Welcome - Start Here',
+    code: `/**
+ * Welcome to the TypeScript Playground!
+ * 
+ * This interactive environment allows you to test and experiment with TypeScript code.
+ * The code here runs in a sandboxed environment using the TypeScript compiler.
+ * 
+ * Available Features:
+ * 1. TypeScript Type Checking
+ * 2. Code Execution
+ * 3. Error Reporting
+ * 4. AI Assistant Support
+ * 
+ * Choose an example from the dropdown menu above to get started!
+ */
+
+// Example: Basic TypeScript Interface
+interface User {
+  id: number;
+  name: string;
+  email: string;
+  isActive: boolean;
+}
+
+// Example: Function with Type Safety
+function greetUser(user: User): string {
+  return \`Hello, \${user.name}! Your email is \${user.email}\`;
+}
+
+// Example: Using the Interface
+const user: User = {
+  id: 1,
+  name: "John Doe",
+  email: "john@example.com",
+  isActive: true
+};
+
+console.log(greetUser(user));`,
+  },
+  {
+    value: 'async_await',
+    label: 'Async/Await Example',
+    code: `/**
+ * Example: Using async/await with TypeScript
+ */
+
+// Define types for our API response
+interface Todo {
+  id: number;
+  title: string;
+  completed: boolean;
+}
+
+// Async function to fetch todos
+async function fetchTodos(): Promise<Todo[]> {
+  try {
+    const response = await fetch('https://jsonplaceholder.typicode.com/todos');
+    const data = await response.json();
+    return data as Todo[];
+  } catch (error) {
+    console.error('Error fetching todos:', error);
+    return [];
+  }
+}
+
+// Main function to demonstrate async/await
+async function main() {
+  console.log('Fetching todos...');
+  const todos = await fetchTodos();
+  console.log('First 3 todos:', todos.slice(0, 3));
+}
+
+// Run the example
+main();`,
+  },
+  {
+    value: 'generics',
+    label: 'Generics Example',
+    code: `/**
+ * Example: Using TypeScript Generics
+ */
+
+// Generic function to create an array of a specific type
+function createArray<T>(length: number, value: T): T[] {
+  return Array(length).fill(value);
+}
+
+// Generic class for a simple stack
+class Stack<T> {
+  private items: T[] = [];
+
+  push(item: T): void {
+    this.items.push(item);
+  }
+
+  pop(): T | undefined {
+    return this.items.pop();
+  }
+
+  peek(): T | undefined {
+    return this.items[this.items.length - 1];
+  }
+
+  isEmpty(): boolean {
+    return this.items.length === 0;
+  }
+}
+
+// Example usage
+const numberStack = new Stack<number>();
+numberStack.push(1);
+numberStack.push(2);
+numberStack.push(3);
+
+console.log('Stack operations:');
+console.log('Pop:', numberStack.pop());
+console.log('Peek:', numberStack.peek());
+console.log('Is empty:', numberStack.isEmpty());
+
+// Using the generic array creator
+const stringArray = createArray<string>(3, 'hello');
+console.log('String array:', stringArray);`,
+  },
+  {
+    value: 'decorators',
+    label: 'Decorators Example',
+    code: `/**
+ * Example: Using TypeScript Decorators
+ * Note: Decorators are an experimental feature
+ */
+
+// Simple method decorator
+function log(target: any, propertyKey: string, descriptor: PropertyDescriptor) {
+  const originalMethod = descriptor.value;
+
+  descriptor.value = function (...args: any[]) {
+    console.log(\`Calling \${propertyKey} with args:\`, args);
+    const result = originalMethod.apply(this, args);
+    console.log(\`\${propertyKey} returned:\`, result);
+    return result;
+  };
+
+  return descriptor;
+}
+
+// Class using the decorator
+class Calculator {
+  @log
+  add(a: number, b: number): number {
+    return a + b;
+  }
+
+  @log
+  multiply(a: number, b: number): number {
+    return a * b;
+  }
+}
+
+// Example usage
+const calc = new Calculator();
+console.log('Calculator operations:');
+calc.add(5, 3);
+calc.multiply(4, 2);`,
+  },
+];
+
+export function TypeScriptPlayground({ templates }: { templates?: Template[] }) {
+  const codeTemplates = templates && Array.isArray(templates) ? templates : EXAMPLE_TEMPLATES;
+  const [code, setCode] = useState<string>(codeTemplates[0].code);
+  const [output, setOutput] = useState<string[]>(['Initializing TypeScript environment...']);
+  const [isLoading, setIsLoading] = useState(true);
+  const [isRunning, setIsRunning] = useState(false);
+  const [showChat, setShowChat] = useState(false);
+  const [messages, setMessages] = useState<Message[]>([]);
+  const [input, setInput] = useState('');
+  const [isAiLoading, setIsAiLoading] = useState(false);
+  const [abortController, setAbortController] = useState<AbortController | null>(null);
+  const [isExpanded, setIsExpanded] = useState(false);
+  const expandTriggerRef = useRef<HTMLButtonElement | null>(null);
+  const lastFocusedRef = useRef<HTMLElement | null>(null);
+
+  const openExpanded = (from?: HTMLElement | null) => {
+    lastFocusedRef.current = from ?? (document.activeElement as HTMLElement | null);
+    setIsExpanded(true);
+    // focus textarea inside modal after open
+    setTimeout(() => {
+      const ta = document.querySelector('.cm-theme') as HTMLElement | null;
+      ta?.focus?.();
+    }, 50);
+  };
+
+  const closeExpanded = () => {
+    setIsExpanded(false);
+    setTimeout(() => {
+      try { lastFocusedRef.current?.focus?.(); } catch (err) {}
+    }, 0);
+  };
+
+  useEffect(() => {
+    if (!isExpanded) return;
+    const onKey = (e: KeyboardEvent) => {
+      if (e.key === 'Escape') {
+        e.preventDefault();
+        closeExpanded();
+      }
+    };
+    document.addEventListener('keydown', onKey);
+    return () => document.removeEventListener('keydown', onKey);
+  }, [isExpanded]);
+
+  useEffect(() => {
+    // Initialize TypeScript environment
+    const initTypeScript = async () => {
+      try {
+        // Load TypeScript compiler
+        const script = document.createElement('script');
+        script.src = 'https://unpkg.com/typescript@latest/lib/typescript.js';
+        document.head.appendChild(script);
+
+        await new Promise((resolve) => {
+          script.onload = resolve;
+        });
+
+        setOutput(['✅ TypeScript environment ready']);
+        setIsLoading(false);
+      } catch (error) {
+        setOutput((prev) => [
+          ...prev,
+          `❌ Error: ${error instanceof Error ? error.message : 'Unknown error'}`,
+        ]);
+        setIsLoading(false);
+      }
+    };
+
+    initTypeScript();
+  }, []);
+
+  const runCode = async () => {
+    if (isLoading || isRunning) {
+      return;
+    }
+    setIsRunning(true);
+    setOutput(['▶ Running code...']);
+
+    try {
+      // Compile TypeScript to JavaScript
+      const jsCode = (window as any).ts.transpile(code, {
+        target: 'ES2020',
+        module: 'ES2020',
+        strict: true,
+        esModuleInterop: true,
+        skipLibCheck: true,
+        forceConsistentCasingInFileNames: true,
+      });
+
+      // Create a sandboxed environment with better console handling
+      const sandbox = `
+        const originalConsole = console;
+        const console = {
+          log: (...args) => {
+            window.parent.postMessage({ type: 'log', args: args.map(arg => 
+              typeof arg === 'object' ? JSON.stringify(arg, null, 2) : String(arg)
+            )}, '*');
+            originalConsole.log(...args);
+          },
+          error: (...args) => {
+            window.parent.postMessage({ type: 'error', args: args.map(arg => 
+              typeof arg === 'object' ? JSON.stringify(arg, null, 2) : String(arg)
+            )}, '*');
+            originalConsole.error(...args);
+          },
+          warn: (...args) => {
+            window.parent.postMessage({ type: 'log', args: args.map(arg => 
+              typeof arg === 'object' ? JSON.stringify(arg, null, 2) : String(arg)
+            )}, '*');
+            originalConsole.warn(...args);
+          },
+          info: (...args) => {
+            window.parent.postMessage({ type: 'log', args: args.map(arg => 
+              typeof arg === 'object' ? JSON.stringify(arg, null, 2) : String(arg)
+            )}, '*');
+            originalConsole.info(...args);
+          }
+        };
+
+        // Add error handling for uncaught errors
+        window.onerror = (message, source, lineno, colno, error) => {
+          console.error(\`Error: \${message}\nLine: \${lineno}, Column: \${colno}\`);
+          return true;
+        };
+
+        // Add promise rejection handling
+        window.onunhandledrejection = (event) => {
+          console.error(\`Unhandled Promise Rejection: \${event.reason}\`);
+        };
+
+        try {
+          ${jsCode}
+        } catch (error) {
+          console.error(error.message);
+        }
+      `;
+
+      // Create an iframe for sandboxed execution
+      const iframe = document.createElement('iframe');
+      iframe.style.display = 'none';
+      document.body.appendChild(iframe);
+
+      // Handle messages from the sandbox
+      const messageHandler = (event: MessageEvent) => {
+        if (event.data.type === 'log') {
+          setOutput(prev => [...prev, ...event.data.args]);
+        } else if (event.data.type === 'error') {
+          setOutput(prev => [...prev, `❌ Error: ${event.data.args.join(' ')}`]);
+        }
+      };
+
+      window.addEventListener('message', messageHandler);
+
+      // Write the sandboxed code to the iframe
+      if (iframe.contentWindow) {
+        iframe.contentWindow.document.open();
+        iframe.contentWindow.document.write(`
+          <!DOCTYPE html>
+          <html>
+            <head>
+              <script>
+                ${sandbox}
+              </script>
+            </head>
+            <body></body>
+          </html>
+        `);
+        iframe.contentWindow.document.close();
+      }
+
+      // Wait for any pending console output before cleanup
+      await new Promise(resolve => setTimeout(resolve, 100));
+
+      // Cleanup
+      window.removeEventListener('message', messageHandler);
+      document.body.removeChild(iframe);
+      setOutput(prev => [...prev, '✅ Code execution completed']);
+      setIsRunning(false);
+    } catch (error: any) {
+      setOutput((prev) => [...prev, `❌ Error: ${error.message}`]);
+      setIsRunning(false);
+    }
+  };
+
+  const handleSubmit = async (e: React.FormEvent) => {
+    e.preventDefault();
+    if (!input.trim()) return;
+
+    const userMessage: Message = { role: 'user', content: input };
+    setMessages(prev => [...prev, userMessage]);
+    setInput('');
+    setIsAiLoading(true);
+
+    const controller = new AbortController();
+    setAbortController(controller);
+
+    try {
+      const response = await fetch('/api/chat', {
+        method: 'POST',
+        headers: { 'Content-Type': 'application/json' },
+        body: JSON.stringify({ messages: [...messages, userMessage], code }),
+        signal: controller.signal
+      });
+
+      if (!response.ok) throw new Error('Failed to get response');
+      
+      const reader = response.body?.getReader();
+      if (!reader) throw new Error('No reader available');
+
+      let assistantMessage = '';
+      while (true) {
+        const { done, value } = await reader.read();
+        if (done) break;
+        
+        const text = new TextDecoder().decode(value);
+        assistantMessage += text;
+        setMessages(prev => {
+          const newMessages = [...prev];
+          const lastMessage = newMessages[newMessages.length - 1];
+          if (lastMessage.role === 'assistant') {
+            lastMessage.content = assistantMessage;
+          } else {
+            newMessages.push({ role: 'assistant', content: assistantMessage });
+          }
+          return newMessages;
+        });
+      }
+    } catch (error) {
+      if (error instanceof Error && error.name === 'AbortError') {
+        setMessages(prev => [...prev, { role: 'assistant', content: 'Response generation stopped.' }]);
+      } else {
+        console.error('Chat error:', error);
+        setMessages(prev => [...prev, { role: 'assistant', content: 'Sorry, there was an error processing your request.' }]);
+      }
+    } finally {
+      setIsAiLoading(false);
+      setAbortController(null);
+    }
+  };
+
+  const handleKeyDown = (e: React.KeyboardEvent<HTMLTextAreaElement>) => {
+    if (e.key === 'Enter' && !e.shiftKey) {
+      e.preventDefault();
+      if (input.trim() && !isAiLoading) {
+        handleSubmit(e as unknown as React.FormEvent);
+      }
+    }
+  };
+
+  const stopGeneration = () => {
+    if (abortController) {
+      abortController.abort();
+      setAbortController(null);
+    }
+  };
+
+  const clearOutput = () => setOutput([]);
+
+  const clearConversation = () => {
+    setMessages([]);
+  };
+
+  return (
+    <Paper withBorder p="md" radius="md">
+      <Stack>
+        <Group justify="space-between" align="center">
+          <Group>
+            <Tooltip label="Load example">
+              <Select
+                size="xs"
+                placeholder="Load example"
+                data={codeTemplates}
+                onChange={(value) =>
+                  value && setCode(codeTemplates.find((t) => t.value === value)?.code || '')
+                }
+                leftSection={<IconTemplate size={14} />}
+              />
+            </Tooltip>
+            <Tooltip label="Ask AI Assistant">
+              <ActionIcon 
+                variant="light" 
+                onClick={() => setShowChat(!showChat)}
+                color={showChat ? "blue" : "gray"}
+              >
+                <IconMessage size={14} />
+              </ActionIcon>
+            </Tooltip>
+          </Group>
+        </Group>
+
+        <Box>
+          <CodeMirror
+            value={code}
+            height="400px"
+            theme={vscodeDark}
+            extensions={[javascript({ typescript: true })]}
+            onChange={setCode}
+            editable={!isLoading}
+            basicSetup={{
+              lineNumbers: true,
+              highlightActiveLineGutter: true,
+              highlightSpecialChars: true,
+              history: true,
+              foldGutter: true,
+              drawSelection: true,
+              dropCursor: true,
+              allowMultipleSelections: true,
+              indentOnInput: true,
+              syntaxHighlighting: true,
+              bracketMatching: true,
+              closeBrackets: true,
+              autocompletion: true,
+              rectangularSelection: true,
+              crosshairCursor: true,
+              highlightActiveLine: true,
+              highlightSelectionMatches: true,
+              closeBracketsKeymap: true,
+              defaultKeymap: true,
+              searchKeymap: true,
+              historyKeymap: true,
+              foldKeymap: true,
+              completionKeymap: true,
+              lintKeymap: true,
+            }}
+          />
+        </Box>
+
+        {showChat && (
+          <>
+            <Paper withBorder p="md" radius="md">
+              <Stack>
+                <Group justify="space-between" align="center">
+                  <Text size="sm" fw={500}>AI Assistant</Text>
+                  <Group>
+                    <Tooltip label={isExpanded ? "Minimize" : "Expand"}>
+                      <ActionIcon 
+                        ref={expandTriggerRef}
+                        variant="light" 
+                        onClick={(e) => openExpanded(e.currentTarget)}
+                        onKeyDown={(e) => {
+                          if (e.key === 'Enter' || e.key === ' ') {
+                            e.preventDefault();
+                            openExpanded(e.currentTarget as HTMLElement);
+                          }
+                        }}
+                        disabled={isExpanded}
+                      >
+                        <IconMaximize size={14} />
+                      </ActionIcon>
+                    </Tooltip>
+                    <Tooltip label="Clear conversation">
+                      <ActionIcon 
+                        variant="light" 
+                        color="red" 
+                        onClick={clearConversation}
+                        disabled={messages.length === 0}
... 119480 lines suppressed ...


(incubator-resilientdb) 03/06: Add .env to .gitignore, enable global stats increment in PBFT commitment, update response handling in Stats, and introduce ResLens Flamegraph Analysis Service with Gunicorn configuration and startup scripts.

Posted by ha...@apache.org.
This is an automated email from the ASF dual-hosted git repository.

harishgokul01 pushed a commit to branch demo
in repository https://gitbox.apache.org/repos/asf/incubator-resilientdb.git

commit 811489294c0367af57ee6813b833f6b33ac90917
Author: harish876 <ha...@gmail.com>
AuthorDate: Sat Dec 20 04:19:52 2025 +0000

    Add .env to .gitignore, enable global stats increment in PBFT commitment, update response handling in Stats, and introduce ResLens Flamegraph Analysis Service with Gunicorn configuration and startup scripts.
---
 .gitignore                                         |   1 +
 platform/consensus/ordering/pbft/commitment.cpp    |   4 +-
 platform/statistic/stats.cpp                       |   5 +-
 scripts/deploy/script/restart_reslens.sh           |  14 ++
 service/tools/config/server/server.config          |   5 +-
 .../tools/kv/api_tools/monitoring/gunicorn.conf.py |  38 ++++
 .../tools/kv/api_tools/monitoring/requirements.txt |  10 +
 .../api_tools/monitoring/reslens_tools_service.py  | 243 +++++++++++++++++++++
 .../monitoring/start_reslens_tools_service.sh      |  75 +++++++
 9 files changed, 389 insertions(+), 6 deletions(-)

diff --git a/.gitignore b/.gitignore
index acd52c56..d5db0cc9 100644
--- a/.gitignore
+++ b/.gitignore
@@ -22,6 +22,7 @@ resdb/
 gmon.out
 .history/
 service/tools/data/cert/
+*.env
 # Generated LLM cache and Pocketflow outputs
 llm_cache.json
 ecosystem/pocketflow/.pf-output/
diff --git a/platform/consensus/ordering/pbft/commitment.cpp b/platform/consensus/ordering/pbft/commitment.cpp
index 4d048331..4a1aacc0 100644
--- a/platform/consensus/ordering/pbft/commitment.cpp
+++ b/platform/consensus/ordering/pbft/commitment.cpp
@@ -245,7 +245,7 @@ int Commitment::ProcessPrepareMsg(std::unique_ptr<Context> context,
     return message_manager_->AddConsensusMsg(context->signature,
                                              std::move(request));
   }
-  //global_stats_->IncPrepare();
+  global_stats_->IncPrepare();
   std::unique_ptr<Request> commit_request = resdb::NewRequest(
       Request::TYPE_COMMIT, *request, config_.GetSelfInfo().id());
   commit_request->mutable_data_signature()->Clear();
@@ -288,7 +288,7 @@ int Commitment::ProcessCommitMsg(std::unique_ptr<Context> context,
     return message_manager_->AddConsensusMsg(context->signature,
                                              std::move(request));
   }
-  //global_stats_->IncCommit();
+  global_stats_->IncCommit();
   // Add request to message_manager.
   // If it has received enough same requests(2f+1), message manager will
   // commit the request.
diff --git a/platform/statistic/stats.cpp b/platform/statistic/stats.cpp
index 21f1524f..dfc1957d 100644
--- a/platform/statistic/stats.cpp
+++ b/platform/statistic/stats.cpp
@@ -167,12 +167,13 @@ void Stats::CrowRoute() {
             res.set_header(
                 "Access-Control-Allow-Headers",
                 "Content-Type, Authorization");  // Specify allowed headers
-
+            
+            res.body = "Not Enabled";
             // Send your response
             if (enable_faulty_switch_) {
               make_faulty_.store(!make_faulty_.load());
+              res.body = "Success";
             }
-            res.body = "Success";
             res.end();
           });
       CROW_ROUTE(app, "/transaction_data")
diff --git a/scripts/deploy/script/restart_reslens.sh b/scripts/deploy/script/restart_reslens.sh
new file mode 100755
index 00000000..229fe830
--- /dev/null
+++ b/scripts/deploy/script/restart_reslens.sh
@@ -0,0 +1,14 @@
+#!/usr/bin/env bash
+
+set -euo pipefail
+
+cd /home/ubuntu/resilient-monitoring/ResLens-Middleware
+
+# Stop existing containers (if any)
+sudo docker-compose down || true
+
+# Start containers in detached mode
+sudo docker-compose up -d
+
+
+
diff --git a/service/tools/config/server/server.config b/service/tools/config/server/server.config
index 88fd8c50..8b435651 100644
--- a/service/tools/config/server/server.config
+++ b/service/tools/config/server/server.config
@@ -47,8 +47,9 @@
     block_cache_capacity: 100
   },
   require_txn_validation:true,
-  enable_viewchange:false,
+  enable_viewchange:true,
   enable_resview:true,
-  enable_faulty_switch:false
+  enable_faulty_switch:false,
+  recovery_enabled:false,
 }
 
diff --git a/service/tools/kv/api_tools/monitoring/gunicorn.conf.py b/service/tools/kv/api_tools/monitoring/gunicorn.conf.py
new file mode 100644
index 00000000..d763514e
--- /dev/null
+++ b/service/tools/kv/api_tools/monitoring/gunicorn.conf.py
@@ -0,0 +1,38 @@
+#!/usr/bin/env python3
+"""
+Gunicorn configuration for ResLens Flamegraph Analysis Service
+"""
+
+# Server socket
+bind = "0.0.0.0:8080"
+backlog = 2048
+
+# Worker processes
+workers = 1  # Single worker for this service
+worker_class = "sync"
+worker_connections = 1000
+max_requests = 1000
+max_requests_jitter = 50
+
+# Timeout
+timeout = 30
+keepalive = 2
+
+# Logging
+accesslog = "-"
+errorlog = "-"
+loglevel = "info"
+access_log_format = '%(h)s %(l)s %(u)s %(t)s "%(r)s" %(s)s %(b)s "%(f)s" "%(a)s"'
+
+# Process naming
+proc_name = "reslens-flamegraph-service"
+
+# Preload app for better performance
+preload_app = True
+
+# Worker timeout
+graceful_timeout = 30
+
+# Restart workers after this many requests
+max_requests = 1000
+max_requests_jitter = 50 
\ No newline at end of file
diff --git a/service/tools/kv/api_tools/monitoring/requirements.txt b/service/tools/kv/api_tools/monitoring/requirements.txt
new file mode 100644
index 00000000..81e680cb
--- /dev/null
+++ b/service/tools/kv/api_tools/monitoring/requirements.txt
@@ -0,0 +1,10 @@
+blinker==1.9.0
+click==8.2.1
+Flask==3.1.1
+flask-cors==6.0.1
+gunicorn==23.0.0
+itsdangerous==2.2.0
+Jinja2==3.1.6
+MarkupSafe==3.0.2
+packaging==25.0
+Werkzeug==3.1.3
diff --git a/service/tools/kv/api_tools/monitoring/reslens_tools_service.py b/service/tools/kv/api_tools/monitoring/reslens_tools_service.py
new file mode 100644
index 00000000..964e7311
--- /dev/null
+++ b/service/tools/kv/api_tools/monitoring/reslens_tools_service.py
@@ -0,0 +1,243 @@
+#!/usr/bin/env python3
+"""
+ResLens Flamegraph Analysis Service
+
+A simple HTTP service for executing ResilientDB random data operations
+as part of the ResLens monitoring and analysis toolkit.
+
+This utility is used mainly to seed data to create a long running data seeding job for flamegroah analysis as these flamegraph processes need to run for more than 30s.
+"""
+
+import os
+import sys
+import json
+import subprocess
+import random
+import threading
+import time
+from flask import Flask, request, jsonify
+from flask_cors import CORS
+
+app = Flask(__name__)
+CORS(app)
+
+class ResLensToolsService:
+    def __init__(self):
+        self.project_root = self._find_project_root()
+        self.seeding_running = False
+        self.seeding_thread = None
+        self.seeding_lock = threading.Lock()
+        print(f"ResLens Tools Service - Using project root: {self.project_root}")
+    
+    def _find_project_root(self):
+        """Find the ResilientDB project root directory."""
+        resilientdb_root = os.getenv("RESILIENTDB_ROOT")
+        if resilientdb_root:
+            return resilientdb_root
+        
+        # Since we're now in service/tools/kv/api_tools/monitoring, go up to project root
+        current_dir = os.path.dirname(os.path.abspath(__file__))
+        project_root = os.path.join(current_dir, "../../../../../../")
+        
+        # Verify this is the project root by checking for bazel-bin
+        if os.path.exists(os.path.join(project_root, "bazel-bin")):
+            return project_root
+        
+        # Fallback to common paths
+        possible_paths = [
+            "/opt/resilientdb",
+            "/home/ubuntu/incubator-resilientdb", 
+            os.path.join(os.path.expanduser("~"), "resilientdb")
+        ]
+        
+        for path in possible_paths:
+            tool_path = os.path.join(path, "bazel-bin/service/tools/kv/api_tools/kv_service_tools")
+            if os.path.exists(tool_path):
+                return path
+        
+        return "/opt/resilientdb"
+    
+    def _get_tool_path(self):
+        """Get the path to the kv_service_tools binary."""
+        return f"{self.project_root}/bazel-bin/service/tools/kv/api_tools/kv_service_tools"
+    
+    def _check_tool_exists(self):
+        """Check if the CLI tool exists."""
+        tool_path = self._get_tool_path()
+        return os.path.exists(tool_path) and os.access(tool_path, os.X_OK)
+    
+    def start_seeding(self, count):
+        """Start data seeding job in background thread."""
+        if self.seeding_running:
+            return {
+                "service": "ResLens Flamegraph Analysis Service",
+                "status": "error",
+                "message": "Seeding job already running"
+            }
+        
+        self.seeding_running = True
+        
+        def seeding_worker():
+            for i in range(count):
+                if not self.seeding_running:
+                    break
+                
+                key = f"key{random.randint(0, 499)}"
+                value = f"value{random.randint(0, 499)}"
+                
+                cmd = [
+                    self._get_tool_path(),
+                    "--config", f"{self.project_root}/service/tools/config/interface/service.config",
+                    "--cmd", "set",
+                    "--key", key,
+                    "--value", value
+                ]
+                
+                try:
+                    subprocess.run(cmd, capture_output=True, text=True, timeout=30)
+                except (subprocess.TimeoutExpired, Exception):
+                    # Silently continue on errors - no logging needed
+                    pass
+                
+                time.sleep(0.1) 
+            
+            with self.seeding_lock:
+                self.seeding_running = False
+        
+        self.seeding_thread = threading.Thread(target=seeding_worker, daemon=True)
+        self.seeding_thread.start()
+        
+        return {
+            "service": "ResLens Flamegraph Analysis Service",
+            "status": "success",
+            "message": f"Started seeding job with {count} operations"
+        }
+    
+    def stop_seeding(self):
+        """Stop the data seeding job."""
+        if not self.seeding_running:
+            return {
+                "service": "ResLens Flamegraph Analysis Service",
+                "status": "error",
+                "message": "No seeding job running"
+            }
+        
+        self.seeding_running = False
+        if self.seeding_thread and self.seeding_thread.is_alive():
+            self.seeding_thread.join(timeout=5)
+        
+        return {
+            "service": "ResLens Flamegraph Analysis Service",
+            "status": "success",
+            "message": "Seeding job stopped"
+        }
+    
+    def get_seeding_status(self):
+        """Get current seeding job status."""
+        with self.seeding_lock:
+            return {
+                "service": "ResLens Flamegraph Analysis Service",
+                "status": "running" if self.seeding_running else "stopped"
+            }
+
+# Global service instance
+service = ResLensToolsService()
+
+@app.route('/health', methods=['GET'])
+def health():
+    """Health check endpoint."""
+    return jsonify({
+        "service": "ResLens Flamegraph Analysis Service",
+        "status": "ok"
+    })
+
+@app.route('/seed', methods=['POST'])
+def start_seeding():
+    """Start data seeding job."""
+    try:
+        data = request.get_json()
+        if not data:
+            return jsonify({
+                "service": "ResLens Flamegraph Analysis Service",
+                "status": "error",
+                "message": "No JSON data provided"
+            }), 400
+        
+        count = data.get('count')
+        if count is None:
+            return jsonify({
+                "service": "ResLens Flamegraph Analysis Service",
+                "status": "error",
+                "message": "Missing 'count' parameter"
+            }), 400
+        
+        if not isinstance(count, int) or count <= 0:
+            return jsonify({
+                "service": "ResLens Flamegraph Analysis Service",
+                "status": "error",
+                "message": "Count must be a positive integer"
+            }), 400
+        
+        # Check if CLI tool exists before starting
+        if not service._check_tool_exists():
+            return jsonify({
+                "service": "ResLens Flamegraph Analysis Service",
+                "status": "error",
+                "message": f"CLI tool not found at {service._get_tool_path()}"
+            }), 503
+        
+        return jsonify(service.start_seeding(count))
+        
+    except Exception as e:
+        return jsonify({
+            "service": "ResLens Flamegraph Analysis Service",
+            "status": "error",
+            "message": str(e)
+        }), 500
+
+@app.route('/stop', methods=['POST'])
+def stop_seeding():
+    """Stop data seeding job."""
+    return jsonify(service.stop_seeding())
+
+@app.route('/status', methods=['GET'])
+def get_status():
+    """Get seeding job status."""
+    return jsonify(service.get_seeding_status())
+
+@app.route('/', methods=['GET'])
+def root():
+    """Root endpoint with service information."""
+    return jsonify({
+        "service": "ResLens Flamegraph Analysis Service",
+        "description": "HTTP service for executing ResilientDB random data operations",
+        "endpoints": {
+            "GET /health": "Health check",
+            "POST /seed": "Start data seeding job (JSON body: {\"count\": 5})",
+            "POST /stop": "Stop data seeding job",
+            "GET /status": "Get seeding job status"
+        },
+        "example": {
+            "POST /seed": {
+                "body": {"count": 10},
+                "response": "Starts background job to execute 10 random set operations"
+            },
+            "POST /stop": {
+                "body": "{}",
+                "response": "Stops the running seeding job"
+            }
+        }
+    })
+
+if __name__ == '__main__':
+    port = int(sys.argv[1]) if len(sys.argv) > 1 else 8080
+    
+    print(f"Starting ResLens Flamegraph Analysis Service on port {port}")
+    print("Available endpoints:")
+    print("  GET  /health - Health check")
+    print("  POST /seed - Start data seeding job")
+    print("  POST /stop - Stop data seeding job")
+    print("  GET  /status - Get seeding job status")
+    print("  GET  / - Service information")
+    
+    app.run(host='0.0.0.0', port=port, debug=False, threaded=True) 
\ No newline at end of file
diff --git a/service/tools/kv/api_tools/monitoring/start_reslens_tools_service.sh b/service/tools/kv/api_tools/monitoring/start_reslens_tools_service.sh
new file mode 100755
index 00000000..f4ac21f6
--- /dev/null
+++ b/service/tools/kv/api_tools/monitoring/start_reslens_tools_service.sh
@@ -0,0 +1,75 @@
+#!/bin/bash
+#
+# Startup script for ResLens Flamegraph Analysis Service
+#
+
+# Set the directory to the script location
+cd "$(dirname "$0")"
+
+# Function to find and activate virtual environment
+activate_venv() {
+    # Check for common virtual environment locations
+    local venv_paths=(
+        "venv"
+        "env"
+        ".venv"
+        ".env"
+        "../venv"
+        "../env"
+        "../../venv"
+        "../../env"
+        "/opt/resilientdb/venv"
+        "/opt/resilientdb/env"
+    )
+    
+    for venv_path in "${venv_paths[@]}"; do
+        if [[ -d "$venv_path" && -f "$venv_path/bin/activate" ]]; then
+            echo "Found virtual environment at: $venv_path"
+            source "$venv_path/bin/activate"
+            return 0
+        fi
+    done
+    
+    # Check if we're already in a virtual environment
+    if [[ -n "$VIRTUAL_ENV" ]]; then
+        echo "Already in virtual environment: $VIRTUAL_ENV"
+        return 0
+    fi
+    
+    echo "No virtual environment found. Using system Python."
+    return 1
+}
+
+# Try to activate virtual environment
+if activate_venv; then
+    echo "Using virtual environment: $VIRTUAL_ENV"
+else
+    echo "Using system Python"
+fi
+
+# Check Python version
+python_version=$(python3 --version 2>&1)
+echo "Python version: $python_version"
+
+# Check if gunicorn is installed
+if ! python3 -c "import gunicorn" &> /dev/null; then
+    echo "Gunicorn not found. Installing..."
+    pip install gunicorn
+fi
+
+# Check if Flask is installed
+if ! python3 -c "import flask" &> /dev/null; then
+    echo "Flask not found. Installing..."
+    pip install flask flask-cors
+fi
+
+echo "Starting ResLens Flamegraph Analysis Service with Gunicorn..."
+
+# Run with gunicorn
+gunicorn \
+    --config gunicorn.conf.py \
+    --bind 0.0.0.0:8080 \
+    --workers 1 \
+    --timeout 30 \
+    --log-level info \
+    reslens_tools_service:app 
\ No newline at end of file


(incubator-resilientdb) 06/06: reverting view change bug fixes and removing reslens-tools-service

Posted by ha...@apache.org.
This is an automated email from the ASF dual-hosted git repository.

harishgokul01 pushed a commit to branch demo
in repository https://gitbox.apache.org/repos/asf/incubator-resilientdb.git

commit e25688b64aed807036e1d70ec5a79f6938bb53d3
Author: harish876 <ha...@gmail.com>
AuthorDate: Wed Dec 31 08:47:36 2025 +0000

    reverting view change bug fixes and removing reslens-tools-service
---
 .bazelrc                                           |   3 +-
 .../consensus/ordering/pbft/response_manager.cpp   |  28 +--
 .../consensus/ordering/pbft/viewchange_manager.cpp |  46 +---
 .../ordering/pbft/viewchange_manager_test.cpp      |  10 +-
 scripts/deploy/script/restart_reslens.sh           |   2 +-
 .../tools/kv/api_tools/monitoring/gunicorn.conf.py |  38 ----
 .../tools/kv/api_tools/monitoring/requirements.txt |  10 -
 .../api_tools/monitoring/reslens_tools_service.py  | 243 ---------------------
 .../monitoring/start_reslens_tools_service.sh      |  75 -------
 service/tools/kv/server_tools/start_kv_service.sh  |   9 +-
 10 files changed, 23 insertions(+), 441 deletions(-)

diff --git a/.bazelrc b/.bazelrc
index 2bb0a3a5..43484445 100644
--- a/.bazelrc
+++ b/.bazelrc
@@ -1,4 +1,5 @@
-build --cxxopt='-std=c++17' --copt="-pg" --linkopt="-pg" --strip=never --jobs=2
+build --cxxopt='-std=c++17' --copt="-g" --copt="-fno-omit-frame-pointer" --cxxopt="-fno-omit-frame-pointer" --linkopt="-g" --strip=never --jobs=2
+# build --cxxopt='-std=c++17' --copt="-pg" --linkopt="-pg" --linkopt="-g" --strip=never --jobs=2
 #build --action_env=PYTHON_BIN_PATH="/usr/bin/python3.10"
 #build --action_env=PYTHON_LIB_PATH="/usr/include/python3.10"
 
diff --git a/platform/consensus/ordering/pbft/response_manager.cpp b/platform/consensus/ordering/pbft/response_manager.cpp
index 7cfa9abd..ca80c4a2 100644
--- a/platform/consensus/ordering/pbft/response_manager.cpp
+++ b/platform/consensus/ordering/pbft/response_manager.cpp
@@ -125,13 +125,7 @@ int ResponseManager::ProcessResponseMsg(std::unique_ptr<Context> context,
   // The callback will be triggered if it received f+1 messages.
   if (request->ret() == -2) {
     LOG(ERROR) << "get response fail:" << request->ret();
-    int current = send_num_.load();
-    if (current > 0) {
-      send_num_--;
-    } else {
-      LOG(ERROR) << "send_num_ is already " << current << ", not decrementing";
-      send_num_.store(0);
-    }
+    send_num_--;
     return 0;
   }
   CollectorResultCode ret =
@@ -226,13 +220,7 @@ void ResponseManager::SendResponseToClient(
   } else {
     LOG(ERROR) << "seq:" << local_id << " no resp";
   }
-  int current = send_num_.load();
-  if (current > 0) {
-    send_num_--;
-  } else {
-    LOG(ERROR) << "send_num_ is already " << current << ", not decrementing";
-    send_num_.store(0);
-  }
+  send_num_--;
 
   if (config_.IsPerformanceRunning()) {
     return;
@@ -265,14 +253,8 @@ int ResponseManager::BatchProposeMsg() {
             << " batch num:" << config_.ClientBatchNum();
   std::vector<std::unique_ptr<QueueItem>> batch_req;
   while (!stop_) {
-    int current_send_num = send_num_.load();
-    if (current_send_num < 0) {
-      LOG(ERROR) << "send_num_ is negative (" << current_send_num << "), resetting to 0";
-      send_num_.store(0);
-      current_send_num = 0;
-    }
-    if (current_send_num > config_.GetMaxProcessTxn()) {
-      LOG(ERROR) << "send num too high, wait:" << current_send_num;
+    if (send_num_ > config_.GetMaxProcessTxn()) {
+      LOG(ERROR) << "send num too high, wait:" << send_num_;
       usleep(100);
       continue;
     }
@@ -425,4 +407,4 @@ void ResponseManager::MonitoringClientTimeOut() {
     }
   }
 }
-}  // namespace resdb
+}  // namespace resdb
\ No newline at end of file
diff --git a/platform/consensus/ordering/pbft/viewchange_manager.cpp b/platform/consensus/ordering/pbft/viewchange_manager.cpp
index bed36862..58900ce0 100644
--- a/platform/consensus/ordering/pbft/viewchange_manager.cpp
+++ b/platform/consensus/ordering/pbft/viewchange_manager.cpp
@@ -129,14 +129,7 @@ void ViewChangeManager::MayStart() {
       view_change_counter_++;
     }
     // std::lock_guard<std::mutex> lk(status_mutex_);
-    LOG(ERROR) << "[VIEWCHANGE] Timeout handler triggered - current status: "
-               << status_ << " attempting to change to READY_VIEW_CHANGE";
-    bool changed = ChangeStatue(ViewChangeStatus::READY_VIEW_CHANGE);
-    LOG(ERROR) << "[VIEWCHANGE] ChangeStatue returned: " << changed
-               << " current status: " << status_;
-    if (changed) {
-      LOG(ERROR) << "[VIEWCHANGE] Status changed to READY_VIEW_CHANGE, sending "
-                    "view change msg";
+    if (ChangeStatue(ViewChangeStatus::READY_VIEW_CHANGE)) {
       SendViewChangeMsg();
       auto viewchange_timer = std::make_shared<ViewChangeTimeout>(
           ViewChangeTimerType::TYPE_VIEWCHANGE, system_info_->GetCurrentView(),
@@ -203,13 +196,10 @@ bool ViewChangeManager::IsValidViewChangeMsg(
       }
       std::string data;
       proof.request().SerializeToString(&data);
-      // Skip signature verification if verifier is null or disabled
-      // if (verifier_ && config_.SignatureVerifierEnabled()) {
-      //   if (!verifier_->VerifyMessage(data, proof.signature())) {
-      //     LOG(ERROR) << "proof signature not valid";
-      //     return false;
-      //   }
-      // }
+      if (!verifier_->VerifyMessage(data, proof.signature())) {
+        LOG(ERROR) << "proof signature not valid";
+        return false;
+      }
     }
   }
   return true;
@@ -485,35 +475,21 @@ void ViewChangeManager::SendViewChangeMsg() {
 
   // n (sequence number of the latest checkpoint) and C (proof for the stable
   // checkpoint)
-  LOG(ERROR) << "[VIEWCHANGE] Getting stable checkpoint with votes";
   *view_change_message.mutable_stable_ckpt() =
       checkpoint_manager_->GetStableCheckpointWithVotes();
-  LOG(ERROR) << "[VIEWCHANGE] Got stable checkpoint, seq: "
-             << view_change_message.stable_ckpt().seq();
 
   // P - P is a set containing a set Pm for each request m that prepared at i
   // with a sequence number higher than n.
-  LOG(ERROR) << "[VIEWCHANGE] Getting highest prepared seq";
   int max_seq = checkpoint_manager_->GetHighestPreparedSeq();
-  LOG(ERROR) << "[VIEWCHANGE] Got highest prepared seq: " << max_seq;
-  LOG(ERROR) << "[VIEWCHANGE] Check prepared or committed txns from "
-             << view_change_message.stable_ckpt().seq() + 1 << " to "
-             << max_seq;
-
-  LOG(ERROR) << "[VIEWCHANGE] Checking prepared messages from "
-             << (view_change_message.stable_ckpt().seq() + 1) << " to "
-             << max_seq;
+  LOG(INFO) << "Check prepared or committed txns from "
+            << view_change_message.stable_ckpt().seq() + 1 << " to " << max_seq;
+
   for (int i = view_change_message.stable_ckpt().seq() + 1; i <= max_seq; ++i) {
     // seq i has been prepared or committed.
-    LOG(ERROR) << "[VIEWCHANGE] Checking seq: " << i;
     if (message_manager_->GetTransactionState(i) >=
         TransactionStatue::READY_COMMIT) {
-      LOG(ERROR) << "[VIEWCHANGE] Seq " << i
-                 << " is READY_COMMIT, getting proof";
       std::vector<RequestInfo> proof_info =
           message_manager_->GetPreparedProof(i);
-      LOG(ERROR) << "[VIEWCHANGE] Got proof for seq " << i
-                 << ", size: " << proof_info.size();
       assert(proof_info.size() >= config_.GetMinDataReceiveNum());
       auto txn = view_change_message.add_prepared_msg();
       txn->set_seq(i);
@@ -524,16 +500,12 @@ void ViewChangeManager::SendViewChangeMsg() {
       }
     }
   }
-  LOG(ERROR) << "[VIEWCHANGE] Finished checking prepared messages";
 
   // Broadcast my view change request.
-  LOG(ERROR) << "[VIEWCHANGE] Creating view change request and broadcasting";
   std::unique_ptr<Request> request = NewRequest(
       Request::TYPE_VIEWCHANGE, Request(), config_.GetSelfInfo().id());
   view_change_message.SerializeToString(request->mutable_data());
-  LOG(ERROR) << "[VIEWCHANGE] About to call BroadCast";
   replica_communicator_->BroadCast(*request);
-  LOG(ERROR) << "[VIEWCHANGE] BroadCast called";
 }
 
 void ViewChangeManager::AddComplaintTimer(uint64_t proxy_id, std::string hash) {
@@ -643,4 +615,4 @@ void ViewChangeManager::SetDuplicateManager(DuplicateManager* manager) {
   duplicate_manager_ = manager;
 }
 
-}  // namespace resdb
+}  // namespace resdb
\ No newline at end of file
diff --git a/platform/consensus/ordering/pbft/viewchange_manager_test.cpp b/platform/consensus/ordering/pbft/viewchange_manager_test.cpp
index 1803dd0b..7a2ec693 100644
--- a/platform/consensus/ordering/pbft/viewchange_manager_test.cpp
+++ b/platform/consensus/ordering/pbft/viewchange_manager_test.cpp
@@ -33,9 +33,6 @@
 #include "platform/consensus/ordering/pbft/transaction_utils.h"
 #include "platform/networkstrate/mock_replica_communicator.h"
 #include "platform/proto/checkpoint_info.pb.h"
-#include "common/crypto/signature_verifier.h"
-#include <thread>
-#include <chrono>
 
 namespace resdb {
 namespace {
@@ -85,12 +82,7 @@ TEST_F(ViewChangeManagerTest, SendViewChange) {
   manager_->MayStart();
   std::unique_ptr<Request> request = std::make_unique<Request>();
   request->set_seq(1);
-  request->set_data("test_data");
-  request->set_hash(SignatureVerifier::CalculateHash("test_data"));
   checkpoint_manager_->AddCommitData(std::move(request));
-  
-  std::this_thread::sleep_for(std::chrono::milliseconds(100));
-  
   std::promise<bool> propose_done;
   std::future<bool> propose_done_future = propose_done.get_future();
   EXPECT_CALL(replica_communicator_, BroadCast)
@@ -129,4 +121,4 @@ TEST_F(ViewChangeManagerTest, SendNewView) {
 
 }  // namespace
 
-}  // namespace resdb
+}  // namespace resdb
\ No newline at end of file
diff --git a/scripts/deploy/script/restart_reslens.sh b/scripts/deploy/script/restart_reslens.sh
index 229fe830..66ffe4e8 100755
--- a/scripts/deploy/script/restart_reslens.sh
+++ b/scripts/deploy/script/restart_reslens.sh
@@ -2,7 +2,7 @@
 
 set -euo pipefail
 
-cd /home/ubuntu/resilient-monitoring/ResLens-Middleware
+cd /home/ubuntu/resilient-ecosystem/DeepObserve/external/monitoring/ResLens-Middleware
 
 # Stop existing containers (if any)
 sudo docker-compose down || true
diff --git a/service/tools/kv/api_tools/monitoring/gunicorn.conf.py b/service/tools/kv/api_tools/monitoring/gunicorn.conf.py
deleted file mode 100644
index d763514e..00000000
--- a/service/tools/kv/api_tools/monitoring/gunicorn.conf.py
+++ /dev/null
@@ -1,38 +0,0 @@
-#!/usr/bin/env python3
-"""
-Gunicorn configuration for ResLens Flamegraph Analysis Service
-"""
-
-# Server socket
-bind = "0.0.0.0:8080"
-backlog = 2048
-
-# Worker processes
-workers = 1  # Single worker for this service
-worker_class = "sync"
-worker_connections = 1000
-max_requests = 1000
-max_requests_jitter = 50
-
-# Timeout
-timeout = 30
-keepalive = 2
-
-# Logging
-accesslog = "-"
-errorlog = "-"
-loglevel = "info"
-access_log_format = '%(h)s %(l)s %(u)s %(t)s "%(r)s" %(s)s %(b)s "%(f)s" "%(a)s"'
-
-# Process naming
-proc_name = "reslens-flamegraph-service"
-
-# Preload app for better performance
-preload_app = True
-
-# Worker timeout
-graceful_timeout = 30
-
-# Restart workers after this many requests
-max_requests = 1000
-max_requests_jitter = 50 
\ No newline at end of file
diff --git a/service/tools/kv/api_tools/monitoring/requirements.txt b/service/tools/kv/api_tools/monitoring/requirements.txt
deleted file mode 100644
index 81e680cb..00000000
--- a/service/tools/kv/api_tools/monitoring/requirements.txt
+++ /dev/null
@@ -1,10 +0,0 @@
-blinker==1.9.0
-click==8.2.1
-Flask==3.1.1
-flask-cors==6.0.1
-gunicorn==23.0.0
-itsdangerous==2.2.0
-Jinja2==3.1.6
-MarkupSafe==3.0.2
-packaging==25.0
-Werkzeug==3.1.3
diff --git a/service/tools/kv/api_tools/monitoring/reslens_tools_service.py b/service/tools/kv/api_tools/monitoring/reslens_tools_service.py
deleted file mode 100644
index 964e7311..00000000
--- a/service/tools/kv/api_tools/monitoring/reslens_tools_service.py
+++ /dev/null
@@ -1,243 +0,0 @@
-#!/usr/bin/env python3
-"""
-ResLens Flamegraph Analysis Service
-
-A simple HTTP service for executing ResilientDB random data operations
-as part of the ResLens monitoring and analysis toolkit.
-
-This utility is used mainly to seed data to create a long running data seeding job for flamegroah analysis as these flamegraph processes need to run for more than 30s.
-"""
-
-import os
-import sys
-import json
-import subprocess
-import random
-import threading
-import time
-from flask import Flask, request, jsonify
-from flask_cors import CORS
-
-app = Flask(__name__)
-CORS(app)
-
-class ResLensToolsService:
-    def __init__(self):
-        self.project_root = self._find_project_root()
-        self.seeding_running = False
-        self.seeding_thread = None
-        self.seeding_lock = threading.Lock()
-        print(f"ResLens Tools Service - Using project root: {self.project_root}")
-    
-    def _find_project_root(self):
-        """Find the ResilientDB project root directory."""
-        resilientdb_root = os.getenv("RESILIENTDB_ROOT")
-        if resilientdb_root:
-            return resilientdb_root
-        
-        # Since we're now in service/tools/kv/api_tools/monitoring, go up to project root
-        current_dir = os.path.dirname(os.path.abspath(__file__))
-        project_root = os.path.join(current_dir, "../../../../../../")
-        
-        # Verify this is the project root by checking for bazel-bin
-        if os.path.exists(os.path.join(project_root, "bazel-bin")):
-            return project_root
-        
-        # Fallback to common paths
-        possible_paths = [
-            "/opt/resilientdb",
-            "/home/ubuntu/incubator-resilientdb", 
-            os.path.join(os.path.expanduser("~"), "resilientdb")
-        ]
-        
-        for path in possible_paths:
-            tool_path = os.path.join(path, "bazel-bin/service/tools/kv/api_tools/kv_service_tools")
-            if os.path.exists(tool_path):
-                return path
-        
-        return "/opt/resilientdb"
-    
-    def _get_tool_path(self):
-        """Get the path to the kv_service_tools binary."""
-        return f"{self.project_root}/bazel-bin/service/tools/kv/api_tools/kv_service_tools"
-    
-    def _check_tool_exists(self):
-        """Check if the CLI tool exists."""
-        tool_path = self._get_tool_path()
-        return os.path.exists(tool_path) and os.access(tool_path, os.X_OK)
-    
-    def start_seeding(self, count):
-        """Start data seeding job in background thread."""
-        if self.seeding_running:
-            return {
-                "service": "ResLens Flamegraph Analysis Service",
-                "status": "error",
-                "message": "Seeding job already running"
-            }
-        
-        self.seeding_running = True
-        
-        def seeding_worker():
-            for i in range(count):
-                if not self.seeding_running:
-                    break
-                
-                key = f"key{random.randint(0, 499)}"
-                value = f"value{random.randint(0, 499)}"
-                
-                cmd = [
-                    self._get_tool_path(),
-                    "--config", f"{self.project_root}/service/tools/config/interface/service.config",
-                    "--cmd", "set",
-                    "--key", key,
-                    "--value", value
-                ]
-                
-                try:
-                    subprocess.run(cmd, capture_output=True, text=True, timeout=30)
-                except (subprocess.TimeoutExpired, Exception):
-                    # Silently continue on errors - no logging needed
-                    pass
-                
-                time.sleep(0.1) 
-            
-            with self.seeding_lock:
-                self.seeding_running = False
-        
-        self.seeding_thread = threading.Thread(target=seeding_worker, daemon=True)
-        self.seeding_thread.start()
-        
-        return {
-            "service": "ResLens Flamegraph Analysis Service",
-            "status": "success",
-            "message": f"Started seeding job with {count} operations"
-        }
-    
-    def stop_seeding(self):
-        """Stop the data seeding job."""
-        if not self.seeding_running:
-            return {
-                "service": "ResLens Flamegraph Analysis Service",
-                "status": "error",
-                "message": "No seeding job running"
-            }
-        
-        self.seeding_running = False
-        if self.seeding_thread and self.seeding_thread.is_alive():
-            self.seeding_thread.join(timeout=5)
-        
-        return {
-            "service": "ResLens Flamegraph Analysis Service",
-            "status": "success",
-            "message": "Seeding job stopped"
-        }
-    
-    def get_seeding_status(self):
-        """Get current seeding job status."""
-        with self.seeding_lock:
-            return {
-                "service": "ResLens Flamegraph Analysis Service",
-                "status": "running" if self.seeding_running else "stopped"
-            }
-
-# Global service instance
-service = ResLensToolsService()
-
-@app.route('/health', methods=['GET'])
-def health():
-    """Health check endpoint."""
-    return jsonify({
-        "service": "ResLens Flamegraph Analysis Service",
-        "status": "ok"
-    })
-
-@app.route('/seed', methods=['POST'])
-def start_seeding():
-    """Start data seeding job."""
-    try:
-        data = request.get_json()
-        if not data:
-            return jsonify({
-                "service": "ResLens Flamegraph Analysis Service",
-                "status": "error",
-                "message": "No JSON data provided"
-            }), 400
-        
-        count = data.get('count')
-        if count is None:
-            return jsonify({
-                "service": "ResLens Flamegraph Analysis Service",
-                "status": "error",
-                "message": "Missing 'count' parameter"
-            }), 400
-        
-        if not isinstance(count, int) or count <= 0:
-            return jsonify({
-                "service": "ResLens Flamegraph Analysis Service",
-                "status": "error",
-                "message": "Count must be a positive integer"
-            }), 400
-        
-        # Check if CLI tool exists before starting
-        if not service._check_tool_exists():
-            return jsonify({
-                "service": "ResLens Flamegraph Analysis Service",
-                "status": "error",
-                "message": f"CLI tool not found at {service._get_tool_path()}"
-            }), 503
-        
-        return jsonify(service.start_seeding(count))
-        
-    except Exception as e:
-        return jsonify({
-            "service": "ResLens Flamegraph Analysis Service",
-            "status": "error",
-            "message": str(e)
-        }), 500
-
-@app.route('/stop', methods=['POST'])
-def stop_seeding():
-    """Stop data seeding job."""
-    return jsonify(service.stop_seeding())
-
-@app.route('/status', methods=['GET'])
-def get_status():
-    """Get seeding job status."""
-    return jsonify(service.get_seeding_status())
-
-@app.route('/', methods=['GET'])
-def root():
-    """Root endpoint with service information."""
-    return jsonify({
-        "service": "ResLens Flamegraph Analysis Service",
-        "description": "HTTP service for executing ResilientDB random data operations",
-        "endpoints": {
-            "GET /health": "Health check",
-            "POST /seed": "Start data seeding job (JSON body: {\"count\": 5})",
-            "POST /stop": "Stop data seeding job",
-            "GET /status": "Get seeding job status"
-        },
-        "example": {
-            "POST /seed": {
-                "body": {"count": 10},
-                "response": "Starts background job to execute 10 random set operations"
-            },
-            "POST /stop": {
-                "body": "{}",
-                "response": "Stops the running seeding job"
-            }
-        }
-    })
-
-if __name__ == '__main__':
-    port = int(sys.argv[1]) if len(sys.argv) > 1 else 8080
-    
-    print(f"Starting ResLens Flamegraph Analysis Service on port {port}")
-    print("Available endpoints:")
-    print("  GET  /health - Health check")
-    print("  POST /seed - Start data seeding job")
-    print("  POST /stop - Stop data seeding job")
-    print("  GET  /status - Get seeding job status")
-    print("  GET  / - Service information")
-    
-    app.run(host='0.0.0.0', port=port, debug=False, threaded=True) 
\ No newline at end of file
diff --git a/service/tools/kv/api_tools/monitoring/start_reslens_tools_service.sh b/service/tools/kv/api_tools/monitoring/start_reslens_tools_service.sh
deleted file mode 100755
index f4ac21f6..00000000
--- a/service/tools/kv/api_tools/monitoring/start_reslens_tools_service.sh
+++ /dev/null
@@ -1,75 +0,0 @@
-#!/bin/bash
-#
-# Startup script for ResLens Flamegraph Analysis Service
-#
-
-# Set the directory to the script location
-cd "$(dirname "$0")"
-
-# Function to find and activate virtual environment
-activate_venv() {
-    # Check for common virtual environment locations
-    local venv_paths=(
-        "venv"
-        "env"
-        ".venv"
-        ".env"
-        "../venv"
-        "../env"
-        "../../venv"
-        "../../env"
-        "/opt/resilientdb/venv"
-        "/opt/resilientdb/env"
-    )
-    
-    for venv_path in "${venv_paths[@]}"; do
-        if [[ -d "$venv_path" && -f "$venv_path/bin/activate" ]]; then
-            echo "Found virtual environment at: $venv_path"
-            source "$venv_path/bin/activate"
-            return 0
-        fi
-    done
-    
-    # Check if we're already in a virtual environment
-    if [[ -n "$VIRTUAL_ENV" ]]; then
-        echo "Already in virtual environment: $VIRTUAL_ENV"
-        return 0
-    fi
-    
-    echo "No virtual environment found. Using system Python."
-    return 1
-}
-
-# Try to activate virtual environment
-if activate_venv; then
-    echo "Using virtual environment: $VIRTUAL_ENV"
-else
-    echo "Using system Python"
-fi
-
-# Check Python version
-python_version=$(python3 --version 2>&1)
-echo "Python version: $python_version"
-
-# Check if gunicorn is installed
-if ! python3 -c "import gunicorn" &> /dev/null; then
-    echo "Gunicorn not found. Installing..."
-    pip install gunicorn
-fi
-
-# Check if Flask is installed
-if ! python3 -c "import flask" &> /dev/null; then
-    echo "Flask not found. Installing..."
-    pip install flask flask-cors
-fi
-
-echo "Starting ResLens Flamegraph Analysis Service with Gunicorn..."
-
-# Run with gunicorn
-gunicorn \
-    --config gunicorn.conf.py \
-    --bind 0.0.0.0:8080 \
-    --workers 1 \
-    --timeout 30 \
-    --log-level info \
-    reslens_tools_service:app 
\ No newline at end of file
diff --git a/service/tools/kv/server_tools/start_kv_service.sh b/service/tools/kv/server_tools/start_kv_service.sh
index 3fd53602..6bd71b74 100755
--- a/service/tools/kv/server_tools/start_kv_service.sh
+++ b/service/tools/kv/server_tools/start_kv_service.sh
@@ -23,10 +23,11 @@ SERVER_CONFIG=service/tools/config/server/server.config
 WORK_PATH=$PWD
 CERT_PATH=${WORK_PATH}/service/tools/data/cert/
 
-./service/tools/kv/server_tools/generate_keys_and_certs.sh || {
-  echo "Failed to generate configs/certificates" 1>&2
-  exit 1
-}
+# This has to be a one time operation
+# ./service/tools/kv/server_tools/generate_keys_and_certs.sh || {
+#   echo "Failed to generate configs/certificates" 1>&2
+#   exit 1
+# }
 
 bazel build //service/kv:kv_service $@
 nohup $SERVER_PATH $SERVER_CONFIG $CERT_PATH/node1.key.pri $CERT_PATH/cert_1.cert > server0.log &


(incubator-resilientdb) 02/06: renaming tools folder

Posted by ha...@apache.org.
This is an automated email from the ASF dual-hosted git repository.

harishgokul01 pushed a commit to branch demo
in repository https://gitbox.apache.org/repos/asf/incubator-resilientdb.git

commit 922d79dfe34111d65df14a985f8b958e43d837e8
Author: harish876 <ha...@gmail.com>
AuthorDate: Mon Dec 15 20:46:23 2025 +0000

    renaming tools folder
---
 ecosystem/AI-Tooling/beacon/.vscode/settings.json           |   4 ----
 ecosystem/AI-Tooling/nexus/parsing-cache.json               |   1 -
 .../{AI-Tooling => ai-tooling}/beacon/.env.local.example    |   0
 .../beacon/.github/assets/beacon-hero.png                   | Bin
 .../beacon/.github/workflows/license.yml                    |   0
 .../beacon/.github/workflows/loc.yml                        |   0
 ecosystem/{AI-Tooling => ai-tooling}/beacon/.gitignore      |   0
 ecosystem/{AI-Tooling => ai-tooling}/beacon/.licenserc.yaml |   0
 ecosystem/{AI-Tooling => ai-tooling}/beacon/.npmrc          |   0
 ecosystem/{AI-Tooling => ai-tooling}/beacon/.nvmrc          |   0
 ecosystem/{AI-Tooling => ai-tooling}/beacon/.prettierignore |   0
 ecosystem/{AI-Tooling => ai-tooling}/beacon/.prettierrc.mjs |   0
 .../{AI-Tooling => ai-tooling}/beacon/.storybook/main.ts    |   0
 .../beacon/.storybook/preview.tsx                           |   0
 .../{AI-Tooling => ai-tooling}/beacon/.stylelintignore      |   0
 .../{AI-Tooling => ai-tooling}/beacon/.stylelintrc.json     |   0
 .../{AI-Tooling => ai-tooling}/beacon/CODE_OF_CONDUCT.md    |   0
 ecosystem/{AI-Tooling => ai-tooling}/beacon/DISCLAIMER.txt  |   0
 ecosystem/{AI-Tooling => ai-tooling}/beacon/LICENSE         |   0
 ecosystem/{AI-Tooling => ai-tooling}/beacon/NOTICE          |   0
 ecosystem/{AI-Tooling => ai-tooling}/beacon/README.md       |   0
 ecosystem/{AI-Tooling => ai-tooling}/beacon/app/_meta.ts    |   0
 .../beacon/app/api/ai-search/route.ts                       |   0
 .../{AI-Tooling => ai-tooling}/beacon/app/api/chat/route.ts |   0
 .../beacon/app/api/compile/route.ts                         |   0
 .../beacon/app/api/github-releases/route.ts                 |   0
 .../beacon/app/docs/[[...mdxPath]]/page.tsx                 |   0
 ecosystem/{AI-Tooling => ai-tooling}/beacon/app/global.css  |   0
 ecosystem/{AI-Tooling => ai-tooling}/beacon/app/layout.tsx  |   0
 .../{AI-Tooling => ai-tooling}/beacon/app/lib/constants.ts  |   0
 .../{AI-Tooling => ai-tooling}/beacon/app/lib/utils.ts      |   0
 .../{AI-Tooling => ai-tooling}/beacon/app/page.module.css   |   0
 ecosystem/{AI-Tooling => ai-tooling}/beacon/app/page.tsx    |   0
 .../{AI-Tooling => ai-tooling}/beacon/app/providers.tsx     |   0
 .../{AI-Tooling => ai-tooling}/beacon/app/search/page.tsx   |   0
 ecosystem/{AI-Tooling => ai-tooling}/beacon/app/sitemap.ts  |   0
 ecosystem/{AI-Tooling => ai-tooling}/beacon/asf.yaml        |   0
 .../beacon/components/AskAIModal.tsx                        |   0
 .../beacon/components/AuthProviders.tsx                     |   0
 .../ColorSchemeControl/ColorSchemeControl.module.css        |   0
 .../ColorSchemeControl/ColorSchemeControl.story.tsx         |   0
 .../components/ColorSchemeControl/ColorSchemeControl.tsx    |   0
 .../components/ColorSchemeControl/HeaderControl.module.css  |   0
 .../beacon/components/ColorSchemeControl/HeaderControl.tsx  |   0
 .../components/ColorSchemeToggle/ColorSchemeToggle.tsx      |   0
 .../beacon/components/CommentSection.tsx                    |   0
 .../beacon/components/Content/Content.story.tsx             |   0
 .../beacon/components/Content/Content.tsx                   |   0
 .../beacon/components/FloatingAssistant.tsx                 |   0
 .../beacon/components/GitHubAuth.tsx                        |   0
 .../beacon/components/InstallationForm.tsx                  |   0
 .../beacon/components/Logo/Logo.story.tsx                   |   0
 .../beacon/components/Logo/Logo.tsx                         |   0
 .../beacon/components/MantineFooter/MantineFooter.tsx       |   0
 .../beacon/components/MantineNavBar/MantineNavBar.tsx       |   0
 .../MantineNextraThemeObserver.tsx                          |   0
 .../beacon/components/PocketFlowChatbot.tsx                 |   0
 .../beacon/components/PythonIDE.tsx                         |   0
 .../beacon/components/PythonPlayground.tsx                  |   0
 .../beacon/components/ReleaseNotes/ReleaseNotes.tsx         |   0
 .../beacon/components/ResContractPlayground.tsx             |   0
 .../beacon/components/SearchBar/PagefindSearch.tsx          |   0
 .../beacon/components/SearchBar/SearchBar.tsx               |   0
 .../beacon/components/TypeScriptPlayground.tsx              |   0
 .../beacon/components/Welcome/Welcome.module.css            |   0
 .../beacon/components/Welcome/Welcome.story.tsx             |   0
 .../beacon/components/Welcome/Welcome.test.tsx              |   0
 .../beacon/components/Welcome/Welcome.tsx                   |   0
 .../beacon/components/cache/NodeConfigGenerator.tsx         |   0
 .../beacon/components/cache/NodeQueryBuilder.tsx            |   0
 .../beacon/components/cache/PythonConfigGenerator.tsx       |   0
 .../beacon/components/cache/PythonQueryBuilder.tsx          |   0
 .../{AI-Tooling => ai-tooling}/beacon/components/index.ts   |   0
 .../beacon/components/landing/Header.tsx                    |   0
 .../beacon/components/landing/HeroContent.tsx               |   0
 .../beacon/components/landing/PulsingCircle.tsx             |   0
 .../beacon/components/landing/ShaderBackground.tsx          |   0
 .../beacon/components/ui/terminal.tsx                       |   0
 .../beacon/components/utils/loadPyodide.ts                  |   0
 .../{AI-Tooling => ai-tooling}/beacon/content/_meta.ts      |   0
 .../{AI-Tooling => ai-tooling}/beacon/content/about.mdx     |   0
 .../{AI-Tooling => ai-tooling}/beacon/content/index.mdx     |   0
 .../beacon/content/installation.mdx                         |   0
 .../{AI-Tooling => ai-tooling}/beacon/content/pythonsdk.mdx |   0
 .../{AI-Tooling => ai-tooling}/beacon/content/rescli.mdx    |   0
 .../beacon/content/rescontract.mdx                          |   0
 .../{AI-Tooling => ai-tooling}/beacon/content/resdb-orm.mdx |   0
 .../beacon/content/resilient-node-cache.mdx                 |   0
 .../beacon/content/resilient-python-cache.mdx               |   0
 .../content/resilientdb/chapters/01_client_interaction.md   |   0
 .../resilientdb/chapters/02_network_communication.md        |   0
 .../content/resilientdb/chapters/03_consensus_management.md |   0
 .../chapters/04_message_transaction_collection.md           |   0
 .../resilientdb/chapters/05_transaction_execution.md        |   0
 .../beacon/content/resilientdb/chapters/06_storage_layer.md |   0
 .../beacon/content/resilientdb/chapters/07_checkpointing.md |   0
 .../resilientdb/chapters/08_resilientdb_configuration.md    |   0
 .../beacon/content/resilientdb/index.mdx                    |   0
 .../beacon/content/resilientdb_graphql/index.mdx            |   0
 .../beacon/content/resilientdb_graphql/setup.mdx            |   0
 .../{AI-Tooling => ai-tooling}/beacon/content/reslens.mdx   |   0
 .../{AI-Tooling => ai-tooling}/beacon/content/resvault.mdx  |   0
 .../{AI-Tooling => ai-tooling}/beacon/eslint.config.mjs     |   0
 ecosystem/{AI-Tooling => ai-tooling}/beacon/jest.config.cjs |   0
 ecosystem/{AI-Tooling => ai-tooling}/beacon/jest.setup.cjs  |   0
 .../beacon/lib/documentIndexer.ts                           |   0
 .../{AI-Tooling => ai-tooling}/beacon/mdx-components.ts     |   0
 ecosystem/{AI-Tooling => ai-tooling}/beacon/next-env.d.ts   |   0
 ecosystem/{AI-Tooling => ai-tooling}/beacon/next.config.mjs |   0
 .../{AI-Tooling => ai-tooling}/beacon/package-lock.json     |   0
 ecosystem/{AI-Tooling => ai-tooling}/beacon/package.json    |   0
 .../beacon/pages/api/auth/[...nextauth].ts                  |   0
 .../beacon/pages/api/create-github-issue.ts                 |   0
 .../{AI-Tooling => ai-tooling}/beacon/pages/auth/_meta.json |   0
 .../{AI-Tooling => ai-tooling}/beacon/pages/auth/error.tsx  |   0
 .../{AI-Tooling => ai-tooling}/beacon/pages/auth/signin.tsx |   0
 .../{AI-Tooling => ai-tooling}/beacon/postcss.config.cjs    |   0
 .../{AI-Tooling => ai-tooling}/beacon/public/favicon.svg    |   0
 .../{AI-Tooling => ai-tooling}/beacon/public/lighthouse.png | Bin
 ecosystem/{AI-Tooling => ai-tooling}/beacon/public/logo.png | Bin
 .../beacon/public/mantine+nextjs+nextra-template.png        | Bin
 .../{AI-Tooling => ai-tooling}/beacon/public/resdb_sdk.py   |   0
 .../beacon/scripts/build-index.js                           |   0
 .../beacon/scripts/build-index.ts                           |   0
 .../beacon/styles/installation.module.css                   |   0
 .../{AI-Tooling => ai-tooling}/beacon/test-utils/index.ts   |   0
 .../{AI-Tooling => ai-tooling}/beacon/test-utils/render.tsx |   0
 ecosystem/{AI-Tooling => ai-tooling}/beacon/theme.ts        |   0
 ecosystem/{AI-Tooling => ai-tooling}/beacon/tsconfig.json   |   0
 .../beacon/types/codemirror__lang-javascript.d.ts           |   0
 .../{AI-Tooling => ai-tooling}/beacon/types/next-auth.d.ts  |   0
 .../beacon/types/react-markdown.d.ts                        |   0
 .../beacon/types/react-syntax-highlighter.d.ts              |   0
 .../nexus/.github/pull_request_template.md                  |   0
 ecosystem/{AI-Tooling => ai-tooling}/nexus/.gitignore       |   0
 ecosystem/{AI-Tooling => ai-tooling}/nexus/README.md        |   0
 .../{AI-Tooling => ai-tooling}/nexus/RESEARCH_SETUP.md      |   0
 ecosystem/{AI-Tooling => ai-tooling}/nexus/components.json  |   0
 ecosystem/{AI-Tooling => ai-tooling}/nexus/docs/DB_SETUP.md |   0
 .../nexus/docs/SYSTEM_ARCHITECTURE.md                       |   0
 ecosystem/{AI-Tooling => ai-tooling}/nexus/docs/blog.md     |   0
 .../{AI-Tooling => ai-tooling}/nexus/docs/images/agent.png  | Bin
 .../nexus/docs/images/research.png                          | Bin
 .../nexus/documents/bchain-transaction-pro.pdf              | Bin
 .../{AI-Tooling => ai-tooling}/nexus/documents/rcc.pdf      | Bin
 .../nexus/documents/resilientdb.pdf                         | Bin
 .../{AI-Tooling => ai-tooling}/nexus/eslint.config.mjs      |   0
 ecosystem/{AI-Tooling => ai-tooling}/nexus/next.config.mjs  |   0
 ecosystem/{AI-Tooling => ai-tooling}/nexus/next.config.ts   |   0
 .../{AI-Tooling => ai-tooling}/nexus/package-lock.json      |   0
 ecosystem/{AI-Tooling => ai-tooling}/nexus/package.json     |   0
 .../{AI-Tooling => ai-tooling}/nexus/postcss.config.mjs     |   0
 .../nexus/public/expolab-icon.png                           | Bin
 .../{AI-Tooling => ai-tooling}/nexus/public/resdb-logo.svg  |   0
 .../nexus/public/resilientdb-icon.png                       | Bin
 .../nexus/src/app/api/research/chat/route.ts                |   0
 .../nexus/src/app/api/research/documents/route.ts           |   0
 .../nexus/src/app/api/research/files/[...path]/route.ts     |   0
 .../nexus/src/app/api/research/prepare-index/route.ts       |   0
 .../{AI-Tooling => ai-tooling}/nexus/src/app/favicon.ico    | Bin
 .../{AI-Tooling => ai-tooling}/nexus/src/app/globals.css    |   0
 .../{AI-Tooling => ai-tooling}/nexus/src/app/layout.tsx     |   0
 ecosystem/{AI-Tooling => ai-tooling}/nexus/src/app/page.tsx |   0
 .../nexus/src/app/research/components/chat-input.tsx        |   0
 .../src/app/research/components/code-generation-tab.tsx     |   0
 .../nexus/src/app/research/components/pdf-preview-tab.tsx   |   0
 .../nexus/src/app/research/components/preview-panel.tsx     |   0
 .../nexus/src/app/research/page.tsx                         |   0
 .../nexus/src/app/research/types.ts                         |   0
 .../nexus/src/components/ai-elements/code-block.tsx         |   0
 .../nexus/src/components/ai-elements/prompt-input.tsx       |   0
 .../nexus/src/components/ai-elements/response.tsx           |   0
 .../nexus/src/components/ai-elements/tool.tsx               |   0
 .../nexus/src/components/context/ToolContext.tsx            |   0
 .../nexus/src/components/providers/QueryProvider.tsx        |   0
 .../nexus/src/components/ui/accordion.tsx                   |   0
 .../nexus/src/components/ui/animated-ai-chat.tsx            |   0
 .../nexus/src/components/ui/badge.tsx                       |   0
 .../nexus/src/components/ui/button.tsx                      |   0
 .../nexus/src/components/ui/card.tsx                        |   0
 .../nexus/src/components/ui/citation-badge.tsx              |   0
 .../nexus/src/components/ui/collapsible.tsx                 |   0
 .../nexus/src/components/ui/dialog.tsx                      |   0
 .../nexus/src/components/ui/document-source-badge.tsx       |   0
 .../nexus/src/components/ui/fluid-blob.tsx                  |   0
 .../nexus/src/components/ui/label.tsx                       |   0
 .../nexus/src/components/ui/loader.tsx                      |   0
 .../nexus/src/components/ui/main-navbar.tsx                 |   0
 .../nexus/src/components/ui/multi-document-selector.tsx     |   0
 .../nexus/src/components/ui/popover.tsx                     |   0
 .../nexus/src/components/ui/resizable.tsx                   |   0
 .../nexus/src/components/ui/scroll-area.tsx                 |   0
 .../nexus/src/components/ui/select.tsx                      |   0
 .../nexus/src/components/ui/separator.tsx                   |   0
 .../nexus/src/components/ui/sheet.tsx                       |   0
 .../nexus/src/components/ui/switch.tsx                      |   0
 .../nexus/src/components/ui/tabs.tsx                        |   0
 .../nexus/src/components/ui/textarea.tsx                    |   0
 .../nexus/src/components/ui/tooltip.tsx                     |   0
 .../nexus/src/config/environment.ts                         |   0
 .../nexus/src/hooks/useDocuments.ts                         |   0
 ecosystem/{AI-Tooling => ai-tooling}/nexus/src/lib/agent.ts |   0
 .../nexus/src/lib/code-composer-agent.ts                    |   0
 .../nexus/src/lib/config/llama-settings.ts                  |   0
 .../{AI-Tooling => ai-tooling}/nexus/src/lib/constants.ts   |   0
 .../nexus/src/lib/google-drive.ts                           |   0
 .../nexus/src/lib/llama-service.ts                          |   0
 .../nexus/src/lib/robust-fact-memory.ts                     |   0
 .../nexus/src/lib/token-estimator.ts                        |   0
 ecosystem/{AI-Tooling => ai-tooling}/nexus/src/lib/utils.ts |   0
 .../nexus/src/tests/test-router.ts                          |   0
 ecosystem/{AI-Tooling => ai-tooling}/nexus/tsconfig.json    |   0
 212 files changed, 5 deletions(-)

diff --git a/ecosystem/AI-Tooling/beacon/.vscode/settings.json b/ecosystem/AI-Tooling/beacon/.vscode/settings.json
deleted file mode 100644
index 7dd4ff3a..00000000
--- a/ecosystem/AI-Tooling/beacon/.vscode/settings.json
+++ /dev/null
@@ -1,4 +0,0 @@
-{
-    "prettier.configPath": ".prettierrc.mjs",
-    "search.useParentIgnoreFiles": true
-}
\ No newline at end of file
diff --git a/ecosystem/AI-Tooling/nexus/parsing-cache.json b/ecosystem/AI-Tooling/nexus/parsing-cache.json
deleted file mode 100644
index 32a2f2ef..00000000
--- a/ecosystem/AI-Tooling/nexus/parsing-cache.json
+++ /dev/null
@@ -1 +0,0 @@
-{"documents/bchain-transaction-pro.pdf":true,"documents/rcc.pdf":true,"documents/resilientdb.pdf":true}
\ No newline at end of file
diff --git a/ecosystem/AI-Tooling/beacon/.env.local.example b/ecosystem/ai-tooling/beacon/.env.local.example
similarity index 100%
rename from ecosystem/AI-Tooling/beacon/.env.local.example
rename to ecosystem/ai-tooling/beacon/.env.local.example
diff --git a/ecosystem/AI-Tooling/beacon/.github/assets/beacon-hero.png b/ecosystem/ai-tooling/beacon/.github/assets/beacon-hero.png
similarity index 100%
rename from ecosystem/AI-Tooling/beacon/.github/assets/beacon-hero.png
rename to ecosystem/ai-tooling/beacon/.github/assets/beacon-hero.png
diff --git a/ecosystem/AI-Tooling/beacon/.github/workflows/license.yml b/ecosystem/ai-tooling/beacon/.github/workflows/license.yml
similarity index 100%
rename from ecosystem/AI-Tooling/beacon/.github/workflows/license.yml
rename to ecosystem/ai-tooling/beacon/.github/workflows/license.yml
diff --git a/ecosystem/AI-Tooling/beacon/.github/workflows/loc.yml b/ecosystem/ai-tooling/beacon/.github/workflows/loc.yml
similarity index 100%
rename from ecosystem/AI-Tooling/beacon/.github/workflows/loc.yml
rename to ecosystem/ai-tooling/beacon/.github/workflows/loc.yml
diff --git a/ecosystem/AI-Tooling/beacon/.gitignore b/ecosystem/ai-tooling/beacon/.gitignore
similarity index 100%
rename from ecosystem/AI-Tooling/beacon/.gitignore
rename to ecosystem/ai-tooling/beacon/.gitignore
diff --git a/ecosystem/AI-Tooling/beacon/.licenserc.yaml b/ecosystem/ai-tooling/beacon/.licenserc.yaml
similarity index 100%
rename from ecosystem/AI-Tooling/beacon/.licenserc.yaml
rename to ecosystem/ai-tooling/beacon/.licenserc.yaml
diff --git a/ecosystem/AI-Tooling/beacon/.npmrc b/ecosystem/ai-tooling/beacon/.npmrc
similarity index 100%
rename from ecosystem/AI-Tooling/beacon/.npmrc
rename to ecosystem/ai-tooling/beacon/.npmrc
diff --git a/ecosystem/AI-Tooling/beacon/.nvmrc b/ecosystem/ai-tooling/beacon/.nvmrc
similarity index 100%
rename from ecosystem/AI-Tooling/beacon/.nvmrc
rename to ecosystem/ai-tooling/beacon/.nvmrc
diff --git a/ecosystem/AI-Tooling/beacon/.prettierignore b/ecosystem/ai-tooling/beacon/.prettierignore
similarity index 100%
rename from ecosystem/AI-Tooling/beacon/.prettierignore
rename to ecosystem/ai-tooling/beacon/.prettierignore
diff --git a/ecosystem/AI-Tooling/beacon/.prettierrc.mjs b/ecosystem/ai-tooling/beacon/.prettierrc.mjs
similarity index 100%
rename from ecosystem/AI-Tooling/beacon/.prettierrc.mjs
rename to ecosystem/ai-tooling/beacon/.prettierrc.mjs
diff --git a/ecosystem/AI-Tooling/beacon/.storybook/main.ts b/ecosystem/ai-tooling/beacon/.storybook/main.ts
similarity index 100%
rename from ecosystem/AI-Tooling/beacon/.storybook/main.ts
rename to ecosystem/ai-tooling/beacon/.storybook/main.ts
diff --git a/ecosystem/AI-Tooling/beacon/.storybook/preview.tsx b/ecosystem/ai-tooling/beacon/.storybook/preview.tsx
similarity index 100%
rename from ecosystem/AI-Tooling/beacon/.storybook/preview.tsx
rename to ecosystem/ai-tooling/beacon/.storybook/preview.tsx
diff --git a/ecosystem/AI-Tooling/beacon/.stylelintignore b/ecosystem/ai-tooling/beacon/.stylelintignore
similarity index 100%
rename from ecosystem/AI-Tooling/beacon/.stylelintignore
rename to ecosystem/ai-tooling/beacon/.stylelintignore
diff --git a/ecosystem/AI-Tooling/beacon/.stylelintrc.json b/ecosystem/ai-tooling/beacon/.stylelintrc.json
similarity index 100%
rename from ecosystem/AI-Tooling/beacon/.stylelintrc.json
rename to ecosystem/ai-tooling/beacon/.stylelintrc.json
diff --git a/ecosystem/AI-Tooling/beacon/CODE_OF_CONDUCT.md b/ecosystem/ai-tooling/beacon/CODE_OF_CONDUCT.md
similarity index 100%
rename from ecosystem/AI-Tooling/beacon/CODE_OF_CONDUCT.md
rename to ecosystem/ai-tooling/beacon/CODE_OF_CONDUCT.md
diff --git a/ecosystem/AI-Tooling/beacon/DISCLAIMER.txt b/ecosystem/ai-tooling/beacon/DISCLAIMER.txt
similarity index 100%
rename from ecosystem/AI-Tooling/beacon/DISCLAIMER.txt
rename to ecosystem/ai-tooling/beacon/DISCLAIMER.txt
diff --git a/ecosystem/AI-Tooling/beacon/LICENSE b/ecosystem/ai-tooling/beacon/LICENSE
similarity index 100%
rename from ecosystem/AI-Tooling/beacon/LICENSE
rename to ecosystem/ai-tooling/beacon/LICENSE
diff --git a/ecosystem/AI-Tooling/beacon/NOTICE b/ecosystem/ai-tooling/beacon/NOTICE
similarity index 100%
rename from ecosystem/AI-Tooling/beacon/NOTICE
rename to ecosystem/ai-tooling/beacon/NOTICE
diff --git a/ecosystem/AI-Tooling/beacon/README.md b/ecosystem/ai-tooling/beacon/README.md
similarity index 100%
rename from ecosystem/AI-Tooling/beacon/README.md
rename to ecosystem/ai-tooling/beacon/README.md
diff --git a/ecosystem/AI-Tooling/beacon/app/_meta.ts b/ecosystem/ai-tooling/beacon/app/_meta.ts
similarity index 100%
rename from ecosystem/AI-Tooling/beacon/app/_meta.ts
rename to ecosystem/ai-tooling/beacon/app/_meta.ts
diff --git a/ecosystem/AI-Tooling/beacon/app/api/ai-search/route.ts b/ecosystem/ai-tooling/beacon/app/api/ai-search/route.ts
similarity index 100%
rename from ecosystem/AI-Tooling/beacon/app/api/ai-search/route.ts
rename to ecosystem/ai-tooling/beacon/app/api/ai-search/route.ts
diff --git a/ecosystem/AI-Tooling/beacon/app/api/chat/route.ts b/ecosystem/ai-tooling/beacon/app/api/chat/route.ts
similarity index 100%
rename from ecosystem/AI-Tooling/beacon/app/api/chat/route.ts
rename to ecosystem/ai-tooling/beacon/app/api/chat/route.ts
diff --git a/ecosystem/AI-Tooling/beacon/app/api/compile/route.ts b/ecosystem/ai-tooling/beacon/app/api/compile/route.ts
similarity index 100%
rename from ecosystem/AI-Tooling/beacon/app/api/compile/route.ts
rename to ecosystem/ai-tooling/beacon/app/api/compile/route.ts
diff --git a/ecosystem/AI-Tooling/beacon/app/api/github-releases/route.ts b/ecosystem/ai-tooling/beacon/app/api/github-releases/route.ts
similarity index 100%
rename from ecosystem/AI-Tooling/beacon/app/api/github-releases/route.ts
rename to ecosystem/ai-tooling/beacon/app/api/github-releases/route.ts
diff --git a/ecosystem/AI-Tooling/beacon/app/docs/[[...mdxPath]]/page.tsx b/ecosystem/ai-tooling/beacon/app/docs/[[...mdxPath]]/page.tsx
similarity index 100%
rename from ecosystem/AI-Tooling/beacon/app/docs/[[...mdxPath]]/page.tsx
rename to ecosystem/ai-tooling/beacon/app/docs/[[...mdxPath]]/page.tsx
diff --git a/ecosystem/AI-Tooling/beacon/app/global.css b/ecosystem/ai-tooling/beacon/app/global.css
similarity index 100%
rename from ecosystem/AI-Tooling/beacon/app/global.css
rename to ecosystem/ai-tooling/beacon/app/global.css
diff --git a/ecosystem/AI-Tooling/beacon/app/layout.tsx b/ecosystem/ai-tooling/beacon/app/layout.tsx
similarity index 100%
rename from ecosystem/AI-Tooling/beacon/app/layout.tsx
rename to ecosystem/ai-tooling/beacon/app/layout.tsx
diff --git a/ecosystem/AI-Tooling/beacon/app/lib/constants.ts b/ecosystem/ai-tooling/beacon/app/lib/constants.ts
similarity index 100%
rename from ecosystem/AI-Tooling/beacon/app/lib/constants.ts
rename to ecosystem/ai-tooling/beacon/app/lib/constants.ts
diff --git a/ecosystem/AI-Tooling/beacon/app/lib/utils.ts b/ecosystem/ai-tooling/beacon/app/lib/utils.ts
similarity index 100%
rename from ecosystem/AI-Tooling/beacon/app/lib/utils.ts
rename to ecosystem/ai-tooling/beacon/app/lib/utils.ts
diff --git a/ecosystem/AI-Tooling/beacon/app/page.module.css b/ecosystem/ai-tooling/beacon/app/page.module.css
similarity index 100%
rename from ecosystem/AI-Tooling/beacon/app/page.module.css
rename to ecosystem/ai-tooling/beacon/app/page.module.css
diff --git a/ecosystem/AI-Tooling/beacon/app/page.tsx b/ecosystem/ai-tooling/beacon/app/page.tsx
similarity index 100%
rename from ecosystem/AI-Tooling/beacon/app/page.tsx
rename to ecosystem/ai-tooling/beacon/app/page.tsx
diff --git a/ecosystem/AI-Tooling/beacon/app/providers.tsx b/ecosystem/ai-tooling/beacon/app/providers.tsx
similarity index 100%
rename from ecosystem/AI-Tooling/beacon/app/providers.tsx
rename to ecosystem/ai-tooling/beacon/app/providers.tsx
diff --git a/ecosystem/AI-Tooling/beacon/app/search/page.tsx b/ecosystem/ai-tooling/beacon/app/search/page.tsx
similarity index 100%
rename from ecosystem/AI-Tooling/beacon/app/search/page.tsx
rename to ecosystem/ai-tooling/beacon/app/search/page.tsx
diff --git a/ecosystem/AI-Tooling/beacon/app/sitemap.ts b/ecosystem/ai-tooling/beacon/app/sitemap.ts
similarity index 100%
rename from ecosystem/AI-Tooling/beacon/app/sitemap.ts
rename to ecosystem/ai-tooling/beacon/app/sitemap.ts
diff --git a/ecosystem/AI-Tooling/beacon/asf.yaml b/ecosystem/ai-tooling/beacon/asf.yaml
similarity index 100%
rename from ecosystem/AI-Tooling/beacon/asf.yaml
rename to ecosystem/ai-tooling/beacon/asf.yaml
diff --git a/ecosystem/AI-Tooling/beacon/components/AskAIModal.tsx b/ecosystem/ai-tooling/beacon/components/AskAIModal.tsx
similarity index 100%
rename from ecosystem/AI-Tooling/beacon/components/AskAIModal.tsx
rename to ecosystem/ai-tooling/beacon/components/AskAIModal.tsx
diff --git a/ecosystem/AI-Tooling/beacon/components/AuthProviders.tsx b/ecosystem/ai-tooling/beacon/components/AuthProviders.tsx
similarity index 100%
rename from ecosystem/AI-Tooling/beacon/components/AuthProviders.tsx
rename to ecosystem/ai-tooling/beacon/components/AuthProviders.tsx
diff --git a/ecosystem/AI-Tooling/beacon/components/ColorSchemeControl/ColorSchemeControl.module.css b/ecosystem/ai-tooling/beacon/components/ColorSchemeControl/ColorSchemeControl.module.css
similarity index 100%
rename from ecosystem/AI-Tooling/beacon/components/ColorSchemeControl/ColorSchemeControl.module.css
rename to ecosystem/ai-tooling/beacon/components/ColorSchemeControl/ColorSchemeControl.module.css
diff --git a/ecosystem/AI-Tooling/beacon/components/ColorSchemeControl/ColorSchemeControl.story.tsx b/ecosystem/ai-tooling/beacon/components/ColorSchemeControl/ColorSchemeControl.story.tsx
similarity index 100%
rename from ecosystem/AI-Tooling/beacon/components/ColorSchemeControl/ColorSchemeControl.story.tsx
rename to ecosystem/ai-tooling/beacon/components/ColorSchemeControl/ColorSchemeControl.story.tsx
diff --git a/ecosystem/AI-Tooling/beacon/components/ColorSchemeControl/ColorSchemeControl.tsx b/ecosystem/ai-tooling/beacon/components/ColorSchemeControl/ColorSchemeControl.tsx
similarity index 100%
rename from ecosystem/AI-Tooling/beacon/components/ColorSchemeControl/ColorSchemeControl.tsx
rename to ecosystem/ai-tooling/beacon/components/ColorSchemeControl/ColorSchemeControl.tsx
diff --git a/ecosystem/AI-Tooling/beacon/components/ColorSchemeControl/HeaderControl.module.css b/ecosystem/ai-tooling/beacon/components/ColorSchemeControl/HeaderControl.module.css
similarity index 100%
rename from ecosystem/AI-Tooling/beacon/components/ColorSchemeControl/HeaderControl.module.css
rename to ecosystem/ai-tooling/beacon/components/ColorSchemeControl/HeaderControl.module.css
diff --git a/ecosystem/AI-Tooling/beacon/components/ColorSchemeControl/HeaderControl.tsx b/ecosystem/ai-tooling/beacon/components/ColorSchemeControl/HeaderControl.tsx
similarity index 100%
rename from ecosystem/AI-Tooling/beacon/components/ColorSchemeControl/HeaderControl.tsx
rename to ecosystem/ai-tooling/beacon/components/ColorSchemeControl/HeaderControl.tsx
diff --git a/ecosystem/AI-Tooling/beacon/components/ColorSchemeToggle/ColorSchemeToggle.tsx b/ecosystem/ai-tooling/beacon/components/ColorSchemeToggle/ColorSchemeToggle.tsx
similarity index 100%
rename from ecosystem/AI-Tooling/beacon/components/ColorSchemeToggle/ColorSchemeToggle.tsx
rename to ecosystem/ai-tooling/beacon/components/ColorSchemeToggle/ColorSchemeToggle.tsx
diff --git a/ecosystem/AI-Tooling/beacon/components/CommentSection.tsx b/ecosystem/ai-tooling/beacon/components/CommentSection.tsx
similarity index 100%
rename from ecosystem/AI-Tooling/beacon/components/CommentSection.tsx
rename to ecosystem/ai-tooling/beacon/components/CommentSection.tsx
diff --git a/ecosystem/AI-Tooling/beacon/components/Content/Content.story.tsx b/ecosystem/ai-tooling/beacon/components/Content/Content.story.tsx
similarity index 100%
rename from ecosystem/AI-Tooling/beacon/components/Content/Content.story.tsx
rename to ecosystem/ai-tooling/beacon/components/Content/Content.story.tsx
diff --git a/ecosystem/AI-Tooling/beacon/components/Content/Content.tsx b/ecosystem/ai-tooling/beacon/components/Content/Content.tsx
similarity index 100%
rename from ecosystem/AI-Tooling/beacon/components/Content/Content.tsx
rename to ecosystem/ai-tooling/beacon/components/Content/Content.tsx
diff --git a/ecosystem/AI-Tooling/beacon/components/FloatingAssistant.tsx b/ecosystem/ai-tooling/beacon/components/FloatingAssistant.tsx
similarity index 100%
rename from ecosystem/AI-Tooling/beacon/components/FloatingAssistant.tsx
rename to ecosystem/ai-tooling/beacon/components/FloatingAssistant.tsx
diff --git a/ecosystem/AI-Tooling/beacon/components/GitHubAuth.tsx b/ecosystem/ai-tooling/beacon/components/GitHubAuth.tsx
similarity index 100%
rename from ecosystem/AI-Tooling/beacon/components/GitHubAuth.tsx
rename to ecosystem/ai-tooling/beacon/components/GitHubAuth.tsx
diff --git a/ecosystem/AI-Tooling/beacon/components/InstallationForm.tsx b/ecosystem/ai-tooling/beacon/components/InstallationForm.tsx
similarity index 100%
rename from ecosystem/AI-Tooling/beacon/components/InstallationForm.tsx
rename to ecosystem/ai-tooling/beacon/components/InstallationForm.tsx
diff --git a/ecosystem/AI-Tooling/beacon/components/Logo/Logo.story.tsx b/ecosystem/ai-tooling/beacon/components/Logo/Logo.story.tsx
similarity index 100%
rename from ecosystem/AI-Tooling/beacon/components/Logo/Logo.story.tsx
rename to ecosystem/ai-tooling/beacon/components/Logo/Logo.story.tsx
diff --git a/ecosystem/AI-Tooling/beacon/components/Logo/Logo.tsx b/ecosystem/ai-tooling/beacon/components/Logo/Logo.tsx
similarity index 100%
rename from ecosystem/AI-Tooling/beacon/components/Logo/Logo.tsx
rename to ecosystem/ai-tooling/beacon/components/Logo/Logo.tsx
diff --git a/ecosystem/AI-Tooling/beacon/components/MantineFooter/MantineFooter.tsx b/ecosystem/ai-tooling/beacon/components/MantineFooter/MantineFooter.tsx
similarity index 100%
rename from ecosystem/AI-Tooling/beacon/components/MantineFooter/MantineFooter.tsx
rename to ecosystem/ai-tooling/beacon/components/MantineFooter/MantineFooter.tsx
diff --git a/ecosystem/AI-Tooling/beacon/components/MantineNavBar/MantineNavBar.tsx b/ecosystem/ai-tooling/beacon/components/MantineNavBar/MantineNavBar.tsx
similarity index 100%
rename from ecosystem/AI-Tooling/beacon/components/MantineNavBar/MantineNavBar.tsx
rename to ecosystem/ai-tooling/beacon/components/MantineNavBar/MantineNavBar.tsx
diff --git a/ecosystem/AI-Tooling/beacon/components/MantineNextraThemeObserver/MantineNextraThemeObserver.tsx b/ecosystem/ai-tooling/beacon/components/MantineNextraThemeObserver/MantineNextraThemeObserver.tsx
similarity index 100%
rename from ecosystem/AI-Tooling/beacon/components/MantineNextraThemeObserver/MantineNextraThemeObserver.tsx
rename to ecosystem/ai-tooling/beacon/components/MantineNextraThemeObserver/MantineNextraThemeObserver.tsx
diff --git a/ecosystem/AI-Tooling/beacon/components/PocketFlowChatbot.tsx b/ecosystem/ai-tooling/beacon/components/PocketFlowChatbot.tsx
similarity index 100%
rename from ecosystem/AI-Tooling/beacon/components/PocketFlowChatbot.tsx
rename to ecosystem/ai-tooling/beacon/components/PocketFlowChatbot.tsx
diff --git a/ecosystem/AI-Tooling/beacon/components/PythonIDE.tsx b/ecosystem/ai-tooling/beacon/components/PythonIDE.tsx
similarity index 100%
rename from ecosystem/AI-Tooling/beacon/components/PythonIDE.tsx
rename to ecosystem/ai-tooling/beacon/components/PythonIDE.tsx
diff --git a/ecosystem/AI-Tooling/beacon/components/PythonPlayground.tsx b/ecosystem/ai-tooling/beacon/components/PythonPlayground.tsx
similarity index 100%
rename from ecosystem/AI-Tooling/beacon/components/PythonPlayground.tsx
rename to ecosystem/ai-tooling/beacon/components/PythonPlayground.tsx
diff --git a/ecosystem/AI-Tooling/beacon/components/ReleaseNotes/ReleaseNotes.tsx b/ecosystem/ai-tooling/beacon/components/ReleaseNotes/ReleaseNotes.tsx
similarity index 100%
rename from ecosystem/AI-Tooling/beacon/components/ReleaseNotes/ReleaseNotes.tsx
rename to ecosystem/ai-tooling/beacon/components/ReleaseNotes/ReleaseNotes.tsx
diff --git a/ecosystem/AI-Tooling/beacon/components/ResContractPlayground.tsx b/ecosystem/ai-tooling/beacon/components/ResContractPlayground.tsx
similarity index 100%
rename from ecosystem/AI-Tooling/beacon/components/ResContractPlayground.tsx
rename to ecosystem/ai-tooling/beacon/components/ResContractPlayground.tsx
diff --git a/ecosystem/AI-Tooling/beacon/components/SearchBar/PagefindSearch.tsx b/ecosystem/ai-tooling/beacon/components/SearchBar/PagefindSearch.tsx
similarity index 100%
rename from ecosystem/AI-Tooling/beacon/components/SearchBar/PagefindSearch.tsx
rename to ecosystem/ai-tooling/beacon/components/SearchBar/PagefindSearch.tsx
diff --git a/ecosystem/AI-Tooling/beacon/components/SearchBar/SearchBar.tsx b/ecosystem/ai-tooling/beacon/components/SearchBar/SearchBar.tsx
similarity index 100%
rename from ecosystem/AI-Tooling/beacon/components/SearchBar/SearchBar.tsx
rename to ecosystem/ai-tooling/beacon/components/SearchBar/SearchBar.tsx
diff --git a/ecosystem/AI-Tooling/beacon/components/TypeScriptPlayground.tsx b/ecosystem/ai-tooling/beacon/components/TypeScriptPlayground.tsx
similarity index 100%
rename from ecosystem/AI-Tooling/beacon/components/TypeScriptPlayground.tsx
rename to ecosystem/ai-tooling/beacon/components/TypeScriptPlayground.tsx
diff --git a/ecosystem/AI-Tooling/beacon/components/Welcome/Welcome.module.css b/ecosystem/ai-tooling/beacon/components/Welcome/Welcome.module.css
similarity index 100%
rename from ecosystem/AI-Tooling/beacon/components/Welcome/Welcome.module.css
rename to ecosystem/ai-tooling/beacon/components/Welcome/Welcome.module.css
diff --git a/ecosystem/AI-Tooling/beacon/components/Welcome/Welcome.story.tsx b/ecosystem/ai-tooling/beacon/components/Welcome/Welcome.story.tsx
similarity index 100%
rename from ecosystem/AI-Tooling/beacon/components/Welcome/Welcome.story.tsx
rename to ecosystem/ai-tooling/beacon/components/Welcome/Welcome.story.tsx
diff --git a/ecosystem/AI-Tooling/beacon/components/Welcome/Welcome.test.tsx b/ecosystem/ai-tooling/beacon/components/Welcome/Welcome.test.tsx
similarity index 100%
rename from ecosystem/AI-Tooling/beacon/components/Welcome/Welcome.test.tsx
rename to ecosystem/ai-tooling/beacon/components/Welcome/Welcome.test.tsx
diff --git a/ecosystem/AI-Tooling/beacon/components/Welcome/Welcome.tsx b/ecosystem/ai-tooling/beacon/components/Welcome/Welcome.tsx
similarity index 100%
rename from ecosystem/AI-Tooling/beacon/components/Welcome/Welcome.tsx
rename to ecosystem/ai-tooling/beacon/components/Welcome/Welcome.tsx
diff --git a/ecosystem/AI-Tooling/beacon/components/cache/NodeConfigGenerator.tsx b/ecosystem/ai-tooling/beacon/components/cache/NodeConfigGenerator.tsx
similarity index 100%
rename from ecosystem/AI-Tooling/beacon/components/cache/NodeConfigGenerator.tsx
rename to ecosystem/ai-tooling/beacon/components/cache/NodeConfigGenerator.tsx
diff --git a/ecosystem/AI-Tooling/beacon/components/cache/NodeQueryBuilder.tsx b/ecosystem/ai-tooling/beacon/components/cache/NodeQueryBuilder.tsx
similarity index 100%
rename from ecosystem/AI-Tooling/beacon/components/cache/NodeQueryBuilder.tsx
rename to ecosystem/ai-tooling/beacon/components/cache/NodeQueryBuilder.tsx
diff --git a/ecosystem/AI-Tooling/beacon/components/cache/PythonConfigGenerator.tsx b/ecosystem/ai-tooling/beacon/components/cache/PythonConfigGenerator.tsx
similarity index 100%
rename from ecosystem/AI-Tooling/beacon/components/cache/PythonConfigGenerator.tsx
rename to ecosystem/ai-tooling/beacon/components/cache/PythonConfigGenerator.tsx
diff --git a/ecosystem/AI-Tooling/beacon/components/cache/PythonQueryBuilder.tsx b/ecosystem/ai-tooling/beacon/components/cache/PythonQueryBuilder.tsx
similarity index 100%
rename from ecosystem/AI-Tooling/beacon/components/cache/PythonQueryBuilder.tsx
rename to ecosystem/ai-tooling/beacon/components/cache/PythonQueryBuilder.tsx
diff --git a/ecosystem/AI-Tooling/beacon/components/index.ts b/ecosystem/ai-tooling/beacon/components/index.ts
similarity index 100%
rename from ecosystem/AI-Tooling/beacon/components/index.ts
rename to ecosystem/ai-tooling/beacon/components/index.ts
diff --git a/ecosystem/AI-Tooling/beacon/components/landing/Header.tsx b/ecosystem/ai-tooling/beacon/components/landing/Header.tsx
similarity index 100%
rename from ecosystem/AI-Tooling/beacon/components/landing/Header.tsx
rename to ecosystem/ai-tooling/beacon/components/landing/Header.tsx
diff --git a/ecosystem/AI-Tooling/beacon/components/landing/HeroContent.tsx b/ecosystem/ai-tooling/beacon/components/landing/HeroContent.tsx
similarity index 100%
rename from ecosystem/AI-Tooling/beacon/components/landing/HeroContent.tsx
rename to ecosystem/ai-tooling/beacon/components/landing/HeroContent.tsx
diff --git a/ecosystem/AI-Tooling/beacon/components/landing/PulsingCircle.tsx b/ecosystem/ai-tooling/beacon/components/landing/PulsingCircle.tsx
similarity index 100%
rename from ecosystem/AI-Tooling/beacon/components/landing/PulsingCircle.tsx
rename to ecosystem/ai-tooling/beacon/components/landing/PulsingCircle.tsx
diff --git a/ecosystem/AI-Tooling/beacon/components/landing/ShaderBackground.tsx b/ecosystem/ai-tooling/beacon/components/landing/ShaderBackground.tsx
similarity index 100%
rename from ecosystem/AI-Tooling/beacon/components/landing/ShaderBackground.tsx
rename to ecosystem/ai-tooling/beacon/components/landing/ShaderBackground.tsx
diff --git a/ecosystem/AI-Tooling/beacon/components/ui/terminal.tsx b/ecosystem/ai-tooling/beacon/components/ui/terminal.tsx
similarity index 100%
rename from ecosystem/AI-Tooling/beacon/components/ui/terminal.tsx
rename to ecosystem/ai-tooling/beacon/components/ui/terminal.tsx
diff --git a/ecosystem/AI-Tooling/beacon/components/utils/loadPyodide.ts b/ecosystem/ai-tooling/beacon/components/utils/loadPyodide.ts
similarity index 100%
rename from ecosystem/AI-Tooling/beacon/components/utils/loadPyodide.ts
rename to ecosystem/ai-tooling/beacon/components/utils/loadPyodide.ts
diff --git a/ecosystem/AI-Tooling/beacon/content/_meta.ts b/ecosystem/ai-tooling/beacon/content/_meta.ts
similarity index 100%
rename from ecosystem/AI-Tooling/beacon/content/_meta.ts
rename to ecosystem/ai-tooling/beacon/content/_meta.ts
diff --git a/ecosystem/AI-Tooling/beacon/content/about.mdx b/ecosystem/ai-tooling/beacon/content/about.mdx
similarity index 100%
rename from ecosystem/AI-Tooling/beacon/content/about.mdx
rename to ecosystem/ai-tooling/beacon/content/about.mdx
diff --git a/ecosystem/AI-Tooling/beacon/content/index.mdx b/ecosystem/ai-tooling/beacon/content/index.mdx
similarity index 100%
rename from ecosystem/AI-Tooling/beacon/content/index.mdx
rename to ecosystem/ai-tooling/beacon/content/index.mdx
diff --git a/ecosystem/AI-Tooling/beacon/content/installation.mdx b/ecosystem/ai-tooling/beacon/content/installation.mdx
similarity index 100%
rename from ecosystem/AI-Tooling/beacon/content/installation.mdx
rename to ecosystem/ai-tooling/beacon/content/installation.mdx
diff --git a/ecosystem/AI-Tooling/beacon/content/pythonsdk.mdx b/ecosystem/ai-tooling/beacon/content/pythonsdk.mdx
similarity index 100%
rename from ecosystem/AI-Tooling/beacon/content/pythonsdk.mdx
rename to ecosystem/ai-tooling/beacon/content/pythonsdk.mdx
diff --git a/ecosystem/AI-Tooling/beacon/content/rescli.mdx b/ecosystem/ai-tooling/beacon/content/rescli.mdx
similarity index 100%
rename from ecosystem/AI-Tooling/beacon/content/rescli.mdx
rename to ecosystem/ai-tooling/beacon/content/rescli.mdx
diff --git a/ecosystem/AI-Tooling/beacon/content/rescontract.mdx b/ecosystem/ai-tooling/beacon/content/rescontract.mdx
similarity index 100%
rename from ecosystem/AI-Tooling/beacon/content/rescontract.mdx
rename to ecosystem/ai-tooling/beacon/content/rescontract.mdx
diff --git a/ecosystem/AI-Tooling/beacon/content/resdb-orm.mdx b/ecosystem/ai-tooling/beacon/content/resdb-orm.mdx
similarity index 100%
rename from ecosystem/AI-Tooling/beacon/content/resdb-orm.mdx
rename to ecosystem/ai-tooling/beacon/content/resdb-orm.mdx
diff --git a/ecosystem/AI-Tooling/beacon/content/resilient-node-cache.mdx b/ecosystem/ai-tooling/beacon/content/resilient-node-cache.mdx
similarity index 100%
rename from ecosystem/AI-Tooling/beacon/content/resilient-node-cache.mdx
rename to ecosystem/ai-tooling/beacon/content/resilient-node-cache.mdx
diff --git a/ecosystem/AI-Tooling/beacon/content/resilient-python-cache.mdx b/ecosystem/ai-tooling/beacon/content/resilient-python-cache.mdx
similarity index 100%
rename from ecosystem/AI-Tooling/beacon/content/resilient-python-cache.mdx
rename to ecosystem/ai-tooling/beacon/content/resilient-python-cache.mdx
diff --git a/ecosystem/AI-Tooling/beacon/content/resilientdb/chapters/01_client_interaction.md b/ecosystem/ai-tooling/beacon/content/resilientdb/chapters/01_client_interaction.md
similarity index 100%
rename from ecosystem/AI-Tooling/beacon/content/resilientdb/chapters/01_client_interaction.md
rename to ecosystem/ai-tooling/beacon/content/resilientdb/chapters/01_client_interaction.md
diff --git a/ecosystem/AI-Tooling/beacon/content/resilientdb/chapters/02_network_communication.md b/ecosystem/ai-tooling/beacon/content/resilientdb/chapters/02_network_communication.md
similarity index 100%
rename from ecosystem/AI-Tooling/beacon/content/resilientdb/chapters/02_network_communication.md
rename to ecosystem/ai-tooling/beacon/content/resilientdb/chapters/02_network_communication.md
diff --git a/ecosystem/AI-Tooling/beacon/content/resilientdb/chapters/03_consensus_management.md b/ecosystem/ai-tooling/beacon/content/resilientdb/chapters/03_consensus_management.md
similarity index 100%
rename from ecosystem/AI-Tooling/beacon/content/resilientdb/chapters/03_consensus_management.md
rename to ecosystem/ai-tooling/beacon/content/resilientdb/chapters/03_consensus_management.md
diff --git a/ecosystem/AI-Tooling/beacon/content/resilientdb/chapters/04_message_transaction_collection.md b/ecosystem/ai-tooling/beacon/content/resilientdb/chapters/04_message_transaction_collection.md
similarity index 100%
rename from ecosystem/AI-Tooling/beacon/content/resilientdb/chapters/04_message_transaction_collection.md
rename to ecosystem/ai-tooling/beacon/content/resilientdb/chapters/04_message_transaction_collection.md
diff --git a/ecosystem/AI-Tooling/beacon/content/resilientdb/chapters/05_transaction_execution.md b/ecosystem/ai-tooling/beacon/content/resilientdb/chapters/05_transaction_execution.md
similarity index 100%
rename from ecosystem/AI-Tooling/beacon/content/resilientdb/chapters/05_transaction_execution.md
rename to ecosystem/ai-tooling/beacon/content/resilientdb/chapters/05_transaction_execution.md
diff --git a/ecosystem/AI-Tooling/beacon/content/resilientdb/chapters/06_storage_layer.md b/ecosystem/ai-tooling/beacon/content/resilientdb/chapters/06_storage_layer.md
similarity index 100%
rename from ecosystem/AI-Tooling/beacon/content/resilientdb/chapters/06_storage_layer.md
rename to ecosystem/ai-tooling/beacon/content/resilientdb/chapters/06_storage_layer.md
diff --git a/ecosystem/AI-Tooling/beacon/content/resilientdb/chapters/07_checkpointing.md b/ecosystem/ai-tooling/beacon/content/resilientdb/chapters/07_checkpointing.md
similarity index 100%
rename from ecosystem/AI-Tooling/beacon/content/resilientdb/chapters/07_checkpointing.md
rename to ecosystem/ai-tooling/beacon/content/resilientdb/chapters/07_checkpointing.md
diff --git a/ecosystem/AI-Tooling/beacon/content/resilientdb/chapters/08_resilientdb_configuration.md b/ecosystem/ai-tooling/beacon/content/resilientdb/chapters/08_resilientdb_configuration.md
similarity index 100%
rename from ecosystem/AI-Tooling/beacon/content/resilientdb/chapters/08_resilientdb_configuration.md
rename to ecosystem/ai-tooling/beacon/content/resilientdb/chapters/08_resilientdb_configuration.md
diff --git a/ecosystem/AI-Tooling/beacon/content/resilientdb/index.mdx b/ecosystem/ai-tooling/beacon/content/resilientdb/index.mdx
similarity index 100%
rename from ecosystem/AI-Tooling/beacon/content/resilientdb/index.mdx
rename to ecosystem/ai-tooling/beacon/content/resilientdb/index.mdx
diff --git a/ecosystem/AI-Tooling/beacon/content/resilientdb_graphql/index.mdx b/ecosystem/ai-tooling/beacon/content/resilientdb_graphql/index.mdx
similarity index 100%
rename from ecosystem/AI-Tooling/beacon/content/resilientdb_graphql/index.mdx
rename to ecosystem/ai-tooling/beacon/content/resilientdb_graphql/index.mdx
diff --git a/ecosystem/AI-Tooling/beacon/content/resilientdb_graphql/setup.mdx b/ecosystem/ai-tooling/beacon/content/resilientdb_graphql/setup.mdx
similarity index 100%
rename from ecosystem/AI-Tooling/beacon/content/resilientdb_graphql/setup.mdx
rename to ecosystem/ai-tooling/beacon/content/resilientdb_graphql/setup.mdx
diff --git a/ecosystem/AI-Tooling/beacon/content/reslens.mdx b/ecosystem/ai-tooling/beacon/content/reslens.mdx
similarity index 100%
rename from ecosystem/AI-Tooling/beacon/content/reslens.mdx
rename to ecosystem/ai-tooling/beacon/content/reslens.mdx
diff --git a/ecosystem/AI-Tooling/beacon/content/resvault.mdx b/ecosystem/ai-tooling/beacon/content/resvault.mdx
similarity index 100%
rename from ecosystem/AI-Tooling/beacon/content/resvault.mdx
rename to ecosystem/ai-tooling/beacon/content/resvault.mdx
diff --git a/ecosystem/AI-Tooling/beacon/eslint.config.mjs b/ecosystem/ai-tooling/beacon/eslint.config.mjs
similarity index 100%
rename from ecosystem/AI-Tooling/beacon/eslint.config.mjs
rename to ecosystem/ai-tooling/beacon/eslint.config.mjs
diff --git a/ecosystem/AI-Tooling/beacon/jest.config.cjs b/ecosystem/ai-tooling/beacon/jest.config.cjs
similarity index 100%
rename from ecosystem/AI-Tooling/beacon/jest.config.cjs
rename to ecosystem/ai-tooling/beacon/jest.config.cjs
diff --git a/ecosystem/AI-Tooling/beacon/jest.setup.cjs b/ecosystem/ai-tooling/beacon/jest.setup.cjs
similarity index 100%
rename from ecosystem/AI-Tooling/beacon/jest.setup.cjs
rename to ecosystem/ai-tooling/beacon/jest.setup.cjs
diff --git a/ecosystem/AI-Tooling/beacon/lib/documentIndexer.ts b/ecosystem/ai-tooling/beacon/lib/documentIndexer.ts
similarity index 100%
rename from ecosystem/AI-Tooling/beacon/lib/documentIndexer.ts
rename to ecosystem/ai-tooling/beacon/lib/documentIndexer.ts
diff --git a/ecosystem/AI-Tooling/beacon/mdx-components.ts b/ecosystem/ai-tooling/beacon/mdx-components.ts
similarity index 100%
rename from ecosystem/AI-Tooling/beacon/mdx-components.ts
rename to ecosystem/ai-tooling/beacon/mdx-components.ts
diff --git a/ecosystem/AI-Tooling/beacon/next-env.d.ts b/ecosystem/ai-tooling/beacon/next-env.d.ts
similarity index 100%
rename from ecosystem/AI-Tooling/beacon/next-env.d.ts
rename to ecosystem/ai-tooling/beacon/next-env.d.ts
diff --git a/ecosystem/AI-Tooling/beacon/next.config.mjs b/ecosystem/ai-tooling/beacon/next.config.mjs
similarity index 100%
rename from ecosystem/AI-Tooling/beacon/next.config.mjs
rename to ecosystem/ai-tooling/beacon/next.config.mjs
diff --git a/ecosystem/AI-Tooling/beacon/package-lock.json b/ecosystem/ai-tooling/beacon/package-lock.json
similarity index 100%
rename from ecosystem/AI-Tooling/beacon/package-lock.json
rename to ecosystem/ai-tooling/beacon/package-lock.json
diff --git a/ecosystem/AI-Tooling/beacon/package.json b/ecosystem/ai-tooling/beacon/package.json
similarity index 100%
rename from ecosystem/AI-Tooling/beacon/package.json
rename to ecosystem/ai-tooling/beacon/package.json
diff --git a/ecosystem/AI-Tooling/beacon/pages/api/auth/[...nextauth].ts b/ecosystem/ai-tooling/beacon/pages/api/auth/[...nextauth].ts
similarity index 100%
rename from ecosystem/AI-Tooling/beacon/pages/api/auth/[...nextauth].ts
rename to ecosystem/ai-tooling/beacon/pages/api/auth/[...nextauth].ts
diff --git a/ecosystem/AI-Tooling/beacon/pages/api/create-github-issue.ts b/ecosystem/ai-tooling/beacon/pages/api/create-github-issue.ts
similarity index 100%
rename from ecosystem/AI-Tooling/beacon/pages/api/create-github-issue.ts
rename to ecosystem/ai-tooling/beacon/pages/api/create-github-issue.ts
diff --git a/ecosystem/AI-Tooling/beacon/pages/auth/_meta.json b/ecosystem/ai-tooling/beacon/pages/auth/_meta.json
similarity index 100%
rename from ecosystem/AI-Tooling/beacon/pages/auth/_meta.json
rename to ecosystem/ai-tooling/beacon/pages/auth/_meta.json
diff --git a/ecosystem/AI-Tooling/beacon/pages/auth/error.tsx b/ecosystem/ai-tooling/beacon/pages/auth/error.tsx
similarity index 100%
rename from ecosystem/AI-Tooling/beacon/pages/auth/error.tsx
rename to ecosystem/ai-tooling/beacon/pages/auth/error.tsx
diff --git a/ecosystem/AI-Tooling/beacon/pages/auth/signin.tsx b/ecosystem/ai-tooling/beacon/pages/auth/signin.tsx
similarity index 100%
rename from ecosystem/AI-Tooling/beacon/pages/auth/signin.tsx
rename to ecosystem/ai-tooling/beacon/pages/auth/signin.tsx
diff --git a/ecosystem/AI-Tooling/beacon/postcss.config.cjs b/ecosystem/ai-tooling/beacon/postcss.config.cjs
similarity index 100%
rename from ecosystem/AI-Tooling/beacon/postcss.config.cjs
rename to ecosystem/ai-tooling/beacon/postcss.config.cjs
diff --git a/ecosystem/AI-Tooling/beacon/public/favicon.svg b/ecosystem/ai-tooling/beacon/public/favicon.svg
similarity index 100%
rename from ecosystem/AI-Tooling/beacon/public/favicon.svg
rename to ecosystem/ai-tooling/beacon/public/favicon.svg
diff --git a/ecosystem/AI-Tooling/beacon/public/lighthouse.png b/ecosystem/ai-tooling/beacon/public/lighthouse.png
similarity index 100%
rename from ecosystem/AI-Tooling/beacon/public/lighthouse.png
rename to ecosystem/ai-tooling/beacon/public/lighthouse.png
diff --git a/ecosystem/AI-Tooling/beacon/public/logo.png b/ecosystem/ai-tooling/beacon/public/logo.png
similarity index 100%
rename from ecosystem/AI-Tooling/beacon/public/logo.png
rename to ecosystem/ai-tooling/beacon/public/logo.png
diff --git a/ecosystem/AI-Tooling/beacon/public/mantine+nextjs+nextra-template.png b/ecosystem/ai-tooling/beacon/public/mantine+nextjs+nextra-template.png
similarity index 100%
rename from ecosystem/AI-Tooling/beacon/public/mantine+nextjs+nextra-template.png
rename to ecosystem/ai-tooling/beacon/public/mantine+nextjs+nextra-template.png
diff --git a/ecosystem/AI-Tooling/beacon/public/resdb_sdk.py b/ecosystem/ai-tooling/beacon/public/resdb_sdk.py
similarity index 100%
rename from ecosystem/AI-Tooling/beacon/public/resdb_sdk.py
rename to ecosystem/ai-tooling/beacon/public/resdb_sdk.py
diff --git a/ecosystem/AI-Tooling/beacon/scripts/build-index.js b/ecosystem/ai-tooling/beacon/scripts/build-index.js
similarity index 100%
rename from ecosystem/AI-Tooling/beacon/scripts/build-index.js
rename to ecosystem/ai-tooling/beacon/scripts/build-index.js
diff --git a/ecosystem/AI-Tooling/beacon/scripts/build-index.ts b/ecosystem/ai-tooling/beacon/scripts/build-index.ts
similarity index 100%
rename from ecosystem/AI-Tooling/beacon/scripts/build-index.ts
rename to ecosystem/ai-tooling/beacon/scripts/build-index.ts
diff --git a/ecosystem/AI-Tooling/beacon/styles/installation.module.css b/ecosystem/ai-tooling/beacon/styles/installation.module.css
similarity index 100%
rename from ecosystem/AI-Tooling/beacon/styles/installation.module.css
rename to ecosystem/ai-tooling/beacon/styles/installation.module.css
diff --git a/ecosystem/AI-Tooling/beacon/test-utils/index.ts b/ecosystem/ai-tooling/beacon/test-utils/index.ts
similarity index 100%
rename from ecosystem/AI-Tooling/beacon/test-utils/index.ts
rename to ecosystem/ai-tooling/beacon/test-utils/index.ts
diff --git a/ecosystem/AI-Tooling/beacon/test-utils/render.tsx b/ecosystem/ai-tooling/beacon/test-utils/render.tsx
similarity index 100%
rename from ecosystem/AI-Tooling/beacon/test-utils/render.tsx
rename to ecosystem/ai-tooling/beacon/test-utils/render.tsx
diff --git a/ecosystem/AI-Tooling/beacon/theme.ts b/ecosystem/ai-tooling/beacon/theme.ts
similarity index 100%
rename from ecosystem/AI-Tooling/beacon/theme.ts
rename to ecosystem/ai-tooling/beacon/theme.ts
diff --git a/ecosystem/AI-Tooling/beacon/tsconfig.json b/ecosystem/ai-tooling/beacon/tsconfig.json
similarity index 100%
rename from ecosystem/AI-Tooling/beacon/tsconfig.json
rename to ecosystem/ai-tooling/beacon/tsconfig.json
diff --git a/ecosystem/AI-Tooling/beacon/types/codemirror__lang-javascript.d.ts b/ecosystem/ai-tooling/beacon/types/codemirror__lang-javascript.d.ts
similarity index 100%
rename from ecosystem/AI-Tooling/beacon/types/codemirror__lang-javascript.d.ts
rename to ecosystem/ai-tooling/beacon/types/codemirror__lang-javascript.d.ts
diff --git a/ecosystem/AI-Tooling/beacon/types/next-auth.d.ts b/ecosystem/ai-tooling/beacon/types/next-auth.d.ts
similarity index 100%
rename from ecosystem/AI-Tooling/beacon/types/next-auth.d.ts
rename to ecosystem/ai-tooling/beacon/types/next-auth.d.ts
diff --git a/ecosystem/AI-Tooling/beacon/types/react-markdown.d.ts b/ecosystem/ai-tooling/beacon/types/react-markdown.d.ts
similarity index 100%
rename from ecosystem/AI-Tooling/beacon/types/react-markdown.d.ts
rename to ecosystem/ai-tooling/beacon/types/react-markdown.d.ts
diff --git a/ecosystem/AI-Tooling/beacon/types/react-syntax-highlighter.d.ts b/ecosystem/ai-tooling/beacon/types/react-syntax-highlighter.d.ts
similarity index 100%
rename from ecosystem/AI-Tooling/beacon/types/react-syntax-highlighter.d.ts
rename to ecosystem/ai-tooling/beacon/types/react-syntax-highlighter.d.ts
diff --git a/ecosystem/AI-Tooling/nexus/.github/pull_request_template.md b/ecosystem/ai-tooling/nexus/.github/pull_request_template.md
similarity index 100%
rename from ecosystem/AI-Tooling/nexus/.github/pull_request_template.md
rename to ecosystem/ai-tooling/nexus/.github/pull_request_template.md
diff --git a/ecosystem/AI-Tooling/nexus/.gitignore b/ecosystem/ai-tooling/nexus/.gitignore
similarity index 100%
rename from ecosystem/AI-Tooling/nexus/.gitignore
rename to ecosystem/ai-tooling/nexus/.gitignore
diff --git a/ecosystem/AI-Tooling/nexus/README.md b/ecosystem/ai-tooling/nexus/README.md
similarity index 100%
rename from ecosystem/AI-Tooling/nexus/README.md
rename to ecosystem/ai-tooling/nexus/README.md
diff --git a/ecosystem/AI-Tooling/nexus/RESEARCH_SETUP.md b/ecosystem/ai-tooling/nexus/RESEARCH_SETUP.md
similarity index 100%
rename from ecosystem/AI-Tooling/nexus/RESEARCH_SETUP.md
rename to ecosystem/ai-tooling/nexus/RESEARCH_SETUP.md
diff --git a/ecosystem/AI-Tooling/nexus/components.json b/ecosystem/ai-tooling/nexus/components.json
similarity index 100%
rename from ecosystem/AI-Tooling/nexus/components.json
rename to ecosystem/ai-tooling/nexus/components.json
diff --git a/ecosystem/AI-Tooling/nexus/docs/DB_SETUP.md b/ecosystem/ai-tooling/nexus/docs/DB_SETUP.md
similarity index 100%
rename from ecosystem/AI-Tooling/nexus/docs/DB_SETUP.md
rename to ecosystem/ai-tooling/nexus/docs/DB_SETUP.md
diff --git a/ecosystem/AI-Tooling/nexus/docs/SYSTEM_ARCHITECTURE.md b/ecosystem/ai-tooling/nexus/docs/SYSTEM_ARCHITECTURE.md
similarity index 100%
rename from ecosystem/AI-Tooling/nexus/docs/SYSTEM_ARCHITECTURE.md
rename to ecosystem/ai-tooling/nexus/docs/SYSTEM_ARCHITECTURE.md
diff --git a/ecosystem/AI-Tooling/nexus/docs/blog.md b/ecosystem/ai-tooling/nexus/docs/blog.md
similarity index 100%
rename from ecosystem/AI-Tooling/nexus/docs/blog.md
rename to ecosystem/ai-tooling/nexus/docs/blog.md
diff --git a/ecosystem/AI-Tooling/nexus/docs/images/agent.png b/ecosystem/ai-tooling/nexus/docs/images/agent.png
similarity index 100%
rename from ecosystem/AI-Tooling/nexus/docs/images/agent.png
rename to ecosystem/ai-tooling/nexus/docs/images/agent.png
diff --git a/ecosystem/AI-Tooling/nexus/docs/images/research.png b/ecosystem/ai-tooling/nexus/docs/images/research.png
similarity index 100%
rename from ecosystem/AI-Tooling/nexus/docs/images/research.png
rename to ecosystem/ai-tooling/nexus/docs/images/research.png
diff --git a/ecosystem/AI-Tooling/nexus/documents/bchain-transaction-pro.pdf b/ecosystem/ai-tooling/nexus/documents/bchain-transaction-pro.pdf
similarity index 100%
rename from ecosystem/AI-Tooling/nexus/documents/bchain-transaction-pro.pdf
rename to ecosystem/ai-tooling/nexus/documents/bchain-transaction-pro.pdf
diff --git a/ecosystem/AI-Tooling/nexus/documents/rcc.pdf b/ecosystem/ai-tooling/nexus/documents/rcc.pdf
similarity index 100%
rename from ecosystem/AI-Tooling/nexus/documents/rcc.pdf
rename to ecosystem/ai-tooling/nexus/documents/rcc.pdf
diff --git a/ecosystem/AI-Tooling/nexus/documents/resilientdb.pdf b/ecosystem/ai-tooling/nexus/documents/resilientdb.pdf
similarity index 100%
rename from ecosystem/AI-Tooling/nexus/documents/resilientdb.pdf
rename to ecosystem/ai-tooling/nexus/documents/resilientdb.pdf
diff --git a/ecosystem/AI-Tooling/nexus/eslint.config.mjs b/ecosystem/ai-tooling/nexus/eslint.config.mjs
similarity index 100%
rename from ecosystem/AI-Tooling/nexus/eslint.config.mjs
rename to ecosystem/ai-tooling/nexus/eslint.config.mjs
diff --git a/ecosystem/AI-Tooling/nexus/next.config.mjs b/ecosystem/ai-tooling/nexus/next.config.mjs
similarity index 100%
rename from ecosystem/AI-Tooling/nexus/next.config.mjs
rename to ecosystem/ai-tooling/nexus/next.config.mjs
diff --git a/ecosystem/AI-Tooling/nexus/next.config.ts b/ecosystem/ai-tooling/nexus/next.config.ts
similarity index 100%
rename from ecosystem/AI-Tooling/nexus/next.config.ts
rename to ecosystem/ai-tooling/nexus/next.config.ts
diff --git a/ecosystem/AI-Tooling/nexus/package-lock.json b/ecosystem/ai-tooling/nexus/package-lock.json
similarity index 100%
rename from ecosystem/AI-Tooling/nexus/package-lock.json
rename to ecosystem/ai-tooling/nexus/package-lock.json
diff --git a/ecosystem/AI-Tooling/nexus/package.json b/ecosystem/ai-tooling/nexus/package.json
similarity index 100%
rename from ecosystem/AI-Tooling/nexus/package.json
rename to ecosystem/ai-tooling/nexus/package.json
diff --git a/ecosystem/AI-Tooling/nexus/postcss.config.mjs b/ecosystem/ai-tooling/nexus/postcss.config.mjs
similarity index 100%
rename from ecosystem/AI-Tooling/nexus/postcss.config.mjs
rename to ecosystem/ai-tooling/nexus/postcss.config.mjs
diff --git a/ecosystem/AI-Tooling/nexus/public/expolab-icon.png b/ecosystem/ai-tooling/nexus/public/expolab-icon.png
similarity index 100%
rename from ecosystem/AI-Tooling/nexus/public/expolab-icon.png
rename to ecosystem/ai-tooling/nexus/public/expolab-icon.png
diff --git a/ecosystem/AI-Tooling/nexus/public/resdb-logo.svg b/ecosystem/ai-tooling/nexus/public/resdb-logo.svg
similarity index 100%
rename from ecosystem/AI-Tooling/nexus/public/resdb-logo.svg
rename to ecosystem/ai-tooling/nexus/public/resdb-logo.svg
diff --git a/ecosystem/AI-Tooling/nexus/public/resilientdb-icon.png b/ecosystem/ai-tooling/nexus/public/resilientdb-icon.png
similarity index 100%
rename from ecosystem/AI-Tooling/nexus/public/resilientdb-icon.png
rename to ecosystem/ai-tooling/nexus/public/resilientdb-icon.png
diff --git a/ecosystem/AI-Tooling/nexus/src/app/api/research/chat/route.ts b/ecosystem/ai-tooling/nexus/src/app/api/research/chat/route.ts
similarity index 100%
rename from ecosystem/AI-Tooling/nexus/src/app/api/research/chat/route.ts
rename to ecosystem/ai-tooling/nexus/src/app/api/research/chat/route.ts
diff --git a/ecosystem/AI-Tooling/nexus/src/app/api/research/documents/route.ts b/ecosystem/ai-tooling/nexus/src/app/api/research/documents/route.ts
similarity index 100%
rename from ecosystem/AI-Tooling/nexus/src/app/api/research/documents/route.ts
rename to ecosystem/ai-tooling/nexus/src/app/api/research/documents/route.ts
diff --git a/ecosystem/AI-Tooling/nexus/src/app/api/research/files/[...path]/route.ts b/ecosystem/ai-tooling/nexus/src/app/api/research/files/[...path]/route.ts
similarity index 100%
rename from ecosystem/AI-Tooling/nexus/src/app/api/research/files/[...path]/route.ts
rename to ecosystem/ai-tooling/nexus/src/app/api/research/files/[...path]/route.ts
diff --git a/ecosystem/AI-Tooling/nexus/src/app/api/research/prepare-index/route.ts b/ecosystem/ai-tooling/nexus/src/app/api/research/prepare-index/route.ts
similarity index 100%
rename from ecosystem/AI-Tooling/nexus/src/app/api/research/prepare-index/route.ts
rename to ecosystem/ai-tooling/nexus/src/app/api/research/prepare-index/route.ts
diff --git a/ecosystem/AI-Tooling/nexus/src/app/favicon.ico b/ecosystem/ai-tooling/nexus/src/app/favicon.ico
similarity index 100%
rename from ecosystem/AI-Tooling/nexus/src/app/favicon.ico
rename to ecosystem/ai-tooling/nexus/src/app/favicon.ico
diff --git a/ecosystem/AI-Tooling/nexus/src/app/globals.css b/ecosystem/ai-tooling/nexus/src/app/globals.css
similarity index 100%
rename from ecosystem/AI-Tooling/nexus/src/app/globals.css
rename to ecosystem/ai-tooling/nexus/src/app/globals.css
diff --git a/ecosystem/AI-Tooling/nexus/src/app/layout.tsx b/ecosystem/ai-tooling/nexus/src/app/layout.tsx
similarity index 100%
rename from ecosystem/AI-Tooling/nexus/src/app/layout.tsx
rename to ecosystem/ai-tooling/nexus/src/app/layout.tsx
diff --git a/ecosystem/AI-Tooling/nexus/src/app/page.tsx b/ecosystem/ai-tooling/nexus/src/app/page.tsx
similarity index 100%
rename from ecosystem/AI-Tooling/nexus/src/app/page.tsx
rename to ecosystem/ai-tooling/nexus/src/app/page.tsx
diff --git a/ecosystem/AI-Tooling/nexus/src/app/research/components/chat-input.tsx b/ecosystem/ai-tooling/nexus/src/app/research/components/chat-input.tsx
similarity index 100%
rename from ecosystem/AI-Tooling/nexus/src/app/research/components/chat-input.tsx
rename to ecosystem/ai-tooling/nexus/src/app/research/components/chat-input.tsx
diff --git a/ecosystem/AI-Tooling/nexus/src/app/research/components/code-generation-tab.tsx b/ecosystem/ai-tooling/nexus/src/app/research/components/code-generation-tab.tsx
similarity index 100%
rename from ecosystem/AI-Tooling/nexus/src/app/research/components/code-generation-tab.tsx
rename to ecosystem/ai-tooling/nexus/src/app/research/components/code-generation-tab.tsx
diff --git a/ecosystem/AI-Tooling/nexus/src/app/research/components/pdf-preview-tab.tsx b/ecosystem/ai-tooling/nexus/src/app/research/components/pdf-preview-tab.tsx
similarity index 100%
rename from ecosystem/AI-Tooling/nexus/src/app/research/components/pdf-preview-tab.tsx
rename to ecosystem/ai-tooling/nexus/src/app/research/components/pdf-preview-tab.tsx
diff --git a/ecosystem/AI-Tooling/nexus/src/app/research/components/preview-panel.tsx b/ecosystem/ai-tooling/nexus/src/app/research/components/preview-panel.tsx
similarity index 100%
rename from ecosystem/AI-Tooling/nexus/src/app/research/components/preview-panel.tsx
rename to ecosystem/ai-tooling/nexus/src/app/research/components/preview-panel.tsx
diff --git a/ecosystem/AI-Tooling/nexus/src/app/research/page.tsx b/ecosystem/ai-tooling/nexus/src/app/research/page.tsx
similarity index 100%
rename from ecosystem/AI-Tooling/nexus/src/app/research/page.tsx
rename to ecosystem/ai-tooling/nexus/src/app/research/page.tsx
diff --git a/ecosystem/AI-Tooling/nexus/src/app/research/types.ts b/ecosystem/ai-tooling/nexus/src/app/research/types.ts
similarity index 100%
rename from ecosystem/AI-Tooling/nexus/src/app/research/types.ts
rename to ecosystem/ai-tooling/nexus/src/app/research/types.ts
diff --git a/ecosystem/AI-Tooling/nexus/src/components/ai-elements/code-block.tsx b/ecosystem/ai-tooling/nexus/src/components/ai-elements/code-block.tsx
similarity index 100%
rename from ecosystem/AI-Tooling/nexus/src/components/ai-elements/code-block.tsx
rename to ecosystem/ai-tooling/nexus/src/components/ai-elements/code-block.tsx
diff --git a/ecosystem/AI-Tooling/nexus/src/components/ai-elements/prompt-input.tsx b/ecosystem/ai-tooling/nexus/src/components/ai-elements/prompt-input.tsx
similarity index 100%
rename from ecosystem/AI-Tooling/nexus/src/components/ai-elements/prompt-input.tsx
rename to ecosystem/ai-tooling/nexus/src/components/ai-elements/prompt-input.tsx
diff --git a/ecosystem/AI-Tooling/nexus/src/components/ai-elements/response.tsx b/ecosystem/ai-tooling/nexus/src/components/ai-elements/response.tsx
similarity index 100%
rename from ecosystem/AI-Tooling/nexus/src/components/ai-elements/response.tsx
rename to ecosystem/ai-tooling/nexus/src/components/ai-elements/response.tsx
diff --git a/ecosystem/AI-Tooling/nexus/src/components/ai-elements/tool.tsx b/ecosystem/ai-tooling/nexus/src/components/ai-elements/tool.tsx
similarity index 100%
rename from ecosystem/AI-Tooling/nexus/src/components/ai-elements/tool.tsx
rename to ecosystem/ai-tooling/nexus/src/components/ai-elements/tool.tsx
diff --git a/ecosystem/AI-Tooling/nexus/src/components/context/ToolContext.tsx b/ecosystem/ai-tooling/nexus/src/components/context/ToolContext.tsx
similarity index 100%
rename from ecosystem/AI-Tooling/nexus/src/components/context/ToolContext.tsx
rename to ecosystem/ai-tooling/nexus/src/components/context/ToolContext.tsx
diff --git a/ecosystem/AI-Tooling/nexus/src/components/providers/QueryProvider.tsx b/ecosystem/ai-tooling/nexus/src/components/providers/QueryProvider.tsx
similarity index 100%
rename from ecosystem/AI-Tooling/nexus/src/components/providers/QueryProvider.tsx
rename to ecosystem/ai-tooling/nexus/src/components/providers/QueryProvider.tsx
diff --git a/ecosystem/AI-Tooling/nexus/src/components/ui/accordion.tsx b/ecosystem/ai-tooling/nexus/src/components/ui/accordion.tsx
similarity index 100%
rename from ecosystem/AI-Tooling/nexus/src/components/ui/accordion.tsx
rename to ecosystem/ai-tooling/nexus/src/components/ui/accordion.tsx
diff --git a/ecosystem/AI-Tooling/nexus/src/components/ui/animated-ai-chat.tsx b/ecosystem/ai-tooling/nexus/src/components/ui/animated-ai-chat.tsx
similarity index 100%
rename from ecosystem/AI-Tooling/nexus/src/components/ui/animated-ai-chat.tsx
rename to ecosystem/ai-tooling/nexus/src/components/ui/animated-ai-chat.tsx
diff --git a/ecosystem/AI-Tooling/nexus/src/components/ui/badge.tsx b/ecosystem/ai-tooling/nexus/src/components/ui/badge.tsx
similarity index 100%
rename from ecosystem/AI-Tooling/nexus/src/components/ui/badge.tsx
rename to ecosystem/ai-tooling/nexus/src/components/ui/badge.tsx
diff --git a/ecosystem/AI-Tooling/nexus/src/components/ui/button.tsx b/ecosystem/ai-tooling/nexus/src/components/ui/button.tsx
similarity index 100%
rename from ecosystem/AI-Tooling/nexus/src/components/ui/button.tsx
rename to ecosystem/ai-tooling/nexus/src/components/ui/button.tsx
diff --git a/ecosystem/AI-Tooling/nexus/src/components/ui/card.tsx b/ecosystem/ai-tooling/nexus/src/components/ui/card.tsx
similarity index 100%
rename from ecosystem/AI-Tooling/nexus/src/components/ui/card.tsx
rename to ecosystem/ai-tooling/nexus/src/components/ui/card.tsx
diff --git a/ecosystem/AI-Tooling/nexus/src/components/ui/citation-badge.tsx b/ecosystem/ai-tooling/nexus/src/components/ui/citation-badge.tsx
similarity index 100%
rename from ecosystem/AI-Tooling/nexus/src/components/ui/citation-badge.tsx
rename to ecosystem/ai-tooling/nexus/src/components/ui/citation-badge.tsx
diff --git a/ecosystem/AI-Tooling/nexus/src/components/ui/collapsible.tsx b/ecosystem/ai-tooling/nexus/src/components/ui/collapsible.tsx
similarity index 100%
rename from ecosystem/AI-Tooling/nexus/src/components/ui/collapsible.tsx
rename to ecosystem/ai-tooling/nexus/src/components/ui/collapsible.tsx
diff --git a/ecosystem/AI-Tooling/nexus/src/components/ui/dialog.tsx b/ecosystem/ai-tooling/nexus/src/components/ui/dialog.tsx
similarity index 100%
rename from ecosystem/AI-Tooling/nexus/src/components/ui/dialog.tsx
rename to ecosystem/ai-tooling/nexus/src/components/ui/dialog.tsx
diff --git a/ecosystem/AI-Tooling/nexus/src/components/ui/document-source-badge.tsx b/ecosystem/ai-tooling/nexus/src/components/ui/document-source-badge.tsx
similarity index 100%
rename from ecosystem/AI-Tooling/nexus/src/components/ui/document-source-badge.tsx
rename to ecosystem/ai-tooling/nexus/src/components/ui/document-source-badge.tsx
diff --git a/ecosystem/AI-Tooling/nexus/src/components/ui/fluid-blob.tsx b/ecosystem/ai-tooling/nexus/src/components/ui/fluid-blob.tsx
similarity index 100%
rename from ecosystem/AI-Tooling/nexus/src/components/ui/fluid-blob.tsx
rename to ecosystem/ai-tooling/nexus/src/components/ui/fluid-blob.tsx
diff --git a/ecosystem/AI-Tooling/nexus/src/components/ui/label.tsx b/ecosystem/ai-tooling/nexus/src/components/ui/label.tsx
similarity index 100%
rename from ecosystem/AI-Tooling/nexus/src/components/ui/label.tsx
rename to ecosystem/ai-tooling/nexus/src/components/ui/label.tsx
diff --git a/ecosystem/AI-Tooling/nexus/src/components/ui/loader.tsx b/ecosystem/ai-tooling/nexus/src/components/ui/loader.tsx
similarity index 100%
rename from ecosystem/AI-Tooling/nexus/src/components/ui/loader.tsx
rename to ecosystem/ai-tooling/nexus/src/components/ui/loader.tsx
diff --git a/ecosystem/AI-Tooling/nexus/src/components/ui/main-navbar.tsx b/ecosystem/ai-tooling/nexus/src/components/ui/main-navbar.tsx
similarity index 100%
rename from ecosystem/AI-Tooling/nexus/src/components/ui/main-navbar.tsx
rename to ecosystem/ai-tooling/nexus/src/components/ui/main-navbar.tsx
diff --git a/ecosystem/AI-Tooling/nexus/src/components/ui/multi-document-selector.tsx b/ecosystem/ai-tooling/nexus/src/components/ui/multi-document-selector.tsx
similarity index 100%
rename from ecosystem/AI-Tooling/nexus/src/components/ui/multi-document-selector.tsx
rename to ecosystem/ai-tooling/nexus/src/components/ui/multi-document-selector.tsx
diff --git a/ecosystem/AI-Tooling/nexus/src/components/ui/popover.tsx b/ecosystem/ai-tooling/nexus/src/components/ui/popover.tsx
similarity index 100%
rename from ecosystem/AI-Tooling/nexus/src/components/ui/popover.tsx
rename to ecosystem/ai-tooling/nexus/src/components/ui/popover.tsx
diff --git a/ecosystem/AI-Tooling/nexus/src/components/ui/resizable.tsx b/ecosystem/ai-tooling/nexus/src/components/ui/resizable.tsx
similarity index 100%
rename from ecosystem/AI-Tooling/nexus/src/components/ui/resizable.tsx
rename to ecosystem/ai-tooling/nexus/src/components/ui/resizable.tsx
diff --git a/ecosystem/AI-Tooling/nexus/src/components/ui/scroll-area.tsx b/ecosystem/ai-tooling/nexus/src/components/ui/scroll-area.tsx
similarity index 100%
rename from ecosystem/AI-Tooling/nexus/src/components/ui/scroll-area.tsx
rename to ecosystem/ai-tooling/nexus/src/components/ui/scroll-area.tsx
diff --git a/ecosystem/AI-Tooling/nexus/src/components/ui/select.tsx b/ecosystem/ai-tooling/nexus/src/components/ui/select.tsx
similarity index 100%
rename from ecosystem/AI-Tooling/nexus/src/components/ui/select.tsx
rename to ecosystem/ai-tooling/nexus/src/components/ui/select.tsx
diff --git a/ecosystem/AI-Tooling/nexus/src/components/ui/separator.tsx b/ecosystem/ai-tooling/nexus/src/components/ui/separator.tsx
similarity index 100%
rename from ecosystem/AI-Tooling/nexus/src/components/ui/separator.tsx
rename to ecosystem/ai-tooling/nexus/src/components/ui/separator.tsx
diff --git a/ecosystem/AI-Tooling/nexus/src/components/ui/sheet.tsx b/ecosystem/ai-tooling/nexus/src/components/ui/sheet.tsx
similarity index 100%
rename from ecosystem/AI-Tooling/nexus/src/components/ui/sheet.tsx
rename to ecosystem/ai-tooling/nexus/src/components/ui/sheet.tsx
diff --git a/ecosystem/AI-Tooling/nexus/src/components/ui/switch.tsx b/ecosystem/ai-tooling/nexus/src/components/ui/switch.tsx
similarity index 100%
rename from ecosystem/AI-Tooling/nexus/src/components/ui/switch.tsx
rename to ecosystem/ai-tooling/nexus/src/components/ui/switch.tsx
diff --git a/ecosystem/AI-Tooling/nexus/src/components/ui/tabs.tsx b/ecosystem/ai-tooling/nexus/src/components/ui/tabs.tsx
similarity index 100%
rename from ecosystem/AI-Tooling/nexus/src/components/ui/tabs.tsx
rename to ecosystem/ai-tooling/nexus/src/components/ui/tabs.tsx
diff --git a/ecosystem/AI-Tooling/nexus/src/components/ui/textarea.tsx b/ecosystem/ai-tooling/nexus/src/components/ui/textarea.tsx
similarity index 100%
rename from ecosystem/AI-Tooling/nexus/src/components/ui/textarea.tsx
rename to ecosystem/ai-tooling/nexus/src/components/ui/textarea.tsx
diff --git a/ecosystem/AI-Tooling/nexus/src/components/ui/tooltip.tsx b/ecosystem/ai-tooling/nexus/src/components/ui/tooltip.tsx
similarity index 100%
rename from ecosystem/AI-Tooling/nexus/src/components/ui/tooltip.tsx
rename to ecosystem/ai-tooling/nexus/src/components/ui/tooltip.tsx
diff --git a/ecosystem/AI-Tooling/nexus/src/config/environment.ts b/ecosystem/ai-tooling/nexus/src/config/environment.ts
similarity index 100%
rename from ecosystem/AI-Tooling/nexus/src/config/environment.ts
rename to ecosystem/ai-tooling/nexus/src/config/environment.ts
diff --git a/ecosystem/AI-Tooling/nexus/src/hooks/useDocuments.ts b/ecosystem/ai-tooling/nexus/src/hooks/useDocuments.ts
similarity index 100%
rename from ecosystem/AI-Tooling/nexus/src/hooks/useDocuments.ts
rename to ecosystem/ai-tooling/nexus/src/hooks/useDocuments.ts
diff --git a/ecosystem/AI-Tooling/nexus/src/lib/agent.ts b/ecosystem/ai-tooling/nexus/src/lib/agent.ts
similarity index 100%
rename from ecosystem/AI-Tooling/nexus/src/lib/agent.ts
rename to ecosystem/ai-tooling/nexus/src/lib/agent.ts
diff --git a/ecosystem/AI-Tooling/nexus/src/lib/code-composer-agent.ts b/ecosystem/ai-tooling/nexus/src/lib/code-composer-agent.ts
similarity index 100%
rename from ecosystem/AI-Tooling/nexus/src/lib/code-composer-agent.ts
rename to ecosystem/ai-tooling/nexus/src/lib/code-composer-agent.ts
diff --git a/ecosystem/AI-Tooling/nexus/src/lib/config/llama-settings.ts b/ecosystem/ai-tooling/nexus/src/lib/config/llama-settings.ts
similarity index 100%
rename from ecosystem/AI-Tooling/nexus/src/lib/config/llama-settings.ts
rename to ecosystem/ai-tooling/nexus/src/lib/config/llama-settings.ts
diff --git a/ecosystem/AI-Tooling/nexus/src/lib/constants.ts b/ecosystem/ai-tooling/nexus/src/lib/constants.ts
similarity index 100%
rename from ecosystem/AI-Tooling/nexus/src/lib/constants.ts
rename to ecosystem/ai-tooling/nexus/src/lib/constants.ts
diff --git a/ecosystem/AI-Tooling/nexus/src/lib/google-drive.ts b/ecosystem/ai-tooling/nexus/src/lib/google-drive.ts
similarity index 100%
rename from ecosystem/AI-Tooling/nexus/src/lib/google-drive.ts
rename to ecosystem/ai-tooling/nexus/src/lib/google-drive.ts
diff --git a/ecosystem/AI-Tooling/nexus/src/lib/llama-service.ts b/ecosystem/ai-tooling/nexus/src/lib/llama-service.ts
similarity index 100%
rename from ecosystem/AI-Tooling/nexus/src/lib/llama-service.ts
rename to ecosystem/ai-tooling/nexus/src/lib/llama-service.ts
diff --git a/ecosystem/AI-Tooling/nexus/src/lib/robust-fact-memory.ts b/ecosystem/ai-tooling/nexus/src/lib/robust-fact-memory.ts
similarity index 100%
rename from ecosystem/AI-Tooling/nexus/src/lib/robust-fact-memory.ts
rename to ecosystem/ai-tooling/nexus/src/lib/robust-fact-memory.ts
diff --git a/ecosystem/AI-Tooling/nexus/src/lib/token-estimator.ts b/ecosystem/ai-tooling/nexus/src/lib/token-estimator.ts
similarity index 100%
rename from ecosystem/AI-Tooling/nexus/src/lib/token-estimator.ts
rename to ecosystem/ai-tooling/nexus/src/lib/token-estimator.ts
diff --git a/ecosystem/AI-Tooling/nexus/src/lib/utils.ts b/ecosystem/ai-tooling/nexus/src/lib/utils.ts
similarity index 100%
rename from ecosystem/AI-Tooling/nexus/src/lib/utils.ts
rename to ecosystem/ai-tooling/nexus/src/lib/utils.ts
diff --git a/ecosystem/AI-Tooling/nexus/src/tests/test-router.ts b/ecosystem/ai-tooling/nexus/src/tests/test-router.ts
similarity index 100%
rename from ecosystem/AI-Tooling/nexus/src/tests/test-router.ts
rename to ecosystem/ai-tooling/nexus/src/tests/test-router.ts
diff --git a/ecosystem/AI-Tooling/nexus/tsconfig.json b/ecosystem/ai-tooling/nexus/tsconfig.json
similarity index 100%
rename from ecosystem/AI-Tooling/nexus/tsconfig.json
rename to ecosystem/ai-tooling/nexus/tsconfig.json


(incubator-resilientdb) 05/06: Implement transaction retrieval with sequence number, integrate LevelDB for summary storage, and update server configuration settings.

Posted by ha...@apache.org.
This is an automated email from the ASF dual-hosted git repository.

harishgokul01 pushed a commit to branch demo
in repository https://gitbox.apache.org/repos/asf/incubator-resilientdb.git

commit 6fb02357e6934bf411156fd90a98bb7eed19d733
Author: harish876 <ha...@gmail.com>
AuthorDate: Wed Dec 31 02:08:22 2025 +0000

    Implement transaction retrieval with sequence number, integrate LevelDB for summary storage, and update server configuration settings.
---
 .../graphql/service/http_server/crow_service.cpp   |  28 ++
 .../graphql/service/kv_service/resdb_kv_client.cpp |  15 ++
 .../graphql/service/kv_service/resdb_kv_client.h   |  11 +-
 executor/kv/kv_executor.cpp                        |   1 +
 .../consensus/execution/transaction_executor.cpp   |   2 +-
 platform/consensus/ordering/pbft/commitment.cpp    |   2 +-
 .../ordering/pbft/viewchange_manager_test.cpp      |   1 -
 platform/statistic/BUILD                           |   5 +
 platform/statistic/stats.cpp                       | 283 +++++++++++++++------
 platform/statistic/stats.h                         |   9 +-
 service/kv/kv_service.cpp                          |   2 +-
 service/tools/config/server/server.config          |   8 +-
 12 files changed, 283 insertions(+), 84 deletions(-)

diff --git a/ecosystem/graphql/service/http_server/crow_service.cpp b/ecosystem/graphql/service/http_server/crow_service.cpp
index 03c738c8..c27f44f8 100644
--- a/ecosystem/graphql/service/http_server/crow_service.cpp
+++ b/ecosystem/graphql/service/http_server/crow_service.cpp
@@ -128,6 +128,34 @@ void CrowService::run() {
     }
   });
 
+  // Get value with sequence number of specific id
+  CROW_ROUTE(app, "/v2/transactions/<string>")
+  ([this](const crow::request &req, response &res, std::string id) {
+    auto result = kv_client_.GetWithSeq(id);
+    if (result != nullptr) {
+      LOG(INFO) << "client get value with seq = " << result->second
+                << ", seq = " << result->first;
+
+      // Send updated blocks list to websocket
+      if (users.size() > 0) {
+        for (auto u : users) u->send_text("Update blocks");
+      }
+
+      num_transactions_++;
+
+      crow::json::wvalue resp;
+      resp["value"] = result->second;
+      resp["seq"] = result->first;
+
+      res.set_header("Content-Type", "application/json");
+      res.end(resp.dump());
+    } else {
+      res.code = 500;
+      res.set_header("Content-Type", "text/plain");
+      res.end("get value with seq fail");
+    }
+  });
+
   // Get values based on key range
   CROW_ROUTE(app, "/v1/transactions/<string>/<string>")
   ([this](const crow::request &req, response &res, std::string min_id,
diff --git a/ecosystem/graphql/service/kv_service/resdb_kv_client.cpp b/ecosystem/graphql/service/kv_service/resdb_kv_client.cpp
index 2273cf98..0baab27c 100644
--- a/ecosystem/graphql/service/kv_service/resdb_kv_client.cpp
+++ b/ecosystem/graphql/service/kv_service/resdb_kv_client.cpp
@@ -64,6 +64,21 @@ std::unique_ptr<std::string> ResDBKVClient::Get(const std::string &key) {
   return std::make_unique<std::string>(response.value());
 }
 
+std::unique_ptr<std::pair<int64_t, std::string>> ResDBKVClient::GetWithSeq(
+    const std::string &key) {
+  KVRequest request;
+  request.set_cmd(KVRequest::GET);
+  request.set_key(key);
+  KVResponse response;
+  int ret = SendRequest(request, &response);
+  if (ret != 0) {
+    LOG(ERROR) << "send request fail, ret:" << ret;
+    return nullptr;
+  }
+  return std::make_unique<std::pair<int64_t, std::string>>(
+      response.seq(), response.value());
+}
+
 std::unique_ptr<std::string> ResDBKVClient::GetAllValues() {
   KVRequest request;
   request.set_cmd(KVRequest::GETALLVALUES);
diff --git a/ecosystem/graphql/service/kv_service/resdb_kv_client.h b/ecosystem/graphql/service/kv_service/resdb_kv_client.h
index ac35afc0..20249b62 100644
--- a/ecosystem/graphql/service/kv_service/resdb_kv_client.h
+++ b/ecosystem/graphql/service/kv_service/resdb_kv_client.h
@@ -19,21 +19,28 @@
 
 #pragma once
 
+#include <cstdint>
+#include <memory>
+#include <string>
+#include <utility>
+
 #include "interface/rdbc/transaction_constructor.h"
 
 namespace sdk {
 
 // ResDBKVClient to send data to the kv server.
 class ResDBKVClient : public resdb::TransactionConstructor {
-public:
+ public:
   ResDBKVClient(const resdb::ResDBConfig &config);
 
   int Set(const std::string &key, const std::string &data);
   int64_t SetWithSeq(const std::string &key, const std::string &data);
+  std::unique_ptr<std::pair<int64_t, std::string>> GetWithSeq(
+      const std::string &key);
   std::unique_ptr<std::string> Get(const std::string &key);
   std::unique_ptr<std::string> GetAllValues();
   std::unique_ptr<std::string> GetRange(const std::string &min_key,
                                         const std::string &max_key);
 };
 
-} // namespace sdk
+}  // namespace sdk
diff --git a/executor/kv/kv_executor.cpp b/executor/kv/kv_executor.cpp
index f6fe8b86..78ed5710 100644
--- a/executor/kv/kv_executor.cpp
+++ b/executor/kv/kv_executor.cpp
@@ -61,6 +61,7 @@ std::unique_ptr<std::string> KVExecutor::ExecuteRequest(
     kv_response.set_seq(kv_request.seq());
   } else if (kv_request.cmd() == KVRequest::GET) {
     kv_response.set_value(Get(kv_request.key()));
+    kv_response.set_seq(kv_request.seq());
   } else if (kv_request.cmd() == KVRequest::GETALLVALUES) {
     kv_response.set_value(GetAllValues());
   } else if (kv_request.cmd() == KVRequest::GETRANGE) {
diff --git a/platform/consensus/execution/transaction_executor.cpp b/platform/consensus/execution/transaction_executor.cpp
index 12f4b49a..f70be048 100644
--- a/platform/consensus/execution/transaction_executor.cpp
+++ b/platform/consensus/execution/transaction_executor.cpp
@@ -335,7 +335,7 @@ void TransactionExecutor::Execute(std::unique_ptr<Request> request,
   response->set_seq(request->seq());
 
   if (post_exec_func_) {
-    post_exec_func_(std::move(request), std::move(response)); //TODO: request_tracking
+    post_exec_func_(std::move(request), std::move(response));
   }
 
   global_stats_->IncExecuteDone();
diff --git a/platform/consensus/ordering/pbft/commitment.cpp b/platform/consensus/ordering/pbft/commitment.cpp
index 4a1aacc0..d75038aa 100644
--- a/platform/consensus/ordering/pbft/commitment.cpp
+++ b/platform/consensus/ordering/pbft/commitment.cpp
@@ -296,7 +296,7 @@ int Commitment::ProcessCommitMsg(std::unique_ptr<Context> context,
       message_manager_->AddConsensusMsg(context->signature, std::move(request));
   if (ret == CollectorResultCode::STATE_CHANGED) {
     // LOG(ERROR)<<request->data().size();
-    // global_stats_->GetTransactionDetails(request->data());
+    //global_stats_->GetTransactionDetails(request->data());
     global_stats_->RecordStateTime("commit");
   }
   return ret == CollectorResultCode::INVALID ? -2 : 0;
diff --git a/platform/consensus/ordering/pbft/viewchange_manager_test.cpp b/platform/consensus/ordering/pbft/viewchange_manager_test.cpp
index 43b87541..1803dd0b 100644
--- a/platform/consensus/ordering/pbft/viewchange_manager_test.cpp
+++ b/platform/consensus/ordering/pbft/viewchange_manager_test.cpp
@@ -89,7 +89,6 @@ TEST_F(ViewChangeManagerTest, SendViewChange) {
   request->set_hash(SignatureVerifier::CalculateHash("test_data"));
   checkpoint_manager_->AddCommitData(std::move(request));
   
-  // Wait a bit for the request to be processed (last_seq_ to be updated)
   std::this_thread::sleep_for(std::chrono::milliseconds(100));
   
   std::promise<bool> propose_done;
diff --git a/platform/statistic/BUILD b/platform/statistic/BUILD
index 3094840b..4c0f32bf 100644
--- a/platform/statistic/BUILD
+++ b/platform/statistic/BUILD
@@ -26,6 +26,10 @@ cc_library(
     name = "stats",
     srcs = ["stats.cpp"],
     hdrs = ["stats.h"],
+    copts = select({
+        "//chain/storage/setting:enable_leveldb_setting": ["-DENABLE_LEVELDB"],
+        "//conditions:default": [],
+    }),
     deps = [
         ":prometheus_handler",
         "//common:asio",
@@ -38,6 +42,7 @@ cc_library(
         "//proto/kv:kv_cc_proto",
         "//third_party:crow",
         "//third_party:prometheus",
+        "//third_party:leveldb",
     ],
 )
 
diff --git a/platform/statistic/stats.cpp b/platform/statistic/stats.cpp
index 2d6099c4..0afb219a 100644
--- a/platform/statistic/stats.cpp
+++ b/platform/statistic/stats.cpp
@@ -22,8 +22,12 @@
 #include <glog/logging.h>
 
 #include <ctime>
+#include <sstream>
 
 #include "common/utils/utils.h"
+#include "leveldb/db.h"
+#include "leveldb/options.h"
+#include "leveldb/write_batch.h"
 #include "proto/kv/kv.pb.h"
 
 namespace asio = boost::asio;
@@ -124,22 +128,88 @@ void Stats::CrowRoute() {
   crow::SimpleApp app;
   while (!stop_) {
     try {
+      //Deprecated
       CROW_ROUTE(app, "/consensus_data")
-          .methods("GET"_method)([this](const crow::request& req,
-                                        crow::response& res) {
-            LOG(ERROR) << "API 1";
-            res.set_header("Access-Control-Allow-Origin",
-                           "*");  // Allow requests from any origin
-            res.set_header("Access-Control-Allow-Methods",
-                           "GET, POST, OPTIONS");  // Specify allowed methods
-            res.set_header(
-                "Access-Control-Allow-Headers",
-                "Content-Type, Authorization");  // Specify allowed headers
-
-            // Send your response
-            res.body = consensus_history_.dump();
-            res.end();
-          });
+          .methods("GET"_method)(
+              [this](const crow::request& req, crow::response& res) {
+                LOG(ERROR) << "API 1";
+                res.set_header("Access-Control-Allow-Origin", "*");
+                res.set_header("Access-Control-Allow-Methods",
+                               "GET, POST, OPTIONS");
+                res.set_header("Access-Control-Allow-Headers",
+                               "Content-Type, Authorization");
+
+                int limit = 10; 
+                int page = 1;
+                
+                std::string url = req.url;
+                size_t query_pos = url.find('?');
+                if (query_pos != std::string::npos) {
+                  std::string query_string = url.substr(query_pos + 1);
+                  std::istringstream iss(query_string);
+                  std::string param;
+                  while (std::getline(iss, param, '&')) {
+                    size_t eq_pos = param.find('=');
+                    if (eq_pos != std::string::npos) {
+                      std::string key = param.substr(0, eq_pos);
+                      std::string value = param.substr(eq_pos + 1);
+                      if (key == "limit") {
+                        try {
+                          limit = std::stoi(value);
+                          if (limit <= 0) limit = 10;
+                        } catch (...) {
+                          limit = 10;
+                        }
+                      } else if (key == "page") {
+                        try {
+                          page = std::stoi(value);
+                          if (page <= 0) page = 1;
+                        } catch (...) {
+                          page = 1;
+                        }
+                      }
+                    }
+                  }
+                }
+
+                nlohmann::json result;
+                int total_count = 0;
+                int offset = (page - 1) * limit;
+                int current_index = 0;
+                int items_collected = 0;
+
+                if (summary_db_) {
+                  std::lock_guard<std::mutex> lock(summary_db_mutex_);
+                  leveldb::Iterator* it =
+                      summary_db_->NewIterator(leveldb::ReadOptions());
+                  
+                  for (it->SeekToFirst(); it->Valid(); it->Next()) {
+                    total_count++;
+                  }
+                  
+                  for (it->SeekToFirst(); it->Valid(); it->Next()) {
+                    if (current_index >= offset && items_collected < limit) {
+                      try {
+                        result[it->key().ToString()] =
+                            nlohmann::json::parse(it->value().ToString());
+                        items_collected++;
+                      } catch (...) {
+                        res.code = 500;
+                        result["error"] = "Failed to parse transaction data";
+                        delete it;
+                        res.body = result.dump();
+                        res.end();
+                        return;
+                      }
+                    }
+                    current_index++;
+                  }
+                  delete it;
+                }
+
+                res.body = result.dump();
+                res.end();
+              });
       CROW_ROUTE(app, "/get_status")
           .methods("GET"_method)([this](const crow::request& req,
                                         crow::response& res) {
@@ -167,7 +237,7 @@ void Stats::CrowRoute() {
             res.set_header(
                 "Access-Control-Allow-Headers",
                 "Content-Type, Authorization");  // Specify allowed headers
-            
+
             res.body = "Not Enabled";
             // Send your response
             if (enable_faulty_switch_) {
@@ -211,6 +281,46 @@ void Stats::CrowRoute() {
             mem_view_json.clear();
             res.end();
           });
+      CROW_ROUTE(app, "/consensus_data/<int>")
+          .methods("GET"_method)([this](const crow::request& req,
+                                        crow::response& res, int txn_number) {
+            LOG(ERROR) << "API 5: Get transaction " << txn_number;
+            res.set_header("Access-Control-Allow-Origin",
+                           "*");  // Allow requests from any origin
+            res.set_header("Access-Control-Allow-Methods",
+                           "GET, POST, OPTIONS");  // Specify allowed methods
+            res.set_header(
+                "Access-Control-Allow-Headers",
+                "Content-Type, Authorization");  // Specify allowed headers
+
+            nlohmann::json result;
+            if (summary_db_) {
+              std::lock_guard<std::mutex> lock(summary_db_mutex_);
+              std::string txn_key = std::to_string(txn_number);
+              std::string value;
+              leveldb::Status status =
+                  summary_db_->Get(leveldb::ReadOptions(), txn_key, &value);
+
+              if (status.ok() && !value.empty()) {
+                try {
+                  result[txn_key] = nlohmann::json::parse(value);
+                } catch (...) {
+                  res.code = 500;
+                  result["error"] = "Failed to parse transaction data";
+                }
+              } else {
+                res.code = 404;
+                result["error"] = "Transaction not found";
+                result["txn_number"] = txn_number;
+              }
+            } else {
+              res.code = 503;
+              result["error"] = "Storage not initialized";
+            }
+
+            res.body = result.dump();
+            res.end();
+          });
       app.port(8500 + transaction_summary_.port).multithreaded().run();
       sleep(1);
     } catch (const std::exception& e) {
@@ -234,6 +344,19 @@ void Stats::SetProps(int replica_id, std::string ip, int port,
   enable_resview = resview_flag;
   enable_faulty_switch_ = faulty_flag;
   if (resview_flag) {
+    std::string storage_path = "/tmp/resdb_summaries_" + std::to_string(port);
+    leveldb::Options options;
+    options.create_if_missing = true;
+    leveldb::DB* db = nullptr;
+    leveldb::Status status = leveldb::DB::Open(options, storage_path, &db);
+    if (status.ok()) {
+      summary_db_.reset(db);
+      LOG(INFO) << "Initialized LevelDB storage for summaries at: "
+                << storage_path;
+    } else {
+      LOG(ERROR) << "Failed to open LevelDB at " << storage_path << ": "
+                 << status.ToString();
+    }
     crow_thread_ = std::thread(&Stats::CrowRoute, this);
   }
 }
@@ -345,8 +468,18 @@ void Stats::SendSummary() {
 
   summary_json_["ext_cache_hit_ratio"] =
       transaction_summary_.ext_cache_hit_ratio_;
-  consensus_history_[std::to_string(transaction_summary_.txn_number)] =
-      summary_json_;
+
+  std::string txn_key = std::to_string(transaction_summary_.txn_number);
+
+  if (summary_db_) {
+    std::lock_guard<std::mutex> lock(summary_db_mutex_);
+    leveldb::Status status = summary_db_->Put(leveldb::WriteOptions(), txn_key,
+                                              summary_json_.dump());
+    if (!status.ok()) {
+      LOG(ERROR) << "Failed to write summary to storage for txn: " << txn_key
+                 << ": " << status.ToString();
+    }
+  }
 
   LOG(ERROR) << summary_json_.dump();
 
@@ -423,59 +556,59 @@ void Stats::MonitorGlobal() {
     run_req_run_time = run_req_run_time_;
 
     LOG(INFO) << "=========== monitor =========\n"
-               << "server call:" << server_call - last_server_call
-               << " server process:" << server_process - last_server_process
-               << " socket recv:" << socket_recv - last_socket_recv
-               << " "
-                  "client call:"
-               << client_call - last_client_call
-               << " "
-                  "client req:"
-               << num_client_req - last_num_client_req
-               << " "
-                  "broad_cast:"
-               << broad_cast_msg - last_broad_cast_msg
-               << " "
-                  "send broad_cast:"
-               << send_broad_cast_msg - last_send_broad_cast_msg
-               << " "
-                  "per send broad_cast:"
-               << send_broad_cast_msg_per_rep - last_send_broad_cast_msg_per_rep
-               << " "
-                  "propose:"
-               << num_propose - last_num_propose
-               << " "
-                  "prepare:"
-               << (num_prepare - last_num_prepare)
-               << " "
-                  "commit:"
-               << (num_commit - last_num_commit)
-               << " "
-                  "pending execute:"
-               << pending_execute - last_pending_execute
-               << " "
-                  "execute:"
-               << execute - last_execute
-               << " "
-                  "execute done:"
-               << execute_done - last_execute_done << " seq gap:" << seq_gap
-               << " total request:" << total_request - last_total_request
-               << " txn:" << (total_request - last_total_request) / 5
-               << " total geo request:"
-               << total_geo_request - last_total_geo_request
-               << " total geo request per:"
-               << (total_geo_request - last_total_geo_request) / 5
-               << " geo request:" << (geo_request - last_geo_request)
-               << " "
-                  "seq fail:"
-               << seq_fail - last_seq_fail << " time:" << time
-               << " "
-                  "\n--------------- monitor ------------";
+              << "server call:" << server_call - last_server_call
+              << " server process:" << server_process - last_server_process
+              << " socket recv:" << socket_recv - last_socket_recv
+              << " "
+                 "client call:"
+              << client_call - last_client_call
+              << " "
+                 "client req:"
+              << num_client_req - last_num_client_req
+              << " "
+                 "broad_cast:"
+              << broad_cast_msg - last_broad_cast_msg
+              << " "
+                 "send broad_cast:"
+              << send_broad_cast_msg - last_send_broad_cast_msg
+              << " "
+                 "per send broad_cast:"
+              << send_broad_cast_msg_per_rep - last_send_broad_cast_msg_per_rep
+              << " "
+                 "propose:"
+              << num_propose - last_num_propose
+              << " "
+                 "prepare:"
+              << (num_prepare - last_num_prepare)
+              << " "
+                 "commit:"
+              << (num_commit - last_num_commit)
+              << " "
+                 "pending execute:"
+              << pending_execute - last_pending_execute
+              << " "
+                 "execute:"
+              << execute - last_execute
+              << " "
+                 "execute done:"
+              << execute_done - last_execute_done << " seq gap:" << seq_gap
+              << " total request:" << total_request - last_total_request
+              << " txn:" << (total_request - last_total_request) / 5
+              << " total geo request:"
+              << total_geo_request - last_total_geo_request
+              << " total geo request per:"
+              << (total_geo_request - last_total_geo_request) / 5
+              << " geo request:" << (geo_request - last_geo_request)
+              << " "
+                 "seq fail:"
+              << seq_fail - last_seq_fail << " time:" << time
+              << " "
+                 "\n--------------- monitor ------------";
     if (run_req_num - last_run_req_num > 0) {
       LOG(INFO) << "  req client latency:"
-                 << static_cast<double>(run_req_run_time -
-                                        last_run_req_run_time) /
-                        (run_req_num - last_run_req_num) / 1000000000.0;
+                << static_cast<double>(run_req_run_time -
+                                       last_run_req_run_time) /
+                       (run_req_num - last_run_req_num) / 1000000000.0;
     }
 
     last_seq_fail = seq_fail;
@@ -530,8 +663,10 @@ void Stats::IncPrepare() {
     prometheus_->Inc(PREPARE, 1);
   }
   num_prepare_++;
-  transaction_summary_.prepare_message_count_times_list.push_back(
-      std::chrono::system_clock::now());
+  if (enable_resview) {
+    transaction_summary_.prepare_message_count_times_list.push_back(
+        std::chrono::system_clock::now());
+  }
 }
 
 void Stats::IncCommit() {
@@ -539,8 +674,10 @@ void Stats::IncCommit() {
     prometheus_->Inc(COMMIT, 1);
   }
   num_commit_++;
-  transaction_summary_.commit_message_count_times_list.push_back(
-      std::chrono::system_clock::now());
+  if (enable_resview) {
+    transaction_summary_.commit_message_count_times_list.push_back(
+        std::chrono::system_clock::now());
+  }
 }
 
 void Stats::IncPendingExecute() { pending_execute_++; }
diff --git a/platform/statistic/stats.h b/platform/statistic/stats.h
index 849c83d1..0d86bb3e 100644
--- a/platform/statistic/stats.h
+++ b/platform/statistic/stats.h
@@ -33,6 +33,11 @@
 #include "proto/kv/kv.pb.h"
 #include "sys/resource.h"
 
+// Forward declaration for LevelDB
+namespace leveldb {
+class DB;
+}
+
 namespace asio = boost::asio;
 namespace beast = boost::beast;
 using tcp = asio::ip::tcp;
@@ -159,9 +164,11 @@ class Stats {
   std::atomic<uint64_t> prev_num_prepare_;
   std::atomic<uint64_t> prev_num_commit_;
   nlohmann::json summary_json_;
-  nlohmann::json consensus_history_;
 
   std::unique_ptr<PrometheusHandler> prometheus_;
+  
+  std::unique_ptr<leveldb::DB> summary_db_;
+  std::mutex summary_db_mutex_;
 };
 
 }  // namespace resdb
diff --git a/service/kv/kv_service.cpp b/service/kv/kv_service.cpp
index 269fb807..07b15462 100644
--- a/service/kv/kv_service.cpp
+++ b/service/kv/kv_service.cpp
@@ -51,7 +51,7 @@ int main(int argc, char** argv) {
     exit(0);
   }
   google::InitGoogleLogging(argv[0]);
-  FLAGS_minloglevel = 1;
+  FLAGS_minloglevel = 0;
 
   char* config_file = argv[1];
   char* private_key_file = argv[2];
diff --git a/service/tools/config/server/server.config b/service/tools/config/server/server.config
index 61c66f04..68cbee87 100644
--- a/service/tools/config/server/server.config
+++ b/service/tools/config/server/server.config
@@ -48,9 +48,9 @@
   },
   require_txn_validation:true,
   enable_resview:true,
-  enable_faulty_switch:true,
-  "enable_viewchange":true,
-  "recovery_enabled":true,
-  "max_client_complaint_num":10
+  enable_faulty_switch:false,
+  enable_viewchange:false,
+  recovery_enabled:true,
+  max_client_complaint_num:10
 }