@nervur-org/dock 0.3.0

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 (285) hide show
  1. package/GETTING_STARTED.md +128 -0
  2. package/LICENSE +202 -0
  3. package/NOTICE +6 -0
  4. package/README.md +37 -0
  5. package/api/quo-api.md +196 -0
  6. package/api/route.ts +227 -0
  7. package/beings/GLOSSARY.md +118 -0
  8. package/beings/WORLDS.md +567 -0
  9. package/beings/avatar.ts +101 -0
  10. package/beings/carry.ts +159 -0
  11. package/beings/clock.ts +552 -0
  12. package/beings/courier.ts +107 -0
  13. package/beings/desk.ts +128 -0
  14. package/beings/doorbell.ts +129 -0
  15. package/beings/envoy.ts +218 -0
  16. package/beings/index.ts +16 -0
  17. package/beings/join.ts +51 -0
  18. package/beings/link.ts +104 -0
  19. package/beings/look.ts +139 -0
  20. package/beings/porter.ts +43 -0
  21. package/beings/presence.ts +39 -0
  22. package/beings/quo-app-bells.md +280 -0
  23. package/beings/quo-dock.md +1942 -0
  24. package/beings/setup.ts +45 -0
  25. package/beings/side.ts +60 -0
  26. package/beings/user.ts +459 -0
  27. package/beings/way.ts +65 -0
  28. package/cli/bundles.ts +20 -0
  29. package/cli/client.ts +73 -0
  30. package/cli/daemon.ts +581 -0
  31. package/cli/estate/Caddyfile +33 -0
  32. package/cli/estate/quo.service +35 -0
  33. package/cli/estate/systems.quo.plist +44 -0
  34. package/cli/estate.ts +48 -0
  35. package/cli/folder.ts +27 -0
  36. package/cli/oauth.ts +32 -0
  37. package/cli/pilot.ts +38 -0
  38. package/cli/quo-dock.md +1942 -0
  39. package/cli/quo.ts +203 -0
  40. package/cli/stand.ts +160 -0
  41. package/dist/api/route.d.ts +21 -0
  42. package/dist/api/route.js +193 -0
  43. package/dist/beings/avatar.d.ts +32 -0
  44. package/dist/beings/avatar.js +100 -0
  45. package/dist/beings/carry.d.ts +12 -0
  46. package/dist/beings/carry.js +174 -0
  47. package/dist/beings/clock.d.ts +161 -0
  48. package/dist/beings/clock.js +528 -0
  49. package/dist/beings/courier.d.ts +50 -0
  50. package/dist/beings/courier.js +96 -0
  51. package/dist/beings/desk.d.ts +53 -0
  52. package/dist/beings/desk.js +135 -0
  53. package/dist/beings/doorbell.d.ts +78 -0
  54. package/dist/beings/doorbell.js +133 -0
  55. package/dist/beings/envoy.d.ts +54 -0
  56. package/dist/beings/envoy.js +211 -0
  57. package/dist/beings/index.d.ts +14 -0
  58. package/dist/beings/index.js +16 -0
  59. package/dist/beings/join.d.ts +15 -0
  60. package/dist/beings/join.js +42 -0
  61. package/dist/beings/link.d.ts +14 -0
  62. package/dist/beings/link.js +91 -0
  63. package/dist/beings/look.d.ts +30 -0
  64. package/dist/beings/look.js +104 -0
  65. package/dist/beings/porter.d.ts +14 -0
  66. package/dist/beings/porter.js +41 -0
  67. package/dist/beings/presence.d.ts +8 -0
  68. package/dist/beings/presence.js +21 -0
  69. package/dist/beings/setup.d.ts +3 -0
  70. package/dist/beings/setup.js +39 -0
  71. package/dist/beings/side.d.ts +32 -0
  72. package/dist/beings/side.js +37 -0
  73. package/dist/beings/user.d.ts +315 -0
  74. package/dist/beings/user.js +462 -0
  75. package/dist/beings/way.d.ts +19 -0
  76. package/dist/beings/way.js +28 -0
  77. package/dist/cli/bundles.d.ts +5 -0
  78. package/dist/cli/bundles.js +17 -0
  79. package/dist/cli/client.d.ts +15 -0
  80. package/dist/cli/client.js +58 -0
  81. package/dist/cli/daemon.d.ts +50 -0
  82. package/dist/cli/daemon.js +584 -0
  83. package/dist/cli/estate/Caddyfile +33 -0
  84. package/dist/cli/estate/quo.service +35 -0
  85. package/dist/cli/estate/systems.quo.plist +44 -0
  86. package/dist/cli/estate.d.ts +5 -0
  87. package/dist/cli/estate.js +50 -0
  88. package/dist/cli/folder.d.ts +2 -0
  89. package/dist/cli/folder.js +25 -0
  90. package/dist/cli/oauth.d.ts +2 -0
  91. package/dist/cli/oauth.js +32 -0
  92. package/dist/cli/pilot.d.ts +5 -0
  93. package/dist/cli/pilot.js +22 -0
  94. package/dist/cli/quo.d.ts +2 -0
  95. package/dist/cli/quo.js +201 -0
  96. package/dist/cli/stand.d.ts +37 -0
  97. package/dist/cli/stand.js +110 -0
  98. package/dist/dock/agents.d.ts +102 -0
  99. package/dist/dock/agents.js +105 -0
  100. package/dist/dock/apns.d.ts +27 -0
  101. package/dist/dock/apns.js +98 -0
  102. package/dist/dock/console.d.ts +6 -0
  103. package/dist/dock/console.js +20 -0
  104. package/dist/dock/dialers.d.ts +56 -0
  105. package/dist/dock/dialers.js +75 -0
  106. package/dist/dock/faculty.d.ts +24 -0
  107. package/dist/dock/faculty.js +142 -0
  108. package/dist/dock/fcm.d.ts +13 -0
  109. package/dist/dock/fcm.js +77 -0
  110. package/dist/dock/grants.d.ts +41 -0
  111. package/dist/dock/grants.js +99 -0
  112. package/dist/dock/http2.d.ts +4 -0
  113. package/dist/dock/http2.js +68 -0
  114. package/dist/dock/index.d.ts +41 -0
  115. package/dist/dock/index.js +113 -0
  116. package/dist/dock/local.d.ts +13 -0
  117. package/dist/dock/local.js +44 -0
  118. package/dist/dock/location.d.ts +19 -0
  119. package/dist/dock/location.js +11 -0
  120. package/dist/dock/notifications.d.ts +38 -0
  121. package/dist/dock/notifications.js +60 -0
  122. package/dist/dock/push.d.ts +79 -0
  123. package/dist/dock/push.js +132 -0
  124. package/dist/dock/service.d.ts +4 -0
  125. package/dist/dock/service.js +107 -0
  126. package/dist/dock/timer.d.ts +52 -0
  127. package/dist/dock/timer.js +149 -0
  128. package/dist/dock/webpush.d.ts +12 -0
  129. package/dist/dock/webpush.js +144 -0
  130. package/dist/harbor/browser.d.ts +15 -0
  131. package/dist/harbor/browser.js +82 -0
  132. package/dist/harbor/capacitor.d.ts +28 -0
  133. package/dist/harbor/capacitor.js +218 -0
  134. package/dist/harbor/disk.d.ts +27 -0
  135. package/dist/harbor/disk.js +249 -0
  136. package/dist/harbor/edge/alarm.d.ts +10 -0
  137. package/dist/harbor/edge/alarm.js +38 -0
  138. package/dist/harbor/edge/edge.d.ts +54 -0
  139. package/dist/harbor/edge/edge.js +370 -0
  140. package/dist/harbor/edge/exercise.d.ts +7 -0
  141. package/dist/harbor/edge/exercise.js +232 -0
  142. package/dist/harbor/edge/given.d.ts +26 -0
  143. package/dist/harbor/edge/given.js +42 -0
  144. package/dist/harbor/edge/platform.d.ts +39 -0
  145. package/dist/harbor/edge/storage.d.ts +30 -0
  146. package/dist/harbor/edge/storage.js +180 -0
  147. package/dist/harbor/edge/worker.d.ts +17 -0
  148. package/dist/harbor/edge/worker.js +67 -0
  149. package/dist/harbor/files.d.ts +15 -0
  150. package/dist/harbor/files.js +220 -0
  151. package/dist/harbor/http.d.ts +19 -0
  152. package/dist/harbor/http.js +177 -0
  153. package/dist/harbor/idb.d.ts +15 -0
  154. package/dist/harbor/idb.js +0 -0
  155. package/dist/harbor/quo.d.ts +10 -0
  156. package/dist/harbor/quo.js +42 -0
  157. package/dist/harbor/resolve.d.ts +16 -0
  158. package/dist/harbor/resolve.js +17 -0
  159. package/dist/harbor/seal.d.ts +3 -0
  160. package/dist/harbor/seal.js +25 -0
  161. package/dist/harbor/sealed.d.ts +35 -0
  162. package/dist/harbor/sealed.js +162 -0
  163. package/dist/harbor/tauri.d.ts +16 -0
  164. package/dist/harbor/tauri.js +59 -0
  165. package/dist/harbor/ward.d.ts +9 -0
  166. package/dist/harbor/ward.js +15 -0
  167. package/dist/human/app.d.ts +32 -0
  168. package/dist/human/app.js +527 -0
  169. package/dist/human/apps.d.ts +10 -0
  170. package/dist/human/apps.js +29 -0
  171. package/dist/human/dom.d.ts +2 -0
  172. package/dist/human/dom.js +15 -0
  173. package/dist/human/door.d.ts +19 -0
  174. package/dist/human/door.js +92 -0
  175. package/dist/human/guest.d.ts +3 -0
  176. package/dist/human/guest.js +33 -0
  177. package/dist/human/html.d.ts +55 -0
  178. package/dist/human/html.js +451 -0
  179. package/dist/human/local.d.ts +7 -0
  180. package/dist/human/local.js +10 -0
  181. package/dist/human/mark.d.ts +8 -0
  182. package/dist/human/mark.js +47 -0
  183. package/dist/human/move.d.ts +17 -0
  184. package/dist/human/move.js +90 -0
  185. package/dist/human/screen.d.ts +19 -0
  186. package/dist/human/screen.js +119 -0
  187. package/dist/human/style.d.ts +2 -0
  188. package/dist/human/style.js +60 -0
  189. package/dist/human/tab.bundle.txt +4775 -0
  190. package/dist/human/tab.d.ts +15 -0
  191. package/dist/human/tab.js +409 -0
  192. package/dist/human/tree.d.ts +50 -0
  193. package/dist/human/tree.js +157 -0
  194. package/dist/human/wake.d.ts +34 -0
  195. package/dist/human/wake.js +179 -0
  196. package/dist/human/web.d.ts +33 -0
  197. package/dist/human/web.js +184 -0
  198. package/dist/human/worker.bundle.txt +3868 -0
  199. package/dist/human/worker.d.ts +1 -0
  200. package/dist/human/worker.js +81 -0
  201. package/dist/human/worlds.d.ts +24 -0
  202. package/dist/human/worlds.js +99 -0
  203. package/dist/mcp/agent.d.ts +10 -0
  204. package/dist/mcp/agent.js +78 -0
  205. package/dist/mcp/allow.d.ts +20 -0
  206. package/dist/mcp/allow.js +88 -0
  207. package/dist/mcp/http.d.ts +27 -0
  208. package/dist/mcp/http.js +92 -0
  209. package/dist/mcp/oauth.d.ts +91 -0
  210. package/dist/mcp/oauth.js +241 -0
  211. package/dist/mcp/route.d.ts +15 -0
  212. package/dist/mcp/route.js +42 -0
  213. package/dist/mcp/runner.d.ts +45 -0
  214. package/dist/mcp/runner.js +99 -0
  215. package/dist/mcp/server.d.ts +11 -0
  216. package/dist/mcp/server.js +102 -0
  217. package/dock/agents.ts +121 -0
  218. package/dock/apns.ts +138 -0
  219. package/dock/console.ts +23 -0
  220. package/dock/dialers.ts +85 -0
  221. package/dock/faculty.ts +148 -0
  222. package/dock/fcm.ts +103 -0
  223. package/dock/grants.ts +111 -0
  224. package/dock/http2.ts +70 -0
  225. package/dock/index.ts +133 -0
  226. package/dock/local.ts +48 -0
  227. package/dock/location.ts +22 -0
  228. package/dock/notifications.ts +67 -0
  229. package/dock/push.ts +161 -0
  230. package/dock/quo-app-bells.md +280 -0
  231. package/dock/quo-dock.md +1942 -0
  232. package/dock/service.ts +100 -0
  233. package/dock/timer.ts +174 -0
  234. package/dock/webpush.ts +182 -0
  235. package/harbor/browser.ts +97 -0
  236. package/harbor/capacitor.ts +223 -0
  237. package/harbor/disk.ts +237 -0
  238. package/harbor/edge/alarm.ts +48 -0
  239. package/harbor/edge/edge.ts +407 -0
  240. package/harbor/edge/exercise.ts +241 -0
  241. package/harbor/edge/given.ts +106 -0
  242. package/harbor/edge/platform.d.ts +39 -0
  243. package/harbor/edge/storage.ts +179 -0
  244. package/harbor/edge/text.d.ts +15 -0
  245. package/harbor/edge/worker.ts +70 -0
  246. package/harbor/edge/wrangler.toml +30 -0
  247. package/harbor/files.ts +221 -0
  248. package/harbor/http.ts +188 -0
  249. package/harbor/idb.ts +0 -0
  250. package/harbor/quo-harbor.md +850 -0
  251. package/harbor/quo.ts +44 -0
  252. package/harbor/resolve.ts +31 -0
  253. package/harbor/seal.ts +26 -0
  254. package/harbor/sealed.ts +183 -0
  255. package/harbor/tauri.ts +79 -0
  256. package/harbor/ward.ts +28 -0
  257. package/human/app.ts +580 -0
  258. package/human/apps.ts +47 -0
  259. package/human/dom.ts +21 -0
  260. package/human/door.ts +113 -0
  261. package/human/guest.ts +34 -0
  262. package/human/html.ts +490 -0
  263. package/human/local.ts +30 -0
  264. package/human/mark.ts +53 -0
  265. package/human/move.ts +122 -0
  266. package/human/quo-human.md +1042 -0
  267. package/human/screen.ts +136 -0
  268. package/human/style.ts +63 -0
  269. package/human/tab.bundle.txt +4775 -0
  270. package/human/tab.ts +446 -0
  271. package/human/tree.ts +217 -0
  272. package/human/wake.ts +191 -0
  273. package/human/web.ts +259 -0
  274. package/human/worker.bundle.txt +3868 -0
  275. package/human/worker.ts +124 -0
  276. package/human/worlds.ts +127 -0
  277. package/mcp/agent.ts +94 -0
  278. package/mcp/allow.ts +131 -0
  279. package/mcp/http.ts +92 -0
  280. package/mcp/oauth.ts +270 -0
  281. package/mcp/quo-mcp.md +343 -0
  282. package/mcp/route.ts +45 -0
  283. package/mcp/runner.ts +136 -0
  284. package/mcp/server.ts +101 -0
  285. package/package.json +121 -0
