nervur 0.22.2-7 → 0.23.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.
package/AUTHORING.md CHANGED
@@ -11,8 +11,8 @@ The shop has three classes and one faculty.
11
11
  - `Order` is one order, from its first item to its shipping.
12
12
  - `Shop` is the steward, the being that runs the house.
13
13
  - `Lobby` is the public being, which strangers may ask.
14
- - `Payments` is a faculty that charges money, which a maker in
15
- `recipe.ts` makes.
14
+ - `Payments` is a faculty that charges money, which `recipe.ts` holds
15
+ by name.
16
16
 
17
17
  ## Words
18
18
 
@@ -32,7 +32,8 @@ The shop has three classes and one faculty.
32
32
  | state | a name read from her cells that decides which asks exist |
33
33
  | house | what holds beings, keeps their cells, and seals every ask |
34
34
  | ground | the process houses run in, holding one key and sealing their seeds, faculties and secrets under it |
35
- | registry | code that makes faculties and bodies by name, for the ground to stand |
35
+ | registry | code that holds faculties by name, for the ground to stand |
36
+ | body | a faculty stood: the living instance houses and bodies use |
36
37
 
37
38
  ## A being
38
39
 
@@ -588,8 +589,8 @@ type Answer = { result: { pending: boolean } } | { error: { message: string } };
588
589
  /**
589
590
  * A payment provider in the ground's process. It answers a call id it has
590
591
  * seen with the answer it gave, so an effect sent twice charges once. A
591
- * provider that changes the world keeps these in the memory its maker
592
- * receives, where a restart and a move keep them.
592
+ * provider that changes the world keeps these in the memory its faculty's
593
+ * `up` receives, where a restart and a move keep them.
593
594
  */
