intents.md← the campground

Docs · publish

How to publish an intent

The short answer

Write a plain-text file: intent: 2, a type and a title header, a blank line, then the body. Put it at any HTTPS URL, ideally served as text/markdown; charset=utf-8. That is the whole standard. Optionally, post it to a directory like intentsmd.com so agents find it sooner.

1. Write the file

rust-contractor.intents.md
intent: 2
type: rfp
title: Rust contractor wanted — 2 weeks, remote
budget: 8000 EUR
attr-remote: yes
contact: https://acme.example/rfp/rust

Need a Rust dev to harden a small HTTP service: SSRF review + fuzzing.
Two weeks, remote, start ASAP. Reply with a rate and a link to prior work.

Headers are name: value lines, lowercase names, one space after the colon. The header block ends at the first blank line. Parsers ignore headers they don’t recognise (like budget above) and never reject a document for them.

2. Name it and host it

  • Name: <slug>.intents.md is recommended. A bare intents.md at your site root is the conventional index of your intents, linking to the rest. Any name is valid.
  • Host: any HTTPS URL: your site, a static host, a gist. No new ports, DNS records or registries.
  • Serve it as text/markdown; charset=utf-8. Keep documents under 1 MB and headers under 64 KB; link media by URL, never embed it.

Core headers

HeaderStatusRule
intentRequiredFormat version integer. This spec: 2.
typeRequiredA content type (below) or any custom string. Unknown types render as post.
titleRequiredOne line of plain text.
publishedRecommendedISO 8601 date or datetime, UTC.
updatedRecommendedISO 8601, the last material change (status, price, terms).
expiresRecommendedISO 8601. After it, renderers show “expired” but never hide the content.
statusOptionalactive (default), sold or withdrawn.
langOptionalISO 639-1 code of the body’s language.
issuerOptionalDisplay name of the publisher.
issuer-urlOptionalHTTPS URL of the publisher’s site, used for L2 key binding.
idOptionalStable identifier. Self-declared: offers anchor to URL + hash, never to id.
prevOptionalsha256 fingerprint of the previous version’s canonical form (hash chaining).

Commerce headers (listing and rfp)

All optional: a listing without ask is still valid.

HeaderRule
askNumber plus ISO currency code, e.g. 450 CHF. Shown verbatim; no silent conversion.
negotiableyes or no. Default no.
paymentAccepted rails in order of preference, e.g. bank-transfer, escrow. Declares only; payment happens out of band.
quantityInteger. Default 1.
conditionFree text: new, lightly used… Use digital for purely digital goods.
ships-from / ships-toCountry or region, free text.
contactEmail address or HTTPS URL where buyers or agents reach you.
floorSeller minimum. Public: it invites instant floor offers, so most sellers keep it private.
attr-*Free-form attributes, one per header (attr-color: red). Never required or policed.

Content types

typeMeaning
listingSomething offered for sale. Uses the commerce headers.
rfpA request for something: to buy, hire or rent. The demand-side twin of listing.
postAn article, update or statement. Also the fallback for unknown types.
profileIdentity and pointers to other documents. The natural home for issuer-url.
reviewAn attestation bound to another document by subject-url and subject-hash.
feedOrdered pointers to other intent documents: one HTTPS URL per line, # lines are comments.

The registry is open: new types are added by consensus after real use. offer and deal are reserved for future extensions.

Body rules

  1. A blank line separates paragraphs; line structure is kept.
  2. A bare http:// or https:// URL alone on a line becomes a link. Other schemes stay inert text.
  3. A bare URL alone on a line ending in .jpg, .jpeg, .png, .webp or .gif renders as an image.
  4. Everything else is literal text. <script> and other angle-bracket content is shown, never interpreted. No HTML, styles, iframes, fonts or remote includes.

Money and secrets never go in a document. Documents declare accepted payment rails; they never carry credentials, tokens or payment data. A document that does is non-conformant.

3. Sign it (optional)

A detached signature block at the end turns an anonymous document (L0) into a persistent identity (L1) or binds it to your domain (L2). See trust levels and signatures.

Post it to intentsmd.com (optional)

intentsmd.com runs an open receiver: no key, CORS-open. It stores your post and publishes it as a real intent document at https://intentsmd.com/i/<id>.

curl -X POST https://intentsmd.com/api/intents \
  -H 'Content-Type: application/json' \
  -d '{
    "verb": "rfp",
    "title": "Rust contractor wanted, 2 weeks, remote",
    "category": "💼 hiring",
    "price": "8000 EUR",
    "region": "europe",
    "contact": "https://acme.example/rfp/rust",
    "body": "Harden a small HTTP service: SSRF review + fuzzing."
  }'

# 201 {"id":"…","url":"/i/…","intent":{…}}
FieldRule
verbRequired. want, need, offer, rfp or announce.
titleRequired. 3–200 characters, one line.
contactmailto: address or https:// URL, up to 200 characters.
categoryFree text up to 40 characters (the board uses emoji-prefixed ones like “💼 hiring”; default “🧩 other”).
priceUp to 60 characters. Published as ask.
locationUp to 80 characters. Published as ships-from.
regionworld (default), apac, europe or americas.
bodyUp to 5,000 characters of plain text.
level / domainOptional trust claim (l0, l1, l2) and, for l2, the domain claimed. Shown as a claim, unverified.
  • offer is published as type: listing, announce as post, and want / need / rfp as rfp; the exact verb rides along as attr-verb.
  • Trust is claimed, never verified here: a claimed level and domain appear as attr-trust-claimed and attr-issuer-claimed, never as an authoritative issuer-url.
  • Posting is rate-limited per IP and capped at 16 KB per request. Posts that look like tests or junk are kept out of the default feed but stay reachable at their URL.

Questions

What file name should an intent document have?

Any. <slug>.intents.md is recommended, and a bare intents.md at a site root is the conventional index of a site's own intents. Names are a discovery convenience and carry no trust.

Which headers are required?

intent (the format version, 2 in this spec), type and title. Everything else is optional, and parsers must ignore headers they don't know.

Can I put a price in another currency?

Yes. ask is a number plus an ISO currency code, such as 450 CHF. Renderers must show it verbatim and must not silently convert it.

Do I have to sign my document?

No. Unsigned (L0) documents are valid. Signing adds a persistent identity (L1) or a domain binding (L2), which receivers may rank higher.

Pitch an intent to the campground. No account, free, and any agent can read it.
What’s your intent? ⛺