@astrale-domains/shell 0.1.0-beta.8 → 0.1.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 (244) hide show
  1. package/README.md +264 -64
  2. package/dist/domain.d.ts +225 -0
  3. package/dist/domain.js +96 -0
  4. package/dist/functions/application/index.js +1 -0
  5. package/dist/functions/application/list-entrypoints.js +6 -0
  6. package/dist/functions/group/assign-member-to-group.js +4 -0
  7. package/dist/functions/group/change-group-membership.js +34 -0
  8. package/dist/functions/group/group-membership-errors.js +23 -0
  9. package/dist/functions/group/index.js +2 -0
  10. package/dist/functions/group/unassign-member-from-group.js +4 -0
  11. package/dist/functions/namespace/index.js +3 -0
  12. package/dist/functions/namespace/link.js +30 -0
  13. package/dist/functions/namespace/namespace-errors.js +28 -0
  14. package/dist/functions/namespace/namespace-name.js +13 -0
  15. package/dist/functions/namespace/rename.js +31 -0
  16. package/dist/functions/namespace/unlink.js +21 -0
  17. package/dist/functions/user/index.js +2 -0
  18. package/dist/functions/user/invite-user.js +39 -0
  19. package/dist/functions/user/record-profile.js +18 -0
  20. package/dist/functions/view-access/assign-views.js +86 -0
  21. package/dist/functions/view-access/index.js +1 -0
  22. package/dist/functions/view-access/view-access-errors.js +28 -0
  23. package/dist/index.d.ts +1 -3
  24. package/dist/index.js +1 -3
  25. package/dist/integrations/index.d.ts +1 -0
  26. package/dist/integrations/index.js +1 -0
  27. package/dist/integrations/integrations.d.ts +9 -0
  28. package/dist/integrations/integrations.js +2 -0
  29. package/dist/integrations/user-invitation/index.d.ts +4 -0
  30. package/dist/integrations/user-invitation/index.js +3 -0
  31. package/dist/integrations/user-invitation/invitation-request-failure.d.ts +5 -0
  32. package/dist/integrations/user-invitation/invitation-request-failure.js +9 -0
  33. package/dist/integrations/user-invitation/invite-user-request.d.ts +6 -0
  34. package/dist/integrations/user-invitation/invite-user-request.js +1 -0
  35. package/dist/integrations/user-invitation/request-user-invitation.d.ts +8 -0
  36. package/dist/integrations/user-invitation/request-user-invitation.js +9 -0
  37. package/dist/mutations/group/index.js +1 -1
  38. package/dist/mutations/group/set-group-membership.js +29 -0
  39. package/dist/mutations/namespace/alias-write.js +22 -0
  40. package/dist/mutations/namespace/index.js +3 -0
  41. package/dist/mutations/namespace/link-alias.js +15 -0
  42. package/dist/mutations/namespace/rename-alias.js +13 -0
  43. package/dist/mutations/namespace/unlink-alias.js +13 -0
  44. package/dist/mutations/user/index.js +1 -1
  45. package/dist/mutations/user/record-user-profile.js +13 -0
  46. package/dist/mutations/view-access/index.js +1 -0
  47. package/dist/mutations/view-access/set-view-access.js +29 -0
  48. package/dist/providers/admin-enrollment/create-admin-enrollment-provider.js +78 -0
  49. package/dist/providers/admin-enrollment/decode-admin-invitation-response.js +20 -0
  50. package/dist/providers/admin-enrollment/index.js +1 -0
  51. package/dist/providers/admin-enrollment/read-enrollment-response.js +34 -0
  52. package/dist/queries/application/index.js +1 -0
  53. package/dist/queries/application/read-installed-entrypoints.js +28 -0
  54. package/dist/queries/group/index.js +2 -0
  55. package/dist/queries/group/read-group-membership-endpoints.js +18 -0
  56. package/dist/queries/group/read-group-membership.js +35 -0
  57. package/dist/queries/namespace/index.js +2 -0
  58. package/dist/queries/namespace/read-designated-node.js +12 -0
  59. package/dist/queries/namespace/read-view-aliases.js +46 -0
  60. package/dist/queries/user/index.js +1 -5
  61. package/dist/queries/user/read-user-profile.js +9 -0
  62. package/dist/queries/view-access/index.js +1 -0
  63. package/dist/queries/view-access/read-view-access.js +35 -0
  64. package/dist/runtime.d.ts +2175 -3
  65. package/dist/runtime.js +24 -14
  66. package/dist/schema/index.d.ts +7 -6
  67. package/dist/schema/index.js +6 -6
  68. package/dist/schema/modules/application/functions/index.d.ts +1 -0
  69. package/dist/schema/modules/application/functions/index.js +1 -0
  70. package/dist/schema/modules/application/functions/list-entrypoints.d.ts +15 -0
  71. package/dist/schema/modules/application/functions/list-entrypoints.js +16 -0
  72. package/dist/schema/modules/application/index.d.ts +2 -0
  73. package/dist/schema/modules/application/index.js +2 -0
  74. package/dist/schema/modules/application/types/entrypoint-entry.d.ts +8 -0
  75. package/dist/schema/modules/application/types/entrypoint-entry.js +7 -0
  76. package/dist/schema/modules/application/types/index.d.ts +1 -0
  77. package/dist/schema/modules/application/types/index.js +1 -0
  78. package/dist/schema/modules/group/classes/group.d.ts +24 -0
  79. package/dist/schema/modules/group/classes/group.js +11 -0
  80. package/dist/schema/modules/group/classes/index.d.ts +2 -0
  81. package/dist/schema/modules/group/classes/index.js +2 -0
  82. package/dist/schema/modules/group/classes/member-of-group.d.ts +30 -0
  83. package/dist/schema/modules/group/classes/member-of-group.js +12 -0
  84. package/dist/schema/modules/group/core/administrators-group.d.ts +1 -0
  85. package/dist/schema/modules/group/core/administrators-group.js +6 -0
  86. package/dist/schema/modules/group/core/applications-group.d.ts +1 -0
  87. package/dist/schema/modules/group/core/applications-group.js +6 -0
  88. package/dist/schema/modules/group/core/index.d.ts +3 -0
  89. package/dist/schema/modules/group/core/index.js +3 -0
  90. package/dist/schema/modules/group/core/members-group.d.ts +1 -0
  91. package/dist/schema/modules/group/core/members-group.js +6 -0
  92. package/dist/schema/modules/group/functions/assign-member-to-group.js +11 -0
  93. package/dist/schema/modules/group/functions/index.js +2 -0
  94. package/dist/schema/modules/group/functions/unassign-member-from-group.js +11 -0
  95. package/dist/schema/modules/group/index.d.ts +3 -0
  96. package/dist/schema/modules/group/index.js +3 -0
  97. package/dist/schema/modules/group/policies/belongs-to-group.d.ts +1 -0
  98. package/dist/schema/modules/group/policies/belongs-to-group.js +5 -0
  99. package/dist/schema/modules/group/policies/index.d.ts +1 -0
  100. package/dist/schema/modules/group/policies/index.js +1 -0
  101. package/dist/schema/modules/group/types/group-membership-input.js +8 -0
  102. package/dist/schema/modules/group/types/index.js +1 -0
  103. package/dist/schema/modules/namespace/classes/alias.d.ts +31 -0
  104. package/dist/schema/modules/namespace/classes/alias.js +13 -0
  105. package/dist/schema/modules/namespace/classes/index.d.ts +2 -0
  106. package/dist/schema/modules/namespace/classes/index.js +2 -0
  107. package/dist/schema/modules/namespace/classes/namespace.d.ts +31 -0
  108. package/dist/schema/modules/namespace/classes/namespace.js +10 -0
  109. package/dist/schema/modules/namespace/core/index.d.ts +1 -0
  110. package/dist/schema/modules/namespace/core/index.js +1 -0
  111. package/dist/schema/modules/namespace/core/views-namespace.d.ts +2 -0
  112. package/dist/schema/modules/namespace/core/views-namespace.js +7 -0
  113. package/dist/schema/modules/namespace/functions/index.js +3 -0
  114. package/dist/schema/modules/namespace/functions/link.js +11 -0
  115. package/dist/schema/modules/namespace/functions/rename.js +11 -0
  116. package/dist/schema/modules/namespace/functions/unlink.js +11 -0
  117. package/dist/schema/modules/namespace/index.d.ts +2 -0
  118. package/dist/schema/modules/namespace/index.js +2 -0
  119. package/dist/schema/modules/namespace/types/index.js +1 -0
  120. package/dist/schema/modules/namespace/types/namespace-name.js +7 -0
  121. package/dist/schema/modules/user/classes/index.d.ts +1 -0
  122. package/dist/schema/modules/user/classes/index.js +1 -0
  123. package/dist/schema/modules/user/classes/user.d.ts +34 -0
  124. package/dist/schema/modules/user/classes/user.js +21 -0
  125. package/dist/schema/modules/user/functions/index.js +2 -0
  126. package/dist/schema/modules/user/functions/invite-user.js +12 -0
  127. package/dist/schema/modules/user/functions/record-profile.js +14 -0
  128. package/dist/schema/modules/user/index.d.ts +2 -0
  129. package/dist/schema/modules/user/index.js +2 -0
  130. package/dist/schema/modules/user/types/index.d.ts +2 -0
  131. package/dist/schema/modules/user/types/index.js +2 -0
  132. package/dist/schema/modules/user/types/invitation-summary.d.ts +16 -0
  133. package/dist/schema/modules/user/types/invitation-summary.js +15 -0
  134. package/dist/schema/modules/user/types/user-profile.d.ts +7 -0
  135. package/dist/schema/modules/user/types/user-profile.js +7 -0
  136. package/dist/schema/modules/view-access/classes/index.d.ts +1 -0
  137. package/dist/schema/modules/view-access/classes/index.js +1 -0
  138. package/dist/schema/modules/view-access/classes/view-access.d.ts +32 -0
  139. package/dist/schema/modules/view-access/classes/view-access.js +18 -0
  140. package/dist/schema/modules/view-access/core/index.d.ts +1 -0
  141. package/dist/schema/modules/view-access/core/index.js +1 -0
  142. package/dist/schema/modules/view-access/core/view-only-group.d.ts +5 -0
  143. package/dist/schema/modules/view-access/core/view-only-group.js +10 -0
  144. package/dist/schema/modules/view-access/functions/assign-views.d.ts +16 -0
  145. package/dist/schema/modules/view-access/functions/assign-views.js +17 -0
  146. package/dist/schema/modules/view-access/functions/index.d.ts +1 -0
  147. package/dist/schema/modules/view-access/functions/index.js +1 -0
  148. package/dist/schema/modules/view-access/index.d.ts +3 -0
  149. package/dist/schema/modules/view-access/index.js +3 -0
  150. package/dist/schema/modules/view-access/types/index.js +1 -0
  151. package/dist/schema/modules/view-access/types/view-assignment.js +16 -0
  152. package/dist/schema/policies/administers-shell-class.js +11 -0
  153. package/dist/schema/policies/index.js +4 -0
  154. package/dist/schema/policies/is-self.js +5 -0
  155. package/dist/schema/policies/owns-class.js +7 -0
  156. package/dist/schema/policies/uses-function.js +5 -0
  157. package/dist/schema/schema.d.ts +833 -0
  158. package/dist/schema/schema.js +35 -0
  159. package/dist/schema/views/application-view.js +4 -0
  160. package/dist/schema/views/index.js +1 -0
  161. package/dist/utils/canonical-node-path/index.js +1 -0
  162. package/dist/utils/canonical-node-path/parse-canonical-node-path.js +8 -0
  163. package/package.json +50 -10
  164. package/dist/actions/index.js +0 -1
  165. package/dist/actions/user/index.js +0 -1
  166. package/dist/actions/user/resolve-home.js +0 -19
  167. package/dist/application.d.ts +0 -5
  168. package/dist/application.js +0 -29
  169. package/dist/mutations/group/membership.js +0 -21
  170. package/dist/mutations/space/access.js +0 -25
  171. package/dist/mutations/space/default.js +0 -25
  172. package/dist/mutations/space/index.js +0 -2
  173. package/dist/mutations/user/repair.js +0 -85
  174. package/dist/queries/space/access.js +0 -14
  175. package/dist/queries/space/admin.js +0 -27
  176. package/dist/queries/space/index.js +0 -3
  177. package/dist/queries/space/member.js +0 -24
  178. package/dist/queries/user/groups.js +0 -24
  179. package/dist/queries/user/home.js +0 -28
  180. package/dist/queries/user/owned-spaces.js +0 -24
  181. package/dist/queries/user/profile.js +0 -17
  182. package/dist/queries/user/setup.js +0 -18
  183. package/dist/schema/domain/index.d.ts +0 -26911
  184. package/dist/schema/domain/index.js +0 -40
  185. package/dist/schema/group/class.d.ts +0 -3288
  186. package/dist/schema/group/class.js +0 -7
  187. package/dist/schema/group/core.d.ts +0 -14
  188. package/dist/schema/group/core.js +0 -14
  189. package/dist/schema/group/index.d.ts +0 -6
  190. package/dist/schema/group/index.js +0 -6
  191. package/dist/schema/group/methods.d.ts +0 -2059
  192. package/dist/schema/group/methods.js +0 -21
  193. package/dist/schema/group/policies.d.ts +0 -1
  194. package/dist/schema/group/policies.js +0 -6
  195. package/dist/schema/group/relationships.d.ts +0 -4313
  196. package/dist/schema/group/relationships.js +0 -8
  197. package/dist/schema/group/view.d.ts +0 -3291
  198. package/dist/schema/group/view.js +0 -6
  199. package/dist/schema/home/index.d.ts +0 -1
  200. package/dist/schema/home/index.js +0 -1
  201. package/dist/schema/home/view.d.ts +0 -3
  202. package/dist/schema/home/view.js +0 -4
  203. package/dist/schema/setup/functions.d.ts +0 -47
  204. package/dist/schema/setup/functions.js +0 -27
  205. package/dist/schema/setup/index.d.ts +0 -1
  206. package/dist/schema/setup/index.js +0 -1
  207. package/dist/schema/space/class.d.ts +0 -2313
  208. package/dist/schema/space/class.js +0 -11
  209. package/dist/schema/space/core.d.ts +0 -22520
  210. package/dist/schema/space/core.js +0 -15
  211. package/dist/schema/space/index.d.ts +0 -6
  212. package/dist/schema/space/index.js +0 -6
  213. package/dist/schema/space/methods.d.ts +0 -2089
  214. package/dist/schema/space/methods.js +0 -30
  215. package/dist/schema/space/policies.d.ts +0 -4
  216. package/dist/schema/space/policies.js +0 -21
  217. package/dist/schema/space/relationships.d.ts +0 -23213
  218. package/dist/schema/space/relationships.js +0 -24
  219. package/dist/schema/space/view.d.ts +0 -2316
  220. package/dist/schema/space/view.js +0 -6
  221. package/dist/schema/user/class.d.ts +0 -1015
  222. package/dist/schema/user/class.js +0 -11
  223. package/dist/schema/user/index.d.ts +0 -3
  224. package/dist/schema/user/index.js +0 -3
  225. package/dist/schema/user/methods.d.ts +0 -14
  226. package/dist/schema/user/methods.js +0 -11
  227. package/dist/schema/user/view.d.ts +0 -1017
  228. package/dist/schema/user/view.js +0 -6
  229. package/dist/workflows/group/assign.js +0 -3
  230. package/dist/workflows/group/change.js +0 -31
  231. package/dist/workflows/group/index.js +0 -3
  232. package/dist/workflows/group/unassign.js +0 -3
  233. package/dist/workflows/index.js +0 -3
  234. package/dist/workflows/setup/admin.js +0 -3
  235. package/dist/workflows/setup/index.js +0 -5
  236. package/dist/workflows/setup/member.js +0 -3
  237. package/dist/workflows/setup/plan.js +0 -88
  238. package/dist/workflows/setup/provision.js +0 -57
  239. package/dist/workflows/setup/run.js +0 -74
  240. package/dist/workflows/space/access.js +0 -41
  241. package/dist/workflows/space/add.js +0 -3
  242. package/dist/workflows/space/default.js +0 -37
  243. package/dist/workflows/space/index.js +0 -4
  244. package/dist/workflows/space/remove.js +0 -3
