@augurworks/augur 0.15.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (190) hide show
  1. package/CANVAS.md +858 -0
  2. package/INSTALL.md +603 -0
  3. package/LICENSE +27 -0
  4. package/README.md +150 -0
  5. package/TRADEMARKS.md +72 -0
  6. package/agents/README.md +65 -0
  7. package/agents/canon-extract.md +117 -0
  8. package/agents/canon.md +151 -0
  9. package/agents/canvas.md +88 -0
  10. package/agents/currency.md +74 -0
  11. package/agents/drafts.md +92 -0
  12. package/agents/identity.md +148 -0
  13. package/agents/prototype-contract.md +69 -0
  14. package/agents/publishing.md +324 -0
  15. package/agents/review-feedback.md +76 -0
  16. package/agents/space-json.md +132 -0
  17. package/agents/ui-skill.md +101 -0
  18. package/agents/working-marks.md +86 -0
  19. package/brand/augur-eye.svg +3 -0
  20. package/brand/augur-icon.svg +41 -0
  21. package/brand/augur-mark.svg +5 -0
  22. package/brand/lentianova-bulky.otf +0 -0
  23. package/brand/lentianova-median.otf +0 -0
  24. package/brand/lentianova.woff2 +0 -0
  25. package/build.js +8409 -0
  26. package/changelog.md +133 -0
  27. package/fonts/inter-latin-wght-normal.woff2 +0 -0
  28. package/package.json +57 -0
  29. package/pitis/PETS.md +121 -0
  30. package/pitis/README.md +117 -0
  31. package/pitis/index.html +266 -0
  32. package/pitis/piti.build.js +81 -0
  33. package/pitis/piti.js +929 -0
  34. package/pitis/roast-agent.md +185 -0
  35. package/realtime/src/index.js +119 -0
  36. package/realtime/wrangler.example.toml +44 -0
  37. package/scripts/adopt.mjs +106 -0
  38. package/scripts/board-snapshot.mjs +197 -0
  39. package/scripts/build-seed-pack.mjs +33 -0
  40. package/scripts/bundle-rekey.mjs +112 -0
  41. package/scripts/bundle-tenancy-rehearsal.mjs +781 -0
  42. package/scripts/canon-extract.mjs +578 -0
  43. package/scripts/canon.mjs +599 -0
  44. package/scripts/canvas-screen.mjs +333 -0
  45. package/scripts/check-local.mjs +136 -0
  46. package/scripts/clawd-art.mjs +75 -0
  47. package/scripts/clawd-canvas.mjs +741 -0
  48. package/scripts/cli.mjs +100 -0
  49. package/scripts/clone.mjs +422 -0
  50. package/scripts/close.mjs +30 -0
  51. package/scripts/connect.mjs +103 -0
  52. package/scripts/deploy.mjs +157 -0
  53. package/scripts/dev.mjs +54 -0
  54. package/scripts/doc-lint.mjs +143 -0
  55. package/scripts/export.mjs +300 -0
  56. package/scripts/fork.mjs +64 -0
  57. package/scripts/freeze.mjs +74 -0
  58. package/scripts/frontdoor-parity.mjs +180 -0
  59. package/scripts/hook.mjs +67 -0
  60. package/scripts/identity-rekey.mjs +112 -0
  61. package/scripts/init.mjs +122 -0
  62. package/scripts/land.mjs +40 -0
  63. package/scripts/lib/adapters.mjs +156 -0
  64. package/scripts/lib/board-snapshot.mjs +511 -0
  65. package/scripts/lib/draft.mjs +385 -0
  66. package/scripts/lib/graduate.mjs +276 -0
  67. package/scripts/lib/instance.mjs +74 -0
  68. package/scripts/lib/marks.mjs +107 -0
  69. package/scripts/lib/materialize.mjs +138 -0
  70. package/scripts/lib/merge3.mjs +124 -0
  71. package/scripts/lib/offline-posture.mjs +120 -0
  72. package/scripts/lib/offline-respawn.mjs +18 -0
  73. package/scripts/lib/offline-wrangler.mjs +78 -0
  74. package/scripts/lib/publish-compose.mjs +12 -0
  75. package/scripts/lib/publish-conflict.mjs +78 -0
  76. package/scripts/lib/publish-evidence.mjs +144 -0
  77. package/scripts/lib/refine-compare.mjs +140 -0
  78. package/scripts/lib/refine-ledger.mjs +150 -0
  79. package/scripts/lib/refine-png.mjs +149 -0
  80. package/scripts/lib/seed-pack-build.mjs +141 -0
  81. package/scripts/lib/state-compare.mjs +68 -0
  82. package/scripts/lib/store.mjs +122 -0
  83. package/scripts/login.mjs +84 -0
  84. package/scripts/mark.mjs +112 -0
  85. package/scripts/migrate-board-keys.mjs +164 -0
  86. package/scripts/migrate.mjs +265 -0
  87. package/scripts/no-foreign-vocabulary.mjs +216 -0
  88. package/scripts/no-product-names.mjs +157 -0
  89. package/scripts/no-tenant-globals.mjs +1134 -0
  90. package/scripts/offline.mjs +247 -0
  91. package/scripts/og.mjs +170 -0
  92. package/scripts/one-tenant-resolver.mjs +146 -0
  93. package/scripts/open.mjs +63 -0
  94. package/scripts/publish.mjs +1041 -0
  95. package/scripts/read.mjs +31 -0
  96. package/scripts/refine.mjs +455 -0
  97. package/scripts/release-drift.mjs +138 -0
  98. package/scripts/restore.mjs +322 -0
  99. package/scripts/review.mjs +125 -0
  100. package/scripts/save.mjs +21 -0
  101. package/scripts/shell-lint.mjs +189 -0
  102. package/scripts/ship.mjs +460 -0
  103. package/scripts/shoot.mjs +264 -0
  104. package/scripts/smoke-invite.mjs +113 -0
  105. package/scripts/state-inventory.mjs +223 -0
  106. package/scripts/status.mjs +177 -0
  107. package/scripts/sync.mjs +27 -0
  108. package/scripts/tenant-do-rehearsal.mjs +1314 -0
  109. package/scripts/ui-copy-lint.mjs +202 -0
  110. package/scripts/watch.mjs +32 -0
  111. package/scripts/wrangler-preflight.mjs +246 -0
  112. package/seed/CANON.md +43 -0
  113. package/seed/README.md +119 -0
  114. package/seed/prototype-status.json +9 -0
  115. package/seed/registry.json +88 -0
  116. package/seed/skills/starter-ui/SKILL.md +52 -0
  117. package/seed/skills/starter-ui/skill.json +11 -0
  118. package/seed/skills/starter-ui/starter-tokens.css +73 -0
  119. package/seed/skills/starter-ui/starter-ui.css +318 -0
  120. package/seed/skills/starter-ui/starter-ui.js +50 -0
  121. package/seed/space.json +5 -0
  122. package/seed/start-here/prototypes/connect-your-terminal/index.html +428 -0
  123. package/seed/start-here/prototypes/connect-your-terminal/preview.webp +0 -0
  124. package/seed/start-here/prototypes/sample-with-comments/index.html +172 -0
  125. package/seed/start-here/prototypes/sample-with-comments/preview.webp +0 -0
  126. package/seed/start-here/prototypes/set-up-your-design-system/index.html +353 -0
  127. package/seed/start-here/prototypes/set-up-your-design-system/preview.webp +0 -0
  128. package/seed/threads.json +52 -0
  129. package/seed/worked-examples/prototypes/field-readings/index.html +273 -0
  130. package/seed/worked-examples/prototypes/field-readings/preview.webp +0 -0
  131. package/seed/worked-examples/prototypes/slide-deck/index.html +214 -0
  132. package/seed/worked-examples/prototypes/slide-deck/preview.webp +0 -0
  133. package/seed/worked-examples/prototypes/specimen-viewer/index.html +203 -0
  134. package/seed/worked-examples/prototypes/specimen-viewer/preview.webp +0 -0
  135. package/src/_worker.js +12668 -0
  136. package/src/board-key.mjs +57 -0
  137. package/src/board-room.mjs +881 -0
  138. package/src/bundle-keys.mjs +138 -0
  139. package/src/canon/collect-in-browser.js +215 -0
  140. package/src/canon/emit.mjs +232 -0
  141. package/src/canon/observe.mjs +260 -0
  142. package/src/canon/schema.mjs +451 -0
  143. package/src/canvas/DSEG-LICENSE.txt +95 -0
  144. package/src/canvas/DSEG7Classic-Bold.woff2 +0 -0
  145. package/src/canvas/canvas.css +885 -0
  146. package/src/canvas/canvas.js +5780 -0
  147. package/src/canvas/capture.js +485 -0
  148. package/src/chrome/appchrome.mjs +568 -0
  149. package/src/currency.mjs +203 -0
  150. package/src/delete-confirmation.mjs +254 -0
  151. package/src/drafts/drafts.js +326 -0
  152. package/src/entry.js +58 -0
  153. package/src/galleries.mjs +400 -0
  154. package/src/health-cron.mjs +173 -0
  155. package/src/identity.json +1 -0
  156. package/src/kv-codec.mjs +135 -0
  157. package/src/kv-identity.mjs +259 -0
  158. package/src/mail.mjs +599 -0
  159. package/src/provenance.mjs +74 -0
  160. package/src/publish-compose.mjs +363 -0
  161. package/src/publish-fork.mjs +221 -0
  162. package/src/publish-units.mjs +44 -0
  163. package/src/purge.mjs +81 -0
  164. package/src/review/COMMENTING-UX.md +306 -0
  165. package/src/review/cat.png +0 -0
  166. package/src/review/comment-cursor.svg +7 -0
  167. package/src/review/comments.js +1738 -0
  168. package/src/room-ticket.mjs +96 -0
  169. package/src/roster-chip.mjs +32 -0
  170. package/src/seed-pack.mjs +261 -0
  171. package/src/state-inventory.mjs +249 -0
  172. package/src/sw-logic.mjs +48 -0
  173. package/src/tenant-cache.mjs +141 -0
  174. package/src/tenant-context.mjs +386 -0
  175. package/src/tenant-do.js +2940 -0
  176. package/src/tenant-host.mjs +144 -0
  177. package/src/tenant-quotas.mjs +140 -0
  178. package/src/unit-core.mjs +103 -0
  179. package/src/unit-object.mjs +338 -0
  180. package/templates/README.md +67 -0
  181. package/templates/shell/deploy.yml +145 -0
  182. package/templates/shell/engine-bump.yml +142 -0
  183. package/templates/shell/health.yml +233 -0
  184. package/templates/shell/kv-backup.yml +201 -0
  185. package/templates/shell/roster-update.yml +110 -0
  186. package/templates/shell/space-preflight.yml +35 -0
  187. package/templates/shell/space-rebake.yml +79 -0
  188. package/templates/shell/store-backup.yml +152 -0
  189. package/templates/shell/wrangler.example.toml +266 -0
  190. package/templates/space/publish.yml +91 -0
