nervur 0.22.2-4 → 0.22.2-6

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 (109) hide show
  1. package/AUTHORING.md +129 -68
  2. package/COMMAND.md +113 -0
  3. package/FACES.md +264 -0
  4. package/FACULTIES.md +487 -0
  5. package/GROUNDS.md +159 -0
  6. package/KIT-SPEC.md +16 -1
  7. package/README.md +16 -9
  8. package/WORLD.md +195 -0
  9. package/dist/app/app-ground.d.ts +1 -1
  10. package/dist/app/app-ground.js +3 -5
  11. package/dist/app/index.d.ts +1 -1
  12. package/dist/app/native.d.ts +9 -44
  13. package/dist/app/native.js +7 -95
  14. package/dist/being/being.d.ts +84 -7
  15. package/dist/being/being.js +1 -1
  16. package/dist/being/index.d.ts +2 -1
  17. package/dist/being/index.js +1 -0
  18. package/dist/being/table.d.ts +6 -0
  19. package/dist/being/table.js +72 -16
  20. package/dist/bench/bench-ground.d.ts +22 -8
  21. package/dist/bench/bench-ground.js +29 -6
  22. package/dist/bench/bench.d.ts +43 -29
  23. package/dist/bench/bench.js +240 -132
  24. package/dist/bench/fake-clock.d.ts +1 -1
  25. package/dist/bench/fake-custody.d.ts +8 -2
  26. package/dist/bench/fake-custody.js +30 -1
  27. package/dist/bench/fake-keys.d.ts +1 -2
  28. package/dist/bench/fake-keys.js +1 -1
  29. package/dist/bench/fake-memory.d.ts +3 -1
  30. package/dist/bench/fake-network.d.ts +16 -7
  31. package/dist/bench/fake-network.js +67 -14
  32. package/dist/bench/index.d.ts +3 -11
  33. package/dist/bench/index.js +2 -10
  34. package/dist/bench/seeded.d.ts +1 -1
  35. package/dist/bench/seeded.js +1 -1
  36. package/dist/bench/stewards.d.ts +157 -5
  37. package/dist/bench/stewards.js +115 -7
  38. package/dist/bodies/joined-carry.d.ts +7 -1
  39. package/dist/bodies/joined-carry.js +9 -3
  40. package/dist/bodies/kept.d.ts +55 -0
  41. package/dist/bodies/kept.js +110 -0
  42. package/dist/bodies/vouch.d.ts +20 -0
  43. package/dist/bodies/vouch.js +71 -0
  44. package/dist/bodies/web-carry.d.ts +9 -2
  45. package/dist/bodies/web-carry.js +30 -9
  46. package/dist/browser/browser-ground.d.ts +17 -2
  47. package/dist/browser/browser-ground.js +25 -13
  48. package/dist/browser/index.d.ts +2 -2
  49. package/dist/browser/locked-custody.d.ts +9 -0
  50. package/dist/browser/locked-custody.js +25 -4
  51. package/dist/edge/durable-clock.d.ts +19 -0
  52. package/dist/edge/durable-clock.js +61 -0
  53. package/dist/edge/durable-memory.d.ts +5 -0
  54. package/dist/edge/durable-memory.js +11 -0
  55. package/dist/edge/durable.d.ts +18 -0
  56. package/dist/edge/durable.js +24 -0
  57. package/dist/edge/edge-ground.d.ts +58 -0
  58. package/dist/edge/edge-ground.js +211 -0
  59. package/dist/edge/index.d.ts +7 -0
  60. package/dist/edge/index.js +9 -0
  61. package/dist/edge/native-crypto.d.ts +8 -0
  62. package/dist/edge/native-crypto.js +102 -0
  63. package/dist/edge/secret-custody.d.ts +6 -0
  64. package/dist/edge/secret-custody.js +40 -0
  65. package/dist/edge/socket-carry.d.ts +39 -0
  66. package/dist/edge/socket-carry.js +111 -0
  67. package/dist/foundation.d.ts +12 -0
  68. package/dist/ground/ground.d.ts +110 -3
  69. package/dist/ground/ground.js +299 -58
  70. package/dist/house/crossing.d.ts +18 -6
  71. package/dist/house/crossing.js +35 -14
  72. package/dist/house/house.d.ts +26 -28
  73. package/dist/house/house.js +405 -167
  74. package/dist/house/rows-shape.d.ts +8 -1
  75. package/dist/house/rows.js +32 -15
  76. package/dist/index.d.ts +9 -6
  77. package/dist/index.js +1 -0
  78. package/dist/node/bridge.js +49 -14
  79. package/dist/node/cli.js +15 -5
  80. package/dist/node/custody.d.ts +14 -0
  81. package/dist/node/custody.js +28 -4
  82. package/dist/node/file-keys.d.ts +4 -0
  83. package/dist/node/file-keys.js +26 -12
  84. package/dist/node/file-memory.js +2 -7
  85. package/dist/node/hand.d.ts +10 -1
  86. package/dist/node/hand.js +29 -7
  87. package/dist/node/index.d.ts +5 -5
  88. package/dist/node/keychain-keys.d.ts +2 -0
  89. package/dist/node/keychain-keys.js +11 -7
  90. package/dist/node/ledger-memory.js +3 -2
  91. package/dist/node/node-ground.d.ts +5 -1
  92. package/dist/node/node-ground.js +21 -12
  93. package/dist/node/sync-folder.d.ts +6 -0
  94. package/dist/node/sync-folder.js +18 -0
  95. package/dist/node/tcp-carry.d.ts +8 -7
  96. package/dist/node/tcp-carry.js +21 -53
  97. package/dist/node/websocket.d.ts +8 -2
  98. package/dist/node/websocket.js +20 -4
  99. package/dist/quo/frame.d.ts +13 -0
  100. package/dist/quo/frame.js +44 -0
  101. package/dist/quo/index.d.ts +1 -0
  102. package/dist/quo/index.js +5 -0
  103. package/dist/serve/index.d.ts +8 -3
  104. package/dist/serve/index.js +9 -5
  105. package/package.json +12 -2
  106. package/dist/bench/fake-carry.d.ts +0 -32
  107. package/dist/bench/fake-carry.js +0 -56
  108. package/dist/bench/fake-faculty.d.ts +0 -25
  109. package/dist/bench/fake-faculty.js +0 -48
