# FABREMENT — WHAT IT DOES, AND HOW TO CONNECT YOUR AGENT

This file ships with the plugin. Someone has handed it to an AI assistant, or is reading it
themselves. It answers two things: **what you can build with Fabrement**, and **how to connect an AI
agent to the site**.

It stops there on purpose. Once an agent is connected it can read the documentation itself — every
operation names the contract that governs it, and `get-skill-doc` returns it in full. A contract's
WHAT TO FETCH section lists the other documents to read. No agent needs a parameter list here;
it would be out of date by the next release.

Plugin version 1.4.0.

---

## What Fabrement is

It builds a WordPress site from a description. You say what you need; you get **native Gutenberg
blocks** — real PHP, CSS and JS files that WordPress renders itself. No page-builder runtime, no
shortcode layer, and the code is yours to read.

One thing to know before starting: those blocks render **through the plugin**. Deactivate or delete
it and their output breaks.

---

## What you can build with it

**Sections, from words.** Hero, cards, team, pricing, slider, gallery, modal, video, sections with
forms — described in a sentence, or copied from a screenshot, or pulled from a Figma frame. A Figma
node comes back as real CSS with flex and grid rather than absolutely-positioned boxes; a frame too
large to read at once comes back section by section.

**Blocks you already made.** Blocks live in your Fabrement project as well as on the site. The
agent sees the project's blocks this site does not have yet and installs them instead of building
the same section again — on a rebuilt site, or a second site on the same project.

**A header and footer, and a frame around the site.** Assembled into a template and applied to the
pages you pick, to a whole post type, or to archive pages. Different sections of a site can wear
different frames, and it is changed in one place rather than page by page.

**Pages and posts**, assembled from those blocks. New ones start as drafts; the agent publishes,
unpublishes, moves to the trash and restores them, and deletes one for good only when asked. Pages
nest — a parent and an order — and listings give each one's parent and order. Categories and tags, the front page,
the blog page and the site settings too.

**Your own kinds of content.** Projects, case studies, recipes, events — each with its own URL, its
own archive, its own filters and categories. And not just the data: the **listing page itself** is
authored, so "projects as cards, filtered by industry, paged" is built rather than approximated.

**Fields on posts, pages and your own post types.** An event's date and venue, a project's client and gallery, a team
member's role and links. Field types: text, textarea, formatted text, number, true/false, select,
date and date-time, image, gallery, file, link, icon, a picked record (one or several), group and
repeater. A field that can be empty can be required; fields are grouped into tabs and set side by
side (from a quarter to the full row).

- **The agent designs them.** There is no screen for creating fields: the agent defines the fields
  of a post type or an options page and saves them as a file under `wp-content/fabrement/fields/`. Every save is
  checked and a mistake is refused with the input to fix. A field keeps its type for good; a field
  that is left out is retired, not deleted — hidden from the editor, its values kept, and sending
  it again brings it back.
- **Editors fill them** in a **Fabrement fields** box on the edit screen, with the tabs and layout
  the agent set up — or the agent reads and fills them itself. Only the fields that changed
  are written.
- **Stored the WordPress way.** Values are ordinary post meta (`fab_<name>`, laid out the way ACF
  lays out its values), so WordPress meta queries work on them; Yoast titles and descriptions use
  them as `%%fab_<name>%%`, and schema.org markup as `{{field:<name>}}`. The values stay in the
  database if the plugin goes.
- **Read by the site's code.** Templates and blocks read them with `fabrement_get_field()`,
  `fabrement_get_fields()` and `fabrement_get_choice_label()` for a select's label.
- **Existing fields are seen, not replaced.** The agent lists what a post type already declares —
  its ACF field groups and registered meta keys as well as Fabrement fields — and builds templates
  on them.

**Site-wide settings.** A phone number, an address, opening hours, social links, an announcement
bar — kept on options pages under **Fabrement → Site General Settings**, one tab per page, with the
same field types. Values live in the WordPress options table, are read with `fabrement_get_option()`,
and every header, footer and block that shows them updates at once. A block lists the site options
it uses.