package/README.md CHANGED
@@ -1,66 +1,266 @@
1
1
  # Shell Domain
2
2
 
3
- Shell is the minimal Kernel-native application plane. Its durable model is one `User` interface,
4
- the concrete `User`, `Group`, `Space`, and `Application` Node Classes, eight relationships, five
5
- Policies, two Functions, seven Methods, five Kernel View declarations, and four deterministic Core
6
- nodes.
7
-
8
- The `ensureUser` Function is the Shell-owned identity genesis boundary. It idempotently provisions an
9
- externally identified `User`, their personal `Space`, and both ownership/default relationships under
10
- the installed Shell Domain's authority. `ensureAdministrator` idempotently assigns one existing User
11
- to Shell's administrator Group. Both keep product mutation under Shell authority while allowing an
12
- authenticated genesis operator to request the transition.
13
-
14
- The Methods are:
15
-
16
- - Group: `assignUser`, `unassignUser`;
17
- - Space: `addUser`, `removeUser`, `setDefault`; and
18
- - Application: `install`, `uninstall`.
19
-
20
- Installation authors the `admin`, `member`, `default-space`, and `shell` Core. An authenticated genesis
21
- operator may invoke `ensureUser`, but cannot mutate Shell Classes directly. The remote handler performs
22
- the atomic identity provisioning as Shell, then callers assign the User explicitly to a Group. Shell
23
- infers no authority from email, claims, path spelling, or creation order.
24
-
25
- ## Source ownership
26
-
27
- - `schema/` owns the complete Domain contract, public Method values, Policies, relationships, DSL
28
- Views, and Core graph;
29
- - `rules/` owns synchronous classifications, decisions, normalization, and result projection;
30
- - `queries/` owns canonical single and composite graph observations plus explicit bounded continuation
31
- pagination when a business observation requires the complete set;
32
- - `mutations/` owns canonical atomic graph changes and their expected rejection evidence;
33
- - `workflows/` owns replay-shaped multi-step business journeys and unknown-outcome recovery;
34
- - `functions/` binds the Function and each Method to a rule, workflow, or direct operation;
35
- - `utils/` owns only the shared graph-endpoint and bounded-query mechanics used by independent
36
- submodules; and
37
- - root `tests/` owns cross-layer and system evidence, while each semantic submodule owns focused
38
- evidence in `__tests__/`.
39
-
40
- No current responsibility earns a `states/`, `capabilities/`, `integrations/`, `migrations/`,
41
- `views/`, `ui/`, or root `scripts/` source layer. DSL View declarations remain in Schema; a future
42
- frontend projection or UI must establish its own concrete responsibility before adding those layers.
43
-
44
- Shell never re-declares shared metadata properties. `Group` and `Space` currently name `K.Named`
45
- and `K.Descriptable` in their `implements` lists because the current DSL makes only `K.Node`
46
- intrinsic and Core-property admission otherwise rejects `name` and `description`. Removing those
47
- interface references awaits the recorded Kernel authoring-default decision; no timestamps are
48
- authored by Shell.
49
-
50
- ## Execution and evidence
51
-
52
- `ShellDomain` is the complete remote product implementation. Its exact handler map proves that the
53
- genesis Functions and all seven Methods are served from the same immutable publication. The handlers use
54
- the SDK's canonical Auth, Query, Mutation, Result, Workflow, and Step contracts. `ensureUser` relies on
55
- the Kernel provision operation's stable idempotency key; the SDK's current inline Step runner does not
56
- claim process-restart replay on its own.
57
-
58
- The executable contract lives in Shell's semantic source, public facades, and tests. Product
59
- decisions, journeys, legacy disposition, dependency gates, and qualification evidence live in
60
- [`.history/`](.history/). Product Domains intentionally have no `.spec/` tree; Kernel authoring
61
- values come through semantic `@astrale-os/sdk/*` facades.
62
-
63
- The source, deterministic Knowledge linter, TypeScript package, unit/cross-layer tests, and remote Shell
64
- contract are qualified locally. Installed-instance, released-package, browser, and live
65
- credential journeys are separate evidence levels and are not claimed here. Shell does not broker
66
- authentication tokens; standard Domain token exchange is owned by Protocol, Server, and SDK.
3
+ Shell owns two concrete Identity classes, User and Group, the member_of_group relation,
4
+ the admin/member/applications/view-only Core groups, the Namespace class and its alias relation, the
5
+ view_access relation, the `views` Core Namespace, three static methods, one User method, three Namespace methods, two Domain functions, and one
6
+ application View, which is its entrypoint. The Schema names the Domain `Shell`. There is no Space, setup function, personal home, or public repair method.
7
+
8
+ ## Contracts
9
+
10
+ | Static method | Input | Output |
11
+ | --- | --- | --- |
12
+ | User.invite | `{ user: UserPath, email: string }` | `{ invitationId, user, state }` |
13
+ | Group.assignMember | `{ member: UserPath \| GroupPath, group: GroupPath }` | `{}` |
14
+ | Group.unassignMember | Same | `{}` |
15
+
16
+ | User method | Input | Output |
17
+ | --- | --- | --- |
18
+ | User.recordProfile | `{ email?: string, displayName?: string }` | `{}` |
19
+
20
+ An account records the email and display name it signs in with, so the directory can name it, in
21
+ `claimedEmail` and `claimedName`: named apart from the `email` or `displayName` a Domain extending
22
+ User declares for its own profile. Its
23
+ `isSelf` Policy admits the account itself alone, and Shell writes, with its own authority, only what
24
+ changed; an email is kept in lower case. The values come from the account, not from its identity
25
+ provider: they name it for display and decide nothing. The GUI records them at each sign-in.
26
+
27
+ | Namespace method | Input | Output |
28
+ | --- | --- | --- |
29
+ | Namespace.link | `{ name: string, target: NodePath }` | `{}` |
30
+ | Namespace.unlink | `{ name: string }` | `{}` |
31
+ | Namespace.rename | `{ name: string, to: string }` | `{}` |
32
+
33
+ | Domain function | Input | Output |
34
+ | --- | --- | --- |
35
+ | listEntrypoints | `{}` | `{ entrypoints: { origin, name, view }[] }` |
36
+ | assignViews | `{ assignments: { identity, set?, unset? }[] }` | `{}` |
37
+
38
+ listEntrypoints reads, with Shell's own authority, every Kernel `of_domain` locator whose View has
39
+ an outgoing `entrypoint` Edge, and returns one entry per Domain in origin order: its origin, the
40
+ `name` of its Domain Node, and the key of its entrypoint View. A Domain without an entrypoint is
41
+ not listed. Shell requires `read` on Kernel `Domain` and `of_domain`, and `traverse` on `entrypoint`
42
+ and `View`. Its `usesFunction` Policy admits any caller whose composed profile holds `can_use`
43
+ on the Function, so holding the capability is enough.
44
+
45
+ The workspace opens only once listEntrypoints answers, so every profile that admits a person to
46
+ the workspace holds it. Administrators and members hold both listEntrypoints and View.resolve
47
+ directly (a Core Edge cannot author Kernel `extends_with`): an invited person, whom Admin assigns
48
+ to Core member, can open the workspace. The Core `applications` Group carries the same two
49
+ capabilities for Identities outside Members, and `query`: the `/v/<name>` page reads its Path with
50
+ a Query under the visitor's own rights, so read rules still decide what it sees. Share them
51
+ dynamically with
52
+ `Group.assignMember({ member: identity, group: applications })`, which composes the profile through
53
+ `extends_with`; `unassignMember` withdraws it.
54
+
55
+ User extends Kernel.Identity and owns only optional creationKey correlation.
56
+ Concrete business classes may declare their own displayName/email; Shell never reads or writes them.
57
+ Group extends Kernel.Identity, Named and Descriptable. Authentication remains the
58
+ Kernel-owned, write-once iss/sub binding. Invitation email is explicit input, not a User property.
59
+
60
+ | Operation | Schema Policy alternatives, in addition to Kernel admission |
61
+ | --- | --- |
62
+ | invite | Core admin membership AND Shell-owned concrete User class; or ownership of the User's concrete class |
63
+ | assignMember / unassignMember | Core admin membership AND Shell-owned concrete Group class; or ownership of the Group's concrete class |
64
+
65
+ ownsClass follows instance_of → concrete class → of_domain → caller. It does not
66
+ infer ownership from an email, a subclass name, or ownership of an ancestor class.
67
+ A Domain cannot assign its Employee to Core member merely by owning Employee. Admin's invitation
68
+ orchestration retains that responsibility. A Group's owner may manage any admitted User or Group in that Group.
69
+ administersShellClass connects Core admin membership and concrete ownership in one Policy pattern;
70
+ it does not treat inheritance from Shell as ownership. These are callable restrictions, not an
71
+ isolation boundary against Root/Manager or the existing broad administrator Kernel profile.
72
+ With Kernel Host beta94 or newer, an external caller needs callable authority through its own
73
+ identity composition AND a passing callable Policy. Declare exact foreign methods in the calling
74
+ Domain's requirements; can_use no longer bypasses the Policy. Root and exact owner exceptions remain.
75
+
76
+ ## Namespaces and aliases
77
+
78
+ **An alias names a Node. It grants nothing.** A name designates at most one Node in its
79
+ Namespace, for every author: `alias` declares the Kernel key `unique: [['source', 'slug']]` in its
80
+ first release, so the Kernel refuses a taken name on the final state of any Mutation, Shell's or an
81
+ administrator's own `mutate`. Edge identity gives a Node at most one alias per Namespace. An alias
82
+ is a Path, `/:shell.astrale.ai:core.views~"shell.astrale.ai:class.alias"(roadmap)`, and reaches its
83
+ Node only for a reader who may read that Node. Its target endpoint accepts any Node, a Class Shell
84
+ does not own, so the alias detaches when its Node is deleted; the Namespace stays.
85
+
86
+ The Core Namespace `views` holds the names opened at `/v/<name>`. Namespace and alias declare
87
+ `read: true` and `traverse: true`: a reader lists and follows the aliases whose Node it may read,
88
+ and an alias toward any other Node does not exist for it. Shell, through its own alias Edges,
89
+ finds the Node of every name, even one it does not read.
90
+
91
+ `link` names any Node its target Path reaches, whatever Domain owns it: an alias grants nothing,
92
+ and each reader sees only the aliases toward Nodes it may read. Offering only Nodes the
93
+ administrator sees is the interface's courtesy, not a server guarantee; any writer already learns
94
+ from a Mutation's locator whether a Path reaches a Node.
95
+
96
+ | Method | Calls | Refusals |
97
+ | --- | --- | --- |
98
+ | link | One Mutation with Shell's authority; its locator resolves `target` | `INVALID_NAME`, `TARGET_NOT_FOUND`, `NAME_TAKEN`, `TARGET_ALREADY_ALIASED` |
99
+ | unlink | One read of the alias Path with Shell's authority, then one Mutation | `INVALID_NAME`, `NAME_NOT_FOUND` |
100
+ | rename | Same; renaming a name to itself writes nothing | `INVALID_NAME`, `NAME_NOT_FOUND`, `NAME_TAKEN` |
101
+
102
+ A name is an Edge slug in lower case (`INVALID_NAME`). That rule is Shell's: an administrator
103
+ writing through `mutate` bypasses it, never the key. Nothing guards a name's uniqueness but the key.
104
+ `unlink` and `rename` change the alias only while it still carries the name they read, so a
105
+ concurrent rename answers `NAME_NOT_FOUND` instead of changing another name. Shell maps the Kernel's
106
+ sealed refusals:
107
+
108
+ | Kernel refusal of the Mutation | link | unlink | rename |
109
+ | --- | --- | --- | --- |
110
+ | `MUTATION_POST_STATE_INVALID`, rule `duplicate-key` | `NAME_TAKEN` | propagates | `NAME_TAKEN` |
111
+ | `MUTATION_PRECONDITION_FAILED` (the alias Edge exists, is gone, or carries another name) | `TARGET_ALREADY_ALIASED` | `NAME_NOT_FOUND` | `NAME_NOT_FOUND` |
112
+ | `MUTATION_LOCATOR_INVALID` (the target Path reaches no Node, or the target was deleted) | `TARGET_NOT_FOUND` | `NAME_NOT_FOUND` | `NAME_NOT_FOUND` |
113
+
114
+ Every other failure propagates. Core admin holds the three methods, `read` and `traverse` on
115
+ Namespace, and every operation on alias. Administration follows `administersShellClass` on the
116
+ Namespace, as for Groups.
117
+
118
+ ## View access
119
+
120
+ **A View given to an account decides where it lands, never what it reads.** `view_access` runs from
121
+ a User or a Group to one Kernel View. The Core group `view-only` limits its members to the Views
122
+ they hold, directly or through a group they are a direct member of; membership in `view-only` and
123
+ in Core `admin` counts the same way. Everyone else, and every administrator, opens the workspace as
124
+ before. Nothing else changes: the View's own Domain still
125
+ guards every Node it shows, and `View.resolve` and `listEntrypoints` answer as before.
126
+
127
+ | Fact | Who writes it | How |
128
+ | --- | --- | --- |
129
+ | `view_access(holder → View)` | Core admin | `assignViews`, or a Mutation that creates or deletes the Edge. It carries no property. |
130
+ | `member_of_group(user → view-only)` | Core admin | `Group.assignMember` / `Group.unassignMember`. |
131
+
132
+ `view_access` declares `read: true` and `traverse: true`, as `alias` does. Its target is a
133
+ Class Shell does not own, so it detaches when its View is deleted, by a Mutation or by a release
134
+ that removes the View. Clients read a visitor's access with its own Queries
135
+ (`shell.views.access()`): never a read function. A Shell release without `view-only` limits no one.
136
+
137
+ `assignViews` takes, for each identity (a User or a Group, by `@NodeId`), the Views to give
138
+ (`set`) and to withdraw (`unset`), by `@NodeId`. It reads the identities' `view_access` Edges and
139
+ writes only what differs, in one Mutation guarded by that read, with Shell's own authority: a View
140
+ already given or already withdrawn costs nothing, and a concurrent change refuses the whole write
141
+ (`VIEW_ACCESS_CONFLICT`). An identity listed twice gets both lists; one View both given and
142
+ withdrawn is refused. One call changes at most 40 identities and 20 Views per list. Core admin
143
+ holds it, and may share `can_use` on it. It never changes `view-only`: whether an identity opens the workspace stays its
144
+ membership, which `Group.assignMember` changes.
145
+
146
+ To limit an invited person to one View: invite them, assign them to `view-only`, give them the
147
+ View with `assignViews`, and give the View an alias in `views` so `/v/<name>` opens it.
148
+
149
+ ## Flows
150
+
151
+ ```text
152
+ Domain creates Employee extending User → unregistered, no group
153
+ Direct credential-evidenced Register → same node authenticates, still no group
154
+ User.invite → provider authentication → Admin ingress → WorkOS/login
155
+ → Admin Register on that same node → member assignment → completed
156
+ Group.assignMember → member_of_group + Kernel.extends_with in one atomic mutation
157
+ Group.unassignMember → remove both edges in one atomic mutation
158
+ ```
159
+
160
+ The invitation flow is coordinated by Admin, not by an Employee callback. Shell's Integration
161
+ carries only user/email/requestId/requestedBy. Its Provider mints an invocation-bound Shell
162
+ proof for its configured HTTPS ingress audience; target/sourceProof are not business inputs.
163
+ A returned pending invitation does not prove email delivery or completed registration.
164
+
165
+ `assignMember({ member: A, group: B })` adds A to B. A and its current and future members inherit
166
+ B's authority. Groups can have several parents; Kernel rejects self-membership and cycles in the
167
+ same transaction as both membership edges. The target Group's manager authorizes this delegation;
168
+ the child Group's managers can subsequently change the population that inherits it.
169
+
170
+ `unassignMember` removes only that direct pair. Another membership path can preserve effective
171
+ access. Queries of `member_of_group` continue to return direct facts; Policy evaluation expands
172
+ the caller's identity composition. Shell must be able to traverse both concrete endpoint Classes,
173
+ including a foreign Group used as the member.
174
+
175
+ Membership methods converge both edges, including an observed partial membership.
176
+ After an uncertain mutation response they re-read the pair; an unconfirmed outcome remains
177
+ explicitly unconfirmed. This is not a global repair scan or an exactly-once guarantee.
178
+
179
+ A Team class extending Group can carry a business permission edge to Project. Membership
180
+ composition lets an Employee, as caller, inherit Team's authority; the protected Project Policy is
181
+ still evaluated by Kernel. Removing composition removes that authority path. Installed
182
+ Kernel E2E evidence, not a handler test, qualifies this behavior.
183
+
184
+ ## Installation and View
185
+
186
+ The Shell principal requests all Kernel root functions, the required extends_with operations,
187
+ and the declared grant/revoke authority. Core admin receives the full declared Shell profile,
188
+ including invite, recordProfile, assignMember, unassignMember, link, unlink, rename and assignViews
189
+ so humans inheriting admin can call those methods. Core member receives Download, Introspect, Query,
190
+ Mutate, View.resolve, listEntrypoints and recordProfile, not blanket class-read grants. Core applications receives listEntrypoints,
191
+ View.resolve and Query.
192
+ The Domain definition's requirements, including Core Identity capabilities in requirements.core, are owned by domain.ts and materialized by installation,
193
+ never by invitation handlers.
194
+
195
+ The sole application entrypoint uses the Vite React frontend at /, composed with
196
+ `@astrale-os/shell-react` and `@astrale-os/ui`. It administers the instance under the caller's own
197
+ session, in three tabs. **Access** lists users, then groups: whether each opens the whole OS or only its Views (two spelled-out options
198
+ over its `view-only` membership; an administrator always does, a Core group is decided by its role)
199
+ and, through a picker, the installed Views given to it. **Groups** lists the groups and the direct
200
+ members of the chosen one, to add or remove. **Addresses** lists the installed Views and the name
201
+ `/v/<name>` each opens at, to give, rename or remove through `Namespace.link`, `rename` and `unlink`;
202
+ a name the Namespace would refuse, or one another View has, is refused beside the field before it is
203
+ sent. Every change applies at once and comes back with a
204
+ message when the Kernel refuses it. A user shows its recorded display name and email, or its concrete
205
+ class when it recorded none, never a guessed foreign profile. Every read is a Query under the
206
+ caller's rights; the screen proxies no privileged read.
207
+
208
+ ## Versions
209
+
210
+ The Domain's version is the `version` of `domain/package.json`, which Release Please writes; it
211
+ also writes it to the root `package.json`, the Project's, which `astrale-domain publish` reads. One
212
+ number names the npm package `@astrale-domains/shell` and the registry Publication
213
+ `shell.astrale.ai@<version>`, so an instance installs a published release by number:
214
+
215
+ ```sh
216
+ astrale domain install shell.astrale.ai@<version> -i <instance> --as <instance>-root
217
+ ```
218
+
219
+ `shell.astrale.ai@<major>.<minor>` installs the highest stable version of that line. The Domain
220
+ releases stable versions from 0.1.1 on; 0.1.0, the first Publication, names the 0.1.0-beta.51
221
+ release.
222
+
223
+ ## Source and qualification
224
+
225
+ Each declaration, Query and Mutation has its own semantic file. Layer roots are facades;
226
+ functions own orchestration, integrations/providers own external effects, views/ui own the
227
+ directory surface. Runtime has one default export and binds the three static Workflows.
228
+ The Dataset is referenced lazily by the root astrale.config.ts.
229
+
230
+ Domain authors import Schema from @astrale-domains/shell; platform workers use the explicit
231
+ /domain and /runtime exports. Creation/registration, installation authority, invitation
232
+ delivery, runtime replay and browser rendering are separate qualification boundaries.
233
+ The redesigned Admin composition, published Register cohort and real invitation/instance-create
234
+ journeys remain release gates; this source README is not evidence that those gates passed.
235
+
236
+ ### Publication boundary
237
+
238
+ `@astrale-domains/shell` is an executable platform package and a deliberate exception to the normal
239
+ Domain publication product. It publishes the remote Shell Domain definition and runtime needed by platform
240
+ Worker deployments through the explicit `./domain` and `./runtime` subpaths, while its root remains
241
+ Schema-only. Its build therefore compiles the explicit roots in `tsconfig.package.json` and applies
242
+ Shell-owned normalization and checks to the emitted platform closure. Source-only `#` aliases are
243
+ rewritten to relative JS and declaration references so consumer path mappings cannot capture private Shell
244
+ types. Tarball qualification then verifies the exact exports, isolated subpaths, absence of source
245
+ maps, and an install using only public npm dependencies.
246
+
247
+ The generic `astrale-domain package` command remains Schema-only and exposes only the Domain root plus
248
+ package metadata. This Shell exception must not be copied to ordinary product Domains or used to
249
+ weaken that SDK contract. Deployment consumers must use the explicit executable subpaths so a linked
250
+ schema import cannot traverse Shell's private application or runtime implementation.
251
+
252
+ Source, package, and deterministic test qualification remain distinct from installed-instance,
253
+ released-package, browser, and live-credential evidence. Shell does not broker authentication
254
+ tokens; standard Domain token exchange is owned by Protocol, Server, and SDK.
255
+
256
+ ### Breaking membership API migration
257
+
258
+ `Group.assignMember` / `Group.unassignMember` replace `assignUser` / `unassignUser` without aliases.
259
+ Callers must change `{ user, group }` to `{ member, group }` and declare the new exact callable
260
+ requirements. The `member_of_group` Class key is preserved; its source role is now `member` and
261
+ accepts User or Group families. Existing User memberships remain valid.
262
+
263
+ Rebuild and install all affected Schema dependents as one coherent revision closure. Admin bootstrap
264
+ and invitation completion must use the new API when this Shell revision is installed. A downgrade
265
+ to the User-only contract requires handling any Group-to-Group facts first. Validate public admission,
266
+ foreign endpoint traversal, and deployed revisions during the coordinated release.
@@ -0,0 +1,225 @@
1
+ import { type DomainDefinition } from '@astrale-os/sdk/domain';
2
+ import { ShellSchema } from './schema/index.js';
3
+ import { type ShellRuntime } from './runtime.js';
4
+ declare const frontend: import("@astrale-os/sdk/view").Frontend<import("@astrale-os/sdk/schema").AuthoredSchema<"shell.astrale.ai", readonly ["kernel.astrale.ai", import("@astrale-os/sdk/schema").KernelSchema] | readonly ["shell.astrale.ai", {
5
+ readonly name: 'Shell';
6
+ readonly entrypoint: 'application';
7
+ readonly classes: {
8
+ readonly User: import("@astrale-os/sdk/schema").AuthoredNodeClass<{
9
+ readonly icon: import("@astrale-os/sdk/schema").ClassIcon;
10
+ readonly inheritance: "open";
11
+ readonly policies: {
12
+ readonly read: true;
13
+ };
14
+ readonly extends: readonly [import("@astrale-os/sdk/schema").KernelClass<"Identity">];
15
+ readonly properties: {
16
+ readonly creationKey: import("zod").ZodOptional<import("zod").ZodString>;
17
+ readonly claimedEmail: import("zod").ZodOptional<import("zod").ZodString>;
18
+ readonly claimedName: import("zod").ZodOptional<import("zod").ZodString>;
19
+ };
20
+ readonly methods: {
21
+ readonly invite: import("@astrale-os/sdk/schema").Method<import("@astrale-os/sdk/schema").CallableProjection<{
22
+ user: string;
23
+ email: string;
24
+ }, {
25
+ readonly mode: 'value';
26
+ readonly value: {
27
+ invitationId: string;
28
+ user: string;
29
+ state: "accepted" | "cancelled" | "completed" | "expired" | "failed" | "pending" | "registered" | "registering";
30
+ };
31
+ }, "authorized", true, false, undefined, undefined>>;
32
+ readonly recordProfile: import("@astrale-os/sdk/schema").Method<import("@astrale-os/sdk/schema").CallableProjection<{
33
+ email?: string | undefined;
34
+ displayName?: string | undefined;
35
+ }, {
36
+ readonly mode: 'value';
37
+ readonly value: Record<string, never>;
38
+ }, "authorized", false, false, undefined, undefined>>;
39
+ };
40
+ }>;
41
+ readonly Group: import("@astrale-os/sdk/schema").AuthoredNodeClass<{
42
+ readonly icon: import("@astrale-os/sdk/schema").ClassIcon;
43
+ readonly inheritance: "open";
44
+ readonly policies: {
45
+ readonly read: true;
46
+ };
47
+ readonly extends: readonly [import("@astrale-os/sdk/schema").KernelClass<"Identity">, import("@astrale-os/sdk/schema").KernelClass<"Named">, import("@astrale-os/sdk/schema").KernelClass<"Descriptable">];
48
+ readonly methods: {
49
+ readonly assignMember: import("@astrale-os/sdk/schema").Method<import("@astrale-os/sdk/schema").CallableProjection<{
50
+ member: string;
51
+ group: string;
52
+ }, {
53
+ readonly mode: 'value';
54
+ readonly value: Record<string, never>;
55
+ }, "authorized", true, false, undefined, undefined>>;
56
+ readonly unassignMember: import("@astrale-os/sdk/schema").Method<import("@astrale-os/sdk/schema").CallableProjection<{
57
+ member: string;
58
+ group: string;
59
+ }, {
60
+ readonly mode: 'value';
61
+ readonly value: Record<string, never>;
62
+ }, "authorized", true, false, undefined, undefined>>;
63
+ };
64
+ }>;
65
+ readonly member_of_group: import("@astrale-os/sdk/schema").DirectedEdgeClass<{
66
+ readonly depth: 0;
67
+ readonly abstract: false;
68
+ readonly extends: readonly [];
69
+ readonly properties: never;
70
+ readonly source: {
71
+ readonly as: "member";
72
+ readonly accepts: readonly (() => {
73
+ readonly kind: 'node';
74
+ readonly abstract: never;
75
+ readonly depth: never;
76
+ readonly properties: never;
77
+ readonly methods: never;
78
+ })[];
79
+ readonly outgoing: "0..*";
80
+ };
81
+ readonly target: {
82
+ readonly as: "group";
83
+ readonly accepts: readonly (() => {
84
+ readonly kind: 'node';
85
+ readonly abstract: never;
86
+ readonly depth: never;
87
+ readonly properties: never;
88
+ readonly methods: never;
89
+ })[];
90
+ readonly incoming: "0..*";
91
+ };
92
+ readonly constraints: Record<never, never>;
93
+ readonly effectiveProperties: never;
94
+ }>;
95
+ readonly Namespace: import("@astrale-os/sdk/schema").AuthoredNodeClass<{
96
+ readonly icon: import("@astrale-os/sdk/schema").ClassIcon;
97
+ readonly policies: {
98
+ readonly read: true;
99
+ readonly traverse: true;
100
+ };
101
+ readonly extends: readonly [import("@astrale-os/sdk/schema").KernelClass<"Named">, import("@astrale-os/sdk/schema").KernelClass<"Descriptable">];
102
+ readonly methods: {
103
+ readonly link: import("@astrale-os/sdk/schema").Method<import("@astrale-os/sdk/schema").CallableProjection<{
104
+ name: string;
105
+ target: string;
106
+ }, {
107
+ readonly mode: 'value';
108
+ readonly value: Record<string, never>;
109
+ }, "authorized", false, false, undefined, undefined>>;
110
+ readonly unlink: import("@astrale-os/sdk/schema").Method<import("@astrale-os/sdk/schema").CallableProjection<{
111
+ name: string;
112
+ }, {
113
+ readonly mode: 'value';
114
+ readonly value: Record<string, never>;
115
+ }, "authorized", false, false, undefined, undefined>>;
116
+ readonly rename: import("@astrale-os/sdk/schema").Method<import("@astrale-os/sdk/schema").CallableProjection<{
117
+ name: string;
118
+ to: string;
119
+ }, {
120
+ readonly mode: 'value';
121
+ readonly value: Record<string, never>;
122
+ }, "authorized", false, false, undefined, undefined>>;
123
+ };
124
+ }>;
125
+ readonly alias: import("@astrale-os/sdk/schema").DirectedEdgeClass<{
126
+ readonly depth: 0;
127
+ readonly abstract: false;
128
+ readonly extends: readonly [];
129
+ readonly properties: never;
130
+ readonly source: {
131
+ readonly as: "namespace";
132
+ readonly accepts: readonly (() => {
133
+ readonly kind: 'node';
134
+ readonly abstract: never;
135
+ readonly depth: never;
136
+ readonly properties: never;
137
+ readonly methods: never;
138
+ })[];
139
+ readonly outgoing: "0..*";
140
+ };
141
+ readonly target: {
142
+ readonly as: "node";
143
+ readonly accepts: readonly (import("@astrale-os/sdk/schema").ClassRef<"Node"> & {
144
+ readonly origin: "kernel.astrale.ai";
145
+ })[];
146
+ readonly incoming: "0..*";
147
+ };
148
+ readonly constraints: Record<never, never>;
149
+ readonly effectiveProperties: never;
150
+ }>;
151
+ readonly view_access: import("@astrale-os/sdk/schema").DirectedEdgeClass<{
152
+ readonly depth: 0;
153
+ readonly abstract: false;
154
+ readonly extends: readonly [];
155
+ readonly properties: never;
156
+ readonly source: {
157
+ readonly as: "holder";
158
+ readonly accepts: readonly (() => {
159
+ readonly kind: 'node';
160
+ readonly abstract: never;
161
+ readonly depth: never;
162
+ readonly properties: never;
163
+ readonly methods: never;
164
+ })[];
165
+ readonly outgoing: "0..*";
166
+ };
167
+ readonly target: {
168
+ readonly as: "view";
169
+ readonly accepts: readonly (import("@astrale-os/sdk/schema").ClassRef<"View"> & {
170
+ readonly origin: "kernel.astrale.ai";
171
+ })[];
172
+ readonly incoming: "0..*";
173
+ };
174
+ readonly constraints: Record<never, never>;
175
+ readonly effectiveProperties: never;
176
+ }>;
177
+ };
178
+ readonly functions: {
179
+ readonly listEntrypoints: import("@astrale-os/sdk/schema").Function<import("@astrale-os/sdk/schema").CallableProjection<Record<string, never>, {
180
+ readonly mode: 'value';
181
+ readonly value: {
182
+ entrypoints: {
183
+ origin: string;
184
+ name: string;
185
+ view: string;
186
+ }[];
187
+ };
188
+ }, "authorized", false, false, undefined, undefined>>;
189
+ readonly assignViews: import("@astrale-os/sdk/schema").Function<import("@astrale-os/sdk/schema").CallableProjection<{
190
+ assignments: {
191
+ identity: string;
192
+ set?: string[] | undefined;
193
+ unset?: string[] | undefined;
194
+ }[];
195
+ }, {
196
+ readonly mode: 'value';
197
+ readonly value: Record<string, never>;
198
+ }, "authorized", false, false, undefined, undefined>>;
199
+ };
200
+ readonly policies: {
201
+ readonly belongsToGroup: import("@astrale-os/sdk/schema").Policy;
202
+ readonly ownsClass: import("@astrale-os/sdk/schema").Policy;
203
+ readonly administersShellClass: import("@astrale-os/sdk/schema").Policy;
204
+ readonly usesFunction: import("@astrale-os/sdk/schema").Policy;
205
+ readonly isSelf: import("@astrale-os/sdk/schema").Policy;
206
+ };
207
+ readonly views: {
208
+ readonly application: import("@astrale-os/sdk/schema").View;
209
+ };
210
+ readonly core: {
211
+ readonly nodes: {
212
+ readonly admin: import("@astrale-os/sdk/schema").CoreNode;
213
+ readonly applications: import("@astrale-os/sdk/schema").CoreNode;
214
+ readonly member: import("@astrale-os/sdk/schema").CoreNode;
215
+ readonly views: import("@astrale-os/sdk/schema").CoreNode;
216
+ readonly 'view-only': import("@astrale-os/sdk/schema").CoreNode;
217
+ };
218
+ };
219
+ }, {
220
+ readonly kernel: "kernel.astrale.ai";
221
+ }]>>;
222
+ declare const domainRequirements: import("@astrale-os/sdk/domain").Requirements;
223
+ export type ShellDomain = DomainDefinition<typeof ShellSchema, ShellRuntime, typeof frontend, undefined, typeof domainRequirements>;
224
+ export declare const domain: ShellDomain;
225
+ export {};