# CMS content audit — a replayable Reelier skill

Read-only content audit of a public sitemap — well-formed urlset, not truncated, canonical URL still present

A real, read-only Reelier skill against a live public API — no account, no keys, no writes. Every replay proves: A public sitemap answers as a complete urlset that still enumerates its canonical URL.

- Steps: 1 · Assertions: 4 · Effect: read (counts parsed from the file, never hand-typed)
- Endpoints: https://www.reelier.com/sitemap.xml
- Canonical file: https://raw.githubusercontent.com/seldonframe/reelier/main/examples/portfolio/cms-content-audit.skill.md
- HTML page: https://www.reelier.com/skills/cms-content-audit

## What this checks

One step: an HTTP GET to the public sitemap.xml. Four assertions hold it to account — the endpoint answered 200, the body opens with <urlset (a real sitemap, not an HTML error page), it carries the closing </urlset> (the document arrived whole, not truncated mid-stream), and <loc>https://www.reelier.com/</loc> is still enumerated (the homepage didn't silently drop out of a regen).

The assertions pin structure and canonicals, never a URL count. The first enumerated URL is bound onto the receipt (first_url = body match /<loc>...</loc>/) instead of pinned, so shipping a new page changes the sitemap without breaking the replay.

This is the only body-as-text audit in the portfolio — it reads the response as content, not as a JSON API, and catches content-integrity breaks (a missing route serving HTML, a truncated response, a dropped canonical) that a JSON shape-check would never see.

## The skill file (verbatim)

```markdown
---
name: cms-content-audit
description: Read-only content audit of a public sitemap — well-formed urlset, not truncated, canonical URL still present
---

<!-- synced from seldonframe/reelier examples/portfolio — edit there -->

# CMS content audit

Inputs: (none — this file replays green as-is; see the personalization note)

<!--
  Personalization: swap the literal host `www.reelier.com` for your own
  domain — one sed pass rewrites BOTH the sitemap URL and the canonical-URL
  assertion, since both carry the same host (the portfolio README's "Point
  these at YOUR project" section has the one-command version). Then make the
  `body contains "<loc>...</loc>"` assertion name a URL you KNOW is always in
  your sitemap (your homepage, a pillar page). The skill grammar has no
  default-value syntax for {{var}} holes — an unbound {{var}} is an explicit
  error, never a guessed fallback — so this file ships with literals that
  replay green with zero flags.

  This is the "did my published content break" audit, not a freshness radar.
  It reads the sitemap the way a crawler would and pins the invariants that
  must never quietly break: the response is a real urlset (not an HTML error
  page), the document arrived whole (the closing tag is present, so it wasn't
  truncated mid-stream), and a canonical URL is still enumerated (a regen that
  silently drops your homepage fails here instead of in Search Console weeks
  later).

  Endpoint verified live on 2026-07-21: 200, application/xml, 73 <loc>
  entries, `<loc>https://www.reelier.com/</loc>` present.
-->

Content moves; structure and canonicals don't. The assertions pin the SHAPE
(it's a urlset, it's complete, the homepage is in it) and bind the first
enumerated URL onto the receipt — never a specific URL count that would rot
the day a new page ships.

## Steps

### Step 1 — Sitemap is a complete urlset with the canonical URL present
- intent: Fetch the public sitemap and confirm it is a well-formed, untruncated urlset that still enumerates the homepage
- action: http.get {"url": "https://www.reelier.com/sitemap.xml"}
- assert: status == 200
- assert: body contains "<urlset"
- assert: body contains "</urlset>"
- assert: body contains "<loc>https://www.reelier.com/</loc>"
- bind: first_url = body match /<loc>([^<]+)<\/loc>/
- effect: read
```

## Run it yourself

`reelier run` takes a local file, so fetch the canonical copy first (or clone the repo). The replay writes its receipt to `.reelier/runs/`.

```sh
curl -fsSL https://raw.githubusercontent.com/seldonframe/reelier/main/examples/portfolio/cms-content-audit.skill.md -o cms-content-audit.skill.md
npx -y reelier@latest run cms-content-audit.skill.md

# or from a clone:
git clone https://github.com/seldonframe/reelier
cd reelier && npx -y reelier@latest run examples/portfolio/cms-content-audit.skill.md
```

## Seed receipt — 2026-07-21

Replayed for real with the published CLI (resolved to reelier@0.14.0) on 2026-07-21; the run record confirms passed: true and 0 LLM tokens (input + output). Verbatim output:

```
✓ Step 1 — Sitemap is a complete urlset with the canonical URL present [passed] 132ms

PASSED: 1/1 steps ok, 0 failed, 132ms total
```

Standing audit log: a GitHub Action replays all five portfolio skills every 6 hours (plus on demand) — https://github.com/seldonframe/reelier/actions/workflows/portfolio-replay.yml. A failing endpoint produces an honestly failing receipt, never a retried-until-green one.

## Point it at your project

Swap the one literal host `www.reelier.com` for your own domain — a single sed pass rewrites both the sitemap URL and the canonical-URL assertion, since they share the host. Then point the `body contains "<loc>...</loc>"` assertion at a URL you KNOW is always in your sitemap (your homepage or a pillar page). The skill grammar has no default-value syntax for {{var}} holes — an unbound {{var}} is an explicit error, never a guessed fallback — so this file ships with literals that replay green with zero flags.

```sh
sed 's/www\.reelier\.com/YOUR-DOMAIN.com/g' cms-content-audit.skill.md > my-content-audit.skill.md \
  && npx -y reelier@latest run my-content-audit.skill.md
```

---

Reelier — agents make claims, Reelier writes receipts. AGPL-3.0.
Portfolio index: https://www.reelier.com/skills (twin: https://www.reelier.com/skills.md) · Replay ledger: https://www.reelier.com/replays · Machine-readable summary: https://www.reelier.com/llms.txt
