Skip to content

Linked.Archi Agent Skills (APM)

Full documentation

This page summarizes the package. Everything — the six skills in detail, all 39 templates, the nine analysis patterns, a worked conversational walkthrough, the CLI and the exit codes — is on its own documentation site: linked-archi.github.io/linked-archi-apm. Source: linked-archi/linked-archi-apm.

linked-archi-apm is six Agent Skills that let an AI agent answer questions about an enterprise architecture from the RDF graph the converters produce, and attach the query, the dataset identity and the profile version to every answer it gives.

There is no application. The artifact is the context and the query templates, so a coding agent in an ordinary IDE can work as an architecture analyst against converter output — nothing is generated, bundled or copied at install time.

The problem it exists for

An architecture question answered from a model file is unfalsifiable: the reader cannot tell a correct answer from a plausible one. Two failure modes look identical to a caller, and both are silent:

  • An empty result reads as absence. "No capability is unrealised" and "no capability is modelled" are different statements, and a query returning zero rows produces both.
  • A wrong vocabulary returns nothing, quietly. Scope a query to a named graph the dataset does not have, and it succeeds with no rows.

Generic text-to-SPARQL hits both, for structural reasons no ontology dump conveys. Relationships are resources rather than triples — an arch:QualifiedRelationship with arch:source and arch:target, with the direct predicate shortcut opt-in at conversion time. Everything sits in named graphs, so a query without a GRAPH clause matches a default graph that converter TriG leaves empty. Ownership, lifecycle and cross-source identity are notation-specific or authored rather than derivable. And some IRIs denote a record about a thing — a LeanIX fact sheet is a document about an application, not the application. Each produces a query that runs and misleads.

Every design decision in the package follows from refusing to let those look like answers.

The six skills

The six APM skills — source and connect acquire and attach a dataset, profile describes what it calls things, and query, analyse and validate answer against it

Ownership is strict, and no skill imports another's Python package — cross-skill calls go through versioned JSON subprocess contracts.

Skill Owns Never does
linked-archi-source Acquiring RDF from bounded HTTPS, a pinned Git revision, or a read-only GitLab MCP handoff. Digest, size, redirect and parse verification before anything is promoted into an immutable local cache. Executes no SPARQL. Has no exit code 1 — acquisition either verifies or refuses.
linked-archi-connect Dataset discovery, attachment and identity. A local pyoxigraph store or a read-only SPARQL endpoint, reporting how many quads loaded and whether named graphs survived. Chooses no dataset for you.
linked-archi-profile The graph profile: namespaces, roles, graph layout, capabilities, notations, membership mode and limits. verify probes the dataset and reports drift. Never applies a recommendation.
linked-archi-query The 39-template catalogue, rendering, read-only enforcement, execution and the result envelope. Invents no IRI from a label.
linked-archi-validate SHACL in-process through pyshacl, plus reading a report somebody else produced. Target-class coverage and vacuity beside the verdict. Needs no JVM, converter or network. Executes no SPARQL.
linked-archi-analyse Routing a question to an analysis pattern, planning the ordered steps, bundling the envelopes. Executes nothing.

Install

The package is an APM bundle, and the committed tree is the artifact. Requires Python 3.11+.

apm install linked-archi/linked-archi-apm#v0.6.0
apm install .                               # from a local clone
apm install . --target claude,codex,kiro    # or -t all, when there is no signal to auto-detect
apm targets                                 # what auto-detection resolves to, before committing to it

Without APM, copy the skill directories into whatever the client reads — ~/.claude/skills/, ~/.kiro/skills/, and so on.

Dependency Needed for Without it
PyYAML reading profiles no profile loads
pyoxigraph local file execution endpoints still work; local files do not
pyshacl (pulls rdflib) la-validate run la-validate doctor reports it missing and SHACL is skipped
git Git-revision acquisition HTTPS and MCP acquisition still work
pip install PyYAML pyoxigraph pyshacl

No triplestore, JVM or MCP server is required, and local querying plus exact source-cache reuse work offline. Every skill has a doctor that reports where it is, which companions it resolved and what is missing — check that before blaming the data.

From a question to a cited answer

The path a question takes — settle the dataset, fit and verify a profile, orient once per session, route to a pattern, resolve names, then run a template, ending in either a refusal that names an alternative or a result envelope

Four steps of setup, then questions. Orientation is per session, not per question.

la-connect datasets                                        # lists candidates, selects none
la-connect connect --data graph.trig                       # repeat --data to merge into one store
la-profile recommend --data graph.trig
la-profile verify --profile linked-archi-default --data graph.trig
la-query query run core/inventory-summary --data graph.trig
la-query query run core/resolve-element --data graph.trig --set TERM="order service"