@@ -0,0 +1,567 @@
1
+ # WORLDS
2
+
3
+ This is how Quo is proposed to a person and to an organisation. It sits
4
+ beside `quo/SPEC.md` and adds no word to it. The spec says what a
5
+ harbor, a ward and a being are, and what crosses a door. This paper says
6
+ what to make of them, so that any setup, from one person with a phone to
7
+ an organisation with ten thousand members, is reasoned in the same words.
8
+ `papers/quo-dock.md` and the papers of its sides follow this one; an
9
+ estate's paper follows all of them. It binds the dock and the estates, never
10
+ the library.
11
+
12
+ It is written in four parts, in this order, because the order is the
13
+ honesty of the paper. First, what Quo allows, which is more than we use.
14
+ Second, the choices we make inside that, each one named as a choice, with
15
+ what Quo would also have allowed and why we chose as we did. Third, the
16
+ world those choices make, home, presence, membership, envoy, route and
17
+ device, narrated once. Fourth, real organisations at every distance from
18
+ Quo, so that the reader finds their own stage and sees the next one. An
19
+ implementer who reads only the first part and builds something unlike the
20
+ rest is still building Quo.
21
+
22
+ ## What Quo allows
23
+
24
+ Quo is three words. A **harbor** is the program a device runs to boot
25
+ wards; it owns the wire and the operating system and is nobody outside its
26
+ device. A **ward** is one process of its harbor, a seed, a partition and a
27
+ body of code, named outward by one public key derived from the seed. A
28
+ **being** is one ordinary object with one voice, living in a ward, with no
29
+ address of her own. Nothing else is Quo.
30
+
31
+ Between beings there is one kind of relation, with two ends. A **standing**
32
+ is a pointer a being holds to another being, through which she asks. An
33
+ **occupant** is a being she invited, whom her ward names when she asks.
34
+ Every relation is born of an **invitation** minted by one side and a
35
+ **knock** by the other, carries two keys, one minted by each side, and ends
36
+ by one side removing it. What a being answers to an occupant is decided by
37
+ her **gate**, which is asked for every describe and every dispatch, and it
38
+ is the whole of permission in Quo: there is no second list anywhere.
39
+
40
+ Two things stand at the edges. A harbor keeps the ask pointer of a ward it
41
+ booted, so it is that ward's **root**, and the root may invite on any being
42
+ of its ward and reach into any of them; that is total, and it stops at the
43
+ device. And a ward may hold one **public being**, who answers anyone at all
44
+ as `{}`, the way every stranger is at every door. What a device can do,
45
+ its clock, its screen, its lines to vendors, it offers by **lend**, as
46
+ beings in a ward of its own that another ward's being reaches by holding a
47
+ standing, exactly as she reaches a being on another planet.
48
+
49
+ That is the whole of it, and this is what it leaves open:
50
+
51
+ - **Quo has no person and no organisation.** A ward has an owner in the
52
+ sense that a root booted it, and no other sense. Who a human is, whether
53
+ two wards are the same party, and what a company is, are not questions
54
+ Quo answers.
55
+ - **Quo has no home.** Three boxes rooted by one party, each holding
56
+ standings on the other two, is Quo, and so is one box with a hundred
57
+ wards. Nothing says which ward, if any, is the one that matters.
58
+ - **Quo has no route.** How bytes arrive at a device is the harbor's
59
+ directory, and Quo says nothing about it. A hostname, a socket, a screen
60
+ and a tool list are all outside the protocol.
61
+ - **Quo has four rungs and no more.** A stranger hears the public being as
62
+ `{}`. An occupant hears what the gate shows that occupant. An owner
63
+ reaches in. A root holds the ask pointer. Guest, member, subscriber,
64
+ admin: every one of those is an occupant, told apart by the gate and by
65
+ nothing else.
66
+ - **Quo has no outside.** A vendor's API, a bank, a mail server, a model at
67
+ its client: to Quo each is either a being someone booted to speak for it,
68
+ or nothing.
69
+
70
+ Everything from here on is one way of filling those gaps. It is our way,
71
+ it is opinionated, and another implementer may fill them otherwise and
72
+ interoperate with us at every door, because a door judges keys and not
73
+ opinions.
74
+
75
+ ## The choices
76
+
77
+ Six choices, each in the same shape: what Quo allows, what we choose, and
78
+ why. Every later sentence of this paper rests on one of them, and a reader
79
+ who disagrees with a choice knows exactly which sentences fall with it.
80
+
81
+ ### The unit is the org
82
+
83
+ Quo allows any party to be the "you" a world is about, or no party at all.
84
+
85
+ We choose the **org**. Every "you" in this paper, in the dock and in the
86
+ estates is an organisation: a company, a family, a club, a service, and at
87
+ the smallest, one human alone, who is an org of one. An org owns wards,
88
+ holds standings, trusts boxes and is trusted by others. A human is never
89
+ modelled as something smaller than an org, and an avatar, an account or a
90
+ user id is never the "you"; each of those is a thing an org holds.
91
+
92
+ Why: one grammar reaches every size. What is said of a family with a box is
93
+ said, word for word, of a person with a phone and of a service with ten
94
+ thousand subscribers. The moment a person and an organisation are two
95
+ kinds of thing, every rule is written twice and the two drift.
96
+
97
+ ### One home per org
98
+
99
+ Quo allows an org to root three boxes and call each one home, or to have
100
+ no place it calls home.
101
+
102
+ We choose **one home per org**, and any number of harbors under it. Home
103
+ is the one ward the org owns on a box it trusts, its own being is the org's
104
+ being, and every relation of the org meets there.
105
+
106
+ Why: the fog. Three homes each hold part of the org, and the day the org
107
+ wants to act as one, "when mail lands in A, tell a friend from B and write
108
+ it down in C", it needs one place that sees all three, and that place is a
109
+ fourth home standing over them, which is one home with three harbors under
110
+ it. Several homes is not a richer arrangement Quo permits and we forbid. It
111
+ is an arrangement that collapses into one home the first time the org
112
+ wants to think. So one home is not a cap: it is the name of the place where
113
+ the fog clears, and an org that has not built it yet is an org that cannot
114
+ yet act as one.
115
+
116
+ ### Every human is an org, with or without a home
117
+
118
+ Quo allows a human to exist only as ids in other parties' wards, and never
119
+ as a ward of her own.
120
+
121
+ We choose to say that **every human is an org from the first moment**,
122
+ whether or not that org has a home yet. A human with no box is an org of
123
+ one whose whole existence is the standings it holds in other orgs' worlds:
124
+ a customer id at a shop, a member id at a club, a presence on a phone. The
125
+ day a box is trusted, a home is booted fresh for that org, and it joins
126
+ each of those memberships from there. Nothing is converted and no id
127
+ changes; the org gains a home and keeps everything it had.
128
+
129
+ Why: the walk. Nobody switches to Quo, and a person who has never heard of
130
+ it must already be in the model when they land on a website of ours. If a
131
+ homeless person were a different kind of thing from a person with a home,
132
+ getting a home would be a migration, and there is none. Homeless is a rung
133
+ on the org's own ladder, and the first one.
134
+
135
+ ### A route says the grammar, a credential says the rung
136
+
137
+ Quo allows a device to hear bytes any way it likes, and to treat every
138
+ arrival as a stranger.
139
+
140
+ We choose to name **three routes** into a device, and to forbid any route to
141
+ fix a rung. A route is one hostname, sent by a reverse proxy to one process,
142
+ and it says only which grammar the bytes are in:
143
+
144
+ | route | grammar |
145
+ | ------ | ------------------------------------------------ |
146
+ | `web.` | a describe as forms and a page, for a human |
147
+ | `mcp.` | a describe as tools, for a model |
148
+ | `api.` | a describe as plain HTTP and JSON, for a program |
149
+
150
+ The rung is proven by what the caller carries, and was decided by whoever
151
+ minted it. No credential is the stranger, on every route, and the stranger
152
+ hears the public being as `{}` on every route. A credential is an
153
+ invitation spent once by a knock, then keys, and it names an identity in a
154
+ world at the rung its minter gave it: an occupant, whether guest,
155
+ subscriber, member or admin, told apart by the gate; or an owner, invited
156
+ on the ward's own door. The same credential is honoured on every route, and
157
+ the same identity sees the same describe whether it arrives as forms, as
158
+ tools or as JSON. The three routes are three renderings of one describe,
159
+ and a caller on one can do nothing a caller on another cannot.
160
+
161
+ Why: a person is not a route. The owner of an estate pilots it from a model,
162
+ presses its buttons in a tab and calls it from a script, and is the same
163
+ owner in all three. A route that fixed a rung would make the same human two
164
+ parties, one per door, which is the fog again, this time inside one box.
165
+
166
+ ### A device is a harbor of the org, never a route
167
+
168
+ Quo allows a phone to be a home, a tab to be a stranger, and an app to hold
169
+ accounts of its own.
170
+
171
+ We choose that **a device in a hand is a harbor the org owns**, that every
172
+ world seen there is a presence, a ward of the org's on that device, and
173
+ that nothing in a hand is ever a home. A phone, a tablet, a laptop and a
174
+ browser tab are the same shape. The app is a browser of the org's worlds
175
+ with no account and no person of its own; who the org is lives at home.
176
+
177
+ Why: night and trust. A hand is reachable only while it dials, so nothing
178
+ runs there for the org at night, and it is lost, stolen and replaced, so no
179
+ one copy of the org is trusted to it. A home on a phone would be a home
180
+ that sleeps and may vanish, and the org would answer for the difference
181
+ every day. So the device is where the org is now, and home is where the
182
+ org is always, and the two never trade places. A device is not a fourth
183
+ route because it does not need one: it is Quo, ward to ward, and the human
184
+ touching it is an occupant of a ward that is theirs.
185
+
186
+ ### A SaaS is an org that has not heard of Quo
187
+
188
+ Quo allows nothing outside its three words, so a vendor's API is not Quo
189
+ and cannot be spoken to.
190
+
191
+ We choose to meet every such vendor through an **envoy**: a being booted on
192
+ the org's side who speaks that vendor's surface, narrowed to what the org
193
+ exposes, one being per vendor and one relation per account. From inside the
194
+ org's world, Google, a bank and a booking service look exactly like orgs
195
+ on Quo, reached through a standing, because each is standing in for a ward
196
+ nobody here runs. And the mirror holds: an org on Quo is a website to every
197
+ human who has never heard of Quo, and a member's world to everyone who
198
+ has, at the same time, at the same doors.
199
+
200
+ Why: Quo bends the SaaS world and cannot wait for it to disappear. An org
201
+ must adopt Quo while every vendor it depends on stays as it is, and must
202
+ serve every customer who never adopts it. Both directions are envoys and
203
+ routes, and neither needs the other side to move.
204
+
205
+ ## The world those choices make
206
+
207
+ ### Three questions, three words
208
+
209
+ Each word of Quo answers one question for an org, and nothing else answers
210
+ it.
211
+
212
+ | word | the question | what it settles |
213
+ | ------ | ------------ | ------------------------------------------- |
214
+ | harbor | whose box | trust: who holds the root, who can reach in |
215
+ | ward | whose world | ownership: one seed, one owner, moves whole |
216
+ | being | whose voice | a role inside a world |
217
+
218
+ A harbor is a device and belongs to the org that holds it. A ward is the
219
+ unit that is owned and the unit that moves: it goes to another box whole,
220
+ and every standing it holds survives, because its pk is the same there. A
221
+ being is one voice inside a ward, and what she may be asked is her gate.
222
+
223
+ **Ownership decides the level, and nothing else does.** A thing is a being
224
+ in the ward of the org that owns it, and the default is always that. A chat
225
+ between two members of an org is a being in the org's ward. A chat between
226
+ two people with no org between them is a being in the home of whichever
227
+ hosts it, the other an occupant through their own home. A ward is booted
228
+ only where a thing must be owned by nobody among its members, so that it
229
+ can move whole or stand on a box none of them fully trusts; and then it is
230
+ an org, however small, with an org's home beside it. How rich a being's
231
+ occupant logic is never promotes her. Only ownership does, and promotion is
232
+ not a migration: a being's cells do not cross into another ward, so
233
+ becoming a ward is a new ward booted, the same class placed in it, and the
234
+ members invited again.
235
+
236
+ Every ward on any harbor is one of three kinds, and there is no fourth:
237
+
238
+ ```
239
+ a home an org's world, one owner, moves whole
240
+ a presence a world's foothold on a device in someone's hand
241
+ the box's own what this harbor lends, one per harbor, never moves
242
+ ```
243
+
244
+ **A harbor boots one ward of its own.** It keeps that ward's ask pointer,
245
+ so it is its root, and everything the box can offer lives there as beings:
246
+ its location, its notifications, its timer, its way of ringing a phone, its
247
+ line to a store, its account at a vendor. A being of any other ward reaches
248
+ one by `lend`, and what she gets is a standing, counted and rotated and
249
+ removable, like every other relation she holds. That ward never moves. Its
250
+ beings are the box's, they die with the box, and a home that moves to
251
+ another box is lent that box's instead. What the org wants asked by others,
252
+ a front desk, a clock with its schedules, is a being with a door in the
253
+ org's home like any other being of theirs.
254
+
255
+ ### An org is three things
256
+
257
+ One org on Quo is three kinds of thing, each on a harbor of different
258
+ trust, each with a different job. For a human alone the three are the
259
+ same three.
260
+
261
+ - **Home** is the one ward the org owns on a harbor it trusts. Its own
262
+ being is the org's being: for a company, its org being; for a human, her
263
+ user being. Inside it live the org's envoys, its avatars and its rules.
264
+ Home runs day and night and is the only thing of the org's that must
265
+ never be lost. A home may stand on a box the org does not run, a
266
+ family's or a host's, and the day the org has a box of its own the home
267
+ moves there whole, and nobody who holds a standing at it is told.
268
+ - **Presence** is a ward the org owns on a harbor in a hand: a phone, a
269
+ desk, a browser tab. It is where the org is now: the screen someone
270
+ touches and what that box lends, GPS, camera, a keychain, each a standing
271
+ the org's being there holds at a being of the box's own ward. It holds
272
+ one standing at home, home holds one back to wake it, and it sees exactly
273
+ what home's gate shows that device. A lost phone is one standing removed
274
+ at home, and nothing of the org is lost.
275
+ - **Membership** is an id in a ward another org owns: an employee id at an
276
+ employer's being, a member id at a party's, a customer id at a shop's.
277
+ Nothing of the org lives there but the id and the key. Home holds a
278
+ standing at it, and it holds one back to push. The other org ends it by
279
+ removing one standing, and home loses that and nothing else.
280
+
281
+ A membership is never a ward of the org's, because a ward it does not own
282
+ is not its. A presence is never home, because its seed was minted where
283
+ the org happened to be. Home is one, presences are as many as the org's
284
+ devices, and memberships are as many as the orgs that know it.
285
+
286
+ Read from the other side, the same three words hold. An organisation's
287
+ home is its ward. Its members are ids at its beings, however many. Ten
288
+ thousand subscribers of a service are ten thousand memberships in the
289
+ service's ward, not ten thousand homes: their homes are elsewhere, or do
290
+ not exist yet, and each subscriber is an org of one either way. A ward is a
291
+ process, and that is the only way ten thousand fit.
292
+
293
+ **A home changes hands, and the change is one act.** A child's home is a
294
+ ward the parent's org owns until the child does; a friend's, one the family
295
+ runs until he has a box. Before that day the host's presences hold the
296
+ door and the child's do not. The day itself is the root minting the child's
297
+ own being the owner standing on that ward, `home`, and stepping back, which
298
+ is what setup does for everyone at boot and may do later. Nothing moves,
299
+ nobody is told, and from then on the door is the child's.
300
+
301
+ **Trust is the root, and it is total.** Whoever holds a box's root can
302
+ read every home on it, partitions and keys, and can reach into any being
303
+ there. A household's privacy toward each other is its trust in whoever
304
+ runs the box, not cryptography, and a home that wants more than that moves
305
+ to a box of its own. That is the whole meaning of "a harbor it trusts",
306
+ and it is read before a home is booted on somebody else's droplet.
307
+
308
+ ### The hub is home
309
+
310
+ Every device, every model, every account and every membership of the org is
311
+ either an occupant of its home or a standing its home holds, and most are
312
+ both. The gate of the org's being is its whole permission model: what its
313
+ phone may ask, what its model may ask, what an employer may push. There is
314
+ no second list.
315
+
316
+ A rule, "when Calendly books, add it to Google", is home answering one
317
+ standing by asking another. There is no trigger vocabulary and no product
318
+ between the two: one being holds both standings and a method joins them.
319
+ Rules run where the hub is, so rules need a home, and that is what a home
320
+ gives an org that a presence cannot: something happens for it at night.
321
+
322
+ ### Everything outside is one relation
323
+
324
+ Everything outside a world relates to it the same way: a standing in, a
325
+ standing back, or both, placed by a knock on an invitation. Two questions
326
+ decide the shape, and nothing else does.
327
+
328
+ **Does it speak Quo?** If it does, a standing goes straight at its door. An
329
+ employer's harbor, a party's, the org's own phone: each has a ward with a
330
+ door, and the org knocks there. Nobody stands in for it.
331
+
332
+ If it does not, an envoy stands in its place. A Google account, a Calendly
333
+ account, a model at its vendor's client, a shop with an old checkout: each
334
+ is a ward nobody here runs, on a harbor nobody here owns, that speaks no
335
+ Quo. So a being is booted in the box's own ward who speaks that vendor's
336
+ surface, narrowed to what is exposed. One being per vendor and one relation
337
+ per account: the credentials are in her cells, the occupant's notes say
338
+ which account a caller is, and a caller never names either. What home holds
339
+ is the standing, so a home that moves box carries no credential and is
340
+ placed again where it lands.
341
+
342
+ **Does it call in?** If it does, it holds a standing back. A booking
343
+ arrives, a payment settles, a mail lands: the outside thing's bytes reach
344
+ the box, since the box owns the wire, and they reach the envoy's own body,
345
+ because she is the being who claimed that path or opened that line at her
346
+ birth. She checks the signature, keeps the delivery id so a retry lands
347
+ once, and asks the right occupant on the right standing. Nothing arrives at
348
+ a door that nobody invited, and whoever is woken cannot tell a webhook from
349
+ a clock, and must not. If it does not call in, the relation is one way, and
350
+ an envoy on a phone is one way by construction, because nothing calls in
351
+ to a phone.
352
+
353
+ ### Three routes, one describe
354
+
355
+ An org's box hears the world on three routes, and a route is a hostname the
356
+ reverse proxy sends to one process. `web.` speaks a being's describe as
357
+ forms and a page, for a human at a screen. `mcp.` speaks it as tools, for a
358
+ model at its client. `api.` speaks it as plain HTTP and JSON, for a
359
+ program, a script or a tab on another origin. A fourth voice, the `quo`
360
+ command on the device itself, speaks it as lines, and reaches the daemon's
361
+ socket rather than a hostname.
362
+
363
+ Every route hears the same four rungs, and hears them the same way:
364
+
365
+ - **A stranger** carries nothing and hears the public being as `{}`, on
366
+ every route alike: as the front desk's first hello, as a public board or
367
+ a catalogue in JSON, as the public being's asks listed as tools. A world
368
+ with no public being answers a stranger silence, on every route alike.
369
+ - **An occupant** carries a credential: an invitation spent once, then
370
+ keys held by an avatar in the org's world. What the occupant hears is the
371
+ gate's answer for that identity, and it is the same answer on every
372
+ route. Guest, subscriber, member and admin are all occupants, and the
373
+ gate is what tells them apart.
374
+ - **An owner** is an occupant of the ward's own door, invited there by
375
+ the root, and reaches into any being of it. The owner creates and
376
+ places, and never does the work: the work goes through an avatar under a
377
+ gate, so every arrival is named and judged.
378
+ - **The root** holds the ask pointer, on the device and nowhere else, and
379
+ is no occupant of anything.
380
+
381
+ A model, a human and a program that hold the same credential are one
382
+ identity, and the org sees one occupant whichever route it came in on. That
383
+ is what makes an estate pilotable from a model, a browser and a script in
384
+ the same day by the same hand, with one gate deciding for all three. A
385
+ model is not a special kind of caller: it is a presence that acts, holding
386
+ one standing, seeing what the gate shows it, and what it does arrives home
387
+ named and counted, exactly as a tap on a phone would.
388
+
389
+ ### The device and the app
390
+
391
+ A Quo app is a browser of worlds and nothing of the org. It has no account,
392
+ no login and no person of its own: every world it shows is a presence ward
393
+ on the device's harbor, and who the org is lives at home. So which app the
394
+ org uses is settled at home, by adding that app as a device of the org's,
395
+ and never by a link. A world's link opens whichever app the platform
396
+ verified for that world's hostname, and any Quo app that opens it is the
397
+ org's, since every one is the same browser. A world names in its claim
398
+ every app it allows to open its links, its own first. An adopter's own app
399
+ is the first app its member meets, and nothing more: from it she reaches
400
+ every world she is in, and from any other Quo app she reaches the same
401
+ worlds through home.
402
+
403
+ One OS user is one harbor. On a desk and on Android the OS has accounts,
404
+ and the app never sees the second person. A shared iPad is one org's
405
+ device, and a second org's presence on it is a ward of the second's, named
406
+ as such, under the first's lock. Building people into the app would be a
407
+ second grammar for identity beside the ward.
408
+
409
+ A tab is a device of the same shape: a harbor on a seed in the browser, a
410
+ presence ward per world, and the org's being there holding what the browser
411
+ lends. It differs from the phone only in how long its seed lives.
412
+
413
+ ### The root boots and steps back
414
+
415
+ A harbor's root is the box's, held by the device's own rule, and it is
416
+ touched once per home: it boots the home ward and mints the org's own
417
+ being an owner standing on it. From then on the owner of that home is the
418
+ org. Placing an envoy, inviting a new device, joining a membership: each is
419
+ an ask on home, shown by the gate to the org's presences and to its model,
420
+ and the box is never logged into for it. The root's shell is for the day
421
+ the root itself must act, and no other.
422
+
423
+ ### A class knows nobody
424
+
425
+ Every being is an instance of a class, and the class is written by someone
426
+ who has never met the org. An author ships a package with a Calendly
427
+ class; an estate's class file re-exports it; the harbor loads it by name;
428
+ the root boots `calendly/alice` with the token the box holds under that
429
+ name. The author sees no human, no token and no partition.
430
+
431
+ Nor does the author know the level. The same class is a being in an org's
432
+ ward today and the being of a ward of its own tomorrow, placed there by a
433
+ root's two owner asks and rewritten for none of it: its members are its
434
+ occupants, its gate reads them, its cells are its record, and which ward
435
+ boots it is never in it. A class is written to work at any level, and an
436
+ estate decides the level. That is what keeps a class from an author who
437
+ knows nobody usable by an estate that knows exactly who.
438
+
439
+ The dock provides the classes every world needs and nobody writes twice:
440
+ the user being, the avatar with its screen side and its model side, the
441
+ bell, the clock, the front desk, the faculties a box lends, and the account
442
+ base an author extends with only the vendor's part. An estate holds class
443
+ bodies and placement, and reaches every general piece through the dock.
444
+ `papers/quo-dock.md` is that catalogue.
445
+
446
+ ### The picture
447
+
448
+ ```
449
+ a box the org trusts a hand their box
450
+ ward alice (home) ward alice (presence) ward acme
451
+ alice, her user being her being there employee being
452
+ avatar "claude" <- her model ward acme (presence) id "alice" at its door
453
+ rules her being there
454
+ ward bob (home) the box's own ward
455
+ ward the-family (the estate's home) screen, GPS, keychain,
456
+ the front, the clock and its schedules notifications
457
+ the box's own ward
458
+ timer, push (web, apns, fcm),
459
+ calendly, google
460
+
461
+ standings, each placed by a knock on an invitation:
462
+ presence -> home, home -> presence her devices
463
+ home -> acme's being, acme's being -> home her memberships
464
+ home -> calendly, notes: alice an account, one way
465
+ home -> google, notes: alice an account that calls in
466
+ any being -> a faculty of its own box by lend, and never off the box
467
+
468
+ routes into the box the org trusts, one grammar each, any rung on each:
469
+ web. forms and a page mcp. tools api. HTTP and JSON
470
+ ```
471
+
472
+ ## Orgs at every distance from Quo
473
+
474
+ Four organisations, each real in shape, each at one stage. Every stage is a
475
+ state the model already holds, and no org moves from one to the next by a
476
+ migration. Nobody switches to Quo.
477
+
478
+ ### Never heard of it: a bakery
479
+
480
+ The bakery takes bookings on Calendly, payments on Stripe and mail on
481
+ Google, and will never run a harbor. To an org on Quo the bakery is three
482
+ envoys: one being per vendor in the box's own ward, each holding the
483
+ bakery's account in her cells, each reached by a standing from the org's
484
+ home. When a booking lands, Calendly's bytes reach the envoy's own body,
485
+ she checks the signature, keeps the delivery id, and asks home on the
486
+ standing home gave her; home's rule adds it to Google by asking the second
487
+ envoy. The bakery is fully in the model and has done nothing. The day it
488
+ runs a harbor, the org's standing moves from the envoy to the bakery's own
489
+ door, and the rule does not change.
490
+
491
+ ### Scouting: a person with the app, and a company with a tab
492
+
493
+ A person downloads the app and opens three links, a shop's, a club's and a
494
+ friend's. The phone is a harbor; each link boots a presence ward on it,
495
+ with the org's being there and one standing at the world it came from. The
496
+ person is an org of one with three memberships and no home. She sees all
497
+ her worlds in one place, because the app is a browser of worlds, and
498
+ nothing runs for her at night. The three orgs each know her as an id bound
499
+ to that phone's presence and nothing more.
500
+
501
+ A company's operations lead opens a supplier's world in a tab. The tab
502
+ boots a harbor on a seed in the browser, a presence ward for that world,
503
+ and the lead's being there. That tab is the company's first presence, in a
504
+ rented room: the supplier's ward knows the company by an id bound to that
505
+ tab's pk, and the company has no home. When the lead opens the same link on
506
+ her phone, the tab's ward moves in by seed and partition, rebinding the
507
+ same pk, and the supplier is told nothing.
508
+
509
+ ### Migrating from SaaS: a filings service
510
+
511
+ A filings service has subscribers, an old checkout and a new harbor. Its
512
+ home is its org ward on a droplet; its subscribers are ids at its beings,
513
+ ten thousand memberships in one process. A subscriber who has
514
+ never heard of Quo arrives on the web route as a stranger, meets the front
515
+ desk, and the checkout she pays at is still the old one, because the
516
+ service's envoy to its payment vendor stands in for it. From the moment she
517
+ pays she is an org of one whose whole existence is a membership in
518
+ a filings service's world, reached from a tab or from the app.
519
+
520
+ A second subscriber already has a home on a family box. Her home holds a
521
+ standing at a filings service's being and it holds one back to push, and she
522
+ reaches the service from her phone through home as the carrier, or
523
+ directly on a presence. The service cannot tell the two subscribers apart
524
+ by route, and does not try: each is an occupant, and the gate says what each
525
+ may ask. The service's own owner pilots it from a model on the mcp route,
526
+ presses its buttons in a tab on the web route, and runs its reports from a
527
+ script on the api route, and is one owner on all three. The old checkout
528
+ stands until the payment vendor speaks Quo or the service replaces it, and
529
+ neither day changes a subscriber's id.
530
+
531
+ ### Fully on Quo: a family estate
532
+
533
+ The family runs a droplet that never sleeps, an edge box at the house and
534
+ a Mac on a desk. The three are one estate because each holds standings on
535
+ the others, minted there and taken here, and not because they share a key;
536
+ each has its own root and each root stops at its device. The estate's home
537
+ is the family's org ward on the droplet, with the front desk, the clock and
538
+ its schedules. Each member's home is a ward on the same droplet, owned by
539
+ that member, trusted to the box the family runs. A child's home is owned
540
+ by a parent until the day the root mints the child the owner standing and
541
+ steps back. The Mac and every phone hold presences, one per world, and the
542
+ edge holds what the house can do as faculties of its own ward.
543
+
544
+ A member's model is an avatar in her home, holding one standing, seeing
545
+ what her gate shows it. Her employer is a membership, her bank an envoy,
546
+ her friend's world a standing at his home on his own box. When she moves
547
+ out and buys a box of her own, her home moves there whole, seed and
548
+ partition, and every standing she holds and every one held at her
549
+ survives, because her pk is the same there. The family is told nothing and
550
+ needs to be told nothing.
551
+
552
+ ## Vocabulary
553
+
554
+ Org, home, presence, membership, hub, rule, envoy and route are in
555
+ `papers/GLOSSARY.md`, with every other word above the spec.
556
+
557
+ ## Where the tree stands
558
+
559
+ This paper decides what the estates and the dock are held to, and one
560
+ piece of the dock is not yet in its words.
561
+
562
+ - The dock holds no org base beside the user being, and no account base
563
+ class. The first arrives when a service bought by an organisation is
564
+ read against a household, which is the pair of users that shows what an
565
+ org actually shares with a home. The second arrives with the second
566
+ vendor to need one. `papers/quo-dock.md` names the same gap from its
567
+ side.
@@ -0,0 +1,101 @@
1
+ // SPDX-License-Identifier: Apache-2.0
2
+ // The avatar. Someone outside Quo's voice: a human at a screen, a model at
3
+ // an MCP client, a model in an API loop. One class for every side. She holds
4
+ // exactly one standing, `user`, and everything her side asks goes through
5
+ // it; the user being reaches her only to push, and she hands the push to
6
+ // every side she has. A side is in-process with her, holds the object, and
7
+ // calls the four methods below: one of the two ways in, `enter` behind a
8
+ // route's proof or `join` with an invitation, then `tools` and `call`.
9
+ // Nothing of a side is in her cells.
10
+ import { isSilence, isWord, wordOf } from '@nervur-org/nervur';
11
+ import type { Answer, Blueprint, Invitation, JsonObject, OccupantRecord, Wanted } from '@nervur-org/nervur';
12
+ import { Carrier } from './carry.ts';
13
+
14
+ // Her one standing, and the id under which the user being pushes to her.
15
+ // Two ids for one far being, because standings and occupants share one
16
+ // namespace and a record holds one or the other.
17
+ export const USER = 'user';
18
+ export const PUSHER = 'user:push';
19
+
20
+ // A carrier who carries for nobody, until a subclass says who: the presence
21
+ // being carries the box's faculties to her user being, and a bare avatar
22
+ // holds one standing and shows nothing of it.
23
+ export class Avatar extends Carrier {
24
+ static override cells = { inbox: [] as JsonObject[] };
25
+ static override asks = {
26
+ notify: { description: 'a push from the user being', input: { type: 'object' }, for: (occ: OccupantRecord | undefined) => occ?.id === PUSHER },
27
+ };
28
+
29
+ // Her sides' ears. One identity is one avatar for life, and two sessions
30
+ // of that identity are two sides on her at once, so a push goes to every
31
+ // ear present; each side adds its own on open and removes it on close.
32
+ // Dropped if there is none.
33
+ readonly ears = new Set<(object: JsonObject) => void>();
34
+
35
+ // ---- what the user being may ask her
36
+
37
+ notify(args: JsonObject) {
38
+ (this.cells.inbox as JsonObject[]).push(args);
39
+ for (const ear of this.ears) ear(args);
40
+ return { notified: true };
41
+ }
42
+
43
+ // ---- what her side calls. Not asks: nobody reaches these through a door.
44
+
45
+ // The credential exchange's last step. `desk` is the desk's public
46
+ // invitation, `proof` is what the route produced. She knocks the desk as a
47
+ // stranger, gets an invitation the user being minted, and joins with it. A
48
+ // knock on a public invitation births nothing, so she holds no standing at
49
+ // the desk afterwards. If she already holds `user`, this is a reconnect and
50
+ // nothing is minted.
51
+ async enter(desk: Invitation, proof: JsonObject): Promise<Blueprint | { error: string }> {
52
+ if (this.standings[USER]) return this.tools();
53
+ const inv = await this.knock(desk, 'device', { proof });
54
+ if (isSilence(inv)) return { error: 'silence' };
55
+ if (isWord(inv)) return { error: wordOf(inv) };
56
+ if (!inv || typeof inv !== 'object' || Array.isArray(inv) || 'error' in inv) return (inv as { error: string }) ?? { error: 'no invitation' };
57
+ return this.join(inv as unknown as Invitation);
58
+ }
59
+
60
+ // Knock with an invitation, hand the far being one back so she can push,
61
+ // and take her as `user`. The only moment a standing is born here. A being
62
+ // who answers the hello with an error object is a being who answered: she
63
+ // is taken all the same, and the way back she did not take is dropped, so
64
+ // any world's public being may admit a guest, hello or not.
65
+ async join(invitation: Invitation): Promise<Blueprint | { error: string }> {
66
+ if (this.standings[USER]) {
67
+ // A standing the far being removed is not one: she drops it and joins
68
+ // afresh, so an identity forgotten at the user being can be let in again.
69
+ const had = await this.tools();
70
+ if (!('error' in had) || had.error !== 'removed') return had;
71
+ this.standings.remove(USER);
72
+ this.occupants.remove(PUSHER);
73
+ }
74
+ const mine = await this.invite(PUSHER);
75
+ if (mine === null) return { error: 'user is taken' };
76
+ const out = await this.knock(invitation, 'hello', { invitation: mine as unknown as JsonObject });
77
+ if (isSilence(out) || isWord(out)) {
78
+ this.occupants.remove(PUSHER);
79
+ return { error: isSilence(out) ? 'silence' : wordOf(out) };
80
+ }
81
+ if (out !== null && typeof out === 'object' && !Array.isArray(out) && 'error' in out) this.occupants.remove(PUSHER);
82
+ await this.take(USER, invitation);
83
+ return this.tools();
84
+ }
85
+
86
+ // Her describe, as the user being shows it to her. This is the tool list.
87
+ async tools(): Promise<Blueprint | { error: string }> {
88
+ const st = this.standings[USER];
89
+ if (!st) return { error: 'not joined' };
90
+ const bp = await st.ask();
91
+ if (isSilence(bp) || isWord(bp)) return { error: isSilence(bp) ? 'silence' : wordOf(bp) };
92
+ return bp as Blueprint;
93
+ }
94
+
95
+ // One call from the side, one ask on the standing. The three words pass
96
+ // through untouched; the side renders them.
97
+ call(name: string, args: JsonObject = {}, wanted?: Wanted): Promise<Answer> {
98
+ const st = this.standings[USER];
99
+ return st ? st.ask(name, args, wanted) : Promise.resolve({ error: 'not joined' });
100
+ }
101
+ }