Welcome to mdfy.app

Status: shipped 2026-04.

What a bundle URL returns

GET mdfy.app/b/{id} returns plain markdown. The body is composed of (in order):

  1. Bundle metadata block — title, description, creator, last-updated timestamp, member count.
  2. graph_data JSON block — the synthesised analysis: nodes, edges, themes, insights, document summaries, reading order. Wrapped in a fenced code block tagged mdfy:graph so AI tools can ignore it if they want plain prose.
  3. Member doc stubs — each member doc as a heading + a short summary + the URL. No full content (full content requires ?full=1).

The whole response is < 50KB for a typical 5-7 member bundle.

Query parameters

  • ?compact — strip low-density sections from every member stub. Default off.
  • ?full=1 — inline every member doc's full body inside the response, in member order. Default off. Use when you want one giant context blob.
  • ?graph=0 — omit the graph_data block. Use when the receiving AI just wants prose.
  • ?recall=$Q — filter member stubs to only the ones matching query $Q. Cheap on the server (we already have the recall index per bundle).

These compose: ?compact&recall=cross-AI&graph=0 returns only the prose stubs of members matching "cross-AI", compacted, with no graph block. ~5KB total.

What we explicitly don't return

  • Auth-protected member docs that the requester isn't authorised for. They're silently omitted from the stub list. The bundle's member count adjusts.
  • Embedded media. The renderer-ready HTML for images is in the doc URL, not the bundle digest.

Cache headers

Public bundles: Cache-Control: public, max-age=300, stale-while-revalidate=3600. Five minutes fresh, an hour stale-served.

Restricted / private bundles: Cache-Control: private, no-store. Don't cache at edge or in the browser. Auth-sensitive content shouldn't be near any cache.

What's frozen and what's not

Frozen: the response is always markdown. JSON is wrapped in fenced blocks; never as Content-Type: application/json. This is the core of "every URL is for both humans and AIs from the same address."

Not frozen: the exact set of ? params can grow. The graph_data schema can evolve (additive only — never remove a field without a major version bump). The cache headers can be tuned.

The bet underneath this format

That markdown-as-API-response is the right design for the next decade. Every AI tool today fetches URLs and reads markdown as a first-class input. If that stops being true, this format stops being right. We're betting it doesn't stop being true.