594
595
  export class Payments {
595
596
  readonly #answered = new Map<string, Answer>();
@@ -619,19 +620,19 @@ export const paymentsOffer = (payments: Payments): Offer => ({ blueprint: Paymen
619
620
 
620
621
  An offer is `{ blueprint, object, kinds?, window? }`. The object answers
621
622
  each call with its call id, and one that changes the world answers a
622
- call id it has seen with the answer it gave. A registry holds a maker
623
- for each faculty by name. The ground stands a faculty when an entry names
624
- its maker, and the entry's `kinds` grants it to the classes it names.
625
- [Writing a faculty](FACULTIES.md) teaches the craft whole, with a faculty
626
- written in Python.
623
+ call id it has seen with the answer it gave. A registry holds each
624
+ faculty by name, as `{ up, install? }`. The ground raises a faculty by
625
+ its `up` when an entry names it, and the entry's `kinds` grants it to
626
+ the classes it names. [Writing a faculty](FACULTIES.md) teaches the
627
+ craft whole, with a faculty written in Python.
627
628
 
628
629
  ```ts
629
630
  // recipe.ts
630
631
  import { Payments, paymentsOffer } from './payments.ts';
631
632
 
632
- // A registry: the ground makes each faculty an entry names, by its maker here.
633
+ // A registry: the ground raises each faculty an entry names by its `up` here.
633
634
  export const faculties = {
634
- payments: () => paymentsOffer(new Payments()),
635
+ payments: { up: () => paymentsOffer(new Payments()) },
635
636
  };
636
637
  ```
637
638
 
@@ -640,8 +641,8 @@ export const faculties = {
640
641
  A ground is the process houses run in, and you write none. `nervur up`
641
642
  runs one on a folder of code: a folder for each house, and each module
642
643
  your entries name. It holds one key in `state/`, and keeps every entry
643
- sealed in its drawer: which faculties stand, and which houses open on
644
- which bodies.
644
+ sealed as the cells of its dock's beings: which faculties stand, and
645
+ which houses open on which bodies.
645
646
 
646
647
  ### The shop's folder
647
648
 
@@ -680,29 +681,44 @@ npx nervur up .
680
681
  The ground boots in one order, and a stop is that order reversed, on an
681
682
  interrupt and on `SIGTERM`.
682
683
 
683
- 1. **Lock.** One ground to its state.
684
- 2. **Key.** Its key is read from `state/key`, drawn there on the first
685
- start.
686
- 3. **Drawer.** Its ledger opens, and the key opens its drawer.
687
- 4. **Ladder.** Each faculty its drawer names stands on its registry. One
688
- that fails stays down, and says why.
689
- 5. **Houses.** Each house of the drawer opens on its bodies.
690
- 6. **Hook.** The listeners, then the hand on its socket.
691
- 7. **Ready.** It tells systemd it is up, where systemd waits.
692
-
693
- It is set by its environment.
694
-
695
- | Setting | What it sets |
684
+ 1. **Primordial.** Its ledger goes up and takes the lock on its state,
685
+ so one ground runs on it. Its unlock, crypto and tools go up. Its key
686
+ is read from `state/key`, drawn there on the first start.
687
+ 2. **The ground's work.** The library's `ground` faculty goes up, which
688
+ the dock alone reaches.
689
+ 3. **Dock.** The ground's own house opens in the ledger, under a seed
690
+ its key derives. Its beings hold every entry, seed, secret and
691
+ setting as their cells.
692
+ 4. **Ladder.** The dock's steward joins your entries to the defaults its
693
+ code fixes, yours winning by name. Each entry is held to what its
694
+ faculty takes. Each body is installed where its entry is new, and
695
+ goes up. One that fails stays down, and says why.
696
+ 5. **Houses.** Each house opens on its bodies, and its door joins the
697
+ carry.
698
+ 6. **Hand.** The hand takes its socket, and the ground tells systemd it
699
+ is up.
700
+
701
+ Its environment names what opens its memory, its key and its hand, and
702
+ nothing else.
703
+
704
+ | Variable | What it names |
696
705
  | --- | --- |
697
- | `NERVUR_TCP_PORT` | its TCP port, 9110 where unset |
698
- | `NERVUR_HTTP_PORT` | its HTTP port, for Quo over the web and every handler; no HTTP where unset |
699
- | `NERVUR_ADDRESSES` | the public addresses it writes into invitations, by commas: `tcp`, `https`, `http`, `wss` or `ws` |
700
- | `NERVUR_ORIGINS` | the pages of other origins it answers on the web, by commas; a page of its own host needs none |
701
- | `NERVUR_ALLOW_PRIVATE` | `1` to dial private and loopback addresses, as two grounds on one machine do |
702
- | `NERVUR_BIND` | the address it listens on, `0.0.0.0` where unset |
703
706
  | `NERVUR_STATE` | its state, `state/` in its folder where unset |
704
707
  | `NERVUR_UNLOCK` | `keychain:<account>` keeps its key in the macOS keychain, in place of `state/key` |
705
- | `NERVUR_WAIT` | its bound on every ask, in milliseconds |
708
+ | `NERVUR_HAND` | its hand's socket, `state/hand` where unset |
709
+
710
+ Every other setting is an arg of an entry its dock keeps, set through
711
+ the hand. Its `tcp` entry listens on every address at 9110. Its `web`
712
+ entry serves the ground's one listener over HTTP, for Quo over the web
713
+ and every handler, once its args name a `port`. It names that listener
714
+ in its `faculties`. Both take `bind`, the public `addresses` written
715
+ into invitations, and `allowPrivate` to dial loopback addresses, as two
716
+ grounds on one machine do. `web` also takes the `origins` of pages it
717
+ answers. `wait set` keeps its bound on every ask.
718
+
719
+ ```bash
720
+ npx nervur faculties update name=web make=web faculties='["listener"]' args='{"port":8080}'
721
+ ```
706
722
 
707
723
  The state holds the key in a file its owner alone reads, and the
708
724
  ground's ledger. Every house keeps its rows in that ledger, sealed. A
@@ -714,10 +730,11 @@ lost key is a lost ground.
714
730
 
715
731
  The ladder stands once, and the ground stands it again at every start.
716
732
  The first entry stands the folder's `recipe.ts` as a registry, by the
717
- ground's own maker `module`. The second makes the payments from it.
733
+ faculty `module` the folder's registry holds. The second raises the
734
+ payments from it. An entry names only faculties that stand already.
718
735
 
719
736
  ```bash
720
- npx nervur faculties add name=recipe make=module args='{"at":"recipe.ts"}'
737
+ npx nervur faculties add name=recipe from=folder make=module args='{"at":"recipe.ts"}'
721
738
  ```
722
739
 
723
740
  ```bash
@@ -727,19 +744,21 @@ npx nervur faculties add name=payments from=recipe make=payments
727
744
  A house is added once, and the ground opens it again at every start.
728
745
 
729
746
  ```bash
730
- npx nervur houses add name=shop classes='{"body":"folder","at":"classes"}' faculties='["payments"]'
747
+ npx nervur houses add name=shop classes='{"faculty":"folder","at":"classes"}' faculties='["payments"]'
731
748
  ```
732
749
 
733
- `classes` names the body of the house's code. `folder` is the ground's
734
- own, and a registry may add more, a git repository among them. A house
735
- keeps its rows in the ground's ledger unless its entry names a `memory`
736
- body. `faculties` names what the house receives, and within it each
737
- faculty's entry names in `kinds` the classes that hold it.
750
+ `classes` names the faculty whose body serves the house's code. `folder`
751
+ is the ground's own, and a registry may add more, a git repository among
752
+ them. A house keeps its rows in the ground's ledger unless its entry
753
+ names a `memory` faculty. `faculties` names what the house receives, and
754
+ within it each faculty's entry names in `kinds` the classes that hold
755
+ it. `houses update` and `faculties update` land a new entry in one
756
+ write, and `faculties restart` takes a body down and up again.
738
757
 
739
758
  A secret reaches a faculty the same way, and never through the
740
759
  environment. `npx nervur secrets set -` reads `{ name, value }` from
741
- standard input into the ground's sealed drawer. A faculty's entry names
742
- the secrets its maker receives in `secrets`.
760
+ standard input into a being of the dock, whose cells no one reads. A
761
+ faculty's entry names the secrets its `up` receives in `secrets`.
743
762
 
744
763
  ### The hand
745
764
 
@@ -751,8 +770,10 @@ describes.
751
770
  npx nervur help
752
771
  ```
753
772
 
754
- A faculty's method is called as its owner calls it, and a faculty named
755
- alone shows its methods. Args are one JSON object, or words `key=value`.
773
+ Two words ask the dock, the ground's own steward, so `houses list` asks
774
+ her `housesList`. A faculty named alone shows its methods, and a method
775
+ after it is called through the dock. Args are one JSON object, or words
776
+ `key=value`.
756
777
 
757
778
  ```bash
758
779
  npx nervur houses list
@@ -805,16 +826,17 @@ with `loginctl enable-linger`. On macOS, the agent goes to
805
826
  houses in a page. Every tab and the service worker of one origin share
806
827
  one ground: the one holding the Web Lock runs it, and the others reach
807
828
  its hand over a `BroadcastChannel`. When it closes, the next opens the
808
- ground from the same storage. `hand` answers the same three requests
809
- the command sends: `describe`, a faculty's method, and an ask of a being
810
- in a named house.
829
+ ground from the same storage. `hand` takes the same requests the
830
+ command sends: `describe`, and an ask of a being in a named house. A
831
+ request that names no house asks the dock's steward, as
832
+ `{ method: 'housesList' }`.
811
833
 
812
834
  Its bodies are the browser's. The ground's key is sealed under an AES
813
835
  key that IndexedDB holds unextractable, and its memory is IndexedDB.
814
- Classes load from the page's own origin through the `origin` body, `{
815
- body: 'origin', at: '/house/index.js' }`, and a path off the origin is
816
- refused. The registry is the object you pass: makers of faculties, and
817
- of any custom body, beside the terrain's own.
836
+ Classes load from the page's own origin through the `origin` faculty, `{
837
+ faculty: 'origin', at: '/house/index.js' }`, and a path off the origin
838
+ is refused. The registry is the object you pass: faculties by name,
839
+ foundation and custom alike, beside the terrain's own.
818
840
 
819
841
  Any script on the origin can use the ground's keys, so the ground is
820
842
  whoever serves the origin's script. Give it an origin of its own, serve
@@ -841,7 +863,7 @@ app's web view, on two interfaces the shell fills in native code:
841
863
  The library holds the rest. The ground's key goes into the secret store,
842
864
  and its memory into the native store, which the system never evicts as
843
865
  it may a web view's storage. A push token reaches the ground through a
844
- faculty your registry makes.
866
+ faculty your registry holds.
845
867
 
846
868
  ## What the house guarantees
847
869
 
@@ -899,7 +921,15 @@ at her call, or where an ask arrives.
899
921
  - A call on the house beside `House.open`, `door` and `ask`.
900
922
  - A faculty in a house's code. Faculties are the ground's.
901
923
  - A drawer opened with a key that did not seal it.
902
- - A secret read by a being, a describe or anyone but a maker its entry
903
- names.
904
- - A faculty entry for `secrets` or `moves`, which the hand alone reaches.
924
+ - A secret read by a being, a describe or anyone but a faculty whose
925
+ entry names it.
926
+ - A faculty raised any way but its `up`, foundation or custom.
927
+ - An entry named `dock`, for a house or a faculty. The dock is the
928
+ library's.
929
+ - A secret or a move asked by anyone but the hand.
930
+ - A grant naming a faculty or a secret the ground does not hold.
931
+ - A secret's cells read through the hand.
932
+ - An entry naming, making or granting `ground` or `shell`. Both are the
933
+ dock's alone.
934
+ - A second ground on the state one runs on.
905
935
  - A ground an owner must write. Each terrain's ships.
package/COMMAND.md CHANGED
@@ -17,11 +17,11 @@ alone reads.
17
17
  npx nervur up .
18
18
  ```
19
19
 
20
- The ground stops cleanly on an interrupt and on `SIGTERM`. It takes a
21
- lock on its state, so a second `nervur up` on the same folder refuses to
22
- start. Keep `state/` as you keep an ssh key: whoever holds its key and
23
- its ledger holds the ground, and without the key the ledger opens
24
- nothing.
20
+ The ground stops cleanly on an interrupt and on `SIGTERM`. Its ledger
21
+ holds a lock on its state while it stands, so a second `nervur up` on
22
+ the same folder refuses to start. Keep `state/` as you keep an ssh key:
23
+ whoever holds its key and its ledger holds the ground, and without the
24
+ key the ledger opens nothing.
25
25
 
26
26
  `nervur service` prints what keeps the ground running across reboots: a
27
27
  systemd unit on Linux, a launchd job on macOS. Nothing is installed; you
@@ -33,20 +33,38 @@ npx nervur service /srv/shop
33
33
 
34
34
  ## Settings
35
35
 
36
- A ground reads its settings from the environment.
36
+ The environment names only what opens the ground's memory, its key and
37
+ its hand.
37
38
 
38
- | Setting | What it sets |
39
+ | Variable | What it names |
39
40
  | --- | --- |
40
41
  | `NERVUR_STATE` | the state folder, `state/` in the ground's folder where unset |
41
- | `NERVUR_TCP_PORT` | the TCP port Quo listens on, 9110 where unset |
42
- | `NERVUR_HTTP_PORT` | the port of the web listener, which faces and Quo over the web share; none where unset |
43
- | `NERVUR_BIND` | the address both listen on, every interface where unset |
44
- | `NERVUR_ADDRESSES` | the public addresses written into invitations, by commas |
45
- | `NERVUR_ORIGINS` | the page origins the web listener answers, by commas |
46
- | `NERVUR_ALLOW_PRIVATE` | `1` to let the ground dial a private or loopback address |
47
42
  | `NERVUR_UNLOCK` | on macOS, `keychain:<account>` keeps the key in the keychain in place of `state/key` |
48
43
  | `NERVUR_HAND` | where the hand's socket is, `state/hand` where unset; a relative path is read from where the command runs |
49
- | `NERVUR_WAIT` | the longest any ask may run, in milliseconds |
44
+
45
+ Every other setting is an entry the ground's dock keeps, set through the
46
+ hand and kept across a restart. The `tcp` entry listens on the loopback
47
+ at 9110 until you name another bind, and the `web` entry listens on no
48
+ port until one is named. The web serves the ground's one listener,
49
+ which its entry names in `faculties`.
50
+
51
+ | Arg | Of | What it sets |
52
+ | --- | --- | --- |
53
+ | `port` | `tcp`, `web` | the port it listens on; with none, it only dials |
54
+ | `bind` | `tcp`, `web` | the address it listens on, every interface where unset |
55
+ | `addresses` | `tcp`, `web` | the public addresses written into invitations |
56
+ | `origins` | `web` | the page origins the web listener answers |
57
+ | `allowPrivate` | `tcp`, `web` | `true` to let the ground dial a private or loopback address |
58
+
59
+ ```bash
60
+ npx nervur faculties update name=web make=web faculties='["listener"]' args='{"port":8080,"addresses":["https://shop.example/quo"]}'
61
+ npx nervur wait set wait=30000
62
+ ```
63
+
64
+ `faculties catalog` prints every faculty the ground can raise and what
65
+ each takes, so an entry it refuses says which arg failed. `wait set`
66
+ keeps the longest any ask may run, in milliseconds, and `wait show`
67
+ prints it.
50
68
 
51
69
  A ground that people reach names its public addresses. Without them, it
52
70
  writes only the addresses it listens on, which a stranger cannot reach.
@@ -62,22 +80,31 @@ Every other word goes to the ground's hand, a socket in `state/` that
62
80
  your user alone may open. Run the command in the ground's folder, or
63
81
  name the socket with `--at <socket>` or `NERVUR_HAND`.
64
82
 
65
- `help` prints what the ground holds: each faculty with its methods, or
66
- why it is down, and each house.
83
+ `help` prints what the ground holds: the asks of its dock, each faculty
84
+ with its methods or why it is down, and each house.
67
85
 
68
86
  ```bash
69
87
  npx nervur help
70
88
  ```
71
89
 
72
- A faculty is called by its name and a method. Named alone, it prints its
73
- methods. Four faculties are the ground's own. `secrets` keeps a secret
74
- in the ground's sealed drawer. `faculties` stands a faculty on the maker
75
- its entry names, and `houses` opens a house on its entry.
90
+ The dock is the ground's own house, and its steward changes the ground.
91
+ Two words ask her, so `houses add` asks `housesAdd`. One word alone
92
+ prints the asks it begins. `secrets set` keeps a secret in a being of
93
+ the dock, whose cells no one reads. `faculties add` raises a faculty by
94
+ the `up` its entry names, and `houses add` opens a house on its entry.
95
+ Each answers why the body is down or the house closed, where it is.
96
+ Each `update` lands a new entry in one write, and `faculties restart`
97
+ takes a body down and up again. A faculty named with a method is called
98
+ through the dock, and named alone it prints its methods.
99
+
100
+ An entry names only faculties and secrets the ground holds already. A
101
+ module and a program stand on the folder's registry, so their entries
102
+ say `from=folder`.
76
103
 
77
104
  ```bash
78
- npx nervur faculties add name=recipe make=module args='{"at":"recipe.ts"}'
105
+ npx nervur faculties add name=recipe from=folder make=module args='{"at":"recipe.ts"}'
79
106
  npx nervur faculties add name=payments from=recipe make=payments secrets='["stripe-key"]'
80
- npx nervur houses add name=main classes='{"body":"folder","at":"house"}' faculties='["payments"]'
107
+ npx nervur houses add name=main classes='{"faculty":"folder","at":"house"}' faculties='["payments"]'
81
108
  ```
82
109
 
83
110
  `ask` asks a being of a house, as the house's owner. `--id <being>` names
@@ -96,6 +123,22 @@ repair, or a look at what her asks do not show.
96
123
  npx nervur ask main --cells
97
124
  ```
98
125
 
126
+ `ask dock` asks the dock's own beings, since no house takes that name.
127
+ `faculty.<name>`, `house.<name>` and the steward hold every entry, seed
128
+ and setting, and a secret's cells are shown to no one.
129
+
130
+ ```bash
131
+ npx nervur ask dock --id faculty.web --cells
132
+ ```
133
+
134
+ `shell run` runs a command on the ground's machine, in its code folder,
135
+ and prints its exit code and what it printed. The words after `--` are
136
+ the command line. Its environment holds nothing of the ground's.
137
+
138
+ ```bash
139
+ npx nervur shell run -- git status
140
+ ```
141
+
99
142
  The command asks no watch. A watch is held by a being on her standing,
100
143
  or by a page through a face, where something waits on its answer.
101
144
 
@@ -116,6 +159,14 @@ secret never stands on a command line or in a shell's history.
116
159
  npx nervur secrets set - < stripe-key.json
117
160
  ```
118
161
 
162
+ `--call <id>`, before the words, names the ask's call id. The same ask
163
+ sent again with the same id answers what the first answered, and runs
164
+ nothing twice. So a script that lost an answer sends its ask again.
165
+
166
+ ```bash
167
+ npx nervur --call deploy-42 houses update name=main classes='{"faculty":"folder","at":"house"}'
168
+ ```
169
+
119
170
  Each word prints one JSON value, the answer, and its exit code says what
120
171
  came back.
121
172
 
package/FACES.md CHANGED
@@ -106,11 +106,12 @@ tries again acts once.
106
106
 
107
107
  ```ts
108
108
  // api.ts
109
- import type { Faculty, FacultyContext, Handler } from 'nervur';
109
+ import type { Body, FacultyContext, Handler } from 'nervur';
110
110
  import { need, s, type Json } from 'nervur/being';
111
111
 
112
112
  type Answer = Awaited<ReturnType<FacultyContext['call']>>;
113
113
  type Entry = { method: string; description?: string; args?: Json; hints?: Json };
114
+ type Calls = Pick<FacultyContext, 'call' | 'describe'>;
114
115
 
115
116
  /** What the steward arms the face with. */
116
117
  export const FaceBlueprint = need('face', {
@@ -124,9 +125,8 @@ export const FaceBlueprint = need('face', {
124
125
  * asks to an agent as tools.
125
126
  */
126
127
  export class Api {
127
- #context: FacultyContext | undefined;
128
+ #context: Calls | undefined;
128
129
  #signup = '';
129
- #calls = 0;
130
130
 
131
131
  arm({ signup }: { signup: string }, context: FacultyContext): Promise<Answer> {
132
132
  this.#context = context;
@@ -134,14 +134,19 @@ export class Api {
134
134
  return Promise.resolve({ result: null });
135
135
  }
136
136
 
137
- #held(): FacultyContext {
137
+ // Told its house opened: every door's token answers from the first request, after any restart.
138
+ opened(context: Calls): void {
139
+ this.#context = context;
140
+ }
141
+
142
+ #held(): Calls {
138
143
  if (this.#context === undefined) throw new Error('the face is not armed');
139
144
  return this.#context;
140
145
  }
141
146
 
142
- // Each call its own id, so a call the house retries acts once.
147
+ // Each call an id drawn afresh, so no life of the face repeats one.
143
148
  #ask(token: string, method: string, args: Json): Promise<Answer> {
144
- return this.#held().call({ token, method, args, id: `api:${++this.#calls}` });
149
+ return this.#held().call({ token, method, args, id: `api:${crypto.randomUUID()}` });
145
150
  }
146
151
 
147
152
  async #tools(token: string): Promise<Json> {
@@ -179,8 +184,8 @@ export class Api {
179
184
  };
180
185
  }
181
186
 
182
- /** The offer a ground hands: the blueprint, the object, and its handler on the ground's listener. */
183
- export const apiOffer = (api: Api): Faculty => ({ blueprint: FaceBlueprint, object: api, handler: api.handler });
187
+ /** The face as a body. */
188
+ export const apiOffer = (api: Api): Body => ({ blueprint: FaceBlueprint, object: api, handler: api.handler, opened: (context) => api.opened(context) });
184
189
  ```
185
190
 
186
191
  **The describe maps onto tools by renaming.** An ask is a tool, its
@@ -190,24 +195,24 @@ tools.
190
195
 
191
196
  ## The registry
192
197
 
193
- The ground makes the face from a registry, as it makes any faculty. A
194
- NodeGround stands the module below with the maker `module`, and the
195
- face from it by an entry that names `from`. The house's entry names
196
- `face` among its faculties, and the steward's `arm` hands the face its
197
- signup.
198
+ The ground raises the face from a registry by its `up`, as it raises any
199
+ faculty. A NodeGround stands the module below with the faculty
200
+ `module`, and the face from it by an entry that names `from`. The
201
+ house's entry names `face` among its faculties, and the steward's `arm`
202
+ hands the face its signup.
198
203
 
199
204
  ```ts
200
205
  // recipe.ts
201
206
  import { Api, apiOffer } from './api.ts';
202
207
 
203
- // A registry: the ground makes the face when an entry names its maker.
208
+ // A registry: the ground raises the face by its `up` when an entry names it.
204
209
  export const faculties = {
205
- face: () => apiOffer(new Api()),
210
+ face: { up: () => apiOffer(new Api()) },
206
211
  };
207
212
  ```
208
213
 
209
214
  ```bash
210
- npx nervur faculties add name=recipe make=module args='{"at":"recipe.ts"}'
215
+ npx nervur faculties add name=recipe from=folder make=module args='{"at":"recipe.ts"}'
211
216
  npx nervur faculties add name=face from=recipe make=face
212
217
  ```
213
218
 
@@ -229,7 +234,7 @@ import { faculties } from './recipe.ts';
229
234
  test('A person signs up at the face, and reaches their member as an API and as tools', async (t) => {
230
235
  const ground = await BenchGround.open({ network: new FakeNetwork(), host: 'desk', modules: { desk }, registry: { faculties } });
231
236
  t.after(() => ground.down());
232
- await ground.hand({ faculty: 'faculties', method: 'add', args: { name: 'face', make: 'face' } });
237
+ await ground.hand({ method: 'facultiesAdd', args: { name: 'face', make: 'face' } });
233
238
  await ground.add('desk', 'desk', { faculties: ['face'] });
234
239
  await ground.ask({ house: 'desk', method: 'arm' });
235
240
  const web = async (path: string, body?: unknown, token?: string) =>