Bridging Architecture Silos — From Scattered Models to a Queryable Knowledge Graph¶
The gap¶
Enterprise architecture modelling languages are expressive enough to capture an organisation's architecture in formal detail. ArchiMate spans strategy to infrastructure; BPMN captures processes; UML captures software design; Backstage captures the service catalog. Between them, the whole range is covered. Expressiveness isn't the problem — and the fact that it takes several notations to cover the range is exactly why a shared graph matters later.
The problem is that capturing the architecture isn't the same as making it usable. The models hold data — what exists — while the knowledge that makes it actionable stays tacit, unwritten, and reachable only by asking the architect — or someone who can read not just the model but the modeling choices behind it. Even in ArchiMate, every model embeds tailoring decisions: which element type stands for what in this organization, which relationships were deliberate and which were convenience, what convention a given layer follows. Those choices are the interpretive key to the model, and they are rarely written down — and almost never in a form a machine can read. The data that is captured tends to stay locked inside tools only architects open. The people who actually make decisions rarely do. A developer choosing how to integrate, a compliance officer checking a control, an on-call engineer tracing what breaks if a service goes down: none of them live in the modeling tool, and none of them would read an ArchiMate diagram if they did. So the architecture exists, but only as data behind a specialist tool — and the knowledge that would make it useful (why this platform is the strategic one, what breaks if it goes, which integration pattern the principles demand) was rarely made explicit at all. It lives in a few architects' heads, and it leaves with them.
This isn't a training problem, and the answer isn't to teach everyone ArchiMate. Developers shouldn't be working in it — they think in API contracts, deployment dependencies, and service catalogs, and they have notations that fit: C4 and PlantUML for structure, Backstage for the catalog. Architects work in ArchiMate; analysts in BPMN. The mistake is assuming one notation should serve everyone. Each audience models in the language native to its concerns — and the graph is what lets those notations coexist instead of fragmenting into disconnected tools.
The Linked.Archi approach is: model in whatever notation fits the author, then let a shared knowledge graph do two things the tool can't — turn that captured data into queryable knowledge by applying the ontology, and deliver it in whatever form fits the consumer. The graph isn't a delivery channel for knowledge that already exists; it's the engine that produces knowledge from information.
Two ways to unify, and the one we use¶
Two approaches to unifying heterogeneous vocabularies — collapsing into one (lossy) versus federating via a canonical superclass layer (lossless).
When ArchiMate, Backstage, BPMN, and others all land in one graph, their vocabularies
do not automatically align: an ArchiMate am4:ApplicationComponent, a Backstage
bs:Component, and a C4 c4:Container are related concepts but not identical ones,
and each notation draws the distinctions it draws on purpose. There are two ways to
reconcile them.
Collapse — convert every source into one vocabulary, discarding the native types. Simple to query, but it throws away the very distinctions the notations were chosen to capture, and it forces the converter to make lossy decisions it then hides.
Federate — keep each native type, and add a thin canonical layer of shared
superclasses above them. This is the approach we use. Both am4:ApplicationComponent
and bs:Component are declared rdfs:subClassOf a canonical ex-org:Application.
Nothing is discarded: the native types remain queryable in full fidelity, and the
canonical superclass gives a single handle for cross-source questions. The one OWL
inference the profile retains — subsumption — does the unification automatically.
This canonical vocabulary is itself a module (an integration module), not part of
arch:core. Core stays domain-neutral — it defines only arch:Element,
arch:Relationship, and the framework scaffolding, with no opinion about what an
"application" is. An organization that federates across notations adopts the canonical
module; one that uses a single notation never needs it. The canonical layer is a
deliberate, opt-in choice, not a built-in assumption.
The canonical module¶
The integration module is small and self-contained. It declares a handful of canonical superclasses, a few canonical properties, and the axioms that bind the notation vocabularies to them. The notation ontologies are not edited — the subclass and subproperty axioms live here, in the integration module, so adopting or dropping federation is a single-file decision.
@prefix ex-org: <https://example.org/arch/onto#> .
@prefix arch: <https://meta.linked.archi/core#> .
@prefix am4: <https://meta.linked.archi/archimate4/onto#> .
@prefix bs: <https://meta.linked.archi/backstage/onto#> .
@prefix owl: <http://www.w3.org/2002/07/owl#> .
@prefix rdfs: <http://www.w3.org/2000/01/rdf-schema#> .
@prefix skos: <http://www.w3.org/2004/02/skos/core#> .
<https://example.org/arch>
a owl:Ontology, arch:Metamodel ;
rdfs:label "Canonical Integration Layer"@en ;
rdfs:comment
"Source-neutral superclasses and properties that federate notation vocabularies for cross-source querying. Imports core; imported by no notation."@en ;
owl:imports <https://meta.linked.archi/core> .
# --- Canonical classes (subclasses of arch:Element, parents of native types) ---
ex-org:Application
a owl:Class ;
rdfs:subClassOf arch:Element ;
skos:prefLabel "Application"@en ;
skos:definition "A deployable software unit, however a source notation names it."@en .
ex-org:Service
a owl:Class ;
rdfs:subClassOf arch:Element ;
skos:prefLabel "Service"@en ;
skos:definition "An exposed unit of functionality."@en .
ex-org:Capability
a owl:Class ;
rdfs:subClassOf arch:Element ;
skos:prefLabel "Capability"@en ;
skos:definition "A business ability that services and applications support."@en .
ex-org:Team
a owl:Class ;
rdfs:subClassOf arch:Element ;
skos:prefLabel "Team"@en ;
skos:definition "An organizational group that can own elements."@en .
# --- Bind native notation classes to the canonical parents ---
# (these axioms are the federation; they live ONLY here)
# ArchiMate 4.0: Service and Role are merged Common-Domain elements;
# there is no separate Business/ApplicationService or BusinessRole.
am4:ApplicationComponent
rdfs:subClassOf ex-org:Application .
bs:Component
rdfs:subClassOf ex-org:Application .
am4:Service
rdfs:subClassOf ex-org:Service .
am4:Capability
rdfs:subClassOf ex-org:Capability .
am4:Role
rdfs:subClassOf ex-org:Team .
bs:Group
rdfs:subClassOf ex-org:Team .
# --- Canonical properties, with native predicates mapped up via subPropertyOf ---
# so a query or shape can use ex-org:ownedBy regardless of source.
ex-org:ownedBy
a owl:ObjectProperty ;
rdfs:subPropertyOf arch:relatesTo ; # VERIFY core's generic relation name
rdfs:label "owned by"@en ;
arch:domainIncludes ex-org:Application ;
arch:rangeIncludes ex-org:Team .
bs:ownedBy
rdfs:subPropertyOf ex-org:ownedBy .
# ArchiMate has no built-in "ownership" predicate; if your models express it
# (e.g. via assignment of a Role, or a custom property), map THAT predicate here:
# <thatPredicate> rdfs:subPropertyOf ex-org:ownedBy .
Tailored ontology classes¶
The canonical integration module holds both broad superclasses and org-specific tailored refinements. Notation ontologies remain separate modules — converters classify into tailored types and project to notation types for export.
The canonical module should be used for broad, source-neutral concepts that sit above modelling-language vocabularies: for example, am4:ApplicationComponent, c4:Container, and bs:Component can all be declared subclasses of a canonical ex-org:Application so cross-source queries have one stable handle without losing the native types. A tailored ontology may also define organization-specific concepts that are more precise than the modelling-language classes themselves, but these should be handled differently. Such tailored classes should normally subclass the canonical concept — for example, ex-org:PublicFacingWebApp rdfs:subClassOf ex-org:Application — while their relationship to ArchiMate, C4, Backstage, or other notation classes is expressed as a projection or mapping rule rather than an automatic logical superclass/subclass claim. Only where the semantics and granularity are strictly safe should a tailored class also be declared rdfs:subClassOf a notation class. In conversion, this means the converter should not merely flatten a tailored ArchiMate model into generic am4: types; it should classify each instance into the most specific tailored class it can justify, preserve provenance for that classification, and then let generation rules project that tailored class into the target notation — for example as an ArchiMate Application Component, a C4 Container, or a Backstage Component. This keeps three things separate: broad federation for querying, tailored classification for organizational meaning, and notation-specific projection for export and delivery.
A note on the canonical mappings under 4.0¶
ArchiMate 4.0's restructuring actually helps the canonical layer. Because 4.0 merged
the per-layer behavior duplicates into single cross-domain elements (one am4:Service,
one am4:Process, one am4:Role), there are fewer native types to map upward than in
3.2 — the canonical ex-org:Service has a single ArchiMate parent to adopt rather than
both an application- and a business-service variant. The federation is leaner as a
direct result of 4.0's consolidation.
Type-level vs instance-level — the distinction that matters¶
Type-level unification is automatic via subsumption — instance-level identity requires explicit, reviewed assertions.
The canonical layer unifies at the type level. "Show me every application
component across all sources, and who owns it" works for free: subsumption gathers
am4: and bs: instances under ex-org:Application with no further work.
It does not, by itself, tell you that two specific nodes — the Backstage
payment-processor and the ArchiMate PaymentProcessor — are the same real-world
system. That is an instance-level fact about your organization, and no converter
can infer it reliably (names differ, identifiers differ, granularity differs). When a
question needs that, identity is asserted explicitly and reviewably — never guessed.
The sections below mark which kind of question each query is.
How it works¶
The three-stage pipeline that transforms heterogeneous architecture artifacts into a unified knowledge graph and generates stakeholder-specific outputs.
What exists today. The pipeline below is the intended end-to-end flow; maturity varies by stage.
The pipeline has three stages.
1. Convert — Artifacts from each tool (ArchiMate Exchange XML, BPMN 2.0.2 XML,
PlantUML, Backstage catalogs) are converted to RDF, typed against each notation's
Linked.Archi ontology — so a Backstage component becomes a bs:Component, an ArchiMate
component an am4:ApplicationComponent. Native semantics are preserved, not flattened.
Each converter emits three named graphs: semantic (the knowledge), views (diagram
layout), and provenance (where each fact came from).
2. Validate — SHACL shapes check the unified graph against metamodel rules (relationship validity, required properties) and organizational governance rules (every component must have an owner, every decision a rationale).
3. Query, Derive & Generate — The graph is queried (SPARQL), derived facts are inferred (derivation rules), and generators produce stakeholder-specific outputs: Markdown for developers, capability maps for executives, SPARQL workbenches for architects, MCP access for AI agents.
The canonical module is what lets a query span sources without caring which tool a fact came from — while the named-graph provenance lets it still recover that origin when needed.
What this looks like in practice¶
Cross-source, type-level: capabilities by team¶
"For each team, what business capabilities do their application components support?" This is a type-level question — it ranges over all application components, whatever their source. The canonical superclass answers it directly:
PREFIX ex-org: <https://example.org/arch/onto#>
PREFIX am4: <https://meta.linked.archi/archimate4/onto#>
PREFIX bs: <https://meta.linked.archi/backstage/onto#>
PREFIX skos: <http://www.w3.org/2004/02/skos/core#>
SELECT ?team ?component ?capability
WHERE {
?app a ex-org:Application ; # subsumes am4: AND bs: components
skos:prefLabel ?component .
OPTIONAL {
?app bs:ownedBy ?t .
?t skos:prefLabel ?team .
}
OPTIONAL {
# ArchiMate 4.0 path: a component serves a behavior element
# (Process or Service) that realizes a capability.
?app am4:serves ?behavior .
?behavior am4:realizes ?cap .
?cap a am4:Capability ;
skos:prefLabel ?capability .
}
}
ORDER BY ?team
Every application component surfaces under one query regardless of whether it was
authored in Backstage or ArchiMate. Where a given node carries ownership (Backstage)
or a capability path (ArchiMate), those bind; the OPTIONALs reflect that not every
node has both — which is exactly the real situation before any instance reconciliation.
Cross-source, instance-level: when one node has data from both tools¶
To get ownership and the capability chain for the same component in one row, the graph must know the Backstage node and the ArchiMate node denote the same system. That is the instance-level fact — asserted once, by hand or by a reconciliation step you review, never fabricated by the converter:
# Identity assertion: the Backstage component and the ArchiMate component
# are the same real-world application. Authored, reviewed, provenance-tracked.
bs-ex:PaymentProcessor
skos:exactMatch am-ex:PaymentProcessor .
With that asserted, the join traverses the link explicitly — runs on any SPARQL engine, no reasoner required:
SELECT ?team ?capability WHERE {
?bsApp a ex-org:Application ;
bs:ownedBy ?t .
?t skos:prefLabel ?team .
?bsApp skos:exactMatch ?amApp . # the reviewed identity bridge
?amApp am4:serves / am4:realizes ?cap .
?cap a am4:Capability ;
skos:prefLabel ?capability .
}
The bridge is one reviewed triple, and making it visible — rather than burying it inside a shared variable name — is the honest representation of what cross-tool identity actually costs.
Identity: correspondence vs. merge¶
There are two ways to assert that two nodes relate to the same system, and they make different claims — not strong-vs-weak versions of one claim. Choosing between them is a modeling decision, and Linked.Archi supports both.
skos:exactMatch — correspondence (the default). Asserts the two nodes denote the
same real-world system and should be treated as interchangeable for cross-source
querying, without claiming they are logically the same individual. It carries no OWL
entailment: a plain SPARQL engine simply traverses the link, and the two nodes keep
their native types. The link lives in the reconciliation graph, can be revised or
revoked without touching source data, and never pulls a reasoner into the everyday
query path.
bs-ex:PaymentProcessor
skos:exactMatch am-ex:PaymentProcessor .
# Same system, two representations. Query crosses the link explicitly.
owl:sameAs — merge (the deliberate exception). Asserts the two IRIs are the same
individual. A reasoner merges them completely: every property of one applies to the
other, both directions, for all purposes. You get the union of both sources' facts on
one logical node with no explicit hop — but you need a reasoner (or sameAs-aware store),
the merge is unforgiving (a wrong sameAs silently corrupts every downstream query),
and it brings OWL entailment into the common path.
bs-ex:PaymentProcessor
owl:sameAs am-ex:PaymentProcessor .
# One individual. A reasoner pools all properties; no explicit hop needed.
The decision rule is substitutability. Ask: would you be comfortable with a
reasoner replacing one IRI with the other everywhere, in any inference, forever? If
yes — the nodes are genuinely one entity and you want the pooled view — use
owl:sameAs. If you only mean "these denote the same system and queries should be able
to cross between them" — use skos:exactMatch. Most EA cross-source links are the
latter, because notations describe the same system at different granularities and from
different concerns (a C4 Container is not an ArchiMate Application Component even when
they are "the same" service), so full logical identity is usually too strong a claim.
That is why correspondence is the default and merge the documented exception —
and why the choice is consistent with the minimal-OWL profile, which keeps inference
out of the everyday path and admits it only as a deliberate, recorded exception.
One constraint when using both. Do not mix the two silently on different links in
the same deployment: a cross-source query written for one mechanism will miss links
made with the other (exactMatch links are not merged by a reasoner; sameAs links do
not need the explicit hop). Pick skos:exactMatch as the deployment default, reserve
owl:sameAs for a documented subset of confirmed-identity cases, and record which was
used — and why — in the reconciliation provenance (below). The queries in this article
use the skos:exactMatch default.
How reconciliation actually works¶
Asserting that triple is the last step of a three-step method. None of it is magic, and today the middle step is human:
- Candidate generation (mechanical). A reconciliation query proposes pairs that
might be the same system, using whatever weak signals exist — normalized labels
(
payment-processor≈Payment Processor), shared external identifiers (a repo URL, a CMDB id, adcterms:identifierboth sources carry), or matching provides/consumes API endpoints. This narrows thousands of node pairs to a short candidate list; it does not decide anything.
# Candidate pairs: a Backstage and an ArchiMate application whose labels
# match after normalization. Output is REVIEWED, not asserted.
SELECT ?bsApp ?amApp ?label WHERE {
?bsApp a bs:Component ; skos:prefLabel ?bl .
?amApp a am4:ApplicationComponent ; skos:prefLabel ?al .
BIND(LCASE(REPLACE(?bl, "[ _-]", "")) AS ?label)
FILTER(?label = LCASE(REPLACE(?al, "[ _-]", "")))
}
-
Human review (the deliberate bottleneck). A person confirms or rejects each candidate. This is the step that cannot be safely automated: a wrong merge fuses two distinct systems and silently corrupts every downstream query, which is worse than leaving them unlinked. The cost is real and scales with the number of shared systems — this is the honest limitation, not a detail to gloss.
-
Assertion with provenance (mechanical). Confirmed pairs are written as
skos:exactMatchtriples into a dedicated reconciliation named graph, separate from the per-source semantic graphs, with provenance (who, when, on what evidence):
# graph: <https://meta.linked.archi/graphs/reconciliation>
bs-ex:PaymentProcessor skos:exactMatch am-ex:PaymentProcessor .
# Provenance for the match, via RDF 1.2 reification — same rdf:reifies
# pattern used for qualified relationships throughout Linked.Archi:
recon:match-001 rdf:reifies
<<( bs-ex:PaymentProcessor skos:exactMatch am-ex:PaymentProcessor )>> ;
dcterms:creator "a.architect" ;
dcterms:date "2025-06-27"^^xsd:date ;
prov:wasDerivedFrom "label-match; confirmed in review"@en .
Keeping the links in their own graph matters: it means an identity decision can be revised or revoked without touching source data, and a query can choose to trust reconciliation or not. The reifier records why the link was asserted, so a wrong merge can be audited and undone — the named-graph provenance from the convert stage extends naturally to the reconciliation stage.
On RDF 1.2. Linked.Archi standardizes on RDF 1.2 throughout — the same
rdf:reifiestriple-term pattern carries qualified-relationship metadata and, here, reconciliation provenance. This is a deliberate choice to build on where the standard is going rather than encode a legacy workaround. Tooling is mid-adoption: RDF4J supports triple terms in its Model API and in-memory store today, with persistent storage partial as of v6. A deployment confirms its own loaders parse triple terms as part of stack setup — this is treated as a known integration requirement, not an open question.
Automated governance¶
SHACL turns governance rules into executable checks. Because the rule targets the canonical class, it covers components from every source at once:
# Every application component — from any tool — must have an owner.
:OwnershipShape
a sh:NodeShape ;
sh:targetClass ex-org:Application ; # am4: + bs: alike
sh:property [ sh:path bs:ownedBy ;
sh:minCount 1 ;
sh:severity sh:Violation ; # mandatory => Violation, not Warning
sh:message "Application component has no owner."@en ; ] .
Impact analysis¶
"What is affected if we decommission the Orders data object?" A type-level traversal over the canonical graph:
PREFIX ex-org: <https://example.org/arch/onto#>
PREFIX am4: <https://meta.linked.archi/archimate4/onto#>
PREFIX ex: <https://meta.linked.archi/examples/orders/> .
PREFIX skos: <http://www.w3.org/2004/02/skos/core#>
SELECT ?level ?label WHERE {
# 1 — components that directly access the data object
{
?a am4:accesses ex:OrdersData ;
skos:prefLabel ?label .
BIND ("1-component" AS ?level)
}
UNION
# 2 — services those components serve (4.0 merged App/Business Service into one)
{
?c am4:accesses ex:OrdersData ;
am4:serves ?a .
?a a am4:Service ;
skos:prefLabel ?label .
BIND ("2-service" AS ?level)
}
UNION
# 3 — capabilities those services realize
{
?c am4:accesses ex:OrdersData ;
am4:serves ?s .
?s a am4:Service ;
am4:realizes ?a .
?a a am4:Capability ;
skos:prefLabel ?label .
BIND ("3-capability" AS ?level)
}
}
ORDER BY ?level
AI agent access¶
The MCP server loads the RDF graph into an in-memory SPARQL engine (Oxigraph) and exposes it to AI agents. An architect asks: "What capabilities are at risk if we decommission the legacy CRM?" The agent translates to SPARQL against the canonical schema, queries the graph, and returns an answer grounded in the actual model — not hallucinated. The canonical class hierarchy is what lets the agent write valid queries without guessing each notation's idiosyncratic vocabulary.
These queries use the direct-predicate representation of relationships — the form maintained for traversal and analytics. The qualified relationship resources (with provenance and lifecycle) remain available for management queries; here we want the fast graph path.
Current Scope and Practical Notes¶
This approach has real limitations.
Canonicalization is a modeling judgment, not a free lunch. Declaring
bs:Component and am4:ApplicationComponent subclasses of ex-org:Application asserts
they are kinds of the same canonical concept. Where notations disagree on granularity
(a C4 Container is often coarser than an ArchiMate Application Component), the canonical
mapping has to take a defensible position, and some nuance lives only in the native type
beneath it. The federation preserves that nuance; it does not erase the need to decide
the mapping.
Instance reconciliation is manual. Type-level unification is automatic; declaring that two specific nodes are the same system is not, and currently must be authored. This is a deliberate safety property — an automatic merge that guesses wrong is worse than no merge — but it is real work, and at scale it is the main cost of cross-source instance questions.
The conversion step is lossy. ArchiMate Exchange XML preserves everything; PlantUML
is best-effort; Backstage catalog-info.yaml is straightforward but shallow.
Keeping the graph current needs an effort. If a model changes and nobody re-runs the converter, the graph is stale. Continuous sync needs tool plugins (absent for most EA tools) or CI/CD triggered on model-file changes.
SPARQL is not a mass-market query language. The cross-source queries are powerful but require someone who can write SPARQL. The MCP server helps; it is not full self-service.
"Model once" assumes someone models. This approach amplifies existing models; it does not create them from nothing.
Where this approach fits¶
Works best when:
- The organization already maintains architecture models (ArchiMate, BPMN).
- Multiple tools hold overlapping information (EA tool + Backstage + ADR repo + CMDB).
- Cross-cutting questions ("which capabilities are at risk?", "which components have no owner?") are asked regularly and currently require manual research.
- Governance rules exist but are enforced manually.
Overkill when:
- The architecture fits in one person's head.
- A single tool already serves all stakeholders.
- The team lacks the semantic-web skills to maintain ontologies and SPARQL.
Getting started¶
- Convert one model. Export ArchiMate as Open Exchange XML, run the converter, load it into the static navigator, browse your architecture as a graph.
- Add SHACL validation. Pick one rule you enforce manually; write a shape; see what it catches.
- Add the canonical module and a second source. Convert your Backstage catalog; adopt the canonical layer; run the type-level capability query across both. This is where federation starts paying off.
- Reconcile a few instances. Assert
skos:exactMatchfor a handful of systems that appear in both tools; run the instance-level join. See the cost and the value concretely. - Deploy the MCP server. Load the graph, connect an agent, ask grounded questions.
Each step delivers standalone value; the full pipeline isn't required to benefit from any stage.
References¶
- Architecture & Approach — The overall vision
- Quick Start Guide — Create a metamodel from scratch
- Semantic Architecture as Code — Turtle files in Git with CI/CD validation
- C4/Structurizr and ArchiMate — When to use which