package/AUTHORING.md CHANGED
@@ -1,10 +1,10 @@
1
1
  # Writing for nervur
2
2
 
3
3
  This guide teaches the two things you write with `nervur`. A **being**
4
- holds logic and state. A **faculty** reaches the world outside. A
5
- **ground** runs them on a machine, and the library ships it. The
6
- examples build one small shop, and every file here is a file the
7
- package's own tests run.
4
+ holds logic and state. A **faculty** reaches the world outside, and
5
+ [Writing a faculty](FACULTIES.md) teaches it whole. A **ground** runs them on
6
+ a machine, and the library ships it. The examples build one small shop,
7
+ and every file here is a file the package's own tests run.
8
8
 
9
9
  The shop has three classes and one faculty.
10
10
 
@@ -169,7 +169,7 @@ JavaScript writes nothing.
169
169
  | `args` | the schema of what it takes; omitted, the empty object alone |
170
170
  | `result` | the schema of what it answers; omitted, nothing |
171
171
  | `hints` | `readOnly`, `idempotent`, `destructive` |
172
- | `examples` | cells, a role, args, fakes, and what it gives |
172
+ | `examples` | a history of her asks, a role, args, fakes, and what it gives |
173
173
  | `description` | one line for readers and agents |
174
174
  | `wait` | milliseconds she may run; omitted, thirty seconds |
175
175
 
@@ -202,6 +202,9 @@ nothing lands.
202
202
  | `this.house.cancelAlarm({ key })` | an alarm removed |
203
203
  | `this.<need>.<method>({…}, { reply? })` | an awaited call, or an effect |
204
204
  | `this.held(id, Need).<ask>({…}, { reply?, after? })` | the same, on a standing, and a watch where `after` is given |
205
+ | `this.held(id).describe()`, `.ask(method, {…}, options)` | a standing with no need: what it shows her, then any ask it showed |
206
+ | `this.stranger({ ward, at }, Need).<ask>({…})` | a far house's public being, asked as a stranger, every ask awaited |
207
+ | `this.stranger({ ward, at }).describe()`, `.ask(method, {…})` | the same with no need: what she shows a stranger, then any ask it showed |
205
208
  | `this.standings` | `list()`, `note(id, notes)` and `drop(id)` |
