diff --git a/alib2cli/src/environment/Environment.h b/alib2cli/src/environment/Environment.h
index 062d08bb22e8c7af62f5f621b37bfec15714216b..c5a590de233cda4131b0569f80e107d3761be3ff 100644
--- a/alib2cli/src/environment/Environment.h
+++ b/alib2cli/src/environment/Environment.h
@@ -55,6 +55,16 @@ public:
 			throw exception::CommonException ( "Binded value of name " + name + " not found." );
 	}
 
+	const std::set < std::string > getBindingNames ( ) const {
+		std::set < std::string > res;
+
+		for ( const std::pair < const std::string, std::string > & kv : m_bindings ) {
+			res.insert ( kv.first );
+		}
+
+		return res;
+	}
+
 	void setBinding ( std::string name, std::string value ) {
 		m_bindings [ std::move ( name ) ] = std::move ( value );
 	}
@@ -75,6 +85,16 @@ public:
 		return ptr->getConstValueReference ( );
 	}
 
+	const std::set < std::string > getVariableNames ( ) const {
+		std::set < std::string > res;
+
+		for ( const std::pair < const std::string, std::shared_ptr < abstraction::OperationAbstraction > > & kv : m_variables ) {
+			res.insert ( kv.first );
+		}
+
+		return res;
+	}
+
 	void setVariable ( std::string name, std::shared_ptr < abstraction::OperationAbstraction > value ) {
 		setVariableInt ( std::move ( name ), std::move ( value ) );
 	}
diff --git a/aql2/src/prompt/Prompt.cpp b/aql2/src/prompt/Prompt.cpp
index 132e35203eb80dd7ecda30cdf4c0c18ac9b9d4db..db51f6919d4df5936f2f9527bff25fb4272a1c2f 100644
--- a/aql2/src/prompt/Prompt.cpp
+++ b/aql2/src/prompt/Prompt.cpp
@@ -6,6 +6,7 @@
  */
 
 #include "Prompt.h"
+#include "ReadlinePromptCompletion.h"
 
 char esc_char [] = { '\a', '\b', '\f', '\n', '\r', '\t', '\v', '\\' };
 char essc_str [] = {  'a',  'b',  'f',  'n',  'r',  't',  'v', '\\' };
