Decision: Inline graph_data in bundle URLs

Companion to the public spec version at /spec. This is the engineering-side version with the receipts.

What we do

Every bundle URL (e.g. mdfy.app/b/wpwVCSDF) returns markdown with the bundle's graph_data JSON inlined as a fenced code block at the top of the response. The receiving AI fetches the URL once and inherits themes, insights, document summaries, and the concept graph in a single round trip.

The alternative we rejected

Lazy / on-demand: ship the URL with just the doc list, let the caller pull /api/bundles/{id}/graph separately if they want analysis.

That's simpler. We chose against it because:

  1. AI agents don't make a second call by default. Claude Code, Cursor, Codex all fetch a URL once and consume what they get. If the analysis isn't in the response, they don't see it.
  2. The graph is small. Median ~3KB per bundle. We measured. Pasting a 3KB JSON block into a 100KB doc response is a 3% size hit and a 0% latency hit.
  3. The graph is the differentiator. Without it, mdfy bundles look like "a list of markdown files concatenated." With it, they look like "synthesised intelligence." We want every AI on the planet to see the second.

The query knobs

We added two ? params so callers can dial cost:

  • ?graph=0 — omit the graph_data block (recall scenarios where the model just wants the prose)
  • ?full=1 — inline every member doc inside the response (max-context scenarios)

Default is graph_data inlined, member docs as URL stubs.

What this commits us to

Bundle analysis has to stay current. The "stale" badge on the analysed pill in the UI is the user-visible commitment to keep it that way. Auto-analyse on member-doc changes is Pro-only; free tier sees the badge and clicks "Re-analyse" manually.