agentleFS
OpenLinkSoftwareOpenLinkSoftware/ai-agent-skills/website-from-webdav/SKILL.md

website-from-webdav

Skill42 starsChanged 50 days agoMITView on GitHub

Publish a static HTML/CSS/JS website (generated by an RDF-Turtle + SHACL + Jinja2 pipeline, e.g. sites/openlink/rdf/build.py) to a Virtuoso WebDAV root and map a public route to it via isql/VHOST_DEFINE. Use for deploying or updating an already-built OpenLink-style portfolio site onto a WebDAV target, verifying a live route serves the generated content, or producing a deployable bundle when live credentials aren't available. Triggers on phrases like "publish this site to WebDAV", "deploy the generated site", "set up an initial OpenLink site from a WebDAV root", "is this site live", or any request to push a pre-rendered static site onto a Virtuoso WebDAV/VHOST target. Does not author or edit RDF content, run the SHACL/Jinja2 pipeline's internal logic, or render pages live from SPARQL — see references/rdf-content-mode.md for the boundary.

The file

We split this skill into the rules it gives an agent

8 rules. About 0 are common, 1 is distinctive, and 7 are very specific to this project.

  • ≈0

    Common · estimate

    Many files like this have a rule of this kind.

  • ≈1

    Distinctive · estimate

    This author's own choices. Worth a look.

  • 7

    Very specific

    Tied to their project's names, files or tools. Probably skip.

  • Common
  • Distinctive
  • Very specific
  1. Very specific:

    Read references/webdav-website-engine-gate.md before claiming either.

    line 19
  2. Very specific:

    Before writing anything, search prior memory/work for validate_generated_weblog_bundle, VHOST_DEFINE, DAV_RES_UPLOAD_STRSES_INT, …

    line 34
  3. Very specific:

    Verify: fetch the live route, confirm the served bytes match the local generated/ file (allowing only whitespace/attribute-order …

    line 38
  4. Very specific:

    Never run rdf/build.py's SHACL validation with warnings suppressed or --skip-validate-style shortcuts.

    line 51
  5. Very specific:

    Avoid $1, $2, and similar tokens in any SQL loaded through isql.

    line 53
  6. Very specific:

    Delete any prior conflicting VHOST_DEFINE for the same host/path before redefining it, same as weblog-from-webdav's …

    line 55
  7. Very specific:

    Treat the certificate-bearing identity and the delegated principal as separate facts: -X/--cert identifies the calling agent, …

    line 56
  8. Distinctive:

    Never write credentials into the skill, generated SQL, logs, or committed files.

    line 57

≈ “Common” is an estimate: at least 1 in 5 of the 350,495 skill files we read have a rule of the same kind, not the same words. “Very specific” is our guess from the words: it names a file, a command, a setting or the project itself.

Keep what fits and drop the rest. Your version, ready for your agents.
Files
SKILL.md

Website From WebDAV

Use this skill to take a static, already-generated HTML/CSS/JS site — the output of an RDF-Turtle + SHACL + Jinja2 pipeline such as sites/openlink/rdf/build.py — and publish it to a Virtuoso WebDAV root with a mapped public route. The site's content model (ontology, SHACL shapes, ordering) is authored and validated upstream of this skill; this skill's job starts at "here is a generated/ folder of finished HTML, get it live."

This is deliberately narrower than weblog-from-webdav or osdi-inclusion-engine: those skills render content live on every request (WebDAV-collection enumeration inside a bespoke VSP, or a shared XSLT skin wrapping WebDAV-sourced HTML). This skill's content is already fully rendered before it arrives — publishing it is a plain WebDAV PUT plus a static-file VHOST_DEFINE, no VSP execution and no live SPARQL query involved. See references/webdav-website-engine-gate.md for why that choice was made and when it would change.

Blocking Gate — A Local File Is Not a Valid Completion

When the user asks to publish, deploy, or "make live" a generated site, a description of what would happen, or a claim that files exist locally, is not a valid completion unless the user explicitly asks only for a local/preview check. The default deliverable is either:

  • a live, verified published site: the target route returns the same content as the local generated/ output, or
  • a complete deployable bundle: generated/*.html, the site's assets/ (site.css, theme.js), a path-substituted templates/deploy-website-route.sql, and a README/run-notes file — with scripts/validate_generated_website_bundle.py passing against it.

Read references/webdav-website-engine-gate.md before claiming either. If deployment credentials (WebDAV and/or isql) are unavailable, stop at the deployable bundle and say plainly that live publication is blocked by missing authenticated access — do not describe hypothetical success.

First decisions

Establish these before publishing anything:

  • Source pipeline directory (e.g. {LLM_ROOT}/Claude Generated/sites/openlink/) and whether rdf/build.py needs to be (re)run first, or generated/ is already current.
  • Target DAV collection, e.g. /DAV/home/kidehen/sites/openlink/.
  • Public route, e.g. https://linkeddata.uriburner.com/sites/openlink/.
  • Identity mode: SQL username/password, isql WebID-TLS, WebID-TLS plus delegation, WebDAV username/password, WebDAV mTLS, or WebDAV mTLS plus On-Behalf-Of.
  • Whether this is a first-time route bootstrap (isql + deploy-website-route.sql required) or a content-only republish of an existing route (WebDAV publish only, per references/webdav-publish-mode.md's out-of-scope boundary — it never touches route configuration).

Workflow

  1. Confirm the source generated/ output is current: if asked to (re)build, run the pipeline's own rdf/validate_shacl.py then rdf/build.py unchanged — this skill does not reimplement or bypass that validation. See references/rdf-content-mode.md.
  2. Before writing anything, search prior memory/work for validate_generated_weblog_bundle, VHOST_DEFINE, DAV_RES_UPLOAD_STRSES_INT, website-from-webdav; reuse proven fixes rather than rediscovering them.
  3. Determine whether the target route already exists (query DB.DBA.HTTP_PATH and WS.WS.SYS_DAV_RES for the target path via isql). If not, bootstrap it: patch templates/deploy-website-route.sql with the real DAV path/route/title, then run it with isql. See references/isql-route-mode.md.
  4. Validate the bundle with scripts/validate_generated_website_bundle.py before any publish. This is blocking.
  5. Publish via WebDAV using scripts/publish_static_bundle.py — PUTs generated/*.html and assets/* recursively, verifies each write with a follow-up GET/PROPFIND compare. See references/webdav-publish-mode.md.
  6. Verify: fetch the live route, confirm the served bytes match the local generated/ file (allowing only whitespace/attribute-order differences, same tolerance the pipeline's own Phase 1 verification uses), confirm assets/site.css/theme.js load with correct MIME types.
  7. Report exactly what happened: route bootstrapped or reused, files published with their DAV paths, verification result — or, if credentials were missing, the deployable bundle location and the explicit statement that live publication did not happen.

Mode references

  • For route bootstrap and isql TLS/WebID syntax, read references/isql-route-mode.md.
  • For WebDAV publication and its out-of-scope boundary, read references/webdav-publish-mode.md.
  • For the pipeline boundary (what this skill does and does not touch in rdf/), read references/rdf-content-mode.md.
  • For why live SPARQL/VSP rendering was not chosen, read references/webdav-website-engine-gate.md.
  • For agent-callable operations, read references/opal-tool-mode.md — not implemented in v1; documented as the extension point.

Practical guardrails

  • Never run rdf/build.py's SHACL validation with warnings suppressed or --skip-validate-style shortcuts; a failing gate means the content is not ready to publish, not an obstacle to route around.
  • DB.DBA.DAV_RES_UPLOAD_STRSES_INT (if used for any non-static-file step) needs a string_output() stream populated via http(content, stream), not a plain string.
  • Avoid $1, $2, and similar tokens in any SQL loaded through isql; they can trigger macro substitution.
  • A static-file VHOST_DEFINE uses is_dav=>1, is_brws=>0, def_page=>'index.html' — do not set def_page=>'index.vsp' unless a VSP entry point genuinely exists; a def_page pointing at a nonexistent VSP resource serves raw source or a 404, not the site.
  • Delete any prior conflicting VHOST_DEFINE for the same host/path before redefining it, same as weblog-from-webdav's route-remove-then-redefine pattern.
  • Treat the certificate-bearing identity and the delegated principal as separate facts: -X/--cert identifies the calling agent, -W/On-Behalf-Of identifies the WebID principal whose ACL rights should be evaluated.
  • Never write credentials into the skill, generated SQL, logs, or committed files.
  • Remote uploads and removals follow the same HTTP → WebDAV → iSQL order and principal PKCS#12 pattern (howto/remote-webdav-upload.ttl, howto/remote-resource-removal.ttl, prefs Steps 215–216). URIBurner writes/deletes go to port 5443. Report :5443 GET and public 443 GET separately after PUT; after DELETE, verify the user-named URL, slash variants, :5443 GET, and the folder listing before claiming removal.

Safe Virtuoso ISQL Error Output

Whenever this workflow invokes OpenLink's native Virtuoso isql client, pass the bare client option COMMAND_TEXT_ON_ERROR=OFF, for example isql {host}:{port} {user} {password} COMMAND_TEXT_ON_ERROR=OFF {script.sql}. Place it before SQL input, script arguments, or -i. OFF maps to the client's internal value 0 and prevents the client from appending the full failed command to error output. The client accepts OFF/ON; literal 0 is rejected. Do not use -u for this setting (-u populates the U argument array). This does not redact secrets from server diagnostics, shell history, or process arguments, so keep credentials out of SQL text and logs. Do not apply this Virtuoso-specific option to unixODBC/iODBC isql clients.

Download now (ZIP)

Does it work?

Reviews from people and from AI agents that ran it: what they used it for, and whether it worked.

No reviews yet

People and AI agents can review whether this works in practice. Say what you used it for, and whether it worked.

  • It worked
  • Partly
  • It didn't
What did you use it for? e.g. Reviewing pull requests in a Rails app

Using an agent? It can post a review for you after it has run the file: the MCP tool registry_write, action report. How to connect one.

Your trail

Files you open will collect here, so you can find them again.

Open two or more, and you can remix the rules you like from each into one list. Kept in this browser only.

Now do this for your own.

Bring your CLAUDE.md, AGENTS.md or skills. agentleFS shows which of your rules are common, which are yours and which only fit one project, and keeps one version your agents read everywhere.