SHACL Shapes
https://meta.linked.archi/archimate3/principle-shapes#
SHACL shapes encoding common enterprise architecture principles and best practices as executable constraints. These shapes validate architecture models against governance patterns such as redundancy avoidance, single authoritative source, separation of concerns, stewardship, and technology standardization. Inspired by the ontology-based EA principle validation approach described in: Montecchiari, D.; Hinkelmann, K. (2026) "Ontology-Based Validation of Enterprise Architecture Principles", Applied Sciences, 16(7):3352. These shapes are designed to be loaded alongside the standard ArchiMate element and relationship shapes. They operate on instance data (architecture models) and detect violations of common governance principles. All shapes use sh:severity sh:Warning by default — organizations should promote specific shapes to sh:Violation based on their governance policies. Usage: ./validate.sh --shacl archimate-principles Or load manually alongside other shapes: core-shapes.ttl + archimate3.2-principle-shapes.ttl + your-model-data.ttl
SELECT $this
WHERE {
$this a am:ApplicationComponent .
FILTER NOT EXISTS {
{ ?owner am:associatedWith $this . } UNION { $this am:associatedWith ?owner . }
{ ?owner a am:BusinessActor . } UNION { ?owner a am:BusinessRole . }
}
}
SELECT $this
WHERE {
$this a am:ApplicationComponent .
FILTER NOT EXISTS {
$this am:realizes ?svc .
?svc a am:ApplicationService .
}
}
SELECT $this
WHERE {
$this a am:ApplicationService .
FILTER NOT EXISTS {
?app am:realizes $this .
?app a am:ApplicationComponent .
}
}
SELECT $this ?app1 ?app2
WHERE {
$this rdf:type/rdfs:subClassOf* am:BehaviorElement .
$this rdf:type/rdfs:subClassOf* am:BusinessLayerElement .
?app1 a am:ApplicationComponent ;
am:realizes $this .
?app2 a am:ApplicationComponent ;
am:realizes $this .
FILTER(STR(?app1) < STR(?app2))
}
SELECT $this ?app1 ?app2
WHERE {
$this a am:BusinessFunction .
?app1 a am:ApplicationComponent ;
am:realizes $this .
?app2 a am:ApplicationComponent ;
am:realizes $this .
FILTER(STR(?app1) < STR(?app2))
}
SELECT $this ?tech
WHERE {
$this a am:BusinessProcess .
{
?tech am:serves $this .
} UNION {
?tech am:realizes $this .
}
?tech rdf:type/rdfs:subClassOf* am:TechnologyLayerElement .
}
SELECT $this
WHERE {
$this a am:BusinessProcess .
FILTER NOT EXISTS {
?role rdf:type/rdfs:subClassOf* am:ActiveStructureElement .
?role rdf:type/rdfs:subClassOf* am:BusinessLayerElement .
?role am:assignedTo $this .
}
}
SELECT $this
WHERE {
$this a am:BusinessService .
FILTER NOT EXISTS {
?behavior am:realizes $this .
?behavior rdf:type/rdfs:subClassOf* am:BehaviorElement .
?behavior rdf:type/rdfs:subClassOf* am:BusinessLayerElement .
}
}
SELECT $this
WHERE {
$this a am:Capability .
FILTER NOT EXISTS {
?behavior am:realizes $this .
?behavior rdf:type/rdfs:subClassOf* am:BehaviorElement .
?behavior rdf:type/rdfs:subClassOf* am:BusinessLayerElement .
}
}
SELECT $this
WHERE {
$this a am:Capability .
FILTER NOT EXISTS {
{
$this am:realizes ?goal .
{ ?goal a am:Goal . } UNION { ?goal a am:Outcome . }
} UNION {
?goal am:serves $this .
{ ?goal a am:Goal . } UNION { ?goal a am:Outcome . }
} UNION {
$this am:associatedWith ?goal .
{ ?goal a am:Goal . } UNION { ?goal a am:Outcome . }
}
}
}
PREFIX am: <https://meta.linked.archi/archimate3/onto#>
SELECT $this (COUNT(?parent) AS ?parentCount)
WHERE {
?parent am:composedOf $this .
}
GROUP BY $this
HAVING (COUNT(?parent) > 1)
SELECT $this ?node
WHERE {
$this a am:ApplicationComponent .
# Deployed on a node: the node realizes the component, or is assigned to an
# artifact or system software that does.
?node (am:realizes|am:assignedTo/am:realizes) $this .
?node a am:Node .
FILTER NOT EXISTS {
?node2 (am:realizes|am:assignedTo/am:realizes) $this .
?node2 a am:Node .
FILTER(?node2 != ?node)
}
}
SELECT $this
WHERE {
$this a am:DataObject .
FILTER NOT EXISTS {
?app a am:ApplicationComponent .
{
?app am:accesses $this .
} UNION {
?app am:realizes $this .
}
}
}
SELECT $this ?target
WHERE {
$this a am:ApplicationComponent .
$this am:serves ?target .
?target a am:ApplicationComponent .
}
SELECT $this (COUNT(DISTINCT ?node) AS ?nodeCount)
WHERE {
$this a am:ApplicationService .
?app am:realizes $this .
?app a am:ApplicationComponent .
# Technology it depends on: serving or realizing the component, or hosting
# what realizes it (a node assigned to an artifact or system software).
?node (am:serves|am:realizes|am:assignedTo/am:realizes) ?app .
?node rdf:type/rdfs:subClassOf* am:TechnologyLayerElement ,
am:ActiveStructureElement .
}
GROUP BY $this
HAVING (COUNT(DISTINCT ?node) > 3)
SELECT $this
WHERE {
$this a/rdfs:subClassOf* arch:Element .
# MINUS, not FILTER NOT EXISTS: the same results, without testing every
# element against every other one — which grows with the square of the model.
MINUS { $this ?p ?other . ?other a ?otherType . ?otherType rdfs:subClassOf* arch:Element . }
MINUS { ?other ?p $this . ?other a ?otherType . ?otherType rdfs:subClassOf* arch:Element . }
}
SELECT $this
WHERE {
$this a/rdfs:subClassOf* arch:Element .
# MINUS, not FILTER NOT EXISTS: the same results, without testing every
# element against every other one — which grows with the square of the model.
MINUS { $this ?p ?other . ?other a ?otherType . ?otherType rdfs:subClassOf* arch:Element . }
MINUS { ?other ?p $this . ?other a ?otherType . ?otherType rdfs:subClassOf* arch:Element . }
}
SELECT $this
WHERE {
$this a/rdfs:subClassOf* arch:Element .
# MINUS, not FILTER NOT EXISTS: the same results, without testing every
# element against every other one — which grows with the square of the model.
MINUS { $this ?p ?other . ?other a ?otherType . ?otherType rdfs:subClassOf* arch:Element . }
MINUS { ?other ?p $this . ?other a ?otherType . ?otherType rdfs:subClassOf* arch:Element . }
}
SELECT $this
WHERE {
$this a/rdfs:subClassOf* arch:Element .
# MINUS, not FILTER NOT EXISTS: the same results, without testing every
# element against every other one — which grows with the square of the model.
MINUS { $this ?p ?other . ?other a ?otherType . ?otherType rdfs:subClassOf* arch:Element . }
MINUS { ?other ?p $this . ?other a ?otherType . ?otherType rdfs:subClassOf* arch:Element . }
}
SELECT $this
WHERE {
$this a/rdfs:subClassOf* arch:Element .
# MINUS, not FILTER NOT EXISTS: the same results, without testing every
# element against every other one — which grows with the square of the model.
MINUS { $this ?p ?other . ?other a ?otherType . ?otherType rdfs:subClassOf* arch:Element . }
MINUS { ?other ?p $this . ?other a ?otherType . ?otherType rdfs:subClassOf* arch:Element . }
}
SELECT $this
WHERE {
$this a/rdfs:subClassOf* arch:Element .
# MINUS, not FILTER NOT EXISTS: the same results, without testing every
# element against every other one — which grows with the square of the model.
MINUS { $this ?p ?other . ?other a ?otherType . ?otherType rdfs:subClassOf* arch:Element . }
MINUS { ?other ?p $this . ?other a ?otherType . ?otherType rdfs:subClassOf* arch:Element . }
}
SELECT $this
WHERE {
$this a/rdfs:subClassOf* arch:Element .
# MINUS, not FILTER NOT EXISTS: the same results, without testing every
# element against every other one — which grows with the square of the model.
MINUS { $this ?p ?other . ?other a ?otherType . ?otherType rdfs:subClassOf* arch:Element . }
MINUS { ?other ?p $this . ?other a ?otherType . ?otherType rdfs:subClassOf* arch:Element . }
}
SELECT $this
WHERE {
$this a/rdfs:subClassOf* arch:Element .
# MINUS, not FILTER NOT EXISTS: the same results, without testing every
# element against every other one — which grows with the square of the model.
MINUS { $this ?p ?other . ?other a ?otherType . ?otherType rdfs:subClassOf* arch:Element . }
MINUS { ?other ?p $this . ?other a ?otherType . ?otherType rdfs:subClassOf* arch:Element . }
}
SELECT $this
WHERE {
$this a/rdfs:subClassOf* arch:Element .
# MINUS, not FILTER NOT EXISTS: the same results, without testing every
# element against every other one — which grows with the square of the model.
MINUS { $this ?p ?other . ?other a ?otherType . ?otherType rdfs:subClassOf* arch:Element . }
MINUS { ?other ?p $this . ?other a ?otherType . ?otherType rdfs:subClassOf* arch:Element . }
}
SELECT $this ?app1 ?app2
WHERE {
$this a am:ApplicationService .
?app1 a am:ApplicationComponent ;
am:realizes $this .
?app2 a am:ApplicationComponent ;
am:realizes $this .
FILTER(STR(?app1) < STR(?app2))
}
SELECT $this ?app1 ?app2
WHERE {
$this a am:BusinessProcess .
?app1 a am:ApplicationComponent ;
am:serves $this .
?app2 a am:ApplicationComponent ;
am:serves $this .
FILTER(STR(?app1) < STR(?app2))
}
SELECT $this ?app1 ?app2
WHERE {
$this a am:BusinessFunction .
?app1 a am:ApplicationComponent ;
am:serves $this .
?app2 a am:ApplicationComponent ;
am:serves $this .
FILTER(STR(?app1) < STR(?app2))
}
SELECT $this
WHERE {
$this a am:Requirement .
FILTER NOT EXISTS {
?element am:realizes $this .
FILTER NOT EXISTS {
?element rdf:type/rdfs:subClassOf* am:MotivationElement .
}
}
}
SELECT $this ?app1 ?app2
WHERE {
$this a am:BusinessObject .
?app1 a am:ApplicationComponent ;
am:accesses $this .
?app2 a am:ApplicationComponent ;
am:accesses $this .
FILTER(STR(?app1) < STR(?app2))
}
SELECT DISTINCT $this ?app1 ?app2
WHERE {
$this a am:DataObject .
# A writer: write or read/write access, or an access not stated to be a read.
?app1 a am:ApplicationComponent .
{
?app1 am:accesses $this .
FILTER NOT EXISTS { ?read1 a am:ReadAccess ; arch:source ?app1 ; arch:target $this . }
} UNION {
?write1 a ?kind1 ; arch:source ?app1 ; arch:target $this .
FILTER(?kind1 IN (am:WriteAccess, am:ReadWriteAccess))
}
?app2 a am:ApplicationComponent .
{
?app2 am:accesses $this .
FILTER NOT EXISTS { ?read2 a am:ReadAccess ; arch:source ?app2 ; arch:target $this . }
} UNION {
?write2 a ?kind2 ; arch:source ?app2 ; arch:target $this .
FILTER(?kind2 IN (am:WriteAccess, am:ReadWriteAccess))
}
FILTER(STR(?app1) < STR(?app2))
}
SELECT $this ?app
WHERE {
$this a am:BusinessService .
?app am:realizes $this .
?app a am:ApplicationComponent .
FILTER NOT EXISTS {
?app2 am:realizes $this .
?app2 a am:ApplicationComponent .
FILTER(?app2 != ?app)
}
}
SELECT $this ?biz
WHERE {
$this a am:Node .
$this am:serves ?biz .
?biz rdf:type/rdfs:subClassOf* am:BusinessLayerElement .
}