byollm 0.1.0 → 0.1.2

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 CHANGED
@@ -1,111 +1,11 @@
1
- > **`alpha.15` is a breaking wire change, and it breaks daemons and relays —
2
- > not app authors.** If you call `app.enqueue(...)` and read results, nothing
3
- > in your code changes. If you run a daemon or an upstream, every package must
4
- > move together: a mixed pair refuses on both sides, because both ends parse
5
- > `.strict()`.
1
+ <!-- release-note 0.1.1 -->
2
+ > **`0.1.2` is documentation only — nothing to upgrade.** `PROTOCOL_VERSION`
3
+ > is still `2`, so a 0.1.0 party and a 0.1.1 party talk to each other in both
4
+ > directions. No dependency, schema, wire field or on-disk shape moved.
6
5
  >
7
- > What moved, all of it reconciling the frozen `byollm_009` with its code:
8
- > `JobStub` gains `site` (the site's identity key id) and loses
9
- > `audienceAllow`; `ResultRequest` gains `leaseId`; `HeartbeatResponse` loses
10
- > `leases`, which nothing read; `WireErrorCode` gains `not-ready`,
11
- > `clock-skew` and `forbidden`, and `403` is `forbidden` rather than
12
- > `unauthorized`. `RESULT_PROVENANCE` is superseded by
13
- > `PROVENANCE_NAMES_DEVICE`. See `byollm_009` Amendment A.>
14
- > **`alpha.16` is a breaking wire change — daemons and relays again, not app
15
- > authors.** `app.enqueue(...)` and reading results are unchanged. All five
16
- > packages move together: both ends parse `.strict()`, so a mixed pair
17
- > refuses.
18
- >
19
- > What moved, all of it Tier 2 of `cloud_008`: `model`, `backendClass` and
20
- > `durationMs` come off `ResultRequest` and are sealed **inside** the result
21
- > envelope as `SealedOutcome = { outcome, ran }` — so a daemon can no longer
22
- > declare a model it did not sign, and a relay carries neither.
23
- > `HeartbeatResponse` loses `leases` (nothing read it) and now reports real
24
- > cancellations instead of an empty list. `WireErrorCode` gains `forbidden`
25
- > for 403, leaving `unauthorized` at exactly 401. The relay gained a
26
- > site-plane `cancel` endpoint, honours `stub.deadlineAt`, honours
27
- > `stub.audience`, and remembers a refusal.>
28
- > **`alpha.17` is additive** — no wire change. It exports `ReleaseReason`,
29
- > which `RoutingStore.releaseLeases` names and the package did not export, so
30
- > the interface was unimplementable outside this repo.>
31
- > **`alpha.18` is a breaking wire change — daemons and relays, not app
32
- > authors.** `app.enqueue(...)` and reading results are unchanged. All five
33
- > packages move together.
34
- >
35
- > The **bearer token is gone**: off `PairPollResponse`, off the runner row,
36
- > off the daemon's pairings file, out of the adapter's schema. It was minted,
37
- > hashed and stored on two disks and never sent, looked up or compared —
38
- > `REQUESTS_SIGNED_NOT_BEARER` was enforced by signatures the whole time. If
39
- > you run the Supabase adapter, apply
40
- > `20260819000000_drop_runner_token.sql`; `byollm_approve_pairing` now takes
41
- > one argument. A pairings file written by an older daemon still loads.
42
- >
43
- > `model`, `backendClass` and `durationMs` moved **inside** the sealed result
44
- > (`SealedOutcome = { outcome, ran }`), so a daemon cannot declare a model it
45
- > did not sign and a relay carries none of them. Writing a `RoutingStore`?
46
- > `releaseLeases` takes an optional `reason` and `complete` requires
47
- > `leaseId`, and **an implementation that ignores either still typechecks** —
48
- > run the store contract tests.>
49
- > **`alpha.19` is additive on the wire and a behaviour change in every
50
- > store.** `ResultResponse` gains an optional `duplicate`. Nothing is removed,
51
- > so an older daemon keeps working — but the *order* two rules are checked in
52
- > has changed, and a `RoutingStore` implementation must change with it.
53
- >
54
- > `complete` now checks **terminal state before holder**, scoped to the device
55
- > that finished the job: a replay from that device is answered `duplicate:
56
- > true` with a 2xx, and anyone else gets exactly the refusal they would get
57
- > for a job that is not terminal. Previously `RESULT_IDEMPOTENT` held only
58
- > because the lease is nulled on success, so the holder check tripped first —
59
- > deleting the idempotency branch failed no test. Run the store contract
60
- > tests; the compiler cannot see this.
61
- >
62
- > **`alpha.3` is a breaking change.** A config naming `openai-http` with a
63
- > remote base URL and an offer scope wider than `private` is narrowed to `private`
64
- > until you acknowledge the spend and set a daily ceiling:
65
- > `byollm offer <backend> public --cap <cents>`. Local base URLs are
66
- > unaffected. `byollm backends` shows the cost class per route.
67
-
68
- <!-- release-note 0.1.0-alpha.21 -->
69
- > [!NOTE]
70
- > **`0.1.0-alpha.20` is not a complete release — do not pin it.** Four
71
- > packages published and `@byollm/server` did not: a Sigstore
72
- > transparency-log 409 on its provenance attestation. The workflow's
73
- > "already published" guard correctly refuses to resume a partial publish,
74
- > so `0.1.0-alpha.21` is that release, whole.
75
- >
76
- > If you run the Supabase adapter, `alpha.21` needs
77
- > `20260819010000_completed_by_lease_id.sql`: alpha.19 shipped §3.6's
78
- > ordering without the column it stores the grant in.
79
-
80
- <!-- release-note 0.1.0-alpha.40 -->
81
- **`byollm start` — stop keeping a terminal open.** The daemon can now run
82
- under your computer's own supervisor and restart itself if it stops: a launchd
83
- agent on macOS, a `systemd --user` unit on Linux, a logon task on Windows. All
84
- user-level — no root, no system directories, and `byollm stop` takes it
85
- away. `byollm status` gained a line saying whether it is actually supervised
86
- right now, including the state that matters most: installed but not running,
87
- which looks fine from an app's dashboard and serves nothing.
88
-
89
- If you are running via `npx`, install properly first (`npm install -g
90
- byollm@latest`) — `install` refuses to supervise a copy in npx's cache, because
91
- npm deletes that directory and the service would fail at some later boot.
92
-
93
- <!-- release-note 0.1.0-alpha.41 -->
94
- **`onNoRunner` takes a string.** Your fallback answer is your own value, not
95
- wire data, and handing back a whole result record for it was ceremony — the
96
- README's own example got the shape wrong, which is how this was found.
97
-
98
- ```ts
99
- const { outcome, fallback } = await job.result({
100
- onNoRunner: () => runOnHostedModel(transcript),
101
- });
102
- ```
103
-
104
- Whatever you return, `result()` labels it `fallback: true` — the stamp is
105
- applied by the wait, not taken from you, so an answer that did not run on
106
- somebody's device cannot be reported as though it did (`FALLBACK_LABELED`).
107
- Both delivery channels do it, polling and Supabase Realtime. Records still
108
- work; they just get labelled too.
6
+ > This README used to open with a stack of release notes instead of with the
7
+ > package. The history moved to `docs/release-notes/` and `CHANGELOG.md`,
8
+ > where none of it was lost. Full note: `docs/release-notes/0.1.1.md`.
109
9
 
110
10
  # `byollm`
111
11
 
@@ -193,6 +93,14 @@ for one. It defaults to 2 GB. **It does not know how big your models are**, so
193
93
  set it to fit your largest. It does not apply to services whose compute happens
194
94
  somewhere else — a hosted model reached through a local port loads nothing here.
195
95
 
96
+ `autoUpdate` (default `false`) lets the daemon install new versions when it is
97
+ offered one. Offers are taken only from `updateAuthority` — the reference hub,
98
+ `https://hub.byollm.cloud`, when you leave it out — and never from any other
99
+ site you paired with, never from a direct-mode pairing, and never for an older
100
+ version. Every update is checked against its npm provenance before it runs and
101
+ rolled back if it fails; [`docs/security.md` §7a](https://github.com/oftomorrowinc/byollm/blob/main/docs/security.md#7a-updates)
102
+ says exactly what is checked.
103
+
196
104
  You do not have to write any of this by hand. `byollm services manage` asks
197
105
  what this machine has and writes the file for you, and it is safe to re-run:
198
106
  it shows what is already there.
@@ -246,35 +154,46 @@ The meter is the product, and it gets the same care as the loop.
246
154
 
247
155
  ```bash
248
156
  byollm status # what's connected, what's running, what you've done for others
249
- byollm sites # which sites this device serves, and which are waiting on you
250
- byollm approve <site> # say yes to a site that asked
157
+ byollm sites # which sites this device serves, and which keys it still holds
251
158
  byollm log # every prompt that has ever run here
252
159
  byollm log --full # the whole text, not the first line
253
- byollm stop # stop claiming work — the off switch, always yours
160
+ byollm stop # stop running in the background — the off switch, always yours
254
161
  byollm start # and bring it back
162
+ byollm forget <url> # drop a pairing entirely
255
163
  ```
256
164
 
257
- ### A site cannot add itself
165
+ ### Which sites this device serves is decided in your dashboard
258
166
 
259
167
  Pairing is with an *app* — a hub, a relay, your own server — and one pairing
260
168
  can cover several sites. Which sites arrives on the heartbeat, from the same
261
169
  party that routes the work.
262
170
 
263
- So a site that turns up after pairing **waits**. It is listed by
264
- `byollm sites` with its fingerprint, nothing is claimed for it, and it starts
265
- being served the moment you run `byollm approve <site>`. Compare the
266
- fingerprint against what the site itself shows you before you do.
267
-
268
- The reason is narrow and worth stating: the daemon pins each site's keys so
269
- that the party routing a job cannot choose which key signed it. If that party
270
- could also *add* a site, it could generate a keypair, announce it, sign its
271
- own work with it, and every pin check downstream would pass — because the
272
- list they check against is the thing it wrote. Approving is the one step it
273
- cannot perform for you.
274
-
275
- A key that moves under a site you already approved is refused rather than
276
- replaced, for the life of the pairing — including when the site leaves the
277
- list and comes back. Rotation is an explicit path, not a silent swap.
171
+ A site that turns up after pairing is **pinned and served** from that
172
+ heartbeat on. Nothing on this machine asks you first: `byollm approve` is
173
+ gone (it exits with a tombstone saying so), and which sites reach your device
174
+ is decided in the app's dashboard, where the person changing it is signed in
175
+ and can see what they are changing.
176
+
177
+ What you get instead is a notice. The first time a new site's work runs here,
178
+ the daemon says `now serving <site>, enabled from your dashboard` with the
179
+ site's fingerprint — on screen in `byollm run`, in `~/.byollm/service.log`
180
+ when it runs in the background — so a change made at the app is never silent
181
+ at the machine. `byollm sites` lists every site this device serves and
182
+ every key it still holds, with fingerprints, for comparing against what the
183
+ site itself shows you.
184
+
185
+ What the daemon still refuses, whatever the app says: a key that moves under
186
+ a site id it has already pinned, for the life of the pairing — including when
187
+ the site leaves the list and comes back (rotation is an explicit, signed path,
188
+ not a silent swap); and any job that does not carry a grant signed by the
189
+ control-plane key this device pinned when it paired. A party that can add a
190
+ site to your heartbeat still cannot sign work for it.
191
+
192
+ The trade is stated plainly in the spec (byollm_016, Amendment K): an app or
193
+ control plane that is compromised can point your device at a site you never
194
+ chose. Spend caps bound what that costs, the notice makes it visible, and the
195
+ levers are yours: `byollm stop` stops all work, `byollm forget <url>` drops
196
+ the pairing.
278
197
 
279
198
  Every prompt is appended to `~/.byollm/ingress.log` **before** it executes, so
280
199
  a job that wedges the computer still leaves a record of what it was. The file is
package/dist/bin.js CHANGED
@@ -1,7 +1,7 @@
1
1
  #!/usr/bin/env node
2
2
  import {
3
3
  main
4
- } from "./chunk-FUKJDD7M.js";
4
+ } from "./chunk-K7QYAF7V.js";
5
5
 
6
6
  // src/bin.ts
7
7
  process.exitCode = await main(process.argv.slice(2));