diff --git a/ldvspec/lofardata/forms.py b/ldvspec/lofardata/forms.py
index cb77f160e21be27d1091c60e7d1de0a88f607bc5..1d2cf1d1ddc0d989290af65ce3ee5d17a901f143 100644
--- a/ldvspec/lofardata/forms.py
+++ b/ldvspec/lofardata/forms.py
@@ -1,8 +1,8 @@
 from django.core.exceptions import ValidationError
 
-from .models import WorkSpecification, DataProductFilter
+from .models import WorkSpecification, DataProductFilter, Group
 
-from django.forms import ModelForm
+from django.forms import ModelForm, CharField
 
 
 class WorkSpecificationForm(ModelForm):
@@ -47,3 +47,24 @@ class WorkSpecificationForm(ModelForm):
                       'batch_size': "The number of files every task generated by this work specification should have. Example: 10 files in total can be split into 5 tasks of 2 files.",
                       'is_auto_submit': "By checking this box, the work specification will be directly sent to the processing site and thus does not need inspection."
                       }
+
+
+class GroupForm(ModelForm):
+    obs_ids = CharField(label='SAS IDs',
+                        help_text="A list of SAS IDs seprated with a comma+space. Example: 123, 456, 789",
+                        required=True)
+
+    class Meta:
+        model = Group
+        fields = ['name', 'selected_workflow', 'selected_workflow_tag', 'processing_site', 'obs_ids']
+        labels = {
+            'selected_workflow': 'Selected workflow',
+            'selected_workflow_tag': 'Workflow tag',
+            'processing_site': 'Processing Site (ATDB)',
+            'name': 'Name',
+        }
+        help_texts = {'selected_workflow': "The pipeline to run on the processing site.",
+                      'selected_workflow_tag': "The pipeline's tag as specified in ATDB.",
+                      'processing_site': "The ATDB processing site to run a specific workflow in.",
+                      'name': "A unique and custom name for this group"
+                      }
diff --git a/ldvspec/lofardata/templates/lofardata/group/create_update.html b/ldvspec/lofardata/templates/lofardata/group/create_update.html
new file mode 100644
index 0000000000000000000000000000000000000000..6609f01f6605dcbbecd0a35b74897a771ca32933
--- /dev/null
+++ b/ldvspec/lofardata/templates/lofardata/group/create_update.html
@@ -0,0 +1,172 @@
+{% extends 'lofardata/index.html' %}
+{% load static %}
+{% load crispy_forms_tags %}
+{% load define_action %}
+{% load widget_tweaks %}
+{% load json %}
+
+{% block myBlock %}
+    <div class="overlay">
+        <div class="modal-dias-wrapper">
+            <div class="modal-dias modal-dias--fit-content">
+                <a class="icon icon--times button--close" href="{% url 'index' %}"></a>
+                <header class="flex-wrapper flex-wrapper--centered flex-wrapper--column">
+                    {% if object.pk %}
+                        <h2 class="title text text--primary">Edit Group {{ object.pk }}</h2>
+                        <form method="post" action="{% url 'group-update' object.pk %}">
+                    {% else %}
+                        <h2 class="title text text--primary">New Group </h2>
+                        <form method="post" action="{% url 'group-create' %}">
+                    {% endif %}
+
+                    {% csrf_token %}
+                    <div class="flex-wrapper flex-wrapper--row flex-wrapper--start">
+                        <!-- Standard input fields -->
+                        <div class="custom--div-margin">
+                            <div class="flex-wrapper">
+                                <div class="flex-wrapper flex-wrapper--row custom__input--fixed-min-width">
+                                    <label class="input__label">{{ form.name.label }}*</label>
+                                    <a class="tooltip-dias tooltip-dias-right custom--tooltip"
+                                       data-tooltip="{{ form.name.help_text }}">m</a>
+                                </div>
+                                <input class="input input--text margin-left margin-bottom"
+                                       id="id_name" name="name"
+                                       test-id="name"
+                                       placeholder="Enter a group name" type="text">
+                            </div>
+
+
+                            <div class="flex-wrapper flex-wrapper--row" id="div_id_processing_site">
+                                <div class="flex-wrapper flex-wrapper--row custom__input--fixed-min-width">
+                                    <label class="input__label">{{ form.processing_site.label }}*</label>
+                                    <a class="tooltip-dias tooltip-dias-right custom--tooltip"
+                                       data-tooltip="{{ form.processing_site.help_text }}">m</a>
+                                </div>
+                                <div class="input-select-wrapper icon--inline icon-after icon-after--angle-down">
+                                    <select class="input input--select custom__input--fixed-width margin-left margin-bottom"
+                                            name="processing_site"
+                                            data-bind="options:processingSites,
+                                                       optionsCaption: '---------',
+                                                       optionsText: function(item) { return item.name + ' - ' + item.url},
+                                                       optionsValue: 'name',
+                                                       value: selectedProcessingSite"
+                                            test-id="processing_site"
+                                    ></select>
+                                </div>
+                            </div>
+
+
+                            <div class="flex-wrapper flex-wrapper--row" id="div_id_selected_workflow_tag">
+                                <div class="flex-wrapper flex-wrapper--row custom__input--fixed-min-width">
+                                    <label class="input__label"
+                                           for="id_selected_workflow_tag">{{ form.selected_workflow_tag.label_tag }}*</label>
+                                    <a class="tooltip-dias tooltip-dias-right custom--tooltip"
+                                       data-tooltip="{{ form.selected_workflow_tag.help_text }}">m</a>
+                                </div>
+                                <div class="input-select-wrapper icon--inline icon-after icon-after--angle-down">
+                                    <select class="input input--select custom__input--fixed-width margin-bottom margin-left"
+                                            id="id_selected_workflow_tag"
+                                            test-id="workflow_tag"
+                                            name="selected_workflow_tag"
+                                            style="width: 12rem"
+                                            data-bind="options:tags,
+                                                       optionsCaption: caption,
+                                                       value: selectedTag,
+                                                       disable: isLoading">
+                                    </select>
+                                </div>
+                            </div>
+
+
+                            <div class="flex-wrapper flex-wrapper--row" id="div_id_selected_workflow">
+                                <div class="flex-wrapper flex-wrapper--row custom__input--fixed-min-width">
+                                    <label class="input__label"
+                                           for="id_selected_workflow">{{ form.selected_workflow.label }}*</label>
+                                    <a class="tooltip-dias tooltip-dias-right custom--tooltip"
+                                       data-tooltip="{{ form.selected_workflow.help_text }}">m</a>
+                                </div>
+                                <div class="input-select-wrapper icon--inline icon-after icon-after--angle-down">
+                                    <select class="input input--select custom__input--fixed-width margin-bottom margin-left"
+                                            id="id_selected_workflow"
+                                            name="selected_workflow"
+                                            style="width: 12rem"
+                                            test-id="workflow"
+                                            data-bind="options:workflowsByTag,
+                                                   optionsCaption: caption,
+                                                   optionsValue: 'workflow_uri',
+                                                   optionsText: 'workflow_uri',
+                                                   value: selectedWorkflow,
+                                                   disable: isLoading">
+                                    </select>
+                                </div>
+                            </div>
+
+                            <div class="flex-wrapper">
+                                <div class="flex-wrapper flex-wrapper--row custom__input--fixed-min-width">
+                                    <label class="input__label">{{ form.obs_ids.label }}*</label>
+                                    <a class="tooltip-dias tooltip-dias-right custom--tooltip"
+                                       data-tooltip="{{ form.obs_ids.help_text }}">m</a>
+                                </div>
+                                <input class="input input--text margin-left margin-bottom"
+                                       id="id_obs_ids" name="obs_ids"
+                                       test-id="obs_ids"
+                                       placeholder="Enter a a list of SAS IDs" type="text">
+                            </div>
+
+                        </div>
+                    </div>
+
+                    <div class="flex-wrapper flex-wrapper--centered margin-bottom margin-top">
+                        <button class="button button--primary margin-right"
+                                type="submit"
+                                name="action"
+                                value="Submit"
+                                test-id="create-update"
+                                title="
+                                {% if object.pk %}
+                                Update the task
+                                {% else %}
+                                Create the task to inspect the result. Send it later to ATDB.
+                                {% endif %}">
+
+                            {% if object.pk %}
+                                Update
+                            {% else %}
+                                Create
+                            {% endif %}
+                        </button>
+                        <a class="button button--red button--primary margin-left" href="{% url 'index' %}">Cancel</a>
+                    </div>
+
+                    </form>
+                </header>
+                {% if form.errors %}
+                    <div class="popup-bar popup-bar--red">
+                        <span class="icon icon--left icon--color-inherit icon--times"></span>
+                        <div class="flex-wrapper flex-wrapper--column">
+                            The input is invalid:
+                            {% for field, errors in form.errors.items %}
+                                {% for error in errors %}
+                                    {% if field == '__all__' %}
+                                        <li class="text text--red text--faded">{{ error }}</li>
+                                    {% else %}
+                                        <li class="text text--red text--faded">{{ field }}: {{ error }}</li>
+                                    {% endif %}
+                                {% endfor %}
+                            {% endfor %}
+                        </div>
+                    </div>
+                {% endif %}
+            </div>
+        </div>
+    </div>
+    <script type='text/javascript' src='https://cdnjs.cloudflare.com/ajax/libs/knockout/3.5.0/knockout-min.js'></script>
+    <script type="text/javascript">
+        const processingSite = "{% url 'processingsite-detail' 'replace' %}";
+        const existingWorkflow = '{{ object.selected_workflow|default_if_none:"null" }}';
+        const existingWorkflowTag = '{{ object.selected_workflow_tag|default_if_none:"null" }}';
+        const processingSites = {{ processing_sites | json }};
+        const existingProcessingSite = '{{ object.processing_site.name }}';
+    </script>
+    <script src="{% static 'update_workflow.js' %}"></script>
+{% endblock %}
diff --git a/ldvspec/lofardata/templates/lofardata/index.html b/ldvspec/lofardata/templates/lofardata/index.html
index 4b7ed7683d8281d81d70e22cae3d43e59080a804..1e9895a21068cd7651afe5b57d94530f52e2a240 100644
--- a/ldvspec/lofardata/templates/lofardata/index.html
+++ b/ldvspec/lofardata/templates/lofardata/index.html
@@ -13,6 +13,10 @@
                title="Create a new work specification"
                href="{% url 'specification-create' %}">
                 <span class="icon icon--plus"></span></a>
