diff --git a/alib2cli/CMakeLists.txt b/alib2cli/CMakeLists.txt
index 4ba76f3ec04e274d196a6e376f5e781066de9970..5107a503523d59451cc47f2ab23dc33af6e08239 100644
--- a/alib2cli/CMakeLists.txt
+++ b/alib2cli/CMakeLists.txt
@@ -40,7 +40,7 @@ set_source_files_properties(
 		GENERATED TRUE
 		COMPILE_OPTIONS "-w")
 
-target_include_directories(alib2cli PRIVATE ${ANTLR4_INCLUDE_DIR_AltCliGrammarLexer} ${ANTLR4_INCLUDE_DIR_AltCliGrammarParser})
+target_include_directories(alib2cli PUBLIC ${ANTLR4_INCLUDE_DIR_AltCliGrammarLexer} ${ANTLR4_INCLUDE_DIR_AltCliGrammarParser})
 target_include_directories(alib2cli SYSTEM PUBLIC ${ANTLR4_INCLUDE_DIR})
 target_link_libraries(alib2cli INTERFACE antlr4_shared)
 
diff --git a/alib2cli/src/environment/Environment.cpp b/alib2cli/src/environment/Environment.cpp
index d241adaa154553eb8e9f9bb2733b449d0f549206..d40d5c1f7942e3450f7dadae51757d235ff1faeb 100644
--- a/alib2cli/src/environment/Environment.cpp
+++ b/alib2cli/src/environment/Environment.cpp
@@ -77,4 +77,19 @@ Environment& Environment::getGlobalScope()
     return m_upper->getGlobalScope();
 }
 
+cli::CommandResult Environment::execute(const std::unique_ptr<cli::Command>& ast)
+{
+    try {
+        cli::CommandResult res = ast->run(*this);
+
+        if (res == CommandResult::CONTINUE || res == CommandResult::BREAK)
+            throw std::logic_error("There is no loop to continue/break.");
+
+        return res;
+    } catch (...) {
+        alib::ExceptionHandler::handle(common::Streams::err);
+        return cli::CommandResult::EXCEPTION;
+    }
+}
+
 } /* namespace cli */
diff --git a/alib2cli/src/environment/Environment.h b/alib2cli/src/environment/Environment.h
index b4b7eb5014daa460c9236673f1922733efa05c78..0e2d90af5c87738a01eecd473cd77d6192547653 100644
--- a/alib2cli/src/environment/Environment.h
+++ b/alib2cli/src/environment/Environment.h
@@ -120,6 +120,7 @@ public:
     }
 
     cli::CommandResult execute(const std::shared_ptr<cli::LineInterface>& lineInterface);
+    cli::CommandResult execute(const std::unique_ptr<cli::Command>& ast);
 
     cli::CommandResult execute_line(cli::CharSequence charSequence);
 
diff --git a/alib2cli/src/parser/Parser2.cpp b/alib2cli/src/parser/Parser2.cpp
index e3b3985844985dfc683fc073dadc69953da10814..6da9503d831ae9d69b7f2dc1defc4aa2bb592955 100644
--- a/alib2cli/src/parser/Parser2.cpp
+++ b/alib2cli/src/parser/Parser2.cpp
@@ -28,10 +28,11 @@ std::unique_ptr<CommandList> Parser2::parse(antlr4::CharStream& stream)
     auto listener = std::make_shared<cli::grammar::BufferedErrorListener>();
 
     AltCliLexer lexer(&stream);
-
+    lexer.removeErrorListeners();
     lexer.addErrorListener(listener.get());
     antlr4::CommonTokenStream tokenStream(&lexer);
     AltCliParser parser(&tokenStream);
+    parser.removeErrorListeners();
     parser.addErrorListener(listener.get());
 
     parser.setErrorHandler(std::make_shared<antlr4::DefaultErrorStrategy>());