**One visual language for the whole site.** Colour roles, typography that changes per screen size,
button styles painted in those colour roles, optional display and accent faces with extra weights.
A Google font can be installed on the site from the Design System screen, so visitors no longer
fetch it from Google. The design can be edited and saved without a Fabrement account. Blocks consume these rather than hard-coded colours, so changing
the brand colour changes the site instead of twenty separate files. Plus a global stylesheet for what belongs to no
single block, and a global script for site-wide behaviour on the front end.

**A "page not found" (404) page.** An ordinary page, built from blocks and translatable, shown
for every address that does not exist — with a real 404 status, kept out of search results and
sitemaps. It can wear its own frame (a template set as the default for "404") and a custom PHP
body that shows, for example, the address that was asked for and the latest posts. Built only when
you ask for one.

**Small changes stay small.** An existing block, page body, listing layout or the global
stylesheet/script is changed by fragment — "replace this line" — instead of being rewritten
whole, which is faster, cheaper and cannot silently drop the rest of the file. A file of a block or
layout is only ever deleted when that is asked for explicitly.

**The things blocks point at.** The media library, a shared icon library, navigation menus, real
contact forms (Contact Form 7 fully; WPForms can be placed and styled). A block never builds a fake
form and never owns an image — it references the real one, and an editor picks the form or swaps
the icon in the block's settings.

**Findability.** SEO titles and descriptions, defaults for a whole site, schema.org markup added
to Yoast's graph and filled from field values, SEO for post-type archives (Yoast presents them like the blog page), and a list
of what still lacks a description.

**Several languages, with WPML.** When WPML is active with two or more languages, the same site is carried into every
language rather than rebuilt per language:

- **Pages and posts** get a version per language: the original is copied with its blocks, image,
  template, SEO settings and categories, linked as the translation, then its text — and its SEO
  title and description — is translated. One
  page in three languages stays one page.
- **Block text reaches WPML's translation editor.** Each block declares which of its fields are
  words — headings, descriptions, button labels, formatted text, repeater rows — so a translator
  sees them. Phone numbers, emails, brand names and links stay out and stay identical everywhere.
- **Headers and footers** render in the visitor's language; their wording is translated once for
  the whole site.
- **Post types, categories and terms** get their own names and URL bases per language. Each type
  can also be left untranslated — one shared set for every language, for things like price lists
  or partner logos.
- **Fields** follow a rule per field: translated (text only), copied from the original and
  kept in step (a price, a date), copied once and then edited apart, or left for each language to fill. A translation started with WPML's
  "+" link starts from its original's values. Options pages have a version per language too.
- **Fixed words in site code** — a "Back to home" or "Next" written into a layout — are found in
  the code, registered with WPML String Translation and translated from the chat.
- **The 404 page** has a version per language like any other page.
- **Media** is one image with a copy per language: listed once, with each copy's alt text, and one
  language's copy can be removed without touching the original.
- **A language switcher** can list every language, or only those a page really exists in.
- **SEO** titles and descriptions per language, a list of what is still untranslated or missing
  across pages, archives and terms, and a check that the home page exists in each.
- **Pages WPML's own editor manages** are not overwritten from the chat; the agent points you to
  that screen instead.

The agent sees none of this on a single-language site — the language tools and their
documentation appear only when WPML runs with at least two languages.

**Reading before writing.** Everything above can be listed and inspected before anything changes,
and a page, template or block can be opened on a preview link before anything is published — a
draft at its real address, a block shown on a real record. A preview link lives for an hour (two for a template or
block) and never shows a private, password-protected or trashed record.

### What it does not do

- **Commerce** — no WooCommerce, no cart, no payments.
- **Translation plugins other than WPML** — Polylang, TranslatePress and the like are not supported.
- **Role-scoped agents** — there is no "marketing may edit text only" mode. An agent gets the whole
  surface or none of it.
- **Life without the plugin** — the blocks need it to render. Posts, pages, media and field
  values stay in WordPress.
- **Writing code on a locked site** — with `DISALLOW_FILE_EDIT` or `DISALLOW_FILE_MODS` set, block
  code, page and archive layout code and the global CSS/JS cannot be written, deleted, installed
  from the project or rolled back; existing blocks
  render, and content, fields, templates, the design system and settings keep working.

---

## What it costs

**The plugin is free.** Download it, install it, use it. There is no licence key and no paid tier of the
plugin itself.