@@ -65,6 +66,11 @@ Prompt::Prompt ( cli::Environment environment ) : m_history_file ( std::string (
 		++ history;
 		++ i;
 	}
+
+
+	// register readline completion function, pass environment
+	rl_attempted_completion_function = readline_completion;
+	rl_aql_environment = & m_environment;
 }
 
 Prompt::~Prompt ( ) {
diff --git a/aql2/src/prompt/ReadlinePromptCompletion.cpp b/aql2/src/prompt/ReadlinePromptCompletion.cpp
new file mode 100644
index 0000000000000000000000000000000000000000..4082d1f9c47898301214860d6cc0f74b6ae002b3
--- /dev/null
+++ b/aql2/src/prompt/ReadlinePromptCompletion.cpp
@@ -0,0 +1,232 @@
+/*
+ * ReadlinePromptCompletion.cpp
+ *
+ *  Created on: 22. 1. 2019
+ *	  Author: Tomas Pecka
+ */
+
+#include <alib/set>
+#include <alib/vector>
+#include <alib/string>
+#include <readline/readline.h>
+#include <registry/Registry.h>
+
+#include "ReadlinePromptCompletion.h"
+
+
+const cli::Environment* rl_aql_environment = nullptr;
+
+/* ========================================================================= */
+
+std::set < std::string > addPrefix ( const std::set < std::string > & collection, const std::string & prefix ) {
+	std::set < std::string > res;
+	for ( const std::string & s : collection )
+		res.insert ( prefix + s );
+
+	return res;
+}
+
+bool startswith ( const std::string & subject, const std::string & prefix ) {
+	if ( prefix.size ( ) > subject.size ( ) )
+		return false;
+
+	return subject.substr ( 0, prefix.size ( ) ) == prefix;
+}
+
+std::set < std::string > filter_completions ( const std::set < std::string > & choices, const char *text ) {
+	std::pair < std::set < std::string > :: const_iterator, std::set < std::string > :: const_iterator > range;
+	const std::string prefix = text;
+
+	range = std::equal_range ( choices.begin ( ), choices.end ( ), prefix,
+			[ &prefix ] ( const std::string & a, const std::string & b ) { return strncmp ( a.c_str ( ), b.c_str ( ), prefix.size ( )) < 0; } );
+
+	return std::set < std::string > ( range.first, range.second );
+}
+
+/* ========================================================================= */
+
+std::set < std::string > fetchAlgorithms ( const char *text ) {
+	std::set < std::string > res;
+	const ext::set < ext::pair < std::string, ext::vector < std::string > > >& algos = abstraction::Registry::listAlgorithms ( );
+
+	for ( const std::pair < std::string, std::vector < std::string > > & algo : algos ) {
+		res.insert ( algo.first );
+	}
+
+	return filter_completions ( res, text );
+}
+
+std::set < std::string > fetchCommands ( const char *text ) {
+	return filter_completions ( { "execute", "introspect", "quit", "help" }, text );
+}
+
+std::set < std::string > fetchCommandsIntrospect ( const char *text ) {
+	return filter_completions ( { "algorithms", "overloads", "casts", "datatypes" }, text );
+}
+
+std::set < std::string > fetchBindings ( const char *text ) {
+	if ( rl_aql_environment )
+		return filter_completions ( addPrefix ( rl_aql_environment -> getBindingNames ( ), "#" ), text );
+	return std::set < std::string > ( );
+}
+
+std::set < std::string > fetchVariables ( const char *text ) {
+	if ( rl_aql_environment )
+		return filter_completions ( addPrefix ( rl_aql_environment -> getVariableNames ( ), "$" ), text );
+	return std::set < std::string > ( );
+}
+
+std::set < std::string > fetchFilepath ( const char *text ) {
+	std::set < std::string > res;
+	char *str;
+	int state = 0;
+
+	while ( ( str = rl_filename_completion_function ( text, state++ ) ) != nullptr ) {
+		res.insert ( str );
+	}
+
+	return res;
+}
+
+/* ========================================================================= */
+
+/**
+ * @param text Prefix
+ * @param state Invocation number of this completion
+ * @param generator Function that generates the completion-strings
+ */
+template < typename... CompletionGeneratorFunc >
+char * completion_generator ( const char *text, int state, const CompletionGeneratorFunc & ... generators ) {
+	static std::string prefix;
+	static std::set < std::string > choices;
+	static std::set < std::string > :: const_iterator iter;
+
+	/* on first call initialize choices */
+	if ( state == 0 ) {
+		prefix = text;
+
+		choices = std::set < std::string > ( );
+
+		/* merge choices from all generators */
+		const std::vector < std::function < std::set < std::string > ( const char* ) > > gens = { generators... };
+		for ( const auto & gen : gens ) {
+			std::set < std::string > tmpres, tmpg = gen ( text );
+
+			std::set_union ( std::begin ( choices ), std::end ( choices ),
+					std::begin ( tmpg ), std::end ( tmpg ),
+					std::inserter ( tmpres, std::begin ( tmpres ) ) );
+			choices = tmpres;
+		}
+
+		iter = choices.begin ( );
+	}
+
+	/* iterate through choices */
+	while ( iter != choices.end ( ) ) {
+		return strdup ( iter ++ -> c_str ( ) );
+	}
+
+	return nullptr;
+}
+
+/* ========================================================================= */
+
+/**
+ * http://www.delorie.com/gnu/docs/readline/rlman_45.html
+ * @param state Function invocation number
+ * @return malloc-allocated string or NULL if no more strings can be generated.
+ * */
+char * complete_algorithm ( const char *text, int state ) {
+	return completion_generator ( text, state, fetchAlgorithms );
+}
+
+char * complete_command ( const char *text, int state ) {
+	return completion_generator ( text, state, fetchCommands );
+}
+
+char * complete_command_introspect ( const char *text, int state ) {
+	return completion_generator ( text, state, fetchCommandsIntrospect );
+}
+
+char * complete_variable ( const char *text, int state ) {
+	return completion_generator ( text, state, fetchVariables );
+}
+
+char * complete_binding ( const char *text, int state ) {
+	return completion_generator ( text, state, fetchBindings );
+}
+
+char * complete_filepath ( const char *text, int state ) {
+	return completion_generator ( text, state, fetchFilepath );
+}
+
+char * complete_filepath_or_variable ( const char *text, int state ) {
+	return completion_generator ( text, state, fetchFilepath, fetchVariables );
+}
+
+/* ========================================================================= */
+
+CompletionContext context ( const char *text, const int start, const int end ) {
+	std::string line ( rl_line_buffer );
+
+	if ( start == 0 )
+		return CompletionContext::COMMAND;
+
+	if ( startswith ( line, "introspect" ) && start == 11 ) {
+		return CompletionContext::COMMAND_INTROSPECT;
+	}
+	else if ( startswith ( line, "introspect overloads" ) && start == 21 )
+		return CompletionContext::ALGORITHM;
+
+	/* TODO
+	else if ( startswith ( line, "introspect algorithms" ) && start == 21 )
+	else if ( startswith ( line, "introspect casts" ) && start == 17 )
+	else if ( startswith ( line, "introspect datatypes" ) && start == 20 )
+	*/
+
+	if ( end - start > 0 && text [ 0 ] == '$' )
+		return CompletionContext::VARIABLE;
+	else if ( end - start > 0 && text [ 0 ] == '#' )
+		return CompletionContext::BINDING;
+
+	/* scan the context backwards. If first non-whitespace character is < or >, then complete a filename */
+	char *p = rl_line_buffer + start - 1;
+	while ( p >= rl_line_buffer && isspace ( *p ) ) p --;
+	if ( p >= rl_line_buffer && ( *p == '<' || *p == '>' ) )
+		return CompletionContext::FILEPATH_OR_VARIABLE;
+
+	if ( startswith ( line, "execute" ) && start == 8 )
+		return CompletionContext::ALGORITHM;
+
+	/* undecided, fallback to filepath */
+	return CompletionContext::FILEPATH;
+}
+
+/* ========================================================================= */
+
+char ** readline_completion ( const char *text, int start, int end ) {
+	// for variables and bindings
+	rl_special_prefixes = "$#@";
+	rl_attempted_completion_over = 1;
+
+	// std::cerr << ">" << text << "< " << start << " " << end << std::endl;
+
+	switch ( context ( text, start, end ) ) {
+		case CompletionContext::ALGORITHM:
+			return rl_completion_matches ( text, complete_algorithm );
+		case CompletionContext::COMMAND:
+			return rl_completion_matches ( text, complete_command );
+		case CompletionContext::COMMAND_INTROSPECT:
+			return rl_completion_matches ( text, complete_command_introspect );
+		case CompletionContext::VARIABLE:
+			return rl_completion_matches ( text, complete_variable );
+		case CompletionContext::BINDING:
+			return rl_completion_matches ( text, complete_binding );
+		case CompletionContext::FILEPATH:
+			return rl_completion_matches ( text, complete_filepath );
+		case CompletionContext::FILEPATH_OR_VARIABLE:
+			return rl_completion_matches ( text, complete_filepath_or_variable );
+		default:
+			return nullptr;
+	}
+}
diff --git a/aql2/src/prompt/ReadlinePromptCompletion.h b/aql2/src/prompt/ReadlinePromptCompletion.h
new file mode 100644
index 0000000000000000000000000000000000000000..dc6105b027cf2b6c080bf704cd5c05b0827c9fa6
--- /dev/null
+++ b/aql2/src/prompt/ReadlinePromptCompletion.h
@@ -0,0 +1,35 @@
+/*
+ * ReadlinePromptCompletion.h
+ *
+ *  Created on: 22. 1. 2019
+ *	  Author: Tomas Pecka
+ */
+
+#ifndef _READLINE_PROMPT_COMPLETION_H
+#define _READLINE_PROMPT_COMPLETION_H
+
+#include <alib/vector>
+#include <alib/set>
+#include <alib/map>
+
+#include <readline/readline.h>
+#include <environment/Environment.h>
+
+extern const cli::Environment* rl_aql_environment;
+
+enum class CompletionContext {
+	COMMAND,
+	COMMAND_INTROSPECT,
+
+	ALGORITHM,
+
+	FILEPATH,
+	FILEPATH_OR_VARIABLE,
+
+	VARIABLE,
+	BINDING,
+};
+
+char** readline_completion ( const char *text, int start, int end );
+
+#endif /* _READLINE_PROMPT_COMPLETION_H */