@dcasegr/skein 0.0.0-stage → 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.
- package/README.md +522 -2
- package/bin/skein-host.js +22 -0
- package/bin/skein.js +8 -0
- package/dist/client/admin-cli.d.ts +10 -0
- package/dist/client/admin-cli.js +370 -0
- package/dist/client/admin.d.ts +139 -0
- package/dist/client/admin.js +256 -0
- package/dist/client/bundle.d.ts +9 -0
- package/dist/client/bundle.js +34 -0
- package/dist/client/cli.d.ts +44 -0
- package/dist/client/cli.js +306 -0
- package/dist/client/client.d.ts +161 -0
- package/dist/client/client.js +237 -0
- package/dist/client/config.d.ts +18 -0
- package/dist/client/config.js +31 -0
- package/dist/client/conversation.d.ts +62 -0
- package/dist/client/conversation.js +113 -0
- package/dist/client/raw.d.ts +94 -0
- package/dist/client/raw.js +154 -0
- package/dist/client/target.d.ts +34 -0
- package/dist/client/target.js +158 -0
- package/dist/dev/cli.d.ts +8 -0
- package/dist/dev/cli.js +248 -0
- package/dist/dev/scan.d.ts +15 -0
- package/dist/dev/scan.js +173 -0
- package/dist/envelope-cbor.d.ts +110 -0
- package/dist/envelope-cbor.js +160 -0
- package/dist/envelope.d.ts +38 -0
- package/dist/envelope.js +101 -0
- package/dist/host/arc.d.ts +131 -0
- package/dist/host/arc.js +425 -0
- package/dist/host/billing.d.ts +102 -0
- package/dist/host/billing.js +167 -0
- package/dist/host/boot.d.ts +246 -0
- package/dist/host/boot.js +643 -0
- package/dist/host/cli.d.ts +57 -0
- package/dist/host/cli.js +1253 -0
- package/dist/host/clock.d.ts +3 -0
- package/dist/host/clock.js +8 -0
- package/dist/host/control.d.ts +45 -0
- package/dist/host/control.js +170 -0
- package/dist/host/cron.d.ts +99 -0
- package/dist/host/cron.js +196 -0
- package/dist/host/deliver.d.ts +53 -0
- package/dist/host/deliver.js +251 -0
- package/dist/host/deploy.d.ts +29 -0
- package/dist/host/deploy.js +55 -0
- package/dist/host/door-answer.d.ts +24 -0
- package/dist/host/door-answer.js +21 -0
- package/dist/host/events.d.ts +89 -0
- package/dist/host/events.js +222 -0
- package/dist/host/fake-arcade.d.ts +40 -0
- package/dist/host/fake-arcade.js +149 -0
- package/dist/host/fake-discovery.d.ts +4 -0
- package/dist/host/fake-discovery.js +58 -0
- package/dist/host/feeds.d.ts +127 -0
- package/dist/host/feeds.js +422 -0
- package/dist/host/frontdoor.d.ts +92 -0
- package/dist/host/frontdoor.js +172 -0
- package/dist/host/genesis.d.ts +259 -0
- package/dist/host/genesis.js +353 -0
- package/dist/host/handles.d.ts +40 -0
- package/dist/host/handles.js +88 -0
- package/dist/host/hostenv.d.ts +30 -0
- package/dist/host/hostenv.js +83 -0
- package/dist/host/image-chain.d.ts +127 -0
- package/dist/host/image-chain.js +440 -0
- package/dist/host/install.d.ts +22 -0
- package/dist/host/install.js +139 -0
- package/dist/host/instances.d.ts +227 -0
- package/dist/host/instances.js +430 -0
- package/dist/host/kernel.d.ts +246 -0
- package/dist/host/kernel.js +603 -0
- package/dist/host/liveness.d.ts +65 -0
- package/dist/host/liveness.js +155 -0
- package/dist/host/manifest.d.ts +160 -0
- package/dist/host/manifest.js +597 -0
- package/dist/host/p2p.d.ts +337 -0
- package/dist/host/p2p.js +1002 -0
- package/dist/host/packet.d.ts +121 -0
- package/dist/host/packet.js +562 -0
- package/dist/host/plan.d.ts +154 -0
- package/dist/host/plan.js +418 -0
- package/dist/host/providers.d.ts +238 -0
- package/dist/host/providers.js +565 -0
- package/dist/host/roster.d.ts +72 -0
- package/dist/host/roster.js +172 -0
- package/dist/host/router.d.ts +773 -0
- package/dist/host/router.js +2389 -0
- package/dist/host/signer.d.ts +49 -0
- package/dist/host/signer.js +167 -0
- package/dist/host/store-sqlite.d.ts +39 -0
- package/dist/host/store-sqlite.js +170 -0
- package/dist/host/stores.d.ts +43 -0
- package/dist/host/stores.js +342 -0
- package/dist/host/sync.d.ts +121 -0
- package/dist/host/sync.js +467 -0
- package/dist/host/testbeef.d.ts +21 -0
- package/dist/host/testbeef.js +37 -0
- package/dist/host/testhost.d.ts +149 -0
- package/dist/host/testhost.js +211 -0
- package/dist/host/vcdiff.d.ts +9 -0
- package/dist/host/vcdiff.js +210 -0
- package/dist/host/wasm-kernel.d.ts +87 -0
- package/dist/host/wasm-kernel.js +296 -0
- package/dist/host/wasm-worker.d.ts +1 -0
- package/dist/host/wasm-worker.js +186 -0
- package/dist/peers/cron.d.ts +33 -0
- package/dist/peers/cron.js +75 -0
- package/dist/peers/infer-main.d.ts +2 -0
- package/dist/peers/infer-main.js +74 -0
- package/dist/peers/infer.d.ts +163 -0
- package/dist/peers/infer.js +367 -0
- package/dist/runtime/beef.d.ts +28 -0
- package/dist/runtime/beef.js +107 -0
- package/dist/runtime/bitcoin.d.ts +36 -0
- package/dist/runtime/bitcoin.js +141 -0
- package/dist/runtime/cid.d.ts +14 -0
- package/dist/runtime/cid.js +51 -0
- package/dist/runtime/dispatch.d.ts +92 -0
- package/dist/runtime/dispatch.js +142 -0
- package/dist/runtime/envelope.d.ts +60 -0
- package/dist/runtime/envelope.js +101 -0
- package/dist/runtime/heads.d.ts +25 -0
- package/dist/runtime/heads.js +37 -0
- package/dist/runtime/identity.d.ts +28 -0
- package/dist/runtime/identity.js +67 -0
- package/dist/runtime/index-store.d.ts +152 -0
- package/dist/runtime/index-store.js +715 -0
- package/dist/runtime/log.d.ts +62 -0
- package/dist/runtime/log.js +104 -0
- package/dist/runtime/programs.d.ts +30 -0
- package/dist/runtime/programs.js +61 -0
- package/dist/runtime/records.d.ts +135 -0
- package/dist/runtime/records.js +149 -0
- package/dist/runtime/sqlite.d.ts +33 -0
- package/dist/runtime/sqlite.js +604 -0
- package/dist/runtime/store.d.ts +141 -0
- package/dist/runtime/store.js +24 -0
- package/dist/runtime/syscalls.d.ts +9 -0
- package/dist/runtime/syscalls.js +41 -0
- package/dist/runtime/tree.d.ts +60 -0
- package/dist/runtime/tree.js +196 -0
- package/dist/runtime/types.d.ts +100 -0
- package/dist/runtime/types.js +7 -0
- package/dist/testapps.d.ts +101 -0
- package/dist/testapps.js +275 -0
- package/dist/testkit.d.ts +25 -0
- package/dist/testkit.js +48 -0
- package/dist/wallet.d.ts +35 -0
- package/dist/wallet.js +87 -0
- package/images/README.md +68 -0
- package/images/default/README.md +38 -0
- package/images/default/bin/frontdoor.cid +1 -0
- package/images/default/bin/frontdoor.json +5 -0
- package/images/default/bin/messagebox.cid +1 -0
- package/images/default/bin/messagebox.json +8 -0
- package/images/default/bin/wallet.cid +1 -0
- package/images/default/bin/wallet.json +14 -0
- package/images/default/etc/config.json +1 -0
- package/images/default/etc/dispatch.json +82 -0
- package/images/host/etc/apps.json +8 -0
- package/kernel-zig/README.md +1247 -0
- package/kernel-zig/web/client.js +65 -0
- package/kernel-zig/web/kernel.d.ts +59 -0
- package/kernel-zig/web/kernel.js +329 -0
- package/kernel-zig/web/store.js +67 -0
- package/kernel-zig/web/worker.js +79 -0
- package/kernel-zig/zig-out/web/skein-kernel.wasm +0 -0
- package/package.json +77 -4
- package/wasm/README.md +35 -0
- package/wasm/frontdoor.wasm +0 -0
- package/wasm/messagebox.wasm +0 -0
- package/wasm/resolve.wasm +0 -0
- package/wasm/wallet.wasm +0 -0
- package/wasm/wire-probe.wasm +0 -0
package/README.md
CHANGED
|
@@ -1,3 +1,523 @@
|
|
|
1
|
-
#
|
|
1
|
+
# skein
|
|
2
2
|
|
|
3
|
-
|
|
3
|
+
A skein is a deterministic WASI machine over a content-addressed graph. Every
|
|
4
|
+
package that reaches it is appended to its log as received, every step a
|
|
5
|
+
program takes is recorded, and replaying the log rebuilds the same graph,
|
|
6
|
+
byte for byte. What a skein does depends on the apps installed in it, and
|
|
7
|
+
the same history runs under any host: a server, a laptop, a browser tab.
|
|
8
|
+
|
|
9
|
+
This repository is the kernel, the boundary programs, the node host and the
|
|
10
|
+
client. Apps live in their own repositories (below). The public explainer is
|
|
11
|
+
https://skein.nexus; these docs are the reference.
|
|
12
|
+
|
|
13
|
+
## What it is
|
|
14
|
+
|
|
15
|
+
Three layers:
|
|
16
|
+
|
|
17
|
+
| layer | what | where |
|
|
18
|
+
|---|---|---|
|
|
19
|
+
| **kernel** | the machine (store, log, scheduler, WASI, fuel) and its four tables, plus the signer import (`wallet`). One implementation, Zig over wasmtime; it also builds for the browser | `kernel-zig/` |
|
|
20
|
+
| **apps** | everything else, each a tree of WASI programs installed under its own name: the front door, messagebox, resolve, wallet, chain, static sites, overlays, the shell, chat, your own | `programs/` here (the boundary programs and the wallet); the rest in sibling repos |
|
|
21
|
+
| **hosts** | whatever drives a kernel from outside: transports, providers, a store and the signer. The host judges nothing and routes nothing | `src/host/` (the node host, `skein-host`); `web/kernel/` (the browser host) |
|
|
22
|
+
|
|
23
|
+
The kernel's four tables:
|
|
24
|
+
|
|
25
|
+
| table | holds | written by |
|
|
26
|
+
|---|---|---|
|
|
27
|
+
| objects | blocks by CID (dag-cbor, git-raw, bitcoin, raw) | the kernel's `objects` operation; programs `put`/`keep` |
|
|
28
|
+
| heads | name → root, each with an owner (the app the name is under) | the kernel's `head` operation; programs `advance`, only under their own app's name |
|
|
29
|
+
| dispatch | rows `(transport, address, sender, program)`: boxes, HTTP paths, libp2p topics. A row is the permission | the kernel's `dispatch` operation |
|
|
30
|
+
| address book | key → transport and address; providers are `local` rows | the kernel's `peers` operation |
|
|
31
|
+
|
|
32
|
+
The four admin operations are the kernel's own, taken on admin messages from
|
|
33
|
+
the owner (or a key the owner delegated with another row). So is the
|
|
34
|
+
claim: a skein started from the default image has no owner until a message
|
|
35
|
+
reaches its claim row, and then the kernel writes the sender's admin rows
|
|
36
|
+
(#127: the owner is the claim's sender, never a key in its body) and removes
|
|
37
|
+
the claim row. No program writes a kernel table. An app writes only heads under its own name; reads are
|
|
38
|
+
global by CID; a call to another app hands back CIDs, not data.
|
|
39
|
+
|
|
40
|
+
## Run a skein locally
|
|
41
|
+
|
|
42
|
+
Needs Node 26 and Zig 0.16.0 through `mise`. The owner's admin messages
|
|
43
|
+
(installing an app, a dispatch row, the address book, a directory into
|
|
44
|
+
`main`) are `bin/skein install|uninstall|routes|grant|peers|host|claim|deploy`:
|
|
45
|
+
the client signs them in its own process with the operator's key
|
|
46
|
+
(`SKEIN_OPERATOR_KEY`, default `~/.skein/operator.key`, which `skein-host
|
|
47
|
+
run` makes) and sends them — over the host's control socket on the host
|
|
48
|
+
machine (`--instance <handle>`), else on one BRC-104 session with the
|
|
49
|
+
instance's origin (#142). A browser wallet sends the same messages from the
|
|
50
|
+
management page. The `bin/skein` client's other commands
|
|
51
|
+
use a wallet reachable over HTTP (default `http://127.0.0.1:3322`; the dev
|
|
52
|
+
setup runs `1sat serve wallet-api`, `scripts/host/wallets.sh`).
|
|
53
|
+
|
|
54
|
+
That HTTP wallet is deny-by-default. The client (origin `skein-client`,
|
|
55
|
+
`SKEIN_ORIGINATOR`) needs these grants
|
|
56
|
+
from the owner's wallet (`scripts/host/grants.sh` grants them for the dev
|
|
57
|
+
stack):
|
|
58
|
+
|
|
59
|
+
| protocol | level | counterparty |
|
|
60
|
+
|---|---|---|
|
|
61
|
+
| `identity key retrieval` | 1 | |
|
|
62
|
+
| `server hmac` | 2 | `self` |
|
|
63
|
+
| `messagebox` | 1 | |
|
|
64
|
+
| `auth message signature` | 2 | the instance's front-door key |
|
|
65
|
+
| `message encryption` | 2 | the instance's front-door key |
|
|
66
|
+
|
|
67
|
+
The front-door key is column 5 of `skein-host list`; a new instance is a
|
|
68
|
+
new counterparty. A missing grant fails the command with the wallet's
|
|
69
|
+
refusal, which names the `1sat permissions grant …` command for it.
|
|
70
|
+
|
|
71
|
+
```
|
|
72
|
+
git clone https://github.com/shruggr/skein && cd skein
|
|
73
|
+
npm install
|
|
74
|
+
(cd kernel-zig && mise exec -- zig build --release) # kernel-zig/zig-out/bin/skein-kernel; fetches skein-sdk by URL+hash
|
|
75
|
+
bin/skein-host add martha --image default # an instance from the default image: identity derived from ~/.skein/master.key, no owner yet
|
|
76
|
+
bin/skein-host run # the host on :8100; martha at http://martha.localhost:8100 or /@martha
|
|
77
|
+
bin/skein claim --instance martha # the claim, signed with ~/.skein/operator.key: you, its sender, own martha; the claim row goes
|
|
78
|
+
```
|
|
79
|
+
|
|
80
|
+
The default image (`images/default`, docs/BOOTSTRAP.md) is the same for
|
|
81
|
+
every user skein: the front door, the messagebox, the wallet, and one row
|
|
82
|
+
to the kernel, `claim`, from anyone: the first claim's sender owns it
|
|
83
|
+
(#127), so claim it first thing. The host signs no user's claim; `skein
|
|
84
|
+
claim --messagebox <url>` names where the instance reaches its owner. A
|
|
85
|
+
second claim is refused. It has no apps (#152). After the claim, install
|
|
86
|
+
the chain, git and site apps by message, and root's route `/` to the site:
|
|
87
|
+
|
|
88
|
+
```
|
|
89
|
+
git clone -q --branch v0.6.0 https://github.com/shruggr/skein-chain ../skein-chain
|
|
90
|
+
git clone -q --branch v0.2.0 https://github.com/shruggr/skein-git ../skein-git
|
|
91
|
+
git clone -q --branch v0.10.0 https://github.com/shruggr/skein-site ../skein-site
|
|
92
|
+
bin/skein install ../skein-chain --instance martha
|
|
93
|
+
bin/skein install ../skein-git --instance martha
|
|
94
|
+
bin/skein install ../skein-site --instance martha
|
|
95
|
+
bin/skein routes add --prefix --filters site.get --settings '{"root":"www"}' / --instance martha
|
|
96
|
+
```
|
|
97
|
+
|
|
98
|
+
Installing a newer version the same way upgrades the app and keeps its
|
|
99
|
+
state (docs/APPS.md, "Reconfiguration").
|
|
100
|
+
|
|
101
|
+
To have apps at birth, boot from an image directory that lists them: the
|
|
102
|
+
default image's `bin/` and `etc/` with an `etc/apps.json` naming each app
|
|
103
|
+
as a directory (relative to the image) or a release tarball by its tree's
|
|
104
|
+
git id (images/README.md):
|
|
105
|
+
|
|
106
|
+
```json
|
|
107
|
+
{ "install": [
|
|
108
|
+
{ "url": "https://github.com/shruggr/skein-chain/archive/refs/tags/v0.6.0.tar.gz", "hash": "13a517e964c4785330d8b7ef77796e149657cbbb" },
|
|
109
|
+
{ "url": "https://github.com/shruggr/skein-git/archive/refs/tags/v0.2.0.tar.gz", "hash": "0894fefd71d7aa1739d77b9d503421b4d55e497a" },
|
|
110
|
+
{ "url": "https://github.com/shruggr/skein-site/archive/refs/tags/v0.10.0.tar.gz", "hash": "2a7b9a492beec6c1c865fc9e33628e18bd36d312" } ],
|
|
111
|
+
"routes": [ { "transport": "http", "address": "/", "prefix": true, "filters": ["site.get"], "root": "www" } ] }
|
|
112
|
+
```
|
|
113
|
+
|
|
114
|
+
```
|
|
115
|
+
bin/skein-host add martha --image ./my-image
|
|
116
|
+
```
|
|
117
|
+
|
|
118
|
+
A plain `skein-host add martha` (no `--image`) is code genesis, with the
|
|
119
|
+
owner in it: `SKEIN_OWNER`, else `~/.skein/owner.identity` (the owner
|
|
120
|
+
wallet's identity key, one line of hex). The tests and the dev stack use it.
|
|
121
|
+
|
|
122
|
+
- State lives in `$SKEIN_HOME` (default `~/.skein`): `master.key` (the one
|
|
123
|
+
secret every instance key derives from), `host.db` (instances, queues, the
|
|
124
|
+
fuel ledger), `instances/<handle>/runtime.db` (each instance's store),
|
|
125
|
+
`logs/host.log`.
|
|
126
|
+
- BRC-169 on the host's own origin (`SKEIN_ROUTER_ORIGIN`) is the host
|
|
127
|
+
skein's onboarding app (shruggr/skein-onboard, #113): the router carries
|
|
128
|
+
`/manifest.json`, `/.well-known/metanet-handles/resolve` and `/search`,
|
|
129
|
+
`/bsvalias/id/…`, `POST /account/register` and `POST /account/profile`
|
|
130
|
+
into the host skein. The app registers handles (a mailbox instance from
|
|
131
|
+
the instance manager, signed over `register <name>@<domain>`), has the
|
|
132
|
+
host's certifier (a child of `master.key`, never in an instance) sign each
|
|
133
|
+
handle certificate under a serial of its own, records every issue, and
|
|
134
|
+
answers resolve, search and the manifest from those records. The handle
|
|
135
|
+
domain, the host's name and note are the app's config, written at the
|
|
136
|
+
host skein's birth from the host's settings (below).
|
|
137
|
+
Revocation is not implemented (the host has no wallet): the certificate's
|
|
138
|
+
revocation outpoint is BRC-52's disabled sentinel.
|
|
139
|
+
- Code genesis (no `--image`) is written at its first start: the owner, the
|
|
140
|
+
owner's admin rows, the boundary programs (front door, messagebox,
|
|
141
|
+
resolve) and their rows, and the host's providers in its address book.
|
|
142
|
+
It has no shell and no chat loop: those are apps, installed next. `skein-host add <h> --boot <dir>` boots
|
|
143
|
+
from a system tree instead (docs/BOOTSTRAP.md). A new log format means a
|
|
144
|
+
new store: move `runtime.db` aside and start again.
|
|
145
|
+
- The full dev stack (owner and inference wallets, mailbox instances, address
|
|
146
|
+
books, the inference peer) is `scripts/host/up.sh`; see
|
|
147
|
+
`scripts/host/README.md`.
|
|
148
|
+
- The host page is http://127.0.0.1:4600 (every instance, a link to its
|
|
149
|
+
origin). A skein from the default image serves its management page, the
|
|
150
|
+
explorer included, at its origin. `bin/skein-dev log | ls | show <cid>` and
|
|
151
|
+
`kernel-zig/zig-out/bin/skein-kernel dump | replay | fuel <store>` read a
|
|
152
|
+
store from the command line.
|
|
153
|
+
|
|
154
|
+
## Run a host
|
|
155
|
+
|
|
156
|
+
### Two shapes: the host loads the kernel, or runs it as a process
|
|
157
|
+
|
|
158
|
+
The kernel is one zig source built two ways (kernel-zig/README.md, "The
|
|
159
|
+
machine and the native host"). The node host runs either, chosen by an
|
|
160
|
+
instance's store:
|
|
161
|
+
|
|
162
|
+
| store (host.db `store`) | the machine | who uses it |
|
|
163
|
+
|---|---|---|
|
|
164
|
+
| `sqlite:<path>` — a set of the host's ONE SQLite database (`SKEIN_STORE_SQLITE`, default `$SKEIN_HOME/store.sqlite` when no native kernel is installed) | the **wasm kernel** (`kernel-zig/zig-out/web/skein-kernel.wasm`), loaded in the host's own process: one machine per active instance on a worker thread, none for an idle one; the host chain held by one more machine; storage node's built-in `node:sqlite` | the npm package (`npx skein-host`, `npx open-exchange`): node alone, any platform node runs on, no toolchain |
|
|
165
|
+
| a file, `lmdb:<dir>` (`SKEIN_STORE`), `rocksdb:<dir>` (`SKEIN_STORE_ROCKSDB`) | the **native kernel** (`kernel-zig/zig-out/bin/skein-kernel`): `serve` per instance, or the one `host` process over RocksDB | a checkout with the kernel built — the hosted shape (the rack) |
|
|
166
|
+
|
|
167
|
+
The same log gives the same state on both: `kernel-zig/equiv/wasm-host.ts`
|
|
168
|
+
replays every store the wasm host writes with the native `skein-kernel
|
|
169
|
+
replay` and compares the state CIDs.
|
|
170
|
+
|
|
171
|
+
The package: `npm pack` (its `prepack` builds `dist/` with tsc and the wasm
|
|
172
|
+
kernel with `zig build web`); it carries no native binary. `bin/skein-host.js`
|
|
173
|
+
and `bin/skein.js` run `dist/` (or a checkout's `src/`).
|
|
174
|
+
|
|
175
|
+
A host runs skeins for others too. It has one of its own, the **host
|
|
176
|
+
skein**: the operator's instance, where the host keeps what is state or
|
|
177
|
+
conversation (docs/ARCH.md, "The host skein").
|
|
178
|
+
|
|
179
|
+
```
|
|
180
|
+
# ~/.skein/host.env — the host's settings: every SKEIN_* line; the environment wins
|
|
181
|
+
SKEIN_ROUTER_ORIGIN=https://id.example.com
|
|
182
|
+
SKEIN_INSTANCE_ORIGIN=https://{handle}.example.com
|
|
183
|
+
SKEIN_HANDLE_DOMAIN=example.com
|
|
184
|
+
SKEIN_HOST_NAME="Example host"
|
|
185
|
+
SKEIN_HTTP=fetch
|
|
186
|
+
```
|
|
187
|
+
|
|
188
|
+
```
|
|
189
|
+
bin/skein-host run # the first run: operator.key, master.key, host.db and the host skein; then the host
|
|
190
|
+
```
|
|
191
|
+
|
|
192
|
+
- `run` reads `$SKEIN_HOME/host.env` (every `SKEIN_*` line; the environment
|
|
193
|
+
wins). On its first run it makes the operator's key
|
|
194
|
+
(`SKEIN_OPERATOR_KEY`, default `$SKEIN_HOME/operator.key`; a file you put
|
|
195
|
+
there is used instead: hex or WIF, mode 0600) and the **host skein**
|
|
196
|
+
(handle `host`) from the host image — the default image with the
|
|
197
|
+
onboarding app (shruggr/skein-onboard v0.4.0, its release tarball,
|
|
198
|
+
fetched and checked by its tree) — its genesis naming the operator's key
|
|
199
|
+
as its owner: its admin rows, its explorer row and the onboarding app's
|
|
200
|
+
routes are there at birth, with no claim. The onboarding app's
|
|
201
|
+
config comes from the settings (`domain` from `SKEIN_HANDLE_DOMAIN`, else
|
|
202
|
+
the domain of `SKEIN_ROUTER_ORIGIN`; `origin`; `name` from
|
|
203
|
+
`SKEIN_HOST_NAME`; `note` from `SKEIN_HOST_NOTE`). It prints the host
|
|
204
|
+
skein's identity and URL, then serves. Later runs start what exists; a
|
|
205
|
+
changed host.env does not reach into the host skein (`skein install
|
|
206
|
+
<a skein-onboard checkout> --instance host --config <file.json>` changes
|
|
207
|
+
the app's config). `skein-host init` is the first run's part alone. Its
|
|
208
|
+
address book alone names the **instance manager**, the host's provider
|
|
209
|
+
that creates, starts and stops instances; the manager acts for no one
|
|
210
|
+
else.
|
|
211
|
+
- `skein-host grant <your wallet's identity key> --apps` gives a browser
|
|
212
|
+
wallet the host skein's admin rows and its apps' owner rows (signed with
|
|
213
|
+
the operator's key), so the management page manages the host skein too.
|
|
214
|
+
- With the onboarding app installed, anyone with a wallet gets a skein: a
|
|
215
|
+
BRC-104 session to the host skein and `POST /onboard/call {"fn":
|
|
216
|
+
"onboard.create", "args": {"handle": "alice", "claim": …}}`, `claim` the
|
|
217
|
+
wallet's own signed claim naming no recipient (#127; skein-onboard's
|
|
218
|
+
README has its shape). The answer, on the same connection, is `{handle,
|
|
219
|
+
identity, url}`: a new instance from the default image, its claim
|
|
220
|
+
forwarded by the instance manager as its first entry — owned by the
|
|
221
|
+
signer, already claimed when its URL first answers. Its owner installs apps into it from there (next sections). A
|
|
222
|
+
handle that is taken is refused (409).
|
|
223
|
+
- **The management page.** Open the host skein's origin
|
|
224
|
+
(`http://host.localhost:8100/`) with a BRC-100 wallet in the browser: it
|
|
225
|
+
creates a skein for your key through that route and opens the new
|
|
226
|
+
skein's own copy of the page. Nothing is written into your wallet: the
|
|
227
|
+
page lists your skeins from the host (`GET <router>/skeins?key=<your
|
|
228
|
+
identity key>`, the skeins whose head `grants` names your key root). There it reads
|
|
229
|
+
the skein through its explorer and installs apps: the git app from the
|
|
230
|
+
image, then any app by repository URL and commit id — you see the rows each
|
|
231
|
+
asks for before your wallet signs. Deploy by hash needs the host to carry
|
|
232
|
+
requests beyond itself: run it with `SKEIN_HTTP=fetch`. Every skein from
|
|
233
|
+
the default image serves the same page (shruggr/skein-site).
|
|
234
|
+
- **A handle from the page** (#103). On the same page, "Register a handle"
|
|
235
|
+
asks the host for `<name>@<domain>` for your key (the domain is the
|
|
236
|
+
router's host name, `id.skein.nexus` in production; the page finds the
|
|
237
|
+
router through `/.well-known/skein-host`, which the router answers at every
|
|
238
|
+
skein's origin): your wallet signs the request, the host creates your
|
|
239
|
+
mailbox instance and answers with the BRC-52 handle certificate, and your
|
|
240
|
+
wallet keeps it (`acquireCertificate`). "Your handles" lists those
|
|
241
|
+
certificates (`listCertificates`) and the mailbox each resolves to. The
|
|
242
|
+
labels `id` and `host` and every instance's handle are refused.
|
|
243
|
+
- **Your profile** (#104). Each of your handles has a Profile form: a name
|
|
244
|
+
and an avatar (an image inscription, by outpoint). Your wallet signs the
|
|
245
|
+
profile record (the OpNS one: DAG-CBOR `{domain, name?, avatar?}`), and
|
|
246
|
+
the page writes it to your mailbox instance as its owner. The host serves
|
|
247
|
+
it with the handle when it is resolved or found; the page shows it as
|
|
248
|
+
signed by the handle's key. "Find a handle" searches the host by handle
|
|
249
|
+
or name.
|
|
250
|
+
- **One key for every instance** (#160, #161, #162). A host can be
|
|
251
|
+
provisioned with ONE private key instead of the master key:
|
|
252
|
+
`SKEIN_KEY_FILE=<path>` (64 hex digits, read and never made) or
|
|
253
|
+
`SKEIN_KEY=<hex>`; set together with `SKEIN_MASTER_KEY` /
|
|
254
|
+
`SKEIN_MASTER_KEY_FILE` the host refuses to start. Every instance then
|
|
255
|
+
signs with that key directly (`skein-host add` records the same identity
|
|
256
|
+
on every row), and every instance's libp2p peer key is the key's one child
|
|
257
|
+
([2, "skein instance"], key ID `libp2p`): a program that asks its signer
|
|
258
|
+
for `libp2p:<handle>` gets it, whatever the handle. One libp2p node per key
|
|
259
|
+
carries all of them: gossip goes to every instance that takes the topic
|
|
260
|
+
(accepted if any accepts); an inbound stream goes to the instance its first
|
|
261
|
+
frame's `topic` names (a frame naming none: the one instance declaring the
|
|
262
|
+
protocol, else `{kind: "error", message: "topic required"}`). Unset: the
|
|
263
|
+
master key's derivation per instance, one node per instance, as before.
|
|
264
|
+
- **Born owned** (#164). A host program on skein's host as a library calls
|
|
265
|
+
`Router.createInstance(handle, owner, {image, owned: true})`: an image
|
|
266
|
+
instance whose genesis names `owner` root, as the host skein is born —
|
|
267
|
+
no claim, no claim route (the CLI has no flag for it).
|
|
268
|
+
- **Path-only handles** (#161). A token id `<txid>_<vout>` is a handle too:
|
|
269
|
+
its instance has no hostname and is reached at `/@<txid>_<vout>/…` on the
|
|
270
|
+
host's origin (its `url` says so). An overlay request at the bare host —
|
|
271
|
+
`POST /submit` (its `X-Topics`) or `POST /lookup` (its `service`
|
|
272
|
+
`ls_color_<id>`, or a `topic` `tm_color_<id>`) — goes to the enabled
|
|
273
|
+
path-only instance whose handle is that `<id>`, so a wallet keeps one
|
|
274
|
+
provider URL; topics naming two instances, or one here and one not, are 400.
|
|
275
|
+
Any other name (#137: `tm_color`, `ls_color`, …) goes to the
|
|
276
|
+
enabled instance whose row names it in its `topics` (host.db: what the
|
|
277
|
+
instance manager's `create` or `start` named), whether or not it has run
|
|
278
|
+
yet; two instances naming the same name are 400. Nothing maps: the
|
|
279
|
+
hostname's instance (or the bare host) as before.
|
|
280
|
+
- **An instance creates instances** (#162). `SKEIN_MANAGER_FOR=<handle>[,…]`
|
|
281
|
+
gives those instances the instance manager in their address book at birth
|
|
282
|
+
(as the host skein has it) and has the manager take their messages: `create
|
|
283
|
+
{handle, image?, config?, claim?, beef?, topics?}`, `start {handle,
|
|
284
|
+
topics?}`, `stop {handle}`. `topics` (#137): the overlay names, gossip
|
|
285
|
+
topics and lookup services alike (`["tm_color", "ls_color"]`),
|
|
286
|
+
the host routes to the instance at the bare host — plain non-empty
|
|
287
|
+
strings, no duplicates; stored with its row; a `start` naming them
|
|
288
|
+
replaces the row's, one naming none keeps them.
|
|
289
|
+
`image` is `default`, `mailbox`, or an image by name: the directory
|
|
290
|
+
`$SKEIN_HOME/images/<name>` (`SKEIN_IMAGES_DIR` names another directory;
|
|
291
|
+
the layout `skein-host add --image <dir>` takes, a link to an app
|
|
292
|
+
repository's `image/` included). `config` is the new instance's apps'
|
|
293
|
+
config at birth, `{<app>: {…}}`, merged as an install's `--config`. On a
|
|
294
|
+
one-key host a create with no `claim` is claimed by the host's own key
|
|
295
|
+
(its owner), so the instance is live at once; on a master-key host the
|
|
296
|
+
owner's signed claim stays required. `beef` (skein-amm#4): an Atomic BEEF
|
|
297
|
+
(bytes) the host hands into the new instance once it is claimed, published
|
|
298
|
+
and following headers — into its receive row `/skein/overlay/beef/1.0.0`
|
|
299
|
+
(the host's own entry, never served to peers), as a fetched BEEF is, from
|
|
300
|
+
the host's own peer; the host names
|
|
301
|
+
no topic (the instance's engine judges it under the topics its config
|
|
302
|
+
declares). The answer gains `delivered: {verdict, reason?}`; a BEEF the
|
|
303
|
+
door turns away (unmined, a bad BUMP) is reported there, not retried, and
|
|
304
|
+
the instance stays created. `stop` also takes the instance off its
|
|
305
|
+
libp2p node (its beacons stop beating); `start` declares it again.
|
|
306
|
+
- `scripts/host/up.sh` brings up the dev stack.
|
|
307
|
+
- Block headers for the chain app: run the host with
|
|
308
|
+
`SKEIN_HEADERS_URL=http://127.0.0.1:8083/chaintracks/v2/tip/stream`
|
|
309
|
+
(Arcade's chaintracks); every instance with the chain app installed is
|
|
310
|
+
subscribed to it (scripts/host/README.md, the feeds). The host fills the
|
|
311
|
+
default image with the whole header chain from that chaintracks' history
|
|
312
|
+
at start and appends every header the feed brings, so a new skein is born
|
|
313
|
+
with the chain (#132, docs/BOOTSTRAP.md, "The image's chain part").
|
|
314
|
+
|
|
315
|
+
## Talk to it
|
|
316
|
+
|
|
317
|
+
An instance is an HTTP server at its own origin. Every request is appended
|
|
318
|
+
as received and the instance's front door (a program) runs BRC-103/104 on it
|
|
319
|
+
inside the VM; the host holds the connection until the request's thread
|
|
320
|
+
comes to rest, and the answer is signed on the session.
|
|
321
|
+
|
|
322
|
+
```
|
|
323
|
+
bin/skein install shell --instance martha # the shell app (from martha's catalog, cloned by her git app): box shell/run
|
|
324
|
+
bin/skein install chat --instance martha # the chat app: box chat
|
|
325
|
+
bin/skein whoami
|
|
326
|
+
bin/skein import ~/some/dir # tree objects into the kernel's objects operation; prints the tree CID
|
|
327
|
+
bin/skein run --tree <cid> -- 'ls | head -3' # box shell/run (the shell app: the shell over a tree)
|
|
328
|
+
bin/skein inbox --wait # the answer, from your mailbox instance
|
|
329
|
+
bin/skein chat --new --wait 'what is here?' # box chat (the chat app; needs the inference peer, bin/skein-infer)
|
|
330
|
+
```
|
|
331
|
+
|
|
332
|
+
- In a browser: a skein from the default image serves the management page
|
|
333
|
+
at its origin (`/`). It talks to that skein, and to every skein on its
|
|
334
|
+
host whose grants name your key root, with the same requests as the commands below,
|
|
335
|
+
signed by your wallet. Its Inbox lists a box of any mailbox you give it
|
|
336
|
+
(by default the mailbox your handle certificate resolves to) and syncs its
|
|
337
|
+
`metanet_inbox` into that wallet with `@1sat/actions`' `syncMetanetInbox`.
|
|
338
|
+
- Messages are BRC-33 (`/sendMessage`, `/listMessages`,
|
|
339
|
+
`/acknowledgeMessage`) on a BRC-104 session, bodies dag-cbor
|
|
340
|
+
(`application/cbor`, BRC-231) or JSON. A message's id is the CID of its
|
|
341
|
+
record; an answer names it in `replyTo`.
|
|
342
|
+
- What an instance sends you goes to your mailbox instance (an instance with
|
|
343
|
+
only the front door and the messagebox): a registration makes one (#113),
|
|
344
|
+
or `skein-host add <h> --mailbox --owner <key>` on a host with no host
|
|
345
|
+
skein.
|
|
346
|
+
- libp2p: an instance with libp2p rows gets a node in the host; topic
|
|
347
|
+
messages and stream frames go through the same front door.
|
|
348
|
+
- App routes live under `/<app>/` (an overlay's `/<app>/submit`,
|
|
349
|
+
`/<app>/lookup`); `{fn, args}` to an app's box calls a function.
|
|
350
|
+
|
|
351
|
+
The wire contract is docs/MESSAGES.md.
|
|
352
|
+
|
|
353
|
+
## Install an app
|
|
354
|
+
|
|
355
|
+
```
|
|
356
|
+
bin/skein install <name> --instance martha # a name from martha's catalog (her site's www/catalog.json)
|
|
357
|
+
bin/skein install https://github.com/<owner>/<repo>#<commit> http://martha.localhost:8100 # any repository and commit, at an origin
|
|
358
|
+
bin/skein install <name> --instance martha --dry-run # the prompt and the messages, nothing sent
|
|
359
|
+
bin/skein uninstall <app> --instance martha
|
|
360
|
+
```
|
|
361
|
+
|
|
362
|
+
`install` prints the prompt — what the app asks for (its head, its rows,
|
|
363
|
+
its reads, its start) — and sends the owner's messages. A repository is
|
|
364
|
+
installed **by hash**: one message to the skein's git app, `{fn:
|
|
365
|
+
"git.clone", args: {url, hash}}`; the app fetches that one commit through
|
|
366
|
+
the host's fetch provider (the host runs with `SKEIN_HTTP=fetch`), checks it
|
|
367
|
+
against the hash, keeps its tree in the store and answers `{tree, app}`
|
|
368
|
+
(the app record, built in the VM). The client plans from the stored tree and
|
|
369
|
+
sends `head` (`<app>/app` → the app record), one `dispatch` per row, and the
|
|
370
|
+
app's `start` — no `objects`: the blocks are already there. Installing
|
|
371
|
+
again is the upgrade. A directory (`skein install <dir>`) is read on your
|
|
372
|
+
machine and the objects the skein lacks are sent. The management page does
|
|
373
|
+
the same from your wallet. docs/APPS.md §3.
|
|
374
|
+
|
|
375
|
+
## Build an app
|
|
376
|
+
|
|
377
|
+
An app is a tree with `etc/app.json`. A complete minimal one is
|
|
378
|
+
`programs/test/app-demo/`: a counter with one interface, a box, a cron tick
|
|
379
|
+
and an HTTP route. Its manifest, with the `peek` function and the
|
|
380
|
+
description left out:
|
|
381
|
+
|
|
382
|
+
```json
|
|
383
|
+
{
|
|
384
|
+
"kind": "app",
|
|
385
|
+
"name": "app-demo",
|
|
386
|
+
"version": "0.1.0",
|
|
387
|
+
"programs": { "demo": "bin/app-demo.wasm" },
|
|
388
|
+
"provides": [{ "interface": "demo.counter/1", "functions": {
|
|
389
|
+
"get": { "writes": false, "args": {}, "answer": { "count": "int" } },
|
|
390
|
+
"add": { "writes": true, "args": { "by": "int", "note?": "string" }, "answer": { "count": "int" } } } }],
|
|
391
|
+
"requires": [],
|
|
392
|
+
"dispatch": [
|
|
393
|
+
{ "address": "app-demo", "sender": "*", "program": "demo" },
|
|
394
|
+
{ "address": "tick", "sender": "$cron", "program": "demo" },
|
|
395
|
+
{ "transport": "http", "address": "/call", "sender": "session", "program": "demo", "fn": "call" }
|
|
396
|
+
],
|
|
397
|
+
"start": { "body": { "kind": "app-demo-start" } },
|
|
398
|
+
"stop": { "body": { "kind": "app-demo-stop" } }
|
|
399
|
+
}
|
|
400
|
+
```
|
|
401
|
+
|
|
402
|
+
- **The name rule.** The app's programs advance only heads under
|
|
403
|
+
`app-demo/…`; its record is `app-demo/app`, its own state the record's
|
|
404
|
+
`state` link.
|
|
405
|
+
- **Rows.** `transport` defaults to `mailbox` (a box). An `http` address is
|
|
406
|
+
relative to `/<app>/`. Senders: `*`, `event`, `session` (http), `$owner`,
|
|
407
|
+
`$self`, `$<provider>` (`$cron`, `$status`), or a key in hex.
|
|
408
|
+
- **Programs** are WASI preview1 modules or WASI 0.2 components. In Zig,
|
|
409
|
+
depend on skein-sdk by tag:
|
|
410
|
+
|
|
411
|
+
```
|
|
412
|
+
zig fetch --save=skein_sdk https://github.com/shruggr/skein-sdk/archive/refs/tags/v0.7.2.tar.gz
|
|
413
|
+
```
|
|
414
|
+
|
|
415
|
+
and dispatch `{fn, args}` with the SDK's `app.serve`
|
|
416
|
+
(`programs/test/app-demo/main.zig`). Build with `zig build` for
|
|
417
|
+
`wasm32-wasi` and commit the module under `bin/`.
|
|
418
|
+
|
|
419
|
+
docs/APPS.md is the specification (the manifest fields, install, calling an
|
|
420
|
+
app, the security model, worked examples for an overlay and the chain app).
|
|
421
|
+
|
|
422
|
+
## Write an overlay
|
|
423
|
+
|
|
424
|
+
An overlay is an app built on shruggr/skein-overlay: the engine program plus
|
|
425
|
+
your topic managers and lookup services, wired from `config.overlay` in its
|
|
426
|
+
manifest, serving BRC-22/24 at `<base>/submit` and `<base>/lookup`, its
|
|
427
|
+
BRC-23 base URL `https://<handle>.<host>/<app>` (`/@<handle>/<app>` on the
|
|
428
|
+
host's origin without wildcard DNS). It
|
|
429
|
+
needs the chain app installed (`requires: ["chain/1"]`). The engine exports
|
|
430
|
+
the `topic`, `lookup` and `sk` Zig modules to build against; its README and
|
|
431
|
+
docs/OVERLAY.md there have the walkthrough.
|
|
432
|
+
|
|
433
|
+
## Build and test
|
|
434
|
+
|
|
435
|
+
```
|
|
436
|
+
cd kernel-zig && mise exec -- zig build # first: the host tests run kernel-zig/zig-out/bin/skein-kernel
|
|
437
|
+
cd kernel-zig && mise exec -- zig build test # the kernel's unit tests
|
|
438
|
+
npm test # the host, client, formats (node --test src/**/*.test.ts)
|
|
439
|
+
TMPDIR=/tmp/sk kernel-zig/equiv/run.sh # equivalence: shell, git, replay exactness, apps, browser, the wasm host
|
|
440
|
+
SKEIN_TEST_STORE=sqlite npm test # the host suite with every test host on the wasm kernel
|
|
441
|
+
```
|
|
442
|
+
|
|
443
|
+
- Gotcha: after a kernel change, a stale `zig-out/bin/skein-kernel` makes
|
|
444
|
+
`npm test` fail with "kernel probe: exited (1)" and can hang the host
|
|
445
|
+
suite. Run `zig build` first.
|
|
446
|
+
- CI (`.github/workflows/test.yml`) runs all four on Ubuntu for every push
|
|
447
|
+
and pull request, with the browser and component parts of the equivalence
|
|
448
|
+
suite skipped (no Playwright, Chromium, wasm-tools or adapter there).
|
|
449
|
+
- `equiv/run.sh` clones the pinned sibling apps (skein-chain, skein-overlay,
|
|
450
|
+
skein-site, skein-shell, skein-chat, skein-onboard, skein-git);
|
|
451
|
+
`SKEIN_CHAIN_DIR`, `SKEIN_OVERLAY_DIR`, `SKEIN_SITE_DIR`,
|
|
452
|
+
`SKEIN_SHELL_DIR`, `SKEIN_CHAT_DIR`, `SKEIN_ONBOARD_DIR`, `SKEIN_GIT_DIR`
|
|
453
|
+
point it at local checkouts. The git app's case (`git-clone.ts`) serves a
|
|
454
|
+
local repository with `git http-backend`. `npm test` installs the
|
|
455
|
+
shell app and the chat app where a test runs them (src/testapps.ts: the
|
|
456
|
+
same pins, fetched once into `$TMPDIR/skein-apps`). The browser cases need Playwright and
|
|
457
|
+
Chromium, else they are skipped with a note.
|
|
458
|
+
- The programs here: `scripts/build-programs.sh && scripts/pin-programs.sh`.
|
|
459
|
+
Developing against a local skein-sdk: clone it next to this checkout and
|
|
460
|
+
prefix a build with `scripts/sdk-local.sh`.
|
|
461
|
+
|
|
462
|
+
## Repositories
|
|
463
|
+
|
|
464
|
+
| repo | what | version |
|
|
465
|
+
|---|---|---|
|
|
466
|
+
| [shruggr/skein](https://github.com/shruggr/skein) | kernel, boundary programs (front door, messagebox, resolve), the wallet program, the node host, the client | log format 8 |
|
|
467
|
+
| [shruggr/skein-sdk](https://github.com/shruggr/skein-sdk) | the Zig package every program is written against: the `skein` imports, codecs, `app`, `files`, `chain`, wallet library, WIT | v0.6.0 |
|
|
468
|
+
| [shruggr/skein-chain](https://github.com/shruggr/skein-chain) | the chain app: the one writer of `chain/state`, ingest a BEEF, the only broadcaster; born with the image's header chain (#132) | v0.4.0 |
|
|
469
|
+
| [shruggr/skein-overlay](https://github.com/shruggr/skein-overlay) | the overlay engine app: BRC-22/24 over topic managers and lookup services | v0.9.2 |
|
|
470
|
+
| [shruggr/skein-shell](https://github.com/shruggr/skein-shell) | the shell app: `run`, and the shell itself (brush, coreutils, the toolset, python's stdlib) | v0.1.1 |
|
|
471
|
+
| [shruggr/skein-chat](https://github.com/shruggr/skein-chat) | the chat app: the turn loop (`chat`), its `bash` calls in the shell app's shell | v0.1.0 |
|
|
472
|
+
| [shruggr/skein-onboard](https://github.com/shruggr/skein-onboard) | the onboarding app, installed in the host skein: creates a skein for a wallet through the instance manager (the wallet's signed claim forwarded, #127); registration over the registrant's session (#135) | v0.3.3 |
|
|
473
|
+
| [shruggr/skein-git](https://github.com/shruggr/skein-git) | the git app: clones one commit by hash into the store, in the VM, and builds its app record (deploy by hash) | v0.1.2 |
|
|
474
|
+
| [shruggr/skein-site](https://github.com/shruggr/skein-site) | the management site, an app (#125: its page at `/site/`, served from its own tree by skein-sdk's `files`; the owner may add a row for `/`): your skeins from the host, create a skein, install apps, the explorer, the Inbox, handles and their profiles | v0.7.6 |
|
|
475
|
+
| [shruggr/skein-nexus](https://github.com/shruggr/skein-nexus) | the source of https://skein.nexus | |
|
|
476
|
+
|
|
477
|
+
This repository's layout:
|
|
478
|
+
|
|
479
|
+
```
|
|
480
|
+
kernel-zig/ the kernel: skein-kernel serve | replay | shell | dump | fuel; equiv/ (the equivalence suite)
|
|
481
|
+
images/ the default image (#89): a system tree with no owner and the claim row, no apps (#152); the host image's own part (#142); images/README.md
|
|
482
|
+
programs/ frontdoor, messagebox, resolve, wallet (Zig over skein-sdk); test/ (fixtures, app-demo)
|
|
483
|
+
wasm/ the committed modules the kernel pins (kernel-zig/src/programs.zig), see wasm/README.md
|
|
484
|
+
src/host/ the node host: skein-host (cli.ts), the HTTP transport, providers, feeds, broadcaster, libp2p node, signer, install
|
|
485
|
+
src/runtime/ the formats and a store reader in TypeScript (no machine)
|
|
486
|
+
src/client/ bin/skein: import, run, chat, inbox, dispatch
|
|
487
|
+
src/peers/ bin/skein-infer (the inference peer), a remote cron provider
|
|
488
|
+
src/dev/ bin/skein-dev (log, ls, show over a store file)
|
|
489
|
+
web/ the browser host (web/kernel/) and a front-end demo
|
|
490
|
+
scripts/ program builds and pins, sdk-local.sh; host/ (the dev stack)
|
|
491
|
+
```
|
|
492
|
+
|
|
493
|
+
## Docs
|
|
494
|
+
|
|
495
|
+
| doc | for |
|
|
496
|
+
|---|---|
|
|
497
|
+
| [docs/ARCH.md](docs/ARCH.md) | the architecture: the kernel, the host, the browser host, the apps |
|
|
498
|
+
| [docs/VM.md](docs/VM.md) | the machine: records, heads, the four tables, imports, `emit`, calls, requests, fuel, time, the index |
|
|
499
|
+
| [docs/MESSAGES.md](docs/MESSAGES.md) | the wire: the front door, sessions, routes, the log format, the messagebox, outbound, providers, broadcast, scheduling, libp2p |
|
|
500
|
+
| [docs/APPS.md](docs/APPS.md) | apps: the manifest, install, calling an app, security, worked examples |
|
|
501
|
+
| [docs/BOOTSTRAP.md](docs/BOOTSTRAP.md) | genesis: the system tree, packets, checkpoints, installing |
|
|
502
|
+
| [docs/WALLET.md](docs/WALLET.md) | the wallet program, the chain state it reads, proofs, SPV |
|
|
503
|
+
| [docs/OVERLAY.md](docs/OVERLAY.md) | pointer to skein-overlay's docs |
|
|
504
|
+
| [docs/SKILLS.md](docs/SKILLS.md) | which skill scripts run in the VM |
|
|
505
|
+
| [kernel-zig/README.md](kernel-zig/README.md) | building and running the kernel, components, the browser build, equivalence |
|
|
506
|
+
| [scripts/host/README.md](scripts/host/README.md) | the dev host: commands, ports, environment, Arcade, libp2p settings |
|
|
507
|
+
| [src/client/README.md](src/client/README.md) | the client |
|
|
508
|
+
| [docs/OPEN.md](docs/OPEN.md) | open questions still live from building |
|
|
509
|
+
|
|
510
|
+
Vocabulary: the **host** is transports + providers + store + signer (there
|
|
511
|
+
is no "router"; the dispatch table routes); the **kernel** is the machine,
|
|
512
|
+
the four tables and the signer import; **admin operations** are kernel
|
|
513
|
+
operations, not programs; every other thing is an **app** under its own
|
|
514
|
+
name; a **box** is a mailbox address in the dispatch table; **emit** is the
|
|
515
|
+
one way out (a message to a key in the address book — unsigned: a skein
|
|
516
|
+
receives mail only on a BRC-104 session to its own front door or over
|
|
517
|
+
libp2p, #126 step 4 — or an event).
|
|
518
|
+
|
|
519
|
+
## Contributing
|
|
520
|
+
|
|
521
|
+
The tracker is issue [#31](https://github.com/shruggr/skein/issues/31):
|
|
522
|
+
decisions, conventions and what is ready to build. Where a doc and an issue
|
|
523
|
+
disagree, the issue is right.
|
|
@@ -0,0 +1,22 @@
|
|
|
1
|
+
#!/usr/bin/env node
|
|
2
|
+
// skein-host for the npm package (and any checkout): src/host/cli.ts built to dist/ (node strips no
|
|
3
|
+
// types under node_modules), else the checkout's TypeScript. No shell, no toolchain: node alone
|
|
4
|
+
// (the kernel is the wasm file the package ships). As bin/skein-host does: SKEIN_HOME (default
|
|
5
|
+
// ~/.skein), and for run | add | event | init SKEIN_OWNER / SKEIN_INFER from owner.identity /
|
|
6
|
+
// infer.identity under it when unset.
|
|
7
|
+
import { existsSync, readFileSync } from "node:fs";
|
|
8
|
+
import { homedir } from "node:os";
|
|
9
|
+
import { join } from "node:path";
|
|
10
|
+
|
|
11
|
+
const root = new URL("..", import.meta.url);
|
|
12
|
+
const home = process.env.SKEIN_HOME || join(homedir(), ".skein");
|
|
13
|
+
process.env.SKEIN_HOME = home;
|
|
14
|
+
const cmd = process.argv[2] ?? "";
|
|
15
|
+
if (["run", "add", "event", "init"].includes(cmd)) {
|
|
16
|
+
for (const [k, f] of [["SKEIN_OWNER", "owner.identity"], ["SKEIN_INFER", "infer.identity"]]) {
|
|
17
|
+
if (!process.env[k] && existsSync(join(home, f))) process.env[k] = readFileSync(join(home, f), "utf8").trim();
|
|
18
|
+
}
|
|
19
|
+
}
|
|
20
|
+
const built = new URL("dist/host/cli.js", root);
|
|
21
|
+
const { main } = await import(existsSync(built) ? built.href : new URL("src/host/cli.ts", root).href);
|
|
22
|
+
process.exitCode = await main(process.argv.slice(2), { vars: process.env, out: (l) => process.stdout.write(`${l}\n`), err: (l) => process.stderr.write(`${l}\n`) });
|
package/bin/skein.js
ADDED
|
@@ -0,0 +1,8 @@
|
|
|
1
|
+
#!/usr/bin/env node
|
|
2
|
+
// skein — the client — for the npm package (and any checkout): dist/client/cli.js, else src/client/cli.ts.
|
|
3
|
+
import { existsSync } from "node:fs";
|
|
4
|
+
|
|
5
|
+
const root = new URL("..", import.meta.url);
|
|
6
|
+
const built = new URL("dist/client/cli.js", root);
|
|
7
|
+
const { main } = await import(existsSync(built) ? built.href : new URL("src/client/cli.ts", root).href);
|
|
8
|
+
main(process.argv.slice(2)).then((code) => process.exit(code), (e) => { process.stderr.write(`skein: ${e?.message ?? e}\n`); process.exit(1); });
|
|
@@ -0,0 +1,10 @@
|
|
|
1
|
+
import { type Vars } from "../host/hostenv.ts";
|
|
2
|
+
export declare const ADMIN_USAGE = "usage (the operator's messages, signed with SKEIN_OPERATOR_KEY, default $SKEIN_HOME/operator.key):\n skein install <catalog-name | url#commit | dir> <where> [--config <file.json>] [--dry-run]\n an app (docs/APPS.md \u00A73): a name from the instance's catalog or a repository\n and commit, cloned by the instance's git app; head <app>/app, its rows, start\n skein uninstall <app> <where> [--dry-run] its stop, then its routes removed (the heads are left)\n skein routes add [--transport mailbox|event|http|libp2p] [--prefix] [--filters f,g] [--fn f] [--settings json] <address> [<handler>] <where> [--dry-run]\n root's own route (#143): <handler> a program record CID, a genesis program,\n or <app>.<role>; an http route with --filters and no handler is a read route\n (the site at /: routes add --prefix --filters site.get --settings '{\"root\":\"www\"}' /)\n skein routes remove [--transport t] [--prefix] <address> <where> [--dry-run]\n skein grant add|remove <key> [--role root|<app>.<role>] <where> [--dry-run] a grant (#143; root by default)\n skein peers add <key> <address> [--transport mailbox|libp2p|local] [--handle h@d] <where> [--dry-run]\n skein peers remove <key> <where> [--dry-run] an address-book entry (#70)\n skein host add|remove (<host-key> --x sats [--rates json] | --from <host origin>) <where> [--dry-run]\n the host row (#130)\n skein claim [--messagebox url] [--handle h@d] <where> [--dry-run] an image's claim (#127, #143): root to the key that sends it\n skein deploy <dir> [--only glob,glob | --all] <where> [--dry-run] a directory into main (objects, head)\n<where>: --instance <handle> (this host machine: over its control socket) | <origin> (one BRC-104 session)\n | --store <runtime.db> (read only: planned and printed, nothing sent)";
|
|
3
|
+
export declare const ADMIN_COMMANDS: readonly ["install", "uninstall", "routes", "grant", "peers", "host", "claim", "deploy"];
|
|
4
|
+
export interface AdminEnv {
|
|
5
|
+
vars: Vars;
|
|
6
|
+
out(line: string): void;
|
|
7
|
+
err(line: string): void;
|
|
8
|
+
}
|
|
9
|
+
/** `skein <command> …` for the admin commands. */
|
|
10
|
+
export declare function adminMain(cmd: string, argv: string[], env: AdminEnv): Promise<number>;
|