atomgraph/linkeddatahub/app
Claude Code and agent skill by atomgraph/linkeddatahub
- community
Checking that the SKILL.md file is still in the repository.
Build a LinkedDataHub application declaratively with the ldh CLI — the document tree (containers and items), content blocks, SPARQL views in table/grid/list/map/graph layouts, charts, federated queries, public access, and an app directory installed with ldh push. Use when the task is to present data in an existing dataspace or to package an installable app. For the domain model and data imports use ldh:dataset; for rendering that data cannot declare (custom XSLT) use ldh:package.
Install
npx vskill@latest install atomgraph/linkeddatahub/appSKILL.md
Build a LinkedDataHub application
A LinkedDataHub app is declared, not generated: it is RDF documents in the dataspace, with no code and no build step. Pages are documents. A page's content is an ordered list of blocks. Lists, tables, maps and charts are blocks backed by SPARQL queries. The whole app can live in a directory of Turtle files that ldh push writes into the dataspace, so it is versioned in git and re-installable.
References:
- HTTP API for agents: https://github.com/AtomGraph/LinkedDataHub/blob/master/AGENTS.md
- CLI (incl.
push): https://docs.linkeddatahub.com/reference/command-line-interface/ - Documents and blocks: https://docs.linkeddatahub.com/reference/data-model/
- Worked examples, one directory per app:
https://github.com/AtomGraph/LinkedDataHub-Apps/tree/master/demo (northwind-traders: dashboards, faceted views, charts; copenhagen: map views)
Ground rules shared with the other ldh skills
- The default graph is empty. Every query pattern goes inside
GRAPH ?g { … }. Give each
linked resource its own graph variable, because each resource lives in its own document.
- A document is not the thing it describes. The topic is
<doc#this>, linked with
foaf:primaryTopic, and its properties go there.
- Setup:
export LDH_BASE=https://<dataspace>/ LDH_CERT_FILE=<owner keystore.p12> LDH_CERT_PASSWORD=….
The password is the deployment's, never a guess.
- Use an `ldh` that matches the instance. Build it from the same LinkedDataHub checkout or release
as the running image (ldh --version). An instance whose end-user responses carry no https://w3id.org/atomgraph/linkeddatahub/dataspaces#admin Link (check with ldh get --head --accept text/turtle "$LDH_BASE") predates the CLI's admin discovery. There, ldh admin commands stop with "advertises no lds:admin link". An admin base advertises itself as its lds:admin only from 6.2.1 on. Use the image built from the same checkout as the CLI.
The document model
| Resource | Shape | |
|---|---|---|
| Container (a section other documents live under) | <> a dh:Container ; dct:title "…" | |
| Item (a leaf page: a dashboard, a chart page, or a record) | <> a dh:Item ; dct:title "…", plus foaf:primaryTopic <#this> when it describes a thing | |
| Rich-text block | <#intro> a ldh:XHTML ; rdf:value """<div xmlns="http://www.w3.org/1999/xhtml">…</div>"""^^rdf:XMLLiteral | |
| Embedded resource block | <#b> a ldh:Object ; rdf:value <resource> | |
| Block order | <> rdf:_1 <#intro> ; rdf:_2 <#b> on the document |
Only `ldh:XHTML` and `ldh:Object` may be `rdf:_N` values. Views, charts and anything else are wrapped in an ldh:Object whose rdf:value names them. Bare ones are rejected by validation. XHTML must be well-formed, in the XHTML namespace, with each tag on one line.
Pick the type by what will live under the page, not by how it looks. A page made only of blocks (a chart page, a dashboard, an about page) with nothing beneath it is a dh:Item. Make it a dh:Container only when documents will be created under it, e.g. the target of an import. Both types take the same blocks.
Built-ins worth knowing: rdf:value ldh:ChildrenView lists the container's children, and the query ldh:SelectChildren selects them for a view of your own (e.g. a map of the children). ldh create container writes the children view as the first block; --no-children-view leaves it out, for a container that embeds its own view of them.
Views and charts
Views render resources; charts render numbers. A view's SELECT returns resources (their rows are navigable, facetable and linkable). A query with COUNT/SUM/GROUP BY belongs in a chart, never a view.
- View layout modes (
ac:mode):ac:ListMode,ac:TableMode,ac:GridMode,ac:MapMode(the
resources need geo:lat/geo:long), ac:GraphMode.
- Chart types (
ldh:chartType):ac:BarChart,ac:LineChart,ac:ScatterChart.
ldh:categoryVarName and ldh:seriesVarName name the query's variables, without ?. ldh:seriesVarName may repeat (--series-var-name too); the series are drawn in the order the query's SELECT projects them.
- A query runs against the dataspace's own endpoint unless it names a service:
<#q> ldh:service <#dbpedia> with <#dbpedia> a sd:Service ; dct:title "DBpedia" ; sd:endpoint <https://dbpedia.org/sparql> ; sd:supportedLanguage sd:SPARQL11Query. Time a remote query before building on it, and write it against the remote store's own graph layout.
- Every non-optional pattern filters rows. A pattern that is there only to sort or to display
(?book schema:datePublished ?year for ORDER BY ?year) goes in OPTIONAL, or resources missing that value silently drop out of the view.
- Per-resource panels ("orders of this customer") are property views in the ontology (ldh:dataset),
not blocks.
The app as a directory
ldh push maps a directory onto the document tree:
Relative URIs in each file resolve against its target URL, so write <> and <#…>. A subdirectory's document name.ttl sits beside it, not inside it. Non-RDF files are uploaded and addressed as ${LDH_BASE}uploads/{sha1}, and .xml files count as RDF/XML. Ignore CSVs that ldh import csv uploads itself.
`root.ttl` replaces the seeded root document, so keep its type: read it first (ldh get --accept text/turtle "$LDH_BASE") and start root.ttl from that. A push replaces every document it writes, so a re-push converges. It stops at the first failed request, and stdout lists what was written before it.
Install order
An installable app is an install.sh that runs, in this order:
ldh admin make-public(only if anonymous visitors should read it). Each run adds another
authorization, so run it once.
- Install the namespace ontology and any
ldh packages add(ldh:dataset). ldh push --dir "$app_dir" "$LDH_BASE", which creates the containers the imports write into.ldh import csv|rdfper data file (ldh:dataset), then wait for each import to finish.
The script is self-contained. It needs ldh and nothing else, so it runs from wherever the app directory is copied. The demo apps in LinkedDataHub-Apps source a shared lib/ldh-app.sh, which is internal to that repository. Do not copy that source line, and do not reference any other checkout by path.
Every command takes the end-user base. The admin commands find the admin app from it, so the script never derives an admin. URI. Keep admin/, *.sh, *.rq and *.csv in .ldhignore so push does not upload them.
Finer access control: ldh admin create group, ldh admin add agent, ldh admin create authorization (https://docs.linkeddatahub.com/reference/administration/acl/). An authorization names documents with --to, and a subtree with --default <container>, which covers every document below the container. --to-all-in takes a class, but not a document class (dh:Item, dh:Container, def:Root or one above them), which the admin refuses: those classes are shared with the admin documents.
Building incrementally instead
For one-off changes to a live dataspace, the create/add commands each make one request and print the new URL:
Pass --uri so later commands can reference what you added; without it the resource is a blank node. If the app is meant to be reinstalled, put the change in the directory too, since the next push overwrites the document.
An object block whose value is an external URI loads it through the Linked Data proxy. When the dataspace describes that resource itself, in one of its own documents, --graph <document> makes the block read the description from there (ldh:graph), with no proxy request. Edits to the embedded resource then write to that document.
Verify
This is the start of the file. Read the full SKILL.md on GitHub.
Security
- Security scanPassed, 90 of 100Pattern checks on the skill's files.
- Model reviewPassed
Quality evaluation
- Task evaluationNot runNo evaluation yet. Run one in Skill Studio.
Source
- SKILL.md in the repositoryCheckingplugins/ldh/skills/app/SKILL.md
Popularity
- 7-day trend score
- 0
Not refreshed yet.
Works with
Any agent vskill installs to: 56 targets in all. These 39 have a page on this site.
- Claude Code
- Cursor
- GitHub Copilot
- Windsurf
- Codex
- Gemini CLI
- Cline
- Amp
- Roo Code
- Goose
- Continue
- Kilo Code
- Junie
- Trae
- OpenHands
- Qwen Code
- AI Agent
- Tabnine Chat
- Sourcegraph Cody
- Amazon Q
- Firebase Genkit
- Sweep
- Devin
- Phind
- Mentat
- Claude Desktop
- Aider
- GPT Pilot
- Plandex
- bolt.new
- v0
- Replit Agent
- Anse
- TypingMind
- BetterChatGPT
- LibreChat
- Warp AI
- Pieces
- Fig AI
Embed badge
[](https://verified-skill.com/skills/atomgraph/linkeddatahub/app)