206
209
  | `this.handle(ask, { bind?, notes?, once?, expires? })` | a handle to one of her asks |
207
210
  | `this.invite(id, { notes?, expires? })` | a new occupant, as a handle |
@@ -261,6 +264,12 @@ hold: `{ result: [...] }`. From a being, pass the result she holds:
261
264
  `readOnly` ask is watched, and a watch on anything else is refused where
262
265
  she makes it.
263
266
 
267
+ A watch may land as a reply instead: `{ after: seen, reply: 'heard' }`.
268
+ It leaves once her ask lands, as an effect does, and its answer asks her
269
+ `heard`, where she writes what she heard and watches again. So a device
270
+ that only dials, a phone or a Pi behind a router, hears its station the
271
+ moment something changes there, and opens no port.
272
+
264
273
  A watch moves only on what its asker could read, since it runs as that
265
274
  asker. One asker holds one watch on one ask with the same args, and a
266
275
  second answers the first at once. A watch across a door holds its
@@ -277,7 +286,11 @@ An **occupant** is someone who may ask her. She mints one with
277
286
  A **standing** is someone she may ask. She receives one where an ask's
278
287
  args carry an invitation under `s.handle`, or where her steward
279
288
  introduces one. She asks through it with `this.held(id, Need)`, which
280
- checks the standing's describe covers the need.
289
+ checks the standing's describe covers the need. A standing from an
290
+ invitation is named `standing:` and sixteen hex digits, and the id is
291
+ what her ask receives. One her steward introduced is named by the being
292
+ it reaches. She asks a far standing from the ask after the one that took
293
+ it.
281
294
 
282
295
  Every relation carries two sets of notes. `notes` are hers alone.
283
296
  `steward` are her steward's, written when the steward made the relation,
