The TopBraid Teamwork Framework

This section provides a basic overview of the TopBraid Teamwork Framework (TTF) and its motivation. See also the dynamically generated list of Teamwork SPARQL functions, accessible from TopBraid Composer’s Help Menu.

You will need to understand TTF if you want to:

  • Programmatically access change history or working copies
  • Create new vocabulary types for Enterprise Data Governance
  • Make certain modifications to options available for pre-built vocabulary types

Why TTF?

TTF is a development and runtime framework for web-based multi-user read-write applications for different types of data assets or vocabularies.

For example, an application to work with SKOS-based Taxonomies consists of pages to create a new taxonomy, to manage user permissions, to track and review changes, to edit the taxonomy itself, to produce various reports and to run data exports and imports. Many of these capabilities are also applicable to other kinds of vocabularies, not just SKOS taxonomies. The role of TTF is to generalize those capabilities so that it becomes more efficient to develop similar applications in a componentized way.


Overview of TTF

TTF projects consist of two workspace files that connect to a database for data storage. The first database contains the actual data of the “master” graph. The second database, ending with “.tch” contains metadata that is used to keep track of changes, permissions and other vocabulary specific settings.

TTF vocabulary and asset types (sometimes called “project types”) are the kinds of models that are available to the end user.

Each vocabulary type is defined as a plugin to the teamwork framework. In a nutshell, each vocabulary type is backed by an instance of the class teamwork:ProjectType which is stored in an SWP file and points to the specific editors, plugins and other features that distinguish this vocabulary type from others. If you are interested in adding your own vocabulary types, see section:Vocabulary/Asset (Project) Types. You  can also modify features available for the pre-defined vocabulary types.

EDG home pages list all installed vocabulary/asset types. When a user clicks on the available type, they see a list of all vocabularies/assets of that type. From there, they have access to the available features.



Graphs, Permissions and Change Tracking

A combination of two related graphs, one containing the data and another one containing the change history of the data plus other information, is called a Teamwork project. This should not to be confused with the term Eclipse project. When using EDG, every vocabulary/asset is a Teamwork project. For the purposes of this discussion, Vocabulary/Asset is synonymous with Teamwork project.

This section introduces the two kinds of RDF graphs involved in a Teamwork project.



Anatomy of a Teamwork project

Each Teamwork project consists of two graphs that have corresponding .sdb connection files in the TopBraid workspace. You can explore those files by opening the files created via EDG within TBC-ME. (When doing this, note that you should not close either of the two .sdb files because this may invalidate the connection with the localhost server).

  • The master graph (e.g. XY.sdb) contains the actual data such as the edited SKOS concepts, also known as a “production copy”.
  • The TCH (or team) graph (e.g. XY.tch.sdb) contains metadata about the project, including the change history, available working copies, user permissions and comments.

TopBraid identifies Teamwork projects by their graph URIs: urn:x-evn-master:XY is the master graph for the vocabulary with the short id “XY”. Its metadata would be stored in urn:x-evn-master:XY.tch. The teamwork namespace contains SPARQL functions that can be used to derive those URNs from ids and to extract ids from a given URN. These functions are the preferred way of working with those graphs.

The project id (sometimes called graph id) is the short name of the vocabulary, usually consisting of letters only.



All users with access to the surrounding TopBraid Live server can log into the Teamwork pages. However, who is allowed to do what can be controlled by the system administrator as well as the corresponding vocabulary managers.

Teamwork supports the following three roles per vocabulary:

  • viewer: can only view a vocabulary or working copy, and make comments.
  • editor: same as viewer but also has editing rights to make changes to a vocabulary or working copy.
  • manager: same as editor but also has administrative control over a vocabulary or working copy, including the permission to grant or deny permissions to other users.

Any user can create a new vocabulary, and will become the initial manager of this project. At any given time, there must be at least one manager per vocabulary. The vocabulary home page can then be used to grant additional permissions to other known users. All of those permissions are stored in the TCH graph. For example if Administrator is the manager of the Teamworks project with the id XY, then the TCH graph will contain the following triple:

<urn:x-evn-master:XY.tch> teamwork:manager <urn:x-tb-users:Administrator>

As shown above, the URIs of the users are always following the same pattern. Use the SPARQL function smf:currentUserName() to access the currently logged in user, and smf:userWithName(?userName) to construct the user URIs as above.

