Skip to content

Latest commit

 

History

History
162 lines (107 loc) · 7.66 KB

SPEC.md

File metadata and controls

162 lines (107 loc) · 7.66 KB
spec meld
spec_version 2.0.0
date 2026-10-12
status public core protocol spec; reference implementation is server.py (partial conformance)

Meld: Core Spec

This is the core spec for meld: the protocol only. It is the source of truth for behavior. Any deployment of meld, self-hosted or otherwise, implements this protocol and does not change anything defined here.

1. Purpose

Meld is an ephemeral context bridge. Two parties exchange ordinary working context over one capability URL. No accounts, no logins, no shared infrastructure. The link is the authorization.

In scope: create, read, reply, expiry, uniform 404, MCP endpoint, OpenAPI spec, and self-hosting.

Out of scope: encryption, accounts, private rooms, owner tokens, email capture, AI in the loop, rate-limit status codes that leak existence.

Usage assumption

Each party keeps its own state. Meld assumes that the parties on either side of a bridge hold whatever they need to continue the work. If a bridge expires or drops, either party can create a new one, share the new link, and pick back up where they left off. This is an assumption about how meld is used, not something meld does. The bridge does not save, restore, link, or carry state between bridges, and a new bridge knows nothing about an old one.

2. Canonical spec

SPEC.md is the only source of truth for behavior. llms.txt, agents.md, skill.md, the MCP manifest, the agent card, and the OpenAPI document are generated from it or checked against it. Drift is a build failure.

Locked behavior:

  • Create returns a code and a URL. That URL is the capability. Create does not return a token.
  • Open window: 36 hours from creation until the first reply.
  • Idle window: the first reply sets 24 hours. Each later reply resets that 24 hours. There is no maximum lifetime once replies have started.
  • Reads do not move the clock.
  • Termination: the timer, or dissolve. Either side can dissolve the bridge at any time from its own end, with no permission from the other side. The URL is the only credential; there is no owner token. Dissolve deletes the bridge from memory at once, and the next request is the uniform 404. Silence still closes the bridge when the timer runs out.
  • Uniform not-found: expired, dissolved, unknown, and over-cap codes return the same status and the same body. An observer cannot tell them apart.
  • Host-readable while live. Whoever runs the server can read the plaintext on a live bridge. The host does not summarize, rewrite, or run a model on it.
  • Not for secrets, credentials, or regulated data. This is a constraint, not a feature to work around.
  • No accounts. No archive. No persistence: every deployment keeps bridges in memory only and writes nothing to disk. A restart of any deployment drops live links.

3. API

The base path is /api/melds. Behavior is what matters.

POST /api/melds

Body: one note. Accept note or context. If older clients also send for and not_for, all supplied strings must be identical; otherwise 400. Reject ttl, email, pin, and prev_code.

Returns: code, url, expires_at.

GET /api/melds/{code} and GET /m/{code}

While live: the note and every reply, plus timestamps. Does not start or reset the timer.

Link-preview crawlers on /m/{code} get an expires-only card. That card does not include the exchange and does not count as a read.

POST /api/melds/{code}/resolve

Body: context (the reply). Appends the reply. The first reply switches the window to 24 hours from now. Each later reply resets that 24 hours.

POST /api/melds/{code}/dissolve

No body. Either side, holding the URL, ends the bridge now. The note and every reply are deleted from memory immediately. Returns 204 when a live bridge was dissolved, and the uniform 404 otherwise. Afterward every request for the code is the uniform 404. No record of the dissolve is kept.

GET /health

Liveness only. No meld data.

Errors

  • Malformed body: 400, with a validation message. This is not an existence oracle.
  • Unknown, expired, dissolved, or over the reply cap: 404 and {"detail":"Meld not found"}. Same status, same body, every time.
  • A missing code never gets a different status, such as an "expired" status or a rate-limit status. Do not rate-limit in a way that changes the status code for a missing code.

Content limit: 100,000 characters per note and per reply.

Reply cap: 50 replies per meld. The next reply is 404, identical to a missing code.

Code entropy: at least 128 bits. Unguessable. No sequential ids.

4. Data model

melds

  • code — primary key
  • note — text, required
  • created_at
  • expires_at
  • reply_count — integer, default 0

replies

  • id
  • code
  • content
  • created_at

No owner token column. No email column.

Timestamps are UTC ISO 8601 everywhere in JSON. Do not mix datetime objects and strings in stored or returned fields.

5. Expiry

A sweep removes expired bridges from memory every 5 minutes, on every deployment. A deployment may also drop expired bridges on each request, but expiry must not depend on someone creating a new meld.

After deletion, the next request is the uniform 404. The server does not keep a record that the code existed.

No backup or time-travel window exists, because nothing is written to disk. trust.md says so in one sentence. Do not claim the data is deleted everywhere if a platform backup still holds it.

6. Surfaces that must match the spec

  • Web UI: one note, create link, show the 36/24 rule, "not for secrets."
  • MCP tools: meld_create, meld_resolve, meld_read, meld_dissolve. No ttl argument. No owner token.
  • OpenAPI: real request and response schemas, including the 404 body. Empty schemas are a defect.
  • Agent docs: two uses only — human writes a note and an agent replies on the link; or two agents talk on one URL.

7. Reference implementation

This repository is the reference implementation. A deployment that changes anything in this spec is a bug.

Self-host stays supported: Docker, Compose with Caddy, or plain Python. Every deployment is memory-only. Behavior of create, read, reply, dissolve, and 404 is the same everywhere.

8. Definition of done

  • Code matches SPEC.md.
  • OpenAPI validates against live responses.
  • No deployment writes bridge content to disk or to a database; a restart drops live links.
  • CI fails on spec drift, empty schemas, or timestamp inconsistency.
  • A client can be written from the OpenAPI document alone.

9. Non-goals

Do not add encryption, accounts, private rooms, owner tokens, email, or a model in the middle. The trust model is the product: a host-readable, timed, capability URL for ordinary disposable handoffs.

Appendix: machine-checked constants

check_spec.py parses this block and fails the build if the code, the generated documents, or the OpenAPI document disagree with it.

open_hours: 36
idle_hours: 24
max_chars: 100000
reply_cap: 50
min_code_bits: 128
sweep_minutes: 5
not_found_status: 404
not_found_body: {"detail":"Meld not found"}
create_fields: note, context
legacy_fields: for, not_for
rejected_fields: ttl, email, pin, prev_code
reply_field: context
mcp_tools: meld_create, meld_resolve, meld_read, meld_dissolve
routes: POST /api/melds, GET /api/melds/{code}, POST /api/melds/{code}/resolve, POST /api/melds/{code}/dissolve, GET /m/{code}, GET /health
melds_columns: code, note, created_at, expires_at, reply_count
replies_columns: id, code, content, created_at
spec_version: 2.0.0
timestamp_format: YYYY-MM-DDTHH:MM:SS.mmmZ
persistence: memory-only (every deployment)

Changelog

  • 2.0.0 (2026-10-09): Adds dissolve. Either side can end a bridge with POST /api/melds/{code}/dissolve; a dissolved code returns the uniform 404. Adds the meld_dissolve MCP tool.
  • 1.0.0 (2026-10-09): First draft. Bridges end only when the timer runs out.