# The Cheldrop skill

This is `SKILL.md` as Claude loads it. Its frontmatter — the part that decides when Claude reaches for it — is shown first, then the skill itself.

```yaml
name: cheldrop
description: Publish and maintain websites through Cheldrop — a Mac app that turns a folder on the user's machine into a live site on their own domain, in their own Cloudflare account. Use whenever the user asks to publish something, share files on a URL, put a document or gallery online, update or reconfigure a site they already have, set up a client vault, or mentions Cheldrop, a Cheldrops folder, cheldrop.yaml, or a site of theirs that "syncs by itself". Also use when the user hands over files and asks for a link to send someone.
```

# Cheldrop

Cheldrop turns a folder into a website. The folder lives on the user's Mac, the
site lives on the user's own domain in the user's own Cloudflare account, and
Cheldrop is the thing in between. Nothing is hosted by Cheldrop or by Anthropic.

There are two ways to work with it, and picking the right one is most of the job.

| You want to change… | Use |
|---|---|
| What the site says — pages, files, images, documents | **The folder.** Write files. |
| How the site behaves — TOC, toolbar, theme, ignore list | **The folder.** Edit `cheldrop.yaml` / `cheldrop.css`. |
| Whether the site exists at all — create, publish now, password, delete | **The MCP tools.** They need the Cloudflare token. |

**Default to the folder.** It is faster, it needs no permissions beyond file
access, and it is how the app is meant to be used. Reach for a tool only when
the change cannot be made by writing a file.

## The folder convention

Site folders live in `~/Documents/Cheldrops/`, one per site, named by site ID:

```
~/Documents/Cheldrops/vault.client.com/
├── cheldrop.yaml      ← configuration (never published)
├── cheldrop.css       ← optional theme (injected, not published as-is)
├── index.md
├── proposal.pdf
└── images/photo.jpg
```

The folder *is* the site. Publishing is full replacement: whatever is in the
folder is what is live, and a file deleted from the folder disappears from the
site on the next publish. Never empty a folder to "start fresh" — that is a
request to wipe a live site, and Cheldrop will refuse it unattended.

A site can be **Live**. A Live folder republishes itself roughly five seconds
after the last change (at most once a minute). So: write the files, say what you
did, and stop. Do not call `publish_now` after every edit to a Live site.

Confirm a site's folder path with `list_sites` rather than assuming it — a folder
can be moved, and older sites may be in "files mode" with no folder at all.

### How files are rendered

- `.md`, `.txt`, PDFs, images, video and audio **at the folder root** get wrapped
  in a generated page — `report.md` is served at `/report.md.html`, with the raw
  file still at `/report.md`.
- `.html` is passed through byte for byte. Cheldrop does not rewrite the user's
  HTML (unless the site sets `theme_user_html: true`).
- Files in subfolders are published as-is, unwrapped. Put things you want wrapped
  at the root.
- A table of contents is generated for multi-file sites: `toc: index` (default) is
  a site-map front page, `toc: sidebar` adds a navigation rail to every generated
  page — a docs site — and `toc: none` generates nothing.
- Hidden files (dotfiles) never publish.

Markdown is the path of least resistance: for most "put this online" requests,
write `index.md` and let Cheldrop render it.

## cheldrop.yaml

The config source of truth. Cheldrop reads it on every publish, the app writes
its own changes back to it, and unknown keys you add survive untouched.

```yaml
schema_version: 1
site: vault.client.com     # subdomain.domain — do not change on an existing site
backend: workers           # workers (free) | r2 (Business Class, large files, passwords)
live: false                # true = this folder republishes itself
password_protected: false  # set by set_password; the password itself is never here
toc: index                 # index (site map) | sidebar (docs site) | none
show_toc: true             # kept in step with toc:; toc: wins if they disagree
show_toolbar: true
toolbar:
  date: true
  raw_file: true
  download: true
  copy_link: true
theme: cheldrop.css        # or null for no theme
theme_user_html: false     # true = inject the theme into the user's own HTML too
header: Acme Docs          # optional site chrome — see "Header and footer"
footer: © 2026 Acme AS     # optional; both absent unless asked for
ignore:                    # globs, publish-relative
  - drafts/
  - "*.psd"
```

Rules, in order of how much trouble breaking them causes:

1. **Never write a secret into this file.** No API tokens, no passwords, no
   admin secrets. These folders end up in iCloud and Dropbox — treat the contents
   as semi-public. Passwords go through `set_password`, which stores only a
   derived hash inside the user's own Cloudflare account.
2. **Never edit `site:`** on a folder that is already published. It is the join
   key to the Cloudflare resources; changing it orphans them.
3. **Invalid YAML publishes nothing.** Cheldrop refuses to guess, and a Live site
   stops updating until the file parses. Re-read what you wrote.
4. **`backend: r2` requires Business Class**, and so does password protection. On
   the free tier, a hand-edited `backend: r2` fails at publish rather than
   silently downgrading.
5. **Respect `ignore`.** If the user keeps working files in the folder, add a
   glob rather than moving their files around.

Turning `live` on by hand in the file works, but the site must have been
published at least once first.

### Making it a docs site

`toc: sidebar` puts a navigation rail on every page Cheldrop generates, which is
all a folder of Markdown needs to become a documentation site. Pages are listed
alphabetically unless the yaml says otherwise:

