Use when adding new error messages to React, or seeing "unknown error code" warnings.
npx skills add alistaircroll/pagelove --skill "sspi"
Install specific skill from multi-skill repository
# Description
Use when you need server-side document composition — includes, resource binding, Liquid templates, and resource creation via PUT or POST
# SKILL.md
name: sspi
description: "Use when you need server-side document composition — includes, resource binding, Liquid templates, and resource creation via PUT or POST"
Server-Side Processing Instructions (SSPI)
SSPI is a capability of the Pagelove platform that allows documents to be manipulated by the server before they are sent to the client. The server treats a site as an integrated system rather than isolated files, enabling:
- Projecting data into templates using site-wide information
- Including fragments from other documents
- Altering data presentation before client delivery
Namespace Declaration
To activate SSPI features, declare the Pagelove namespace on the <html> element:
<html xmlns:p="https://pagelove.org/1.0"
xmlns:resource="https://pagelove.org/1.0/Resource">
All recognized Pagelove namespace declarations, tags, and attributes are stripped before the page is delivered to the client. Clients never see SSPI markup — only the processed result.
Includes (<pagelove:include>)
Declarative cross-document fragment inclusion. Allows one document to include a fragment from another while keeping it addressable, authorisable, and writable.
<pagelove:include selector="header#nav" resource="/partials.html" />
Attributes:
- selector (required) — CSS selector identifying which fragment to include
- resource (optional) — constrains which resources the selector searches. Supports glob-style wildcards (*, **, ?). If omitted, the selector evaluates across the entire site graph
Cardinality: Resolution must yield exactly one element:
- Zero matches -> 404 Not Found
- Multiple matches -> 500 Internal Server Error
Mutation behavior: When clients PUT, POST, or DELETE included fragments, modifications apply to the origin resource, not the including document. Authorization rules and ETag concurrency control evaluate in the origin context.
Examples:
<!-- Include a specific element from a specific file -->
<pagelove:include resource="/partials.html" selector="header#nav" />
<!-- Search the entire site for a unique element -->
<pagelove:include selector="#partials header#nav" />
<!-- INVALID: resource without selector -->
<pagelove:include resource="/partials.html" />
Resource Binding (resource:name)
Site-wide CSS selector queries bound to named variables. Data lives in HTML, queries use CSS selectors, and integration happens inside documents.
<div resource:users="[id][itemtype='http://example.com/TeamMember']"
pagelove:template="text/liquid">
<!-- users variable is now available in the template -->
</div>
Syntax: resource:<name>="<css-selector>" — the <name> becomes the variable name, the CSS selector is evaluated across the entire site graph.
Properties:
- Site-wide — selectors span all documents in the site
- Structural — results are HTML elements, not deserialized data
- Live — evaluation occurs at render time (every request)
- Read-only — for rendering only; modifications use HTTP methods
Requires the Resource namespace: xmlns:resource="https://pagelove.org/1.0/Resource"
Multiple bindings can coexist on a single element. Invalid selectors cause document processing failures.
Resource Creation
Two modes for creating new resources (HTML files):
Mode 1: Direct Creation via PUT
Send PUT to a new path with a complete HTML body. The resource name is client-determined, no templating occurs.
PUT /new-page.html HTTP/2
Content-Type: text/html
<!DOCTYPE html>
<html>...</html>
Requires one authz check: PUT permission for the new path.
Mode 2: Templated Creation via POST
POST to a template file triggers server-side processing. The template generates a new resource.
Process:
1. Client sends POST /templates/thing.html
2. Server verifies POST permission for the template
3. Template processes with request data (body, query params, headers, actor identity)
4. Generated document must contain <base href="/final/path.html"> declaring the storage location
5. Server verifies PUT permission for the <base href> location (second authz check)
6. Document is written to the specified path
7. Server responds with 301 Moved Permanently + Location: <base.href>
Two authorization checks required: POST to the template AND PUT to the final location.
| Aspect | PUT | POST + Template |
|---|---|---|
| Name determination | Client | Template via <base> |
| Server logic | None | Full templating |
| Authorization checks | 1 | 2 |
| Response | Standard | 301 redirect |
Templating (pagelove:template)
Server-side rendering using the Liquid template engine, scoped to individual HTML elements.
<div resource:users="[itemtype*=TeamMember]"
pagelove:template="text/liquid">
<ul>
{% for user in users %}
<li>{{ user | microdata: "name" }}</li>
{% endfor %}
</ul>
</div>
Activation: Add pagelove:template="text/liquid" to any element. Only the subtree rooted at that element is processed.
Data sources:
1. Bound resources — variables from resource:name attributes
2. HTTP request — accessible via {{ request }} (includes body, query params, headers, actor)
3. Template-local variables — standard Liquid variables
Constraints — templates are:
- Scoped — only the annotated element's subtree
- Side-effect free — cannot mutate documents or create resources
- Deterministic — cannot perform I/O or issue HTTP requests
Composition: Use <pagelove:include> for structural composition (pulling in fragments) and pagelove:template for data-driven rendering. They work together.
# Supported AI Coding Agents
This skill is compatible with the SKILL.md standard and works with all major AI coding agents:
Learn more about the SKILL.md standard and how to use these skills with your preferred AI coding agent.