@@ -365,13 +378,14 @@ export class Shop extends Being.of({
365
378
  | `bear({ kind, id, args })` | places a new being; the same id twice answers the first |
366
379
  | `remove({ id })` | removes a being and everything of hers |
367
380
  | `list()` | every being, her kind, whether she is absent, and her dead letters |
368
- | `ask({ id, method, args }, { reply? })` | asks any being as her occupant `steward` |
381
+ | `ask({ id, method, args }, { reply? })` | asks any being as her occupant `steward`; with no method, reads what she shows the steward |
369
382
  | `introduce({ from, to, notes })` | gives `from` a standing on `to`, and `to` an occupant |
370
383
  | `invite({ id, occupant, notes, expires? })` | gives a being a new occupant, and the steward its handle |
371
384
 
372
385
  `bear`, `remove`, `introduce` and `invite` land in the steward's own
373
386
  write. If her ask fails, none of them happened. A being borne runs her
374
- `born` ask first, where her class declares one.
387
+ `born` ask first, where her class declares one, asked as the occupant
388
+ `steward`, so its entry says `for: 'steward'`.
375
389
 
376
390
  Every other being is placed as `normal`. She holds the standing
377
391
  `steward` and the occupant `steward`, and can drop neither.
@@ -469,10 +483,19 @@ hold.
469
483
  Every need is covered, or she is absent. An absent being answers silence
470
484
  and keeps her cells, and answers again once an offer covers her needs.
471
485
 
486
+ A standing is matched to a need by rules two to four alone. A describe
487
+ names no blueprint, so the need's name is hers to choose there.
488
+
489
+ A need she forgot to declare is a member she does not hold, and the call
490
+ throws inside her ask, which answers only `the ask failed`. So check your
491
+ classes with `npx tsc --noEmit` beside your tests, which run with
492
+ `node --test`.
493
+
472
494
  ### Testing on the bench
473
495
 
474
- The bench opens two houses in one process, on fake memory, keys, clock
475
- and carry. So every ask crosses a door as it would in production.
496
+ The bench opens two houses on one ground in memory, on fake memory,
497
+ keys and clock. A being of the bench's own house asks hers through a
498
+ door, so every ask crosses as it would in production.
476
499
 
477
500
  ```ts
478
501
  // order.test.ts
@@ -495,38 +518,49 @@ test('An order is paid once the provider calls the handle it was given', async (
495
518
  assert.deepEqual(await order.ask('add', { sku: 'tea', price: 4 }), { result: { total: 4 } });
496
519
  assert.deepEqual(await order.ask('checkout'), { result: null });
497
520
  await bench.settle();
498
- assert.equal((await order.cells())!.state, 'paying', 'the charge left once checkout landed, and answered pending');
521
+ assert.equal((await order.describe())?.state, 'paying', 'the charge left once checkout landed, and answered pending');
499
522
 
500
523
  assert.deepEqual(await payments.settle('first'), { result: null });
501
524
  await bench.settle();
502
- assert.equal((await order.cells())!.state, 'paid');
525
+ assert.equal((await order.describe())?.state, 'paid');
503
526
  assert.deepEqual(await order.ask('add', { sku: 'jam', price: 1 }), { error: { message: 'not in this state' } });
504
527
  });
505
528
  ```
506
529
 
507
- `place(Class, { id, cells })` bears a being and starts her from those
508
- cells. A placed being is asked with `ask(method, args, { role })`,
509
- described with `describe({ role })`, and read with `cells()`. `settle()`
510
- lets every effect and reply run, and `advance(ms)` moves the fake clock.
511
-
512
- The bench plays a role with an occupant named for it, whose own notes and
513
- steward notes both hold the role as `true`.
530
+ `place(Class, { id, born })` has the bench's steward bear a being. A
531
+ placed being is asked with `ask(method, args, { role })` and described
532
+ with `describe({ role })`. Test her through her asks first, as every
533
+ asker meets her. `cells()` reads her cells through the hand, as her owner
534
+ inspects them. An effect answers with the reply it brings once it lands.
535
+ `settle()` lets every effect and reply run, and `advance(ms)` moves the
536
+ fake clock.
537
+
538
+ The bench plays a role as an owner could, judged on her cells as they
539
+ stand. `root`, and a role root holds, is the hand. `steward` is the
540
+ bench's steward, and `being` a being it introduces to her. Any other
541
+ role is an occupant the bench's steward invites, with the role `true` in
542
+ its steward notes. A role read from her own notes is hers to grant, and
543
+ a handle only her own ask mints.
514
544
 
515
545
  A steward and a public being are placed where the house places them.
516
546
  `Bench.open({ steward: Shop, public: Lobby, classes: [Order] })` opens the
517
547
  author's house with them there, and `place(Shop)` and `place(Lobby)` find
518
- them. A role `root` holds is played through the hand, on any being. On
519
- the public being, a role a stranger holds is played by a box with no
520
- relation, signed with a key drawn from the bench's seed.
548
+ them. On the public being, a role a stranger holds is played by a being
549
+ of the bench's own house, asking as a stranger. Beside a steward the test
550
+ brings, the bench plays `root` and `stranger` alone, and places no other
551
+ being. A world of your steward and the beings she bears is tested on a
552
+ BenchGround, as [Faces](FACES.md) tests its desk.
521
553
  `Bench.check(Shop, { position: 'steward' })` and `Bench.check(Lobby, {
522
- position: 'public', steward: Shop })` check them.
554
+ position: 'public' })` check them.
523
555
 
524
- An entry's `examples` are tests the bench runs. Each is one ask on a
525
- fresh bench: `cells` start her, `role` asks, `args` are the ask's,
526
- `fakes` answer her needs, and `gives` is the answer owed. `Bench.check`
527
- runs every example twice from one seed and flags a class that answers
528
- differently. It then describes every state to every role, and names every
529
- finding that failed.
556
+ An entry's `examples` are tests the bench runs. Each is a history, then
557
+ one ask, on a fresh bench. `given` lists the asks of hers that bring her
558
+ from her `born` to where the example starts. `role` asks, `args` are the
559
+ ask's, `fakes` answer her needs, and `gives` is the answer owed.
560
+ `Bench.check` runs every example twice from one seed and flags a class
561
+ that answers differently, or leaves her cells differently. It then
562
+ describes every state to every role it plays, and names every finding
563
+ that failed.
530
564
 
531
565
  ## A faculty
532
566
 
@@ -582,34 +616,11 @@ export const paymentsOffer = (payments: Payments): Offer => ({ blueprint: Paymen
582
616
  ```
583
617
 
584
618
  An offer is `{ blueprint, object, kinds?, window?, handler?, stop? }`.