diff --git a/aql2/CMakeLists.txt b/aql2/CMakeLists.txt
index 5a25be108974154b1282b59b3dce6d6161233380..d6929a3d542b817bfcec13c500145033d83e629f 100644
--- a/aql2/CMakeLists.txt
+++ b/aql2/CMakeLists.txt
@@ -1,13 +1,14 @@
 project(alt-aql VERSION ${CMAKE_PROJECT_VERSION})
 
 find_package(LibXml2 REQUIRED)
+find_package(replxx REQUIRED)
 find_package(PkgConfig)
 
 pkg_check_modules(TCLAP REQUIRED IMPORTED_TARGET tclap>=1.2.5)
 pkg_check_modules(READLINE REQUIRED IMPORTED_TARGET readline>=8.0)
 
 alt_executable(aql2
-	DEPENDS alib2elgo alib2graph_algo alib2algo alib2aux alib2raw_cli_integration alib2raw alib2str_cli_integration alib2str alib2graph_data alib2data alib2cli alib2xml alib2common alib2abstraction alib2measure alib2std LibXml2::LibXml2 PkgConfig::READLINE PkgConfig::TCLAP
+	DEPENDS alib2elgo alib2graph_algo alib2algo alib2aux alib2raw_cli_integration alib2raw alib2str_cli_integration alib2str alib2graph_data alib2data alib2cli alib2xml alib2common alib2abstraction alib2measure alib2std LibXml2::LibXml2 PkgConfig::READLINE PkgConfig::TCLAP replxx
 )
 
 # stdlib
