From 38c075d61d78d932c0cf8f711886528ef3810001 Mon Sep 17 00:00:00 2001 From: Alan Wizemann Date: Wed, 22 Apr 2026 01:03:57 +0100 Subject: [PATCH] docs: ship site-status-checker example template + v2.2.0 release notes MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit First installable template demonstrating the format: - Dashboard with stat widgets (up/down/last-checked) + configured-sites list + quick-start markdown. - Cross-agent AGENTS.md with the full cron-prompt contract so any agent that reads agents.md (Claude Code, Cursor, Codex, Aider, Jules, Copilot, Zed, …) picks up the behavior on first run. - Cron job (0 9 * * *) that ships paused with the [tmpl:…] tag, pinging a user-editable sites.txt and writing results to status-log.md. - First-run bootstrap logic in AGENTS.md: if sites.txt doesn't exist yet the agent creates it with two placeholder URLs, then proceeds. Plus examples/templates/README.md explaining the staging/ layout, authoring conventions, and how to rebuild a bundle after editing. CI validates the bundle via ProjectTemplateExampleTemplateTests so drift between staging/ and the built .scarftemplate fails on every build. v2.2.0 release notes cover the full feature surface including the install preview sheet, scarf:// + file:// URL handling, skills namespacing, cron-job tagging, memory-block markers, and the lock-driven uninstall flow. Co-Authored-By: Claude Opus 4.7 (1M context) --- examples/templates/README.md | 37 ++++++++++ .../site-status-checker.scarftemplate | Bin 0 -> 5410 bytes .../site-status-checker/staging/AGENTS.md | 66 ++++++++++++++++++ .../site-status-checker/staging/README.md | 33 +++++++++ .../staging/cron/jobs.json | 7 ++ .../staging/dashboard.json | 64 +++++++++++++++++ .../site-status-checker/staging/template.json | 20 ++++++ releases/v2.2.0/RELEASE_NOTES.md | 45 ++++++++++++ 8 files changed, 272 insertions(+) create mode 100644 examples/templates/README.md create mode 100644 examples/templates/site-status-checker/site-status-checker.scarftemplate create mode 100644 examples/templates/site-status-checker/staging/AGENTS.md create mode 100644 examples/templates/site-status-checker/staging/README.md create mode 100644 examples/templates/site-status-checker/staging/cron/jobs.json create mode 100644 examples/templates/site-status-checker/staging/dashboard.json create mode 100644 examples/templates/site-status-checker/staging/template.json create mode 100644 releases/v2.2.0/RELEASE_NOTES.md diff --git a/examples/templates/README.md b/examples/templates/README.md new file mode 100644 index 0000000..4586e90 --- /dev/null +++ b/examples/templates/README.md @@ -0,0 +1,37 @@ +# Example Templates + +This directory holds reference `.scarftemplate` bundles shipped in the Scarf repo. Each subdirectory is one template, laid out as: + +``` +/ +├── staging/ Source tree — the exact layout of the bundle +│ ├── template.json +│ ├── README.md +│ ├── AGENTS.md +│ ├── dashboard.json +│ ├── cron/jobs.json (optional) +│ ├── skills//… (optional) +│ ├── instructions/… (optional) +│ └── memory/append.md (optional) +└── .scarftemplate Built bundle (zipped staging dir) +``` + +## Available templates + +- **[site-status-checker](site-status-checker/)** — daily HTTP uptime check for a user-editable list of URLs. Dashboard + cron + AGENTS.md. The simplest example that exercises the full format. + +## Rebuilding a bundle after editing + +```bash +cd /staging +zip -qq -r ../.scarftemplate . +``` + +The Scarf test suite (`ProjectTemplateExampleTemplateTests`) validates each shipped `.scarftemplate` on every build, so a bundle that fails to round-trip through `inspect → buildPlan` will fail CI. + +## Authoring conventions + +- **Always ship `AGENTS.md`.** It's the Linux Foundation cross-agent standard ([agents.md](https://agents.md/)) and every supported agent reads it. Agent-specific shims (`CLAUDE.md`, `GEMINI.md`, `.cursorrules`, `.github/copilot-instructions.md`) go under `instructions/` and only when there's a real per-agent behavior the author needs. +- **Cron jobs ship paused.** Don't assume the user wants your job running on install. Write the prompt so running it manually from chat (`"run the X job"`) also works — the cron is just a schedule wrapper. +- **Dashboard values that change at runtime should be placeholders.** The agent (not the installer) keeps them fresh. Start with sensible zeros / "never" / "unknown" so an uninstalled, inactive project still renders cleanly. +- **Don't claim in the manifest what you don't ship.** The `contents` block is cross-checked against the unpacked files — a mismatch makes the installer refuse the bundle. diff --git a/examples/templates/site-status-checker/site-status-checker.scarftemplate b/examples/templates/site-status-checker/site-status-checker.scarftemplate new file mode 100644 index 0000000000000000000000000000000000000000..35bca1d6c1cf7c1e45a1cdbcd2dd23ec03eba80b GIT binary patch literal 5410 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 literal 0 HcmV?d00001 diff --git a/examples/templates/site-status-checker/staging/AGENTS.md b/examples/templates/site-status-checker/staging/AGENTS.md new file mode 100644 index 0000000..a661b6f --- /dev/null +++ b/examples/templates/site-status-checker/staging/AGENTS.md @@ -0,0 +1,66 @@ +# Site Status Checker — Agent Instructions + +This project maintains a daily uptime check for a short list of URLs. The same instructions apply whether you're Hermes, Claude Code, Cursor, Codex, Aider, or any other agent that reads `AGENTS.md`. + +## Project layout + +- `sites.txt` — one URL per line. Lines starting with `#` are comments. This is the source of truth for what to check. **Not shipped with the template** — created on first run (see below). +- `status-log.md` — append-only markdown log. Newest run at the top. Each run is a section with the ISO-8601 timestamp as the heading. Also created on first run. +- `.scarf/dashboard.json` — Scarf dashboard. **Only the `value` fields of the three stat widgets and the `items` array of the "Watched Sites" list widget should be updated.** The section titles, widget types, and structure must stay intact. + +## First-run bootstrap + +If `sites.txt` doesn't exist in the project root, create it with this starter content and tell the user you did: + +``` +# One URL per line. Lines starting with # are comments. +# Replace these placeholders with the sites you want to watch. +https://example.com +https://example.org +``` + +If `status-log.md` doesn't exist, create it with a one-line header: + +``` +# Site Status Log + +Newest run at the top. Each section is a single check. +``` + +## What to do when the cron job fires + +The cron job runs this project's "Check site status" prompt. When invoked: + +1. Read `sites.txt` in the project root. Ignore empty lines and `#`-prefixed comments. Expect plain URLs; be tolerant of whitespace around them. +2. For each URL, make an HTTP GET request with a 10-second timeout. Follow up to 3 redirects. Treat any 2xx or 3xx response as **up**, anything else (including timeouts and DNS failures) as **down**. +3. Build a results table: URL, status (up/down), HTTP code (or error reason), response time in milliseconds. +4. Prepend a new section to `status-log.md`: + ``` + ## + + | URL | Status | Code | Latency | + |-----|--------|------|---------| + | … | up | 200 | 142 ms | + | … | down | timeout | — | + ``` +5. Update `.scarf/dashboard.json`: + - `Sites Up` stat widget: `value` = count of up results. + - `Sites Down` stat widget: `value` = count of down results. + - `Last Checked` stat widget: `value` = the ISO-8601 timestamp you just wrote. + - `Watched Sites` list widget `items`: one entry per URL with `text` = URL and `status` = `"up"` or `"down"` (lowercase). +6. If the cron job has a `deliver` target set, emit a one-line summary (`3 up, 1 down — example.com timed out`) as the agent's final response so the delivery mechanism picks it up. + +## What not to do + +- Don't modify the structure of `dashboard.json` (section titles, widget types, widget titles, `columns`). Only the values listed above are writable. +- Don't truncate `status-log.md` — it's the historical record. If it grows past 1 MB, add a one-line note at the top of the file asking the user to archive it. +- Don't invent URLs. If `sites.txt` is empty or missing, leave the dashboard untouched and write a single `status-log.md` entry noting "no sites configured." +- Don't run browsers or headless Chrome. Plain HTTP GET is sufficient. + +## When the user asks you things + +- "What's the status of my sites?" — read the top section of `status-log.md` and summarize. +- "Add a site" — append the URL to `sites.txt` on its own line. Don't sort or reorder existing entries. Confirm back to the user which URL you added. +- "Remove a site" — delete the matching line from `sites.txt`. If multiple match, ask before choosing. +- "Run the check now" — do everything in the cron flow above, then summarize the results in chat. +- "Why is [site] down?" — read the last 3-5 entries for that URL in `status-log.md` and report any pattern you see (consistent timeouts, intermittent 5xx, DNS failures, etc.). Don't speculate beyond what the log shows. diff --git a/examples/templates/site-status-checker/staging/README.md b/examples/templates/site-status-checker/staging/README.md new file mode 100644 index 0000000..51bd3d4 --- /dev/null +++ b/examples/templates/site-status-checker/staging/README.md @@ -0,0 +1,33 @@ +# Site Status Checker + +A minimal uptime watchdog that pings a list of URLs once a day, records pass/fail results, and keeps a simple Scarf dashboard up to date. + +## What you get + +- **`sites.txt`** — one URL per line. This is the source of truth for what the cron job checks. Edit it to add or remove sites. +- **`status-log.md`** — the agent's append-only log of check results. New runs append a section at the top. +- **`.scarf/dashboard.json`** — Scarf dashboard with live stat widgets (sites up, sites down, last checked), the full list of watched sites with their last-known status, and a usage guide. +- **Cron job `Check site status`** — registered (paused) by the installer; tag `[tmpl:awizemann/site-status-checker]`. Runs daily at 9:00 AM when enabled. The prompt tells the agent to read `sites.txt`, check each URL, write results to `status-log.md`, and update the stat widgets in `dashboard.json`. + +## First steps + +1. Open the **Cron** sidebar and enable the `[tmpl:awizemann/site-status-checker] Check site status` job. It's paused on install so nothing runs without your explicit say-so. +2. Edit `sites.txt` in your project root — replace the two placeholder URLs with the sites you actually want to watch. +3. From the project's dashboard, ask your agent to run the job now: "Run the site status check and update the dashboard." +4. Future runs happen automatically at 9 AM daily. + +## Customizing + +- **Change the schedule.** Edit the cron job in the Cron sidebar — the schedule field accepts `30m`, `every 2h`, or standard cron expressions like `0 9 * * *`. +- **Change what "down" means.** By default the agent treats any non-2xx HTTP response as down. If you want to check for specific strings in the body (e.g. "Maintenance"), tell the agent in `AGENTS.md` and it will adapt. +- **Add alerting.** Set a `deliver` target on the cron job (Discord, Slack, Telegram) — the agent will post the run summary there instead of just writing to `status-log.md`. + +## Uninstalling + +Templates don't auto-uninstall in Scarf 2.2. To remove this one by hand: + +1. Delete this project directory (removes the dashboard, AGENTS.md, sites.txt, status-log.md). +2. Remove the project entry from the Scarf sidebar (click the `−` next to the project name). +3. Delete the `[tmpl:awizemann/site-status-checker] Check site status` cron job from the Cron sidebar. + +No memory appendix or skills were installed, so nothing else needs cleanup. diff --git a/examples/templates/site-status-checker/staging/cron/jobs.json b/examples/templates/site-status-checker/staging/cron/jobs.json new file mode 100644 index 0000000..84dd951 --- /dev/null +++ b/examples/templates/site-status-checker/staging/cron/jobs.json @@ -0,0 +1,7 @@ +[ + { + "name": "Check site status", + "schedule": "0 9 * * *", + "prompt": "Run the site status check for this project. Follow the instructions in AGENTS.md: read sites.txt, HTTP GET each URL, prepend a results section to status-log.md, and update the three stat widgets plus the Watched Sites list items in .scarf/dashboard.json. When done, reply with a one-line summary like '3 up, 1 down — example.com timed out'." + } +] diff --git a/examples/templates/site-status-checker/staging/dashboard.json b/examples/templates/site-status-checker/staging/dashboard.json new file mode 100644 index 0000000..6693994 --- /dev/null +++ b/examples/templates/site-status-checker/staging/dashboard.json @@ -0,0 +1,64 @@ +{ + "version": 1, + "title": "Site Status", + "description": "Daily uptime check for your watched URLs. The stat widgets and list update automatically when the cron job runs.", + "theme": { "accent": "green" }, + "sections": [ + { + "title": "Current Status", + "columns": 3, + "widgets": [ + { + "type": "stat", + "title": "Sites Up", + "value": 0, + "icon": "checkmark.circle.fill", + "color": "green", + "subtitle": "responded 2xx/3xx" + }, + { + "type": "stat", + "title": "Sites Down", + "value": 0, + "icon": "xmark.circle.fill", + "color": "red", + "subtitle": "non-2xx, timeout, DNS" + }, + { + "type": "stat", + "title": "Last Checked", + "value": "never", + "icon": "clock", + "color": "blue", + "subtitle": "ISO-8601 timestamp" + } + ] + }, + { + "title": "Watched Sites", + "columns": 1, + "widgets": [ + { + "type": "list", + "title": "Configured Sites (from sites.txt)", + "items": [ + { "text": "https://example.com", "status": "unknown" }, + { "text": "https://example.org", "status": "unknown" } + ] + } + ] + }, + { + "title": "How to Use", + "columns": 1, + "widgets": [ + { + "type": "text", + "title": "Quick Start", + "format": "markdown", + "content": "**1.** Enable the `[tmpl:awizemann/site-status-checker] Check site status` cron job in the Cron sidebar. It ships paused — nothing runs until you say so.\n\n**2.** Edit `sites.txt` in this project's folder to replace the placeholder URLs with the sites you actually want to watch.\n\n**3.** Ask your agent: *\"Run the site status check now.\"* The dashboard refreshes and a new entry appears at the top of `status-log.md`.\n\n**4.** Daily at 9 AM the cron job fires automatically. Change the schedule in the Cron sidebar if you want a different cadence.\n\nSee `README.md` and `AGENTS.md` in the project root for the full spec." + } + ] + } + ] +} diff --git a/examples/templates/site-status-checker/staging/template.json b/examples/templates/site-status-checker/staging/template.json new file mode 100644 index 0000000..e4f1a44 --- /dev/null +++ b/examples/templates/site-status-checker/staging/template.json @@ -0,0 +1,20 @@ +{ + "schemaVersion": 1, + "id": "awizemann/site-status-checker", + "name": "Site Status Checker", + "version": "1.0.0", + "minScarfVersion": "2.2.0", + "minHermesVersion": "0.9.0", + "author": { + "name": "Alan Wizemann", + "url": "https://github.com/awizemann/scarf" + }, + "description": "A daily uptime check for a short list of URLs. Writes status to status-log.md and updates the dashboard with current counts.", + "category": "monitoring", + "tags": ["monitoring", "uptime", "cron", "starter"], + "contents": { + "dashboard": true, + "agentsMd": true, + "cron": 1 + } +} diff --git a/releases/v2.2.0/RELEASE_NOTES.md b/releases/v2.2.0/RELEASE_NOTES.md new file mode 100644 index 0000000..077d583 --- /dev/null +++ b/releases/v2.2.0/RELEASE_NOTES.md @@ -0,0 +1,45 @@ +## What's New in 2.2.0 + +Scarf projects can now travel. This release introduces **Project Templates** — a shareable `.scarftemplate` bundle format that packages a project's dashboard, agent instructions, skills, and cron jobs into a single file anyone can install with one click from a local file or an `scarf://install?url=…` deep link. + +### Project Templates + +- **Bundle format: `.scarftemplate`.** A zip archive carrying a `template.json` manifest, the project's dashboard, a required `AGENTS.md` (the [Linux Foundation cross-agent instructions standard](https://agents.md/) — reads natively in Claude Code, Cursor, Codex, Aider, Jules, Copilot, Zed, and more), a README shown in the installer, optional per-agent instruction shims (`CLAUDE.md`, `GEMINI.md`, `.cursorrules`, `.github/copilot-instructions.md`), optional namespaced skills, optional cron job definitions, and an optional memory appendix. Every bundle is agent-portable out of the box. +- **Install preview sheet.** Before anything touches disk, Scarf shows you the exact project directory that will be created, every file inside it, every skill that will be namespaced under `~/.hermes/skills/templates//`, every cron job that will be registered (always paused — you enable each one manually), and a live diff of the memory appendix against your existing `MEMORY.md`. The manifest's content claim is cross-checked against the actual zip entries so a bundle can't hide files from the preview. +- **`scarf://install?url=…` deep links.** Register Scarf as the handler for the `scarf` URL scheme so a future catalog site can link one-click installs straight into the app. Only `https://` payloads are accepted; `file://`, `javascript:`, and `http://` are refused on principle. A 50 MB size cap keeps a malicious link from exhausting disk. The URL never auto-installs — the preview sheet is always user-confirmed. +- **Export any project as a template.** Select a project, open the new Templates menu in the Projects toolbar, fill in a handful of fields (id, name, version, description, optional author + category + tags), tick the skills and cron jobs you want to include, optionally drop in a memory snippet, and save. The exporter builds the bundle and you can hand it to anyone. +- **No-overwrite, reversible by design.** Installed templates drop a `/.scarf/template.lock.json` recording exactly what they wrote — every project file, skill path, cron job name, and memory block id. Installing the same template id twice is refused at the preview step so you don't accidentally double-append to `MEMORY.md`. Uninstalling by hand is a matter of deleting the project directory, the skills namespace folder, and any `[tmpl:] …` cron jobs — no hidden state. +- **Safe globals.** Skills install to `~/.hermes/skills/templates///` so they never collide with your own skills. Cron jobs are prefixed with `[tmpl:]` and start paused so nothing unexpected kicks off on install. The installer **never** touches `~/.hermes/config.yaml`, `auth.json`, sessions, or any credential-bearing path. + +### Using templates + +- **Install from file:** Projects → Templates → *Install from File…*, pick a `.scarftemplate` from disk. +- **Install from URL:** Projects → Templates → *Install from URL…*, paste an https URL. +- **Install from the web:** click any `scarf://install?url=…` link in a browser. +- **Export:** select a project → Projects → Templates → *Export "<name>" as Template…*, fill the form, save. + +### Under the hood + +- New models in `Core/Models/ProjectTemplate.swift` (manifest, inspection, install plan, lock, errors). +- `Core/Services/ProjectTemplateService.swift` unzips, parses, and validates; `ProjectTemplateInstaller.swift` executes the plan atomically-enough (pre-flights conflicts, then writes); `ProjectTemplateExporter.swift` builds bundles from a live project + selections. +- `Core/Services/TemplateURLRouter.swift` is the process-wide landing pad for `scarf://` URLs so a cold-launch browser click still reaches the install sheet. +- Installer dispatches cron creation via `hermes cron create` (there's no direct Scarf write path for `cron/jobs.json`), then diffs before/after to pause the newly-registered jobs. +- New Swift Testing suites: `ProjectTemplateServiceTests`, `TemplateURLRouterTests`, `ProjectTemplateExportTests`. + +### Uninstall + +- **One-click uninstall** driven by `template.lock.json`. Right-click any template-installed project in the sidebar → **Uninstall Template…**, or click the uninstall button in the dashboard header. A preview sheet lists every file, cron job, and memory block that will be removed, and every user-created file that will be preserved. +- **User content is never removed.** Files you (or the agent) added to the project dir after install — like a `sites.txt` or `status-log.md` — are detected and listed as "keep" in the preview. The project directory itself is removed only if nothing user-owned is left inside. +- **Clean global state.** The isolated `~/.hermes/skills/templates//` namespace is removed wholesale. Tagged cron jobs are removed via `hermes cron remove`. The memory block between the `` markers is stripped, leaving the rest of MEMORY.md intact. The project registry entry is removed last. +- **No undo.** v1 uninstall is destructive — to reinstall, run the install flow again. + +### Not in this release (planned for v2.3) + +- In-app catalog browser backed by a GitHub Pages `templates.json`. +- EdDSA-signed bundles reusing the Sparkle key. +- Template updates (compare installed lock against a newer bundle's version, offer a diff). +- Installing into remote `ServerContext`s (v1 is local-only). + +### Migrating from 2.1.x + +Sparkle will offer the update automatically. No config migration needed. Existing projects are untouched — templates are additive.