585
-
586
- - **The object has the blueprint's methods.** Each takes one args object
587
- and a context, and answers `{ result }` or `{ error: { message } }`. A
588
- throw is a failure to answer, and the house tries again.
589
- - **The context holds the call id.** An effect arrives again with the same
590
- call id when an answer was lost. A faculty that changes the world
591
- answers a call id it has seen with the answer it gave.
592
- - **A handle arrives as a token.** The faculty calls it with
593
- `context.call({ token, args, id })`. Its own `id` makes that call run
594
- once, however often it is sent.
595
- - **`kinds` is the ground's grant.** It lists the classes that may hold
596
- the offer. Without it, every class whose need it covers holds it.
597
- - **`window` is how long the faculty remembers a call id.** It is seven
598
- days where omitted, and the house gives up on an effect at it.
599
- - **`handler` answers HTTP on the ground's one listener.** It takes a
600
- `Request` and answers a `Response`, or `null` where the request is not
601
- its own. A site, an API or an MCP server is a faculty with a handler.
602
- - **`stop` is called when the ground stops**, faculties in the reverse of
603
- the order they were made.
604
-
605
- The object arrives living. The ground makes and starts the faculty, and
606
- the house never starts, stops or restarts it. Every being whose need it
607
- covers holds the same object.
608
-
609
- A faculty is the ground's, never a house's. The ground's recipe makes
610
- each one by name, from the settings the ground hands it. `env` is the
611
- ground's environment, so a secret stays on its machine and out of the
612
- code. `dir(name)` answers a folder of the faculty's own.
619
+ The object answers each call with its call id, and one that changes the
620
+ world answers a call id it has seen with the answer it gave. The ground's
621
+ recipe makes each faculty by name, and `kinds` grants it to the classes
622
+ it names. [Writing a faculty](FACULTIES.md) teaches the craft whole, with a
623
+ faculty written in Python.
613
624
 
614
625
  ```ts
615
626
  // recipe.ts
@@ -620,10 +631,6 @@ export const faculties = () => ({
620
631
  });
621
632
  ```
622
633
 
623
- Policy over a faculty is written as a being. Limits, approvals and
624
- quotas are not the faculty's. One being holds the raw faculty through
625
- `kinds`, and every other being reaches her through a standing.
626
-
627
634
  ## A ground
628
635
 
629
636
  A ground is the process houses run in, and you write none. `nervur up`
@@ -641,6 +648,13 @@ nervur-ground/
641
648
  state/ made by the ground, its owner's alone
642
649
  ```
643
650
 
651
+ The folder is a package of ECMAScript modules, so Node reads its
652
+ TypeScript as it is written, with no build step.
653
+
654
+ ```bash
655
+ npm init -y && npm pkg set type=module && npm install nervur
656
+ ```
657
+
644
658
  A house's folder names what the house holds.
645
659
 
646
660
  ```ts
@@ -672,9 +686,11 @@ It is set by its environment.
672
686
 
673
687
  | Setting | What it sets |
674
688
  | --- | --- |
675
- | `NERVUR_TCP_PORT` | its TCP port, 7300 where unset |
689
+ | `NERVUR_TCP_PORT` | its TCP port, 9110 where unset |
676
690
  | `NERVUR_HTTP_PORT` | its HTTP port, for Quo over the web and every handler; no HTTP where unset |
677
- | `NERVUR_ADDRESSES` | the public addresses it writes into invitations, by commas |
691
+ | `NERVUR_ADDRESSES` | the public addresses it writes into invitations, by commas: `tcp`, `https`, `http`, `wss` or `ws` |
692
+ | `NERVUR_ORIGINS` | the pages of other origins it answers on the web, by commas; a page of its own host needs none |
693
+ | `NERVUR_ALLOW_PRIVATE` | `1` to dial private and loopback addresses, as two grounds on one machine do |
678
694
  | `NERVUR_BIND` | the address it listens on, `0.0.0.0` where unset |
679
695
  | `NERVUR_STATE` | its state, `state/` in its folder where unset |
680
696
  | `NERVUR_KEYCHAIN` | a keychain service holding its seeds on macOS, in place of files |
@@ -682,8 +698,10 @@ It is set by its environment.
682
698
 
683
699
  The state holds each house's seed in a file its owner alone reads, and
684
700
  each house's ledger. A ledger appends every write and never rewrites
685
- one, and one behind its witness is refused, so a restored backup cannot
686
- replay what a house already answered. A lost seed is a lost house.
701
+ one. Its witness keeps where it last stood, and a ledger behind its
702
+ witness is refused. So a ledger restored alone cannot replay what a
703
+ house already answered, though a whole state folder restored with its
704
+ witnesses is not seen. A lost seed is a lost house.
687
705
 
