diff --git a/.vscode/launch.json b/.vscode/launch.json
index a12ffb326dad1b2f113bf70239d67f6ddd1c4195..4c467e7af97849455887aad9be0005103afc24fa 100644
--- a/.vscode/launch.json
+++ b/.vscode/launch.json
@@ -291,6 +291,32 @@
             "visualizerFile": "${env:LRS_PKG_ROOT}/src/qt-natvis/qt5.natvis.xml",
             "showDisplayString": true
         },
+        {
+            "name": "TestEngine (kDB::SMQuery) (gdb)",
+            "type": "cppdbg",
+            "request": "launch",
+            "program": "${env:LRS_PKG_ROOT}/host-build-debug/kDB/kDB/SMQuery/tests/TestEngine",
+            "args": [],
+            "stopAtEntry": false,
+            "cwd": "${env:LRS_PKG_ROOT}",
+            "environment": [],
+            "externalConsole": false,
+            "MIMode": "gdb",
+            "setupCommands": [
+                {
+                    "description": "Enable pretty-printing for gdb",
+                    "text": "-enable-pretty-printing",
+                    "ignoreFailures": true
+                },
+                {
+                    "description": "Set Disassembly Flavor to Intel",
+                    "text": "-gdb-set disassembly-flavor intel",
+                    "ignoreFailures": true
+                }
+            ],
+            "visualizerFile": "${env:LRS_PKG_ROOT}/src/qt-natvis/qt5.natvis.xml",
+            "showDisplayString": true
+        },
         
     ]
 }
diff --git a/docs/doxygen/pages/kDBSMQuery.dox b/docs/doxygen/pages/kDBSMQuery.dox
new file mode 100644
index 0000000000000000000000000000000000000000..b5c5821209b47be76a98fc45bb40e95113875ab7
--- /dev/null
+++ b/docs/doxygen/pages/kDBSMQuery.dox
@@ -0,0 +1,19 @@
+/**
+\page kDB_SMQuery kDB::SMQuery Library
+\defgroup kDB_SMQuery
+
+kDB::SMQuery is a kDB library which allows to execute Simple Management Query.
+
+The idea is for the engine to be able to execute query of the form
+
+@code
+SOME KEY name1: value1 name2: value2 ... 
+@endcode
+
+For instance:
+
+@code
+CREATE DATASETS uri: <uri_of_dataset>
+@endcode
+
+*/
\ No newline at end of file
diff --git a/docs/doxygen/pages/mainpage.dox b/docs/doxygen/pages/mainpage.dox
index 49d3b8f792beae90153fe53a25c7f62fe0a41ebb..09e4d0e158bdcb6cc7b2e8c564c55a9ae6177d7f 100644
--- a/docs/doxygen/pages/mainpage.dox
+++ b/docs/doxygen/pages/mainpage.dox
@@ -1,7 +1,12 @@
 /**
 \mainpage kDB: Knowledge DataBase
 \section kdb_overview General overview
+
+\section kDB_core Core Libraries
+ - \ref kDB_SMQuery Simple Management Query
+
 \section kdb_extensions Extensions
+ - \ref kDBDatasets extension to manage datasets
  - \ref kDBQueries extension to handle query templates in C++/Python
 
  */
diff --git a/kDB/CMakeLists.txt b/kDB/CMakeLists.txt
index df5f029158eff0ba18d2b00007b74a85f143b79b..178d975f52983a8feeb5e543b54c96e21f5a05a7 100644
--- a/kDB/CMakeLists.txt
+++ b/kDB/CMakeLists.txt
@@ -1,6 +1,7 @@
 add_subdirectory(RDFDB)
 add_subdirectory(Repository)
 add_subdirectory(RDFView)
+add_subdirectory(SMQuery)
 add_subdirectory(SPARQL)
 add_subdirectory(Utils)
 
diff --git a/kDB/Forward.h b/kDB/Forward.h
index bd61d9b6a54bfd83753e2b616e263e294f817a19..11d1216984ed8960573891dd51e6e72b69231e46 100644
--- a/kDB/Forward.h
+++ b/kDB/Forward.h
@@ -69,4 +69,12 @@ namespace kDB
   {
     class Database;
   }
+  namespace SMQuery
+  {
+    class Engine;
+    namespace Interfaces
+    {
+      class Action;
+    }
+  }
 }
