diff --git a/repos/os/recipes/src/nit_focus/content.mk b/repos/os/recipes/src/nit_focus/content.mk
new file mode 100644
index 0000000000..3c04b84335
--- /dev/null
+++ b/repos/os/recipes/src/nit_focus/content.mk
@@ -0,0 +1,2 @@
+SRC_DIR = src/app/nit_focus
+include $(GENODE_DIR)/repos/base/recipes/src/content.inc
diff --git a/repos/os/recipes/src/nit_focus/hash b/repos/os/recipes/src/nit_focus/hash
new file mode 100644
index 0000000000..bd21e6ffca
--- /dev/null
+++ b/repos/os/recipes/src/nit_focus/hash
@@ -0,0 +1 @@
+2017-11-19 8a4dfb6ff5019ef00c5428040243f05e936eb655
diff --git a/repos/os/recipes/src/nit_focus/used_apis b/repos/os/recipes/src/nit_focus/used_apis
new file mode 100644
index 0000000000..69a94c6d26
--- /dev/null
+++ b/repos/os/recipes/src/nit_focus/used_apis
@@ -0,0 +1,3 @@
+base
+os
+report_session
diff --git a/repos/os/src/app/nit_focus/README b/repos/os/src/app/nit_focus/README
new file mode 100644
index 0000000000..a9e5468f61
--- /dev/null
+++ b/repos/os/src/app/nit_focus/README
@@ -0,0 +1,8 @@
+The nit_focus component implements the input-focus policy for the nitpicker
+GUI server. It consumes nitpicker's 'clicked' report and, in turn, produces a
+'focus' report to be consumed by nitpicker.
+
+Focus changes are subjected to a configurable policy, which is selected via
+Genode's regular policy-selection mechanism based on the label of the clicked
+nitpicker client. The client is focused only if the policy has the attribute
+'focus' set to "yes".
diff --git a/repos/os/src/app/nit_focus/main.cc b/repos/os/src/app/nit_focus/main.cc
new file mode 100644
index 0000000000..7169b07ace
--- /dev/null
+++ b/repos/os/src/app/nit_focus/main.cc
@@ -0,0 +1,65 @@
+/*
+ * \brief Input-focus policy for the nitpicker GUI server
+ * \author Norman Feske
+ * \date 2017-11-19
+ */
+
+/*
+ * Copyright (C) 2017 Genode Labs GmbH
+ *
+ * This file is part of the Genode OS framework, which is distributed
+ * under the terms of the GNU Affero General Public License version 3.
+ */
+
+/* Genode includes */
+#include
+#include
+#include
+#include
+
+namespace Nit_focus {
+ using namespace Genode;
+ struct Main;
+}
+
+
+struct Nit_focus::Main
+{
+ Env &_env;
+
+ Attached_rom_dataspace _config_rom { _env, "config" };
+ Attached_rom_dataspace _clicked_rom { _env, "clicked" };
+
+ Reporter _focus_reporter { _env, "focus" };
+
+ void _handle_update()
+ {
+ _clicked_rom.update();
+ _config_rom.update();
+
+ typedef String<160> Label;
+ Label const label = _clicked_rom.xml().attribute_value("label", Label());
+
+ try {
+ Session_policy const policy(label, _config_rom.xml());
+ if (policy.attribute_value("focus", true)) {
+ Reporter::Xml_generator xml(_focus_reporter, [&] () {
+ xml.attribute("label", label); });
+ }
+ }
+ catch (...) { /* don't change focus on policy mismatch */ }
+ }
+
+ Signal_handler _update_handler {
+ _env.ep(), *this, &Main::_handle_update };
+
+ Main(Env &env) : _env(env)
+ {
+ _clicked_rom.sigh(_update_handler);
+ _focus_reporter.enabled(true);
+ _handle_update();
+ }
+};
+
+
+void Component::construct(Genode::Env &env) { static Nit_focus::Main main(env); }
diff --git a/repos/os/src/app/nit_focus/target.mk b/repos/os/src/app/nit_focus/target.mk
new file mode 100644
index 0000000000..704a357cb0
--- /dev/null
+++ b/repos/os/src/app/nit_focus/target.mk
@@ -0,0 +1,3 @@
+TARGET = nit_focus
+SRC_CC = main.cc
+LIBS = base