package/README.md ADDED
@@ -0,0 +1,150 @@
1
+ # Augur
2
+
3
+ A prototype and research repository for product teams. Real, clickable
4
+ prototypes and the design system they are built from, on one site with login,
5
+ comments and live boards on top. Underneath it is all git and static HTML.
6
+
7
+ **Building the prototypes is the easy part.** An agent can produce a convincing
8
+ screen in a minute, and most teams already have more of them than they can find.
9
+ What is missing is everything around them: where the last version went, who
10
+ changed it, which of the four things called "the dashboard" is the one being
11
+ reviewed, and where the feedback landed. That is what this is. Prototypes live
12
+ in one place with the design system they are made from, comments stick to the
13
+ pixels they are about, boards let you run the real screens side by side, and
14
+ every version is a commit you can walk back to.
15
+
16
+ It runs on your own box, or on somebody else's. There is no editor to be locked
17
+ out of and no export to negotiate: a prototype is a folder of static HTML in a
18
+ git repository you already own.
19
+
20
+ **See it running: [demo.augur.works](https://demo.augur.works)**, sign in with
21
+ `visita@fulla.demo` / `regadora`. It resets every night, so scribble away.
22
+
23
+ ![The projects gallery](docs/shots/gallery.png)
24
+
25
+ The demo runs [Fulla](https://github.com/andratwiro/augur-space-fulla), an
26
+ invented community garden product. That repo doubles as the starter space, so
27
+ everything below works against it.
28
+
29
+ ## How a prototype gets made
30
+
31
+ There is no editor. A prototype is briefed, not drawn. You describe the screen
32
+ the way you would brief a designer, and an agent builds it as a page in the
33
+ space, using the design system like anyone else on the team.
34
+
35
+ The brief that made [Seed swap](https://demo.augur.works/garden/seed-swap/):
36
+
37
+ ```text
38
+ Seed swap — a noticeboard where members offer saved seeds and claim each
39
+ other's. One screen. A board of offer cards: who, what, roughly how many,
40
+ which plot they came from — "Fava beans, saved from plot 12, ~40 seeds".
41
+ Claiming an offer keeps the card on the board but settles it down visually;
42
+ the swap happens at the shed, not in the app. The empty state suggests the
43
+ first action instead of apologizing. Warm and hand-made like the rest of
44
+ Fulla — use the fulla design system, don't invent new vocabulary. Add the
45
+ one-line meta description. No routing, no backend; seed the board with a
46
+ handful of believable offers.
47
+ ```
48
+
49
+ ![The agent building the seed swap screen from the brief, the browser hot-reloading into it, and a comment pinned on the result](docs/shots/authoring.gif)
50
+
51
+ That is Claude Code in the capture; any coding agent that can read the
52
+ contracts in [agents/](./agents/) does the same job. Screens in the demo space
53
+ carry the session that made them: [open the repo and read one](https://github.com/andratwiro/augur-space-fulla/tree/main/garden/prompts).
54
+ The follow-ups read like design direction, because that is what they are.
55
+
56
+ ## Boards where the prototypes run
57
+
58
+ Drop a live prototype next to the stickies and drive it. Everyone on the board
59
+ sees the same screen state. Agents join as pixel mascots and work next to you.
60
+ Up close: the specimen spins inside its tile, a teammate's cursor works the
61
+ area, and Menta the agent strolls over to watch.
62
+
63
+ ![A live prototype spinning on the board while people and agents move](docs/shots/canvas-live.gif)
64
+
65
+ ## Comments on the real pixels
66
+
67
+ Shift+C on any prototype opens review mode. A pin sticks to the element it
68
+ talks about, the thread keeps everyone's face on it, and the design system
69
+ shows through as a layer.
70
+
71
+ ![Review mode on a prototype](docs/shots/review.png)
72
+
73
+ ## Build your design library
74
+
75
+ The same space that holds your prototypes holds your design system. Tokens,
76
+ base, components, patterns and pages each get a tier, every entry is a plain
77
+ HTML page you write, and the site renders it with a live preview and the class
78
+ names it documents. A small registry gives the review overlay the same
79
+ vocabulary, so a pin on a prototype knows which component it landed on.
80
+
81
+ ![The components tier of the library](docs/shots/library.png)
82
+
83
+ Up close, at the tokens depth: paddings shade in place like devtools, and the
84
+ panel lists the tokens a component drinks with their live values. Token usage
85
+ is tracked to the pixel across every prototype that links the system.
86
+
87
+ ![A component's padding shaded, its tokens listed with live values](docs/shots/tokens.png)
88
+
89
+ ## Try it locally
90
+
91
+ **Under ten seconds from an empty folder to a page in your browser**, and that is
92
+ a measured number rather than a hopeful one: three runs on a laptop with a fast
93
+ connection came in at 7.3s, 9.0s and 9.2s, stopwatch from `git clone` to a `200`
94
+ on `http://localhost:8788/` serving the real gallery. Most of that is the two
95
+ clones, so a slower connection moves the number and nothing else does — the
96
+ engine itself is about two seconds from cold to serving.
97
+
98
+ ```bash
99
+ git clone https://github.com/andratwiro/augur.git
100
+ git clone https://github.com/andratwiro/augur-space-fulla.git
101
+ cd augur-space-fulla
102
+ node ../augur/scripts/dev.mjs
103
+ ```
104
+
105
+ There is no install step and no build step in that list, and that is not an
106
+ omission: **the engine has no runtime dependencies**, so plain `node` is enough.
107
+ What you get is the full shell — the gallery, the library, review mode, boards —
108
+ with about a second of hot reload on every save. No login prompt, because a bare
109
+ clone has no user list to gate against; add one and the gate turns on.
110
+
111
+ Prototypes are self-contained static HTML, so `index.html` also opens straight
112
+ from disk. That is fine for your own glance and never a way to show anyone
113
+ anything: no chrome, no comments, no boards, and the link works on exactly one
114
+ machine.
115
+
116
+ ## How it is put together
117
+
118
+ - **A space is a git repo.** Your design system and your prototypes, nothing
119
+ else. Only the contents of `prototypes/` folders and the gallery tiers ever
120
+ publish. The research notes sitting next to them stay private by
121
+ construction.
122
+ - **The engine is this repo.** It composes spaces into one static site and
123
+ runs the overlay worker on Cloudflare. It carries no secrets and no content.
124
+ - **A private deploy shell holds your instance.** The engine pin, the user
125
+ list, every secret. Engine fixes reach your instance by pin bump, never by
126
+ forking.
127
+ - **Publishing is `augur land`** on a workspace that serves drafts — open one
128
+ prototype, edit, land; seconds, atomic, with history. Self-hosted instances
129
+ without a unit store publish with `augur publish`. A git push saves and shares
130
+ work without deploying anything.
131
+
132
+ ## Run your own
133
+
134
+ [INSTALL.md](./INSTALL.md) is the recipe, written to be executed top to bottom
135
+ by a person or an agent. About an hour, most of it waiting on DNS and CI.
136
+
137
+ ## Docs
138
+
139
+ - [CLAUDE.md](./CLAUDE.md), the engine conventions
140
+ - [agents/](./agents/), the contracts for agents working in a space
141
+ - [CANVAS.md](./CANVAS.md), the board engine and how agents co-work on it
142
+ - [CONTRIBUTING.md](./CONTRIBUTING.md), fork to PR, never fork to deploy
143
+
144
+ ## License
145
+
146
+ MIT for the code. See [LICENSE](./LICENSE).
147
+
148
+ The name, the marks in `brand/` and the typefaces bundled with them are not part of
149
+ that grant — [TRADEMARKS.md](./TRADEMARKS.md) says what you can do without asking
150
+ (fork it, rename it, say what it is) and what needs a word first.
package/TRADEMARKS.md ADDED
@@ -0,0 +1,72 @@
1
+ # Trademarks, brand assets and bundled fonts
2
+
3
+ [LICENSE](./LICENSE) is MIT and covers the **code**. It does not, and was never meant to,
4
+ hand over the project's name or the files in [`brand/`](./brand). This page says where that
5
+ line is, because a bare MIT file placed next to a logo reads as though it grants the logo
6
+ too.
7
+
8
+ ## What the MIT licence does not grant
9
+
10
+ These are **unregistered** marks. That is what is true today and it is what this page
11
+ claims — no more, because claiming a registration you do not hold is a misrepresentation,
12
+ and no less, because an unregistered mark is still a mark.
13
+
14
+ **The name.** "Augur", used as the name of a product, a service, a company or a domain.
15
+
16
+ **The marks.** `brand/augur-mark.svg`, `brand/augur-icon.svg`, `brand/augur-eye.svg`, and
17
+ the copies of them that a build emits (`augur-mark.png`, `augur-icon-192.png`,
18
+ `augur-icon-512.png`, `augur-eye.svg`). Copying a file is not a licence to wear it.
19
+
20
+ **The fonts.** `brand/lentianova.woff2`, `brand/lentianova-bulky.otf` and
21
+ `brand/lentianova-median.otf` are **third-party typefaces, licensed to this project and not
22
+ sublicensable by it**. They sit in the repository because the build needs them; they are
23
+ not covered by the MIT grant, and no MIT grant could cover them, because they are not this
24
+ project's to give. If you are shipping something built from this repository, obtain your
25
+ own licence or substitute your own typeface — every font reference resolves through the
26
+ design-system tokens, so replacing it is a value change, not a code change.
27
+
28
+ > The project's own licence position on these typefaces is not yet settled for commercial
29
+ > use. Until it is, treat them as the most restricted files in the repository.
30
+
31
+ `src/canvas/DSEG7Classic-Bold.woff2` is different: it ships under the SIL Open Font
32
+ License, and its terms are in [`src/canvas/DSEG-LICENSE.txt`](./src/canvas/DSEG-LICENSE.txt)
33
+ alongside it.
34
+
35
+ ## What you can do without asking
36
+
37
+ **Run it, fork it, change it, ship it.** That is what MIT is for, and none of the above
38
+ narrows it. A fork that keeps the code and replaces the name and the marks needs no
39
+ permission from anyone.
40
+
41
+ **Say what it is.** "Built on Augur", "compatible with Augur", "an Augur instance" —
42
+ describing a thing accurately by its name is nominative use, and it is fine. So is naming
43
+ the project in a talk, a blog post, an academic paper or a comparison table.
44
+
45
+ **Keep the marks in an unmodified copy.** Redistributing the repository as it is, marks
46
+ included, is fine. What is not fine is lifting the marks out of it.
47
+
48
+ ## What needs asking
49
+
50
+ Using the name or the marks in a way that suggests a project is **the** Augur, or is
51
+ endorsed by, affiliated with or maintained by it. Concretely: naming your product or your
52
+ company Augur or something confusable with it; registering a domain of the form
53
+ `augur-<something>` for a service you run; putting the mark on a paid hosted service; or
54
+ using it as the icon of an application that is not this one.
55
+
56
+ Modified copies must not carry the marks. That is the whole point of the carve-out: the
57
+ mark is how someone tells which copy they are looking at, and a mark on a fork makes that
58
+ question unanswerable.
59
+
60
+ ## Asking
61
+
62
+ Open an issue on the repository. There is no form and no fee.
63
+
64
+ ## In short
65
+
66
+ Take the code. Leave the name.
67
+
68
+ ---
69
+
70
+ *This page describes the position; it is not legal advice, and it has not yet been through
71
+ a lawyer. The trademark itself is not yet cleared — see the project's own launch notes. If
72
+ you are relying on any of this commercially, ask your own counsel.*
@@ -0,0 +1,65 @@
1
+ # agents/ — engine docs for agents working in a workspace
2
+
3
+ These files are the engine's contract for the everyday things a **workspace
4
+ collaborator's agent** does with Augur: shipping work, reading review feedback,
5
+ what the engine expects of a prototype folder, the `space.json` schema, users
6
+ and avatars.
7
+
8
+ The word for the thing is **workspace** — one per instance, served at its root.
9
+ The FILE is still `space.json` and every identifier keeps its old spelling; see
10
+ [space-json.md](./space-json.md) for why that is a decision and not a leftover.
11
+
12
+ They ship WITH the engine so every instance gets the same, current contract —
13
+ when an engine change alters behavior, the same commit updates the doc here.
14
+ Workspace repos should link to these files (the engine clone sits next to every
15
+ workspace clone that publishes), never copy them: a copied contract drifts.
16
+
17
+ ## Getting in
18
+
19
+ A workspace is a sign-in gate. Pages need a person's session; creating and publishing
20
+ prototypes needs a **publish token**, and an agent gets one by device pairing, never by
21
+ asking anyone for a password:
22
+
23
+ ```
24
+ npx augur connect --origin https://<the workspace>
25
+ ```
26
+
27
+ It prints one line to relay — *ask the owner of this workspace to open `<link>` and
28
+ enter `<code>`* — and waits. The owner opens the link in a browser they are already
29
+ signed in to and types the code; the token lands in `~/.config/augur/tokens.json`, and
30
+ `augur ship` / `augur publish` use it from then on. `publish` runs the pairing itself when
31
+ it finds no token, so inside a workspace tree nothing has to be done first. On a workspace
32
+ that serves drafts (`/.well-known/augur.json` says `drafts.enabled`), the everyday verbs
33
+ are `augur open` and `augur land` instead — see [drafts.md](./drafts.md). To get the
34
+ tree from a hostname, pair first, then `npx augur clone --space <id>` — it reads the
35
+ origin from the pairing.
36
+
37
+ Not on npm yet? The engine clone sits next to every workspace that publishes:
38
+ `node <engine>/scripts/cli.mjs connect --origin <origin>`. The instance says all of this
39
+ itself at `GET /llms.txt` (and as data at `/.well-known/augur.json`); a signed-out
40
+ request for an engine path answers `401` with the same facts.
41
+
42
+ Two things an agent never does: type a password into a terminal (`augur login` exists
43
+ for CI, and says so), and try the `pass` field from a deploy shell's `identity.json` —
44
+ that is a first-sign-in seed for a self-hosted instance, dead on a hosted workspace, and
45
+ the gate throttles failed attempts per address and per email.
46
+
47
+ Read them by trigger, not up front:
48
+
49
+ | When you are… | Read |
50
+ |---|---|
51
+ | asking what is current here, or what changed lately | [currency.md](./currency.md) |
52
+ | starting work on a prototype somebody else might also be in | [working-marks.md](./working-marks.md) — read it BEFORE the first edit |
53
+ | changing a prototype on a workspace that serves drafts | [drafts.md](./drafts.md) — open, edit, land |
54
+ | shipping / going live on a workspace without drafts | [publishing.md](./publishing.md) |
55
+ | acting on review comments | [review-feedback.md](./review-feedback.md) |
56
+ | building a prototype folder | [prototype-contract.md](./prototype-contract.md) |
57
+ | naming a canonical screen, or asked to "pull screens X, Y, Z" | [canon.md](./canon.md) |
58
+ | editing `space.json` | [space-json.md](./space-json.md) |
59
+ | building or forking a design system (`skills/<x>-ui/`) | [ui-skill.md](./ui-skill.md) |
60
+ | asked to copy a design system out of a live product | [canon-extract.md](./canon-extract.md) |
61
+ | adding users / avatars / login questions | [identity.md](./identity.md) |
62
+ | a board-shaped ask (brainstorm, compare, map a flow) or canvas work | [canvas.md](./canvas.md) — includes WHEN to suggest a canvas |
63
+
64
+ Engine *development* (build.js, worker, overlays) is a different audience:
65
+ see [../CLAUDE.md](../CLAUDE.md) and [../CONTRIBUTING.md](../CONTRIBUTING.md).
@@ -0,0 +1,117 @@
1
+ # Extracting a design system from a live product
2
+
3
+ `augur canon` turns "copy the design system from this URL" into a flow: a working folder,
4
+ a fixed list of token roles, an evidence collector that runs where the login already is, a
5
+ grader that is arithmetic rather than taste, and an emitter that writes the result into the
6
+ workspace's design system.
7
+
8
+ **Augur does none of the deciding.** Which of a product's eleven greys is its hairline, and
9
+ which single colour means "act on this", is judgement. This engine ships the harness; the
10
+ user's own agent, on the user's own account with whatever provider they like, does the
11
+ judging. There is no model call in this repository, no API key, no endpoint, no inference
12
+ dependency, and `augur canon` added none — `../test/canon-no-inference.test.mjs` fails the
13
+ build on the commit that changes that.
14
+
15
+ ## Why a URL and not a repository
16
+
17
+ Extracting a design system from a codebase is a solved problem and it is the wrong door for
18
+ the person who needs this one. The people who feel the cost of not having a canon are
19
+ product managers and designers: they hold a **login** to the product, not commit rights to
20
+ it. So the collector runs inside the browser they are already signed in to, sees the real
21
+ screens behind the login, and makes no request of its own.
22
+
23
+ ## The flow
24
+
25
+ ```
26
+ augur canon start <url> the working folder, the brief, the skeleton answer
27
+ augur canon snippet the collector to paste into your own browser
28
+ augur canon collect <url> or: read a PUBLIC page over HTTP
29
+ augur canon collect --merge fold several screens into one observation
30
+ augur canon grade grade the answer
31
+ augur canon apply write it into the workspace's design system
32
+ ```
33
+
34
+ `start` writes a `BRIEF.md` into the folder that names the actual URL, prefix and
35
+ workspace, with the role table inline. **That file is written for an agent to follow start
36
+ to finish**; hand it over rather than paraphrasing it.
37
+
38
+ ## The three files
39
+
40
+ | File | What it is | Who writes it |
41
+ | --- | --- | --- |
42
+ | `observation.json` | evidence: ranked colours, type sizes, gaps, radii, shadows, the product's own custom properties, candidate class families | the collector |
43
+ | `canon.json` | the answer: a value for each token role, plus named components | **the user's agent** |
44
+ | the skill folder | `<prefix>-tokens.css`, `<prefix>-canon.css`, `skill.json`, `registry.json`, `CANON.md` | `apply` |
45
+
46
+ The observation is ranked by how much of the screen a value actually covers, not by how
47
+ many times it appears in a stylesheet — which is why the browser door is the better
48
+ evidence as well as the only one that gets past a login. Text colour is weighted by the ink
49
+ it puts on the page rather than by the box, so a full-height container inheriting a colour
50
+ it never paints does not outrank the body.
51
+
52
+ ## One format, not two
53
+
54
+ The roles in `../src/canon/schema.mjs` are exactly the tokens a workspace is born with (see
55
+ `../seed/README.md`). That is enforced: `../test/canon-schema.test.mjs` fails if the seed
56
+ grows a token the schema does not name, or reads one the extractor would not emit.
57
+
58
+ It buys three things, and they are the reason the list is fixed rather than discovered per
59
+ product:
60
+
61
+ - **The screens a workspace already has re-skin instead of breaking.** Every prototype
62
+ links `<prefix>-tokens.css`; replacing the values moves all of them at once.
63
+ - **The page that teaches the design system keeps teaching it.** `set-up-your-design-system`
64
+ reads the token file live, so after an extraction it shows the team their own product.
65
+ - **A prototype written against one design system works against another.** Pulling a screen
66
+ from an example workspace into a real one is a copy, not a port.
67
+
68
+ Roles marked *computed* may be left out; they are derived from the ones that were observed,
69
+ and derived to be legible — a `mark-ink` computed from `mark` is guaranteed to clear 4.5:1
70
+ as text on the sheet, which a colour picked by eye frequently does not. A value the roles
71
+ have no slot for goes under an `x-` name and emits as a real token.
72
+
73
+ ## What `apply` will and will not do
74
+
75
+ - **Regenerates** `<prefix>-tokens.css`. Safe because the roles are fixed.
76
+ - **Creates** `<prefix>-canon.css` with the extracted components. Its own file.
77
+ - **Never touches** the workspace's own component stylesheet (`<prefix>-ui.css`). That is
78
+ the workspace's writing, not the extractor's.
79
+ - **Refuses** a class name the workspace already defines. Two rules for one selector in two
80
+ files is a bug that shows up on one screen and nowhere else.
81
+ - **Merges** `registry.json` by name, keeping the workspace's own labels and descriptions.
82
+ - Emits under the **workspace's** prefix even when the canon calls itself something else —
83
+ renaming a workspace's tokens orphans every prototype that reads them.
84
+
85
+ ## What the grader enforces
86
+
87
+ Arithmetic only, and each rule exists because the failure it catches is invisible in a diff:
88
+
89
+ - every observed role answered, every value the right kind;
90
+ - the type scale and the space ramp climb;
91
+ - body text clears 4.5:1 on the sheet, and so does the mark used as text;
92
+ - **no component hard-codes a colour** — a component that does stops moving when a token
93
+ changes, and then the design system is decoration;
94
+ - every `var()` a component reads is a token the canon defines;
95
+ - every class carries the skill's class prefix, and the CSS defines every class it lists.
96
+
97
+ `augur canon grade --space <workspace>` grades the design system a workspace is actually
98
+ carrying, read back off disk. A workspace that has never been near the extractor should
99
+ pass it.
100
+
101
+ ## Where it stops
102
+
103
+ - The collector sees **rendered** values, so a colour that only exists in a state nobody
104
+ triggered — an error toast, a disabled row — is not in the evidence. Collect the screens
105
+ that matter, including the ugly ones.
106
+ - It reads no images. A logo, an illustration style and a photographic treatment are design
107
+ system and none of them are in here.
108
+ - **`font-display` and `font-body` are stacks, not files.** Nothing downloads a face, so a
109
+ stack naming a face the workspace does not already have falls back silently — and a near
110
+ fallback looks intentional, which makes it harder to notice, not easier. Self-host the
111
+ face and add the `@font-face` yourself, or name one that is already there.
112
+ - A role typed `length` holds one length, so a `border-radius` SHORTHAND (four values, or a
113
+ slash) has no role. Put a representative length in the role so the scale still works and
114
+ carry the real shorthand as an `x-` token.
115
+ - Dark mode is a second canon, not a second column: collect it separately.
116
+ - A cross-origin stylesheet cannot be read for custom properties. Computed styles still
117
+ count, and the observation says how many sheets were unreadable.
@@ -0,0 +1,151 @@
1
+ # The canon — how canonical screens and parts are named
2
+
3
+ The canon is the part of a workspace that is meant to be **pulled by name**: "build it
4
+ the way `invoice-detail` is built", "pull `invoice-list`, `invoice-detail` and
5
+ `invoice-empty` and wire them together". That instruction is the whole return on having a
6
+ design system, and it presumes `invoice-detail` names something an agent can find COLD —
7
+ no human pointing, in a session that has never seen this workspace before.
8
+
9
+ Names decide whether that works, and names drift the moment they are only a habit. One
10
+ screen lands as `checkout-v2`, the next as `new_Checkout`, a third as a scratch folder
11
+ wearing the same name as a canonical page, and the instruction stops resolving. Renaming
12
+ everything afterwards works and costs a day. This file is the scheme that makes the day
13
+ unnecessary, and `augur canon` is that scheme as a command.
14
+
15
+ **Resolving a name is one line, and it needs nothing else read first:**
16
+
17
+ ```bash
18
+ augur canon find invoice-detail # → the tier, the folder, the entry page, what it links
19
+ augur canon list # → every canonical name with its one-line description
20
+ ```
21
+
22
+ Both read the tree at the moment they are asked. There is no index file, so there is
23
+ nothing to regenerate and nothing that can be stale — the directory names ARE the index.
24
+ That holds only while they obey the scheme below, which is what `augur canon check` is
25
+ for.
26
+
27
+ **If the workspace has no canon yet, this file is the second thing to read.** A team that
28
+ would benefit from a canon usually already has one — their live product — and
29
+ `augur canon <start|collect|snippet|grade|apply>` copies it out of there into this
30
+ workspace's design system: see [canon-extract.md](canon-extract.md). Same command, same
31
+ `canon` word, because it is the same job at a different stage; the scheme below is what
32
+ the extracted result then gets named by. Note that the extractor's grading verb is
33
+ `grade` rather than `check` — `check` is this file's verb, and it answers a different
34
+ question (do the NAMES resolve, not do the TOKENS pass).
35
+
36
+ ## Where the canon lives
37
+
38
+ Four directories at the workspace root. Each is published and gets its own tab on the
39
+ site, and the build reads them directly — this is the engine's existing contract, not a
40
+ new layout.
41
+
42
+ | Where | What it holds | Pull it when |
43
+ | --- | --- | --- |
44
+ | `base/<name>/` | one atom, every state on one page | you need the button, the input, the badge |
45
+ | `components/<name>/` | one composed component | you need the thing itself |
46
+ | `patterns/<name>/` | an arrangement several screens repeat | you need the layout, not the parts |
47
+ | `pages/<name>/` | a whole screen | somebody said "pull screens X, Y, Z" |
48
+
49
+ Everything else in a workspace is **not** the canon, and a bare name never means one of
50
+ them. A folder under `<project>/prototypes/` is a working prototype — an exploration,
51
+ kept as the record of one. `playground/` is scratch. Both can be promoted; see
52
+ [Growing the canon](#growing-the-canon).
53
+
54
+ ## The name
55
+
56
+ **A canonical name is a directory name, and there is no second name.** The live site can
57
+ rename what a card DISPLAYS (that override lives in KV, not in the repo) and it never
58
+ changes what a name resolves to. If the two disagree, the folder is right.
59
+
60
+ **Form.** Lowercase ASCII letters, digits and single hyphens — `^[a-z0-9]+(-[a-z0-9]+)*$`.
61
+ No underscores, no spaces, no capitals, forty characters and four words at the outside.
62
+
63
+ **Subject first, qualifier last.** `invoice-list`, `invoice-detail`, `invoice-empty` —
64
+ never `list-of-invoices`, never `empty-invoice`. This is the rule that does the work:
65
+ A→Z sorts a subject's screens together, so a directory listing reads as a table of
66
+ contents and "pull the invoice screens" is one glance instead of a search. It is also
67
+ what lets somebody who knows one name in a family guess the rest.
68
+
69
+ **The qualifier comes from a closed set**, so the same idea is spelled the same way in
70
+ every workspace and an agent told "the empty state of the invoice list" can write down
71
+ `invoice-empty` without asking:
72
+
73
+ `-list` · `-detail` · `-new` · `-edit` · `-empty` · `-error` · `-loading` · `-confirm` · `-success`
74
+
75
+ Anything else at the end of a name is a second subject word, not a state. `-index`,
76
+ `-view`, `-show`, `-create`, `-add`, `-blank`, `-none`, `-fail`, `-done` and `-ok` are
77
+ the near misses — every one means a word already on the list, and `augur canon check`
78
+ names them rather than renaming anything, because which of two words a team says is
79
+ theirs to settle.
80
+
81
+ **A name says WHAT, never WHEN.** `-v2`, `-final`, `-copy`, `-old`, `-wip`, `-draft`,
82
+ `-tmp`, `-test`, a date, a ticket id — all refused. Every one encodes a moment in
83
+ somebody's afternoon, and a name carrying one cannot be guessed by the person who has to
84
+ pull it tomorrow. The version of a canon entry is its git history. (`-new` is on the
85
+ allowed list because it is a state — the create screen; `-new2` is not.)
86
+
87
+ **One name, one thing.** A name resolves in exactly one tier. Two tiers holding the same
88
+ name fails `check`; a prototype or playground folder holding a canonical name is reported
89
+ as a shadow, because the canon wins and that copy is one nobody will ever be sent to.
90
+
91
+ **Every entry says what it shows**, in one sentence in `<meta name="description">` — the
92
+ same tag the gallery card, the link preview and the canvas insert-picker already read
93
+ (see [prototype-contract.md](./prototype-contract.md)). `augur canon list` prints it, and
94
+ it is the only way a name is found by somebody who does not know it yet. An entry without
95
+ one fails `check`, and `augur canon save` refuses to create one.
96
+
97
+ ## Growing the canon
98
+
99
+ A canon that only grows when somebody schedules an afternoon for it does not grow. The
100
+ promotion is therefore one command, run at the moment the screen is finished and still
101
+ in front of you:
102
+
103
+ ```bash
104
+ augur canon save orders/prototypes/order-detail # → pages/order-detail/
105
+ augur canon save playground/filter-bar --tier components
106
+ augur canon save . --as invoice-detail --dry-run
107
+ ```
108
+
109
+ What it does, and what each part of it exists to prevent:
110
+
111
+ - **Copies, never moves.** The prototype stays where it is: comment pins are keyed to the
112
+ URL a screen was reviewed at, and the prototype is the record of the exploration. The
113
+ canon entry is the thing to copy from. When the two later disagree, `check` reports the
114
+ shadow rather than guessing which is current.
115
+ - **Applies the naming rules, and says so.** A source folder called `order-detail-v2`
116
+ promotes as `order-detail`, with the change printed. `--as <name>` overrides.
117
+ - **Repoints the design-system references for the new depth.** A prototype three levels
118
+ down references `../../../skills/<prefix>-ui/…`; a canon entry two levels down
119
+ references `../../skills/<prefix>-ui/…`. Getting that wrong produces a page that looks
120
+ correct on the site (the build rewrites the reference anyway) and opens unstyled from
121
+ disk — which is the failure that made promotion feel like a chore, because it is
122
+ invisible until somebody opens the file. This is the hand-edit the command exists to
123
+ remove.
124
+ - **Refuses rather than half-doing it.** No description and no `--desc` → refused. A name
125
+ already used in another tier → refused. An entry already there → refused unless
126
+ `--replace`. `--dry-run` prints the identical plan and writes nothing.
127
+ - **Writes `CANON.md` at the workspace root** if the workspace has none, so an agent
128
+ arriving cold finds the scheme by looking at the workspace rather than by being told.
129
+ Most workspaces already have it at birth — `augur init` scaffolds one and the seed ships
130
+ one — because the workspace whose names have already drifted is exactly the one that has
131
+ been worked in for a month without anybody promoting anything.
132
+
133
+ Promotion is also how a planned page becomes a real one: a slug listed in `space.json`
134
+ `pendingPages` shows on the site as a roadmap entry and drops off by itself the moment
135
+ `pages/<slug>/` exists.
136
+
137
+ ## Checking it
138
+
139
+ ```bash
140
+ augur canon check
141
+ ```
142
+
143
+ Fails on the things that make a name un-findable: a name that is not lowercase-hyphen, a
144
+ name carrying a version or a date, two tiers holding one name, an entry with no
145
+ `index.html`, an entry with no description, and a skill reference that does not resolve
146
+ from where the entry sits. Reports as advice: a near-miss qualifier, a name over four
147
+ words, a prototype shadowing a canonical name, a missing `CANON.md`.
148
+
149
+ A green run says the names are findable. It cannot say they are the right names for the
150
+ things — whether `invoice-detail` is the screen a person would ask for by that name is a
151
+ review question, and no lint has ever been able to answer it.
@@ -0,0 +1,88 @@
1
+ # Canvas — live multiplayer whiteboards, and when to suggest one
2
+
3
+ Augur has an infinite-canvas layer: sticky notes, shapes, text, images, tables,
4
+ drawings, arrows, sections, stamps, and **live prototype tiles** — all
5
+ multiplayer (shared cursors, presence, co-typing) with an agent able to join the
6
+ room as a visible participant. A canvas IS a prototype (a small loader page in
7
+ the workspace repo), so boards publish, share, and comment like any other prototype.
8
+
9
+ The deep reference — node schemas, the co-work protocol, engine internals — is
10
+ **`../CANVAS.md`**. This file is the agent-facing contract only.
11
+
12
+ ## Suggest it — the ask-shape rule
13
+
14
+ Canvas is a tool in your belt. When a request is **board-shaped, offer it** (one
15
+ line: "this feels like a board — want me to set up a canvas?"); don't silently
16
+ build one, don't wait to be asked:
17
+
18
+ - "brainstorm / explore options / how might we…" → stickies + sections
19
+ - comparing variants side by side → tiles of the alternatives + annotation
20
+ - mapping a flow / journey / timeline / system → shapes + arrows + sections
21
+ - workshop-style input from several people → a shared board beats a doc
22
+ - reviewing many screens at once → prototype tiles arranged spatially
23
+
24
+ ## Making a board
25
+
26
+ Copy any existing board folder — a short loader (`window.GV_CANVAS = {name}` +
27
+ the two engine tags) — into `<opportunity>/prototypes/<board>/`, or use the
28
+ in-app "+ New canvas" button (signed-in users). Publish like any prototype.
29
+ Boards are public by the same obscure-share-link model as prototypes.
30
+
31
+ ## Reading and writing a board
32
+
33
+ - **Read:** `GET /__board?path=/<opportunity>/<board>/` → `{doc}`, where `doc` is
34
+ `{name, nameV, nodes, tombs, clock}` (or `{doc: null}` if the board was never
35
+ saved). `nodes` and `tombs` live INSIDE `doc`. Node types and their exact
36
+ fields: **`../CANVAS.md` § "Node schemas"** — the single write contract
37
+ (positions in world px, `rich` HTML whitelist, image `desc` rules).
38
+ - **Write (full-state):** `POST /__board?path=…` with the body wrapped in a doc
39
+ envelope — `{"doc": {…, "nodes": [...]}}`. A bare node array (or any body
40
+ without `doc.nodes` as an array) 400s.
41
+ - **Versions:** every node carries `v` + `vn` under last-writer-wins. Writing
42
+ through the proper doors (the ClawdCanvas client, `GVCanvas.addNode`, the
43
+ in-page editor) bumps automatically. Hand-rolling a full-state write over an
44
+ existing board: bump each modified node's `v` above what you read, or the room
45
+ keeps its copy.
46
+ - **Images** upload via `POST /__asset` (content-hashed, immutable) — content
47
+ type must be `image/jpeg|png|webp|gif` (else **415**), 4MB cap (else **413**);
48
+ they read back at `GET /__asset/<40-hex-hash>`. Or point `src` at an image
49
+ committed in the workspace repo. Never write new data-URLs.
50
+
51
+ ## Co-working live (the default when changing a board)
52
+
53
+ Join the board's room as a visible agent and stream per-node ops — never a
54
+ full-state `POST /__board` while people are on it. The client:
55
+ `../scripts/clawd-canvas.mjs` (`ClawdCanvas`; needs **Node 22+** for the global
56
+ WebSocket) — connect, then `moveCursorTo`, `pose('thinking'|'sparkles'|…)`,
57
+ `say()/unsay()`, `focus(id)`, `upsert/del/rename`, `dragNode`, `typeNode`,
58
+ `status()`. Long sessions run the daemon (`node clawd-canvas.mjs daemon
59
+ <boardPath> <cmdFile>` — launch detached; identity is derived, don't pass
60
+ `--name` unless it's a `--sibling` agent — the daemon rejects a bare `--name`).
61
+
62
+ **Show activity first:** the human watches the canvas, not your terminal. On any
63
+ ask, your first move is visual — walk to the spot, pose, say what you're doing,
64
+ stub the placeholder — *then* do the real work, and delete the stub when the
65
+ artifact lands. Full protocol + daemon command set: **`../CANVAS.md` § "Working
66
+ on the canvas"**.
67
+
68
+ ⏳ **A room is named by the PATH THE CLIENT SENDS, and that is not where this is
69
+ going.** Today the path you pass is the room's identity, so two boards at the same
70
+ path are the same room and the server takes the client's word for which one it is.
71
+ Deriving the name server-side from the workspace plus the path is planned and not
72
+ built. Nothing in this doc depends on which it is — you pass the board's path
73
+ either way — but do not build anything that relies on choosing a room name, and do
74
+ not read today's behaviour as a guarantee.
75
+
76
+ **Origins:** with a deploy shell next door the client resolves them itself. From
77
+ a bare workspace clone it works too: `space.json`'s `siteOrigin` supplies the site
78
+ and the client connects through the site's `/__rt` proxy. Env overrides:
79
+ `CANVAS_SITE_ORIGIN`, `CANVAS_RT_ORIGIN`.
80
+
81
+ ## Testing near canvases
82
+
83
+ A test that opens a canvas page (or connects a client) **joins the real room and
84
+ writes real data**. Isolate the room path onto a throwaway path — and it **must
85
+ be under `/__test/`**: only `/__test/` rooms are RAM-only, every other path gets
86
+ real DO SQLite + KV writes (there is no self-healing for a non-`/__test/` path).
87
+ Use the `Object.defineProperty` clobber in **`../CANVAS.md` § "Multiplayer"** and
88
+ block `POST **/__board` in Playwright routes.