diff --git a/bob/bio/face/annotator/Base.py b/bob/bio/face/annotator/Base.py
index 003ed72b29b1840e2d8112c33c93c05d927881e4..e99dde1eb3be35d795368265546b070317bc3038 100644
--- a/bob/bio/face/annotator/Base.py
+++ b/bob/bio/face/annotator/Base.py
@@ -1,21 +1,20 @@
-from bob.bio.base import read_original_data as base_read
+from bob.bio.base.annotator import Base as __Base
 
 
-class Base(object):
-    """Base class for all annotators"""
+class Base(__Base):
+    """Base class for all face annotators"""
 
-    def __init__(self, read_original_data=None, **kwargs):
+    def __init__(self, **kwargs):
         super(Base, self).__init__(**kwargs)
-        self.read_original_data = read_original_data or base_read
 
-    def annotate(self, image, **kwargs):
+    def annotate(self, sample, **kwargs):
         """Annotates an image and returns annotations in a dictionary.
         All annotator should return at least the topleft and bottomright
         coordinates.
 
         Parameters
         ----------
-        image : array
+        sample : numpy.ndarray
             The image should be a Bob format (#Channels, Height, Width) RGB
             image.
         **kwargs
@@ -24,5 +23,5 @@ class Base(object):
         raise NotImplementedError()
 
     # Alisa call to annotate
-    def __call__(self, image, **kwargs):
-        return self.annotate(image, **kwargs)
+    def __call__(self, sample, **kwargs):
+        return self.annotate(sample, **kwargs)
diff --git a/bob/bio/face/annotator/FailSafe.py b/bob/bio/face/annotator/FailSafe.py
deleted file mode 100644
index 4b9b587865772eae7d920e6b69ae260e2d6301ba..0000000000000000000000000000000000000000
--- a/bob/bio/face/annotator/FailSafe.py
+++ /dev/null
@@ -1,37 +0,0 @@
-import logging
-from . import Base
-
-logger = logging.getLogger(__name__)
-
-
-class FailSafe(Base):
-    """A fail-safe annotator.
-    This annotator takes a list of annotator and tries them until you get your
-    annotations.
-    The annotations of previous annotator is passed to the next one.
-    """
-
-    def __init__(self, annotators, required_keys, **kwargs):
-        super(FailSafe, self).__init__(**kwargs)
-        self.annotators = list(annotators)
-        self.required_keys = list(required_keys)
-
-    def annotate(self, image, **kwargs):
-        if 'annotations' not in kwargs or kwargs['annotations'] is None:
-            kwargs['annotations'] = {}
-        for annotator in self.annotators:
-            try:
-                annotations = annotator(image, **kwargs)
-            except Exception:
-                logger.warning(
-                    "The annotator `%s' failed to annotate!", annotator,
-                    exc_info=True)
-                annotations = {}
-            if not annotations:
-                logger.debug(
-                    "Annotator `%s' returned empty annotations.", annotator)
-            kwargs['annotations'].update(annotations)
-            # check if we have all the required annotations
-            if all(key in kwargs['annotations'] for key in self.required_keys):
-                break
-        return kwargs['annotations']
diff --git a/bob/bio/face/annotator/__init__.py b/bob/bio/face/annotator/__init__.py
index 9f64b622c89211a701dac65cbc97095e6dda1a59..83adf1d8d9d1ae3ab7d5572edeb72abc38e85553 100644
--- a/bob/bio/face/annotator/__init__.py
+++ b/bob/bio/face/annotator/__init__.py
@@ -1,5 +1,5 @@
+from bob.ip.facedetect import bounding_box_from_annotation
 from .Base import Base
-from .FailSafe import FailSafe
 
 
 def bounding_box_to_annotations(bbx):
@@ -8,3 +8,50 @@ def bounding_box_to_annotations(bbx):
         'bottomright': bbx.bottomright,
     }
     return landmarks
+
+
+def min_face_size_validator(annotations, min_face_size=(32, 32)):
+    """Validates annotations based on face's minimal size.
+
+    Parameters
+    ----------
+    annotations : dict
+        The annotations in dictionary format.
+    min_face_size : (int, int), optional
+        The minimal size of a face.
+
+    Returns
+    -------
+    bool
+        True, if the face is large enough.
+    """
+    bbx = bounding_box_from_annotation(source='direct', **annotations)
+    if bbx.size < min_face_size:
+        return False
+    return True
+
+
+# gets sphinx autodoc done right - don't remove it
+def __appropriate__(*args):
+    """Says object was actually declared here, and not in the import module.
+    Fixing sphinx warnings of not being able to find classes, when path is
+    shortened.
+
+    Parameters
+    ----------
+    *args
+        An iterable of objects to modify
+
+    Resolves `Sphinx referencing issues
+    <https://github.com/sphinx-doc/sphinx/issues/3048>`
+    """
+
+    for obj in args:
+        obj.__module__ = __name__
+
+
+__appropriate__(
+    Base,
+)
+
+__all__ = [_ for _ in dir() if not _.startswith('_')]
diff --git a/bob/bio/face/annotator/bobipdlib.py b/bob/bio/face/annotator/bobipdlib.py
new file mode 100644
index 0000000000000000000000000000000000000000..d1c6a759f03a28a8c4e3805c3f8ac7b6223fcc71
--- /dev/null
+++ b/bob/bio/face/annotator/bobipdlib.py
@@ -0,0 +1,19 @@
+from . import Base, bounding_box_to_annotations
+from bob.ip.facedetect import bounding_box_from_annotation
+from bob.ip.dlib import DlibLandmarkExtraction
+
+
+class BobIpDlib(Base):
+    """Annotator using bob.ip.dlib"""
+
+    def __init__(self, **kwargs):
+        super(BobIpDlib, self).__init__(**kwargs)
+        self.detector = DlibLandmarkExtraction(bob_landmark_format=True)
+
+    def annotate(self, image, **kwargs):
+        landmarks = self.detector(image)
+        if not landmarks:
+            return {}
+        bounding_box = bounding_box_from_annotation(source='eyes', **landmarks)
+        landmarks.update(bounding_box_to_annotations(bounding_box))
+        return landmarks
diff --git a/bob/bio/face/script/annotate.py b/bob/bio/face/script/annotate.py
deleted file mode 100644
index e8a50d838ed054f31f20ca14cefb885cfaefbee1..0000000000000000000000000000000000000000
--- a/bob/bio/face/script/annotate.py
+++ /dev/null
@@ -1,87 +0,0 @@
-"""A script to help annotate databases.
-"""
-import logging
-import json
-import click
-from os.path import dirname, isfile
-from bob.extension.scripts.click_helper import (
-    verbosity_option, Command, Option)
-from bob.io.base import create_directories_safe
-from bob.bio.base.tools.grid import indices
-
-logger = logging.getLogger(__name__)
-
-
-@click.command(entry_point_group='bob.bio.config', cls=Command)
-@click.option('--database', '-d', required=True, cls=Option,
-              entry_point_group='bob.bio.database')
-@click.option('--annotator', '-a', required=True, cls=Option,
-              entry_point_group='bob.bio.annotator')
-@click.option('--output-dir', '-o', required=True, cls=Option)
-@click.option('--force', '-f', is_flag=True, cls=Option)
-@click.option('--jobs', type=click.INT, default=1,)
-@verbosity_option(cls=Option)
-def annotate(database, annotator, output_dir, force, jobs, **kwargs):
-    """Annotates a database.
-    The annotations are written in text file (json) format which can be read
-    back using :any:`bob.db.base.read_annotation_file` (annotation_type='json')
-
-    \b
-    Parameters
-    ----------
-    database : :any:`bob.bio.database`
-        The database that you want to annotate. Can be a ``bob.bio.database``
-        entry point or a path to a Python file which contains a variable
-        named `database`.
-    annotator : callable
-        A function that takes the database and a sample (biofile) of the
-        database and returns the annotations in a dictionary. Can be a
-        ``bob.bio.annotator`` entry point or a path to a Python file which
-        contains a variable named `annotator`.
-    output_dir : str
-        The directory to save the annotations.
-    force : bool, optional
-        Wether to overwrite existing annotations.
-    jobs : int, optional
-        Use this option alongside gridtk to submit this script as an array job.
-    verbose : int, optional
-        Increases verbosity (see help for --verbose).
-
-    \b
-    [CONFIG]...            Configuration files. It is possible to pass one or
-                           several Python files (or names of ``bob.bio.config``
-                           entry points) which contain the parameters listed
-                           above as Python variables. The options through the
-                           command-line (see below) will override the values of
-                           configuration files.
-    """
-    logger.debug('database: %s', database)
-    logger.debug('annotator: %s', annotator)
-    logger.debug('force: %s', force)
-    logger.debug('output_dir: %s', output_dir)
-    logger.debug('jobs: %s', jobs)
-    logger.debug('kwargs: %s', kwargs)
-    biofiles = database.objects(groups=None, protocol=database.protocol)
-    biofiles = sorted(biofiles)
-    if jobs > 1:
-        start, end = indices(biofiles, jobs)
-        biofiles = biofiles[start:end]
-    logger.info("Saving annotations in %s", output_dir)
-    total = len(biofiles)
-    logger.info("Annotating %d samples ...", total)
-    for i, biofile in enumerate(biofiles):
-        logger.info(
-            "Extracting annotations for sample %d out of %d", i + 1, total)
-        outpath = biofile.make_path(output_dir, '.json')
-        if isfile(outpath):
-            if force:
-                logger.debug("Overwriting the annotations file `%s'", outpath)
-            else:
-                logger.debug("The annotation `%s' already exists", outpath)
-                continue
-        data = annotator.read_original_data(
-            biofile, database.original_directory, database.original_extension)
-        annot = annotator(data)
-        create_directories_safe(dirname(outpath))
-        with open(outpath, 'w') as f:
-            json.dump(annot, f, indent=1, allow_nan=False)
diff --git a/bob/bio/face/test/test_annotators.py b/bob/bio/face/test/test_annotators.py
new file mode 100644
index 0000000000000000000000000000000000000000..c71dbe4faa94dd0b87efebc8060cdad1a3896586
--- /dev/null
+++ b/bob/bio/face/test/test_annotators.py
@@ -0,0 +1,13 @@
+from __future__ import print_function
+import bob.io.base
+import bob.io.base.test_utils
+import bob.io.image
+import bob.ip.facedetect
+
+face_image = bob.io.base.load(bob.io.base.test_utils.datafile(
+    'testimage.jpg', 'bob.ip.facedetect'))
+
+
+def test_bob_ip_facedetect():
+    from bob.bio.face.annotator.bobipfacedetect import BobIpFacedetect
+    annot = BobIpFacedetect(face_image)
diff --git a/setup.py b/setup.py
index 1fef71cafc4f0402b3845d77a5e923f2fae69f15..9cf6eb0382bf3eb8e359f1e12248485be20d5983 100644
--- a/setup.py
+++ b/setup.py
@@ -181,10 +181,6 @@ setup(
             'bic-jets          = bob.bio.face.config.algorithm.bic_jets:algorithm',  # BIC on gabor jets
         ],
 
-        'bob.bio.cli': [
-            'annotate          = bob.bio.face.script.annotate:annotate'
-        ]
-
     },
 
     # Classifiers are important if you plan to distribute this package through