Content with Claude, ownership with git: how this blog works

How this site is built: static pages generated by Astro, Markdown files kept in git, the Sveltia CMS panel, Pagefind search, Cloudflare hosting, and a writing flow in which Claude prepares the drafts.

Three tidy rectangular blocks joined by thin lines; small scattered squares on the left settle into an orderly grid toward the right. An abstract, text-free composition.

A blog’s posts usually live in a database behind an admin panel. The author logs in, writes, saves, and whoever owns the panel effectively owns the posts. On this site the posts are plain text files in a git repository. The panel is only an interface for editing those files, so it can be dropped at any time in favour of a text editor. What follows walks through the parts of this setup in order. Every statement here can be checked against files in the site’s repository (package.json, astro.config.mjs, wrangler.jsonc, public/admin/config.yml, src/content/schema.ts).

A post is a file: Markdown, front matter and a schema

Each post is a .md file under src/content/posts/tr/ or src/content/posts/en/. The top of the file holds a YAML block (front matter) with fields such as title, date, category, language, status and sources; below it sits the text, written in Markdown. The Turkish and English versions share a filename. That simple rule also simplifies pairing: finding the translation needs no lookup table, just the same name in the other folder.

Astro’s content collections turn these files into a data source. According to the Astro docs, collections are defined in src/content.config.ts, the glob() loader takes a pattern and a base directory for local files, and fields are validated against a schema written with Zod; a file that does not match produces an error. This site works the same way: the posts collection reads the {tr,en}/*.md pattern and the schema lives in src/content/schema.ts. Rules such as title length, a description of 20 to 300 characters, a category from the defined ids, a date with a timezone offset, and at least one source are kept there.

In practice a broken post does not slip into production quietly. The npm run build command runs a separate content check (content:check) before the Astro build; it verifies the schema, filename rules, Turkish and English pairing, source count and heading structure. If anything fails, the build stops. The quality gate is not a person’s attention but a command’s exit code.

The panel: Sveltia CMS and the git history

To edit posts in a browser, Sveltia CMS runs at /admin. By the project’s own description, Sveltia is a git-based single-page application served from a CDN and built for static sites, positioned as a successor to Decap CMS (formerly Netlify CMS). On this site the configuration lives in public/admin/config.yml and handles the two languages with the multiple_folders structure. According to the Sveltia docs, in that structure each locale gets its own folder and paths follow the <folder>/<locale>/<file> pattern, which matches the repository’s posts/tr and posts/en layout exactly.

Every save in the panel goes to the repository as a commit through the GitHub backend. The docs list several ways to authenticate. One is signing in with a personal access token: the token is kept in the browser’s local storage, and a fine-grained token needs read and write access to contents. Another is an OAuth flow with a GitHub App and the Sveltia Authenticator, which runs on Cloudflare Workers. For a blog with a single editor, token sign-in is the lowest-maintenance option because it needs no extra server; OAuth is an upgrade that can be added if more people start writing. In local mode no authentication is needed at all, and the panel works directly on the folder on the computer.

The real gain here is ownership. Content sits in the repository, not in a service’s database. Each change can be read as a diff, reverted, or tried on a branch. If the panel disappeared or fell out of favour tomorrow, the posts would stay exactly as they are.

Claude drafts, the human edits and decides

The drafts of the posts on this site are prepared with Claude and edited by a person. Because the writing flow runs through files, the collaboration is plain: Claude writes a .md file under src/content/posts/tr/, then adds the English counterpart, and the change goes into git. There is no login to hand over and no write access to a database to grant. All that exists is a repository’s files, and everything can be reviewed as a diff, just like a human contribution.

The schema carries a lot of weight in this arrangement. Because a source list is mandatory, every post has to show the pages it rests on, and the content check will not let a post without sources through to the build. There is also a warning that tries to catch first-person experience phrasing. In other words, the limits of automation are written down as rules: a check cannot guarantee that the text is correct, but it filters out what is missing or malformed. Verifying accuracy is still the human’s job.

For transparency, every post opens with the line “This post was drafted with Claude.” That line can be switched off per post through the aiDisclosure field in the front matter; it is on by default.

Build and release: static files, search and Cloudflare

The build produces only static files: HTML, CSS, very little JavaScript and SVG covers. astro.config.mjs sets output: 'static'; URLs always end with a slash, and each page is generated as an index.html in its own folder.

The site is bilingual, but Astro’s built-in i18n routing is not used. Path segments change with the translation (for example /tr/yazilar/ on the Turkish side and /en/posts/ on the English side). A single route table therefore produces every URL, and the language toggle, the hreflang tags, the sitemap and each language’s RSS feed are all fed from that same table. That is also why the sitemap is a hand-written endpoint rather than a ready-made integration.

Search uses Pagefind. According to its docs, Pagefind runs after the static build finishes, scans the output folder and writes a search bundle with no server component of its own; it reads the lang attribute on each page’s root element, builds a separate index per language and adapts stemming to the language. On this site npm run build appends that step to the end of the build. The result is search with neither a running server nor a paid search service.

Hosting is on Cloudflare Workers. The Astro docs say a static site needs no adapter, only a wrangler.jsonc whose assets.directory is ./dist. This site’s file follows that and also sets a 404 page and two custom domains. According to Cloudflare’s pricing page, requests to static assets are free and unlimited (as of 2026-11-14), so the hosting cost of a site like this is practically zero. Deployment is one command: npm run deploy runs the production check, then the build, and finally wrangler deploy.

Scheduled publishing follows the same logic: a post dated in the future stays invisible until the build time reaches that date. With no server, a rebuild has to be triggered for it, so “scheduling” depends on the site being regenerated.

What does this cost?

The weaknesses of this arrangement are real and are not worth hiding. A git-based panel does not offer a database-backed panel’s dashboard, autosave and live preview with the same comfort. Scheduled publishing needs a rebuild. Sveltia’s own docs also note that sign-in with PKCE is not yet implemented, so practical authentication goes through a token or OAuth.

In return, three things are gained: near-zero operating burden, content that cannot be locked away and can be moved, and the ability to judge an AI draft and a human correction in the same form, as a readable diff. For a personal blog, those three outweigh the comfort of a panel.

Sources

  1. Astro docs: Content collectionsaccessed 14 November 2026
  2. Astro docs: Deploy to Cloudflareaccessed 14 November 2026
  3. Sveltia CMS docs: GitHub backend and authenticationaccessed 14 November 2026
  4. Sveltia CMS docs: i18n structuresaccessed 14 November 2026
  5. Sveltia CMS: project pageaccessed 14 November 2026
  6. Pagefind docs: Multilingual searchaccessed 14 November 2026
  7. Pagefind docs: Getting startedaccessed 14 November 2026
  8. Cloudflare docs: Workers pricingaccessed 14 November 2026

This post was drafted with Claude.