You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@nlpcraft.apache.org by ar...@apache.org on 2020/12/17 21:10:30 UTC

[incubator-nlpcraft] branch master updated: NLPCRAFT-194 fix.

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

aradzinski pushed a commit to branch master
in repository https://gitbox.apache.org/repos/asf/incubator-nlpcraft.git


The following commit(s) were added to refs/heads/master by this push:
     new 50fcffd  NLPCRAFT-194 fix.
50fcffd is described below

commit 50fcffd56992380d4632590d6b4ee9f75d51302c
Author: Aaron Radzinski <ar...@datalingvo.com>
AuthorDate: Thu Dec 17 13:10:16 2020 -0800

    NLPCRAFT-194 fix.
---
 .../nlpcraft/common/config/NCConfigurable.scala    |   18 +-
 .../nlpcraft/examples/time/TimeModelApp.java       |    4 +-
 .../nlpcraft/model/tools/cmdline/NCCli.scala       | 1584 ++------------------
 .../model/tools/cmdline/NCCliCommands.scala        | 1135 ++++++++++++++
 .../model/tools/cmdline/NCCliRestSpec.scala        |  326 ++++
 .../model/tools/embedded/NCEmbeddedProbe.java      |    4 +-
 .../model/tools/test/NCTestAutoModelValidator.java |    6 +-
 .../test/impl/NCTestAutoModelValidatorImpl.scala   |    9 +-
 .../scala/org/apache/nlpcraft/probe/NCProbe.scala  |    7 +-
 .../org/apache/nlpcraft/probe/NCProbeBoot.scala    |    9 +-
 .../scala/org/apache/nlpcraft/NCTestContext.scala  |    4 +-
 .../nlpcraft/model/intent/dsl/NCDslSpec.scala      |    5 +-
 12 files changed, 1637 insertions(+), 1474 deletions(-)

