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
statusispending(created, awaiting review),live, orsuperseded. Every version stays addressable forever via?v=<seq>. - Versions record an
author_kind—session(an authoring agent under human direction),runner(the autonomous annotation loop), orhuman— plus a one-linenotesaying 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 pending →
processed (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:
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
processedwith a response like "addressed in v8: reworded the severity axis" — ordismissedwith 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.
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.cssbaseline 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>.
| Route | Auth | Does |
|---|---|---|
| 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
| Route | Auth | Does |
|---|---|---|
| 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
| Route | Auth | Does |
|---|---|---|
| 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. |