Install
fairpage-cli is one binary, fairpage, for macOS and Linux on Intel and ARM, and for Windows on Intel. There is nothing else to install: no Node, no build step.
# macOS and Linux
curl -fsSL https://fairpage.co/install.sh | sh
# Windows, in PowerShell
powershell -c "irm https://fairpage.co/install.ps1 | iex"
- The script checks the download against its published checksum and puts
fairpagein/usr/local/binwhen it can write there, else~/.local/bin; on Windows, in%LOCALAPPDATA%\Programs\fairpage.FAIRPAGE_PREFIXpicks another folder. fairpage updateinstalls a newer release once its signature checks out, andfairpage devsays once a day when there is one.FAIRPAGE_VERSION=v0.1.0with the script installs a given version.
Log in
You log in once per computer, to your Fairpage account. login shows a code and opens the approval page in your browser. Log in there if you have to, check that the code matches your terminal and choose Approve.
fairpage login
# Open https://fairpage.co/cli/approve and check the code: BCDF-GHJK
- The login reaches every site you are a member of, with your role on each.
fairpage siteslists them;clonewithout a name offers them, and takes the only one when you have one.fairpage new "Nord Bakery"starts a site you own, as “New site” on your sites page does. fairpage invite <email>, in a site’s folder, mails an invitation to it.--role designerfor someone who builds,--ownerto hand the site to the client.- Codes last ten minutes.
--urllogs in to another Fairpage, such as--url=localhost:3000for one on your machine. - Tokens are stored in
~/.config/fairpage/credentials.json, readable only by you.FAIRPAGE_TOKENoverrides it, for CI. fairpage logoutforgets the token on this machine. To cut it off everywhere, revoke it on your account page.
Day to day
You and the owner edit one shared draft. The live site changes only when someone publishes.
- Pull before you start.
fairpage pullbrings in what the owner changed in the editor. - Work locally.
fairpage devserves the site onlocalhost:4321, rendered by Fairpage with your unpushed files laid over the draft. The page reloads when you save, and styleguide problems show as warnings. - Push when a piece of work is done. A push is all or nothing, and it becomes one step in the site’s history, so the owner can undo it like their own changes.
- Publish when it’s ready.
fairpage publishlists what differs from the live site and asks before it goes.--restoreputs the previous version back.
Commands
Every command takes --json for scripts.
loginLog in to your account through the browser. --token stores a token you already have; --no-browser only prints the address.
logoutForget this machine’s token for the app. The token works until you revoke it on your account page.
whoamiThe account you are logged in as.
sitesYour sites, with your role on each and the editor’s address.
new <name>Start a site you own and build as its designer. --slug chooses its address.
clone [site] [folder]Download a site’s draft into a new folder, named after the site by default. Without a site, your only one, or one you pick from a list.
invite <email>Mail an invitation to this folder’s site. --role is editor or designer; --owner hands the site over.
statusLocal changes, draft changes, files changed on both sides, and conflicts waiting to be resolved.
pullTake the draft’s changes. A file changed on both sides is kept aside in .fairpage/theirs/ and the command exits with 2.
resolve [path…]Settle conflicts, keeping your file. --theirs keeps the draft’s version instead.
checkCheck your changes as a push would and render every page, without writing anything. Exits with 1 on any problem.
pushSend local changes to the draft, all or nothing. --dry-run shows what would go.
publishShow draft against live, ask, publish. -y skips the question; --restore swaps the previous publish back.
rows push <collection> <file>Import rows into a collection from JSON or CSV, up to 5,000 at a time. Rows without a status are published.
devPreview on localhost with live reload. --port picks the port (4321 by default); --open opens the browser.
docs [words…]The reference for building sites, from the app. --search finds paragraphs, --list names the sections. Needs no login.
A site’s files
A site is plain files. Paths that start with _, and components/, never answer a URL.
index.x.htmlThe home page, at /. about.x.html is /about; services/index.x.html is /services._layout.x.htmlWraps every page in its folder and renders <slot />.components/card.x.htmlUsed as <card />; attributes become props._content/schema.yamlThe collections and their fields. A page reads one as content.posts.blog/[posts].x.htmlOne page per row of the collection in the brackets, at /blog/<slug>, which it reads as item. The folder is any path, so addresses need not follow the collection's name._styleguide/theme.css with the tokens, guide.md with the rules in words, and example sections/._pages.yamlDescriptions, share images and redirects.public/Served as is: favicon.svg, fonts, files.404.x.htmlThe not-found page.Markup and styles
Pages are HTML with expressions in braces and control flow as attributes. There is no <script> in a site’s pages.
<title>Journal</title>
<h1 class="text-4xl font-display text-ink">Journal</h1>
<article @each={content.posts as post} class="py-8 border-b border-line">
<a href={"/posts/" + post.slug}>{post.title}</a>
<p @if={post.summary}>{post.summary}</p>
</article>
Classes are Tailwind 4 utilities over the site’s own tokens, compiled by Fairpage. There is no default palette and no arbitrary values: p-[13px] and inline style properties are refused, which is what keeps the owner’s edits and the AI’s on brand. dev shows a refused class as a warning; push and publish stop on it.
With Claude Code
clone writes an AGENTS.md into the folder, unless one is there already. It covers the commands, the workflow, the file layout and how a site differs from the markup reference, so an agent can build and push without a briefing. For the rest, fairpage docs markup, docs utilities or docs --search <term> prints the reference from the server, current with it. Neither AGENTS.md nor CLAUDE.md is synced to the site.
cd acme
claude "Add a Journal: a posts collection, a list page and a page per post, in the styleguide's type scale."
Drafts, conflicts, limits
Conflicts
If the draft changed under you, a push is refused with the files in question: pull, resolve, push again. Nothing pushes while conflicts are waiting.
What only a designer or developer can change
The collection schema, the styleguide and, on a styleguide site, any CSS; Lua files only a developer. Editors change content, pages and sections within them. A schema change can add fields; to retire one mark it removed: true, to rename use was:. The content is migrated on push.
Publishing
Publish is refused while any page in the draft has errors, or when there is no index.x.html. Local changes you haven’t pushed are not published.
Limits
Coming later
domain, to connect a custom domain.
Until then, connect one on the site’s Domains page.