```yaml
toc:
  mode: sidebar
  items:              # optional; anything left out is appended alphabetically
    - intro.md
    - guide:          # one group, one level deep — the label links to guide/ if it exists
        - setup.md
        - usage.md
```

Name the files as they sit in the folder (`intro.md`, not `intro.md.html`). The
rail is styled from the same tokens as the rest of the site, so `cheldrop.css`
restyles it too.

### Header and footer

Optional, absent unless asked for, and rendered into every page Cheldrop
generates:

```yaml
header:
  title: Acme Docs         # `header: Acme Docs` is the short form
  logo: logo.png           # a file in the folder; it must publish, so no ignore glob over it
  link: /                  # where the title and logo point; default /
footer:
  text: © 2026 Acme AS     # `footer: © 2026 Acme AS` is the short form
  links:
    - Contact: mailto:hi@acme.com
    - Privacy: /privacy.html
```

Link targets must be `http(s)`, `mailto`, `tel`, or a path/anchor on the site —
anything else is dropped rather than published. A logo that is not among the
published files is skipped and the title stands alone, so check the file is in
the folder and not covered by `ignore`.

## cheldrop.css

A rendering input, not a passthrough file. Its contents are published under a
generated name and linked into every page Cheldrop generates. It styles the
wrappers, the table of contents and the toolbar; it does not touch the user's own
HTML unless `theme_user_html: true`.

Write plain CSS. There is no build step, no preprocessor, and no framework.

A theme is a set of custom properties on `:root` — `--bg`, `--surface`,
`--text`, `--muted`, `--accent`, `--accent-ink`, `--on-accent`, `--radius`,
`--font-display`, `--font-ui`. The stylesheet is linked last, so those tokens
win over Cheldrop's built-in look in light and dark alike; a site that should
follow the reader's system needs its own `@media (prefers-color-scheme: dark)`
block. Never fetch a font over the network — a published Cheldrop site makes no
outside calls, so name faces and let them fall back.

The file may have come from one of Cheldrop's starter themes, in which case its
header carries a `cheldrop-theme:` line naming it. Editing it is expected and
safe: the app compares the file against the original and asks before a theme
change would overwrite the changes.

## The MCP tools

Available when the user has Cheldrop's MCP server on (Settings → MCP server).
Cheldrop must be running. Nothing here returns a secret — not the Cloudflare
token, not a site's admin secret, and never a password.

It is a standard MCP server on `127.0.0.1:3847`, so any local MCP client can
drive it, not only Claude Desktop. If the user is in a client that has no
Cheldrop tools, they set it up from Settings → MCP server → *Set up another
app*; a client that runs in the cloud cannot reach it at all, by design.

- **`get_settings`** — is Cheldrop configured, which domains are available, free
  or Business Class, app version, the Cheldrops root. Call this first when you
  do not know the lay of the land; a domain that is not in `available_domains`
  cannot be published to.
- **`list_sites`** — every site with `folder_path`, `live`, `live_status`,
  backend, whether it is password-protected. This is how you find the folder to
  write into.
- **`create_site`** — the whole setup in one move: creates the folder, writes
  `cheldrop.yaml`, provisions the Cloudflare resources, publishes a placeholder,
  and turns Live on. Then you write the real files into the returned
  `folder_path`. Pass `backend: "r2"` if the site needs password protection or
  files over 25 MB.
- **`adopt_folder`** — register a folder that already carries a `cheldrop.yaml`
  (a new Mac, a moved folder). Publishes nothing.
- **`publish_now`** — publish a folder immediately instead of waiting for Live
  sync. Use it for non-Live sites, or when the user is watching and wants it now.
- **`set_password`** — protection on or off for an R2 site. Republishes the site
  to apply it. Cheldrop never stores the password, so tell the user what it is
  once and say it cannot be recovered — only replaced.
- **`delete_site`** — destructive, not undoable. The first call only describes
  what would go. Ask the user in plain words, get a real yes, then call again
  with `confirmed: true`. Never chain both calls on your own initiative. The
  local folder is kept unless the user asks for `folder_action: "trash"`.

Errors come back as complete sentences meant for the user — relay them rather
than paraphrasing, especially the ones about token permissions, which tell the
user exactly what to add.

## Working patterns

**"Set up a vault for client X"**

1. `get_settings` → confirm configured, pick a domain the user actually owns.
2. `create_site` with `subdomain`, `domain`, and `backend: "r2"` if it needs a
   password.
3. `set_password` if asked — then tell the user the password, once.
4. Write the files into `folder_path`.
5. Live publishes them. Give the user the URL.

**"Update the site"**

1. `list_sites` → find `folder_path` and whether it is Live.
2. Read what is there, then write the changes.
3. Live: say it will be live in a few seconds. Not Live: `publish_now`.

**"Change how it looks"**

Edit `cheldrop.css` in the folder. Nothing else is needed.

**"Take it down"**

Ask whether they mean unpublish or delete. `delete_site` removes it from
Cloudflare for good; turning `live: false` just stops it updating.

## Free tier limits

One site, `backend: workers` only, no password protection, 25 MB per file. When
a limit is hit, the tool result carries an `upgrade` field — pass on what it says
and move on. Do not try to route around a limit.

## What Cheldrop is not

Not a CMS, not a build pipeline, not a deploy target for a React app. It
publishes files. If the user needs a framework build, build it elsewhere and put
the output folder in Cheldrop.
