diff --git a/scarf/scarfTests/ProjectTemplateTests.swift b/scarf/scarfTests/ProjectTemplateTests.swift index 6b14205..3e68fb4 100644 --- a/scarf/scarfTests/ProjectTemplateTests.swift +++ b/scarf/scarfTests/ProjectTemplateTests.swift @@ -1063,6 +1063,68 @@ final class TestRegistryLock: @unchecked Sendable { #expect(cronPrompt.contains("{{PROJECT_DIR}}")) } + /// Exercises the second shipped template — `awizemann/template-author` — + /// which is a skill-only bundle (no config, no cron, no memory). The + /// shape is deliberately different from site-status-checker so a + /// regression in the installer's "no config, no cron" path can't hide + /// behind the richer example template. Also asserts the skill lands + /// under the expected namespaced path so Hermes's recursive skill + /// discovery finds it. + @Test func templateAuthorParsesAndPlans() throws { + let bundle = try Self.locateExample(author: "awizemann", name: "template-author") + + let service = ProjectTemplateService(context: .local) + let inspection = try service.inspect(zipPath: bundle) + defer { service.cleanupTempDir(inspection.unpackedDir) } + + // Manifest shape: schemaVersion 2 (contains `skills` claim, which + // wasn't part of v1), no config, no cron, one skill. + #expect(inspection.manifest.id == "awizemann/template-author") + #expect(inspection.manifest.name == "Scarf Template Author") + #expect(inspection.manifest.version == "1.0.0") + #expect(inspection.manifest.schemaVersion == 2) + #expect(inspection.manifest.contents.dashboard) + #expect(inspection.manifest.contents.agentsMd) + #expect(inspection.manifest.contents.cron == nil) + #expect(inspection.manifest.contents.config == nil) + #expect(inspection.manifest.contents.memory == nil) + #expect(inspection.manifest.contents.skills == ["scarf-template-author"]) + #expect(inspection.manifest.config == nil) + #expect(inspection.cronJobs.isEmpty) + + // Plan: empty config, empty cron, but one skill queued for install + // under the template's namespaced dir. The namespace path has to + // match what the uninstaller wipes — `skills/templates/` — + // or uninstall leaves orphan skill files. + let scratch = try ProjectTemplateServiceTests.makeTempDir() + defer { try? FileManager.default.removeItem(atPath: scratch) } + let plan = try service.buildPlan(inspection: inspection, parentDir: scratch) + #expect(plan.projectDir.hasSuffix("awizemann-template-author")) + #expect(plan.cronJobs.isEmpty) + #expect(plan.configSchema == nil) + #expect(plan.configValues.isEmpty) + #expect(plan.memoryAppendix == nil) + + // The skill should land at + // `~/.hermes/skills/templates/awizemann-template-author/scarf-template-author/SKILL.md` + // — namespace dir + skill folder + SKILL.md. Anything else + // breaks Hermes's recursive discovery or the uninstaller's + // `rm -rf` on the namespace dir. + let namespaceDir = try #require(plan.skillsNamespaceDir) + #expect(namespaceDir.hasSuffix("/skills/templates/awizemann-template-author")) + #expect(plan.skillsFiles.count == 1) + let skillDest = try #require(plan.skillsFiles.first?.destinationPath) + #expect(skillDest.hasSuffix("/scarf-template-author/SKILL.md")) + #expect(skillDest.hasPrefix(namespaceDir)) + + // No-config templates deliberately skip the manifest cache — + // the dashboard's Configuration button only shows up when + // `.scarf/manifest.json` exists, so a skill-only template + // like this one correctly doesn't surface that button. + // (See ProjectTemplateService.buildPlan lines 198–227.) + #expect(plan.manifestCachePath == nil) + } + /// Resolve the example bundle path robustly. Unit-test working dirs /// differ between `xcodebuild test` (project root) and an Xcode IDE /// run (build-output dir), so we walk up from this source file until diff --git a/templates/awizemann/template-author/staging/AGENTS.md b/templates/awizemann/template-author/staging/AGENTS.md new file mode 100644 index 0000000..54c0fe6 --- /dev/null +++ b/templates/awizemann/template-author/staging/AGENTS.md @@ -0,0 +1,55 @@ +# Template Author — Agent Instructions + +This project is a help surface for the `scarf-template-author` Hermes skill. The same instructions apply whether you're Claude Code, Cursor, Codex, Aider, or any other agent that reads `AGENTS.md`. + +## What this project is + +Two things: + +1. A minimal dashboard (`.scarf/dashboard.json`) the user lands on after install. It's a Quick Start text widget + an empty list widget. The list is an optional scratchpad where you can log projects you've scaffolded for the user, giving them a running audit trail. That's nice-to-have, not mandatory. +2. A skill at `~/.hermes/skills/templates/awizemann-template-author/scarf-template-author/SKILL.md`. The skill is the real value — it teaches you how to interview the user and scaffold a new Scarf-compatible project. + +## What this project is NOT + +- Not a running service. No cron jobs, no background tasks, no secrets. +- Not a dashboard you need to keep updated. The dashboard is documentation; the only mutation worth doing is appending to the Scaffolded Projects list after you scaffold something. + +## When the user asks to create a Scarf project + +The primary trigger. Phrases that should activate the full scaffolding flow: + +- "Create a new Scarf project that …" +- "Scaffold a dashboard for …" +- "Set up a project to watch / track / report on …" +- "Help me author a Scarf template." +- "Build me a project that runs daily and …" + +When you hear those: + +1. Load the skill at `~/.hermes/skills/templates/awizemann-template-author/scarf-template-author/SKILL.md` and follow its interview flow. Do not improvise — the skill encodes the specific invariants Scarf enforces (widget types, field-type constraints, the `{{PROJECT_DIR}}` token, the paused-on-install cron rule, the secret-fields-have-no-defaults rule). +2. Scaffold into a directory the user picks. Use absolute paths. +3. After writing files, tell the user to register the project: click **+** in Scarf's Projects sidebar and pick the directory. Do not try to edit `~/.hermes/scarf/projects.json` yourself — Scarf reloads the registry on its own and the UI path is safer. +4. Optionally append to the Scaffolded Projects list in this project's `dashboard.json` so the user has a local record of what you've built for them. Preserve every other field in the dashboard as-is. + +## When the user asks reference questions + +If the user asks something like "what widget types does Scarf support?" or "how do I add a secret field?", you don't need to scaffold anything — answer inline. The skill's reference sections cover: + +- The seven widget types (`stat`, `progress`, `text`, `table`, `chart`, `list`, `webview`) and their required fields. +- The seven config field types (`string`, `text`, `number`, `bool`, `enum`, `list`, `secret`) and their constraint keys. +- The `AGENTS.md` contract that every scaffolded project should honour. + +Point them at the skill file if they want to read it directly. It's ~400 lines of structured markdown. + +## What not to do + +- Don't scaffold without asking the user where the project should live. The interview always asks for a parent directory. +- Don't register secrets in `/.scarf/config.json`. Secret field values go through the macOS Keychain at install time; `config.json` stores `keychain://…` URIs, never plaintext. A scaffolded project that hasn't been installed yet has no secrets on disk at all. +- Don't claim dashboard widget titles the cron job doesn't actually update. The scaffolded `AGENTS.md` is a contract — if it says "the cron updates Sites Up / Sites Down", the cron prompt must match. +- Don't skip `{{PROJECT_DIR}}` token substitution in cron prompts. Hermes doesn't set a CWD for cron runs, so relative paths resolve against the agent's own dir — the installer swaps `{{PROJECT_DIR}}` for the absolute project path at install time. + +## Reference + +- `SKILL.md` at `~/.hermes/skills/templates/awizemann-template-author/scarf-template-author/SKILL.md` — the full scaffolding playbook. +- [Project Templates wiki page](https://github.com/awizemann/scarf/wiki/Project-Templates) — user-facing docs. +- [`awizemann/site-status-checker`](https://awizemann.github.io/scarf/templates/awizemann-site-status-checker/) — a complete working example covering dashboard stats, a configurable list, a cron job, a Site-tab webview, and a full AGENTS.md contract. Read it when you're unsure how a piece should look. diff --git a/templates/awizemann/template-author/staging/README.md b/templates/awizemann/template-author/staging/README.md new file mode 100644 index 0000000..fa4e8d6 --- /dev/null +++ b/templates/awizemann/template-author/staging/README.md @@ -0,0 +1,46 @@ +# Scarf Template Author + +A Hermes skill that teaches your agent how to scaffold a new Scarf project — and, because Scarf's `.scarftemplate` format is symmetric with a live project on disk, how to shape it so you can publish it to the catalog later if you want. + +## What you get + +Installing this template drops a skill at `~/.hermes/skills/templates/awizemann-template-author/scarf-template-author/SKILL.md` and a minimal "how to use" project in a folder of your choice. Every agent that reads the standard `~/.hermes/skills/` directory — Claude Code, Cursor, Codex, Aider, and the rest of the [agents.md](https://agents.md/) family — picks the skill up automatically. + +## How to use it + +After install, open your agent in any directory and say something like: + +- *"Create a new Scarf project that watches the number of open PRs in my GitHub repo."* +- *"Scaffold a Scarf dashboard that tracks daily focus time from my Toggl logs."* +- *"Set up a project that runs a cron job to summarise my inbox each morning."* +- *"Help me author a Scarf template I can share."* + +The agent will ask four or five questions (purpose, data source, cadence, what to display, any secrets) and then write: + +- `/.scarf/dashboard.json` +- `/.scarf/manifest.json` — only if you're going to use a configuration form or want to export later +- `/AGENTS.md` +- `/README.md` +- Optionally a cron job registered via `hermes cron create` (always created paused — you enable it from Scarf's Cron sidebar when ready). + +When it's done, click **+** in Scarf's Projects sidebar and pick the directory. Your dashboard appears. Iterate on it by asking your agent to tweak widgets or add fields. + +## Turning a local project into a shareable template + +Once you're happy with the result, Scarf → Projects → Templates → *Export "<name>" as Template…* produces a `.scarftemplate` anyone can install. The exporter carries the configuration *schema* but never your filled-in values — so your secrets and personal settings stay local. + +## About this template's own dashboard + +The installed project itself is tiny — a single Quick Start text widget and an empty list widget meant to serve as a scratchpad for tracking which scaffolded projects you've created. Its only purpose is to give you a place to land after install and a reminder of the trigger phrases above. The real value is the skill. + +## Reference + +- [Project Templates wiki page](https://github.com/awizemann/scarf/wiki/Project-Templates) — full spec + troubleshooting. +- [`awizemann/site-status-checker`](https://awizemann.github.io/scarf/templates/awizemann-site-status-checker/) — a complete, non-trivial example the skill studies and references. +- Dashboard / configuration schemas are Swift-authoritative at `scarf/scarf/Core/Models/ProjectDashboard.swift` and `scarf/scarf/Core/Models/TemplateConfig.swift` in the Scarf repo. + +## What this template intentionally is not + +- Not an archetype picker. v1 is blank-slate conversational; pre-baked starters (`monitor`, `dev-dashboard`, `personal-log`, etc.) may land in v1.1 once we see what shapes people ask for most often. +- Not a graphical wizard. The conversational agent path is strictly richer than a fixed form, and dogfoods Scarf's agent-first philosophy. +- Not a remote-scaffolding tool. It writes files into a directory on the machine where the agent runs; pair with Scarf's remote-server mode if you want to scaffold onto another box. diff --git a/templates/awizemann/template-author/staging/dashboard.json b/templates/awizemann/template-author/staging/dashboard.json new file mode 100644 index 0000000..63e9bc8 --- /dev/null +++ b/templates/awizemann/template-author/staging/dashboard.json @@ -0,0 +1,33 @@ +{ + "version": 1, + "title": "Template Author", + "description": "A Hermes skill that helps your agent scaffold new Scarf projects — ask in chat, answer a short interview, and land a working dashboard with the right shape to export as a .scarftemplate later. The Scaffolded Projects list below grows as you use the skill.", + "theme": { "accent": "blue" }, + "sections": [ + { + "title": "Quick Start", + "columns": 1, + "widgets": [ + { + "type": "text", + "title": "Ask your agent", + "format": "markdown", + "content": "**This project gives you a skill, not a service.** There are no cron jobs running, no dashboards to maintain. The real value lives at `~/.hermes/skills/templates/awizemann-template-author/scarf-template-author/SKILL.md`.\n\n**Trigger phrases** your agent listens for:\n\n- *\"Create a new Scarf project that watches …\"*\n- *\"Scaffold a dashboard to track …\"*\n- *\"Set up a project that runs a daily check on …\"*\n- *\"Help me author a Scarf template.\"*\n\nThe agent will interview you (purpose → data source → cadence → widgets → config → secrets), write `/.scarf/dashboard.json`, `/.scarf/manifest.json`, `/AGENTS.md`, and `/README.md`, then tell you to click **+** in Scarf's Projects sidebar to register the directory.\n\nWhen you're happy with the result, **Projects → Templates → Export** turns it into a `.scarftemplate` you can share.\n\nSee the [Project Templates wiki page](https://github.com/awizemann/scarf/wiki/Project-Templates) for the full spec." + } + ] + }, + { + "title": "Scaffolded Projects", + "columns": 1, + "widgets": [ + { + "type": "list", + "title": "Projects this skill has built for you", + "items": [ + { "text": "Nothing yet — ask your agent to scaffold a project and it'll optionally log entries here.", "status": "pending" } + ] + } + ] + } + ] +} diff --git a/templates/awizemann/template-author/staging/skills/scarf-template-author/SKILL.md b/templates/awizemann/template-author/staging/skills/scarf-template-author/SKILL.md new file mode 100644 index 0000000..455b33f --- /dev/null +++ b/templates/awizemann/template-author/staging/skills/scarf-template-author/SKILL.md @@ -0,0 +1,392 @@ +--- +name: scarf-template-author +description: Scaffold a new Scarf project — dashboard, optional configuration schema, optional cron job, and AGENTS.md — from a short conversational interview with the user. Output is immediately usable locally and cleanly exportable as a .scarftemplate bundle. +version: 1.0.0 +author: Alan Wizemann +license: MIT +platforms: [macos] +metadata: + hermes: + tags: [Scarf, templates, scaffolding, dashboard, authoring] + homepage: https://github.com/awizemann/scarf/wiki/Project-Templates +prerequisites: + commands: [hermes] +--- + +# Scarf Template Author + +Scaffold a new Scarf-compatible project from a conversational interview. The output is both (a) a working project on disk the user can register with Scarf and use immediately, and (b) correctly shaped to be exported as a `.scarftemplate` bundle via Scarf's Export flow later. + +## When to invoke this skill + +Activate when the user says things like: + +- *"Create a new Scarf project that watches / tracks / reports on …"* +- *"Scaffold a dashboard for …"* +- *"Set up a project that runs a daily check on …"* +- *"Help me author a Scarf template."* +- *"Build me a Scarf project to monitor …"* + +Do **not** activate for pure reference questions like *"what widget types does Scarf support?"* or *"how does Scarf handle secrets?"* — answer those inline from the reference sections below. + +Also do not activate when the user explicitly wants to edit an existing project's dashboard — that's a plain file edit, not a scaffold. + +## How a Scarf project is shaped on disk + +A Scarf project is just a directory registered in `~/.hermes/scarf/projects.json`. For Scarf to render a useful dashboard and for the project to be exportable as a `.scarftemplate`, it needs these files at minimum: + +``` +/ +├── .scarf/ +│ ├── dashboard.json # REQUIRED for dashboard rendering +│ └── manifest.json # OPTIONAL — required only if the project declares a config schema or you want to export cleanly +├── AGENTS.md # Cross-agent instructions (agents.md standard) — ship this for every project +└── README.md # User-facing explanation +``` + +If the project will have a scheduled job, ALSO register a cron entry via `hermes cron create`. For an exportable bundle, also author `cron/jobs.json` in the staging directory — that's where Scarf's exporter will pick jobs up from. + +Secrets never land in `dashboard.json` or `config.json`. At install time, Scarf routes secret-type config values to the macOS Keychain; `config.json` stores `keychain://service/account` URIs. When scaffolding from scratch (no install), the user either manages secrets via the post-install Configuration editor after export, or stashes them in their `~/.hermes/config.yaml` if they're Hermes-level secrets rather than project-level. + +## The interview + +Ask these questions in order. Don't batch. Each answer shapes the next question. + +### 1. Purpose and data source + +- *"In one sentence — what does this project do?"* +- *"Where does its data come from? Files, a URL, a shell command's output, an API call, a database, a spreadsheet?"* + +Goal: figure out whether the project is **passive** (user maintains some files, dashboard reflects them), **pull-based** (we fetch from an HTTP endpoint or CLI tool on a schedule), or **push-based** (something external writes to a file we watch). + +### 2. Refresh cadence + +- *"How often should it refresh? Every hour? Daily? Weekly? Only when I ask?"* + +If "only when I ask" → no cron job; user invokes the agent manually. If any scheduled cadence → cron job. + +Map to cron expressions: +- Every hour: `0 * * * *` +- Daily at 9 AM: `0 9 * * *` +- Weekly Monday 9 AM: `0 9 * * 1` +- Every 15 minutes: `*/15 * * * *` + +### 3. What the dashboard shows + +Explain the seven widget types (see Widget Catalog below) in plain English, then ask which ones feel right. Offer concrete suggestions based on the purpose: + +- Counting things (open PRs, failing tests, up/down sites) → `stat` widgets. +- A list of items with status → `list` with `text` + `status` per item. +- Time-series data → `chart` with `line` or `bar` type. +- Rows × columns of heterogeneous data → `table`. +- A live URL (useful for monitoring a site) → `webview`. **Including a webview widget exposes a Site tab** next to the Dashboard tab — worth noting to the user. +- A progress bar for something with a clear 0-to-N scale → `progress`. +- Static help / markdown → `text` with `format: "markdown"`. + +### 4. Configuration needs + +- *"Does this project need anything configurable by the user — URLs to watch, API tokens, thresholds, a list of accounts?"* + +If yes → design a config schema. Fields map to seven types (see Config Schema Design below). Remember: **secret fields never have defaults**; that's a hard validator rule. + +If no → skip `.scarf/manifest.json`; the project works but won't have a Configuration form. + +### 5. Target agents + +- *"Which agents will operate this project? Just Claude Code? Also Cursor / Codex / Aider / other?"* + +For v1 just write `AGENTS.md` — every modern agent reads it, and if you need a specific shim (CLAUDE.md, GEMINI.md, .cursorrules), add it as a symlink to AGENTS.md so content stays in sync. + +## Widget Catalog (JSON shapes) + +All widgets require `type` and `title`. Type-specific fields: + +### `stat` — single metric +```json +{ "type": "stat", "title": "Sites Up", "value": 0, + "icon": "checkmark.circle.fill", "color": "green", "subtitle": "responded 2xx/3xx" } +``` +`value` accepts number OR string (`WidgetValue` enum). `icon` is an SF Symbol name. `color` is one of: `green`, `red`, `blue`, `orange`, `yellow`, `purple`, `gray`. + +### `progress` — 0.0 to 1.0 progress bar +```json +{ "type": "progress", "title": "Test Coverage", "value": 0.72, "label": "72% of statements" } +``` + +### `text` — markdown or plain text block +```json +{ "type": "text", "title": "Quick Start", "format": "markdown", + "content": "**1.** Click + in the Projects sidebar.\n\n**2.** ..." } +``` +`format` is `"markdown"` or `"plain"`. + +### `table` — columns × rows of strings +```json +{ "type": "table", "title": "Failing Tests", + "columns": ["Test", "Duration", "Last Passed"], + "rows": [["testFoo", "4.2s", "Apr 20"], ["testBar", "0.9s", "Apr 18"]] } +``` +Every row MUST have the same length as `columns`. + +### `chart` — line / bar / area / pie with series +```json +{ "type": "chart", "title": "Requests / day", "chartType": "line", + "xLabel": "Date", "yLabel": "Count", + "series": [{ + "name": "staging", + "color": "blue", + "data": [{"x": "Apr 20", "y": 142}, {"x": "Apr 21", "y": 189}] + }] +} +``` +`chartType` is `"line"`, `"bar"`, `"area"`, or `"pie"`. + +### `list` — items with optional status badge +```json +{ "type": "list", "title": "Watched Sites", + "items": [ + { "text": "https://example.com", "status": "up" }, + { "text": "https://example.org", "status": "down" } + ] +} +``` +`status` values: `"up"`, `"down"`, `"pending"`, `"ok"`, `"warn"`, `"error"` — render as coloured badges. + +### `webview` — embedded live URL +```json +{ "type": "webview", "title": "First Watched Site", + "url": "https://awizemann.github.io/scarf/", "height": 420 } +``` +**Important:** including any `webview` widget in a dashboard exposes a **Site** tab next to the Dashboard tab in the project view. Useful for templates that watch something renderable. The agent can update `url` on cron runs to keep the Site tab in sync with config (e.g., set it to `values.sites[0]`). + +## Config Schema Design + +If the project needs user-configurable values, design a schema. Put it in `/.scarf/manifest.json` with this shape: + +```json +{ + "schemaVersion": 2, + "id": "author/project", + "name": "My Project", + "version": "1.0.0", + "description": "Short one-liner.", + "contents": { "dashboard": true, "agentsMd": true, "config": 2 }, + "config": { + "schema": [ + { "key": "sites", "type": "list", "itemType": "string", "label": "Sites", + "required": true, "minItems": 1, "maxItems": 25, + "default": ["https://example.com"] }, + { "key": "api_token", "type": "secret", "label": "API Token", "required": true } + ], + "modelRecommendation": { + "preferred": "claude-haiku-4", + "rationale": "Short-running, tool-light workload — haiku is plenty." + } + } +} +``` + +Note: `contents.config` is the **count of schema fields**, not a boolean. In the example above it's `2` because there are two fields. + +### Field types and constraints + +| Type | Rendered as | Constraint keys | +|---|---|---| +| `string` | Text field | `pattern` (regex), `minLength`, `maxLength` | +| `text` | Multi-line editor | `minLength`, `maxLength` | +| `number` | Number field | `min`, `max` | +| `bool` | Toggle | — | +| `enum` | Segmented (≤4) / Dropdown (>4) | `options: [{value, label}]` (REQUIRED) | +| `list` | Repeatable rows | `itemType: "string"` (required), `minItems`, `maxItems` | +| `secret` | Password field, routes to Keychain | — | + +Every field takes `key` (required), `label` (required), `description` (optional — markdown), `required` (bool), `default` (optional; type matches the field type). + +### Hard rules + +- **Secret fields MUST NOT have a `default`.** The validator rejects the manifest if they do — a default makes no sense because the Keychain entry doesn't exist yet at install time. +- **Enum fields MUST have non-empty `options`.** +- **List fields MUST have `itemType: "string"`** in v1 (only itemType supported). +- **Field keys MUST be unique** within a schema. +- **`schemaVersion` MUST be 2** when a `config` block is present; it stays 1 if there's no config. +- **`contents.config`** must equal the actual count of schema fields — a claim mismatch is rejected. + +## Cron Job Design + +If the project has a scheduled task, register a cron job via `hermes cron create` AND — if you expect the user to export this as a `.scarftemplate` — author a `cron/jobs.json` in the staging layout so the exporter picks it up. + +### Staging shape (for exportable templates) + +``` +/ +├── .scarf/ +├── AGENTS.md +├── README.md +└── cron/ + └── jobs.json +``` + +Where `cron/jobs.json` is: + +```json +[ + { + "name": "Check site status", + "schedule": "0 9 * * *", + "prompt": "Read {{PROJECT_DIR}}/.scarf/config.json — get values.sites and values.timeout_seconds — then HTTP GET each URL with that timeout, write the results to {{PROJECT_DIR}}/status-log.md, and update {{PROJECT_DIR}}/.scarf/dashboard.json's stat widgets by title (Sites Up, Sites Down, Last Checked). Reply with a one-line summary." + } +] +``` + +### Gotchas + +- **Hermes does not set a CWD when firing cron jobs.** Relative paths in the prompt resolve against wherever the Hermes process happens to be running, not the project. Always use `{{PROJECT_DIR}}` in the prompt — the installer substitutes the absolute path at install time. This is THE most common template-author mistake. +- **Cron jobs created by the installer start paused.** Their name is auto-prefixed with `[tmpl:]`. The user enables them from Scarf's Cron sidebar when ready. +- **Registering a cron job for a user's local (non-exported) project:** run `hermes cron create --name "" "" ""` directly, substituting the absolute `` path for `{{PROJECT_DIR}}` yourself. Then `hermes cron pause ` so it doesn't run until the user opts in. + +### Schedule quick reference + +| Cadence | Expression | +|---|---| +| Every 15 minutes | `*/15 * * * *` | +| Hourly at :00 | `0 * * * *` | +| Daily at 9 AM | `0 9 * * *` | +| Weekly Monday 9 AM | `0 9 * * 1` | +| First of the month, 9 AM | `0 9 1 * *` | + +## Writing the files + +After the interview, write files in this order. + +### Step 1 — confirm parent directory + +Ask: *"Where should I create the project? Give me an absolute path — I'll make a `` directory inside it."* + +Make sure the parent exists and is writable. Make sure `/` does NOT already exist. If it does, ask whether to pick a different name or bail. + +### Step 2 — create the skeleton + +```bash +mkdir -p //.scarf +``` + +### Step 3 — write `dashboard.json` + +Use the Widget Catalog above. Always include: + +- `version: 1` +- `title` (the project's display name) +- `description` (a one-liner shown under the title) +- `sections` (array; each has `title`, optional `columns` (1–4, default 3), `widgets`) + +Keep section titles short. Group related widgets. First section is usually "Current Status" or similar with the key stats. + +### Step 4 — write `manifest.json` (only if the project has a config schema) + +Put the full manifest shape from Config Schema Design above. Use `schemaVersion: 2`, match `contents.config` to the actual field count, and ensure every secret field has no `default`. + +If there's no config schema, skip this file — the project still works, it just won't have a Configuration button. You can add it later. + +### Step 5 — write `AGENTS.md` + +Every scaffolded project needs an `AGENTS.md` that covers: + +- **Purpose** — what the project does. +- **Layout** — which files exist and what they're for. +- **Configuration** — if there's a config schema, document every field: what it's for, what valid values look like, what happens when it's missing. +- **Dashboard** — list every widget the cron job (if any) updates, by title. If the cron updates a webview widget's URL, document that explicitly. +- **Cron behaviour** — what the cron job does, what it reads, what it writes, what its exit criteria are. +- **Chat prompts** — common user questions and how to answer them (e.g., *"What's the status of my sites?"* → "read the top section of `status-log.md` and summarise"). +- **What NOT to do** — e.g., *don't modify `.scarf/config.json` yourself; tell the user to open the Configuration button.* + +Use `{{PROJECT_DIR}}` placeholders in AGENTS.md only if the template will be installed through the installer (which substitutes the token). For a hand-scaffolded local-only project, substitute the absolute path yourself — `{{PROJECT_DIR}}` only resolves at install time. + +### Step 6 — write `README.md` + +User-facing. Keep it short: + +- One-paragraph purpose. +- How to install / first run (for an unexported project: "click + in Scarf's Projects sidebar"). +- How to trigger the cron job manually (Cron sidebar → Run Now). +- A pointer at `AGENTS.md` for agents. + +### Step 7 — register the cron job (if any) + +For a local non-exported project: + +```bash +hermes cron create --name "" "" "" +# Then pause it so it doesn't fire until the user's ready: +hermes cron pause +``` + +Read the id back from `hermes cron list --json` or parse the create output. + +For an exportable template (one you're staging in `templates///staging/`): just author `cron/jobs.json` — the installer registers + pauses at install time, and prefixes the name with `[tmpl:]`. + +### Step 8 — register the project with Scarf + +Tell the user: *"I've written the files. Click the **+** button in Scarf's Projects sidebar and pick ``. The dashboard will appear."* + +Do NOT edit `~/.hermes/scarf/projects.json` directly — Scarf owns that file and reloads it on its own. The UI path is safer. + +### Step 9 (optional) — log to the Template Author project's list + +If the user has the `awizemann/template-author` project installed (the one that shipped this skill), append an entry to its `dashboard.json`'s `Scaffolded Projects` list widget: + +```json +{ "text": "", "status": "ok" } +``` + +This gives the user a running audit trail of everything you've scaffolded for them. Preserve every other field in the dashboard as-is. + +## Testing your scaffold + +### Minimum smoke test + +1. Tell the user to click **+** in Scarf's Projects sidebar and pick the directory. +2. Dashboard appears — sanity check every widget renders correctly. +3. If there's a cron job: click the job in Scarf's Cron sidebar → **Run Now**. The agent executes the prompt; dashboard updates when it finishes. + +### Configuration-form test (only if schema was declared) + +To verify the Configuration form renders, you need to *install* the project as a template — scaffolded projects don't go through the installer, so the form never runs. Export the project first: + +1. Projects → Templates → **Export "<name>" as Template…** → save the `.scarftemplate` somewhere. +2. Projects → Templates → **Install from File…** → pick the bundle → the Configure step should render the form you designed. +3. Cancel the install (the preview sheet has a Cancel button) — you just wanted to verify the form shape. + +### Catalog validation (only if publishing) + +If the user plans to submit this to the public catalog at `awizemann.github.io/scarf/templates/`: + +```bash +# From the repo root +./scripts/catalog.sh check +``` + +Validates every template in `templates///` against the Python validator — the same one the PR CI uses. Catches schema issues, claim mismatches, size violations, common secret patterns. + +## Common pitfalls + +Things to check before declaring the scaffold done: + +- [ ] Every cron prompt uses `{{PROJECT_DIR}}` (for exported) OR an absolute path (for local-only). Relative paths will fail. +- [ ] `contents.config` in the manifest equals the actual field count. Claim mismatch = rejected. +- [ ] No `default` on any `secret` field. +- [ ] Every enum field has non-empty `options`. +- [ ] Every list field has `itemType: "string"`. +- [ ] Every table widget has rows of length equal to `columns`. +- [ ] Every webview widget has an https URL that renders something meaningful even pre-first-run (Scarf homepage is a decent placeholder). +- [ ] `dashboard.json` has `version: 1` at the top. +- [ ] `AGENTS.md` documents every config field, every updated widget, and the cron behaviour — the user relies on it as the source of truth when things drift. + +## Reference — source of truth files + +- **Dashboard widget schema** — `scarf/scarf/Core/Models/ProjectDashboard.swift` in the Scarf repo. If you need exact field types or defaults, read it. +- **Config schema + validation** — `scarf/scarf/Core/Models/TemplateConfig.swift` and `scarf/scarf/Core/Services/ProjectConfigService.swift`. +- **Exporter behaviour** — `scarf/scarf/Core/Services/ProjectTemplateExporter.swift`. Verifies what files the exporter will pick up from a live project and what it'll carry into a bundle. +- **Installer contract** — `scarf/scarf/Core/Services/ProjectTemplateInstaller.swift`. Verifies what `{{PROJECT_DIR}}` substitution covers and where installed files land. +- **Catalog validator** — `tools/build-catalog.py` in the Scarf repo. Run with `./scripts/catalog.sh check` for the same rules CI uses. +- **Worked example** — `templates/awizemann/site-status-checker/staging/` in the Scarf repo. Complete end-to-end: dashboard with stats + list + webview, a config schema with a list + a number, a cron job, an AGENTS.md that documents every moving part. Read it first whenever you're unsure how a piece should look. +- **User-facing docs** — [Project Templates wiki page](https://github.com/awizemann/scarf/wiki/Project-Templates). diff --git a/templates/awizemann/template-author/staging/template.json b/templates/awizemann/template-author/staging/template.json new file mode 100644 index 0000000..1241e18 --- /dev/null +++ b/templates/awizemann/template-author/staging/template.json @@ -0,0 +1,19 @@ +{ + "schemaVersion": 2, + "id": "awizemann/template-author", + "name": "Scarf Template Author", + "version": "1.0.0", + "description": "Install this to give your agent a skill that scaffolds new Scarf projects — dashboards, optional configuration schemas, cron jobs, and AGENTS.md — from a short conversational interview. Scaffolded projects are usable locally and cleanly exportable as .scarftemplate bundles.", + "minScarfVersion": "2.2.0", + "author": { + "name": "Alan Wizemann", + "url": "https://github.com/awizemann" + }, + "category": "developer-tools", + "tags": ["meta", "authoring", "skill", "scaffolding"], + "contents": { + "dashboard": true, + "agentsMd": true, + "skills": ["scarf-template-author"] + } +} diff --git a/templates/awizemann/template-author/template-author.scarftemplate b/templates/awizemann/template-author/template-author.scarftemplate new file mode 100644 index 0000000..5957140 Binary files /dev/null and b/templates/awizemann/template-author/template-author.scarftemplate differ diff --git a/templates/catalog.json b/templates/catalog.json index 7abaeb5..f303b5d 100644 --- a/templates/catalog.json +++ b/templates/catalog.json @@ -63,6 +63,37 @@ "configurable" ], "version": "1.1.0" + }, + { + "author": { + "name": "Alan Wizemann", + "url": "https://github.com/awizemann" + }, + "bundleSha256": "670b2e07ad9bb327c11fa64db1beacf86614a3d388de6fe6e2a19ac957e1346b", + "bundleSize": 13889, + "category": "developer-tools", + "config": null, + "contents": { + "agentsMd": true, + "dashboard": true, + "skills": [ + "scarf-template-author" + ] + }, + "description": "Install this to give your agent a skill that scaffolds new Scarf projects \u2014 dashboards, optional configuration schemas, cron jobs, and AGENTS.md \u2014 from a short conversational interview. Scaffolded projects are usable locally and cleanly exportable as .scarftemplate bundles.", + "detailSlug": "awizemann-template-author", + "id": "awizemann/template-author", + "installUrl": "https://raw.githubusercontent.com/awizemann/scarf/main/templates/awizemann/template-author/template-author.scarftemplate", + "minHermesVersion": null, + "minScarfVersion": "2.2.0", + "name": "Scarf Template Author", + "tags": [ + "meta", + "authoring", + "skill", + "scaffolding" + ], + "version": "1.0.0" } ] }