Write Markdown; crofty builds it with Hugo and deploys it to a website you own on your own domain and accounts. It never talks to a server of ours — there isn't one. Deploys go straight to your Cloudflare account over its API, with no Node or Wrangler in the loop.
crofty is a plain CLI you can run yourself, but it's built so your AI can run it
for you: a person double-clicks the installer, and an assistant takes it from
there — crofty init included. If you work that way, point your assistant at
crofty agent first — it
prints crofty's whole command surface (every command with its flags and
examples, the usual workflow, and the machine-readable state to read — config,
features, validate and doctor all take --json) in one shot, with no
project needed. From there it can drive everything below.
Download the installer and double-click it. That is the whole installation, and it is the only part meant for you rather than your assistant.
- macOS — crofty.pkg
- Windows — crofty-setup.exe
Both carry Hugo with them, so there is nothing to install
first: when the installer finishes, crofty build works.
Your OS will warn you the first time. That is expected — the installers are unsigned. Nothing you have to do here needs a terminal:
- macOS — the first open is refused: "crofty.pkg cannot be opened because it is from an unidentified developer." Open System Settings → Privacy & Security, scroll to Security, and next to the message about crofty.pkg press Open Anyway. The button only appears after the refusal, so let it happen first. Confirm once more, and the installer runs.
- Windows — SmartScreen says "Windows protected your PC". Press More info, then Run anyway.
On Windows, crofty is listed afterwards in Settings → Apps → Installed apps, so removing it is a click too.
Linux has no click installer. Take the archive below.
crofty is one file. The releases page carries it for every OS, and your browser is enough to get it:
- Download the archive that matches your machine —
crofty_<version>_windows_amd64.zip,crofty_<version>_linux_arm64.tar.gz, and so on. - Unpack it. Inside is a single
croftybinary. - Move it wherever you keep such programs. Putting that directory on your PATH saves you typing; it is not required, since a full path runs just as well.
Don't unpack it into a .crofty/ directory. That name belongs to crofty's own
per-site state, and crofty init writes there.
curl -fsSL https://crofty.site/install.sh | sh # macOS / Linux
irm https://github.com/ShiroDoromoto/crofty/releases/latest/download/install.ps1 | iex # WindowsThese are shortcuts for when they work. Both fetch through your system's TLS
stack, and on Windows that stack sometimes declines to supply a credential at
all (SEC_E_NO_CREDENTIALS) — the download dies before crofty is anywhere in
the picture. Nothing here can fix that machine; the archive above simply goes
through your browser instead, and arrives.
The script drops crofty in ~/.local/bin and touches nothing else. For a
system-wide install, name the prefix: curl -fsSL https://crofty.site/install.sh | sudo PREFIX=/usr/local sh.
Each release ships a crofty_<version>_checksums.txt if you want to verify what
you downloaded.
To uninstall, delete the binary — rm ~/.local/bin/crofty (or
/usr/local/bin/crofty). crofty keeps no state inside its own install
directory, and your sites are yours: they live where crofty init put them, and
nothing removes them but you.
crofty wraps Hugo at runtime for build and preview, and needs the
extended build (the theme's stylesheets are SCSS).
Only the click installers bring their own. They don't touch a hugo you already
have: the bundled copy sits next to crofty, off your PATH, and crofty runs it in
preference to whatever PATH happens to name.
Every other route expects a hugo on your PATH, and none of them installs one for
you — a distro's hugo is often outdated or not the extended build, and one that
fails the build is worse than none. Install
hugo-extended yourself; crofty build /
crofty preview will tell you if it's missing. To point crofty at a particular
one, set CROFTY_HUGO=/path/to/hugo.
On Windows you don't have to: crofty update replaces a crofty installed by
script with the same body the installer drops, Hugo included. That is the way in
on a Windows machine with an ARM chip, where installing one yourself is not an
option — Hugo publishes no extended build for that architecture.
Once crofty is installed, it updates itself:
crofty updateIt fetches the latest release and swaps the binary in place — no reinstall, no
admin, and no OS warning (a file crofty downloads itself carries no quarantine
flag). This works for the click installers (.pkg / .exe) and the per-user
install script. There is no automatic update: it only runs when you (or the AI
driving crofty) ask it to, and it points you at the release notes so the upgrade
stays your call. crofty still tells you when a release is out.
A system-wide install script (PREFIX=/usr/local) is root-owned, so crofty update sends you back to re-run the script with sudo instead. Either way,
crofty doctor shows whether an update will work from your install.
Those routes no longer receive updates. Leave, then come back by one of the routes above:
brew uninstall crofty && brew untap ShiroDoromoto/crofty # macOS
scoop uninstall crofty && scoop bucket rm crofty # Windows
sudo apt remove crofty # Debian/Ubuntu
sudo dnf remove crofty # Fedora/RHELThen install the .pkg / .exe, or run the install script. Nothing you wrote
is touched — crofty keeps no state inside its own install directory.
First, start a project (a website you own) — pick where it goes:
crofty init # asks for a name, then creates it under ~/Documents/Crofty/
crofty init <name> # a bare name lands in ~/Documents/Crofty/<name>
crofty init . # use the current folder (a path or absolute dir works too)Then build and publish it:
cd <the path it prints> # crofty init prints where it created the site
crofty preview # see it in a browser — no account needed
crofty connect # save your Cloudflare API token (to your keychain)
crofty deploy # build the current site and publish it to your own Cloudflare Pagescrofty init scaffolds a standard Hugo project plus a .crofty/ folder:
your-site/
├── hugo.yaml # standard Hugo config (baseURL, title, …)
├── .crofty/
│ └── config.json # crofty settings (deploy target) — never your content, no secrets
└── content/
├── _index.md # your home page, in Markdown
└── posts/
└── welcome/
└── index.md # a sample post to edit or delete
To change settings later, run crofty init inside the project (or point it
at one). It prompts for an optional support link; analytics and the site title
are settings you (or your AI) edit directly in hugo.yaml / data/profile.yml
— it shows where, and never rewrites them for you. The build output is a plain
Hugo project, so you can take it and run hugo yourself without this tool.
A runner has no terminal to type a secret into and no keychain to keep one, so crofty takes the credential from an environment variable its secret store injects — one name per credential, and only crofty's own names:
crofty build
CROFTY_CLOUDFLARE_API_TOKEN=$SECRET crofty deploy --skip-buildCROFTY_SFTP_PASSWORD, CROFTY_SFTP_KEY_PASSPHRASE and CROFTY_FTPS_PASSWORD
do the same for the other providers. There is no --token flag and nothing is
read from stdin: a secret must not land in your shell history, in ps, or in an
assistant's context. A credential from the environment is used for that run
alone — never written to the keychain, and .crofty/config.json is left as it
is. crofty prints which variable it came from.
Cloudflare also has to know the account. Deploy once from your own terminal so
deploy.accountId is pinned in .crofty/config.json (that file ships with your
site), or pass --account <id>. With no terminal crofty never guesses: it stops
and names what to set.
You don't have to learn that by deploying. crofty doctor says whether a run
with no terminal could publish from where it is standing — where the credential
would come from (which variable, or the keychain), and what is missing with the
fix for each, --json included. It looks at presence, never at a value: no
secret is printed and nothing goes to the network, so it can tell you a token is
there but not that it still works.
The sample project starts as a blog (content/posts/), but a crofty site is a
whole Hugo site — the homepage bits an author rarely escapes are pages too. Two
kinds, both drawn by the same frozen theme:
- Fixed pages you maintain — about, contact, access, legal — are a Markdown
file at
content/<slug>/index.md. - Collections that grow like the blog — a gallery, a shop, a discography —
are a section folder: an
_index.mdplus one folder per item.
Put any of them in the top navigation through hugo.yaml's menu.main (crofty
prints the lines to paste; it never rewrites hugo.yaml). Contact and commerce
stay external on a static site — embed a form (Formspree, Tally) or link out to
a checkout (Stripe, BOOTH). crofty agent prints these recipes in full: the two
page kinds, the menu snippet, and where the external pieces go.
crofty init # create a new project (or re-run to configure an existing one)
crofty agent # print the whole command surface for an AI to read first
crofty features # list what crofty can do and how to turn each on
crofty config # show this project's current configuration
crofty add # turn on a capability (mermaid, abc, highlight, raw-html, analytics)
crofty lang # add or list the languages your site is written in
crofty preview # see your site in a browser (local, no account)
crofty build # render the site to ./dist with Hugo (to inspect it)
crofty connect # save the Cloudflare API token used to deploy
crofty deploy # build the current site and publish it to Cloudflare Pages
crofty analytics # read your traffic (GA4) and search performance (Search Console)
crofty validate # check content against the crofty spec (v0)
crofty doctor # check the built site, and whether a deploy would get through
crofty share # print a ready-to-post fragment (text + link) for any SNS
crofty theme # bring the theme onto disk to customize (eject tokens or full)
crofty reset # remove saved credentials (keychain) and statecrofty validate [path ...] (default ./content) reports, in field order,
what does not match the spec and how to fix it — in plain language you can act
on by hand or hand to any assistant. It is side-effect-free; --json emits the
same findings as structured output for tools. It exits non-zero when any
blocking error is found.
crofty share <post> composes a ready-to-post fragment — the title, a summary,
and a link back to your site — for each channel in the post's crofty.targets
(or --to). The body is never included: the summary and link are all you give
away, so readers come to your site for the rest. It touches no credentials and
posts nothing — it prints the text (and, where a platform has one, a pre-filled
compose link) for you or your agent to paste or open. --json emits the same
fragments as structured output; --plain prints just the text and link.
crofty analytics reads your own traffic from the command line: GA4 (who
visited, what they read) and Search Console (search queries, pages, sitemaps),
as a plain table or --json for an assistant. It uses your own Google
service-account key, kept in your OS keychain, and talks to Google's APIs
directly — there is no server of ours in between. Set the property in
hugo.yaml (params.crofty.analytics); crofty analytics status walks you
through the one-time setup and tells you the next missing step.
A draft stays off your published site: add draft: true to a post's
frontmatter, or give it a future date to schedule it ahead. crofty build
lists any posts it leaves out, so nothing disappears silently.
crofty eject (convert to a plain Hugo project) is planned for a later
milestone.
The bundled theme is static and ships no JavaScript or trackers.
Your sites hold everything of yours. Apart from them, crofty keeps one small
state folder — a list of where your projects are, so it can find them from any
directory. It lives in your OS's config folder; set CROFTY_HOME to keep it
somewhere else, which is what to do if that folder is locked down. If crofty
cannot write it, your site is still complete; only the finding-it-from-anywhere
part is off. crofty config says where that folder is and whether crofty may
write there, so you never have to find out by running something that writes.
Requires Go 1.25+ (and Hugo to run it).
go build -o crofty .See LICENSE.