diff --git a/nlpcraft/src/main/scala/org/apache/nlpcraft/common/config/NCConfigurable.scala b/nlpcraft/src/main/scala/org/apache/nlpcraft/common/config/NCConfigurable.scala
index 5df0d27..bdbaa53 100644
--- a/nlpcraft/src/main/scala/org/apache/nlpcraft/common/config/NCConfigurable.scala
+++ b/nlpcraft/src/main/scala/org/apache/nlpcraft/common/config/NCConfigurable.scala
@@ -303,19 +303,21 @@ object NCConfigurable extends LazyLogging {
         else {
             val name = cfgFileOpt.get
     
-            logger.info(s"Attempting to load/merge configuration from specified configuration file: $name")
+            logger.info(s"Attempting to load/merge configuration from configuration file: $name")
             
             tmpCfg =
                 if (dfltCfg.isDefined)
-                    ConfigFactory.load(ConfigFactory.
-                        parseFile(new java.io.File(name)).
-                        withFallback(ConfigFactory.parseResources(name)).
-                        withFallback(dfltCfg.get)
+                    ConfigFactory.load(
+                        ConfigFactory.
+                            parseFile(new java.io.File(name)).
+                            withFallback(ConfigFactory.parseResources(name)).
+                            withFallback(dfltCfg.get)
                     )
                 else
-                    ConfigFactory.load(ConfigFactory.
-                        parseFile(new java.io.File(name)).
-                        withFallback(ConfigFactory.parseResources(name))
+                    ConfigFactory.load(
+                        ConfigFactory.
+                            parseFile(new java.io.File(name)).
+                            withFallback(ConfigFactory.parseResources(name))
                     )
         }
         
diff --git a/nlpcraft/src/main/scala/org/apache/nlpcraft/examples/time/TimeModelApp.java b/nlpcraft/src/main/scala/org/apache/nlpcraft/examples/time/TimeModelApp.java
index d6ddf54..8f52122 100644
--- a/nlpcraft/src/main/scala/org/apache/nlpcraft/examples/time/TimeModelApp.java
+++ b/nlpcraft/src/main/scala/org/apache/nlpcraft/examples/time/TimeModelApp.java
@@ -19,6 +19,8 @@ package org.apache.nlpcraft.examples.time;
 
 import org.apache.nlpcraft.model.tools.embedded.NCEmbeddedProbe;
 
+import java.util.Collections;
+
 /**
  * An app that demo the usage of embedded probe. This is an alternative way to
  * deploy data models using embedded probe that can run in any host JVM application.
@@ -32,7 +34,7 @@ public class TimeModelApp {
      */
     public static void main(String[] args) throws Exception {
         // Start the data probe "in place" with 'TimeModel' model.
-        if (NCEmbeddedProbe.start(null, TimeModel.class.getName()))
+        if (NCEmbeddedProbe.start(null, Collections.singletonList(TimeModel.class.getName())))
             Thread.currentThread().join();
     }
 }
diff --git a/nlpcraft/src/main/scala/org/apache/nlpcraft/model/tools/cmdline/NCCli.scala b/nlpcraft/src/main/scala/org/apache/nlpcraft/model/tools/cmdline/NCCli.scala
index 3e6da2b..71e5c7e 100644
--- a/nlpcraft/src/main/scala/org/apache/nlpcraft/model/tools/cmdline/NCCli.scala
+++ b/nlpcraft/src/main/scala/org/apache/nlpcraft/model/tools/cmdline/NCCli.scala
@@ -55,6 +55,8 @@ import org.jline.reader.impl.history.DefaultHistory
 import org.jline.terminal.{Terminal, TerminalBuilder}
 import org.jline.utils.AttributedString
 import org.jline.utils.InfoCmp.Capability
+import org.apache.nlpcraft.model.tools.cmdline.NCCliRestSpec._
+import org.apache.nlpcraft.model.tools.cmdline.NCCliCommands._
 import resource.managed
 
 import scala.annotation.tailrec
@@ -89,6 +91,9 @@ object NCCli extends App {
     private final val PRB_BEACON_PATH = ".nlpcraft/probe_beacon"
     private final val HIST_PATH = ".nlpcraft/.cli_history"
 
+    private final val DFLT_USER_EMAIL = "admin@admin.com"
+    private final val DFLT_USER_PASSWD = "admin"
+
     private final lazy val VER = NCVersion.getCurrent
     private final lazy val JAVA = U.sysEnv("NLPCRAFT_CLI_JAVA").getOrElse(new File(SystemUtils.getJavaHome, s"bin/java${if (SystemUtils.IS_OS_UNIX) "" else ".exe"}").getAbsolutePath)
     private final lazy val INSTALL_HOME = U.sysEnv("NLPCRAFT_CLI_INSTALL_HOME").getOrElse(SystemUtils.USER_DIR)
@@ -147,10 +152,10 @@ object NCCli extends App {
         extends Exception
 
     case class NoLocalServer()
-        extends IllegalStateException(s"Local server not found.")
+        extends IllegalStateException(s"Local server not found, use $C'start-server'$RST command to start one.")
 
     case class NoLocalProbe()
-        extends IllegalStateException(s"Local probe not found.")
+        extends IllegalStateException(s"Local probe not found, use $C'start-probe'$RST command to start one.")
 
     case class MissingParameter(cmd: Command, paramId: String)
         extends IllegalArgumentException(
@@ -180,7 +185,7 @@ object NCCli extends App {
         extends IllegalStateException(s"REST error (HTTP ${c(httpCode)}).")
 
     case class MalformedJson()
-        extends IllegalStateException("Malformed JSON.")
+        extends IllegalStateException(s"Malformed JSON. ${c("Tip:")} on Windows make sure to escape double quotes.")
 
     case class TooManyArguments(cmd: Command)
         extends IllegalArgumentException(s"Too many arguments, type $C'help --cmd=${cmd.name}'$RST to get help.")
@@ -188,27 +193,6 @@ object NCCli extends App {
     case class NotEnoughArguments(cmd: Command)
         extends IllegalArgumentException(s"Not enough arguments, type $C'help --cmd=${cmd.name}'$RST to get help.")
 
-    case class RestSpec(
-        path: String,
-        desc: String,
-        group: String,
-        params: Seq[RestSpecParameter]
-    )
-
-    sealed trait JsonType
-
-    case object STRING extends JsonType
-    case object BOOLEAN extends JsonType
-    case object NUMERIC extends JsonType
-    case object OBJECT extends JsonType
-    case object ARRAY extends JsonType
-
-    case class RestSpecParameter(
-        name: String,
-        kind: JsonType,
-        optional: Boolean = false // Mandatory by default.
-    )
-
     // Project templates for 'gen-project' command.
     private lazy val PRJ_TEMPLATES: Map[String, Seq[String]] = {
         val m = mutable.HashMap.empty[String, Seq[String]]
@@ -234,288 +218,6 @@ object NCCli extends App {
         m.toMap
     }
 
-    //noinspection DuplicatedCode
-    // TODO: this needs to be loaded dynamically from OpenAPI spec.
-    private final val REST_SPEC = Seq(
-        RestSpec(
-            path = "clear/conversation",
-            desc = "Clears conversation STM",
-            group = "Asking",
-            params = Seq(
-                RestSpecParameter(name = "acsTok", kind = STRING),
-                RestSpecParameter(name = "mdlId", kind = STRING),
-                RestSpecParameter(name = "usrId", kind = STRING, optional = true),
-                RestSpecParameter(name = "usrExtId", kind = STRING, optional = true)
-            )
-        ),
-        RestSpec(
-            "clear/dialog",
-            "Clears dialog flow",
-            "Asking",
-            params = Seq(
-                RestSpecParameter(name = "acsTok", kind = STRING),
-                RestSpecParameter(name = "mdlId", kind = STRING),
-                RestSpecParameter(name = "usrId", kind = STRING, optional = true),
-                RestSpecParameter(name = "usrExtId", kind = STRING, optional = true)
-            )
-        ),
-        RestSpec(
-            "model/sugsyn",
-            "Runs model synonym suggestion tool",
-            "Tools",
-            params = Seq(
-                RestSpecParameter(name = "acsTok", kind = STRING),
-                RestSpecParameter(name = "mdlId", kind = STRING),
-                RestSpecParameter(name = "minScore", kind = NUMERIC)
-            )
-        ),
-        RestSpec(
-            "check",
-            "Gets status and result of submitted requests",
-            "Asking",
-            params = Seq(
-                RestSpecParameter(name = "acsTok", kind = STRING),
-                RestSpecParameter(name = "usrId", kind = STRING, optional = true),
-                RestSpecParameter(name = "usrExtId", kind = STRING, optional = true),
-                RestSpecParameter(name = "srvReqIds", kind = ARRAY, optional = true),
-                RestSpecParameter(name = "maxRows", kind = NUMERIC, optional = true)
-            )
-        ),
-        RestSpec(
-            "cancel",
-            "Cancels a question",
-            "Asking",
-            params = Seq(
-                RestSpecParameter(name = "acsTok", kind = STRING),
-                RestSpecParameter(name = "usrId", kind = STRING, optional = true),
-                RestSpecParameter(name = "usrExtId", kind = STRING, optional = true),
-                RestSpecParameter(name = "srvReqIds", kind = ARRAY, optional = true),
-            )
-        ),
-        RestSpec(
-            "ask",
-            "Asks a question",
-            "Asking",
-            params = Seq(
-                RestSpecParameter(name = "acsTok", kind = STRING),
-                RestSpecParameter(name = "usrId", kind = STRING, optional = true),
-                RestSpecParameter(name = "usrExtId", kind = STRING, optional = true),
-                RestSpecParameter(name = "txt", kind = STRING),
-                RestSpecParameter(name = "mdlId", kind = STRING),
-                RestSpecParameter(name = "data", kind = OBJECT, optional = true),
-                RestSpecParameter(name = "enableLog", kind = BOOLEAN, optional = true),
-            )
-        ),
-        RestSpec(
-            "ask/sync",
-            "Asks a question in synchronous mode",
-            "Asking",
-            params = Seq(
-                RestSpecParameter(name = "acsTok", kind = STRING),
-                RestSpecParameter(name = "usrId", kind = STRING, optional = true),
-                RestSpecParameter(name = "usrExtId", kind = STRING, optional = true),
-                RestSpecParameter(name = "txt", kind = STRING),
-                RestSpecParameter(name = "mdlId", kind = STRING),
-                RestSpecParameter(name = "data", kind = OBJECT, optional = true),
-                RestSpecParameter(name = "enableLog", kind = BOOLEAN, optional = true),
-            )
-        ),
-        RestSpec(
-            "user/get",
-            "Gets current user information",
-            "User",
-            params = Seq(
-                RestSpecParameter(name = "acsTok", kind = STRING),
-                RestSpecParameter(name = "id", kind = STRING, optional = true),
-                RestSpecParameter(name = "usrExtId", kind = STRING, optional = true)
-            )
-        ),
-        RestSpec(
-            "user/all",
-            "Gets all users",
-            "User",
-            params = Seq(
-                RestSpecParameter(name = "acsTok", kind = STRING),
-            )
-        ),
-        RestSpec(
-            "user/update",
-            "Updates regular user",
-            "User",
-            params = Seq(
-                RestSpecParameter(name = "acsTok", kind = STRING),
-                RestSpecParameter(name = "firstName", kind = STRING),
-                RestSpecParameter(name = "lastName", kind = STRING),
-                RestSpecParameter(name = "id", kind = STRING, optional = true),
-                RestSpecParameter(name = "avatarUrl", kind = STRING, optional = true),
-                RestSpecParameter(name = "properties", kind = OBJECT, optional = true)
-            )
-        ),
-        RestSpec(
-            "user/delete",
-            "Deletes user",
-            "User",
-            params = Seq(
-                RestSpecParameter(name = "acsTok", kind = STRING),
-                RestSpecParameter(name = "id", kind = STRING, optional = true),
-                RestSpecParameter(name = "usrExtId", kind = STRING, optional = true)
-            )
-        ),
-        RestSpec(
-            "user/admin",
-            "Updates user admin permissions",
-            "User",
-            params = Seq(
-                RestSpecParameter(name = "acsTok", kind = STRING),
-                RestSpecParameter(name = "id", kind = STRING, optional = true),
-                RestSpecParameter(name = "isAdmin", kind = BOOLEAN)
-            )
-        ),
-        RestSpec(
-            "user/passwd/reset",
-            "Resets password for the user",
-            "User",
-            params = Seq(
-                RestSpecParameter(name = "acsTok", kind = STRING),
-                RestSpecParameter(name = "id", kind = STRING, optional = true),
-                RestSpecParameter(name = "newPasswd", kind = STRING)
-            )
-        ),
-        RestSpec(
-            "user/add",
-            "Adds new user",
-            "User",
-            params = Seq(
-                RestSpecParameter(name = "acsTok", kind = STRING),
-                RestSpecParameter(name = "firstName", kind = STRING),
-                RestSpecParameter(name = "lastName", kind = STRING),
-                RestSpecParameter(name = "email", kind = STRING),
-                RestSpecParameter(name = "passwd", kind = STRING),
-                RestSpecParameter(name = "isAdmin", kind = BOOLEAN),
-                RestSpecParameter(name = "usrExtId", kind = STRING, optional = true),
-                RestSpecParameter(name = "avatarUrl", kind = STRING, optional = true),
-                RestSpecParameter(name = "properties", kind = OBJECT, optional = true)
-            )
-        ),
-        RestSpec(
-            "company/get",
-            "Gets current user company information",
-            "Company",
-            params = Seq(
-                RestSpecParameter(name = "acsTok", kind = STRING),
-            )
-        ),
-        RestSpec(
-            "company/add",
-            "Adds new company",
-            "Company",
-            params = Seq(
-                RestSpecParameter(name = "acsTok", kind = STRING),
-                RestSpecParameter(name = "name", kind = STRING),
-                RestSpecParameter(name = "website", kind = STRING, optional = true),
-                RestSpecParameter(name = "country", kind = STRING, optional = true),
-                RestSpecParameter(name = "region", kind = STRING, optional = true),
-                RestSpecParameter(name = "city", kind = STRING, optional = true),
-                RestSpecParameter(name = "address", kind = STRING, optional = true),
-                RestSpecParameter(name = "postalCode", kind = STRING, optional = true),
-                RestSpecParameter(name = "adminEmail", kind = STRING),
-                RestSpecParameter(name = "adminPasswd", kind = STRING),
-                RestSpecParameter(name = "adminFirstName", kind = STRING),
-                RestSpecParameter(name = "adminLastName", kind = STRING),
-                RestSpecParameter(name = "adminAvatarUrl", kind = STRING, optional = true)
-            )
-        ),
-        RestSpec(
-            "company/update",
-            "Updates company data",
-            "Company",
-            params = Seq(
-                RestSpecParameter(name = "acsTok", kind = STRING),
-                RestSpecParameter(name = "name", kind = STRING),
-                RestSpecParameter(name = "website", kind = STRING, optional = true),
-                RestSpecParameter(name = "country", kind = STRING, optional = true),
-                RestSpecParameter(name = "region", kind = STRING, optional = true),
-                RestSpecParameter(name = "city", kind = STRING, optional = true),
-                RestSpecParameter(name = "address", kind = STRING, optional = true),
-                RestSpecParameter(name = "postalCode", kind = STRING, optional = true)
-            )
-        ),
-        RestSpec(
-            "company/delete",
-            "Deletes company",
-            "Company",
-            params = Seq(
-                RestSpecParameter(name = "acsTok", kind = STRING),
-            )
-        ),
-        RestSpec(
-            "company/token/reset",
-            "Resets company probe auth token",
-            "Company",
-            params = Seq(
-                RestSpecParameter(name = "acsTok", kind = STRING),
-            )
-        ),
-        RestSpec(
-            "feedback/add",
-            "Adds feedback",
-            "Asking",
-            params = Seq(
-                RestSpecParameter(name = "acsTok", kind = STRING),
-                RestSpecParameter(name = "usrId", kind = STRING, optional = true),
-                RestSpecParameter(name = "extUsrId", kind = STRING, optional = true),
-                RestSpecParameter(name = "comment", kind = STRING, optional = true),
-                RestSpecParameter(name = "srvReqId", kind = STRING),
-                RestSpecParameter(name = "score", kind = STRING)
-            )
-        ),
-        RestSpec(
-            "feedback/delete",
-            "Deletes feedback",
-            "Asking",
-            params = Seq(
-                RestSpecParameter(name = "acsTok", kind = STRING),
-                RestSpecParameter(name = "id", kind = NUMERIC)
-            )
-        ),
-        RestSpec(
-            "feedback/all",
-            "Gets all feedback",
-            "Asking",
-            params = Seq(
-                RestSpecParameter(name = "acsTok", kind = STRING),
-                RestSpecParameter(name = "usrId", kind = STRING, optional = true),
-                RestSpecParameter(name = "extUsrId", kind = STRING, optional = true),
-                RestSpecParameter(name = "srvReqId", kind = STRING, optional = true)
-            )
-        ),
-        RestSpec(
-            "signin",
-            "Signs in and obtains new access token",
-            "Authentication",
-            params = Seq(
-                RestSpecParameter(name = "email", kind = STRING),
-                RestSpecParameter(name = "passwd", kind = STRING)
-            )
-        ),
-        RestSpec(
-            "signout",
-            "Signs out and releases access token",
-            "Authentication",
-            params = Seq(
-                RestSpecParameter(name = "acsTok", kind = STRING),
-            )
-        ),
-        RestSpec(
-            "probe/all",
-            "Gets all probes",
-            "Probe",
-            params = Seq(
-                RestSpecParameter(name = "acsTok", kind = STRING),
-            )
-        )
-    )
-
     case class HttpRestResponse(
         code: Int,
         data: String
@@ -524,7 +226,8 @@ object NCCli extends App {
     case class ReplState(
         var isServerOnline: Boolean = false,
         var isProbeOnline: Boolean = false,
-        var accessToken: Option[String] = None,
+        var accessToken: Option[String] = None, // Access token obtain with 'userEmail'.
+        var userEmail: Option[String] = None, // Email of the user with 'accessToken'.
         var serverLog: Option[File] = None,
         var probeLog: Option[File] = None,
         var probes: List[Probe] = Nil // List of connected probes.
@@ -535,6 +238,7 @@ object NCCli extends App {
         def resetServer(): Unit = {
             isServerOnline = false
             accessToken = None
+            userEmail = None
             serverLog = None
             probes = Nil
         }
@@ -550,1098 +254,6 @@ object NCCli extends App {
 
     private val state = ReplState()
 
-    // Single CLI command.
-    case class Command(
-        name: String,
-        group: String,
-        synopsis: String,
-        desc: Option[String] = None,
-        params: Seq[Parameter] = Seq.empty,
-        examples: Seq[Example] = Seq.empty,
-        body: (Command, Seq[Argument], Boolean) ⇒ Unit
-    ) {
-        /**
-         *
-         * @param name
-         * @return
-         */
-        def findParameterByNameOpt(name: String): Option[Parameter] =
-            params.find(_.names.contains(name))
-
-        /**
-         *
-         * @param id
-         * @return
-         */
-        def findParameterByIdOpt(id: String): Option[Parameter] =
-            params.find(_.id == id)
-
-        /**
-         *
-         * @param id
-         * @return
-         */
-        def findParameterById(id: String): Parameter =
-            findParameterByIdOpt(id).get
-    }
-
-    // Single command's example.
-    case class Example(
-        usage: Seq[String],
-        desc: String
-    )
-
-    // Single command's parameter.
-    case class Parameter(
-        id: String,
-        names: Seq[String],
-        value: Option[String] = None,
-        optional: Boolean = false, // Mandatory by default.
-        synthetic: Boolean = false,
-        desc: String
-    )
-
-    // Parsed command line argument.
-    case class Argument(
-        parameter: Parameter, // Formal parameter this argument refers to.
-        value: Option[String]
-    ) {
-        /**
-         * Gets the original argument string.
-         *
-         * @return
-         */
-        def origString(): String =  value match {
-            case Some(s) ⇒ s"${parameter.names.head}=$s"
-            case None ⇒ parameter.names.head
-        }
-    }
-
-    //noinspection DuplicatedCode
-    // All supported commands.
-    private final val CMDS = Seq(
-        Command(
-            name = "rest",
-            group = "2. REST Commands",
-            synopsis = s"REST call in a convenient way for command line mode.",
-            desc = Some(
-                s"When using this command you supply all call parameters as a single ${y("'--json'")} parameter with a JSON string. " +
-                s"In REPL mode, you can hit ${rv(" Tab ")} to see auto-suggestion and auto-completion candidates for " +
-                s"commonly used paths. However, ${y("'call'")} command provides more convenient way to issue REST " +
-                s"calls when in REPL mode."
-            ),
-            body = cmdRest,
-            params = Seq(
-                Parameter(
-                    id = "path",
-                    names = Seq("--path", "-p"),
-                    value = Some("path"),
-                    desc =
-                        s"REST path, e.g. ${y("'signin'")} or ${y("'ask/sync'")}. " +
-                        s"Note that you don't need supply '/' at the beginning. " +
-                        s"See more details at https://nlpcraft.apache.org/using-rest.html " +
-                        s"In REPL mode, hit ${rv(" Tab ")} to see auto-suggestion for possible REST paths."
-                ),
-                Parameter(
-                    id = "json",
-                    names = Seq("--json", "-j"),
-                    value = Some("'json'"),
-                    desc =
-                        s"REST call parameters as JSON object. Since standard JSON only supports double " +
-                        s"quotes the entire JSON string should be enclosed in single quotes. You can " +
-                        s"find full OpenAPI specification for NLPCraft REST API at " +
-                        s"https://nlpcraft.apache.org/using-rest.html"
-                )
-            ),
-            examples = Seq(
-                Example(
-                    usage = Seq(
-                        s"$$ nlpcraft.sh rest ",
-                        "  -p=signin",
-                        "  -j='{\"email\": \"admin@admin.com\", \"passwd\": \"admin\"}'"
-                    ),
-                    desc = s"${bo("Unix/Linux:")} issues ${y("'signin'")} REST call with given JSON payload."
-                ),
-                Example(
-                    usage = Seq(
-                        s"> nlpcraft.cmd rest ",
-                        "  -p=signin",
-                        "  -j='{\\\"email\\\": \\\"admin@admin.com\\\", \\\"passwd\\\": \\\"admin\\\"}'"
-                    ),
-                    desc =
-                        s"${bo("Windows:")} issues ${y("'signin'")} REST call with given JSON payload. " +
-                        s"Note the necessary escaping of double quotes."
-                )
-            )
-        ),
-        Command(
-            name = "signin",
-            group = "2. REST Commands",
-            synopsis = s"Wrapper for ${c("'/signin'")} REST call.",
-            desc = Some(
-                s"If no arguments provided, it signs in with the " +
-                s"default 'admin@admin.com' user account. NOTE: please make sure to remove this account when " +
-                s"running in production."
-            ),
-            body = cmdSignIn,
-            params = Seq(
-                Parameter(
-                    id = "email",
-                    names = Seq("--email", "-e"),
-                    value = Some("email"),
-                    optional = true,
-                    desc =
-                        s"Email of the user. If not provided, 'admin@admin.com' will be used."
-                ),
-                Parameter(
-                    id = "passwd",
-                    names = Seq("--passwd", "-p"),
-                    value = Some("****"),
-                    optional = true,
-                    desc =
-                        s"User password to sign in. If not provided, the default password will be used."
-                )
-            ),
-            examples = Seq(
-                Example(
-                    usage = Seq(
-                        s"$PROMPT $SCRIPT_NAME signin"
-                    ),
-                    desc = s"Signs in with the default ${c("admin@admin.com")} user account."
-                )
-            )
-        ),
-        Command(
-            name = "signout",
-            group = "2. REST Commands",
-            synopsis = s"Wrapper for ${c("'/signout'")} REST call in REPL mode.",
-            desc = Some(
-                s"Signs out currently signed in user. Note that this command makes sense only in REPL mode."
-            ),
-            body = cmdSignOut,
-            examples = Seq(
-                Example(
-                    usage = Seq(
-                        s"$PROMPT $SCRIPT_NAME signout"
-                    ),
-                    desc = s"Signs out currently signed in user, if any."
-                )
-            )
-        ),
-        Command(
-            name = "call",
-            group = "2. REST Commands",
-            synopsis = s"REST call in a convenient way for REPL mode.",
-            desc = Some(
-                s"When using this command you supply all call parameters separately through their own parameters named " +
-                s"after their corresponding parameters in REST specification. " +
-                s"In REPL mode, hit ${rv(" Tab ")} to see auto-suggestion and " +
-                s"auto-completion candidates for commonly used paths and call parameters."
-            ),
-            body = cmdCall,
-            params = Seq(
-                Parameter(
-                    id = "path",
-                    names = Seq("--path", "-p"),
-                    value = Some("path"),
-                    desc =
-                        s"REST path, e.g. ${y("'signin'")} or ${y("'ask/sync'")}. " +
-                        s"Note that you don't need supply '/' at the beginning. " +
-                        s"See more details at https://nlpcraft.apache.org/using-rest.html " +
-                        s"In REPL mode, hit ${rv(" Tab ")} to see auto-suggestion for possible REST paths."
-                ),
-                Parameter(
-                    id = "xxx",
-                    names = Seq("--xxx"),
-                    value = Some("value"),
-                    optional = true,
-                    synthetic = true,
-                    desc =
-                        s"${y("'xxx'")} name corresponds to the REST call parameter that can be found at https://nlpcraft.apache.org/using-rest.html " +
-                        s"The value of this parameter should be a valid JSON value using valid JSON syntax. Note that strings " +
-                        s"don't have to be in double quotes. JSON objects and arrays should be specified as a JSON string in single quotes. You can have " +
-                        s"as many ${y("'--xxx=value'")} parameters as requires by the ${y("'--path'")} parameter. " +
-                        s"In REPL mode, hit ${rv(" Tab ")} to see auto-suggestion for possible parameters and their values."
-                )
-            ),
-            examples = Seq(
-                Example(
-                    usage = Seq(
-                        s"$PROMPT $SCRIPT_NAME call -p=signin",
-                        "  --email=admin@admin.com",
-                        "  --passwd=admin"
-                    ),
-                    desc =
-                        s"Issues ${y("'signin'")} REST call with given JSON payload provided as a set of parameters. " +
-                        s"Note that ${y("'--email'")} and ${y("'--passwd'")} parameters correspond to the REST call " +
-                        s"specification for ${y("'/signin'")} path."
-                ),
-                Example(
-                    usage = Seq(
-                        s"$$ nlpcraft.sh call --path=ask/sync",
-                        "  --acsTok=qwerty123456",
-                        "  --txt=\"User request\"",
-                        "  --mdlId=my.model.id",
-                        "  --data='{\"data1\": true, \"data2\": 123, \"data3\": \"some text\"}'",
-                        "  --enableLog=false"
-                    ),
-                    desc =
-                        s"${bo("Unix/Linux:")} issues ${y("'ask/sync'")} REST call with given JSON payload provided as a set of parameters."
-                ),
-                Example(
-                    usage = Seq(
-                        s"> nlpcraft.cmd call --path=ask/sync",
-                        "  --acsTok=qwerty123456",
-                        "  --txt=\"User request\"",
-                        "  --mdlId=my.model.id",
-                        "  --data='{\\\"data1\\\": true, \\\"data2\\\": 123, \\\"data3\\\": \\\"some text\\\"}'",
-                        "  --enableLog=false"
-                    ),
-                    desc =
-                        s"${bo("Windows:")} issues ${y("'ask/sync'")} REST call with given JSON payload provided " +
-                        s"as a set of parameters. Note the necessary double quote escaping."
-                )
-            )
-        ),
-        Command(
-            name = "ask",
-            group = "2. REST Commands",
-            synopsis = s"Wrapper for ${c("'/ask/sync'")} REST call.",
-            desc = Some(
-                s"Requires user to be already signed in. This command ${bo("only makes sense in the REPL mode")} as " +
-                s"it requires user to be signed in. REPL session keeps the currently active access " +
-                s"token after user signed in. For command line mode, use ${c("'rest'")} command with " +
-                s"corresponding parameters."
-            ),
-            body = cmdAsk,
-            params = Seq(
-                Parameter(
-                    id = "mdlId",
-                    names = Seq("--mdlId"),
-                    value = Some("model.id"),
-                    desc =
-                        s"ID of the data model to send the request to. " +
-                        s"In REPL mode, hit ${rv(" Tab ")} to see auto-suggestion for possible model IDs."
-                ),
-                Parameter(
-                    id = "txt",
-                    names = Seq("--txt"),
-                    value = Some("txt"),
-                    desc =
-                        s"Text of the question."
-                ),
-                Parameter(
-                    id = "data",
-                    names = Seq("--data"),
-                    value = Some("'{}'"),
-                    optional = true,
-                    desc = s"Additional JSON data with maximum JSON length of 512000 bytes. Default is ${c("'null'")}."
-                ),
-                Parameter(
-                    id = "enableLog",
-                    names = Seq("--enableLog"),
-                    value = Some("true|false"),
-                    optional = true,
-                    desc = s"Flag to enable detailed processing log to be returned with the result. Default is ${c("'false'")}."
-                )
-            ),
-            examples = Seq(
-                Example(
-                    usage = Seq(
-                        s"""> ask --txt="User request" --mdlId=my.model.id"""
-                    ),
-                    desc =
-                        s"Issues ${y("'ask/sync'")} REST call with given text and model ID."
-                )
-            )
-        ),
-        Command(
-            name = "gen-sql",
-            group = "3. Miscellaneous",
-            synopsis = s"Generates NLPCraft model stub from SQL databases.",
-            desc = Some(
-                s"You can choose database schema, set of tables and columns for which you want to generate NLPCraft " +
-                s"model. After the model is generated you can further configure and customize it for your specific needs. " +
-                s"Find more information at ${y("https://nlpcraft.apache.org/tools/sql_model_gen.html")}"
-            ),
-            body = cmdSqlGen,
-            params = Seq(
-                Parameter(
-                    id = "url",
-                    names = Seq("--url", "-r"),
-                    value = Some("url"),
-                    desc =
-                        s"Database JDBC URL."
-                ),
-                Parameter(
-                    id = "driver",
-                    names = Seq("--driver", "-d"),
-                    value = Some("class"),
-                    desc =
-                        s"Mandatory JDBC driver class. Note that 'class' must be a fully qualified class name. " +
-                        s"It should also be available on the classpath."
-                ),
-                Parameter(
-                    id = "schema",
-                    names = Seq("--schema", "-s"),
-                    value = Some("schema"),
-                    desc =
-                        s"Database schema to scan."
-                ),
-                Parameter(
-                    id = "out",
-                    names = Seq("--out", "-o"),
-                    value = Some("filename"),
-                    desc =
-                        s"Name of the output JSON or YAML model file. " +
-                        s"It should have one of the following extensions: .js, .json, .yml, or .yaml. " +
-                        s"File extension determines the output file format."
-                ),
-                Parameter(
-                    id = "user",
-                    names = Seq("--user", "-u"),
-                    value = Some("username"),
-                    optional = true,
-                    desc = s"Database user name."
-                ),
-                Parameter(
-                    id = "password",
-                    names = Seq("--password", "-w"),
-                    value = Some("password"),
-                    optional = true,
-                    desc = s"Database password."
-                ),
-                Parameter(
-                    id = "modelId",
-                    names = Seq("--model-id", "-x"),
-                    value = Some("id"),
-                    optional = true,
-                    desc = s"Generated model ID. By default, the model ID is ${c("'sql.model.id'")}."
-                ),
-                Parameter(
-                    id = "modelVer",
-                    names = Seq("--model-ver", "-v"),
-                    value = Some("version"),
-                    optional = true,
-                    desc = s"Generated model version. By default, the model version is ${c("'1.0.0-timestamp'")}."
-                ),
-                Parameter(
-                    id = "modelName",
-                    names = Seq("--model-name", "-n"),
-                    value = Some("name"),
-                    optional = true,
-                    desc = s"Generated model name. By default, the model name is ${c("'SQL-based-model'")}."
-                ),
-                Parameter(
-                    id = "exclude",
-                    names = Seq("--exclude", "-e"),
-                    value = Some("list"),
-                    optional = true,
-                    desc =
-                        s"Semicolon-separate list of tables and/or columns to exclude. By default, none of the " +
-                        s"tables and columns in the schema are excluded. See ${c("--help")} parameter to get more details."
-                ),
-                Parameter(
-                    id = "include",
-                    names = Seq("--include", "-i"),
-                    value = Some("list"),
-                    optional = true,
-                    desc =
-                        s"Semicolon-separate list of tables and/or columns to include. By default, all of the " +
-                        s"tables and columns in the schema are included. See ${c("--help")} parameter to get more details."
-                ),
-                Parameter(
-                    id = "prefix",
-                    names = Seq("--prefix", "-f"),
-                    value = Some("list"),
-                    optional = true,
-                    desc =
-                        s"Comma-separate list of table or column name prefixes to remove. These prefixes will be " +
-                        s"removed when name is used for model elements synonyms. By default, no prefixes will be removed."
-                ),
-                Parameter(
-                    id = "suffix",
-                    names = Seq("--suffix", "-q"),
-                    value = Some("list"),
-                    optional = true,
-                    desc =
-                        s"Comma-separate list of table or column name suffixes to remove. These suffixes will be " +
-                        s"removed when name is used for model elements synonyms. By default, no suffixes will be removed."
-                ),
-                Parameter(
-                    id = "synonyms",
-                    names = Seq("--synonyms", "-y"),
-                    value = Some("true|false"),
-                    optional = true,
-                    desc = s"Flag on whether or not to generated auto synonyms for the model elements. Default is ${c("'true'")}."
-                ),
-                Parameter(
-                    id = "override",
-                    names = Seq("--override", "-z"),
-                    value = Some("true|false"),
-                    optional = true,
-                    desc =
-                        s"Flag to determine whether or not to override output file if it already exist. " +
-                        s"If override is disabled (default) and output file exists - a unique file name " +
-                        s"will be used instead. Default is ${c("'false'")}."
-                ),
-                Parameter(
-                    id = "parent",
-                    names = Seq("--parent", "-p"),
-                    value = Some("true|false"),
-                    optional = true,
-                    desc =
-                        s"Flag on whether or not to use element's parent relationship for defining " +
-                        s"SQL columns and their containing (i.e. parent) tables. Default is ${c("'false'")}."
-                ),
-                Parameter(
-                    id = "help",
-                    names = Seq("--help", "-h"),
-                    optional = true,
-                    desc =
-                        s"Gets extended help and usage information for the ${c("'gen-sql'")} command. " +
-                        s"Includes information on how to run this tool standalone."
-                )
-            ),
-            examples = Seq(
-                Example(
-                    usage = Seq(
-                        s"$PROMPT $SCRIPT_NAME gen-sql --help"
-                    ),
-                    desc =
-                        s"Shows full help and usage information for ${c("gen-sql")} command."
-                ),
-                Example(
-                    usage = Seq(
-                        s"$PROMPT $SCRIPT_NAME gen-sql",
-                        "  --url=jdbc:postgresql://localhost:5432/mydb",
-                        "  --driver=org.postgresql.Driver",
-                        """  --prefix="tbl_, col_"""",
-                        """  --suffix="_tmp, _old, _unused"""",
-                        "  --schema=public",
-                        """  --exclude="#_.+"""",
-                        "  --out=model.json"
-                    ),
-                    desc =
-                        s"Generates model stub from given SQL database connection."
-                )
-            )
-        ),
-        Command(
-            name = "sugsyn",
-            group = "2. REST Commands",
-            synopsis = s"Wrapper for ${c("'/model/sugsyn'")} REST call.",
-            desc = Some(
-                s"Requires user to be already signed in. This command ${bo("only makes sense in the REPL mode")} as " +
-                s"it requires user to be signed in. REPL session keeps the currently active access " +
-                s"token after user signed in. For command line mode, use ${c("'rest'")} command with " +
-                s"corresponding parameters. Note also that it requires a local probe running that hosts " +
-                s"the specified model. Find more information about this tool at ${y("https://nlpcraft.apache.org/tools/syn_tool.html")}"
-            ),
-            body = cmdSugSyn,
-            params = Seq(
-                Parameter(
-                    id = "mdlId",
-                    names = Seq("--mdlId"),
-                    value = Some("model.id"),
-                    desc =
-                        s"ID of the model to run synonym suggestion on. " +
-                        s"In REPL mode, hit ${rv(" Tab ")} to see auto-suggestion for possible model IDs. " +
-                        s"Note that the probe hosting this model must be connected to the server."
-                ),
-                Parameter(
-                    id = "minScore",
-                    names = Seq("--minScore"),
-                    value = Some("0.5"),
-                    optional = true,
-                    desc = s"Minimal score to include into the result (from 0 to 1). Default is ${c("0.5")}."
-                )
-            ),
-            examples = Seq(
-                Example(
-                    usage = Seq(
-                        s"""> sugsyn --mdlId=my.model.id"""
-                    ),
-                    desc =
-                        s"Issues ${y("'model/sugsyn'")} REST call with default min score and given model ID."
-                )
-            )
-        ),
-        Command(
-            name = "tail-server",
-            group = "1. Server & Probe Commands",
-            synopsis = s"Shows last N lines from the local server log.",
-            desc = Some(
-                s"Only works for the server started via this script."
-            ),
-            body = cmdTailServer,
-            params = Seq(
-                Parameter(
-                    id = "lines",
-                    names = Seq("--lines", "-l"),
-                    value = Some("num"),
-                    desc =
-                        s"Number of the server log lines from the end to display. Default is 20."
-                )
-            ),
-            examples = Seq(
-                Example(
-                    usage = Seq(s"$PROMPT $SCRIPT_NAME tail-server --lines=20 "),
-                    desc = s"Prints last 20 lines from the local server log."
-                )
-            )
-        ),
-        Command(
-            name = "tail-probe",
-            group = "1. Server & Probe Commands",
-            synopsis = s"Shows last N lines from the local probe log.",
-            desc = Some(
-                s"Only works for the probe started via this script."
-            ),
-            body = cmdTailProbe,
-            params = Seq(
-                Parameter(
-                    id = "lines",
-                    names = Seq("--lines", "-l"),
-                    value = Some("num"),
-                    desc =
-                        s"Number of the probe log lines from the end to display. Default is 20."
-                )
-            ),
-            examples = Seq(
-                Example(
-                    usage = Seq(s"$PROMPT $SCRIPT_NAME tail-probe --lines=20 "),
-                    desc = s"Prints last 20 lines from the local probe log."
-                )
-            )
-        ),
-        Command(
-            name = "start-server",
-            group = "1. Server & Probe Commands",
-            synopsis = s"Starts local server.",
-            desc = Some(
-                s"Server is started in the external JVM process with both stdout and stderr piped out into log file. " +
-                s"Command will block until the server is started unless ${y("'--no-wait'")} parameter is used or timeout is expired."
-            ),
-            body = cmdStartServer,
-            params = Seq(
-                Parameter(
-                    id = "config",
-                    names = Seq("--config", "-c"),
-                    value = Some("path"),
-                    optional = true,
-                    desc =
-                        s"Configuration file path. Server will automatically look for ${y("'nlpcraft.conf'")} " +
-                        s"configuration file in the same directory as NLPCraft JAR file. If the configuration file has " +
-                        s"different name or in different location use this parameter to provide an alternative path. " +
-                        s"Note that the server and the probe can use the same file for their configuration."
-                ),
-                Parameter(
-                    id = "igniteConfig",
-                    names = Seq("--ignite-config", "-i"),
-                    value = Some("path"),
-                    optional = true,
-                    desc =
-                        s"Apache Ignite configuration file path. Note that Apache Ignite is used as a cluster " +
-                        s"computing plane and a default distributed storage. Server will automatically look for " +
-                        s"${y("'ignite.xml'")} configuration file in the same directory as NLPCraft JAR file. If the " +
-                        s"configuration file has different name or in different location use this parameter to " +
-                        s"provide an alternative path."
-                ),
-                Parameter(
-                    id = "jvmopts",
-                    names = Seq("--jvm-opts", "-j"),
-                    value = Some("<jvm flags>"),
-                    optional = true,
-                    desc =
-                        s"Space separated list of JVM flags to use. If not provided, the default ${y("'-ea -Xms2048m -XX:+UseG1GC'")} flags " +
-                        s"will be used."
-                ),
-                Parameter(
-                    id = "noWait",
-                    names = Seq("--no-wait"),
-                    optional = true,
-                    desc =
-                        s"Instructs command not to wait for the server startup and return immediately."
-                ),
-                Parameter(
-                    id = "timeoutMins",
-                    names = Seq("--timeout-mins", "-t"),
-                    optional = true,
-                    value = Some("3"),
-                    desc =
-                        s"Timeout in minutes to wait until server is started. If not specified the default is 2 minutes."
-                )
-            ),
-            examples = Seq(
-                Example(
-                    usage = Seq(s"$PROMPT $SCRIPT_NAME start-server"),
-                    desc = "Starts local server with default configuration."
-                ),
-                Example(
-                    usage = Seq(s"$PROMPT $SCRIPT_NAME start-server -c=/opt/nlpcraft/nlpcraft.conf -t=5"),
-                    desc = "Starts local server with alternative configuration file and timeout of 5 mins."
-                )
-            )
-        ),
-        Command(
-            name = "start-probe",
-            group = "1. Server & Probe Commands",
-            synopsis = s"Starts local probe.",
-            desc = Some(
-                s"Probe is started in the external JVM process with both stdout and stderr piped out into log file. " +
-                s"Command will block until the probe is started unless ${y("'--no-wait'")} parameter is used or timeout is expired."
-            ),
-            body = cmdStartProbe,
-            params = Seq(
-                Parameter(
-                    id = "config",
-                    names = Seq("--config", "-c"),
-                    value = Some("path"),
-                    optional = true,
-                    desc =
-                        s"Configuration file path. Probe will automatically look for ${y("'nlpcraft.conf'")} " +
-                        s"configuration file in the same directory as NLPCraft JAR file. If the configuration file has " +
-                        s"different name or in different location use this parameter to provide an alternative path. " +
-                        s"Note that the server and the probe can use the same file for their configuration."
-                ),
-                Parameter(
-                    id = "cp",
-                    names = Seq("--cp", "-p"),
-                    value = Some("path"),
-                    optional = true,
-                    desc =
-                        s"Additional JVM classpath that will be appended to the default NLPCraft JVM classpath. " +
-                        s"Although this configuration property is optional, when deploying your own models you must " +
-                        s"provide this additional classpath for the models and their dependencies this probe will be hosting. " +
-                        s"NOTE: this is only optional if you are running example models shipped with NLPCraft."
-                ),
-                Parameter(
-                    id = "models",
-                    names = Seq("--models", "-m"),
-                    value = Some("<model list>"),
-                    optional = true,
-                    desc =
-                        s"Comma separated list of fully qualified class names for models to deploy. This will override " +
-                        s"${y("'nlpcraft.probe.models'")} configuration property from either default configuration file " +
-                        s"or the one provided by ${y("--config")} parameter. NOTE: if you provide the list of your " +
-                        s"own models here or in configuration file - you must also provide the additional classpath " +
-                        s"for them via ${y("--cp")} parameter."
-                ),
-                Parameter(
-                    id = "jvmopts",
-                    names = Seq("--jvm-opts", "-j"),
-                    value = Some("<jvm flags>"),
-                    optional = true,
-                    desc =
-                        s"Space separated list of JVM flags to use. If not provided, the default ${y("'-ea -Xms1024m'")} flags " +
-                        s"will be used."
-                ),
-                Parameter(
-                    id = "noWait",
-                    names = Seq("--no-wait"),
-                    optional = true,
-                    desc =
-                        s"Instructs command not to wait for the probe startup and return immediately."
-                ),
-                Parameter(
-                    id = "timeoutMins",
-                    names = Seq("--timeout-mins", "-t"),
-                    optional = true,
-                    value = Some("3"),
-                    desc =
-                        s"Timeout to wait until probe is started. If not specified the default is 1 minute."
-                )
-            ),
-            examples = Seq(
-                Example(
-                    usage = Seq(s"$PROMPT $SCRIPT_NAME start-probe"),
-                    desc = "Starts local probe with default configuration and parameters."
-                ),
-                Example(
-                    usage = Seq(
-                        s"$PROMPT $SCRIPT_NAME start-probe ",
-                        "  --config=/opt/nlpcraft.conf ",
-                        "  --models=my.package.Model ",
-                        "  --cp=/opt/target/classes ",
-                        "  --jmv-opts=\"-ea -Xms2048m\" ",
-                        "  --timeout-mins=5"
-                    ),
-                    desc =
-                        s"Starts local probe for ${y("'my.package.Model'")} model with alternative configuration " +
-                        s"file and additional parameters."
-                )
-            )
-        ),
-        Command(
-            name = "test-model",
-            group = "3. Miscellaneous",
-            synopsis = s"Runs auto model validation.",
-            desc = Some(
-                s"Runs ${y("'NCTestAutoModelValidator'")} model auto-validator for given models."
-            ),
-            body = cmdTestModel,
-            params = Seq(
-                Parameter(
-                    id = "cp",
-                    names = Seq("--cp", "-p"),
-                    value = Some("path"),
-                    optional = true,
-                    desc =
-                        s"Additional JVM classpath that will be appended to the default NLPCraft JVM classpath. " +
-                        s"Although this configuration property is optional, when testing your own models you must " +
-                        s"provide this additional classpath for the models and their dependencies. " +
-                        s"NOTE: this is only optional if you are testing example models shipped with NLPCraft."
-                ),
-                Parameter(
-                    id = "models",
-                    names = Seq("--models", "-m"),
-                    value = Some("<model list>"),
-                    desc =
-                        s"Comma separated list of fully qualified class names for models to test. NOTE: if you provide " +
-                        s"the list of your own models here - you must also provide the additional classpath " +
-                        s"for them via ${y("--cp")} parameter."
-                ),
-                Parameter(
-                    id = "jvmopts",
-                    names = Seq("--jvm-opts", "-j"),
-                    value = Some("<jvm flags>"),
-                    optional = true,
-                    desc =
-                        s"Space separated list of JVM flags to use. If not provided, the default ${y("'-ea -Xms1024m'")} flags " +
-                        s"will be used."
-                )
-            ),
-            examples = Seq(
-                Example(
-                    usage = Seq(
-                        s"$PROMPT $SCRIPT_NAME test-model ",
-                        "  --models=my.package.Model ",
-                        "  --cp=/opt/target/classes ",
-                        "  --jmv-opts=\"-ea -Xms2048m\""
-                    ),
-                    desc =
-                        s"Runs model auto-validator for ${y("'my.package.Model'")} model."
-                )
-            )
-        ),
-        Command(
-            name = "info-server",
-            group = "1. Server & Probe Commands",
-            synopsis = s"Info about local server.",
-            body = cmdInfoServer
-        ),
-        Command(
-            name = "info-probe",
-            group = "1. Server & Probe Commands",
-            synopsis = s"Info about local probe.",
-            body = cmdInfoProbe
-        ),
-        Command(
-            name = "info",
-            group = "1. Server & Probe Commands",
-            synopsis = s"Info about local probe & server.",
-            body = cmdInfo
-        ),
-        Command(
-            name = "cls",
-            group = "3. Miscellaneous",
-            synopsis = s"Clears terminal screen.",
-            body = cmdCls
-        ),
-        Command(
-            name = "no-ansi",
-            group = "3. Miscellaneous",
-            synopsis = s"Disables ANSI escape codes for terminal colors & controls.",
-            desc = Some(
-                s"This is a special command that can be combined with any other commands."
-            ),
-            body = cmdNoAnsi,
-            examples = Seq(
-                Example(
-                    usage = Seq(s"$PROMPT $SCRIPT_NAME help -c=rest no-ansi"),
-                    desc = s"Displays help for ${y("'rest'")} commands without using ANSI color and escape sequences."
-                )
-            )
-        ),
-        Command(
-            name = "no-logo",
-            group = "3. Miscellaneous",
-            synopsis = s"Disables showing NLPCraft logo at the start.",
-            desc = Some(
-                s"This is a special command that can be combined with any other command in a command line mode."
-            ),
-            body = cmdNoLogo,
-            examples = Seq(
-                Example(
-                    usage = Seq(s"$PROMPT $SCRIPT_NAME version -s no-logo"),
-                    desc =
-                        s"Displays just the version information without any additional logo output. " +
-                        s"This command makes sense only in command lime mode (NOT in REPL mode)."
-                )
-            )
-        ),
-        Command(
-            name = "ansi",
-            group = "3. Miscellaneous",
-            synopsis = s"Enables ANSI escape codes for terminal colors & controls.",
-            desc = Some(
-                s"This is a special command that can be combined with any other commands."
-            ),
-            body = cmdAnsi,
-            examples = Seq(
-                Example(
-                    usage = Seq(s"$PROMPT $SCRIPT_NAME help -c=rest ansi"),
-                    desc = s"Displays help for ${y("'rest'")} commands with ANSI color and escape sequences."
-                )
-            )
-        ),
-        Command(
-            name = "ping-server",
-            group = "1. Server & Probe Commands",
-            synopsis = s"Pings local server.",
-            desc = Some(
-                s"Server is pinged using ${y("'/health'")} REST call to check its online status."
-            ),
-            body = cmdPingServer,
-            params = Seq(
-                Parameter(
-                    id = "number",
-                    names = Seq("--number", "-n"),
-                    value = Some("num"),
-                    optional = true,
-                    desc =
-                        "Number of pings to perform. Must be a number > 0. Default is 1."
-                )
-            ),
-            examples = Seq(
-                Example(
-                    usage = Seq(
-                        s"$PROMPT $SCRIPT_NAME ping-server -n=10"
-                    ),
-                    desc = "Pings local server 10 times."
-                )
-            )
-        ),
-        Command(
-            name = "stop-server",
-            group = "1. Server & Probe Commands",
-            synopsis = s"Stops local server.",
-            desc = Some(
-                s"Local server must be started via ${y(s"'$SCRIPT_NAME'")} or other compatible way."
-            ),
-            body = cmdStopServer
-        ),
-        Command(
-            name = "stop-probe",
-            group = "1. Server & Probe Commands",
-            synopsis = s"Stops local probe.",
-            desc = Some(
-                s"Local probe must be started via ${y(s"'$SCRIPT_NAME'")} or other compatible way."
-            ),
-            body = cmdStopProbe
-        ),
-        Command(
-            name = "stop",
-            group = "1. Server & Probe Commands",
-            synopsis = s"Stops both local server & probe.",
-            desc = Some(
-                s"Both local server & probe must be started via ${y(s"'$SCRIPT_NAME'")} or other compatible way."
-            ),
-            body = cmdStop
-        ),
-        Command(
-            name = "quit",
-            group = "3. Miscellaneous",
-            synopsis = s"Quits REPL mode.",
-            body = cmdQuit
-        ),
-        Command(
-            name = "help",
-            group = "3. Miscellaneous",
-            synopsis = s"Displays help for ${y(s"'$SCRIPT_NAME'")}.",
-            desc = Some(
-                s"By default, without ${y("'--all'")} or ${y("'--cmd'")} parameters, displays the abbreviated form of manual " +
-                s"only listing the commands without parameters or examples."
-            ),
-            body = cmdHelp,
-            params = Seq(
-                Parameter(
-                    id = "cmd",
-                    names = Seq("--cmd", "-c"),
-                    value = Some("cmd"),
-                    optional = true,
-                    desc = "Set of commands to show the manual for. Can be used multiple times."
-                ),
-                Parameter(
-                    id = "all",
-                    names = Seq("--all", "-a"),
-                    optional = true,
-                    desc = "Flag to show full manual for all commands."
-                )
-            ),
-            examples = Seq(
-                Example(
-                    usage = Seq(s"$PROMPT $SCRIPT_NAME help -c=rest --cmd=version"),
-                    desc = s"Displays help for ${y("'rest'")} and ${y("'version'")} commands."
-                ),
-                Example(
-                    usage = Seq(s"$PROMPT $SCRIPT_NAME help -all"),
-                    desc = "Displays help for all commands."
-                )
-            )
-        ),
-        Command(
-            name = "version",
-            group = "3. Miscellaneous",
-            synopsis = s"Displays full version of ${y(s"'$SCRIPT_NAME'")} script.",
-            desc = Some(
-                "Depending on the additional parameters can display only the semantic version or the release date."
-            ),
-            body = cmdVersion,
-            params = Seq(
-                Parameter(
-                    id = "semver",
-                    names = Seq("--sem-ver", "-s"),
-                    value = None,
-                    optional = true,
-                    desc = s"Display only the semantic version value, e.g. ${VER.version}."
-                ),
-                Parameter(
-                    id = "reldate",
-                    names = Seq("--rel-date", "-d"),
-                    value = None,
-                    optional = true,
-                    desc = s"Display only the release date, e.g. ${VER.date}."
-                )
-            )
-        ),
-        Command(
-            name = "gen-project",
-            group = "3. Miscellaneous",
-            synopsis = s"Generates project stub with default configuration.",
-            desc = Some(
-                "This command supports Java, Scala, and Kotlin languages with either Maven, Gradle or SBT " +
-                "as a build tool. Generated projects compiles and runs and can be used as a quick development sandbox."
-            ),
-            body = cmdGenProject,
-            params = Seq(
-                Parameter(
-                    id = "outputDir",
-                    names = Seq("--outputDir", "-d"),
-                    value = Some("path"),
-                    optional = true,
-                    desc = s"Output directory. Default value is the current working directory."
-                ),
-                Parameter(
-                    id = "baseName",
-                    names = Seq("--baseName", "-n"),
-                    value = Some("name"),
-                    desc =
-                        s"Base name for the generated files. For example, if base name is ${y("'MyApp'")}, " +
-                        s"then generated Java file will be named as ${y("'MyAppModel.java'")} and model file as ${y("'my_app_model.yaml'")}."
-                ),
-                Parameter(
-                    id = "lang",
-                    names = Seq("--lang", "-l"),
-                    value = Some("name"),
-                    optional = true,
-                    desc =
-                        s"Language to generate source files in. Supported value are ${y("'java'")}, ${y("'scala'")}, ${y("'kotlin'")}. " +
-                        s"Default value is ${y("'java'")}."
-                ),
-                Parameter(
-                    id = "buildTool",
-                    names = Seq("--buildTool", "-b"),
-                    value = Some("name"),
-                    optional = true,
-                    desc =
-                        s"Build tool name to use. Supported values are ${y("'mvn'")} and ${y("'gradle'")} for ${y("'java'")}, " +
-                        s"${y("'scala'")}, ${y("'kotlin'")}, and ${y("'sbt'")} for ${y("'scala'")} language. Default value is ${y("'mvn'")}."
-                ),
-                Parameter(
-                    id = "packageName",
-                    names = Seq("--packageName", "-p"),
-                    value = Some("name"),
-                    optional = true,
-                    desc = s"JVM package name to use in generated source code. Default value is ${y("'org.apache.nlpcraft.demo'")}."
-                ),
-                Parameter(
-                    id = "modelType",
-                    names = Seq("--modelType", "-m"),
-                    value = Some("type"),
-                    optional = true,
-                    desc = s"Type of generated model file. Supported value are ${y("'yaml'")} or ${y("'json'")}. Default value is ${y("'yaml'")}."
-                ),
-                Parameter(
-                    id = "override",
-                    names = Seq("--override", "-o"),
-                    value = Some("true|false"),
-                    optional = true,
-                    desc = s"Whether or not to override existing output directory. Default value is ${y("'false'")}."
-                )
-            ),
-            examples = Seq(
-                Example(
-                    usage = Seq("> gen-project -n=MyProject -l=scala -b=sbt"),
-                    desc = s"Generates Scala SBT project."
-                ),
-                Example(
-                    usage = Seq("> gen-project -n=MyProject -l=kotlin -p=com.mycompany.nlp -o=true"),
-                    desc = s"Generates Kotlin Maven project."
-                )
-            )
-        ),
-        Command(
-            name = "gen-model",
-            group = "3. Miscellaneous",
-            synopsis = s"Generates data model file stub.",
-            desc = Some(
-                "Generated model stub will have all default configuration. Model file can be either YAML or JSON."
-            ),
-            body = cmdGenModel,
-            params = Seq(
-                Parameter(
-                    id = "filePath",
-                    names = Seq("--filePath", "-f"),
-                    value = Some("path"),
-                    desc =
-                        s"File path for the model stub. File path can either be an absolute path, relative path or " +
-                        s"just a file name in which case the current folder will be used. File must have one of the " +
-                        s"following extensions: ${y("'json'")}, ${y("'js'")}, ${y("'yaml'")}, or ${y("'yml'")}."
-                ),
-                Parameter(
-                    id = "modelId",
-                    names = Seq("--modelId", "-n"),
-                    value = Some("id"),
-                    desc = "Model ID."
-                ),
-                Parameter(
-                    id = "override",
-                    names = Seq("--override", "-o"),
-                    value = Some("true|false"),
-                    optional = true,
-                    desc = s"Override output directory flag. Supported: ${y("'true'")}, ${y("'false'")}. Default value is ${y("'false'")}"
-                )
-            ),
-            examples = Seq(
-                Example(
-                    usage = Seq("> gen-model -f=myModel.json -n=my.model.id"),
-                    desc = s"Generates JSON model file stub in the current folder."
-                ),
-                Example(
-                    usage = Seq("> gen-model -f=c:/tmp/myModel.yaml -n=my.model.id --override=true"),
-                    desc = s"Generates YAML model file stub in ${y("'c:/temp'")} folder overriding existing file, if any."
-                )
-            )
-        )
-    ).sortBy(_.name)
-
-    require(
-        U.getDups(CMDS.map(_.name)).isEmpty,
-        "Dup commands."
-    )
-
     private final val NO_LOGO_CMD = CMDS.find(_.name == "no-logo").get
     private final val NO_ANSI_CMD = CMDS.find(_.name == "no-ansi").get
     private final val ANSI_CMD = CMDS.find(_.name == "ansi").get
@@ -1683,21 +295,20 @@ object NCCli extends App {
      *
      * @param pathOpt
      */
-    private def checkFilePath(pathOpt: Option[Argument]): Unit = {
+    private def checkFilePath(pathOpt: Option[Argument]): Unit =
         if (pathOpt.isDefined) {
             val file = new File(stripQuotes(pathOpt.get.value.get))
 
             if (!file.exists() || !file.isFile)
                 throw new IllegalArgumentException(s"File not found: ${c(file.getAbsolutePath)}")
         }
-    }
 
     /**
      * @param cmd  Command descriptor.
      * @param args Arguments, if any, for this command.
      * @param repl Whether or not running from REPL.
      */
-    private def cmdStartServer(cmd: Command, args: Seq[Argument], repl: Boolean): Unit = {
+    private [cmdline] def cmdStartServer(cmd: Command, args: Seq[Argument], repl: Boolean): Unit = {
         val cfgPath = args.find(_.parameter.id == "config")
         val igniteCfgPath = args.find(_.parameter.id == "igniteConfig")
         val noWait = args.exists(_.parameter.id == "noWait")
@@ -1721,7 +332,10 @@ object NCCli extends App {
 
         // Ensure that there isn't another local server running.
         loadServerBeacon() match {
-            case Some(b) ⇒ throw new IllegalStateException(s"Existing server (pid ${c(b.pid)}) detected.")
+            case Some(b) ⇒ throw new IllegalStateException(
+                s"Existing server (pid ${c(b.pid)}) detected. " +
+                s"Use ${c("'stop-server'")} command to stop it, if necessary."
+            )
             case None ⇒ ()
         }
 
@@ -1896,7 +510,7 @@ object NCCli extends App {
                     if (state.accessToken.isDefined) {
                         val tbl = new NCAsciiTable()
 
-                        tbl += (s"${g("Email")}", "admin@admin.com")
+                        tbl += (s"${g("Email")}", state.userEmail.get)
                         tbl += (s"${g("Access token")}", state.accessToken.get)
 
                         logln(s"Signed in with default user:\n$tbl")
@@ -1914,8 +528,56 @@ object NCCli extends App {
      * @param args Arguments, if any, for this command.
      * @param repl Whether or not running from REPL.
      */
-    private def cmdTestModel(cmd: Command, args: Seq[Argument], repl: Boolean): Unit = {
+    private [cmdline] def cmdTestModel(cmd: Command, args: Seq[Argument], repl: Boolean): Unit = {
+        // TODO: in the future - we'll need add support here for remote servers.
+        if (loadServerBeacon().isEmpty)
+            throw NoLocalServer()
 
+        val cfgPath = args.find(_.parameter.id == "config")
+        val addCp = args.find(_.parameter.id == "cp") match {
+            case Some(cp) ⇒ cp.value.get
+            case None ⇒ null
+        }
+        val mdls = args.find(_.parameter.id == "models") match {
+            case Some(arg) ⇒ stripQuotes(arg.value.get)
+            case None ⇒ null
+        }
+        val jvmOpts = args.find(_.parameter.id == "jvmopts") match {
+            case Some(arg) ⇒ U.splitTrimFilter(stripQuotes(arg.value.get), " ")
+            case None ⇒ Seq("-ea", "-Xms1024m")
+        }
+
+        checkFilePath(cfgPath)
+
+        val sep = System.getProperty("path.separator")
+
+        var validatorArgs = mutable.ArrayBuffer.empty[String]
+
+        validatorArgs += JAVA
+        validatorArgs ++= jvmOpts
+
+        if (cfgPath.isDefined)
+            validatorArgs += s"-DNLPCRAFT_PROBE_CONFIG=${cfgPath.get}"
+
+        if (mdls != null)
+            validatorArgs += s"-DNLPCRAFT_TEST_MODELS=$mdls"
+
+        validatorArgs += "-cp"
+        validatorArgs += (if (addCp == null) JAVA_CP else s"$JAVA_CP$sep$addCp".replace(s"$sep$sep", sep))
+        validatorArgs += "org.apache.nlpcraft.model.tools.test.NCTestAutoModelValidator"
+
+        val validatorPb = new ProcessBuilder(validatorArgs.asJava)
+
+        validatorPb.directory(new File(INSTALL_HOME))
+        validatorPb.inheritIO()
+
+        try {
+            validatorPb.start().onExit().get()
+        }
+        catch {
+            case _: InterruptedException ⇒ () // Ignore.
+            case e: Exception ⇒ error(s"Failed to run model validator: ${y(e.getLocalizedMessage)}")
+        }
     }
 
     /**
@@ -1923,7 +585,7 @@ object NCCli extends App {
      * @param args Arguments, if any, for this command.
      * @param repl Whether or not running from REPL.
      */
-    private def cmdStartProbe(cmd: Command, args: Seq[Argument], repl: Boolean): Unit = {
+    private [cmdline] def cmdStartProbe(cmd: Command, args: Seq[Argument], repl: Boolean): Unit = {
         // Ensure that there is a local server running since probe
         // cannot finish its start unless there's a server to connect to.
         // TODO: in the future - we'll need add support here for remote servers.
@@ -1959,7 +621,10 @@ object NCCli extends App {
 
         // Ensure that there isn't another local probe running.
         loadProbeBeacon() match {
-            case Some(b) ⇒ throw new IllegalStateException(s"Existing probe (pid ${c(b.pid)}) detected.")
+            case Some(b) ⇒ throw new IllegalStateException(
+                s"Existing probe (pid ${c(b.pid)}) detected. " +
+                s"Use ${c("'stop-probe'")} command to stop it, if necessary."
+            )
             case None ⇒ ()
         }
 
@@ -2164,7 +829,7 @@ object NCCli extends App {
      * @param args Arguments, if any, for this command.
      * @param repl Whether or not executing from REPL.
      */
-    private def cmdTailServer(cmd: Command, args: Seq[Argument], repl: Boolean): Unit = {
+    private [cmdline] def cmdTailServer(cmd: Command, args: Seq[Argument], repl: Boolean): Unit = {
         val lines = args.find(_.parameter.id == "lines") match {
             case Some(arg) ⇒
                 try
@@ -2190,7 +855,7 @@ object NCCli extends App {
      * @param args Arguments, if any, for this command.
      * @param repl Whether or not executing from REPL.
      */
-    private def cmdTailProbe(cmd: Command, args: Seq[Argument], repl: Boolean): Unit = {
+    private [cmdline] def cmdTailProbe(cmd: Command, args: Seq[Argument], repl: Boolean): Unit = {
         val lines = args.find(_.parameter.id == "lines") match {
             case Some(arg) ⇒
                 try
@@ -2216,7 +881,7 @@ object NCCli extends App {
      * @param args Arguments, if any, for this command.
      * @param repl Whether or not executing from REPL.
      */
-    private def cmdPingServer(cmd: Command, args: Seq[Argument], repl: Boolean): Unit = {
+    private [cmdline] def cmdPingServer(cmd: Command, args: Seq[Argument], repl: Boolean): Unit = {
         val endpoint = getRestEndpointFromBeacon
 
         val num = args.find(_.parameter.id == "number") match {
@@ -2336,15 +1001,24 @@ object NCCli extends App {
                 state.isServerOnline = true
 
                 try {
-                    val baseUrl = "http://" + beacon.restEndpoint
+                    val baseUrl = "http://" + beacon.restEndpoint // TODO: https?
 
                     // Attempt to signin with the default account.
                     if (autoSignIn && state.accessToken.isEmpty)
                         httpPostResponseJson(
                             baseUrl,
                             "signin",
-                            "{\"email\": \"admin@admin.com\", \"passwd\": \"admin\"}") match {
-                            case Some(json) ⇒ state.accessToken = Option(Try(U.getJsonStringField(json, "acsTok")).getOrElse(null))
+                            s"""{"email": "$DFLT_USER_EMAIL", "passwd": "$DFLT_USER_PASSWD"}""") match {
+                            case Some(json) ⇒
+                                Option(Try(U.getJsonStringField(json, "acsTok"))) match {
+                                    case Some(tok) ⇒
+                                        state.userEmail = Some(DFLT_USER_EMAIL)
+                                        state.accessToken = Some(tok.get)
+                                    case None ⇒
+                                        state.userEmail = None
+                                        state.accessToken = None
+
+                                }
                             case None ⇒ ()
                         }
 
@@ -2442,7 +1116,7 @@ object NCCli extends App {
      * @param args Arguments, if any, for this command.
      * @param repl Whether or not executing from REPL.
      */
-    private def cmdQuit(cmd: Command, args: Seq[Argument], repl: Boolean): Unit =
+    private [cmdline] def cmdQuit(cmd: Command, args: Seq[Argument], repl: Boolean): Unit =
         if (repl) {
             loadServerBeacon() match {
                 case Some(b) ⇒ warn(s"Local server (pid ${c(b.pid)}) is still running.")
@@ -2460,7 +1134,7 @@ object NCCli extends App {
      * @param args Arguments, if any, for this command.
      * @param repl Whether or not executing from REPL.
      */
-    private def cmdStop(cmd: Command, args: Seq[Argument], repl: Boolean): Unit = {
+    private [cmdline] def cmdStop(cmd: Command, args: Seq[Argument], repl: Boolean): Unit = {
         doCommand(Seq(STOP_SRV_CMD.name), repl)
         doCommand(Seq(STOP_PRB_CMD.name), repl)
     }
@@ -2470,7 +1144,7 @@ object NCCli extends App {
      * @param args Arguments, if any, for this command.
      * @param repl Whether or not executing from REPL.
      */
-    private def cmdStopServer(cmd: Command, args: Seq[Argument], repl: Boolean): Unit =
+    private [cmdline] def cmdStopServer(cmd: Command, args: Seq[Argument], repl: Boolean): Unit =
         loadServerBeacon() match {
             case Some(beacon) ⇒
                 val pid = beacon.pid
@@ -2497,7 +1171,7 @@ object NCCli extends App {
      * @param args Arguments, if any, for this command.
      * @param repl Whether or not executing from REPL.
      */
-    private def cmdStopProbe(cmd: Command, args: Seq[Argument], repl: Boolean): Unit =
+    private [cmdline] def cmdStopProbe(cmd: Command, args: Seq[Argument], repl: Boolean): Unit =
         loadProbeBeacon() match {
             case Some(beacon) ⇒
                 val pid = beacon.pid
@@ -2522,7 +1196,7 @@ object NCCli extends App {
      * @param args Arguments, if any, for this command.
      * @param repl Whether or not executing from REPL.
      */
-    private def cmdNoLogo(cmd: Command, args: Seq[Argument], repl: Boolean): Unit = {
+    private [cmdline] def cmdNoLogo(cmd: Command, args: Seq[Argument], repl: Boolean): Unit = {
         warn("This command should be used together with other command in a command line mode.")
     }
 
@@ -2531,7 +1205,7 @@ object NCCli extends App {
      * @param args Arguments, if any, for this command.
      * @param repl Whether or not executing from REPL.
      */
-    private def cmdNoAnsi(cmd: Command, args: Seq[Argument], repl: Boolean): Unit =
+    private [cmdline] def cmdNoAnsi(cmd: Command, args: Seq[Argument], repl: Boolean): Unit =
         NCAnsi.setEnabled(false)
 
     /**
@@ -2539,7 +1213,7 @@ object NCCli extends App {
      * @param args Arguments, if any, for this command.
      * @param repl Whether or not executing from REPL.
      */
-    private def cmdAnsi(cmd: Command, args: Seq[Argument], repl: Boolean): Unit =
+    private [cmdline] def cmdAnsi(cmd: Command, args: Seq[Argument], repl: Boolean): Unit =
         NCAnsi.setEnabled(true)
 
     /**
@@ -2547,7 +1221,7 @@ object NCCli extends App {
      * @param args Arguments, if any, for this command.
      * @param repl Whether or not executing from REPL.
      */
-    private def cmdHelp(cmd: Command, args: Seq[Argument], repl: Boolean): Unit = {
+    private [cmdline] def cmdHelp(cmd: Command, args: Seq[Argument], repl: Boolean): Unit = {
         /**
          *
          */
@@ -2793,6 +1467,15 @@ object NCCli extends App {
         state.probes.foreach(addProbeToTable(tbl, _))
 
         logln(s"Connected probes (${state.probes.size}):\n${tbl.toString}")
+
+        if (state.accessToken.isDefined) {
+            val tbl = new NCAsciiTable()
+
+            tbl += (s"${g("Email")}", state.userEmail.get)
+            tbl += (s"${g("Access token")}", state.accessToken.get)
+
+            logln(s"Signed in user account:\n$tbl")
+        }
     }
 
     /**
@@ -2801,7 +1484,7 @@ object NCCli extends App {
      * @param args Arguments, if any, for this command.
      * @param repl Whether or not executing from REPL.
      */
-    private def cmdInfo(cmd: Command, args: Seq[Argument], repl: Boolean): Unit = {
+    private [cmdline] def cmdInfo(cmd: Command, args: Seq[Argument], repl: Boolean): Unit = {
         doCommand(Seq(SRV_INFO_CMD.name), repl)
         doCommand(Seq(PRB_INFO_CMD.name), repl)
     }
@@ -2812,7 +1495,7 @@ object NCCli extends App {
      * @param args Arguments, if any, for this command.
      * @param repl Whether or not executing from REPL.
      */
-    private def cmdInfoServer(cmd: Command, args: Seq[Argument], repl: Boolean): Unit = {
+    private [cmdline] def cmdInfoServer(cmd: Command, args: Seq[Argument], repl: Boolean): Unit = {
         loadServerBeacon() match {
             case Some(beacon) ⇒ logServerInfo(beacon)
             case None ⇒ throw NoLocalServer()
@@ -2825,7 +1508,7 @@ object NCCli extends App {
      * @param args Arguments, if any, for this command.
      * @param repl Whether or not executing from REPL.
      */
-    private def cmdInfoProbe(cmd: Command, args: Seq[Argument], repl: Boolean): Unit = {
+    private [cmdline] def cmdInfoProbe(cmd: Command, args: Seq[Argument], repl: Boolean): Unit = {
         loadProbeBeacon() match {
             case Some(beacon) ⇒ logProbeInfo(beacon)
             case None ⇒ throw NoLocalProbe()
@@ -2838,7 +1521,7 @@ object NCCli extends App {
      * @param args Arguments, if any, for this command.
      * @param repl Whether or not executing from REPL.
      */
-    private def cmdCls(cmd: Command, args: Seq[Argument], repl: Boolean): Unit =
+    private [cmdline] def cmdClear(cmd: Command, args: Seq[Argument], repl: Boolean): Unit =
         term.puts(Capability.clear_screen)
 
     /**
@@ -2855,11 +1538,11 @@ object NCCli extends App {
      * @param args Arguments, if any, for this command.
      * @param repl Whether or not executing from REPL.
      */
-    private def cmdSignIn(cmd: Command, args: Seq[Argument], repl: Boolean): Unit =
+    private [cmdline] def cmdSignIn(cmd: Command, args: Seq[Argument], repl: Boolean): Unit =
         state.accessToken match {
             case None ⇒
-                val email = args.find(_.parameter.id == "email").flatMap(_.value).getOrElse("admin@admin.com")
-                val passwd = args.find(_.parameter.id == "passwd").flatMap(_.value).getOrElse("admin")
+                val email = args.find(_.parameter.id == "email").flatMap(_.value).getOrElse(DFLT_USER_EMAIL)
+                val passwd = args.find(_.parameter.id == "passwd").flatMap(_.value).getOrElse(DFLT_USER_PASSWD)
 
                 httpRest(
                     cmd,
@@ -2881,7 +1564,7 @@ object NCCli extends App {
      * @param args Arguments, if any, for this command.
      * @param repl Whether or not executing from REPL.
      */
-    private def cmdSignOut(cmd: Command, args: Seq[Argument], repl: Boolean): Unit =
+    private [cmdline] def cmdSignOut(cmd: Command, args: Seq[Argument], repl: Boolean): Unit =
         state.accessToken match {
             case Some(acsTok) ⇒
                 httpRest(
@@ -2920,7 +1603,7 @@ object NCCli extends App {
      * @param args Arguments, if any, for this command.
      * @param repl Whether or not executing from REPL.
      */
-    private def cmdSqlGen(cmd: Command, args: Seq[Argument], repl: Boolean): Unit = {
+    private [cmdline] def cmdSqlGen(cmd: Command, args: Seq[Argument], repl: Boolean): Unit = {
         val nativeArgs = args.flatMap { arg ⇒
             val param = arg.parameter.names.head
 
@@ -2943,7 +1626,7 @@ object NCCli extends App {
      * @param args Arguments, if any, for this command.
      * @param repl Whether or not executing from REPL.
      */
-    private def cmdSugSyn(cmd: Command, args: Seq[Argument], repl: Boolean): Unit =
+    private [cmdline] def cmdSugSyn(cmd: Command, args: Seq[Argument], repl: Boolean): Unit =
         state.accessToken match {
             case Some(acsTok) ⇒
                 val mdlId = args.find(_.parameter.id == "mdlId").flatMap(_.value).getOrElse(throw MissingParameter(cmd, "mdlId"))
@@ -2970,7 +1653,7 @@ object NCCli extends App {
      * @param args Arguments, if any, for this command.
      * @param repl Whether or not executing from REPL.
      */
-    private def cmdAsk(cmd: Command, args: Seq[Argument], repl: Boolean): Unit =
+    private [cmdline] def cmdAsk(cmd: Command, args: Seq[Argument], repl: Boolean): Unit =
         state.accessToken match {
             case Some(acsTok) ⇒
                 val mdlId = args.find(_.parameter.id == "mdlId").flatMap(_.value).getOrElse(throw MissingParameter(cmd, "mdlId"))
@@ -3001,7 +1684,7 @@ object NCCli extends App {
      * @param args Arguments, if any, for this command.
      * @param repl Whether or not executing from REPL.
      */
-    private def cmdCall(cmd: Command, args: Seq[Argument], repl: Boolean): Unit = {
+    private [cmdline] def cmdCall(cmd: Command, args: Seq[Argument], repl: Boolean): Unit = {
         val normArgs = args.filter(!_.parameter.synthetic)
         val synthArgs = args.filter(_.parameter.synthetic)
 
@@ -3052,7 +1735,7 @@ object NCCli extends App {
      * @param args Arguments, if any, for this command.
      * @param repl Whether or not executing from REPL.
      */
-    private def cmdRest(cmd: Command, args: Seq[Argument], repl: Boolean): Unit = {
+    private [cmdline] def cmdRest(cmd: Command, args: Seq[Argument], repl: Boolean): Unit = {
         val path = args.find(_.parameter.id == "path").getOrElse(throw MissingParameter(cmd, "path")).value.get
         val json = stripQuotes(args.find(_.parameter.id == "json").getOrElse(throw MissingParameter(cmd, "json")).value.get)
 
@@ -3224,7 +1907,7 @@ object NCCli extends App {
       * @param args Arguments, if any, for this command.
       * @param repl Whether or not executing from REPL.
       */
-    private def cmdGenModel(cmd: Command, args: Seq[Argument], repl: Boolean): Unit = {
+    private [cmdline] def cmdGenModel(cmd: Command, args: Seq[Argument], repl: Boolean): Unit = {
         val filePath = get(cmd, args, "filePath")
         val overrideFlag = get(cmd, args,"override", "false").toLowerCase
         val modelId = get(cmd, args,"modelId")
@@ -3274,7 +1957,7 @@ object NCCli extends App {
       * @param args Arguments, if any, for this command.
       * @param repl Whether or not executing from REPL.
       */
-    private def cmdGenProject(cmd: Command, args: Seq[Argument], repl: Boolean): Unit = {
+    private [cmdline] def cmdGenProject(cmd: Command, args: Seq[Argument], repl: Boolean): Unit = {
         val outputDir = get(cmd, args, "outputDir", ".")
         val baseName = get(cmd, args,"baseName")
         val lang = get(cmd, args,"lang", "java").toLowerCase
@@ -3506,10 +2189,14 @@ object NCCli extends App {
         }
 
         if (resp.code == 200) {
-            if (path == "signin")
+            if (path == "signin") {
+                state.userEmail = Some(U.getJsonStringField(json, "email"))
                 state.accessToken = Some(U.getJsonStringField(resp.data, "acsTok"))
-            else if (path == "signout")
+            }
+            else if (path == "signout") {
+                state.userEmail = None
                 state.accessToken = None
+            }
         }
     }
 
@@ -3527,7 +2214,7 @@ object NCCli extends App {
         }
 
         if (state.accessToken.isDefined)
-            logln(s"Server signed in with default '${c("admin@admin.com")}' user.")
+            logln(s"Server signed in with default '${c(DFLT_USER_EMAIL)}' user.")
 
         val parser = new DefaultParser()
 
@@ -3692,7 +2379,7 @@ object NCCli extends App {
                                         if (path == "signin") {
                                             candidates.add(
                                                 mkCandidate(
-                                                    disp = "--email=admin@admin.com",
+                                                    disp = s"--email=$DFLT_USER_EMAIL",
                                                     grp = DFTL_USER_GRP,
                                                     desc = null,
                                                     completed = true
@@ -3700,7 +2387,7 @@ object NCCli extends App {
                                             )
                                             candidates.add(
                                                 mkCandidate(
-                                                    disp = "--passwd=admin",
+                                                    disp = s"--passwd=$DFLT_USER_PASSWD",
                                                     grp = DFTL_USER_GRP,
                                                     desc = null,
                                                     completed = true
@@ -3772,15 +2459,14 @@ object NCCli extends App {
 
         while (!exit) {
             val rawLine = try {
-                val srvStr = bo(s"${if (state.isServerOnline) s"ON " else s"OFF "}")
-                val prbStr = bo(s"${if (state.isProbeOnline) s"ON " else s"OFF "}")
-                val acsTokStr = bo(s"${state.accessToken.getOrElse("n/a")} ")
+                val acsTokStr = bo(s"${state.accessToken.getOrElse("N/A")} ")
 
-                val prompt1 = rb(w(s" srv:$srvStr")) + rb(w(s"prb:$prbStr")) // Server status.
-                val prompt2 = wb(k(s" acsTok: $acsTokStr")) // Access toke, if any.
-                val prompt3 = kb(g(s" ${Paths.get("").toAbsolutePath} ")) // Current working directory.
+                val prompt1 = if (state.isServerOnline) gb(k(s" server: ${BO}ON$RST$GB ")) else rb(w(s" server: ${BO}OFF$RST$RB "))
+                val prompt2 = if (state.isProbeOnline) gb(k(s" probe: ${BO}ON$RST$GB ")) else rb(w(s" probe: ${BO}OFF$RST$RB "))
+                val prompt3 = wb(k(s" acsTok: $acsTokStr")) // Access token, if any.
+                val prompt4 = kb(g(s" ${Paths.get("").toAbsolutePath} ")) // Current working directory.
 
-                reader.printAbove("\n" + prompt1 + ":" + prompt2 + ":" + prompt3)
+                reader.printAbove("\n" + prompt1 + ":" + prompt2 + ":" + prompt3 + ":" + prompt4)
                 reader.readLine(s"${g(">")} ")
             }
             catch {
@@ -3832,7 +2518,7 @@ object NCCli extends App {
      * @param args Arguments, if any, for this command.
      * @param repl Whether or not executing from REPL.
      */
-    private def cmdVersion(cmd: Command, args: Seq[Argument], repl: Boolean): Unit =
+    private [cmdline] def cmdVersion(cmd: Command, args: Seq[Argument], repl: Boolean): Unit =
         if (args.isEmpty)
             logln((
                 new NCAsciiTable
diff --git a/nlpcraft/src/main/scala/org/apache/nlpcraft/model/tools/cmdline/NCCliCommands.scala b/nlpcraft/src/main/scala/org/apache/nlpcraft/model/tools/cmdline/NCCliCommands.scala
new file mode 100644
index 0000000..9ccdce8
--- /dev/null
+++ b/nlpcraft/src/main/scala/org/apache/nlpcraft/model/tools/cmdline/NCCliCommands.scala
@@ -0,0 +1,1135 @@
+/*
+ * 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.
+ */
+
+package org.apache.nlpcraft.model.tools.cmdline
+
+import org.apache.commons.lang3.SystemUtils
+import org.apache.nlpcraft.common._
+import org.apache.nlpcraft.common.version.NCVersion
+
+// Parsed command line argument.
+private [cmdline] case class Argument(
+    parameter: Parameter, // Formal parameter this argument refers to.
+    value: Option[String]
+) {
+    /**
+     * Gets the original argument string.
+     *
+     * @return
+     */
+    def origString(): String =  value match {
+        case Some(s) ⇒ s"${parameter.names.head}=$s"
+        case None ⇒ parameter.names.head
+    }
+}
+
+// Single CLI command.
+private [cmdline] case class Command(
+    name: String,
+    group: String,
+    synopsis: String,
+    desc: Option[String] = None,
+    params: Seq[Parameter] = Seq.empty,
+    examples: Seq[Example] = Seq.empty,
+    body: (Command, Seq[Argument], Boolean) ⇒ Unit
+) {
+    /**
+     *
+     * @param name
+     * @return
+     */
+    def findParameterByNameOpt(name: String): Option[Parameter] =
+        params.find(_.names.contains(name))
+
+    /**
+     *
+     * @param id
+     * @return
+     */
+    def findParameterByIdOpt(id: String): Option[Parameter] =
+        params.find(_.id == id)
+
+    /**
+     *
+     * @param id
+     * @return
+     */
+    def findParameterById(id: String): Parameter =
+        findParameterByIdOpt(id).get
+}
+
+// Single command's example.
+private [cmdline] case class Example(
+    usage: Seq[String],
+    desc: String
+)
+
+// Single command's parameter.
+private [cmdline] case class Parameter(
+    id: String,
+    names: Seq[String],
+    value: Option[String] = None,
+    optional: Boolean = false, // Mandatory by default.
+    synthetic: Boolean = false,
+    desc: String
+)
+
+private [cmdline] object NCCliCommands {
+    private final lazy val SCRIPT_NAME = U.sysEnv("NLPCRAFT_CLI_SCRIPT").getOrElse(s"nlpcraft.${if (SystemUtils.IS_OS_UNIX) "sh" else "cmd"}")
+    private final lazy val PROMPT = if (SCRIPT_NAME.endsWith("cmd")) ">" else "$"
+    private final lazy val VER = NCVersion.getCurrent
+
+    //noinspection DuplicatedCode
+    // All supported commands.
+    private [cmdline] final val CMDS = Seq(
+        Command(
+            name = "rest",
+            group = "2. REST Commands",
+            synopsis = s"REST call in a convenient way for command line mode.",
+            desc = Some(
+                s"When using this command you supply all call parameters as a single ${y("'--json'")} parameter with a JSON string. " +
+                s"In REPL mode, you can hit ${rv(" Tab ")} to see auto-suggestion and auto-completion candidates for " +
+                s"commonly used paths. However, ${y("'call'")} command provides more convenient way to issue REST " +
+                s"calls when in REPL mode."
+            ),
+            body = NCCli.cmdRest,
+            params = Seq(
+                Parameter(
+                    id = "path",
+                    names = Seq("--path", "-p"),
+                    value = Some("path"),
+                    desc =
+                        s"REST path, e.g. ${y("'signin'")} or ${y("'ask/sync'")}. " +
+                        s"Note that you don't need supply '/' at the beginning. " +
+                        s"See more details at https://nlpcraft.apache.org/using-rest.html " +
+                        s"In REPL mode, hit ${rv(" Tab ")} to see auto-suggestion for possible REST paths."
+                ),
+                Parameter(
+                    id = "json",
+                    names = Seq("--json", "-j"),
+                    value = Some("'json'"),
+                    desc =
+                        s"REST call parameters as JSON object. Since standard JSON only supports double " +
+                        s"quotes the entire JSON string should be enclosed in single quotes. You can " +
+                        s"find full OpenAPI specification for NLPCraft REST API at " +
+                        s"https://nlpcraft.apache.org/using-rest.html"
+                )
+            ),
+            examples = Seq(
+                Example(
+                    usage = Seq(
+                        s"$$ nlpcraft.sh rest ",
+                        "  -p=signin",
+                        "  -j='{\"email\": \"admin@admin.com\", \"passwd\": \"admin\"}'"
+                    ),
+                    desc = s"${bo("Unix/Linux:")} issues ${y("'signin'")} REST call with given JSON payload."
+                ),
+                Example(
+                    usage = Seq(
+                        s"> nlpcraft.cmd rest ",
+                        "  -p=signin",
+                        "  -j='{\\\"email\\\": \\\"admin@admin.com\\\", \\\"passwd\\\": \\\"admin\\\"}'"
+                    ),
+                    desc =
+                        s"${bo("Windows:")} issues ${y("'signin'")} REST call with given JSON payload. " +
+                        s"Note the necessary escaping of double quotes."
+                )
+            )
+        ),
+        Command(
+            name = "signin",
+            group = "2. REST Commands",
+            synopsis = s"Wrapper for ${c("'/signin'")} REST call.",
+            desc = Some(
+                s"If no arguments provided, it signs in with the " +
+                    s"default 'admin@admin.com' user account. NOTE: please make sure to remove this account when " +
+                    s"running in production."
+            ),
+            body = NCCli.cmdSignIn,
+            params = Seq(
+                Parameter(
+                    id = "email",
+                    names = Seq("--email", "-e"),
+                    value = Some("email"),
+                    optional = true,
+                    desc =
+                        s"Email of the user. If not provided, 'admin@admin.com' will be used."
+                ),
+                Parameter(
+                    id = "passwd",
+                    names = Seq("--passwd", "-p"),
+                    value = Some("****"),
+                    optional = true,
+                    desc =
+                        s"User password to sign in. If not provided, the default password will be used."
+                )
+            ),
+            examples = Seq(
+                Example(
+                    usage = Seq(
+                        s"$PROMPT $SCRIPT_NAME signin"
+                    ),
+                    desc = s"Signs in with the default ${c("admin@admin.com")} user account."
+                )
+            )
+        ),
+        Command(
+            name = "signout",
+            group = "2. REST Commands",
+            synopsis = s"Wrapper for ${c("'/signout'")} REST call in REPL mode.",
+            desc = Some(
+                s"Signs out currently signed in user. Note that this command makes sense only in REPL mode."
+            ),
+            body = NCCli.cmdSignOut,
+            examples = Seq(
+                Example(
+                    usage = Seq(
+                        s"$PROMPT $SCRIPT_NAME signout"
+                    ),
+                    desc = s"Signs out currently signed in user, if any."
+                )
+            )
+        ),
+        Command(
+            name = "call",
+            group = "2. REST Commands",
+            synopsis = s"REST call in a convenient way for REPL mode.",
+            desc = Some(
+                s"When using this command you supply all call parameters separately through their own parameters named " +
+                    s"after their corresponding parameters in REST specification. " +
+                    s"In REPL mode, hit ${rv(" Tab ")} to see auto-suggestion and " +
+                    s"auto-completion candidates for commonly used paths and call parameters."
+            ),
+            body = NCCli.cmdCall,
+            params = Seq(
+                Parameter(
+                    id = "path",
+                    names = Seq("--path", "-p"),
+                    value = Some("path"),
+                    desc =
+                        s"REST path, e.g. ${y("'signin'")} or ${y("'ask/sync'")}. " +
+                        s"Note that you don't need supply '/' at the beginning. " +
+                        s"See more details at https://nlpcraft.apache.org/using-rest.html " +
+                        s"In REPL mode, hit ${rv(" Tab ")} to see auto-suggestion for possible REST paths."
+                ),
+                Parameter(
+                    id = "xxx",
+                    names = Seq("--xxx"),
+                    value = Some("value"),
+                    optional = true,
+                    synthetic = true,
+                    desc =
+                        s"${y("'xxx'")} name corresponds to the REST call parameter that can be found at https://nlpcraft.apache.org/using-rest.html " +
+                        s"The value of this parameter should be a valid JSON value using valid JSON syntax. Note that strings " +
+                        s"don't have to be in double quotes. JSON objects and arrays should be specified as a JSON string in single quotes. You can have " +
+                        s"as many ${y("'--xxx=value'")} parameters as requires by the ${y("'--path'")} parameter. " +
+                        s"In REPL mode, hit ${rv(" Tab ")} to see auto-suggestion for possible parameters and their values."
+                )
+            ),
+            examples = Seq(
+                Example(
+                    usage = Seq(
+                        s"$PROMPT $SCRIPT_NAME call -p=signin",
+                        "  --email=admin@admin.com",
+                        "  --passwd=admin"
+                    ),
+                    desc =
+                        s"Issues ${y("'signin'")} REST call with given JSON payload provided as a set of parameters. " +
+                        s"Note that ${y("'--email'")} and ${y("'--passwd'")} parameters correspond to the REST call " +
+                        s"specification for ${y("'/signin'")} path."
+                ),
+                Example(
+                    usage = Seq(
+                        s"$$ nlpcraft.sh call --path=ask/sync",
+                        "  --acsTok=qwerty123456",
+                        "  --txt=\"User request\"",
+                        "  --mdlId=my.model.id",
+                        "  --data='{\"data1\": true, \"data2\": 123, \"data3\": \"some text\"}'",
+                        "  --enableLog=false"
+                    ),
+                    desc =
+                        s"${bo("Unix/Linux:")} issues ${y("'ask/sync'")} REST call with given JSON payload provided as a set of parameters."
+                ),
+                Example(
+                    usage = Seq(
+                        s"> nlpcraft.cmd call --path=ask/sync",
+                        "  --acsTok=qwerty123456",
+                        "  --txt=\"User request\"",
+                        "  --mdlId=my.model.id",
+                        "  --data='{\\\"data1\\\": true, \\\"data2\\\": 123, \\\"data3\\\": \\\"some text\\\"}'",
+                        "  --enableLog=false"
+                    ),
+                    desc =
+                        s"${bo("Windows:")} issues ${y("'ask/sync'")} REST call with given JSON payload provided " +
+                        s"as a set of parameters. Note the necessary double quote escaping."
+                )
+            )
+        ),
+        Command(
+            name = "ask",
+            group = "2. REST Commands",
+            synopsis = s"Wrapper for ${c("'/ask/sync'")} REST call.",
+            desc = Some(
+                s"Requires user to be already signed in. This command ${bo("only makes sense in the REPL mode")} as " +
+                s"it requires user to be signed in. REPL session keeps the currently active access " +
+                s"token after user signed in. For command line mode, use ${c("'rest'")} command with " +
+                s"corresponding parameters."
+            ),
+            body = NCCli.cmdAsk,
+            params = Seq(
+                Parameter(
+                    id = "mdlId",
+                    names = Seq("--mdlId"),
+                    value = Some("model.id"),
+                    desc =
+                        s"ID of the data model to send the request to. " +
+                        s"In REPL mode, hit ${rv(" Tab ")} to see auto-suggestion for possible model IDs."
+                ),
+                Parameter(
+                    id = "txt",
+                    names = Seq("--txt"),
+                    value = Some("txt"),
+                    desc =
+                        s"Text of the question."
+                ),
+                Parameter(
+                    id = "data",
+                    names = Seq("--data"),
+                    value = Some("'{}'"),
+                    optional = true,
+                    desc = s"Additional JSON data with maximum JSON length of 512000 bytes. Default is ${c("'null'")}."
+                ),
+                Parameter(
+                    id = "enableLog",
+                    names = Seq("--enableLog"),
+                    value = Some("true|false"),
+                    optional = true,
+                    desc = s"Flag to enable detailed processing log to be returned with the result. Default is ${c("'false'")}."
+                )
+            ),
+            examples = Seq(
+                Example(
+                    usage = Seq(
+                        s"""> ask --txt="User request" --mdlId=my.model.id"""
+                    ),
+                    desc =
+                        s"Issues ${y("'ask/sync'")} REST call with given text and model ID."
+                )
+            )
+        ),
+        Command(
+            name = "gen-sql",
+            group = "3. Miscellaneous",
+            synopsis = s"Generates NLPCraft model stub from SQL databases.",
+            desc = Some(
+                s"You can choose database schema, set of tables and columns for which you want to generate NLPCraft " +
+                s"model. After the model is generated you can further configure and customize it for your specific needs. " +
+                s"Find more information at https://nlpcraft.apache.org/tools/sql_model_gen.html"
+            ),
+            body = NCCli.cmdSqlGen,
+            params = Seq(
+                Parameter(
+                    id = "url",
+                    names = Seq("--url", "-r"),
+                    value = Some("url"),
+                    desc =
+                        s"Database JDBC URL."
+                ),
+                Parameter(
+                    id = "driver",
+                    names = Seq("--driver", "-d"),
+                    value = Some("class"),
+                    desc =
+                        s"Mandatory JDBC driver class. Note that 'class' must be a fully qualified class name. " +
+                        s"It should also be available on the classpath."
+                ),
+                Parameter(
+                    id = "schema",
+                    names = Seq("--schema", "-s"),
+                    value = Some("schema"),
+                    desc =
+                        s"Database schema to scan."
+                ),
+                Parameter(
+                    id = "out",
+                    names = Seq("--out", "-o"),
+                    value = Some("filename"),
+                    desc =
+                        s"Name of the output JSON or YAML model file. " +
+                        s"It should have one of the following extensions: .js, .json, .yml, or .yaml. " +
+                        s"File extension determines the output file format."
+                ),
+                Parameter(
+                    id = "user",
+                    names = Seq("--user", "-u"),
+                    value = Some("username"),
+                    optional = true,
+                    desc = s"Database user name."
+                ),
+                Parameter(
+                    id = "password",
+                    names = Seq("--password", "-w"),
+                    value = Some("password"),
+                    optional = true,
+                    desc = s"Database password."
+                ),
+                Parameter(
+                    id = "modelId",
+                    names = Seq("--model-id", "-x"),
+                    value = Some("id"),
+                    optional = true,
+                    desc = s"Generated model ID. By default, the model ID is ${c("'sql.model.id'")}."
+                ),
+                Parameter(
+                    id = "modelVer",
+                    names = Seq("--model-ver", "-v"),
+                    value = Some("version"),
+                    optional = true,
+                    desc = s"Generated model version. By default, the model version is ${c("'1.0.0-timestamp'")}."
+                ),
+                Parameter(
+                    id = "modelName",
+                    names = Seq("--model-name", "-n"),
+                    value = Some("name"),
+                    optional = true,
+                    desc = s"Generated model name. By default, the model name is ${c("'SQL-based-model'")}."
+                ),
+                Parameter(
+                    id = "exclude",
+                    names = Seq("--exclude", "-e"),
+                    value = Some("list"),
+                    optional = true,
+                    desc =
+                        s"Semicolon-separate list of tables and/or columns to exclude. By default, none of the " +
+                        s"tables and columns in the schema are excluded. See ${c("--help")} parameter to get more details."
+                ),
+                Parameter(
+                    id = "include",
+                    names = Seq("--include", "-i"),
+                    value = Some("list"),
+                    optional = true,
+                    desc =
+                        s"Semicolon-separate list of tables and/or columns to include. By default, all of the " +
+                        s"tables and columns in the schema are included. See ${c("--help")} parameter to get more details."
+                ),
+                Parameter(
+                    id = "prefix",
+                    names = Seq("--prefix", "-f"),
+                    value = Some("list"),
+                    optional = true,
+                    desc =
+                        s"Comma-separate list of table or column name prefixes to remove. These prefixes will be " +
+                        s"removed when name is used for model elements synonyms. By default, no prefixes will be removed."
+                ),
+                Parameter(
+                    id = "suffix",
+                    names = Seq("--suffix", "-q"),
+                    value = Some("list"),
+                    optional = true,
+                    desc =
+                        s"Comma-separate list of table or column name suffixes to remove. These suffixes will be " +
+                        s"removed when name is used for model elements synonyms. By default, no suffixes will be removed."
+                ),
+                Parameter(
+                    id = "synonyms",
+                    names = Seq("--synonyms", "-y"),
+                    value = Some("true|false"),
+                    optional = true,
+                    desc = s"Flag on whether or not to generated auto synonyms for the model elements. Default is ${c("'true'")}."
+                ),
+                Parameter(
+                    id = "override",
+                    names = Seq("--override", "-z"),
+                    value = Some("true|false"),
+                    optional = true,
+                    desc =
+                        s"Flag to determine whether or not to override output file if it already exist. " +
+                        s"If override is disabled (default) and output file exists - a unique file name " +
+                        s"will be used instead. Default is ${c("'false'")}."
+                ),
+                Parameter(
+                    id = "parent",
+                    names = Seq("--parent", "-p"),
+                    value = Some("true|false"),
+                    optional = true,
+                    desc =
+                        s"Flag on whether or not to use element's parent relationship for defining " +
+                        s"SQL columns and their containing (i.e. parent) tables. Default is ${c("'false'")}."
+                ),
+                Parameter(
+                    id = "help",
+                    names = Seq("--help", "-h"),
+                    optional = true,
+                    desc =
+                        s"Gets extended help and usage information for the ${c("'gen-sql'")} command. " +
+                        s"Includes information on how to run this tool standalone."
+                )
+            ),
+            examples = Seq(
+                Example(
+                    usage = Seq(
+                        s"$PROMPT $SCRIPT_NAME gen-sql --help"
+                    ),
+                    desc =
+                        s"Shows full help and usage information for ${c("gen-sql")} command."
+                ),
+                Example(
+                    usage = Seq(
+                        s"$PROMPT $SCRIPT_NAME gen-sql",
+                        "  --url=jdbc:postgresql://localhost:5432/mydb",
+                        "  --driver=org.postgresql.Driver",
+                        """  --prefix="tbl_, col_"""",
+                        """  --suffix="_tmp, _old, _unused"""",
+                        "  --schema=public",
+                        """  --exclude="#_.+"""",
+                        "  --out=model.json"
+                    ),
+                    desc =
+                        s"Generates model stub from given SQL database connection."
+                )
+            )
+        ),
+        Command(
+            name = "sugsyn",
+            group = "2. REST Commands",
+            synopsis = s"Wrapper for ${c("'/model/sugsyn'")} REST call.",
+            desc = Some(
+                s"Requires user to be already signed in. This command ${bo("only makes sense in the REPL mode")} as " +
+                s"it requires user to be signed in. REPL session keeps the currently active access " +
+                s"token after user signed in. For command line mode, use ${c("'rest'")} command with " +
+                s"corresponding parameters. Note also that it requires a local probe running that hosts " +
+                s"the specified model. Find more information about this tool at https://nlpcraft.apache.org/tools/syn_tool.html"
+            ),
+            body = NCCli.cmdSugSyn,
+            params = Seq(
+                Parameter(
+                    id = "mdlId",
+                    names = Seq("--mdlId"),
+                    value = Some("model.id"),
+                    desc =
+                        s"ID of the model to run synonym suggestion on. " +
+                        s"In REPL mode, hit ${rv(" Tab ")} to see auto-suggestion for possible model IDs. " +
+                        s"Note that the probe hosting this model must be connected to the server."
+                ),
+                Parameter(
+                    id = "minScore",
+                    names = Seq("--minScore"),
+                    value = Some("0.5"),
+                    optional = true,
+                    desc = s"Minimal score to include into the result (from 0 to 1). Default is ${c("0.5")}."
+                )
+            ),
+            examples = Seq(
+                Example(
+                    usage = Seq(
+                        s"""> sugsyn --mdlId=my.model.id"""
+                    ),
+                    desc =
+                        s"Issues ${y("'model/sugsyn'")} REST call with default min score and given model ID."
+                )
+            )
+        ),
+        Command(
+            name = "tail-server",
+            group = "1. Server & Probe Commands",
+            synopsis = s"Shows last N lines from the local server log.",
+            desc = Some(
+                s"Only works for the server started via this script."
+            ),
+            body = NCCli.cmdTailServer,
+            params = Seq(
+                Parameter(
+                    id = "lines",
+                    names = Seq("--lines", "-l"),
+                    value = Some("num"),
+                    desc =
+                        s"Number of the server log lines from the end to display. Default is 20."
+                )
+            ),
+            examples = Seq(
+                Example(
+                    usage = Seq(s"$PROMPT $SCRIPT_NAME tail-server --lines=20 "),
+                    desc = s"Prints last 20 lines from the local server log."
+                )
+            )
+        ),
+        Command(
+            name = "tail-probe",
+            group = "1. Server & Probe Commands",
+            synopsis = s"Shows last N lines from the local probe log.",
+            desc = Some(
+                s"Only works for the probe started via this script."
+            ),
+            body = NCCli.cmdTailProbe,
+            params = Seq(
+                Parameter(
+                    id = "lines",
+                    names = Seq("--lines", "-l"),
+                    value = Some("num"),
+                    desc =
+                        s"Number of the probe log lines from the end to display. Default is 20."
+                )
+            ),
+            examples = Seq(
+                Example(
+                    usage = Seq(s"$PROMPT $SCRIPT_NAME tail-probe --lines=20 "),
+                    desc = s"Prints last 20 lines from the local probe log."
+                )
+            )
+        ),
+        Command(
+            name = "start-server",
+            group = "1. Server & Probe Commands",
+            synopsis = s"Starts local server.",
+            desc = Some(
+                s"Server is started in the external JVM process with both stdout and stderr piped out into log file. " +
+                s"Command will block until the server is started unless ${y("'--no-wait'")} parameter is used or timeout is expired."
+            ),
+            body = NCCli.cmdStartServer,
+            params = Seq(
+                Parameter(
+                    id = "config",
+                    names = Seq("--config", "-c"),
+                    value = Some("path"),
+                    optional = true,
+                    desc =
+                        s"Configuration file path. Server will automatically look for ${y("'nlpcraft.conf'")} " +
+                        s"configuration file in the same directory as NLPCraft JAR file. If the configuration file has " +
+                        s"different name or in different location use this parameter to provide an alternative path. " +
+                        s"Note that the server and the probe can use the same file for their configuration."
+                ),
+                Parameter(
+                    id = "igniteConfig",
+                    names = Seq("--ignite-config", "-i"),
+                    value = Some("path"),
+                    optional = true,
+                    desc =
+                        s"Apache Ignite configuration file path. Note that Apache Ignite is used as a cluster " +
+                        s"computing plane and a default distributed storage. Server will automatically look for " +
+                        s"${y("'ignite.xml'")} configuration file in the same directory as NLPCraft JAR file. If the " +
+                        s"configuration file has different name or in different location use this parameter to " +
+                        s"provide an alternative path."
+                ),
+                Parameter(
+                    id = "jvmopts",
+                    names = Seq("--jvm-opts", "-j"),
+                    value = Some("<jvm flags>"),
+                    optional = true,
+                    desc =
+                        s"Space separated quoted string of JVM flags to use. If not provided, the " +
+                        s"default ${y("'-ea -Xms2048m -XX:+UseG1GC'")} flags will be used."
+                ),
+                Parameter(
+                    id = "noWait",
+                    names = Seq("--no-wait"),
+                    optional = true,
+                    desc =
+                        s"Instructs command not to wait for the server startup and return immediately."
+                ),
+                Parameter(
+                    id = "timeoutMins",
+                    names = Seq("--timeout-mins", "-t"),
+                    optional = true,
+                    value = Some("3"),
+                    desc =
+                        s"Timeout in minutes to wait until server is started. If not specified the default is 2 minutes."
+                )
+            ),
+            examples = Seq(
+                Example(
+                    usage = Seq(s"$PROMPT $SCRIPT_NAME start-server"),
+                    desc = "Starts local server with default configuration."
+                ),
+                Example(
+                    usage = Seq(s"$PROMPT $SCRIPT_NAME start-server -c=/opt/nlpcraft/nlpcraft.conf -t=5"),
+                    desc = "Starts local server with alternative configuration file and timeout of 5 mins."
+                )
+            )
+        ),
+        Command(
+            name = "start-probe",
+            group = "1. Server & Probe Commands",
+            synopsis = s"Starts local probe.",
+            desc = Some(
+                s"Probe is started in the external JVM process with both stdout and stderr piped out into log file. " +
+                s"Command will block until the probe is started unless ${y("'--no-wait'")} parameter is used or timeout is expired."
+            ),
+            body = NCCli.cmdStartProbe,
+            params = Seq(
+                Parameter(
+                    id = "config",
+                    names = Seq("--config", "-c"),
+                    value = Some("path"),
+                    optional = true,
+                    desc =
+                        s"Configuration file path. Probe will automatically look for ${y("'nlpcraft.conf'")} " +
+                        s"configuration file in the same directory as NLPCraft JAR file. If the configuration file has " +
+                        s"different name or in different location use this parameter to provide an alternative path. " +
+                        s"Note that the server and the probe can use the same file for their configuration."
+                ),
+                Parameter(
+                    id = "cp",
+                    names = Seq("--cp", "-p"),
+                    value = Some("path"),
+                    optional = true,
+                    desc =
+                        s"Additional JVM classpath that will be appended to the default NLPCraft JVM classpath. " +
+                        s"Although this configuration property is optional, when deploying your own models you must " +
+                        s"provide this additional classpath for the models and their dependencies this probe will be hosting. " +
+                        s"NOTE: this is only optional if you are running example models shipped with NLPCraft."
+                ),
+                Parameter(
+                    id = "models",
+                    names = Seq("--models", "-m"),
+                    value = Some("<model list>"),
+                    optional = true,
+                    desc =
+                        s"Comma separated list of fully qualified class names for models to deploy. This will override " +
+                        s"${y("'nlpcraft.probe.models'")} configuration property from either default configuration file " +
+                        s"or the one provided by ${y("--config")} parameter. NOTE: if you provide the list of your " +
+                        s"own models here or in configuration file - you must also provide the additional classpath " +
+                        s"for them via ${y("--cp")} parameter."
+                ),
+                Parameter(
+                    id = "jvmopts",
+                    names = Seq("--jvm-opts", "-j"),
+                    value = Some("<jvm flags>"),
+                    optional = true,
+                    desc =
+                        s"Space separated quoted string of JVM flags to use. If not provided, the " +
+                        s"default ${y("'-ea -Xms1024m'")} flags will be used."
+                ),
+                Parameter(
+                    id = "noWait",
+                    names = Seq("--no-wait"),
+                    optional = true,
+                    desc =
+                        s"Instructs command not to wait for the probe startup and return immediately."
+                ),
+                Parameter(
+                    id = "timeoutMins",
+                    names = Seq("--timeout-mins", "-t"),
+                    optional = true,
+                    value = Some("3"),
+                    desc =
+                        s"Timeout to wait until probe is started. If not specified the default is 1 minute."
+                )
+            ),
+            examples = Seq(
+                Example(
+                    usage = Seq(s"$PROMPT $SCRIPT_NAME start-probe"),
+                    desc = "Starts local probe with default configuration and parameters."
+                ),
+                Example(
+                    usage = Seq(
+                        s"$PROMPT $SCRIPT_NAME start-probe ",
+                        "  --config=/opt/nlpcraft.conf ",
+                        "  --models=my.package.Model ",
+                        "  --cp=/opt/target/classes ",
+                        "  --jmv-opts=\"-ea -Xms2048m\" ",
+                        "  --timeout-mins=5"
+                    ),
+                    desc =
+                        s"Starts local probe for ${y("'my.package.Model'")} model with alternative configuration " +
+                        s"file and additional parameters."
+                )
+            )
+        ),
+        Command(
+            name = "test-model",
+            group = "3. Miscellaneous",
+            synopsis = s"Runs ${y("'NCTestAutoModelValidator'")} model auto-validator.",
+            desc = Some(
+                s"Validation consists " +
+                s"of starting an embedded probe, scanning all deployed models for ${y("'NCIntentSample'")} annotations and their corresponding " +
+                s"callback methods, submitting each sample input sentences from ${y("'NCIntentSample'")} annotation and " +
+                s"checking that resulting intent matches the intent the sample was attached to. " +
+                s"See more details at https://nlpcraft.apache.org/tools/test_framework.html"
+            ),
+            body = NCCli.cmdTestModel,
+            params = Seq(
+                Parameter(
+                    id = "config",
+                    names = Seq("--config", "-c"),
+                    value = Some("path"),
+                    optional = true,
+                    desc =
+                        s"Configuration file path. By default, the embedded probe will automatically look for ${y("'nlpcraft.conf'")} " +
+                        s"configuration file in the same directory as NLPCraft JAR file. If the configuration file has " +
+                        s"different name or in different location use this parameter to provide an alternative path."
+                ),
+                Parameter(
+                    id = "cp",
+                    names = Seq("--cp", "-p"),
+                    value = Some("path"),
+                    optional = true,
+                    desc =
+                        s"Additional JVM classpath that will be appended to the default NLPCraft JVM classpath. " +
+                        s"Although this configuration property is optional, when testing your own models you must " +
+                        s"provide this additional classpath for the models and their dependencies. " +
+                        s"NOTE: this is only optional if you are testing example models shipped with NLPCraft."
+                ),
+                Parameter(
+                    id = "models",
+                    names = Seq("--models", "-m"),
+                    value = Some("<model list>"),
+                    optional = true,
+                    desc =
+                        s"Comma separated list of fully qualified class names for models to test. NOTE: if you provide " +
+                        s"the list of your own models here - you must also provide the additional classpath " +
+                        s"for them via ${y("--cp")} parameter."
+                ),
+                Parameter(
+                    id = "jvmopts",
+                    names = Seq("--jvm-opts", "-j"),
+                    value = Some("<jvm flags>"),
+                    optional = true,
+                    desc =
+                        s"Space separated quoted string of JVM flags to use. If not provided, the " +
+                        s"default ${y("'-ea -Xms1024m'")} flags will be used."
+                )
+            ),
+            examples = Seq(
+                Example(
+                    usage = Seq(
+                        s"$PROMPT $SCRIPT_NAME test-model ",
+                        "  --models=my.package.Model ",
+                        "  --cp=/opt/target/classes ",
+                        "  --jmv-opts=\"-ea -Xms2048m\""
+                    ),
+                    desc =
+                        s"Runs model auto-validator for ${y("'my.package.Model'")} model."
+                )
+            )
+        ),
+        Command(
+            name = "info-server",
+            group = "1. Server & Probe Commands",
+            synopsis = s"Info about local server.",
+            body = NCCli.cmdInfoServer
+        ),
+        Command(
+            name = "info-probe",
+            group = "1. Server & Probe Commands",
+            synopsis = s"Info about local probe.",
+            body = NCCli.cmdInfoProbe
+        ),
+        Command(
+            name = "info",
+            group = "1. Server & Probe Commands",
+            synopsis = s"Info about local probe & server.",
+            body = NCCli.cmdInfo
+        ),
+        Command(
+            name = "clear",
+            group = "3. Miscellaneous",
+            synopsis = s"Clears terminal screen.",
+            body = NCCli.cmdClear
+        ),
+        Command(
+            name = "no-ansi",
+            group = "3. Miscellaneous",
+            synopsis = s"Disables ANSI escape codes for terminal colors & controls.",
+            desc = Some(
+                s"This is a special command that can be combined with any other commands."
+            ),
+            body = NCCli.cmdNoAnsi,
+            examples = Seq(
+                Example(
+                    usage = Seq(s"$PROMPT $SCRIPT_NAME help -c=rest no-ansi"),
+                    desc = s"Displays help for ${y("'rest'")} commands without using ANSI color and escape sequences."
+                )
+            )
+        ),
+        Command(
+            name = "no-logo",
+            group = "3. Miscellaneous",
+            synopsis = s"Disables showing NLPCraft logo at the start.",
+            desc = Some(
+                s"This is a special command that can be combined with any other command in a command line mode."
+            ),
+            body = NCCli.cmdNoLogo,
+            examples = Seq(
+                Example(
+                    usage = Seq(s"$PROMPT $SCRIPT_NAME version -s no-logo"),
+                    desc =
+                        s"Displays just the version information without any additional logo output. " +
+                            s"This command makes sense only in command lime mode (NOT in REPL mode)."
+                )
+            )
+        ),
+        Command(
+            name = "ansi",
+            group = "3. Miscellaneous",
+            synopsis = s"Enables ANSI escape codes for terminal colors & controls.",
+            desc = Some(
+                s"This is a special command that can be combined with any other commands."
+            ),
+            body = NCCli.cmdAnsi,
+            examples = Seq(
+                Example(
+                    usage = Seq(s"$PROMPT $SCRIPT_NAME help -c=rest ansi"),
+                    desc = s"Displays help for ${y("'rest'")} commands with ANSI color and escape sequences."
+                )
+            )
+        ),
+        Command(
+            name = "ping-server",
+            group = "1. Server & Probe Commands",
+            synopsis = s"Pings local server.",
+            desc = Some(
+                s"Server is pinged using ${y("'/health'")} REST call to check its online status."
+            ),
+            body = NCCli.cmdPingServer,
+            params = Seq(
+                Parameter(
+                    id = "number",
+                    names = Seq("--number", "-n"),
+                    value = Some("num"),
+                    optional = true,
+                    desc =
+                        "Number of pings to perform. Must be a number > 0. Default is 1."
+                )
+            ),
+            examples = Seq(
+                Example(
+                    usage = Seq(
+                        s"$PROMPT $SCRIPT_NAME ping-server -n=10"
+                    ),
+                    desc = "Pings local server 10 times."
+                )
+            )
+        ),
+        Command(
+            name = "stop-server",
+            group = "1. Server & Probe Commands",
+            synopsis = s"Stops local server.",
+            desc = Some(
+                s"Local server must be started via ${y(s"'$SCRIPT_NAME'")} or other compatible way."
+            ),
+            body = NCCli.cmdStopServer
+        ),
+        Command(
+            name = "stop-probe",
+            group = "1. Server & Probe Commands",
+            synopsis = s"Stops local probe.",
+            desc = Some(
+                s"Local probe must be started via ${y(s"'$SCRIPT_NAME'")} or other compatible way."
+            ),
+            body = NCCli.cmdStopProbe
+        ),
+        Command(
+            name = "stop",
+            group = "1. Server & Probe Commands",
+            synopsis = s"Stops both local server & probe.",
+            desc = Some(
+                s"Both local server & probe must be started via ${y(s"'$SCRIPT_NAME'")} or other compatible way."
+            ),
+            body = NCCli.cmdStop
+        ),
+        Command(
+            name = "quit",
+            group = "3. Miscellaneous",
+            synopsis = s"Quits REPL mode. Note that started server and probe, if any, will remain running.",
+            body = NCCli.cmdQuit
+        ),
+        Command(
+            name = "help",
+            group = "3. Miscellaneous",
+            synopsis = s"Displays help for ${y(s"'$SCRIPT_NAME'")}.",
+            desc = Some(
+                s"By default, without ${y("'--all'")} or ${y("'--cmd'")} parameters, displays the abbreviated form of manual " +
+                s"only listing the commands without parameters or examples."
+            ),
+            body = NCCli.cmdHelp,
+            params = Seq(
+                Parameter(
+                    id = "cmd",
+                    names = Seq("--cmd", "-c"),
+                    value = Some("cmd"),
+                    optional = true,
+                    desc = "Set of commands to show the manual for. Can be used multiple times."
+                ),
+                Parameter(
+                    id = "all",
+                    names = Seq("--all", "-a"),
+                    optional = true,
+                    desc = "Flag to show full manual for all commands."
+                )
+            ),
+            examples = Seq(
+                Example(
+                    usage = Seq(s"$PROMPT $SCRIPT_NAME help -c=rest --cmd=version"),
+                    desc = s"Displays help for ${y("'rest'")} and ${y("'version'")} commands."
+                ),
+                Example(
+                    usage = Seq(s"$PROMPT $SCRIPT_NAME help -all"),
+                    desc = "Displays help for all commands."
+                )
+            )
+        ),
+        Command(
+            name = "version",
+            group = "3. Miscellaneous",
+            synopsis = s"Displays full version of ${y(s"'$SCRIPT_NAME'")} script.",
+            desc = Some(
+                "Depending on the additional parameters can display only the semantic version or the release date."
+            ),
+            body = NCCli.cmdVersion,
+            params = Seq(
+                Parameter(
+                    id = "semver",
+                    names = Seq("--sem-ver", "-s"),
+                    value = None,
+                    optional = true,
+                    desc = s"Display only the semantic version value, e.g. ${VER.version}."
+                ),
+                Parameter(
+                    id = "reldate",
+                    names = Seq("--rel-date", "-d"),
+                    value = None,
+                    optional = true,
+                    desc = s"Display only the release date, e.g. ${VER.date}."
+                )
+            )
+        ),
+        Command(
+            name = "gen-project",
+            group = "3. Miscellaneous",
+            synopsis = s"Generates project stub with default configuration.",
+            desc = Some(
+                "This command supports Java, Scala, and Kotlin languages with either Maven, Gradle or SBT " +
+                "as a build tool. Generated projects compiles and runs and can be used as a quick development sandbox."
+            ),
+            body = NCCli.cmdGenProject,
+            params = Seq(
+                Parameter(
+                    id = "outputDir",
+                    names = Seq("--outputDir", "-d"),
+                    value = Some("path"),
+                    optional = true,
+                    desc = s"Output directory. Default value is the current working directory."
+                ),
+                Parameter(
+                    id = "baseName",
+                    names = Seq("--baseName", "-n"),
+                    value = Some("name"),
+                    desc =
+                        s"Base name for the generated files. For example, if base name is ${y("'MyApp'")}, " +
+                        s"then generated Java file will be named as ${y("'MyAppModel.java'")} and model file as ${y("'my_app_model.yaml'")}."
+                ),
+                Parameter(
+                    id = "lang",
+                    names = Seq("--lang", "-l"),
+                    value = Some("name"),
+                    optional = true,
+                    desc =
+                        s"Language to generate source files in. Supported value are ${y("'java'")}, ${y("'scala'")}, ${y("'kotlin'")}. " +
+                        s"Default value is ${y("'java'")}."
+                ),
+                Parameter(
+                    id = "buildTool",
+                    names = Seq("--buildTool", "-b"),
+                    value = Some("name"),
+                    optional = true,
+                    desc =
+                        s"Build tool name to use. Supported values are ${y("'mvn'")} and ${y("'gradle'")} for ${y("'java'")}, " +
+                        s"${y("'scala'")}, ${y("'kotlin'")}, and ${y("'sbt'")} for ${y("'scala'")} language. Default value is ${y("'mvn'")}."
+                ),
+                Parameter(
+                    id = "packageName",
+                    names = Seq("--packageName", "-p"),
+                    value = Some("name"),
+                    optional = true,
+                    desc = s"JVM package name to use in generated source code. Default value is ${y("'org.apache.nlpcraft.demo'")}."
+                ),
+                Parameter(
+                    id = "modelType",
+                    names = Seq("--modelType", "-m"),
+                    value = Some("type"),
+                    optional = true,
+                    desc = s"Type of generated model file. Supported value are ${y("'yaml'")} or ${y("'json'")}. Default value is ${y("'yaml'")}."
+                ),
+                Parameter(
+                    id = "override",
+                    names = Seq("--override", "-o"),
+                    value = Some("true|false"),
+                    optional = true,
+                    desc = s"Whether or not to override existing output directory. Default value is ${y("'false'")}."
+                )
+            ),
+            examples = Seq(
+                Example(
+                    usage = Seq("> gen-project -n=MyProject -l=scala -b=sbt"),
+                    desc = s"Generates Scala SBT project."
+                ),
+                Example(
+                    usage = Seq("> gen-project -n=MyProject -l=kotlin -p=com.mycompany.nlp -o=true"),
+                    desc = s"Generates Kotlin Maven project."
+                )
+            )
+        ),
+        Command(
+            name = "gen-model",
+            group = "3. Miscellaneous",
+            synopsis = s"Generates data model file stub.",
+            desc = Some(
+                "Generated model stub will have all default configuration. Model file can be either YAML or JSON."
+            ),
+            body = NCCli.cmdGenModel,
+            params = Seq(
+                Parameter(
+                    id = "filePath",
+                    names = Seq("--filePath", "-f"),
+                    value = Some("path"),
+                    desc =
+                        s"File path for the model stub. File path can either be an absolute path, relative path or " +
+                        s"just a file name in which case the current folder will be used. File must have one of the " +
+                        s"following extensions: ${y("'json'")}, ${y("'js'")}, ${y("'yaml'")}, or ${y("'yml'")}."
+                ),
+                Parameter(
+                    id = "modelId",
+                    names = Seq("--modelId", "-n"),
+                    value = Some("id"),
+                    desc = "Model ID."
+                ),
+                Parameter(
+                    id = "override",
+                    names = Seq("--override", "-o"),
+                    value = Some("true|false"),
+                    optional = true,
+                    desc = s"Override output directory flag. Supported: ${y("'true'")}, ${y("'false'")}. Default value is ${y("'false'")}"
+                )
+            ),
+            examples = Seq(
+                Example(
+                    usage = Seq("> gen-model -f=myModel.json -n=my.model.id"),
+                    desc = s"Generates JSON model file stub in the current folder."
+                ),
+                Example(
+                    usage = Seq("> gen-model -f=c:/tmp/myModel.yaml -n=my.model.id --override=true"),
+                    desc = s"Generates YAML model file stub in ${y("'c:/temp'")} folder overriding existing file, if any."
+                )
+            )
+        )
+    ).sortBy(_.name)
+
+    require(
+        U.getDups(CMDS.map(_.name)).isEmpty,
+        "Dup commands."
+    )
+}
diff --git a/nlpcraft/src/main/scala/org/apache/nlpcraft/model/tools/cmdline/NCCliRestSpec.scala b/nlpcraft/src/main/scala/org/apache/nlpcraft/model/tools/cmdline/NCCliRestSpec.scala
new file mode 100644
index 0000000..47dfca1
--- /dev/null
+++ b/nlpcraft/src/main/scala/org/apache/nlpcraft/model/tools/cmdline/NCCliRestSpec.scala
@@ -0,0 +1,326 @@
+/*
+ * 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.
+ */
+
+package org.apache.nlpcraft.model.tools.cmdline
+
+private [cmdline] case class RestSpec(
+    path: String,
+    desc: String,
+    group: String,
+    params: Seq[RestSpecParameter]
+)
+
+private [cmdline] sealed trait JsonType
+
+private [cmdline] case object STRING extends JsonType
+private [cmdline] case object BOOLEAN extends JsonType
+private [cmdline] case object NUMERIC extends JsonType
+private [cmdline] case object OBJECT extends JsonType
+private [cmdline] case object ARRAY extends JsonType
+
+private [cmdline] case class RestSpecParameter(
+    name: String,
+    kind: JsonType,
+    optional: Boolean = false // Mandatory by default.
+)
+
+/**
+ * NLPCraft REST specification.
+ * TODO: this needs to be loaded dynamically from OpenAPI spec.
+ */
+private [cmdline] object NCCliRestSpec {
+    //noinspection DuplicatedCode
+    private [cmdline] final val REST_SPEC = Seq(
+        RestSpec(
+            path = "clear/conversation",
+            desc = "Clears conversation STM",
+            group = "Asking",
+            params = Seq(
+                RestSpecParameter(name = "acsTok", kind = STRING),
+                RestSpecParameter(name = "mdlId", kind = STRING),
+                RestSpecParameter(name = "usrId", kind = STRING, optional = true),
+                RestSpecParameter(name = "usrExtId", kind = STRING, optional = true)
+            )
+        ),
+        RestSpec(
+            "clear/dialog",
+            "Clears dialog flow",
+            "Asking",
+            params = Seq(
+                RestSpecParameter(name = "acsTok", kind = STRING),
+                RestSpecParameter(name = "mdlId", kind = STRING),
+                RestSpecParameter(name = "usrId", kind = STRING, optional = true),
+                RestSpecParameter(name = "usrExtId", kind = STRING, optional = true)
+            )
+        ),
+        RestSpec(
+            "model/sugsyn",
+            "Runs model synonym suggestion tool",
+            "Tools",
+            params = Seq(
+                RestSpecParameter(name = "acsTok", kind = STRING),
+                RestSpecParameter(name = "mdlId", kind = STRING),
+                RestSpecParameter(name = "minScore", kind = NUMERIC)
+            )
+        ),
+        RestSpec(
+            "check",
+            "Gets status and result of submitted requests",
+            "Asking",
+            params = Seq(
+                RestSpecParameter(name = "acsTok", kind = STRING),
+                RestSpecParameter(name = "usrId", kind = STRING, optional = true),
+                RestSpecParameter(name = "usrExtId", kind = STRING, optional = true),
+                RestSpecParameter(name = "srvReqIds", kind = ARRAY, optional = true),
+                RestSpecParameter(name = "maxRows", kind = NUMERIC, optional = true)
+            )
+        ),
+        RestSpec(
+            "cancel",
+            "Cancels a question",
+            "Asking",
+            params = Seq(
+                RestSpecParameter(name = "acsTok", kind = STRING),
+                RestSpecParameter(name = "usrId", kind = STRING, optional = true),
+                RestSpecParameter(name = "usrExtId", kind = STRING, optional = true),
+                RestSpecParameter(name = "srvReqIds", kind = ARRAY, optional = true),
+            )
+        ),
+        RestSpec(
+            "ask",
+            "Asks a question",
+            "Asking",
+            params = Seq(
+                RestSpecParameter(name = "acsTok", kind = STRING),
+                RestSpecParameter(name = "usrId", kind = STRING, optional = true),
+                RestSpecParameter(name = "usrExtId", kind = STRING, optional = true),
+                RestSpecParameter(name = "txt", kind = STRING),
+                RestSpecParameter(name = "mdlId", kind = STRING),
+                RestSpecParameter(name = "data", kind = OBJECT, optional = true),
+                RestSpecParameter(name = "enableLog", kind = BOOLEAN, optional = true),
+            )
+        ),
+        RestSpec(
+            "ask/sync",
+            "Asks a question in synchronous mode",
+            "Asking",
+            params = Seq(
+                RestSpecParameter(name = "acsTok", kind = STRING),
+                RestSpecParameter(name = "usrId", kind = STRING, optional = true),
+                RestSpecParameter(name = "usrExtId", kind = STRING, optional = true),
+                RestSpecParameter(name = "txt", kind = STRING),
+                RestSpecParameter(name = "mdlId", kind = STRING),
+                RestSpecParameter(name = "data", kind = OBJECT, optional = true),
+                RestSpecParameter(name = "enableLog", kind = BOOLEAN, optional = true),
+            )
+        ),
+        RestSpec(
+            "user/get",
+            "Gets current user information",
+            "User",
+            params = Seq(
+                RestSpecParameter(name = "acsTok", kind = STRING),
+                RestSpecParameter(name = "id", kind = STRING, optional = true),
+                RestSpecParameter(name = "usrExtId", kind = STRING, optional = true)
+            )
+        ),
+        RestSpec(
+            "user/all",
+            "Gets all users",
+            "User",
+            params = Seq(
+                RestSpecParameter(name = "acsTok", kind = STRING),
+            )
+        ),
+        RestSpec(
+            "user/update",
+            "Updates regular user",
+            "User",
+            params = Seq(
+                RestSpecParameter(name = "acsTok", kind = STRING),
+                RestSpecParameter(name = "firstName", kind = STRING),
+                RestSpecParameter(name = "lastName", kind = STRING),
+                RestSpecParameter(name = "id", kind = STRING, optional = true),
+                RestSpecParameter(name = "avatarUrl", kind = STRING, optional = true),
+                RestSpecParameter(name = "properties", kind = OBJECT, optional = true)
+            )
+        ),
+        RestSpec(
+            "user/delete",
+            "Deletes user",
+            "User",
+            params = Seq(
+                RestSpecParameter(name = "acsTok", kind = STRING),
+                RestSpecParameter(name = "id", kind = STRING, optional = true),
+                RestSpecParameter(name = "usrExtId", kind = STRING, optional = true)
+            )
+        ),
+        RestSpec(
+            "user/admin",
+            "Updates user admin permissions",
+            "User",
+            params = Seq(
+                RestSpecParameter(name = "acsTok", kind = STRING),
+                RestSpecParameter(name = "id", kind = STRING, optional = true),
+                RestSpecParameter(name = "isAdmin", kind = BOOLEAN)
+            )
+        ),
+        RestSpec(
+            "user/passwd/reset",
+            "Resets password for the user",
+            "User",
+            params = Seq(
+                RestSpecParameter(name = "acsTok", kind = STRING),
+                RestSpecParameter(name = "id", kind = STRING, optional = true),
+                RestSpecParameter(name = "newPasswd", kind = STRING)
+            )
+        ),
+        RestSpec(
+            "user/add",
+            "Adds new user",
+            "User",
+            params = Seq(
+                RestSpecParameter(name = "acsTok", kind = STRING),
+                RestSpecParameter(name = "firstName", kind = STRING),
+                RestSpecParameter(name = "lastName", kind = STRING),
+                RestSpecParameter(name = "email", kind = STRING),
+                RestSpecParameter(name = "passwd", kind = STRING),
+                RestSpecParameter(name = "isAdmin", kind = BOOLEAN),
+                RestSpecParameter(name = "usrExtId", kind = STRING, optional = true),
+                RestSpecParameter(name = "avatarUrl", kind = STRING, optional = true),
+                RestSpecParameter(name = "properties", kind = OBJECT, optional = true)
+            )
+        ),
+        RestSpec(
+            "company/get",
+            "Gets current user company information",
+            "Company",
+            params = Seq(
+                RestSpecParameter(name = "acsTok", kind = STRING),
+            )
+        ),
+        RestSpec(
+            "company/add",
+            "Adds new company",
+            "Company",
+            params = Seq(
+                RestSpecParameter(name = "acsTok", kind = STRING),
+                RestSpecParameter(name = "name", kind = STRING),
+                RestSpecParameter(name = "website", kind = STRING, optional = true),
+                RestSpecParameter(name = "country", kind = STRING, optional = true),
+                RestSpecParameter(name = "region", kind = STRING, optional = true),
+                RestSpecParameter(name = "city", kind = STRING, optional = true),
+                RestSpecParameter(name = "address", kind = STRING, optional = true),
+                RestSpecParameter(name = "postalCode", kind = STRING, optional = true),
+                RestSpecParameter(name = "adminEmail", kind = STRING),
+                RestSpecParameter(name = "adminPasswd", kind = STRING),
+                RestSpecParameter(name = "adminFirstName", kind = STRING),
+                RestSpecParameter(name = "adminLastName", kind = STRING),
+                RestSpecParameter(name = "adminAvatarUrl", kind = STRING, optional = true)
+            )
+        ),
+        RestSpec(
+            "company/update",
+            "Updates company data",
+            "Company",
+            params = Seq(
+                RestSpecParameter(name = "acsTok", kind = STRING),
+                RestSpecParameter(name = "name", kind = STRING),
+                RestSpecParameter(name = "website", kind = STRING, optional = true),
+                RestSpecParameter(name = "country", kind = STRING, optional = true),
+                RestSpecParameter(name = "region", kind = STRING, optional = true),
+                RestSpecParameter(name = "city", kind = STRING, optional = true),
+                RestSpecParameter(name = "address", kind = STRING, optional = true),
+                RestSpecParameter(name = "postalCode", kind = STRING, optional = true)
+            )
+        ),
+        RestSpec(
+            "company/delete",
+            "Deletes company",
+            "Company",
+            params = Seq(
+                RestSpecParameter(name = "acsTok", kind = STRING),
+            )
+        ),
+        RestSpec(
+            "company/token/reset",
+            "Resets company probe auth token",
+            "Company",
+            params = Seq(
+                RestSpecParameter(name = "acsTok", kind = STRING),
+            )
+        ),
+        RestSpec(
+            "feedback/add",
+            "Adds feedback",
+            "Asking",
+            params = Seq(
+                RestSpecParameter(name = "acsTok", kind = STRING),
+                RestSpecParameter(name = "usrId", kind = STRING, optional = true),
+                RestSpecParameter(name = "extUsrId", kind = STRING, optional = true),
+                RestSpecParameter(name = "comment", kind = STRING, optional = true),
+                RestSpecParameter(name = "srvReqId", kind = STRING),
+                RestSpecParameter(name = "score", kind = STRING)
+            )
+        ),
+        RestSpec(
+            "feedback/delete",
+            "Deletes feedback",
+            "Asking",
+            params = Seq(
+                RestSpecParameter(name = "acsTok", kind = STRING),
+                RestSpecParameter(name = "id", kind = NUMERIC)
+            )
+        ),
+        RestSpec(
+            "feedback/all",
+            "Gets all feedback",
+            "Asking",
+            params = Seq(
+                RestSpecParameter(name = "acsTok", kind = STRING),
+                RestSpecParameter(name = "usrId", kind = STRING, optional = true),
+                RestSpecParameter(name = "extUsrId", kind = STRING, optional = true),
+                RestSpecParameter(name = "srvReqId", kind = STRING, optional = true)
+            )
+        ),
+        RestSpec(
+            "signin",
+            "Signs in and obtains new access token",
+            "Authentication",
+            params = Seq(
+                RestSpecParameter(name = "email", kind = STRING),
+                RestSpecParameter(name = "passwd", kind = STRING)
+            )
+        ),
+        RestSpec(
+            "signout",
+            "Signs out and releases access token",
+            "Authentication",
+            params = Seq(
+                RestSpecParameter(name = "acsTok", kind = STRING),
+            )
+        ),
+        RestSpec(
+            "probe/all",
+            "Gets all probes",
+            "Probe",
+            params = Seq(
+                RestSpecParameter(name = "acsTok", kind = STRING),
+            )
+        )
+    )
+}
diff --git a/nlpcraft/src/main/scala/org/apache/nlpcraft/model/tools/embedded/NCEmbeddedProbe.java b/nlpcraft/src/main/scala/org/apache/nlpcraft/model/tools/embedded/NCEmbeddedProbe.java
index 7786ea4..3ab85d8 100644
--- a/nlpcraft/src/main/scala/org/apache/nlpcraft/model/tools/embedded/NCEmbeddedProbe.java
+++ b/nlpcraft/src/main/scala/org/apache/nlpcraft/model/tools/embedded/NCEmbeddedProbe.java
@@ -21,6 +21,8 @@ import org.apache.nlpcraft.common.*;
 import org.apache.nlpcraft.model.tools.test.*;
 import org.apache.nlpcraft.probe.*;
 import org.apache.nlpcraft.probe.mgrs.nlp.*;
+
+import java.util.Collection;
 import java.util.concurrent.*;
 import java.util.function.*;
 
@@ -93,7 +95,7 @@ public class NCEmbeddedProbe {
      * @throws NCException Thrown in case of any errors starting the data probe.
      * @return Whether or not probe started ok.
      */
-    public static boolean start(String cfgFile, String... mdlClasses) {
+    public static boolean start(String cfgFile, Collection<String> mdlClasses) {
         CompletableFuture<Integer> fut = new CompletableFuture<>();
 
         NCProbeBoot$.MODULE$.startEmbedded(cfgFile, mdlClasses, fut);
diff --git a/nlpcraft/src/main/scala/org/apache/nlpcraft/model/tools/test/NCTestAutoModelValidator.java b/nlpcraft/src/main/scala/org/apache/nlpcraft/model/tools/test/NCTestAutoModelValidator.java
index 21321a2..885149f 100644
--- a/nlpcraft/src/main/scala/org/apache/nlpcraft/model/tools/test/NCTestAutoModelValidator.java
+++ b/nlpcraft/src/main/scala/org/apache/nlpcraft/model/tools/test/NCTestAutoModelValidator.java
@@ -22,9 +22,9 @@ import org.apache.nlpcraft.model.tools.test.impl.*;
 
 /**
  * Data model auto-validator is based on {@link NCIntentSample} annotations. Validation consists of starting an embedded
- * probe, scanning for {@link NCIntentSample} annotations and their corresponding callback methods, submitting each sample input
- * sentences from {@link NCIntentSample} annotation and checking that resulting intent matches the intent the sample
- * was attached to.
+ * probe, scanning all deployed models for {@link NCIntentSample} annotations and their corresponding callback methods,
+ * submitting each sample input sentences from {@link NCIntentSample} annotation and checking that resulting intent
+ * matches the intent the sample was attached to.
  * <p>
  * Note that there can be more than one {@link NCIntentSample} annotation attached to the intent callback. Each such
  * annotation will trigger conversation STM reset before its samples will be submitted. This gives an opportunity
diff --git a/nlpcraft/src/main/scala/org/apache/nlpcraft/model/tools/test/impl/NCTestAutoModelValidatorImpl.scala b/nlpcraft/src/main/scala/org/apache/nlpcraft/model/tools/test/impl/NCTestAutoModelValidatorImpl.scala
index 2a72c77..30dca04 100644
--- a/nlpcraft/src/main/scala/org/apache/nlpcraft/model/tools/test/impl/NCTestAutoModelValidatorImpl.scala
+++ b/nlpcraft/src/main/scala/org/apache/nlpcraft/model/tools/test/impl/NCTestAutoModelValidatorImpl.scala
@@ -24,6 +24,8 @@ import org.apache.nlpcraft.model.tools.embedded.NCEmbeddedProbe
 import org.apache.nlpcraft.model.tools.test.NCTestClientBuilder
 import org.apache.nlpcraft.probe.mgrs.model.NCModelManager
 
+import scala.collection.JavaConverters._
+
 /**
   * Implementation for `NCTestAutoModelValidator` class.
   */
@@ -38,10 +40,13 @@ private [test] object NCTestAutoModelValidatorImpl extends LazyLogging {
      */
     @throws[Exception]
     def isValid: Boolean = {
-        val classes = U.sysEnv(PROP_MODELS).orNull
+        val classes = U.sysEnv(PROP_MODELS) match {
+            case Some(s) ⇒ U.splitTrimFilter(s, ",")
+            case None ⇒ null
+        }
         val cfgFile = U.sysEnv(PROP_PROBE_CFG).orNull
 
-        if (NCEmbeddedProbe.start(cfgFile, classes))
+        if (NCEmbeddedProbe.start(cfgFile, classes.asJava))
             try
                 process(NCModelManager.getAllModels().map(p ⇒ p.model.getId → p.samples.toMap).toMap.filter(_._2.nonEmpty))
             finally
diff --git a/nlpcraft/src/main/scala/org/apache/nlpcraft/probe/NCProbe.scala b/nlpcraft/src/main/scala/org/apache/nlpcraft/probe/NCProbe.scala
index 44abbef..d071837 100644
--- a/nlpcraft/src/main/scala/org/apache/nlpcraft/probe/NCProbe.scala
+++ b/nlpcraft/src/main/scala/org/apache/nlpcraft/probe/NCProbe.scala
@@ -27,10 +27,10 @@ import scala.util.control.Exception.ignoring
   * Data probe main app.
   */
 object NCProbe extends App {
-    val fut = new CompletableFuture[Integer]
-
     NCAnsi.ackStatus()
 
+    val fut = new CompletableFuture[Integer]
+
     NCProbeBoot.start(args, fut)
 
     while (!fut.isDone)
@@ -38,5 +38,6 @@ object NCProbe extends App {
             fut.get()
         }
 
-    System.exit(fut.get)
+    if (fut.get != 0)
+        System.exit(fut.get)
 }
\ No newline at end of file
diff --git a/nlpcraft/src/main/scala/org/apache/nlpcraft/probe/NCProbeBoot.scala b/nlpcraft/src/main/scala/org/apache/nlpcraft/probe/NCProbeBoot.scala
index 96120b9..a54e22f 100644
--- a/nlpcraft/src/main/scala/org/apache/nlpcraft/probe/NCProbeBoot.scala
+++ b/nlpcraft/src/main/scala/org/apache/nlpcraft/probe/NCProbeBoot.scala
@@ -100,7 +100,6 @@ private [probe] object NCProbeBoot extends LazyLogging with NCOpenCensusTrace {
             withValue(s"$prefix.token", fromAnyRef("3141592653589793")).
             withValue(s"$prefix.upLink", fromAnyRef("localhost:8201")).
             withValue(s"$prefix.downLink", fromAnyRef("localhost:8202")).
-            withValue(s"$prefix.model", fromAnyRef(null)).
             withValue(s"$prefix.models", fromAnyRef("")).
             withValue(s"$prefix.lifecycle", fromIterable(Seq().asJava)).
             withValue(s"$prefix.resultMaxSizeBytes", fromAnyRef(1048576)).
@@ -156,6 +155,8 @@ private [probe] object NCProbeBoot extends LazyLogging with NCOpenCensusTrace {
             val models: String = getString(s"$prefix.models")
             val lifecycle: Seq[String] = getStringList(s"$prefix.lifecycle")
         }
+
+        println(s"Models -> ${Cfg.models}")
         
         ProbeConfig(
             Cfg.id,
@@ -337,7 +338,7 @@ private [probe] object NCProbeBoot extends LazyLogging with NCOpenCensusTrace {
       */
     private [probe] def startEmbedded(
         cfgFile: String,
-        mdlClasses: Array[String],
+        mdlClasses: java.util.Collection[String],
         fut: CompletableFuture[Integer]): Unit = {
         checkStarted()
     
@@ -351,7 +352,7 @@ private [probe] object NCProbeBoot extends LazyLogging with NCOpenCensusTrace {
                 Some(
                     ConfigFactory.empty().withValue(
                         "nlpcraft.probe.models",
-                        fromAnyRef(mdlClasses.mkString(","))
+                        fromAnyRef(mdlClasses.asScala.mkString(","))
                     )
                 )
         )
@@ -449,7 +450,7 @@ private [probe] object NCProbeBoot extends LazyLogging with NCOpenCensusTrace {
         tbl += (s"${B}Down-Link$RST", cfg.downLinkString)
         tbl += (s"${B}Up-Link$RST", cfg.upLinkString)
         tbl += (s"${B}Lifecycle$RST", cfg.lifecycle)
-        tbl += (s"${B}Models (${cfg.modelsSeq.size})$RST" , cfg.modelsSeq)
+        tbl += (s"${B}Models (${cfg.modelsSeq.size})$RST", cfg.modelsSeq)
         tbl += (s"${B}JARs Folder$RST", cfg.jarsFolder.getOrElse(""))
 
         tbl.info(logger, Some("Probe Configuration:"))
diff --git a/nlpcraft/src/test/scala/org/apache/nlpcraft/NCTestContext.scala b/nlpcraft/src/test/scala/org/apache/nlpcraft/NCTestContext.scala
index a48c934..8bb384b 100644
--- a/nlpcraft/src/test/scala/org/apache/nlpcraft/NCTestContext.scala
+++ b/nlpcraft/src/test/scala/org/apache/nlpcraft/NCTestContext.scala
@@ -23,6 +23,8 @@ import org.apache.nlpcraft.probe.mgrs.model.NCModelManager
 import org.junit.jupiter.api.TestInstance.Lifecycle
 import org.junit.jupiter.api._
 
+import java.util.Collections
+
 /**
   *
   */
@@ -74,7 +76,7 @@ abstract class NCTestContext {
 
                 probeStarted = false
 
-                if (NCEmbeddedProbe.start(null, ann.model().getName)) {
+                if (NCEmbeddedProbe.start(null, Collections.singletonList(ann.model().getName))) {
                     probeStarted = true
                 
                     if (ann.startClient()) {
diff --git a/nlpcraft/src/test/scala/org/apache/nlpcraft/model/intent/dsl/NCDslSpec.scala b/nlpcraft/src/test/scala/org/apache/nlpcraft/model/intent/dsl/NCDslSpec.scala
index 8dc75c5..8487dc5 100644
--- a/nlpcraft/src/test/scala/org/apache/nlpcraft/model/intent/dsl/NCDslSpec.scala
+++ b/nlpcraft/src/test/scala/org/apache/nlpcraft/model/intent/dsl/NCDslSpec.scala
@@ -18,13 +18,14 @@
 package org.apache.nlpcraft.model.intent.dsl
 
 import java.io.IOException
-
 import org.apache.nlpcraft.common.NCException
 import org.apache.nlpcraft.model.tools.embedded.NCEmbeddedProbe
 import org.apache.nlpcraft.model.tools.test.{NCTestClient, NCTestClientBuilder}
 import org.junit.jupiter.api.Assertions.assertTrue
 import org.junit.jupiter.api.{AfterEach, BeforeEach, Test}
 
+import java.util.Collections
+
 /**
  * DSL test model test. Make sure to start up the NLPCraft server before running this test.
  */
@@ -36,7 +37,7 @@ class NCDslSpec {
     @throws[IOException]
     private[dsl] def setUp(): Unit = {
         // Start embedded probe with the test model.
-        if (NCEmbeddedProbe.start(null, classOf[NCDslTestModel].getName)) {
+        if (NCEmbeddedProbe.start(null, Collections.singletonList(classOf[NCDslTestModel].getName))) {
             cli = new NCTestClientBuilder().newBuilder.build
 
             cli.open("nlpcraft.dsl.test")