diff --git a/aql2/src/REPL.cpp b/aql2/src/REPL.cpp
new file mode 100644
index 0000000000000000000000000000000000000000..61b91485af9d2fc4d21725d99551f086bf8412b7
--- /dev/null
+++ b/aql2/src/REPL.cpp
@@ -0,0 +1,123 @@
+#include <AltCliLexer.h>
+#include <functional>
+#include <grammar/Autocomplete.h>
+#include <parser/Parser2.h>
+#include <replxx.hxx>
+#include "REPL.h"
+
+using namespace replxx;
+using namespace replxx::helper;
+
+cli::CommandResult REPL::run(cli::Environment& env)
+{
+    using cl = Replxx::Color;
+    syntax_highlight_t regex_color{
+        // numbers
+        {"[\\-|+]{0,1}[0-9]+", cl::BLUE}, // integers
+        {"[\\-|+]{0,1}[0-9]*\\.[0-9]+", cl::BLUE}, // decimals
+        {"[\\-|+]{0,1}[0-9]+e[\\-|+]{0,1}[0-9]+", cl::BLUE}, // scientific notation
+
+        // strings
+        {"\"(.|\n)*?\"", cl::YELLOW}, // double quotes
+    };
+
+    Replxx rx;
+    // set the max history size
+    rx.set_max_history_size(128);
+    // set the max number of hint rows to show
+    rx.set_max_hint_rows(3);
+    rx.set_word_break_characters(" \n\t.,-%!;:=*~^'\"/?<>|[](){}");
+    rx.set_completion_count_cutoff(128);
+    rx.set_double_tab_completion(false);
+    rx.set_complete_on_empty(true);
+    rx.set_beep_on_ambiguous_completion(false);
+    rx.set_no_color(false);
+    rx.set_indent_multiline(true);
+
+    rx.set_highlighter_callback([regex_color, this](std::string const& context, replxx::Replxx::colors_t& colors) {
+        return hook_color(context, colors, regex_color, this->m_tokens);
+    });
+    std::vector<std::string> lines;
+
+    rx.bind_key(Replxx::KEY::ENTER, [&](char32_t) {
+        std::string input{rx.get_state().text()};
+        if (input.empty()) {
+            return rx.invoke(replxx::Replxx::ACTION::COMMIT_LINE, Replxx::KEY::ENTER);
+        }
+        try {
+            cli::Parser2::parseString(input);
+        } catch (const std::exception&) {
+            return rx.invoke(Replxx::ACTION::NEW_LINE, Replxx::KEY::ENTER);
+        }
+
+        return rx.invoke(replxx::Replxx::ACTION::COMMIT_LINE, Replxx::KEY::ENTER);
+    });
+
+    cli::Autocomplete complete;
+
+    rx.set_completion_callback([&complete](const std::string&, int&) {
+        Replxx::completions_t completions;
+
+        return completions;
+    });
+
+    std::string prompt = "aql> ";
+
+
+    // display the prompt and retrieve input from the user
+    char const* cInput;
+    while (true) {
+        do {
+            cInput = rx.input(prompt);
+        } while ((cInput == nullptr) && (errno == EAGAIN));
+
+        if (cInput == nullptr) {
+            break;
+        }
+
+        // change cInput into a std::string
+        // easier to manipulate
+        std::string input{cInput};
+        if (input.empty()) {
+            continue;
+        }
+
+        std::unique_ptr<cli::Command> ast = cli::Parser2::parseString(input);
+        env.execute(ast);
+
+
+        rx.history_add(input);
+    }
+    return cli::CommandResult::OK;
+}
+
+REPL::REPL()
+{
+    antlr4::ANTLRInputStream inputStream{""};
+    cli::grammar::lexer::AltCliLexer const lexer{&inputStream};
+
+    const auto& vocabulary = lexer.getVocabulary();
+
+    const auto tokensCount = vocabulary.getMaxTokenType();
+
+    for (size_t i = 0; i < tokensCount; ++i) {
+        auto token = vocabulary.getDisplayName(i);
+
+        if (token == vocabulary.getSymbolicName(i)) {
+            continue;
+        }
+
+        if (token[0] == '\'' && token[token.size() - 1] == '\'') {
+            token = token.substr(1, token.size() - 2);
+        }
+
+        const bool isKeyword = std::all_of(token.cbegin(), token.cend(), [](char c) {
+            return isalpha(c);
+        });
+
+        if (isKeyword)
+            m_tokens.emplace(token, replxx::Replxx::Color::BRIGHTBLUE);
+        else
+            m_tokens.emplace(token, replxx::Replxx::Color::GREEN);
+    }
+}
diff --git a/aql2/src/REPL.h b/aql2/src/REPL.h
new file mode 100644
index 0000000000000000000000000000000000000000..32c9cd3b47fd031420e04f217134051f44b46702
--- /dev/null
+++ b/aql2/src/REPL.h
@@ -0,0 +1,27 @@
+#pragma once
+
+#include <string>
+#include <vector>
+
+#include <environment/Environment.h>
+#include <replxx.hxx>
+
+class REPL {
+    std::unordered_map<std::string, replxx::Replxx::Color> m_tokens;
+public:
+    REPL();
+
+    cli::CommandResult run(cli::Environment& environment);
+};
+
+namespace replxx::helper {
+    int utf8str_codepoint_len(char const *s, int utf8len);
+    int context_len(char const *prefix);
+
+    typedef std::vector<std::pair<std::string, Replxx::Color>> syntax_highlight_t;
+    typedef std::unordered_map<std::string, Replxx::Color> keyword_highlight_t;
+
+
+    void hook_color(std::string const &context, replxx::Replxx::colors_t &colors,
+                    syntax_highlight_t const &regex_color, keyword_highlight_t const &word_color);
+}
\ No newline at end of file
diff --git a/aql2/src/REPL.replxx.cpp b/aql2/src/REPL.replxx.cpp
new file mode 100644
index 0000000000000000000000000000000000000000..c98bfad92cb9848463ed73a4cf00aef8f92fdb1e
--- /dev/null
+++ b/aql2/src/REPL.replxx.cpp
@@ -0,0 +1,132 @@
+#include "REPL.h"
+
+#include <cstring>
+#include <functional>
+#include <regex>
+
+using namespace replxx;
+
+namespace replxx::helper {
+
+int utf8str_codepoint_len(char const* s, int utf8len)
+{
+    int codepointLen = 0;
+    unsigned char m4 = 128 + 64 + 32 + 16;
+    unsigned char m3 = 128 + 64 + 32;
+    unsigned char m2 = 128 + 64;
+    for (int i = 0; i < utf8len; ++i, ++codepointLen) {
+        char c = s[i];
+        if ((c & m4) == m4) {
+            i += 3;
+        } else if ((c & m3) == m3) {
+            i += 2;
+        } else if ((c & m2) == m2) {
+            i += 1;
+        }
+    }
+    return (codepointLen);
+}
+
+int context_len(char const* prefix)
+{
+    auto wb = " \t\n\r\v\f-=+*&^%$#@!,./?<>;:`~'\"[]{}()\\|";
+    int i = static_cast<int>(strlen(prefix) - 1);
+    int cl = 0;
+    while (i >= 0) {
+        if (strchr(wb, prefix[i]) != NULL) {
+            break;
+        }
+        ++cl;
+        --i;
+    }
+    return (cl);
+}
+
+inline bool is_kw(char ch)
+{
+    return isalnum(ch) || (ch == '_');
+}
+
+void hook_color(std::string const& context, replxx::Replxx::colors_t& colors, syntax_highlight_t const& regex_color, keyword_highlight_t const& word_color)
+{
+
+    bool inWord(false);
+    int wordStart(0);
+    int wordEnd(0);
+    int colorOffset(0);
+    auto dohl = [&](int i) {
+        inWord = false;
+        std::string intermission(context.substr(wordEnd, wordStart - wordEnd));
+        colorOffset += utf8str_codepoint_len(intermission.c_str(), intermission.length());
+        int wordLen(i - wordStart);
+        std::string keyword(context.substr(wordStart, wordLen));
+        bool bold(false);
+        if (keyword.substr(0, 5) == "bold_") {
+            keyword = keyword.substr(5);
+            bold = true;
+        }
+        bool underline(false);
+        if (keyword.substr(0, 10) == "underline_") {
+            keyword = keyword.substr(10);
+            underline = true;
+        }
+        keyword_highlight_t::const_iterator it(word_color.find(keyword));
+        Replxx::Color color = Replxx::Color::DEFAULT;
+        if (it != word_color.end()) {
+            color = it->second;
+        }
+        if (bold) {
+            color = replxx::color::bold(color);
+        }
+        if (underline) {
+            color = replxx::color::underline(color);
+        }
+        for (int k(0); k < wordLen; ++k) {
+            Replxx::Color& c(colors.at(colorOffset + k));
+            if (color != Replxx::Color::DEFAULT) {
+                c = color;
+            }
+        }
+        colorOffset += wordLen;
+        wordEnd = i;
+    };
+    for (int i(0); i < static_cast<int>(context.length()); ++i) {
+        if (!inWord) {
+            if (is_kw(context[i])) {
+                inWord = true;
+                wordStart = i;
+            }
+        } else if (inWord && !is_kw(context[i])) {
+            dohl(i);
+        }
+        if ((context[i] != '_') && ispunct(context[i])) {
+            wordStart = i;
+            dohl(i + 1);
+        }
+    }
+    if (inWord) {
+        dohl(context.length());
+    }
+
+    // highlight matching regex sequences
+    for (auto const& e : regex_color) {
+        size_t pos{0};
+        std::string str = context;
+        std::smatch match;
+
+        while (std::regex_search(str, match, std::regex(e.first))) {
+            std::string c{match[0]};
+            std::string prefix(match.prefix().str());
+            pos += utf8str_codepoint_len(prefix.c_str(), static_cast<int>(prefix.length()));
+            int len(utf8str_codepoint_len(c.c_str(), static_cast<int>(c.length())));
+
+            for (int i = 0; i < len; ++i) {
+                colors.at(pos + i) = e.second;
+            }
+
+            pos += len;
+            str = match.suffix();
+        }
+    }
+}
+}