688
706
  A house is added once, and the ground opens it again at every start.
689
707
 
@@ -714,17 +732,23 @@ npx nervur houses list
714
732
  ```
715
733
 
716
734
  `ask` asks a being in a house as `root`: the steward, or the being
717
- `--id` names. The owner lands a paper in a being with one ask, and her
718
- `accept` names `root` in its `for`, or names no `for`.
735
+ `--id` names. The owner opens an order through the steward, and hands a
736
+ courier's paper to it the same way. The steward's `hire` carries the
737
+ paper unopened, and the order takes it.
719
738
 
720
739
  ```bash
721
740
  npx nervur ask shop open id=first
722
741
  ```
723
742
 
724
743
  ```bash
725
- npx nervur ask shop --id alice accept invitation=7b22…
744
+ npx nervur ask shop hire order=first courier=7b22…
726
745
  ```
727
746
 
747
+ `--id` names the being asked in the steward's place, as `npx nervur ask
748
+ shop --id first` shows the order's describe. `--cells` reads her cells
749
+ and asks nothing, as `npx nervur ask shop --id first --cells`. No one
750
+ but the owner reads them, and only her own asks write them.
751
+
728
752
  Each prints one JSON value. It exits 0 on a result and 1 on an error
729
753
  answered. It exits 2 where nothing was asked, so a script tells a
730
754
  refusal from a ground that is down. The hand is `state/hand` in the
@@ -812,3 +836,40 @@ through a faculty your recipe makes.
812
836
  leaves her absent, and the refusal says why.
813
837
 
814
838
  A failed ask changed nothing she owns, so asking again is safe.
839
+
840
+ ## What the house refuses
841
+
842
+ Each refusal answers why, where it is met: at her class's first resolve,
843
+ at her call, or where an ask arrives.
844
+
845
+ - A being reaching anything her position, her needs and `this.house` do
846
+ not give.
847
+ - A ground's own references handed to a being, or offered to her as a
848
+ faculty.
849
+ - A handle or an invitation in her cells.
850
+ - Her cells read by anyone but the owner's hand.
851
+ - A standing she mints herself. Standings arrive from the house.
852
+ - A far standing asked in the ask that took it. She asks it from her next
853
+ ask.
854
+ - A write by anyone else to her notes, and by her to her steward's.
855
+ - An occupant id the house reserves, and one she already holds.
856
+ - Two member names that clash.
857
+ - An ask with no entry.
858
+ - A state no ask reaches, an ask no role reaches, and a role unused.
859
+ - A method landing in a state its `to` does not name.
860
+ - A `readOnly` ask that writes.
861
+ - A need and an offer that disagree on `idempotent`.
862
+ - A schema keyword outside the subset `s` writes.
863
+ - Two offers covering one need for one kind, and a kind two sources
864
+ claim.
865
+ - An effect sent before its ask landed, or sent again while a call for
866
+ it is pending.
867
+ - An ask a stranger reaches that is not idempotent.
868
+ - An invite from a public being.
869
+ - A seed inside the house, and a seed that is not sixty-four hex digits.
870
+ - A memory opened with keys that derive another bound.
871
+ - A send to a private address, unless its ground allows it.
872
+ - A call on the house beside `House.open`, `door` and `ask`.
873
+ - A faculty in a house's code. Faculties are the ground's.
874
+ - A custom body for a ground's own custody or memory.
875
+ - A ground an owner must write. Each terrain's ships.
package/COMMAND.md ADDED
@@ -0,0 +1,113 @@
1
+ # The command
2
+
3
+ `nervur` is the command the package installs. It holds no business of
4
+ its own. Two words start things on your machine, and every other word is
5
+ read from what the running ground says it holds. This guide assumes you
6
+ have read [the package's start](README.md), which runs a first ground.
7
+
8
+ ## Starting a ground
9
+
10
+ `nervur up` runs a NodeGround on a folder until it is stopped. The folder
11
+ holds the ground's recipe, a folder of code for each house, and `state/`,
12
+ where the ground keeps its seeds, its record and its hand.
13
+
14
+ ```bash
15
+ npx nervur up .
16
+ ```
17
+
18
+ The ground stops cleanly on an interrupt and on `SIGTERM`. It takes a
19
+ lock on its folder, so a second `nervur up` on the same folder refuses to
20
+ start.
21
+
22
+ `nervur service` prints what keeps the ground running across reboots: a
23
+ systemd unit on Linux, a launchd job on macOS. Nothing is installed; you
24
+ place what it prints.
25
+
26
+ ```bash
27
+ npx nervur service /srv/shop
28
+ ```
29
+
30
+ ## Settings
31
+
32
+ A ground reads its settings from the environment.
33
+
34
+ | Setting | What it sets |
35
+ | --- | --- |
36
+ | `NERVUR_STATE` | the state folder, `state/` in the ground's folder where unset |
37
+ | `NERVUR_TCP_PORT` | the TCP port Quo listens on, 9110 where unset |
38
+ | `NERVUR_HTTP_PORT` | the port of the web listener, which faces and Quo over the web share; none where unset |
39
+ | `NERVUR_BIND` | the address both listen on, every interface where unset |
40
+ | `NERVUR_ADDRESSES` | the public addresses written into invitations, by commas |
41
+ | `NERVUR_ORIGINS` | the page origins the web listener answers, by commas |
42
+ | `NERVUR_ALLOW_PRIVATE` | `1` to let the ground dial a private or loopback address |
43
+ | `NERVUR_KEYCHAIN` | on macOS, a keychain service that keeps the seeds in place of files |
44
+ | `NERVUR_HAND` | where the hand's socket is, `state/hand` where unset; a relative path is read from where the command runs |
45
+ | `NERVUR_WAIT` | the longest any ask may run, in milliseconds |
46
+
47
+ A ground that people reach names its public addresses. Without them, it
48
+ writes only the addresses it listens on, which a stranger cannot reach.
49
+
50
+ A socket's path fits 103 bytes on macOS and 107 on Linux, and a longer
51
+ one refuses to start by name. A ground in a deep folder names a shorter
52
+ path in `NERVUR_HAND`, such as `state/hand` run from the folder, and every
53
+ command that reaches it names the same.
54
+
55
+ ## Asking the ground
56
+
57
+ Every other word goes to the ground's hand, a socket in `state/` that
58
+ your user alone may open. Run the command in the ground's folder, or
59
+ name the socket with `--at <socket>` or `NERVUR_HAND`.
60
+
61
+ `help` prints what the ground holds: each faculty with its methods, and
62
+ each house.
63
+
64
+ ```bash
65
+ npx nervur help
66
+ ```
67
+
68
+ A faculty is called by its name and a method. Named alone, it prints its
69
+ methods. The ground's own `houses` faculty adds, removes and lists houses.
70
+
71
+ ```bash
72
+ npx nervur houses add name=main memory='{"body":"ledger"}' classes='{"body":"folder","at":"house"}'
73
+ ```
74
+
75
+ `ask` asks a being of a house, as the house's owner. `--id <being>` names
76
+ her, and with none it asks the steward. With no method, it prints what
77
+ she shows.
78
+
79
+ ```bash
80
+ npx nervur ask main
81
+ ```
82
+
83
+ `--cells` reads a being's cells as they last landed, and asks nothing.
84
+ Nothing but the hand reads cells, which makes it the tool for a test, a
85
+ repair, or a look at what her asks do not show.
86
+
87
+ ```bash
88
+ npx nervur ask main --cells
89
+ ```
90
+
91
+ The command asks no watch. A watch is held by a being on her standing,
92
+ or by a page through a face, where something waits on its answer.
93
+
94
+ ## Arguments and answers
95
+
96
+ Arguments are one JSON object, or words `key=value`. A value is read as
97
+ JSON where it reads as JSON, and as text where it does not, so
98
+ `count=3` is a number and `name=Ada` is text.
99
+
100
+ ```bash
101
+ npx nervur ask main hello '{"name":"Ada"}'
102
+ ```
103
+
104
+ Each word prints one JSON value, the answer, and its exit code says what
105
+ came back.
106
+
107
+ | Exit | What it means |
108
+ | --- | --- |
109
+ | 0 | a result, or what she shows |
110
+ | 1 | an error the ground or the being answered |
111
+ | 2 | nothing was asked: a word the command does not know, or a hand that does not answer |
112
+
113
+ So a script tells a refusal from a ground that is down.