diff --git a/muppet/lookup.py b/muppet/lookup.py
new file mode 100644
index 0000000000000000000000000000000000000000..0abb64479bd05c9e58f7d64dddd813e139f68f99
--- /dev/null
+++ b/muppet/lookup.py
@@ -0,0 +1,200 @@
+"""
+[Jq(1)](https://jqlang.github.io/jq/) like expressions for python.
+
+Something similar to Jq, but built on python objects.
+All procedures eventually return the expecetd value, or a
+user-supplied default value.
+
+
+Example
+-------
+        lookup(i) \
+                .ref('docstring') \
+                .ref('tags') \
+                .select(Ref('tag_name') == 'summary')) \
+                .idx(0)
+                .ref('text') \
+                .exec()
+
+TODO
+----
+- `select`
+  Selects all values from a list which matches a given expression.
+  This would however require us to manage multiple values at once.
+"""
+
+from typing import Any, Union
+
+
+class _Expression:
+    """
+    A test expression.
+
+        x.find(Ref("key") == "summary")
+    Would focus in on the first list element which has the key "key"
+    with a value of "summary".
+
+    This is the root-class, and doesn't make sense to initialize directly.
+    """
+
+    def run(self, value: Any) -> bool:
+        return False
+
+
+class _RefEqExpr(_Expression):
+    """
+    Equality expression.
+
+    Assumes that the left part is a _RefExpr and the right part is a value.
+
+    Checks that the left reference exists in the given value, and that
+    it's value is equal to the right one.
+    """
+
+    def __init__(self, left: '_RefExpr', right: Any):
+        self.left = left
+        self.right = right
+
+    def run(self, value: Any) -> bool:
+        if self.left.key not in value:
+            return False
+        else:
+            return bool(value[self.left.key] == self.right)
+
+
+class _RefExpr(_Expression):
+    """
+    A key reference expression.
+
+    By itself, checks if the given key exists in the given value.
+    Intended to be used for dictionaries, but will work on anything
+    implementing `in`.
+    """
+
+    def __init__(self, key: str):
+        self.key = key
+
+    def __eq__(self, other: Any) -> '_RefEqExpr':  # type: ignore
+        """
+        Return a new expression checking equality between left and right.
+
+        Left side will be ourself, while the right side can in theory
+        be anything (see _RefEqExpr for details).
+
+        Typing is removed here, since the base object specifies the type as
+            def __eq__(self, x: Any) -> bool:
+                ...
+        Which we aren't allowed to deviate from according to the
+        Liskov substitution principle. However, at least sqlalchemy
+        uses the exact same "trick" for the exact same effect. So
+        there is a president.
+
+        """
+        return _RefEqExpr(self, other)
+
+    def run(self, value: Any) -> bool:
+        return self.key in value
+
+
+class _NullLookup:
+    """
+    A failed lookup.
+
+    Shares the same interface as true "true" lookup class, but all
+    methods imidiattely propagate the failure state.
+
+    This saves us from null in the code.
+    """
+
+    def get(self, _: str) -> '_NullLookup':
+        """Propagate null."""
+        return self
+
+    def ref(self, _: str) -> '_NullLookup':
+        """Propagate null."""
+        return self
+
+    def idx(self, _: int) -> '_NullLookup':
+        """Propagate null."""
+        return self
+
+    def find(self, _: _Expression) -> '_NullLookup':
+        """Propagate null."""
+        return self
+
+    def value(self, dflt: Any = None) -> Any:
+        """Return the default value."""
+        return dflt
+
+
+class _TrueLookup:
+    """Easily lookup values in nested data structures."""
+
+    def __init__(self, object: Any):
+        self.object = object
+
+    def get(self, key: str) -> Union['_TrueLookup', '_NullLookup']:
+        """Select object field by name."""
+        try:
+            return _TrueLookup(getattr(self.object, key))
+        except Exception:
+            return _NullLookup()
+
+    def ref(self, key: str) -> Union['_TrueLookup', '_NullLookup']:
+        """Select object by dictionary key."""
+        try:
+            return _TrueLookup(self.object[key])
+        except TypeError:
+            # Not a dictionary
+            return _NullLookup()
+        except KeyError:
+            # Key not in dictionary
+            return _NullLookup()
+
+    def idx(self, idx: int) -> Union['_TrueLookup', '_NullLookup']:
+        """Select array index."""
+        try:
+            return _TrueLookup(self.object[idx])
+        except TypeError:
+            # Not a list
+            return _NullLookup()
+        except IndexError:
+            # Index out of range
+            return _NullLookup()
+
+    def find(self, expr: _Expression) -> Union['_TrueLookup', '_NullLookup']:
+        """Find the first element in list matching expression."""
+        for item in self.object:
+            if expr.run(item):
+                return _TrueLookup(item)
+        return _NullLookup()
+
+    def value(self, dflt: Any = None) -> Any:
+        """
+        Return the found value.
+
+        If no value is found, either return None, or the second argument.
+        """
+        return self.object
+
+
+# Implemented as a union between our two different types, since the
+# split is an implementation detail to easier handle null values.
+Lookup = Union[_TrueLookup, _NullLookup]
+"""Lookup type."""
+
+
+def lookup(base: Any) -> Lookup:
+    """
+    Create a new lookup base object.
+
+    All queries should start here.
+
+    Parameters
+    ----------
+    base - Can be anything which has meaningful subfields.
+    """
+    return _TrueLookup(base)
+
+
+Ref = _RefExpr
diff --git a/tests/test_lookup.py b/tests/test_lookup.py
new file mode 100644
index 0000000000000000000000000000000000000000..4ad12d95a92b05b40ef88a1d5cc68645d330d1bc
--- /dev/null
+++ b/tests/test_lookup.py
@@ -0,0 +1,46 @@
+"""Unit tests for lookup."""
+
+from muppet.lookup import lookup, Ref
+
+
+def test_simple_lookup():
+    assert lookup(str).get('split').value() == str.split
+    assert lookup({'a': 'b'}).ref('a').value() == 'b'
+    assert lookup("Hello").idx(1).value() == 'e'
+
+
+def test_simple_failing_lookups():
+    assert lookup(str).get('missing').value() is None
+    assert lookup(str).get('missing').get('x').value() is None
+    assert lookup(str).get('missing').ref('x').value() is None
+    assert lookup(str).get('missing').idx(0).value() is None
+    assert lookup(str).get('missing').find('Anything can go here').value() is None
+
+
+def test_expressions():
+    # Missing field
+    assert not Ref('field').run({})
+    # Present field
+    assert Ref('field').run({'field': 'anything'})
+    # Equality on missing field
+    assert not (Ref('field') == 'anything').run({'not': 'else'})
+    # Equality on present field with different value
+    assert not (Ref('field') == 'anything').run({'field': 'else'})
+    # Equality on present field with expected value
+    assert (Ref('field') == 'anything').run({'field': 'anything'})
+
+
+def test_find():
+    assert lookup([{'something': 'else'}, {'key': 'value'}]) \
+        .find(Ref('key')) \
+        .value() == {'key': 'value'}
+
+    assert lookup([{'something': 'else'}, {'key': 'value'}, {'key': '2'}]) \
+        .find(Ref('key') == '2') \
+        .ref('key') \
+        .value() == '2'
+
+    assert lookup([{'something': 'else'}, {'key': 'value'}]) \
+        .find(Ref('key') == '2') \
+        .ref('key') \
+        .value() is None