# Superflow for agents

Superflow holds drawings: UI designs made of frames, shapes and text, and
flowcharts made of shapes joined by arrows. A person edits them at `/app`, a
Supernote tablet can draw them and send handwritten pages back, and an agent
reads and edits them through the API below. This file is the whole contract.

## Access

A person creates a token at `/app` → Agents. Send it as
`Authorization: Bearer sf_…`. A token sees the drawings of the person who made
it. Base URL: the origin this file was served from (`https://superflow.jcorp.app`
or `https://superflow.jcorp.ai`; both reach the same data).

A command-line client with no dependencies is at `/superflow.mjs`:

```sh
curl -s https://superflow.jcorp.app/superflow.mjs -o superflow.mjs
export SUPERFLOW_TOKEN=sf_…
node superflow.mjs list
node superflow.mjs outline <id>          # read this first: one line per element
node superflow.mjs svg <id> -o out.svg   # then look at it: rsvg-convert out.svg -o out.png
node superflow.mjs patch <id> ops.json   # small edits
```

## Routes (`/agent/v1`)

| Route | Body → result |
| --- | --- |
| `GET /docs` | → `{docs: [{id, name, rev, els, updated, url}]}` |
| `POST /docs` | `{name?, doc?}` → 201 `{id, name, rev, url}` |
| `GET /docs/:id` | → `{id, name, rev, updated, url, doc}` |
| `PUT /docs/:id` | `{doc?, name?, rev?}` → `{id, name, rev}` |
| `PATCH /docs/:id` | `{ops: [...], rev?}` → `{id, rev, els}` |
| `DELETE /docs/:id` | → 204 |
| `GET /docs/:id/outline` | `?frame=<id>` → text, one line per element |
| `GET /docs/:id/svg` | `?frame=<id>` → SVG, images inlined |
| `GET /docs/:id/html` | `?frame=<id>` → HTML with absolutely positioned boxes |
| `GET /imports` | → `{imports: [...]}`: pages that came back from the Supernote |
| `POST /sends` | `{doc, frame?}` → queue a drawing or frame for the Supernote |

Errors are `{"error": code, "message": sentence}`. `rev` is optional on
writes; when sent, a write to a drawing that changed since returns 409 `stale`
with the current `rev`. The person may be editing the same drawing: their
editor picks up your change within about 20 seconds or when its window regains
focus, and merges by element id. Prefer `PATCH` with ops over `PUT` so you only
touch the elements you mean to. `url` opens the drawing in the editor.

## Format

A drawing is `{"v": 1, "els": [Element, …]}`. `els` is paint order: later
elements are on top. Coordinates are absolute canvas pixels, x right, y down,
even for elements inside a frame. Unknown fields are refused with the field's
name, so a typo is reported rather than dropped.

Every element: `id` (1–32 of `A-Za-z0-9_-`, unique), `type`, and optionally
`name` (shown in the layers list), `parent` (id of the frame or group that
contains it), `op` (opacity 0–1), `hidden`, `locked`.

| type | geometry | other fields |
| --- | --- | --- |
| `frame` | `x y w h` | `fill stroke sw radius clip rot`. An artboard or a container; children are clipped unless `clip: false`. Top-level frames are the screens. |
| `group` | none (box comes from its members) | |
| `rect` | `x y w h` | `fill stroke sw dash radius rot`, label: `text size weight font align tc` |
| `ellipse`, `diamond` | `x y w h` | as `rect` without `radius` |
| `text` | `x y`, `w h` optional (estimated) | `text` (required, `\n` for lines, no wrapping), `size weight font align`, `fill` is the text colour |
| `line`, `arrow` | `pts: [x0, y0, x1, y1, …]` | `stroke sw dash`, `start: {el}`, `end: {el}`, `route: "straight" \| "elbow"`, label: `text size` |
| `pen` | `pts` | `stroke sw` (a freehand stroke; pages from the Supernote arrive as these) |
| `image` | `x y w h` | `src` (an image id uploaded in the editor), `radius rot` |

Colours are `#rgb`, `#rrggbb`, `#rrggbbaa` or `"none"`. `sw` is stroke width
(0–64). `weight` is 400, 500, 600 or 700. `font` is `sans`, `serif`, `mono` or
`hand`. `align` is `left`, `center` or `right`. `rot` is degrees about the centre.

Defaults when a field is absent: frame `fill #ffffff`, no stroke; rect, ellipse
and diamond `fill #ffffff`, `stroke #1e1e1e`, `sw 2`; text `fill #1e1e1e`,
`size 16`; shape labels are centred, `tc #1e1e1e`; line, arrow and pen
`stroke #1e1e1e`, `sw 2`.

A line or arrow with `start`/`end` is a connector: give any two points in
`pts` and the server routes it between the outlines of the two elements, and
re-routes it when either moves. `x y w h` of path elements and groups are
derived; do not send them.

## Ops (`PATCH`)

```json
{"ops": [
  {"op": "add", "el": {"type": "rect", "parent": "home", "x": 24, "y": 120, "w": 342, "h": 56, "radius": 12, "fill": "#2563eb", "stroke": "none", "text": "Continue", "tc": "#ffffff", "weight": 600}},
  {"op": "set", "id": "title", "props": {"text": "Welcome back", "size": 28, "name": null}},
  {"op": "move", "id": "card", "dx": 0, "dy": 40},
  {"op": "remove", "id": "old-footer"},
  {"op": "order", "id": "badge", "to": "front"}
]}
```

`add` puts the element on top (or under `"before": <id>`); an omitted `id` is
generated. `set` changes fields and `null` removes one; `id` and `type` cannot
change. `move` and `remove` include everything inside a frame or group. The
whole list applies or none of it does.

## Reading a drawing

`outline` is the cheapest accurate view. One line per element, indented by
containment; positions are relative to the enclosing frame; only styling that
differs from the defaults is listed:

```
frame #home "Home" 390x844 at 0,0
  text #title "Welcome back" 180x36 at 24,64 size 28 weight 700
  rect #cta "Continue" 342x56 at 24,120 fill #2563eb stroke none radius 12 tc #ffffff
  arrow #a1 #cta -> #next
group #k2j9x0qa "Supernote 2026-11-11 18:40"
  pen #p1 37 points in 120x40 at 30,200
```

A group named `Supernote <time>` holds what was handwritten on the tablet over
that drawing: treat its pen strokes as the person's markup. `GET /imports`
lists those pages with the tablet's handwriting recognition in `text`.
To see the drawing, fetch `svg` and render it. `html` gives the same frames as
absolutely positioned boxes, a starting point for real markup.

## Limits

4,000 elements, 400,000 path points and 1.5 MB of JSON per drawing; 300 drawings.