Signing the site in to Fabrement is free as well, and a new account starts with a small credit so the chat
inside wp-admin can be used before any key is added. Once that credit is spent, the wp-admin chat runs on
the user own API key for Gemini, Anthropic or OpenAI, and those providers bill directly. Fabrement does
not resell tokens.

Connecting an external agent over MCP costs nothing on our side: it runs in whatever AI client the user
already has.

Anything beyond that, including future plans or limits, is not described here. Say so rather than guessing.

---

## Setting the site up

Three steps, and the middle one is the one people skip.

**1. Install and activate.** WordPress 6.9+, PHP 8.0+. Upload the plugin ZIP the usual way. A
**Fabrement** menu appears in the sidebar.

**2. Sign the site in to Fabrement.** Open **Fabrement** in wp-admin and sign the site in. Do it
now. Block code is checked and stored by the Fabrement service, and the guides an agent works from
(`get-skill-doc`) come from it too, so this site-level account is needed before an agent can read
its rules or create, change, import, read the code of, or roll back blocks. Pages, posts, post types, fields, menus, media, SEO, icons, global
CSS/JS and site settings work without it; the design system can be edited and saved on the site,
but creating one in your account needs the sign-in.

Skip it and an agent's first doc read or block save comes back saying the site is not signed in to
the Fabrement service. That is this step, not a permissions problem.

**3. Optional, depending on what you want.** The chat inside wp-admin — **My Blocks → New Block** —
starts on the account's credit; after that it needs your own API key for Gemini, Anthropic or
OpenAI (**Fabrement → API Connection**, last in the menu). Figma input needs a Figma token
(**API Connection → Figma**). SEO and structured data need Yoast SEO, which the agent can install.

---

## Connecting an AI agent

### ChatGPT, Codex and Claude: OAuth (experimental)

In **Fabrement → MCP Connection**, pick a client: **Claude**, **ChatGPT**, **Cursor** or **Codex**.
Claude and Codex have two tabs, **Recommended** (OAuth) and **Advanced**; ChatGPT has only the
OAuth setup, Cursor only an access key (below). If OAuth is off, the client's **Connect** button
turns it on; the same switch is in the **Connection access** card.

- **Claude (claude.ai)** — **Connect to Claude (1-click)** opens Claude's "add custom connector"
  form with this site's name and URL already filled in.
- **ChatGPT** — **Open ChatGPT Plugins**, then **Create app** → **Create MCP App**, and paste the
  displayed server name and MCP server URL into the New Plugin dialog (turn on Developer mode first
  if Create app is missing).
- **Codex** — add the displayed URL in the Codex app's form (Add MCP server), then **Authenticate**.
  The commands and `config.toml` entry are on the **Advanced** tab.
- **Claude Code** — the command is on Claude's **Advanced** tab, under **Claude Code (OAuth)**.

Then sign in to WordPress as an administrator and approve the request. ChatGPT and Codex are
separate clients: connecting one does not connect the other. OAuth needs no application password
or static Authorization header.

Authorization and tokens stay in this WordPress installation, not in the Fabrement backend. Access
is the full Fabrement agent surface, not read-only. A connection stays until you **Disconnect** it
in the **Connection access** card, turn OAuth off, lose administrator rights, or the site's address
changes. Access tokens expire after one hour; clients renew them with rotating refresh tokens
without asking you to reconnect. Turning OAuth off revokes its connections without touching
application passwords.

OAuth needs **HTTPS**, a successful database setup and a compatible MCP Adapter. An explicitly
saved Off is preserved across updates and reactivation. ChatGPT and claude.ai additionally need a
public site address. Local Codex/Claude Code can reach a local HTTPS site with a trusted
certificate; their local HTTP callback is allowed, but does not remove the site's HTTPS
requirement. Existing application-password connections are untouched; the generated OAuth entry
uses `fabrement-<site-name>`, without a hash. The hostname is used if the title cannot form a
usable ASCII name. The separate site sign-in to Fabrement is still required for block
storage/validation.

Database setup runs on activation or after an update that changes the database version. WordPress
Multisite is not supported. Actual ChatGPT/claude.ai login must be tested on a public HTTPS site;
local automated tests do not prove provider compatibility.

### Application passwords: prerequisites

- **An administrator account.** The agent interface is built on the Abilities API of WordPress 6.9,
  which the plugin already requires.