+            <a class="button button--secondary button--icon-button margin-left"
+               title="Create a new group"
+               href="{% url 'group-create' %}">
+                <span class="icon icon--layer-plus"></span></a>
         </div>
 
         <div class="table">
diff --git a/ldvspec/lofardata/tests/test_group_creation.py b/ldvspec/lofardata/tests/test_group_creation.py
new file mode 100644
index 0000000000000000000000000000000000000000..037db535934d080df9eb727943f651b99dd234b4
--- /dev/null
+++ b/ldvspec/lofardata/tests/test_group_creation.py
@@ -0,0 +1,10 @@
+import unittest
+
+from lofardata.models import WorkSpecification, Group
+
+class WorkSpecificationCreation(unittest.TestCase):
+    def test_create_group_with_one_obs_id(self):
+        pass
+
+    def test_create_group_with_multiple_obs_ids(self):
+        pass
diff --git a/ldvspec/lofardata/urls.py b/ldvspec/lofardata/urls.py
index 2b1ff6b53c68d279a6165ed269e3f13b6079edcd..afcc17c81be747766bac4d816ff449359cc3aa6a 100644
--- a/ldvspec/lofardata/urls.py
+++ b/ldvspec/lofardata/urls.py
@@ -32,6 +32,8 @@ urlpatterns = [
     # GUI
     path('', views.Specifications.as_view(), name='index'),
     path('api/', views.api, name='api'),
+
+
     path('specification/<int:pk>/', views.WorkSpecificationDetailView.as_view(), name='specification-detail'),
     path('specification/add/', views.WorkSpecificationCreateUpdateView.as_view(), name='specification-create'),
     path('specification/update/<int:pk>/', views.WorkSpecificationCreateUpdateView.as_view(), name='specification-update'),
@@ -40,6 +42,8 @@ urlpatterns = [
     path('specification/tasks/<int:pk>/', views.WorkSpecificationATDBTasksView.as_view(), name='specification-tasks'),
     path('specification/dataset-size-info/<int:pk>/', views.WorkSpecificationDatasetSizeInfoView.as_view(), name='dataset-size-info'),
     path('specification/dataproducts/<int:pk>', views.DataProductViewPerSasID.as_view(), name='specification-dataproducts'),
+
+    path('group/add/', views.GroupCreateUpdateView.as_view(), name='group-create')
     # Workaround for injecting the urls from the ModelViewSet, which requires a "Router"
 
 
diff --git a/ldvspec/lofardata/views.py b/ldvspec/lofardata/views.py
index ecf0799379fb30b63a3855e9700d2eaa2d5c0939..c4a28b5778f89b5e39e919ea40f138da0ee09e16 100644
--- a/ldvspec/lofardata/views.py
+++ b/ldvspec/lofardata/views.py
@@ -14,13 +14,14 @@ from rest_framework.response import Response
 from rest_framework.reverse import reverse_lazy
 from rest_framework.schemas.openapi import AutoSchema
 
-from .forms import WorkSpecificationForm
+from .forms import WorkSpecificationForm, GroupForm
 from .mixins import CanAccessWorkSpecificationMixin
 from .models import (
     ATDBProcessingSite,
     DataProduct,
     DataProductFilter,
     WorkSpecification,
+    Group,
 )
 from .serializers import (
     ATDBProcessingSiteSerializer,
@@ -66,12 +67,14 @@ def api(request):
     atdb_hosts = ATDBProcessingSite.objects.values("name", "url")
     return render(request, "lofardata/api.html", {"atdb_hosts": atdb_hosts})
 
+
 def set_post_submit_values(specification, user):
     specification.async_task_result = None
     specification.is_ready = False
     if specification.created_by is None:
         specification.created_by = user
 
+
 class Specifications(ListView):
     serializer_class = WorkSpecificationSerializer
     template_name = "lofardata/index.html"
@@ -224,6 +227,7 @@ class DataProductViewPerSasID(LoginRequiredMixin, CanAccessWorkSpecificationMixi
     def get_object(self):
         return WorkSpecification.objects.get(pk=self.kwargs['pk'])
 
+
 # ---------- REST API views ----------
 class DataProductView(generics.ListCreateAPIView):
     model = DataProduct
@@ -289,3 +293,21 @@ class WorkSpecificationViewset(viewsets.ModelViewSet):
         time.sleep(1)  # allow for some time to pass
 
         return redirect("index")
+
+
+class GroupCreateUpdateView(LoginRequiredMixin, UpdateView):
+    template_name = "lofardata/group/create_update.html"
+    model = Group
+    form_class = GroupForm
+
+    def get_object(self, queryset=None):
+        if self.kwargs.__len__() == 0 or self.kwargs["pk"] is None:
+            group = Group()
+        else:
+            group = Group.objects.get(pk=self.kwargs["pk"])
+        return group
+
+    def get_context_data(self, **kwargs):
+        context = super().get_context_data(**kwargs)
+        context["processing_sites"] = list(ATDBProcessingSite.objects.values("name", "url"))
+        return context