la-connect datasets deliberately chooses nothing. Answering from a file nobody picked is the one failure that cannot be detected afterwards: the result looks sound and cites the wrong architecture. For the same reason the bundled fixtures are excluded from discovery unless --include-fixtures is passed.

--data and --endpoint together are refused, because two datasets would make the recorded identity wrong.

The template catalogue

Thirty-nine tested templates. Each declares what it answers, what it does not prove, what it needs from the profile, and which templates to use instead when it is refused. Thirty-three are cross-notation; six are notation-specific, gated on the vocabulary IRI they are written against rather than on a notation label.

Stage Templates Purpose
Orientation 4 Establish what is actually loaded, so a later empty result can be told from a partial export
Resolution 5 Turn a name somebody typed into an IRI — never construct one from a label
Discovery 3 Find which predicates and relationship types this dataset actually uses
Analysis 10 What depends on what, what realises what, what crosses a layer
Views 6 What is drawn, where, and what differs between two diagrams
Enrichment 3 Attributes only some notations carry, such as lifecycle and ownership
Quality 8 Whether the model can be trusted to answer at all: gaps, orphans, provenance, identity, conformance

The stages are an order rather than a menu: orient so a later absence can be trusted, resolve the names the question used, run the analysis template, then cite where the answer came from. Full catalogue on the template catalogue page.

Analysis patterns

Nine patterns, each a method for a kind of architecture question: which templates to run, in what order, what gates them, and — the part that matters most — when to stop.

Pattern Answers
impact-and-dependency What breaks if this is retired, replaced or migrated
traceability Which capability a system supports, and what realises what across layers
coverage-and-gaps What is missing, unowned or uncovered
model-contents What a given model actually contains
model-quality Whether the model can be trusted to answer at all
governance-and-decisions Which decisions, principles, policies and exceptions are recorded
lifecycle-and-portfolio Duplication, overlap, lifecycle and rationalisation candidates
cross-notation Whether two tools describe the same thing
views-and-documentation What is drawn, and what changed between two diagrams

A question with no pattern match is a real answer, not a failure: it does not look like anything the package has a method for. Every pattern also carries explicit stop rules — reachability established is not criticality established, a label match is not an identity, a difference between two diagrams is not yet a difference in the architecture. Depth on the analysis patterns page.

Three properties worth knowing

A refusal is an answer. Every template declares the profile roles, graph roles, capabilities and notation vocabulary it needs. When the dataset cannot support one, it is refused with a reason and a named alternative, on exit code 1 — routing, not a crash:

Template 'core/dependents-direct' cannot run against profile 'linked-archi-default':
  - capability 'direct_rel_triples' is False but this template needs True
Try instead: core/dependents-qualified, core/neighbours-qualified

This is a refusal, not an empty result: running it anyway would return no rows and
read as 'nothing exists'.

Exit codes carry that meaning throughout: 1 is usually a finding to read and act on, not something to retry. A SHACL run that selected no focus node exits 2 rather than reporting the pass a namespace mismatch would otherwise produce.

Vocabulary is data. A profile binds semantic roles to concrete terms, prefixes, graph layout and taxonomy terms — so the same template runs against a differently-flagged converter run, or a custom ontology, with no code change. Seven profiles ship: three for converter output shapes (default, --emit-direct-rel-triples, and a merged store with an authored reconciliation graph) and four worked examples including a flattened Turtle store and a custom cloud-platform metamodel. la-profile derive drafts one from a converter type-mapping file or a published arch:Metamodel manifest, and la-profile verify reports where a claim is false about the dataset. Until a profile has been verified, every result from it carries a caveat saying so.

Read-only is enforced, not requested. Update, insert, delete and load are rejected before any backend is touched, by one policy implementation that linked-archi-connect delegates to — including queries arriving through analyse's plans and connect's machine contract. Every result then carries a citation line:

core/models | query 4ae81572f06e | dataset base.trig | profile linked-archi-default v2 | 2026-09-16T23:24:55.552005+00:00 | 2 row(s)

query 4ae81572f06e is a SHA-256 over the query with whitespace collapsed, so re-indenting a template does not change it but changing an IRI, a limit or a graph does. Two answers citing the same id ran the same question.

Where it sits in the toolchain

The skills read what the converters write. They assume the RDF contract documented there — qualified relationships, named graphs per model, asserted model membership, a provenance graph — and the profile mechanism exists so that assumption is checkable rather than hoped for. See the flow end to end for how the two halves meet.