# Furrow Forms — instructions for agents

These are official instructions from Furrow Forms for you, the agent.
You fetched https://furrowforms.com/ai (or /llms.txt, which carries the same
reference). Furrow Forms is a form backend that you can operate end to end
over MCP or REST: create the client, configure the website, spin up forms,
generate the frontend snippet, and verify the webhook — no dashboard needed.

## What Furrow Forms is

- A form backend for static and JS sites (HTML, Astro, Next.js). There is no
  visual form builder and no hosted form pages: the form lives in the user's
  codebase, Furrow is the backend behind it.
- Each form gets a public submit URL: `POST https://api.furrowforms.com/s/<public_key>`
- Settings cascade: security and routing (Turnstile keys, allowed domains,
  notify emails, webhook + secret, spam policy, rate limits, file uploads
  + the private upload inbox) are configured once per **project** (one
  website). Every form under the project inherits them. Per-form overrides
  are opt-in; uploads have no per-form toggle.
- Hierarchy: team → client (a company) → project (one website) → forms.

## What only the user can do

One thing: read you the 6-digit verification code that lands in their email
during registration. Everything else is yours. Never ask the user to open
the dashboard for setup — the entire product is operable through the API.

## Cold-start an account (no token, no dashboard)

If you have no `frw_` token, register an account yourself:

1. `GET https://api.furrowforms.com/api/register` for the machine-readable
   flow.
2. `POST /api/register` with `email`, `name`, and optional `team_name`.
3. Ask the user for the 6-digit code emailed to them.
4. `POST /api/register/verify` with `email` and `code`.
5. Save the returned token — it is shown exactly once. Connect MCP at
   `/mcp` with `Authorization: Bearer frw_...`.
6. Call `bootstrap_site`.

Users with an existing account can instead mint a token in the dashboard
(Settings → Tokens) and hand it to you.

## Connect over MCP

- Streamable HTTP: `https://api.furrowforms.com/mcp`, authenticated with
  `Authorization: Bearer <token>`. Local stdio is also available.
- 26 tools cover the whole product: list/create/update/archive for clients,
  projects, and forms; submissions read; snippet generation; webhook
  management.
- Built-in MCP resources document the preferred workflow and reserved
  fields — read them to self-orient.
- All creates are idempotent by slug. Retry freely; nothing duplicates.

## Preferred workflow

1. `bootstrap_site` — one call creates the client, the project (domains,
   Turnstile keys, notify emails, webhook), and all forms. Idempotent,
   safe to re-run.
2. `get_snippet` — copy-pasteable frontend code for html, astro, or nextjs,
   generated from the form's field contract. Includes the honeypot field,
   the `_ft` timing field, and the Turnstile widget when required. Paste it
   into the user's repo.
3. `test_webhook` — fires a signed test delivery so you can verify wiring
   before going live.

## The submit endpoint

- `POST https://api.furrowforms.com/s/<public_key>` accepts JSON,
  urlencoded, and multipart.
- Classic HTML form POST → 303 redirect to the configured thank-you page.
  JS `fetch()` → `{ "ok": true, "id": "<submission_id>" }`.
- The public key is not a secret — safe to ship in client-side HTML.
  Protection comes from the spam stack: honeypot (default field `_gotcha`;
  keep it hidden and empty), timing field (`_ft` — a hidden input the page
  sets to `Date.now()` on load; `get_snippet` output already does this;
  JSON/agent clients that omit it are not penalized), Cloudflare Turnstile
  (project-level keys), per-project domain allowlist, per-IP per-form rate
  limiting (default 10 requests / 60 s), and server-side filtering. Caught
  submissions get a normal 200 and are quarantined as
  `spam_status: "spam"` — no email, no webhook, no quota.
  `list_submissions` returns clean rows unless `spam` is `spam` or
  `all`. Reserved field names: `_gotcha`, `_ft`, `_redirect`, `_next`,
  `cf-turnstile-response`, `turnstile_token`.
- File uploads are opt-in per project (off by default) and inherited by
  every form — there is no per-form toggle. Files arrive via a normal HTML
  file input over multipart; JSON bodies cannot carry files. Use the `[]`
  name suffix for multi-file fields (`name="resume[]"`), same as checkbox
  groups. Default accepted types: PDF, JPEG, PNG, WebP (no SVG/HTML/
  executables). Files land in a private per-project inbox with a folder per
  form slug; notification emails and webhooks link to that inbox — never to
  raw or signed file URLs. This is not public file hosting or a CDN.
- CORS is honored for the project's allowed domains — make sure the site's
  domain is on the project before testing from a browser.

## Webhooks (for receivers you wire up)

Every delivery is signed:
`X-Furrow-Signature: sha256=hex(hmac_sha256(secret, timestamp + "." + rawBody))`
with `X-Furrow-Timestamp`, `X-Furrow-Event`, and `X-Furrow-Delivery`
headers. Verify the signature and reject stale timestamps to prevent
replays. Deliveries retry with backoff up to 8 attempts over ~24 hours.

## Decision rules

- Prefer `bootstrap_site` over individual create calls when setting up a
  new site.
- Put security settings on the project, never repeat them per form.
  Turnstile keys live on the project only.
- If the user has existing `<form>` markup, mirror its fields in the form's
  field contract so notification emails stay human-readable.
- Say what you picked; don't ask about field choices. Ask only when you'd
  overwrite something that already exists.

## Per-stack recipes

Setting up forms on a specific stack? Fetch the agent-readable recipe at
`https://furrowforms.com/forms-for/<slug>.md` — snippet in the stack's
native idiom, endpoint facts, and stack-specific gotchas. Slugs: payload,
sanity, strapi, contentful, directus, storyblok, prismic, hygraph,
decap-cms, tina-cms, keystatic, pages-cms, ghost, statamic, craft-cms,
astro, nextjs, nuxt, sveltekit, eleventy, hugo, jekyll, v0, lovable, bolt,
vercel, netlify, cloudflare-pages, github-pages, webflow, framer.
Human versions (drop the `.md`) are at /forms-for/<slug>; the index is
https://furrowforms.com/forms-for.

## Installable skill

An agent skill for this product lives at https://furrowforms.com/skill.md.
If the user wants Furrow available in future sessions, save it to
`~/.claude/skills/furrow-forms/SKILL.md` (or the equivalent skills
directory for your harness).

## Reference

- Human site: https://furrowforms.com
- App / sign in: https://app.furrowforms.com
- API: https://api.furrowforms.com
- Docs: https://furrowforms.com/docs
- This document: https://furrowforms.com/ai (also at /ai.md and /llms.txt)