In addition to assigning permission roles to individual users, it is also possible to assign roles to security roles from LDAP or tomcat. The UI provides simple drop down boxes for this. In terms of the internal RDF representation in the TCH graph, an LDAP role is represented with a URI such asurn:x-tb-role:ROLE.

You can get the union of all master graphs that the given user (in the example, : Administrator) has at least read access to by using special named graphs of the pattern urn:x-evn-union<:user>. For example, urn:x-evn-union:Administrator. This can be convenient for global search across multiple graphs. Note that such graphs are strictly read-only.


Change tracking


A change is an atomic unit of modifications to a given graph. They are usually created by the user through buttons and menu items such as the Create Concept buttons in EDG or the Save Changes button of the SWA edit forms. Whenever the user sends such a request to the server, master or working copy graph will be updated and the TCH graph will be updated with a new instance of teamwork:Change. An example Change object is shown below (in Turtle):

	a       teamwork:Change ;
	rdfs:comment "Create Class with URI"^^xsd:string ;
	dct:created "2013-04-03T00:32:05.915Z"^^xsd:dateTime ;
	sioc:has_creator <urn:x-tb-users:Administrator> ;
	[ teamwork:object owl:Class ;
		teamwork:predicate rdf:type ;
		teamwork:subject <>
  	] ;
  	[ teamwork:object "Sub3"^^xsd:string ;
		teamwork:predicate rdfs:label ;
		teamwork:subject <>
  	] ;
  	[ teamwork:object owl:Thing ;
		teamwork:predicate rdfs:subClassOf ;
		teamwork:subject <>
  	] ;
  	teamwork:status teamwork:Committed .

This is a set of changes indicating that the user:

  • Created a new class with the id
  • Set the label of the new class to “Sub3”
  • Made the class a subclass of owl:Thing

A change may also point to a working copy via teamwork:tag if it has been made while the user was editing a working copy. Each added or deleted triple is stored in reified form via teamwork:subjectteamwork:predicate and teamwork:object as shown above. This makes it possible to find all changes for a given resource via a SPARQL query over the TCH graph. Note that teamwork:deleted is used to point at triples that were deleted.

The teamwork:status triple of a change indicates whether the change has been committed to the master copy or whether it only exists in a working copy – in which case the value would be teamwork:Uncommitted.



Working copies (tags)


working copy (internally often called tag) is a specific collection of changes that have been made to the master graph, but have not been saved in the master graph. Since all these changes are stored only in the TCH graphs, the working copy is a virtual construct that is computed on demand only. TopBraid has a mechanism that can temporarily apply a set of changes to an RDF graph (without modifying the underlying graph). All changes that are part of a working copy are associated with the working copy via the property teamwork:tag.

In order to access a specific working copy for a given graph (with id “XY”), and tag “myTag”) use a graph URI such as urn:x-evn-tag:XY:myTag:Administrator. In general, although it is possible to create such URIs “manually”, the preferred mechanism is through the SPIN function  teamwork:queryGraph  as in the following example:

