byollm 0.1.0-alpha.4 → 0.1.0-alpha.40

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,5 +1,5 @@
1
1
  > [!WARNING]
2
- > **Alpha (`0.1.0-alpha.4`) — under active development. Don't use this yet.**
2
+ > **Alpha (`0.1.0-alpha.40`) — under active development. Don't use this yet.**
3
3
  >
4
4
  > Install it deliberately: `npx byollm@alpha`, or `npm install byollm@alpha`.
5
5
  >
@@ -11,7 +11,67 @@
11
11
  > npm assigns `latest` on a first publish and won't let it be removed, so a
12
12
  > bare install resolves here too. This notice is the only guard — deliberately
13
13
  > not an npm deprecation, which would read as *abandoned* rather than *early*.
14
- > Ask for `@alpha` explicitly so your lockfile records that you meant to.
14
+ > Ask for `@alpha` explicitly so your lockfile records that you meant to.>
15
+ > **`alpha.15` is a breaking wire change, and it breaks daemons and relays —
16
+ > not app authors.** If you call `app.enqueue(...)` and read results, nothing
17
+ > in your code changes. If you run a daemon or an upstream, every package must
18
+ > move together: a mixed pair refuses on both sides, because both ends parse
19
+ > `.strict()`.
20
+ >
21
+ > What moved, all of it reconciling the frozen `byollm_009` with its code:
22
+ > `JobStub` gains `site` (the site's identity key id) and loses
23
+ > `audienceAllow`; `ResultRequest` gains `leaseId`; `HeartbeatResponse` loses
24
+ > `leases`, which nothing read; `WireErrorCode` gains `not-ready`,
25
+ > `clock-skew` and `forbidden`, and `403` is `forbidden` rather than
26
+ > `unauthorized`. `RESULT_PROVENANCE` is superseded by
27
+ > `PROVENANCE_NAMES_DEVICE`. See `byollm_009` Amendment A.>
28
+ > **`alpha.16` is a breaking wire change — daemons and relays again, not app
29
+ > authors.** `app.enqueue(...)` and reading results are unchanged. All five
30
+ > packages move together: both ends parse `.strict()`, so a mixed pair
31
+ > refuses.
32
+ >
33
+ > What moved, all of it Tier 2 of `cloud_008`: `model`, `backendClass` and
34
+ > `durationMs` come off `ResultRequest` and are sealed **inside** the result
35
+ > envelope as `SealedOutcome = { outcome, ran }` — so a daemon can no longer
36
+ > declare a model it did not sign, and a relay carries neither.
37
+ > `HeartbeatResponse` loses `leases` (nothing read it) and now reports real
38
+ > cancellations instead of an empty list. `WireErrorCode` gains `forbidden`
39
+ > for 403, leaving `unauthorized` at exactly 401. The relay gained a
40
+ > site-plane `cancel` endpoint, honours `stub.deadlineAt`, honours
41
+ > `stub.audience`, and remembers a refusal.>
42
+ > **`alpha.17` is additive** — no wire change. It exports `ReleaseReason`,
43
+ > which `RoutingStore.releaseLeases` names and the package did not export, so
44
+ > the interface was unimplementable outside this repo.>
45
+ > **`alpha.18` is a breaking wire change — daemons and relays, not app
46
+ > authors.** `app.enqueue(...)` and reading results are unchanged. All five
47
+ > packages move together.
48
+ >
49
+ > The **bearer token is gone**: off `PairPollResponse`, off the runner row,
50
+ > off the daemon's pairings file, out of the adapter's schema. It was minted,
51
+ > hashed and stored on two disks and never sent, looked up or compared —
52
+ > `REQUESTS_SIGNED_NOT_BEARER` was enforced by signatures the whole time. If
53
+ > you run the Supabase adapter, apply
54
+ > `20260819000000_drop_runner_token.sql`; `byollm_approve_pairing` now takes
55
+ > one argument. A pairings file written by an older daemon still loads.
56
+ >
57
+ > `model`, `backendClass` and `durationMs` moved **inside** the sealed result
58
+ > (`SealedOutcome = { outcome, ran }`), so a daemon cannot declare a model it
59
+ > did not sign and a relay carries none of them. Writing a `RoutingStore`?
60
+ > `releaseLeases` takes an optional `reason` and `complete` requires
61
+ > `leaseId`, and **an implementation that ignores either still typechecks** —
62
+ > run the store contract tests.>
63
+ > **`alpha.19` is additive on the wire and a behaviour change in every
64
+ > store.** `ResultResponse` gains an optional `duplicate`. Nothing is removed,
65
+ > so an older daemon keeps working — but the *order* two rules are checked in
66
+ > has changed, and a `RoutingStore` implementation must change with it.
67
+ >
68
+ > `complete` now checks **terminal state before holder**, scoped to the device
69
+ > that finished the job: a replay from that device is answered `duplicate:
70
+ > true` with a 2xx, and anyone else gets exactly the refusal they would get
71
+ > for a job that is not terminal. Previously `RESULT_IDEMPOTENT` held only
72
+ > because the lease is nulled on success, so the holder check tripped first —
73
+ > deleting the idempotency branch failed no test. Run the store contract
74
+ > tests; the compiler cannot see this.
15
75
  >
16
76
  > **`alpha.3` is a breaking change.** A config naming `openai-http` with a
17
77
  > remote base URL and an offer scope wider than `self` is narrowed to `self`
@@ -19,6 +79,31 @@
19
79
  > `byollm offer <backend> public --cap <cents>`. Local base URLs are
20
80
  > unaffected. `byollm backends` shows the cost class per route.
21
81
 
82
+ <!-- release-note 0.1.0-alpha.21 -->
83
+ > [!NOTE]
84
+ > **`0.1.0-alpha.20` is not a complete release — do not pin it.** Four
85
+ > packages published and `@byollm/server` did not: a Sigstore
86
+ > transparency-log 409 on its provenance attestation. The workflow's
87
+ > "already published" guard correctly refuses to resume a partial publish,
88
+ > so `0.1.0-alpha.40` is that release, whole.
89
+ >
90
+ > If you run the Supabase adapter, `alpha.21` needs
91
+ > `20260819010000_completed_by_lease_id.sql`: alpha.19 shipped §3.6's
92
+ > ordering without the column it stores the grant in.
93
+
94
+ <!-- release-note 0.1.0-alpha.40 -->
95
+ **`byollm install` — stop keeping a terminal open.** The daemon can now run
96
+ under your machine's own supervisor and restart itself if it stops: a launchd
97
+ agent on macOS, a `systemd --user` unit on Linux, a logon task on Windows. All
98
+ user-level — no root, no system directories, and `byollm uninstall` takes it
99
+ away. `byollm status` gained a line saying whether it is actually supervised
100
+ right now, including the state that matters most: installed but not running,
101
+ which looks fine from an app's dashboard and serves nothing.
102
+
103
+ If you are running via `npx`, install properly first (`npm install -g
104
+ byollm@alpha`) — `install` refuses to supervise a copy in npx's cache, because
105
+ npm deletes that directory and the service would fail at some later boot.
106
+
22
107
  # `byollm`
23
108
 
24
109
  What end users run. Connects **outbound** to an app you trust, claims only the
@@ -86,18 +171,75 @@ URL, a path or a flag — there is no field on the wire for any of them.
86
171
  therefore advertised. A backend that is down is never advertised, so you never
87
172
  get work you cannot run.
88
173
 
174
+ ## Keep it running
175
+
176
+ By default `byollm connect` and `byollm run` hold a terminal — close the
177
+ window and the machine stops serving. Nothing breaks (your pairings live in
178
+ `~/.byollm/pairings.json` and survive), but the machine goes quiet without
179
+ telling anyone, and if it is on a team's roster, the first person to notice is
180
+ a teammate whose job did not run.
181
+
182
+ ```bash
183
+ byollm install # keep running in the background, and restart if it stops
184
+ byollm status # says whether it is actually supervised right now
185
+ byollm uninstall
186
+ ```
187
+
188
+ It installs at the user level on every platform — a launchd `LaunchAgent` on
189
+ macOS, a `systemd --user` unit on Linux, a logon task on Windows. No root, no
190
+ system directories: it runs as you, it stops when you say so, and you can read
191
+ every file it wrote. Output goes to `~/.byollm/service.log` on all three.
192
+
193
+ Two things worth knowing:
194
+
195
+ - **Install `byollm` properly first.** `byollm install` refuses to supervise a
196
+ copy running from `npx`'s cache, because npm deletes that directory without
197
+ warning and the service would stop working at some later boot with nothing
198
+ to show for it. `npm install -g byollm@alpha` first.
199
+ - **On Linux, `systemd --user` stops when you log out** unless lingering is
200
+ enabled. `byollm install` prints the one command for that rather than
201
+ running it — it changes something outside your session, so it is your call.
202
+
203
+ `byollm status` reports three states, not two: running under supervision,
204
+ *installed but not running* (the one that looks fine from an app's dashboard
205
+ and serves nothing), and not installed at all.
206
+
89
207
  ## The trust surface
90
208
 
91
209
  The meter is the product, and it gets the same care as the loop.
92
210
 
93
211
  ```bash
94
212
  byollm status # what's connected, what's running, what you've done for others
213
+ byollm sites # which sites this machine serves, and which are waiting on you
214
+ byollm approve <site> # say yes to a site that asked
95
215
  byollm log # every prompt that has ever run here
96
216
  byollm log --full # the whole text, not the first line
97
217
  byollm pause # stop claiming work
98
218
  byollm resume
99
219
  ```
100
220
 
221
+ ### A site cannot add itself
222
+
223
+ Pairing is with an *app* — a hub, a relay, your own server — and one pairing
224
+ can cover several sites. Which sites arrives on the heartbeat, from the same
225
+ party that routes the work.
226
+
227
+ So a site that turns up after pairing **waits**. It is listed by
228
+ `byollm sites` with its fingerprint, nothing is claimed for it, and it starts
229
+ being served the moment you run `byollm approve <site>`. Compare the
230
+ fingerprint against what the site itself shows you before you do.
231
+
232
+ The reason is narrow and worth stating: the daemon pins each site's keys so
233
+ that the party routing a job cannot choose which key signed it. If that party
234
+ could also *add* a site, it could generate a keypair, announce it, sign its
235
+ own work with it, and every pin check downstream would pass — because the
236
+ list they check against is the thing it wrote. Approving is the one step it
237
+ cannot perform for you.
238
+
239
+ A key that moves under a site you already approved is refused rather than
240
+ replaced, for the life of the pairing — including when the site leaves the
241
+ list and comes back. Rotation is an explicit path, not a silent swap.
242
+
101
243
  Every prompt is appended to `~/.byollm/ingress.log` **before** it executes, so
102
244
  a job that wedges the machine still leaves a record of what it was. The file is
103
245
  JSONL, `0600`, and yours to read, grep and delete.
package/dist/bin.js CHANGED
@@ -1,7 +1,7 @@
1
1
  #!/usr/bin/env node
2
2
  import {
3
3
  main
4
- } from "./chunk-CKWS6NEW.js";
4
+ } from "./chunk-RYUKSHXG.js";
5
5
 
6
6
  // src/bin.ts
7
7
  process.exitCode = await main(process.argv.slice(2));