# Schaffa skills

Each section contains one complete SKILL.md file.

## Read Schaffa

````markdown
---
name: schaffa-read
description: Use when the user provides a Schaffa URL to read.
---

# Schaffa Read

Fetch the supplied URL with the shell. Do not use web search or a browser to retrieve it.

`curl --fail --silent --show-error --location "<url>"`

- Page URLs use `/p/<slug>`; append `/raw` when exact HTML source is needed.
- File URLs use `/f/<id>.<ext>`; save binary files with `--output <temporary-file>` before inspecting them.
- Guide URLs use `/g/<slug>`; use `.md` or `.json` when structured guide content is easier to process.

If curl fails, report its HTTP or network error. Do not substitute search results.
````

## Write HTML

````markdown
---
name: schaffa-html
description: Use when the user asks to communicate through an HTML document, or if they mention "HTML" with no additional context.
---

# Schaffa HTML

Use this skill for a readable plan, spec, write-up, findings, summary, report, comparison, or set of UI mocks. Do not use it for HTML that ships as part of a product.

Create one complete, self-contained HTML file capped at 512 KB.

- Write it like a spec, not a landing page: dense, scannable, and without hero copy or decorative chrome.
- Make it mobile-readable with a responsive viewport and no fixed-width layout.
- Use semantic HTML, inline CSS, inline SVG, and data-URL images.
- For UI mocks, render real styled variants, label them A, B, C, and so on, and arrange them for direct comparison.
- Do not include scripts, forms, frames, event handlers, JavaScript URLs, meta refresh, external stylesheets, or external assets.
- Never include secrets, private URLs, or local filesystem paths.

Publish the finished file directly to Schaffa:

```sh
curl --fail-with-body --silent --show-error \
  -F "html=@<html-file>;type=text/html" \
  "https://schaffa.dev/api/pages"
```

Add `-H "Authorization: Bearer $SCHAFFA_TOKEN"` for a permanent page. Without it, the page expires after one hour. Keep one local file across revisions; for a permanent page, upload later versions with `PUT /api/pages/<slug>` so its public URL stays stable.

Read `publicUrl` from the JSON response and return it with the local path. Never claim the document is hosted before the upload succeeds, and do not verify it in a browser unless the user asks.
````

## Upload File

````markdown
---
name: schaffa-file
description: Use when the user asks to upload or share a file, or a public file URL is needed.
---

# Schaffa File

Require `SCHAFFA_TOKEN` in the environment. If the token is unset, tell the user instead of guessing.

```sh
curl --fail-with-body --silent --show-error \
  -H "Authorization: Bearer $SCHAFFA_TOKEN" \
  -F "file=@<file>" \
  "https://schaffa.dev/api/files"
```

Read `publicUrl` from the JSON response and return it. On HTTP 401, report that the token is missing or invalid and do not retry.

Use only files the user placed in scope. Treat the URL as public. Schaffa removes the original filename; recognized images are stripped of metadata, resized when needed, converted to WebP, and the original image is discarded. Never write the token value literally or expose request headers.
````

## Write Guide

````markdown
---
name: schaffa-guide
description: Use when the user asks for a step-by-step guide.
---

# Schaffa Guide

Keep `SCHAFFA_TOKEN` in the environment. Start before the first action. Keep `.schaffa/guide-session.json` and `.schaffa/recordings/` local and uncommitted; they do not store the token.

Prefer automatic recording:

- Signed-in Chrome on macOS: `npx schaffa record --title "<title>" --chrome "<url>"`
- Isolated browser profile: `npx schaffa record --title "<title>" --browser "<url>"`
- Desktop: `npx schaffa record --title "<title>" --desktop --app <bundle-id>`

`--chrome` asks running Chrome for a window without creating or selecting a profile. Chrome chooses an existing profile session with its logins, extensions, and password manager. Do not promise a specific profile. The recorder binds to that exact window and ignores others. Use `--browser` only for an isolated profile.

Clicks get a compact cursor and red target outline. Close the recorded window or press Ctrl+C to publish. Alt+Shift+R pauses capture. After upload failure, run `npx schaffa guide sync`; a clean sync publishes.

Review every server step. Use a one-based number or exact step ID. Published fixes create an immutable revision:

- Inspect: `npx schaffa guide status --json`
- Edit: `npx schaffa guide edit-step --step <number-or-id> --title "<title>" --text "<instruction>"`
- Replace an image: `npx schaffa guide replace-screenshot --step <number-or-id> --screenshot <path>`
- Delete: `npx schaffa guide delete-step --step <number-or-id>`

Replacement does not recreate the cursor or target outline. Add them to the image before upload when needed.

For mixed work, record manually:

- Start: `npx schaffa guide start --title "<title>"`
- Add a step: `npx schaffa guide step --title "<step>" --text "<instruction>" --action <type> --target "<target>" --verification "<expected-result>"`
- Finish: `npx schaffa guide finish --json`

Record state changes, not every click. Add screenshots only when visible state helps. Never capture authentication, passwords, payments, private data, or secret-manager screens. Chrome pixels can expose tabs, extensions, and forms; pause and review. Desktop mode ignores other apps, editable values, and secure controls.

Writes use the persisted edit revision. On conflict, reload and reconcile. Retry with the original idempotent manifest entry.

Finishing publishes it automatically. Fix preflight findings and rerun `npx schaffa guide finish --json`. Return its URL.
````

## Write Presentation

````markdown
---
name: schaffa-presentation
description: Use when the user asks for a presentation, slide deck, or slides.
---

# Schaffa Presentation

Keep `SCHAFFA_TOKEN` in the environment and create the deck as Marp Markdown. Keep images local; do not use remote fonts, CDNs, or external image URLs.

Publish the HTML deck and its Markdown source:

`npx schaffa publish <deck.md> --kind presentation --json`

Add `--export pdf`, `--export pptx`, or both when the user wants downloadable exports. Return the presentation's public URL and any requested export URLs from the JSON response.
````
