diff --git a/shared/workspaces/workspaces/capability/statemachine.py b/shared/workspaces/workspaces/capability/statemachine.py
new file mode 100644
index 0000000000000000000000000000000000000000..cbc5f0e820046cbd9e741f5bc8e3997a9c276c22
--- /dev/null
+++ b/shared/workspaces/workspaces/capability/statemachine.py
@@ -0,0 +1,192 @@
+"""
+Prototype of the state machine concept for capability execution.
+
+The idea here is to replace the step sequence with a state machine. The state machine
+reacts to certain events by triggering actions and going into another state.
+"""
+import abc
+import json
+
+
+class State(abc.ABC):
+    """
+    A state that a machine could reside in.
+    """
+    @abc.abstractmethod
+    def matches(self, other: "State") -> bool:
+        """
+        This is most likely implemented by doing a string-equality test.
+
+        :param other:  the other state to compare to
+        :return:  true if we and the other state match
+        """
+        pass
+
+
+class Action(abc.ABC):
+    """
+    An action to take upon performing a transition. We expect to see several implementations
+    of this interface:
+
+    - SendNotification(template, additional_args) that sends a notification with
+      the event and additional arguments
+
+    - StartWorkflow(workflow_name, additional_args) that starts a workflow with the
+      provided name, the event and additional arguments
+    """
+    @abc.abstractmethod
+    def execute(self):
+        pass
+
+
+class Pattern(abc.ABC):
+    @abc.abstractmethod
+    def matches(self, event: dict) -> bool:
+        """
+        This is most likely going to be implemented as a JSON Path expression, using
+        the jsonpath-python library: https://pypi.org/project/jsonpath-python/
+
+        :param event: a JSON object
+        :return: true if this pattern matches that event object
+        """
+        pass
+
+
+class TransitionIF(abc.ABC):
+    """
+    A transition between states
+    """
+    def __init__(self, from_state: State, to_state: State, pattern: Pattern, action: Action):
+        self.from_state, self.to_state = from_state, to_state
+        self.pattern = pattern
+        self.action = action
+
+    @abc.abstractmethod
+    def matches(self, state: State, event: dict) -> bool:
+        """
+        True if this transition is applicable in the supplied state and matches the supplied event.
+        :param state: state to check against
+        :param event: event to match against
+        :return: true if everything matches
+        """
+        return self.from_state.matches(state) and self.pattern.matches(event)
+
+    @abc.abstractmethod
+    def take(self) -> State:
+        """
+        Take this transition. Perform the action associated with this transition and then
+        reveal the new state to the caller.
+
+        :return: the new state
+        """
+        self.action.execute()
+        return self.to_state
+
+
+class MealyMachine:
+    """
+    I am a state machine for a given capability. I am responsible for handling events
+    and transitioning to other states.
+    """
+    def __init__(self):
+        self.transitions = []
+        self.current_state: State = None
+
+    def on_event(self, event: dict):
+        """
+        Process an event and possibly take a transition.
+
+        This is more of an example of how this could be done than an efficient way
+        to do it.
+
+        :param event:
+        :return:
+        """
+        # look through our transitions to see if we have one that matches
+        # for the state we're currently in
+        for transition in self.transitions:
+
+            # we're going off a "first match wins" algorithm here
+            # if multiple transitions match, make sure the most specific
+            # patterns occur earlier in the list of transitions
+            if transition.matches(self.current_state, event):
+                # take the transition
+                self.current_state = transition.take(self)
+
+                # do not look for another transition
+                break
+
+
+class CapabilityInfoForMachines:
+    """
+    This is a demonstration of the sort of query I expect we'll use to locate executions
+    that are active and need to be acted on in response to an event of some kind.
+    """
+    def find_requests_matching_transition(self, event: dict) -> list["CapabilityExecution"]:
+        """
+        The concept here is to let the database do the heavy lifting and actually tell us
+        whether there are any executions that are both in the right state and matching
+        this event, that we would therefore need to act on.
+
+        :param event:  the event to check
+        :return:       a list of matching capability executions
+        """
+        return self.session.query("""
+        SELECT * 
+        FROM transitions t
+        JOIN machines m ON t.machine_id = m.id
+        JOIN capabilities c ON c.machine_id = m.id
+        JOIN capability_requests cr on cr.capability_name = c.name
+        JOIN capability_executions ce on cr.capability_request_id = ce.capability_request_id
+        WHERE %(event)s @? t.pattern AND ce.state = t.from_state
+        """, {"event": json.dumps(event)})
+
+    def build_tables(self):
+        """
+        This is just a demonstration method to hold some SQL to demo the tables I have
+        in mind for this system.
+        """
+        self.session.execute("""
+        CREATE TABLE machines(id serial primary key);
+        CREATE TABLE actions(id serial primary key, action_type varchar, action_arguments json);
+        
+        CREATE TABLE transitions (
+            id serial primary key, 
+            machine_id integer references(machines),
+            from_state varchar, 
+            to_state varchar, 
+            pattern jsonpath, 
+            action_id integer references(actions)
+        );
+         
+        """)
+
+
+class CapabilityExecution:
+    def process(self, event):
+        self.machine.on_event(event)
+
+
+class CapabilityServiceMachineMananger:
+    """
+    This is a demonstration of how to handle state transitions without keeping explicit
+    machines alive during the execution of the program. The idea here is to be more
+    efficient and more event-driven.
+    """
+    def __init__(self):
+        self.info = CapabilityInfoForMachines()
+
+    def on_event(self, event: dict):
+        # we get an event, we just try and find matches for it
+        for execution in self.info.find_requests_matching_transition(event):
+            # now we have the execution in hand, we can process the event.
+            execution.process(event)
+
+            # another approach here would be to be more explicit about what
+            # transition matched and prevent the execution from really doing
+            # any real thinking, something like this (assuming "transition" is
+            # the matching transition, returned from the SQL alchemy query):
+            # execution.state = execution.transition.take(event)
+
+            # we don't need to hold this execution in memory, so nothing else has
+            # to be done here