- **Application passwords available**, which in practice means **HTTPS**. WordPress makes an
  exception for local development environments.

### Generating the connection

wp-admin → **Fabrement → MCP Connection**:

- **Claude / Codex** — **Advanced** tab → **Application password** → **Generate application
  password**.
- **Cursor** (application password is its only method) — **Create access key**, then **Add to
  Cursor**.

It creates a WordPress application password and builds it into the setup:

| Client | What you get |
|---|---|
| **Claude** | a Claude Code `claude mcp add …` command, or a `.mcp.json` entry |
| **Codex** | a `codex mcp add …` command (PowerShell or bash), the URL and header for the Codex app's form — fill in the Authorization header there and leave the Bearer token environment variable empty — or a `~/.codex/config.toml` entry |
| **Cursor** | a one-click install link that opens Cursor, or a `~/.cursor/mcp.json` entry |

Each also has a **Let Claude/Codex/Cursor set it up** section with a copyable setup prompt (for Cursor, inside
"If Cursor does not open, add the server by hand"). It contains the private credential: share it
only with your trusted AI client, never publish it or commit it to a repository.

New application-password setups use `fabrement-<site-name>`, matching the OAuth
name. Existing client entries are not renamed automatically. Check the name before
adding: another site with the same title, or an existing OAuth connection, needs a
different name unless you intend to replace it. Codex's token environment variable
is specific to the site URL, including when two sites have the same title.
Windows commands use **PowerShell**, with double-quoted values. Start Codex from
that same terminal; already running apps do not inherit new environment values.
The Linux/macOS export lasts only for the current bash/zsh session. For persistent
setup without environment-variable inheritance, use the private configuration file.

Then:

1. **Copy it immediately** — it is shown once, on the page that opens after generating. The
   password inside keeps working until you revoke it.
2. Run the command, open the link, or paste the entry — whichever form you picked.
3. **Start a new chat.** An AI client loads its tool list when a conversation begins, so an
   already-open conversation will show nothing no matter how correct the setup is.

Revoking is the **Disconnect** button next to it in the **Connection access** card on the same
screen. The list shows only your own connections: OAuth grants and the application passwords
Fabrement issued (named "Fabrement MCP (…)").

### Any other MCP client

Nothing in the connection is specific to one client. It is a standard **HTTP MCP server** with two
facts, both included in any application-password setup above:

| | |
|---|---|
| URL | `https://your-site.com/wp-json/fabrement/v1/mcp` |
| Header | `Authorization: Basic <base64 of login:password>` |

Any MCP client that speaks HTTP transport and lets you set a request header can connect: point it at
the URL, add the header. Clients that only accept a Bearer token work too — the same base64 value is
accepted as `Authorization: Bearer <base64 of login:password>`. In a JSON-configured client it
usually looks like:

```json
{
  "mcpServers": {
    "fabrement-your-site": {
      "type": "http",
      "url": "https://your-site.com/wp-json/fabrement/v1/mcp",
      "headers": { "Authorization": "Basic <base64 of login:password>" }
    }
  }
}
```

If a client that has no button here behaves oddly, name it when reporting the problem.

### When it does not work

| What you see | What it is |
|---|---|
| The button gives an error about application passwords | no HTTPS, or application passwords disabled on the site |
| Connected, but the assistant sees no tools | the conversation started before you connected — open a new one |
| 401 / "incorrect password" | the setup was truncated when copied, or the password was revoked |
| A doc read or block save says the site is not signed in | step 2 above was skipped |

---

## Once connected

The assistant takes it from here. The rules for every area live in documents it can fetch itself
(`get-skill-doc` returns one by id, once the site is signed in), and every operation points at the document that governs it.
Contracts list required and optional documents in WHAT TO FETCH. A well-behaved agent reads the
contract and its required documents for an area before its first call there,
looks at the existing site before creating anything, and opens a preview to check its own work
before saying it is done.

You can simply ask for what you want: "a case studies section with a filterable listing", "make the
header sticky and dark", "this page needs an FAQ block matching our style".

### Two things worth telling the assistant

**"Without writing code" is not "no code".** Code is produced. You can read it, and so can any
developer you hire later.

**A 200 is not a verified page.** Ask it to open the preview and look, not just to report success.
