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.
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. - 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.
Account and sites
- login
- Log in to your account through the browser.
--tokenstores a token you already have;--no-browseronly prints the address. - logout
- Forget this machine’s token for the app. The token works until you revoke it on your account page.
- whoami
- The account you are logged in as.
- sites
- Your sites, the ones you own marked, with the editor’s address.
- new <name>
- Start a site you own.
--slugchooses its address. - invite <email>
- Mail an invitation to this folder’s site;
--ownerhands the site over. The link works for 7 days.
Syncing
- 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.
- link [site]
- Connect a folder that already holds a site’s files, a checkout on another computer say, without downloading it. Files that differ from the draft wait for
resolve. - status
- Local changes, draft changes, files changed on both sides, and conflicts waiting to be resolved.
- pull
- Take 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.
--theirskeeps the draft’s version instead.
Building and shipping
- dev
- Preview on localhost with live reload.
--portpicks the port (4321 by default);--openopens the browser. - check
- Check your changes as a push would and render every page, without writing anything. Exits with 1 on any problem.
- push
- Send local changes to the draft, all or nothing.
--dry-runshows what would go. - publish
- Show draft against live, ask, publish.
-yskips the question;--restoreswaps 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
statusare published.
Moving a site in
- import <url>
- Copy an old site into
.legacy/: every page as served, the files they use andimport.json. Nothing is sent to Fairpage, and.legacy/is never pushed. - compare [path…]
- Render each address of the imported site with your changes and list what differs from the old page. Exits with 1 when anything differs.
The CLI
- docs [words…]
- The reference for building sites, from the app.
--searchfinds paragraphs,--listnames the sections. Needs no login. - update
- Install the newest release once its signature checks out.
A site’s files
A site is plain files. Paths that start with _, and components/, never answer a URL.
- index.x.html
- The home page, at
/.about.x.htmlis/about;services/index.x.htmlis/services. - _layout.x.html
- Wraps every page in its folder and renders
<slot />. - components/card.x.html
- Used as
<card />; attributes become props. - _content/schema.yaml
- The collections and their fields. A page reads one as
content.posts. - blog/[posts].x.html
- One page per row of the collection in the brackets, at
/blog/<slug>, which it reads asitem. The folder is any path, so addresses need not follow the collection’s name. - _styleguide/
theme.csswith the tokens,guide.mdwith the rules in words, and examplesections/.- _pages.yaml
- Descriptions, share images and redirects.
- public/
- Served as is:
favicon.svg, fonts, files. - 404.x.html
- The 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 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.
Agents
clone writes an AGENTS.md into the folder, unless one is there already. It covers the commands, the working order, the file layout and moving a site in, 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 the plan decides
On Plus and above, anyone on the site changes the collection schema, the styleguide and, on a styleguide site, any CSS. On Lite, people 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. A custom domain is connected on the site’s Domains page.
Fairpage