Site source
A site's files live in git. You clone the repository, edit it, and push.
Git is the source of truth for what a site is made of. It is git rather than an upload API for one reason: the build sandbox needs credentials that reach one site and nothing else, and a git credential is per repository by nature.
Two repositories
A site has two repositories, and the split is what lets a post go live alone.
| Repository | Holds | Address |
|---|---|---|
| source | the site's code and design | https://api.heyclave.party/git/<site id>.git |
| content | the site's posts | https://api.heyclave.party/git/<site id>.content.git |
The build mounts the content repository at src/content/, so the two can
never hold one file. Every surface takes one tree: a path under
src/content/ routes itself to the content repository.
A batch that crosses the two repositories is refused. Two commits in two repositories are not one change.
The content repository takes an allowlist of formats. "Not code" is what it has to promise, and a denylist promises only "not the code we thought of".
Files you may not change
Clave maintains some files and freezes them: package.json, the lockfiles
and .npmrc. A push that changes one is refused, by the API and by the
pre-receive hook.
The reason is the build. A site that edits its own dependency list builds against a tree that the file does not describe.
astro.config.mjs is not frozen. A site that wants another
integration adds it itself.
Where a file may go
What a site may hold is gated by where the file goes, not by one list of formats.
src/assetstakes what the build's toolchain can read. A file the toolchain cannot decode is a build failure that blames the site's own source.public/is copied out as it is, and nothing opens it. It takes a second, shorter list — today.pdfalone.
public/ must never take a format that runs script. That directory is
served from the site's own hostname, and an upload link that writes into
it travels over chat.
Three ways a file arrives
- A push, for anything in the tree.
- The API, with
PUT /v1/sites/{id}/assets/{path}for a file the agent already holds,POST /v1/sites/{id}/photosfor a stock photo, andPOST /v1/sites/{id}/uploadsfor a link the owner uses. - An upload link, which the owner opens in a browser and drops a file on. The link is bound to one site, it expires, it has a slot count, and each file has a byte cap.
One daily allowance covers all three. Read Site source.
Drafts of posts
A post marked draft: true never reaches the live site. The filter is in
the platform, not in the site's own code: a filter in a page is code an
agent may remove, and a draft post on the live site is the one mistake
this feature must not make.