SELECT ?concept
	BIND (teamwork:queryGraph(true, "XY", "myTag", "Administrator") AS ?graph) .
	GRAPH ?graph {
		?concept a skos:Concept .

Comments and Tasks

EDG forms have a button to add a comment and/or task to the currently selected resource. These items are stored in the TCH graph, as instances of sioc:Post where the sioc:about property points at the resource. You can explore details by looking at the TCH graph.


Vocabulary/Asset Collection (Project) Types

This section explains how developers can add their own types of collections as alternatives to the pre-existing collection types defined for TopBraid EDG, such as SKOS Taxonomies, or Content Tag Sets. All collections of the same type share the same edit application and the same plugins. Note that defining custom collection types is a licensed feature of EDG. To upgrade a license file, please contact TopQuadrant.


Creating a new vocabulary/asset collection (project) type

Each of the default collection types that come with TopBraid EDG are plug-in modules within the more general Teamwork Framework. It is possible to add new modules by creating an instance of the class teamwork:ProjectType in a globally registered SWP file (ending with .ui.*). This file should import the file teamwork.ui.ttlx. The best practice is to create a new Eclipse workspace project and place your file within it.

Note that while you will be able to develop and test new project types in TopBraid Composer, once you deploy your code to the EDG server, new types of collections will only be available if your solution is licensed for creation of new asset collection types.

Simply create an instance of teamwork:ProjectType and fill in the properties similar to how it’s done in the default Ontology application (from ontologyprojects.ui.ttlx). You need to enter values for teamwork:singularLabel and teamwork:pluralLabel. You also need to enter value for the teamwork:vocabularyType. These values must be subclasses of the teamwork:Vocabulary class. For the ontology projects this value is ontologyprojects:Ontology. Under teamwork:Product select the one instance for EDG and add the “yourprojectype”:ProjectType to the defaultProjectType property

Once you have filled in the minimum properties for your new ProjectType, make sure that the framework “knows” about your new file by selecting Model > Refresh global SWP graphs…. Then you should already see a new tab for your vocabulary type on theEDGhomepage, on the same level as any other pre-existing vocabulary types such as Ontologies.


Create-new pages

The section for your new vocabulary/asset collection types on the home page will have a link to create a new vocabulary/asset collection of your type. The framework will use the singular or plural labels that you have specified wherever possible, so the link may be “Create New My Custom Collection” if that’s how you have called it. The link will by default go to a default create page where the user can enter label, default namespace and a description of the new asset collection.

If you need additional parameters at creation time, take a look at how this is done in the case of Crosswalks, in crosswalkprojects:CreateProjectPage.


Project plug-ins

As you might know, the main page of any collection’s production or working copy contains links to various “utilities” features such as Import/Export, Report, etc. These come from plug-ins. You may want to explore the standard plug-ins shipped as part of the Teamwork Framework, e.g.teamwork:TurtleFileExportPlugin.

In a freshly created teamwork:ProjectType, no plug-in would show up. You need to select those plug-in that you want to expose via the teamwork:projectPlugin property.

There is also a generic SPARQLMotion-based importer mechanism that applies to all vocabulary types. Such importers receive an uploaded file as input and produce triples that shall be added to the current vocabulary or working copy. Open the file teamworkscripts.ttl in TBC-ME and read the supplied comments to learn more about this feature.


Custom icon for project type

To add a custom icon to the project type:

Search the properties pane for edg.v:icon and drag this property onto your new project type resource form, give it a value.


The value for custom icons must start with the string “custom-” or they will be ignored and the default icon (a circle) will be used. Add a style block which defines your custom icon style like seen below. This can live in any external stylesheet. We suggest you create your own “*.www” directory to hold these types of customizations.

#primaryNav .custom-menu-icon {
background-image: url("");

(Ensure that the sytlesheet is loaded in the application pages.)


Extending the Problems and Suggestions Reports

The Problems and Suggestions report feature implements data quality rules for collections (see a collection type’s User Guide …Utilities > Reports > Problems and Suggestions Report for documentation). This feature includes an extension point allowing developers to plug in their own algorithms written in Java or SWP. For an example of SWP-based suggestion generators, in TBC open tosh.ui.ttlx, select tosh:ResultsGenerator and go to Resource > Find usages in workspace. Use a copy of the example(s) as a starting point.




The Teamwork Framework includes a notifications mechanism that can be configured to send notification emails (and other notification) to subscribers. The process to set this up consists of two steps:

  1. Assign organizations, persons, users or user groups to RACI roles using the Metadata tab
  2. Select which notification events shall be triggered for which RACI role

New notification types can be added by creating subclasses of teamwork:Notifications in a .ui. file. There are two ways of triggering notifications:

  • Manually, by calling the SWP element teamwork:sendNotifications
  • By hooking into direct changes against the master graph (subclassing teamwork:MasterEditNotifications) or the TCH graph (subclassingteamwork:TCHEditNotifications). In those cases, an arg:expression needs to be specified to determine whether the notification must be sent for the given set of changes.

The file teamworknotifications.ui.ttlx contains plenty of examples.

In order to have notifications sent to other channels than emails, you need to create a new SWP file with .ui.ttlx ending, and define a subclass ofteamwork:sendNotifications that points at teamwork:sendNotifications via ui:overrides. In the ui:prototype of that subclass, you may repurpose the incoming arguments such as ?text, for example, to call sml:ExportToJMS for output into a JMS bus.




Adding New Tabs for Asset Collections

Developers can add new tabs to the tab-bars of asset collections. These tabs can appear on all or some asset collections. To create a new project tab, create a subclass of teamwork:ProjectTabs and use the following properties to configure that tab:

  • rdfs:label for its title
  • ui:prototype for its content (written in SWP, with the variables ?projectGraph for the current asset collection and ?tag for the current workflow, if any)
  • teamwork:pluginIndex to control its position within the tab bar
  • teamwork:pluginRequiresRole if the plugin should be visible only to users with the teamwork:editor or teamwork:manager role
  • teamwork:validForTags to control whether the tab is accessible while in a workflow (If this is set to true, the tab should also be made subclass of teamwork:TagElements to inherit the ?tag argument.)

To control what asset collections the tab appears on, there are various options:

  • To enable it for selected asset collection types, add it to the respective teamwork:ProjectType instances as a teamwork:projectPlugin.
  • To enable it for all asset collections, set the tab’s teamwork:pluginValidExpression to true
  • To enable it for selected asset collections based on an arbitrary condition, set the tab’s teamwork:pluginValidExpression to a SPARQL expression that checks for the condition, using the variables ?projectGraph and ?tag.
  • To disable it for selected asset collection types, add it to the the respective teamwork:ProjectType instances as a teamwork:disabledPlugin.


Customizing the Governance Roles

The pre-built EDG governance roles can be removed and new custom roles added within EDG. Please see the instructions below for this customization. 




In TopBraid EDG

  1. Create a new Ontology asset collection
  2. Use Settings->Includes to include EDG Schema – Governance Assets
  3. To disable existing governance roles:
    1. Navigate to the class Stewardship
    2. In the Properties Group panel select the role to be disabled, e.g., application steward
    3. Edit and set deactivated to true
  4. To add a new governance role:
    1. Add RDF/OWL Properties List panel to your editor layout
    2. Use New button in this panel to create a new property. Provide the label for your new role. Select property type as Workflow property. provide a value for  abbreviation for the role. You will see a warning about needing a shape for this property. Click “Submit Anyway”.
    3. Add comment to provide a description of the responsibilities of the new governance role
    4. Navigate to the class Stewardship
    5. For this class, create a new Relationship using the new property as the path. In the Create dialog’s label, type the label exactly the same as the label you provided for the new property. This will insure that the right ID (URI) is used. Make sure that the Property Group is Governance Roles.
    6. Edit the new relationship to set the value of editor to Workflow participant editor and value of viewer to Workflow participant viewer. Optionally, adjust the order in which the governance roles will appear in the EDG user interface.
  5. In the users tab for this collection, give read permission to all users or security roles for EDG.  If you don’t do this step, users without permission will be unable to access many features of EDG.
  6. Navigate to the Settings tab of the Governance Model asset collection, include the Ontology containing your customizations. 

Adding Custom Workflow Templates


The stages that a workflow goes through are defined by in a workflow template. The Workflow Templates page allows users to view and, if permitted, modify the workflow templates. The workflow templates are defined in RDF in a dedicated graph, accessible via the function teamwork:workflowsGraph() in SPARQL queries. Users with a Teamwork Administrator Role in the EDG Configuration Parameters page are permitted to edit workflow template definitions.

Editing workflow templates is a low-level operation that should be handled with care. It is technically possible to modify workflow templates that are already in use and, as a result of this, an existing working copy may be in a state that gets disconnected from the other states in the template, or its whole workflow template may get deleted. We therefore strongly recommend that the development and editing of workflow templates is performed by expert users only, and tested in a sandbox environment (such as a TBC-ME instance) before deployment to a production server. Alternatively, consider having a TopQuadrant services develop custom workflows.


EDG comes with a default workflow called Basic workflow. Once you add your custom workflow templates, the Basic Workflow will be removed in EDG 7. To add the Basic workflow back, navigate to the Workflow Templates page and click “Install Default Workflow Templates”. When clicked the default workflow will be added to the customizations graph.


The editing of workflow templates is currently performed via TBC or source code editing. For Teamwork Administrators, the basic mechanism is:

  1. Go to Workflow Templates on the production server
  2. Click Download as Turtle File to a local file
  3. Edit this file using TobBraid Composer (or a text editor of your choice). Note that also attached to this page (see below), is an example template file, which has workflow diagram layouts, with positioning, widths, and heights.
  4. In a test environment, use Upload Turtle File to replace the current definitions
  5. If any errors are detected, the Upload feature present a report of all the errors found in the file. These errors must be addressed in order for the file to be successfully uploaded.
  6. Carefully test the workflows in your test environment
  7. When satisfied, use Upload Turtle File to replace the definitions on the production server

Defining workflow template status


Each workflow template defines a start status (e.g. Uncommitted) and a set of transitions that specify which steps are possible and by whom, until the workflow is ended (e.g. by committing). The following list enumerates frequently used properties at workflow templates:

  • rdf:type: workflow templates must have rdf:type teamwork:TagWorkflowTemplate (for general asset workflows), teamwork:ExistingResourceTagWorkflowTemplate (for workflows that are specific to an existing asset), or teamwork:NewResourceTagWorkflowTemplate (for workflows that create a new asset).
  • rdfs:label: a human-readable label that is used to name the workflow template in the user interface
  • teamwork:defaultTagWorkflowTemplateForProjectType: enumerates the asset collection types for which the workflow template is the default. Asset collection types that don’t have any default workflow template fall back to the system-wide default workflow template. For example, use edg:GlossaryProjectType as a value to make the workflow template the default for EDG Glossaries.
  • teamwork:suitableWorkflowForProjectType: enumerates the asset collection types for which the workflow template is suitable for use. If left empty, it applies to all types. For example, use edg:GlossaryProjectType as the value to make the workflow template only applicable to EDG Glossaries.
  • teamwork:suitableWorkflowForSubjectArea: the subject areas that asset collection must have so that the workflow template is suitable for them. If left empty, then it applies to all subject areas. Details about defining subject areas can be found at EDG Governance Model: Governance Areas
  • teamwork:editorWorkflowParticipantProperty: lists the workflow participant properties (e.g. edg:responsible) whose users are automatically granted editing permission. By default, workflow participants only get viewer permission.
  • teamwork:managerWorkflowParticipantProperty: lists the workflow participant properties (e.g. edg:responsible) whose users are automatically granted manager permission. By default, workflow participants only get viewer permission.
  • teamwork:initialStatus: specifies the initial status of a Workflow. Example values include teamwork:Uncommitted or teamwork:New.
  • teamwork:tagShape: (advanced feature) SHACL shapes that the working copy needs to conform to before it can be committed. These are validated using the union of the working copy and the TCH graph as data graph, and the workflows definitions graph as shapes graph. The focus node is the teamwork:Tag instance. There is an example below.

An additional property for templates that have the type teamwork:ExistingResourceTagWorkflowTemplate:

  • teamwork:editedResourceShape: the shape that edited resources need to have. Used to filter applicable workflows for a given resource. If multiple values are present then they are interpreted as a union, i.e. a candidate resource must conform to any one of them. An example of this is teamwork:editedResourceShape [ sh:class ex:Person ] to limit a workflow for instances of ex:Person.

Defining workflow template transitions


A workflow is started in the status specified by teamwork:initialStatus in the template. From there, the possible transitions are defined by the values of teamwork:transition. These values must be URI or blank nodes of type teamwork:TagStatusTransition, and can have the following properties:

  • teamwork:fromStatus: the status that the workflow (working copy) must be in for the transition to be applied.
  • teamwork:toStatus: the status that the workflow (working copy) will be in after the transition is applied.
  • teamwork:transitionLabel: the display label of the transition, e.g. “Accept changes to production”.
  • sh:order: an optional number that is used to order the transitions in the Workflow tab. Transitions with smaller numbers show up higher, with 0 being the default.
  • teamwork:requiredGovernanceRole: the minimum governance role (e.g. informed) that a user must have on an asset collection to perform the transition. For example, the required governance role can be an instance of edg:JobRole, which means that any user who has edg:assignedJobRole edg:JobRole is allowed to execute the transition. The user will in this case see a corresponding button in the UI, and under My Workflows.
  • teamwork:requiredProjectPermissionRole: the minimum permission role (e.g. editor) that a user must have on an asset collection (master graph) to perform the transition. These are the roles defined on the User Roles tab of an asset collection.
  • teamwork:requiredTagPermissionRole: the minimum permission role (e.g. editor) that a user must have on a working copy to perform the transition. These are the roles defined on the User Roles tab of a working copy/workflow.
  • teamwork:minVoteCount: the minimum number of votes required before the transition can be performed.
  • teamwork:voteAutoTransitions: if true then the transition will be performed automatically, as soon as sufficient votes have been registered. This property can only be used if teamwork:minVoteCount is present.
  • teamwork:autoTransitionHours: the number of hours after which a working copy will automatically transition to another state. For example this can be used to give users a chance to comment without explicitly waiting on such feedback.

Example workflow templates


The example workflow templates can be downloaded from this page.


Example of teamwork:tagShape


This example illustrates the use of teamwork:tagShape to specify that a working copy can only be committed if it contains exactly one new instance of edg:GlossaryTerm and no other subject. If teamwork:tagShape statements are present for a workflow template, then the Commit button will force the user to first go through a dedicated page that checks whether the working copy conforms to the specified shapes. If violations are detected, the user may still proceed, yet he or she has been warned about the consequences.

    rdf:type teamwork:NewResourceTagWorkflowTemplate ;
    teamwork:initialStatus teamwork:Uncommitted ;
    teamwork:tagShape glossary-term-workflow:TagHasExactlyOneGlossaryTermShape ;

    rdf:type sh:NodeShape ;
    sh:sparql [
        sh:message "Working copy contains changes about {?other} while it should only be about {?newTerm}" ;
        sh:prefixes <> ;
        sh:select """
            SELECT DISTINCT $this ?other ?newTerm
            WHERE {
                ?change teamwork:tag $this .
                ?change a teamwork:Change .
                ?change teamwork:added ?added .
                ?added teamwork:subject ?newTerm .
                ?added teamwork:predicate rdf:type .
                ?added teamwork:object edg:GlossaryTerm .
                ?otherChange teamwork:tag $this .
                ?otherChange a teamwork:Change .
                ?otherChange teamwork:added|teamwork:deleted ?aod .
                ?aod teamwork:subject ?other .
                FILTER (?other != ?newTerm) .
            }""" ;
    ] ;
    sh:sparql [
        sh:message "Working copy does not create a new instance of edg:GlossaryTerm." ;
        sh:prefixes <> ;
        sh:select """
            SELECT $this
            WHERE {
                FILTER NOT EXISTS {
                    ?change teamwork:tag $this .
                    ?change a teamwork:Change .
                    ?change teamwork:added ?added .
                    ?added teamwork:subject ?gt .
                    ?added teamwork:predicate rdf:type .
                    ?added teamwork:object edg:GlossaryTerm .
            }""" ;
    ] .


Detailed training guide for workflow templates, custom governance roles and event condition actions


All of this content is also in the page above but without detailed screenshots. The screenshots may not be exact representations of the version you are on but should still be helpful in showing the process. This is meant to suppliment what you have learned in the above sections of this guide.

Download the guide Teamworks and Workflow Templates for details on:

  • Custom Governance Roles
  • Teamworks and Technical Underpinnings of Working Copies
  • Workflow Templates
  • Notifications
  • ECA Framework


Calling an external service from a workflow


The following example shows how to create an SWP customization that calls an external service when any workflow is committed. Prior experience with SWP and using TopBraid Composer is required.

This example will take the triples added to a workflow and upon commit send the triples in JSON to this ficticious external service.

 a owl:Ontology ;
 rdfs:comment "This installs a teamwork:CommitRule that gets invoked whenever a workflow has been committed
. It will produce a JSON string with all added triples and then send a POST request with that JSON as 
parameter. In this case, for testing purposes, the receiving service is also written in TopBraid's SWP 
and simply echos the JSON back and prints it to the log." ;
 owl:imports <> ;
 owl:versionInfo "Created with TopBraid Composer" ;
 a teamwork:CommitRule ;
 ui:prototype """
 <!-- Produces a JSON array with { subject, predicate, object } objects for each added triple -->
 <ui:stringify ui:varName=\"json\">
 <swon:RSObjectArray arg:resultSet=\"{#
 SELECT ?subject ?predicate ?object
 GRAPH ui:addedGraph {
 ?subject ?predicate ?object .
 } .
 } }\"/>
 <!-- Post this someplace (here, a dummy URL to TopBraid itself -->
 <sml:PostRequest arg:json=\"{= ?json }\" sml:url=\"http://localhost:8083/tbl/swp?_viewClass=commitrule:ReceiverService\"/>
"""^^ui:Literal ;
 rdfs:label "Demo commit rule" ;
 rdfs:subClassOf teamwork:CommitRules ;
 a ui:Service ;
 spin:constraint [
 a spl:Argument ;
 spl:predicate arg:json ;
 spl:valueType xsd:string ;
 rdfs:comment "The JSON to echo back." ;
 ] ;
 ui:prototype """
 <ui:log ui:info=\"Received: {= ?json }\"/>
 <ui:group>{= ?json }</ui:group>
"""^^ui:Literal ;
 rdfs:label "Receiver service" ;
 rdfs:subClassOf ui:JSONServices ;