ARTIFOUNDRY

Documentation

Artifoundry is an artifact platform built agent-first: pages are versioned entities behind an API, readers annotate what they see, agents forge revisions, and humans hold the promotion gate. These docs cover the concepts, the workflows, and the full API surface.

Artifacts & versions

An artifact is a named, self-contained HTML page inside a project namespace — identified by its slug. Its content lives entirely in versions: append-only, immutable rows numbered seq 1, 2, 3… Publishing never mutates anything; it appends the next version.

  • Each artifact has a live pointer naming the one version served by default. Promotion moves the pointer; the previous live version becomes superseded.
  • A version's status is pending (created, awaiting review), live, or superseded. Every version stays addressable forever via ?v=<seq>.
  • Versions record an author_kindsession (an authoring agent under human direction), runner (the autonomous annotation loop), or human — plus a one-line note saying why the version exists.
  • Versions may carry assets (images, data files), content-addressed so unchanged files cost nothing across versions; a version that omits assets inherits its predecessor's.

Rows are never mutated. Promotion — the admin-only gate — moves the live pointer forward; the version it leaves behind becomes superseded but stays addressable at ?v=N forever.

Annotations

An annotation is reader feedback anchored to a text selection — quote plus surrounding context (a TextQuoteSelector-style anchor) and the nearest section heading — with a comment and an optional name.

Crucially, every annotation pins the exact version it was made on. The highlight stays valid against that version forever, the agent knows precisely what text the reader saw, and anchor drift — the classic failure of annotation systems — is structurally impossible. Annotations move through pendingprocessed (with a response shown back to the reader) or dismissed (with a reason).

Projects & tokens

A project is a namespace (one team, product, or repo) with two credentials of very different weight:

  • The project token — an unguessable path segment doubling as the reader credential. It grants: reading every page and version, creating annotations, and creating pending versions. It is exactly as powerful as possessing a page URL, no more.
  • The admin token — a server-configured bearer that authorizes moving the live pointer (?promote=live, /promote) and writing project assets. Promotion fails closed if it is unset — and it never enters the runner's environment, so a fully hijacked agent still cannot publish to readers.

Served chrome

Authors write plain, self-contained HTML linking the project's shared artifact.css. At serve time the platform injects the chrome: an artifact switcher, a version picker (visibly amber when you are viewing anything non-live), and the annotator. Pages carry a window.__schmiede context object naming the project, slug, and the exact version on screen — which is how annotations pin correctly even on historical views.

Doorbell & runner

New annotations ring a doorbell — a debounced wake-up carrying no payload (a burst of comments rings once per quiet window). The runner wakes, pulls the pending queue itself, and invokes a headless agent with the annotations framed explicitly as quoted reader data, never instructions. It publishes its edits as pending versions and answers every annotation. A daily sweep re-runs the queue, so a lost ring delays work but never drops it. Containment is layered: a dedicated unprivileged user, a read-only system with one writable working directory, and reader-level tokens only.

The archive

Every accepted version is also committed to a write-behind git archive — one commit per version, message carrying project, slug, seq, author kind, and note. It is strictly one-way: the platform database is canonical; the archive exists for durability, blame, and grep, and nothing ever reads it back. There is exactly one source of truth.

Author & publish

Author a full, self-contained HTML document — no external requests, baseline styles via <link rel="stylesheet" href="./artifact.css">, page-specific styles in its own <style> block. Preview it straight from disk. Then publish:

one call, live immediately (authoring trust)
curl -X PUT "$BASE/api/$TOKEN/artifacts/<slug>?promote=live" \
  -H "authorization: Bearer $ADMIN" -H "content-type: application/json" \
  -d '{"html": "…", "note": "what changed and why"}'

Without ?promote=live (or without the admin token) the version lands pending — the right default for anything that wants review first.

The annotation loop

  • A reader highlights text on any served page, comments, sends. The annotation stores pending, pinned to the version on screen; the doorbell rings.
  • The runner pulls status=pending, fetches the raw HTML of the pinned versions (a dedicated route — served pages carry injected chrome that must never round-trip into a new version), applies the feedback, and PUTs one new pending version per slug.
  • It PATCHes each annotation to processed with a response like "addressed in v8: reworded the severity axis" — or dismissed with a reason, including for any comment that tries to instruct the agent rather than improve the page.

Review & promote

Pending versions are ordinary pages — open ?v=N, read what the agent forged, then either promote or leave it superseded by your own follow-up. The artifact index (GET /artifacts) reports a pending_count per artifact, so "what awaits review" is one call.

the review gate
curl -X POST "$BASE/api/$TOKEN/artifacts/<slug>/promote" \
  -H "authorization: Bearer $ADMIN" -d '{"version": 8}'

Onboard a project

  • Register the project: a name plus a freshly minted unguessable token.
  • Upload the project's artifact.css baseline as a project asset.
  • Seed any existing pages as version 1 each (a folder-walking seed script ships with the platform).
  • In the project's repo, a small config file records the namespace, source folder, registry, URL prefix, and publish call — so any authoring agent knows how this project publishes.

API — artifacts

All routes live under /api/<project-token>/…. Reader-token routes need nothing further; admin routes require Authorization: Bearer <admin token>.

RouteAuthDoes
PUT/artifacts/:slug reader Append the next version (pending). Body: html (required), note, author, author_kind, assets[{path, mime, data₆₄}] — omit assets to inherit the previous version's. Title is read from the page's <title>.
PUT/artifacts/:slug?promote=live admin Same, but the new version goes straight to live.
POST/artifacts/:slug/promote admin Move the live pointer to {version: seq}; the old live version becomes superseded.
GET/artifacts reader Project index: slug, title, live_seq, latest_seq, pending_count.
GET/artifacts/:slug reader Metadata + the full version list (no HTML bodies).
GET/artifacts/:slug/html?v=N reader Raw version HTML, without injected chrome — what agents edit. Omit ?v for live.
PUT/assets/:path admin Project-scoped file (e.g. artifact.css); raw body, mime from content-type.

API — annotations

RouteAuthDoes
POST/annotations reader Create, pinned to {version: id} (must belong to the project). Anchor: quote (required), prefix, suffix, section; plus comment (required), author. Rate-limited per client.
GET/annotations?slug&status&version reader List, joined with the pinned version's slug and seq. The runner's queue is ?status=pending.
PATCH/annotations/:id reader Set status (processed / dismissed) and response — the answer shown back to the reader.

Serving

RouteAuthDoes
GET/:token/:slug URL The live version with chrome injected; .html suffix tolerated. ?v=N pins any version, any status — pending review and superseded history included.
GET/:token/<path> URL Project assets fall back where no artifact matches — /:token/artifact.css serves the shared baseline.
GET/:token/assets/:slug/<path> URL Version-scoped assets of the live (or ?v-pinned) version — pages reference ./assets/<slug>/….
GET/api/health · /api/chrome.js open Liveness; the injected chrome bundle.