diff --git a/kDB/SMQuery/CMakeLists.txt b/kDB/SMQuery/CMakeLists.txt
new file mode 100644
index 0000000000000000000000000000000000000000..33c98b59ff7a7fd7ce49151439d790816da694f8
--- /dev/null
+++ b/kDB/SMQuery/CMakeLists.txt
@@ -0,0 +1,24 @@
+add_subdirectory(tests)
+
+# Create library
+
+set(KDBSMQUERY_SRCS
+  Engine.cpp
+  Parser.cpp
+  Interfaces/Interfaces.cpp
+  )
+
+add_library(kDBSMQuery SHARED ${KDBSMQUERY_SRCS})
+target_link_libraries(kDBSMQuery PUBLIC knowCore )
+
+# Install
+install(TARGETS kDBSMQuery EXPORT kDBTargets ${INSTALL_TARGETS_DEFAULT_ARGS} )
+set(PROJECT_EXPORTED_TARGETS kDBSMQuery  ${PROJECT_EXPORTED_TARGETS} CACHE INTERNAL "")
+
+install( FILES
+  Engine.h
+  DESTINATION ${INSTALL_INCLUDE_DIR}/kDBSMQuery )
+
+  install( FILES
+  Interfaces/Action.h
+  DESTINATION ${INSTALL_INCLUDE_DIR}/kDBSMQuery/Interfaces )
diff --git a/kDB/SMQuery/Engine.cpp b/kDB/SMQuery/Engine.cpp
new file mode 100644
index 0000000000000000000000000000000000000000..8a9230921a3b36cf19d14e0b200372bf792fa98d
--- /dev/null
+++ b/kDB/SMQuery/Engine.cpp
@@ -0,0 +1,46 @@
+#include "Engine.h"
+
+#include <QHash>
+
+#include "Parser.h"
+#include "Interfaces/Action.h"
+
+using namespace kDB::SMQuery;
+
+struct Engine::Private
+{
+  QHash<QString, Interfaces::Action*> key2action;
+  QList<Interfaces::Action*> actions;
+};
+
+Engine::Engine() : d(new Private)
+{
+
+}
+
+Engine::~Engine()
+{
+  qDeleteAll(d->actions);
+  delete d;
+}
+
+void Engine::add(const QStringList& _keys, Interfaces::Action* _action)
+{
+  d->actions.append(_action);
+  for(const QString& key : _keys)
+  {
+    d->key2action[key.toUpper()] = _action;
+  }
+}
+
+knowCore::ReturnVoid Engine::execute(const QString& _text)
+{
+  KNOWCORE_RETURN_VALUE_TRY(query, Parser::parse(_text));
+  QString key = query.key.join(" ").toUpper();
+  if(d->key2action.contains(key))
+  {
+    return d->key2action.value(key)->execute(key, query.parameters);
+  } else {
+    return kCrvError("No action for '{}'", key);
+  }
+}
diff --git a/kDB/SMQuery/Engine.h b/kDB/SMQuery/Engine.h
new file mode 100644
index 0000000000000000000000000000000000000000..86c390e2070c51126905d4c3457bf331edff1229
--- /dev/null
+++ b/kDB/SMQuery/Engine.h
@@ -0,0 +1,31 @@
+#include <QStringList>
+
+#include <kDB/Forward.h>
+
+namespace kDB::SMQuery
+{
+  /**
+   * @ingroup kDB_SMQuery
+   * 
+   * Execution engine for Simple Management Query
+   */
+  class Engine
+  {
+  public:
+    Engine();
+    ~Engine();
+    /**
+     * Add an \ref _action for the list of \ref _keys.
+     * 
+     * _keys take the form of "SOME ACTION" and will react to query with "SOME ACTION".
+     */
+    void add(const QStringList& _keys, Interfaces::Action* _action);
+    /**
+     * Execute a query.
+     */
+    knowCore::ReturnVoid execute(const QString& _text);
+  private:
+    struct Private;
+    Private* const d;
+  };
+}
\ No newline at end of file
diff --git a/kDB/SMQuery/Forward.h b/kDB/SMQuery/Forward.h
new file mode 100644
index 0000000000000000000000000000000000000000..e69de29bb2d1d6434b8b29ae775ad8c2e48c5391
diff --git a/kDB/SMQuery/Interfaces/Action.h b/kDB/SMQuery/Interfaces/Action.h
new file mode 100644
index 0000000000000000000000000000000000000000..e5ca21a1779f4f9f88189dfa304b166b0dbc0dbc
--- /dev/null
+++ b/kDB/SMQuery/Interfaces/Action.h
@@ -0,0 +1,19 @@
+#include <knowCore/Forward.h>
+
+namespace kDB::SMQuery::Interfaces
+{
+  /**
+   * @ingroup kDB_SMQuery
+   * 
+   * Define an action to be executed by the SMQuery engine
+   */
+  class Action
+  {
+  public:
+    virtual ~Action();
+    /**
+     * Execute the action with the given \ref _key and \ref _parameters
+     */
+    virtual knowCore::ReturnVoid execute(const QString& _key, const knowCore::ValueHash& _parameters) = 0;
+  };
+}
diff --git a/kDB/SMQuery/Interfaces/Interfaces.cpp b/kDB/SMQuery/Interfaces/Interfaces.cpp
new file mode 100644
index 0000000000000000000000000000000000000000..c5f1cfda7091cb418c9673fa371c915e213a5b85
--- /dev/null
+++ b/kDB/SMQuery/Interfaces/Interfaces.cpp
@@ -0,0 +1,6 @@
+#include "Action.h"
+
+using namespace kDB::SMQuery::Interfaces;
+
+Action::~Action()
+{}
diff --git a/kDB/SMQuery/Parser.cpp b/kDB/SMQuery/Parser.cpp
new file mode 100644
index 0000000000000000000000000000000000000000..cdc698254b372b3b432a3f58eb3583f8873a946e
--- /dev/null
+++ b/kDB/SMQuery/Parser.cpp
@@ -0,0 +1,167 @@
+#include "Parser.h"
+
+#include <knowCore/BigNumber.h>
+#include <knowCore/LexerTextStream.h>
+
+using namespace kDB::SMQuery;
+
+struct Parser::Private
+{
+  struct Token
+  {
+    enum class Type {
+      END_OF_FILE,
+      IDENTIFIER,
+      COLON,
+      VALUE
+    };
+    Type type;
+    QString text;
+    knowCore::Value value;
+  };
+  QString getIdentifier(knowCore::LexerTextStream::Element lastChar);
+  knowCore::ReturnValue<Token> nextToken();
+
+  knowCore::LexerTextStream stream;
+};
+
+QString Parser::Private::getIdentifier(knowCore::LexerTextStream::Element lastChar)
+{
+  QString identifierStr;
+  if( lastChar.content != 0) {
+    identifierStr = lastChar.content;
+  }
+  while (not stream.eof() )
+  {
+    lastChar = stream.getNextChar();
+    if( lastChar.isLetter() or lastChar == '_')
+    {
+      identifierStr += lastChar.content;
+    } else {
+      stream.unget(lastChar);
+      break;
+    }
+  }
+  return identifierStr;
+}
+
+knowCore::ReturnValue<Parser::Private::Token> Parser::Private::nextToken()
+{
+  using Token = Private::Token;
+  knowCore::LexerTextStream::Element lastChar = stream.getNextNonSeparatorChar();
+  const knowCore::LexerTextStream::Element firstChar = lastChar;
+  if( lastChar == EOF ) return kCrvSuccess(Token{Token::Type::END_OF_FILE, QString(), knowCore::Value()});
+
+  KNOWCORE_ASSERT(lastChar.content.size() == 1);
+  switch(lastChar.content.at(0).toLatin1())
+  {
+    case '<':
+    { // This  an URI
+      auto [string, finished] = stream.getString(">");
+      if(finished)
+      {
+        return kCrvSuccess(Token{Token::Type::VALUE, QString(), knowCore::Value::fromValue(knowCore::Uri(string.content))});
+      } else {
+        return kCrvError("Unfinished uri: {}", string.content);
+      }
+    }
+    case '"':
+    { // This  a String
+      auto [string, finished] = stream.getString("\"");
+      if(finished)
+      {
+        return kCrvSuccess(Token{Token::Type::VALUE, QString(), knowCore::Value::fromValue(string.content)});
+      } else {
+        return kCrvError("Unfinished uri: {}", string.content);
+      }
+    }
+    case ':':
+      return kCrvSuccess(Token{Token::Type::COLON, QString(), knowCore::Value()});
+    default:
+    {
+      if(lastChar.isLetter())
+      {
+        return kCrvSuccess(Token{Token::Type::IDENTIFIER, getIdentifier(lastChar), knowCore::Value()});
+      } else if(lastChar.isDigit())
+      {
+        auto [number, isinteger] = stream.getDigit(lastChar);
+        KNOWCORE_RETURN_VALUE_TRY(bn, knowCore::BigNumber::fromString(number.content));
+        return kCrvSuccess(Token{Token::Type::VALUE, QString(), bn.toValue()});
+      } else {
+        return kCrvError("Invalid character: {}", lastChar.content);
+      }
+    }
+  }
+
+
+}
+
+knowCore::ReturnValue<Parser::Result> Parser::parse(const QString& _string)
+{
+  using Token = Private::Token;
+  Private d;
+  d.stream.setString(_string);
+  Result r;
+  bool parsingKey = true;
+  while(parsingKey)
+  {
+    KNOWCORE_RETURN_VALUE_TRY(token, d.nextToken());
+    switch(token.type)
+    {
+      case Token::Type::END_OF_FILE:
+       return kCrvSuccess(r);
+      case Token::Type::IDENTIFIER:
+      {
+        r.key.append(token.text);
+        break;
+      }
+      case Token::Type::COLON:
+      {
+        if(r.key.isEmpty())
+        {
+          return kCrvError("Unexpected ':'");
+        }
+        QString name = r.key.takeLast();
+        KNOWCORE_RETURN_VALUE_TRY(token, d.nextToken());
+        if(token.type != Token::Type::VALUE)
+        {
+          return kCrvError("Expected value after '{}:'", name);
+        }
+        r.parameters.add(name, token.value);
+        parsingKey = false;
+        break;
+      }
+      default:
+        return kCrvError("Unexpected token, expecting identifier, ':' or end of file.");
+    }
+  }
+  while(true)
+  {
+    KNOWCORE_RETURN_VALUE_TRY(token, d.nextToken());
+    switch(token.type)
+    {
+      case Token::Type::END_OF_FILE:
+       return kCrvSuccess(r);
+      case Token::Type::IDENTIFIER:
+      {
+        QString name = token.text;
+        KNOWCORE_RETURN_VALUE_TRY(token_colon, d.nextToken());
+        if(token_colon.type != Token::Type::COLON)
+        {
+          return kCrvError("Expected ':' after '{}'", name);
+        }
+        KNOWCORE_RETURN_VALUE_TRY(token_value, d.nextToken());
+        if(token_value.type != Token::Type::VALUE)
+        {
+          return kCrvError("Expected value after '{}:'", name);
+        }
+        r.parameters.add(name, token_value.value);
+        break;
+      }
+      default:
+        return kCrvError("Unexpected token, expecting identifier or end of file.");
+    }
+  }
+
+}
+
diff --git a/kDB/SMQuery/Parser.h b/kDB/SMQuery/Parser.h
new file mode 100644
index 0000000000000000000000000000000000000000..a2f04fb4bc33b4c61398a3223d782339d30b3e52
--- /dev/null
+++ b/kDB/SMQuery/Parser.h
@@ -0,0 +1,18 @@
+#include <knowCore/ValueHash.h>
+
+namespace kDB::SMQuery
+{
+  class Parser
+  {
+  public:
+    struct Result
+    {
+      QStringList key;
+      knowCore::ValueHash parameters;
+    };
+  public:
+    static knowCore::ReturnValue<Result> parse(const QString& _query);
+  private:
+    struct Private;
+  };
+}
diff --git a/kDB/SMQuery/tests/CMakeLists.txt b/kDB/SMQuery/tests/CMakeLists.txt
new file mode 100644
index 0000000000000000000000000000000000000000..233d8da77da1abad5d2673bea129d6c419ebe50d
--- /dev/null
+++ b/kDB/SMQuery/tests/CMakeLists.txt
@@ -0,0 +1,3 @@
+add_executable(TestEngine TestEngine.cpp )
+target_link_libraries(TestEngine PRIVATE kDBSMQuery Qt5::Test)
+add_test(NAME TEST-SMQuery-Engine COMMAND TestEngine)
diff --git a/kDB/SMQuery/tests/TestEngine.cpp b/kDB/SMQuery/tests/TestEngine.cpp
new file mode 100644
index 0000000000000000000000000000000000000000..568edae861d1508b1260486f4faa20eb7e2bb1a1
--- /dev/null
+++ b/kDB/SMQuery/tests/TestEngine.cpp
@@ -0,0 +1,70 @@
+#include "TestEngine.h"
+
+#include "../Interfaces/Action.h"
+#include "../Engine.h"
+
+#include <knowCore/TypeDefinitions.h>
+#include <knowCore/Test.h>
+#include <knowCore/ValueHash.h>
+
+class TestFailAction : public kDB::SMQuery::Interfaces::Action
+{
+public:
+  virtual ~TestFailAction() {}
+  knowCore::ReturnVoid execute(const QString&, const knowCore::ValueHash&) override
+  {
+    return kCrvError("Expected failure.");
+  }
+
+};
+
+class TestAction : public kDB::SMQuery::Interfaces::Action
+{
+public:
+  virtual ~TestAction() {}
+  knowCore::ReturnVoid execute(const QString& _key, const knowCore::ValueHash& _parameters) override
+  {
+    if(_key == "ALSO FAIL")
+    {
+      return kCrvError("Expected failure.");
+    } else if(_key == "DO SUCCEED")
+    {
+      if(_parameters.contains("uri") and _parameters.value("uri") != knowCore::Value::fromValue("hello world"_kCu))
+      {
+        return kCrvError("Invalid uri.");
+      }
+      if(_parameters.contains("value") and _parameters.value("value") != knowCore::Value::fromValue(12))
+      {
+        return kCrvError("Invalid value.");
+      }
+      if(_parameters.contains("text") and _parameters.value("text") != knowCore::Value::fromValue("some text"_kCs))
+      {
+        return kCrvError("Invalid text.");
+      }
+      return kCrvSuccess();
+    } else {
+      return kCrvError("Should not happen.");
+    }
+  }
+
+};
+void TestEngine::testQuery()
+{
+  kDB::SMQuery::Engine e;
+  e.add({"TRIGGER FAIL"}, new TestFailAction);
+  e.add({"ALSO FAIL", "DO SUCCEED"}, new TestAction);
+
+  KNOWCORE_TEST_VERIFY_FAILURE_VOID(e.execute("RANDOM ACTION"));
+  KNOWCORE_TEST_VERIFY_FAILURE_VOID(e.execute("TRIGGER FAIL"));
+  KNOWCORE_TEST_VERIFY_FAILURE_VOID(e.execute("ALSO FAIL"));
+  KNOWCORE_TEST_VERIFY_SUCCESS_VOID(e.execute("DO SUCCEED uri: <hello world>"));
+  KNOWCORE_TEST_VERIFY_SUCCESS_VOID(e.execute("DO SUCCEED uri: <hello world> value: 12"));
+  KNOWCORE_TEST_VERIFY_SUCCESS_VOID(e.execute("DO SUCCEED uri: <hello world> value: 12 text: \"some text\""));
+
+  KNOWCORE_TEST_VERIFY_FAILURE_VOID(e.execute("DO SUCCEED uri: <hello>"));
+  KNOWCORE_TEST_VERIFY_FAILURE_VOID(e.execute("DO SUCCEED value: 121"));
+  KNOWCORE_TEST_VERIFY_FAILURE_VOID(e.execute("DO SUCCEED text: \"some wrong text\""));
+}
+
+QTEST_MAIN(TestEngine)
+
diff --git a/kDB/SMQuery/tests/TestEngine.h b/kDB/SMQuery/tests/TestEngine.h
new file mode 100644
index 0000000000000000000000000000000000000000..a9d04ea664cc7b3d811ff04af8131c160871044f
--- /dev/null
+++ b/kDB/SMQuery/tests/TestEngine.h
@@ -0,0 +1,10 @@
+
+#include <QtTest/QtTest>
+
+class TestEngine : public QObject
+{
+  Q_OBJECT
+private slots:
+  void testQuery();
+};
+
diff --git a/kDBConfig.cmake.in b/kDBConfig.cmake.in
index 5c75483330f7e350eac2a07baf048456db3d5620..ce09787c2c14a6764537127c1719106d5d44c0ba 100644
--- a/kDBConfig.cmake.in
+++ b/kDBConfig.cmake.in
@@ -59,6 +59,7 @@ macro(__kdb_add_nice_target_core_library CV KCF name)
 endmacro()
 
 __kdb_add_nice_target_core_library(TRUE __KDB_COMPONENTS_FINDABLE__ Repository)
+__kdb_add_nice_target_core_library(TRUE __KDB_COMPONENTS_FINDABLE__ SMQuery)
 
 macro(__kdb_add_nice_target_components CV KE KCF name)
   if(${CV})