@dinglebear/labby 2.3.2 → 2.6.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +139 -86
- package/lib/platform.js +14 -1
- package/package.json +1 -1
- package/scripts/check-package.js +1 -0
- package/scripts/install.js +84 -3
package/README.md
CHANGED
|
@@ -55,39 +55,30 @@ Labby is centered on the current gateway/operator surface:
|
|
|
55
55
|
Use the generated service, action, and CLI catalogs below for the complete
|
|
56
56
|
current product surface instead of copying inventories into hand-written
|
|
57
57
|
documentation. Standalone ACP chat, Marketplace/MCP Registry browser, Fleet,
|
|
58
|
-
Deploy, and Stash
|
|
58
|
+
Deploy, and the old Agent Artifact Manager (Stash) remain retired; current Linux principal-scoped File Stash is a separate contract. Bounded provider-backed discovery
|
|
59
59
|
through the `artifacts` control-plane service does not restore those products.
|
|
60
60
|
|
|
61
61
|
## Quick Start
|
|
62
62
|
|
|
63
|
-
###
|
|
63
|
+
### Install Labby
|
|
64
64
|
|
|
65
|
-
|
|
66
|
-
stdio server without proxy flags:
|
|
65
|
+
Download the reviewed installer snapshot over canonical HTTPS, then run it locally:
|
|
67
66
|
|
|
68
67
|
```bash
|
|
69
|
-
|
|
70
|
-
labby
|
|
71
|
-
labby
|
|
68
|
+
curl --proto '=https' --proto-redir '=https' --tlsv1.2 -fSLo labby-install.sh \
|
|
69
|
+
https://raw.githubusercontent.com/dinglebear-ai/labby/5ee609bb255bebfbd9eef4d805998ac1e084b878/scripts/install.sh
|
|
70
|
+
sh labby-install.sh
|
|
72
71
|
```
|
|
73
72
|
|
|
74
|
-
|
|
75
|
-
a random high port. Child flags follow the first child token unchanged, and an
|
|
76
|
-
explicit separator is available for unusual commands:
|
|
73
|
+
This initial script is trusted through canonical HTTPS delivery and the explicitly reviewed commit snapshot above; the download does not follow a mutable branch. Its reviewed, embedded SHA-256 pins authenticate the verifier bootstrap; the installer never downloads a replacement checksum to decide which verifier to trust. It uses an installed GitHub CLI **2.102.0 or newer**, or downloads and verifies pinned 2.102.0 into a private temporary directory. It does not change your PATH or install that helper globally. Required system tools are `curl`, `tar`, and `sha256sum` or `shasum`; macOS bootstrap also uses `unzip`.
|
|
77
74
|
|
|
78
|
-
|
|
79
|
-
labby proxy /path/to/dist.js --workspace /srv/data --read-only
|
|
80
|
-
labby proxy -- npx -y @modelcontextprotocol/server-filesystem /srv/data
|
|
81
|
-
```
|
|
75
|
+
Labby release archives still require checksum and provenance verification against the exact repository, release workflow, immutable tag and hosted-runner policy. Releases with `<archive>.sigstore.jsonl` bundles need no GitHub account: verification runs without tokens and with an empty credential store. Older releases without bundles require your own GitHub authentication; the installer stops before downloading their archive if authentication is unavailable. No privileged credential is supplied or shared. Installing a binary does not establish complete onboarding; the subsequent product-owned setup checks remain required.
|
|
82
76
|
|
|
83
|
-
|
|
84
|
-
development. Bearer and OAuth setup, exact-port resource audiences, safe Serve
|
|
85
|
-
ownership, configuration precedence, output modes, and recovery are covered in
|
|
86
|
-
the [stdio MCP proxy guide](./docs/guides/STDIO_MCP_PROXY.md).
|
|
77
|
+
The recommended local setup uses a native service, loopback listener, generated protected credentials, and a short-lived browser handoff. In Settings, connect your Agent provider, choose a discovered model and complete a starter Agent test, register selected supported clients, then use Discover to add and verify an MCP server. Required failures remain visible and resumable; installation alone is not full readiness. No manual configuration-file edits are needed on this path.
|
|
87
78
|
|
|
88
|
-
|
|
79
|
+
#### Optional agent-assisted guidance
|
|
89
80
|
|
|
90
|
-
The
|
|
81
|
+
The checked-in `install-labby` skill helps with guided installation, advanced deployments, and repair. It is optional. To add it to a skill-aware agent:
|
|
91
82
|
|
|
92
83
|
```bash
|
|
93
84
|
npx skills add https://github.com/dinglebear-ai/labby --skill install-labby
|
|
@@ -97,9 +88,9 @@ npx skills add https://github.com/dinglebear-ai/labby --skill install-labby
|
|
|
97
88
|
$install-labby
|
|
98
89
|
```
|
|
99
90
|
|
|
100
|
-
The skill inspects the
|
|
91
|
+
The skill inspects the selected host, follows binary-owned setup operations, helps with explicitly requested advanced deployment choices, and verifies the same required first-use checks. Built-in Agent configuration and external-client registration are separate steps. Security-sensitive durable writes remain owned by the Labby binary.
|
|
101
92
|
|
|
102
|
-
See [`
|
|
93
|
+
See [`skills/install-labby/SKILL.md`](./skills/install-labby/SKILL.md) for the canonical APM orchestration skill and [`docs/adr/0001-install-labby-first-class-install-orchestrator.md`](./docs/adr/0001-install-labby-first-class-install-orchestrator.md) for the architecture decision.
|
|
103
94
|
|
|
104
95
|
#### Install through APM
|
|
105
96
|
|
|
@@ -110,17 +101,17 @@ get the skills and the MCP registration in one step:
|
|
|
110
101
|
apm install -g dinglebear-ai/labby
|
|
111
102
|
```
|
|
112
103
|
|
|
113
|
-
That deploys `install-labby`, `using-labby`, and `
|
|
104
|
+
That deploys `install-labby`, `using-labby`, `using-codemode`, and `using-snippets` into
|
|
114
105
|
`~/.claude/skills` and `~/.agents/skills` and registers the `labby` stdio MCP
|
|
115
106
|
server (`npx -y @dinglebear/labby mcp`) for Claude Code and Codex; `apm.yml` at
|
|
116
107
|
the repository root is the manifest and `apm outdated -g` reports new
|
|
117
108
|
releases. APM does not install the `labby` binary or provision a gateway host:
|
|
118
|
-
|
|
119
|
-
|
|
109
|
+
use the standalone installer above and `labby setup` for that. The optional
|
|
110
|
+
`$install-labby` skill can guide those steps.
|
|
120
111
|
|
|
121
112
|
#### Manual Verified Release
|
|
122
113
|
|
|
123
|
-
|
|
114
|
+
For independent verification of the installer itself, use GitHub CLI **2.102.0 or newer**. Older versions are rejected by Labby's installer and release gates because they lack the corrected signer and source-ref verification policy. Public provenance bundles allow this verification without GitHub login; legacy attestation lookup requires your own `gh auth login` or `GH_TOKEN`.
|
|
124
115
|
|
|
125
116
|
Linux/macOS:
|
|
126
117
|
|
|
@@ -131,7 +122,10 @@ version=vX.Y.Z
|
|
|
131
122
|
base="https://github.com/dinglebear-ai/labby/releases/download/$version"
|
|
132
123
|
curl -fSLO "$base/labby-install.sh"
|
|
133
124
|
curl -fSLO "$base/labby-install.sh.sha256"
|
|
125
|
+
# For releases publishing bundles; older releases require authenticated verification.
|
|
126
|
+
curl -fSLO "$base/labby-install.sh.sigstore.jsonl"
|
|
134
127
|
gh attestation verify labby-install.sh \
|
|
128
|
+
--bundle labby-install.sh.sigstore.jsonl \
|
|
135
129
|
--repo dinglebear-ai/labby \
|
|
136
130
|
--signer-workflow dinglebear-ai/labby/.github/workflows/release.yml \
|
|
137
131
|
--source-ref "refs/tags/$version" \
|
|
@@ -152,10 +146,12 @@ downloads the release archive for the current platform and verifies only the
|
|
|
152
146
|
same release; it does not require `gh` and does not verify GitHub build
|
|
153
147
|
provenance. Use `labby-install.sh` on Linux or macOS when provenance
|
|
154
148
|
verification matters. Current releases do not publish Windows binaries or
|
|
155
|
-
installers.
|
|
149
|
+
installers. The Windows installer source uses the same reviewed verifier pins,
|
|
150
|
+
protected temporary extraction, and account-free bundle policy; Windows runtime
|
|
151
|
+
qualification is still required before a Windows release claim.
|
|
156
152
|
|
|
157
153
|
The separately downloaded and attested install scripts resolve an immutable GitHub Release containing the current
|
|
158
|
-
platform asset,
|
|
154
|
+
platform asset, prepare a verified GitHub CLI, verify the archive's attestation against the
|
|
159
155
|
Labby repository, `release.yml`, exact tag, and hosted-runner policy, verify its checksum, and install `labby` onto the
|
|
160
156
|
user PATH. The shell installer then runs `labby setup`, which
|
|
161
157
|
asks whether this machine should run a server or connect to an existing one.
|
|
@@ -227,8 +223,8 @@ labby host update auto status
|
|
|
227
223
|
labby host update auto disable
|
|
228
224
|
```
|
|
229
225
|
|
|
230
|
-
Both modes require Apple Silicon
|
|
231
|
-
|
|
226
|
+
Both modes require Apple Silicon. The installer uses a suitable existing GitHub
|
|
227
|
+
CLI or bootstraps its pinned verifier in a private temporary directory. They skip drafts, prereleases, missing platform assets, and versions
|
|
232
228
|
equal to or older than the installed binary. The installer verifies attestations
|
|
233
229
|
and checksums before atomic replacement. No separate language runtime is required.
|
|
234
230
|
Use `labby host update --automatic --dry-run` to check without installing.
|
|
@@ -240,21 +236,23 @@ Prerequisites:
|
|
|
240
236
|
- Rust 1.97.1 or newer. CI/release verifies with Rust 1.97.1.
|
|
241
237
|
- `just` for repo commands.
|
|
242
238
|
- `cargo-nextest` for the main test suite.
|
|
243
|
-
- `pnpm 9.15.9`
|
|
239
|
+
- Node.js 22.x and `pnpm 9.15.9` to build the Labby web UI. The repo pins these in
|
|
244
240
|
[.mise.toml](./.mise.toml) and
|
|
245
|
-
[apps/
|
|
241
|
+
[apps/web/package.json](./apps/web/package.json).
|
|
246
242
|
- `openssl` if you want to generate a bearer token manually.
|
|
247
243
|
|
|
248
244
|
```bash
|
|
249
245
|
git clone git@github.com:dinglebear-ai/labby.git
|
|
250
246
|
cd labby
|
|
251
247
|
just install
|
|
252
|
-
just web-build
|
|
253
248
|
labby serve --host 127.0.0.1 --port 8765
|
|
254
249
|
```
|
|
255
250
|
|
|
256
|
-
`just install`
|
|
257
|
-
|
|
251
|
+
`just install` installs the locked frontend dependencies, builds and validates
|
|
252
|
+
the static web UI, then embeds it in the all-features release binary and installs
|
|
253
|
+
it at `~/.local/bin/labby`. The normal build, run, and service-install recipes
|
|
254
|
+
also build the UI automatically before compiling Rust. Node.js and pnpm are
|
|
255
|
+
build-time tools only; prebuilt release binaries already include the UI.
|
|
258
256
|
|
|
259
257
|
On macOS, install the gateway as a persistent per-user service instead of
|
|
260
258
|
running `labby serve` in a terminal:
|
|
@@ -285,7 +283,7 @@ service is changed.
|
|
|
285
283
|
For loopback development, `labby serve` can bootstrap a missing bearer token for
|
|
286
284
|
you. If `LABBY_MCP_HTTP_TOKEN` is absent and `LABBY_AUTH_MODE` is not `oauth`, it
|
|
287
285
|
generates a token, writes a minimal `~/.labby/.env`, reloads it into the running
|
|
288
|
-
process, prints
|
|
286
|
+
process, prints configuration guidance, and continues. The token itself is stored in
|
|
289
287
|
`~/.labby/.env` rather than printed.
|
|
290
288
|
|
|
291
289
|
Bootstrap writes these required `setup` keys if no env exists yet:
|
|
@@ -297,9 +295,11 @@ Bootstrap writes these required `setup` keys if no env exists yet:
|
|
|
297
295
|
- `LABBY_AUTH_MODE=bearer`
|
|
298
296
|
|
|
299
297
|
It also enforces secure file creation via Labby's `env_merge` path (`0600` perms on
|
|
300
|
-
Unix)
|
|
298
|
+
Unix). This is a minimal loopback bootstrap, not the guided onboarding flow.
|
|
299
|
+
Run `labby setup` for interactive server/client configuration, or
|
|
300
|
+
`labby setup state --json` to inspect the snapshot without changing configuration. Ongoing configuration is available in the operator UI's Settings pages.
|
|
301
301
|
|
|
302
|
-
For explicit setup:
|
|
302
|
+
For explicit setup with a manually generated bearer token:
|
|
303
303
|
|
|
304
304
|
```bash
|
|
305
305
|
mkdir -p ~/.labby
|
|
@@ -309,9 +309,8 @@ labby setup
|
|
|
309
309
|
labby serve --host 127.0.0.1 --port 8765
|
|
310
310
|
```
|
|
311
311
|
|
|
312
|
-
Open `http://127.0.0.1:8765/`.
|
|
313
|
-
|
|
314
|
-
checkout.
|
|
312
|
+
Open `http://127.0.0.1:8765/`. Release binaries and normal source builds already
|
|
313
|
+
include the operator UI; no separate web-assets step is needed.
|
|
315
314
|
|
|
316
315
|
### Self-Host The Gateway
|
|
317
316
|
|
|
@@ -321,7 +320,7 @@ gateway host or VM. Labby does not ship a Docker image or Compose deployment;
|
|
|
321
320
|
stdio MCP servers and agent CLIs are installed and launched at runtime.
|
|
322
321
|
|
|
323
322
|
```bash
|
|
324
|
-
|
|
323
|
+
labby host incus setup --version vX.Y.Z
|
|
325
324
|
incus exec labby -- systemctl status labby --no-pager
|
|
326
325
|
incus exec labby -- curl -fsS http://127.0.0.1:8765/ready
|
|
327
326
|
```
|
|
@@ -330,6 +329,31 @@ See [docs/runtime/INCUS.md](./docs/runtime/INCUS.md) for the full Incus
|
|
|
330
329
|
runbook, bare-metal variant, `/dev/net/tun` Tailscale passthrough, manual
|
|
331
330
|
`claude`/`codex`/`gemini` login checklist, and rollback commands.
|
|
332
331
|
|
|
332
|
+
### Proxy One Stdio MCP Server
|
|
333
|
+
|
|
334
|
+
After installing Labby, configure proxy defaults once and launch a JavaScript
|
|
335
|
+
stdio server without proxy flags:
|
|
336
|
+
|
|
337
|
+
```bash
|
|
338
|
+
labby config proxy set
|
|
339
|
+
labby doctor proxy
|
|
340
|
+
labby proxy /path/to/dist.js
|
|
341
|
+
```
|
|
342
|
+
|
|
343
|
+
The built-in zero-flag policy is Tailscale Serve plus tailnet authorization on
|
|
344
|
+
a random high port. Child flags follow the first child token unchanged, and an
|
|
345
|
+
explicit separator is available for unusual commands:
|
|
346
|
+
|
|
347
|
+
```bash
|
|
348
|
+
labby proxy /path/to/dist.js --workspace /srv/data --read-only
|
|
349
|
+
labby proxy -- npx -y @modelcontextprotocol/server-filesystem /srv/data
|
|
350
|
+
```
|
|
351
|
+
|
|
352
|
+
Use `labby proxy --local --auth none ...` for explicit loopback-only
|
|
353
|
+
development. Bearer and OAuth setup, exact-port resource audiences, safe Serve
|
|
354
|
+
ownership, configuration precedence, output modes, and recovery are covered in
|
|
355
|
+
the [stdio MCP proxy guide](./docs/guides/STDIO_MCP_PROXY.md).
|
|
356
|
+
|
|
333
357
|
## Core Workflows
|
|
334
358
|
|
|
335
359
|
### Start Labby
|
|
@@ -439,8 +463,9 @@ MCP call shapes:
|
|
|
439
463
|
{ "code": "async () => codemode.run(\"gateway-summary\", {\"includeHealth\": true})" }
|
|
440
464
|
```
|
|
441
465
|
|
|
442
|
-
Code Mode can call exposed upstream
|
|
443
|
-
|
|
466
|
+
Code Mode can call exposed upstream tools and eligible catalog-admitted
|
|
467
|
+
in-process Labby actions. Route, Loadout, caller, and action policy still
|
|
468
|
+
apply; sandbox access does not grant unrestricted administration.
|
|
444
469
|
|
|
445
470
|
### Work With Code Mode Snippets
|
|
446
471
|
|
|
@@ -454,14 +479,14 @@ labby snippet test my-snippet
|
|
|
454
479
|
```
|
|
455
480
|
|
|
456
481
|
Snippets are stored per-user under `$LABBY_HOME` and executed through the
|
|
457
|
-
gateway Code Mode runner, so they can reach exposed upstream tools
|
|
458
|
-
actions. The `snippets` service is gateway-gated: it is unavailable in builds
|
|
482
|
+
gateway Code Mode runner, so they can reach exposed upstream tools and eligible
|
|
483
|
+
catalog-admitted in-process actions. The `snippets` service is gateway-gated: it is unavailable in builds
|
|
459
484
|
without the `gateway` feature.
|
|
460
485
|
|
|
461
486
|
### Audit Health And Logs
|
|
462
487
|
|
|
463
488
|
```bash
|
|
464
|
-
labby doctor #
|
|
489
|
+
labby doctor # system, auth, gateway, and relay audit
|
|
465
490
|
labby doctor system # local env vars, disk, toolchain
|
|
466
491
|
labby doctor auth # auth/OAuth env vars, files, permissions
|
|
467
492
|
labby doctor proxy # zero-route stdio-proxy config/dependency preflight
|
|
@@ -522,14 +547,15 @@ MCP service tools use the shared action shape:
|
|
|
522
547
|
|
|
523
548
|
```json
|
|
524
549
|
{
|
|
525
|
-
"action": "
|
|
526
|
-
"params": {
|
|
550
|
+
"action": "gateway.list",
|
|
551
|
+
"params": {}
|
|
527
552
|
}
|
|
528
553
|
```
|
|
529
554
|
|
|
530
555
|
Every service tool also supports `help` and `schema` through the shared
|
|
531
|
-
dispatcher. Destructive MCP actions
|
|
532
|
-
|
|
556
|
+
dispatcher. Destructive MCP actions require the MRTR elicitation exchange.
|
|
557
|
+
Clients without form elicitation receive `confirmation_required`;
|
|
558
|
+
`params.confirm` does not authorize execution.
|
|
533
559
|
|
|
534
560
|
## Configuration
|
|
535
561
|
|
|
@@ -560,7 +586,7 @@ Useful environment variables:
|
|
|
560
586
|
| `LABBY_AUTH_PROVIDER` | Inbound OAuth identity provider: `google` (stable) or `authelia` (open beta). |
|
|
561
587
|
| `LABBY_GOOGLE_CLIENT_ID` / `LABBY_GOOGLE_CLIENT_SECRET` | Google credentials when Google is selected. |
|
|
562
588
|
| `LABBY_AUTHELIA_ISSUER_URL` / `LABBY_AUTHELIA_CLIENT_ID` / `LABBY_AUTHELIA_CLIENT_SECRET` | Authelia OIDC configuration; see the pinned registration contract in the OAuth guide. |
|
|
563
|
-
| `LABBY_AUTH_ADMIN_EMAIL` |
|
|
589
|
+
| `LABBY_AUTH_ADMIN_EMAIL` | Administrator email or comma-separated emails; required in OAuth mode. |
|
|
564
590
|
| `LABBY_OAUTH_ENCRYPTION_KEY` | Base64 32-byte key required for encrypted upstream OAuth credentials. Rotation requires reauthorizing affected upstreams. |
|
|
565
591
|
| `LABBY_WEB_ASSETS_DIR` | Override static Labby export directory. |
|
|
566
592
|
| `LABBY_WEB_UI_AUTH_DISABLED` | Development-only browser auth bypass. |
|
|
@@ -569,13 +595,15 @@ Useful environment variables:
|
|
|
569
595
|
| `LABBY_ACTOR_KEY_SECRET` | Stable secret for redacted actor correlation in logs. |
|
|
570
596
|
| `LABBY_ADMIN_ENABLED` | Runtime opt-in for the `lab_admin` tool. |
|
|
571
597
|
|
|
572
|
-
|
|
573
|
-
|
|
574
|
-
|
|
598
|
+
Static bearer authentication establishes an operator transport ceiling, not a
|
|
599
|
+
universal durable administrator grant. Operation-specific access authority
|
|
600
|
+
still applies. Public protected MCP routes validate route-scoped Labby OAuth
|
|
601
|
+
JWTs; do not treat `LABBY_MCP_HTTP_TOKEN` as a public resource credential.
|
|
575
602
|
|
|
576
603
|
When driving the web UI with automation while OAuth is enabled, pass the bearer
|
|
577
|
-
token as a same-origin header. `/auth/session` recognizes that token and returns
|
|
578
|
-
|
|
604
|
+
token as a same-origin header. `/auth/session` recognizes that token and returns
|
|
605
|
+
an authenticated session projection whose authority depends on durable access
|
|
606
|
+
state; a bearer credential does not universally grant durable administration:
|
|
579
607
|
|
|
580
608
|
```bash
|
|
581
609
|
TOKEN=$(awk -F= '/^LABBY_MCP_HTTP_TOKEN=/{print $2}' ~/.labby/.env)
|
|
@@ -590,11 +618,13 @@ See [runtime configuration](./docs/runtime/CONFIG.md),
|
|
|
590
618
|
## Current Catalogs
|
|
591
619
|
|
|
592
620
|
Do not maintain action, feature, env, or coverage inventories by hand in this
|
|
593
|
-
README. The generated artifacts
|
|
621
|
+
README. The generated artifacts describe the all-feature documentation
|
|
622
|
+
projection. Runtime feature, platform, startup, route, and caller authorization
|
|
623
|
+
gates still determine what a running gateway exposes:
|
|
594
624
|
|
|
595
625
|
| Artifact | Purpose |
|
|
596
626
|
| --- | --- |
|
|
597
|
-
| [service-catalog.md](./docs/generated/service-catalog.md) |
|
|
627
|
+
| [service-catalog.md](./docs/generated/service-catalog.md) | Service metadata, conditional registration, features, categories, and supported surfaces. |
|
|
598
628
|
| [action-catalog.md](./docs/generated/action-catalog.md) | Per-service actions and destructive metadata. |
|
|
599
629
|
| [env-reference.md](./docs/generated/env-reference.md) | Env vars generated from service metadata. |
|
|
600
630
|
| [api-routes.md](./docs/generated/api-routes.md) | Mounted HTTP routes. |
|
|
@@ -610,68 +640,83 @@ just docs-generate
|
|
|
610
640
|
just docs-check
|
|
611
641
|
```
|
|
612
642
|
|
|
613
|
-
`docs
|
|
614
|
-
|
|
643
|
+
`labby docs check` verifies generated-artifact freshness and invariants. The
|
|
644
|
+
`just docs-check` recipe also checks Markdown links, documentation policy,
|
|
645
|
+
instruction topology, and control-plane contracts with their regression tests.
|
|
646
|
+
Neither establishes live service health or deployment acceptance. Fix generated
|
|
647
|
+
content at the entrypoints in the [source-ownership index](./docs/generated/README.md),
|
|
648
|
+
then regenerate; that index is itself generated.
|
|
615
649
|
|
|
616
650
|
## Architecture
|
|
617
651
|
|
|
618
|
-
The workspace
|
|
652
|
+
The workspace uses Rust 2024, resolver 3, a single
|
|
619
653
|
`[workspace.package]` version, shared `[workspace.dependencies]`, and shared
|
|
620
654
|
`[workspace.lints]` (`unsafe_code = "forbid"`, `mod_module_files = "deny"`,
|
|
621
|
-
`disallowed_macros = "deny"`). The
|
|
622
|
-
|
|
655
|
+
`disallowed_macros = "deny"`). The member inventory and exact Git-pinned MCP SDK
|
|
656
|
+
revision are maintained in [Cargo.toml](./Cargo.toml);
|
|
657
|
+
[Architecture](./docs/ARCH.md) owns the complete crate map.
|
|
623
658
|
|
|
624
659
|
| Path | Role |
|
|
625
660
|
| --- | --- |
|
|
626
|
-
| [crates/labby-primitives](./crates/labby-primitives) |
|
|
627
|
-
| [crates/labby-apis](./crates/labby-apis) |
|
|
661
|
+
| [crates/labby-primitives](./crates/labby-primitives) | Workspace dependency-leaf crate: `ActionSpec`/`ParamSpec`, `PluginMeta`/`EnvVar`/`Category`, `UiSchema`, static SSRF checks. |
|
|
662
|
+
| [crates/labby-apis](./crates/labby-apis) | Pure SDK contracts for core HTTP behavior, setup, doctor, and Artifact control; no ambient product configuration. |
|
|
628
663
|
| [crates/labby-auth](./crates/labby-auth) | OAuth/JWT/session middleware, route support, and upstream OAuth runtime. |
|
|
629
664
|
| [crates/labby-runtime](./crates/labby-runtime) | Surface-neutral contracts and helpers: `ToolError`, gateway config DTOs, dispatch helpers, redaction, path safety, and security helpers. |
|
|
630
665
|
| [crates/labby-codemode](./crates/labby-codemode) | Client-neutral Code Mode runner kernel, broker, result shaping, snippets, and TypeScript descriptor generation. |
|
|
631
666
|
| [crates/labby-gateway](./crates/labby-gateway) | Gateway manager, upstream MCP proxy pool, Code Mode host adapter, discovery/imports, virtual servers, protected routes, and OAuth lifecycle. |
|
|
632
|
-
| [crates/labby-openapi](./crates/labby-openapi) | OpenAPI
|
|
667
|
+
| [crates/labby-openapi](./crates/labby-openapi) | OpenAPI-to-Code-Mode derivation and hardened outbound HTTP execution. |
|
|
668
|
+
| [crates/labby-browser](./crates/labby-browser) | Reusable browser bridge, pairing, permission, and invocation runtime. |
|
|
669
|
+
| [crates/labby-model](./crates/labby-model) | Model-checking and verification support; never a product dependency. |
|
|
633
670
|
| [crates/labby-web](./crates/labby-web) | Embedded/filesystem web asset serving with symlink escape defense. |
|
|
634
671
|
| [crates/labby](./crates/labby) | Product binary crate: CLI, MCP, HTTP API, config loading, gateway dispatch, logs, setup, snippets, filesystem access, and output rendering. |
|
|
635
672
|
| [crates/labby-winjob](./crates/labby-winjob) | Windows Job Object process-tree support, isolated so the main workspace can keep `unsafe_code = "forbid"`. |
|
|
636
673
|
| [crates/xtask](./crates/xtask) | Repo automation tasks; not published. |
|
|
637
|
-
| [apps/
|
|
674
|
+
| [apps/web](./apps/web/README.md) | Labby web UI, statically exported and served by `labby serve`. |
|
|
638
675
|
| [packages/labby-mcp](./packages/labby-mcp) | npm launcher wrapper behind `npx -y @dinglebear/labby mcp`. |
|
|
639
676
|
| [plugins](./plugins) | Claude/Codex plugin assets and skills. |
|
|
640
677
|
| [docs](./docs/README.md) | Topic documentation and generated inventories. |
|
|
641
678
|
|
|
642
|
-
Shared
|
|
643
|
-
|
|
644
|
-
|
|
645
|
-
`
|
|
679
|
+
Shared operations belong in the owning extracted runtime or product dispatch.
|
|
680
|
+
`labby-gateway` owns upstream discovery, routing, OAuth lifecycle, and the
|
|
681
|
+
gateway Code Mode host; `labby-codemode` owns the host-neutral kernel.
|
|
682
|
+
`labby-apis` remains a pure SDK boundary. Product adapters under
|
|
683
|
+
`crates/labby/src` translate input, caller context, and output without duplicating
|
|
684
|
+
authorization, validation, or operation semantics. See
|
|
646
685
|
[Architecture](./docs/ARCH.md) and [Dispatch](./docs/dev/DISPATCH.md).
|
|
647
686
|
|
|
648
687
|
## Development
|
|
649
688
|
|
|
689
|
+
Read the canonical [AGENTS.md](./AGENTS.md), the [development workflow](./docs/dev/DEVELOPMENT.md), and the nearest nested instructions before changing code. `CLAUDE.md` and `GEMINI.md` are compatibility symlinks to AGENTS.md. See [documentation maintenance](./docs/dev/DOCUMENTATION.md) for documentation ownership and checks.
|
|
690
|
+
|
|
691
|
+
Builds and tests do not update an installed gateway. The install, service, host-sync, and auth-disabled local-preview commands below are separate opt-in operations, not routine validation steps.
|
|
692
|
+
|
|
650
693
|
Prefer the `just` aliases:
|
|
651
694
|
|
|
652
695
|
```bash
|
|
653
696
|
just check # cargo check --workspace --all-features
|
|
654
697
|
just test # cargo nextest run --workspace --all-features
|
|
655
698
|
just test-integration # cargo nextest run --workspace --all-features --run-ignored ignored-only
|
|
656
|
-
just lint # skill drift +
|
|
699
|
+
just lint # skill drift + toolchain sync + module reachability + clippy + fmt
|
|
700
|
+
just docs-check # generated freshness + links + documentation policy and regressions
|
|
701
|
+
just rustdoc-check # strict Rustdoc + workspace doctests
|
|
657
702
|
just deny # cargo deny check
|
|
658
|
-
just build #
|
|
659
|
-
just build-release # release build
|
|
703
|
+
just build # web export + optimized all-features Rust build
|
|
704
|
+
just build-release # web export + release build and binary installation
|
|
660
705
|
just service-install # build and install the native persistent gateway service
|
|
661
706
|
just service-status # inspect the native service manager state
|
|
662
707
|
labby host service install --install-self -y # install current binary + start system service
|
|
663
708
|
labby host service restart --install-self -y # reinstall current binary + restart service
|
|
664
709
|
labby host service status --json # inspect the host Labby gateway service
|
|
665
710
|
just host-sync # repo dev shortcut: rebuild + install binary + restart host service
|
|
666
|
-
just web-build #
|
|
711
|
+
just web-build # locked dependency install + validated static UI export
|
|
667
712
|
just web-watch # rebuild web assets when frontend files change
|
|
668
|
-
just run -- help # cargo run --all-features -- <args>
|
|
713
|
+
just run -- help # web export + cargo run --all-features -- <args>
|
|
669
714
|
just chat-local # local Labby admin UI workflow with browser auth disabled
|
|
670
|
-
just install #
|
|
671
|
-
just mcp-token # rotate
|
|
715
|
+
just install # web export + release build + install ~/.local/bin/labby
|
|
716
|
+
just mcp-token # rotate checkout .env token and print it; not daemon secret rotation
|
|
672
717
|
```
|
|
673
718
|
|
|
674
|
-
|
|
719
|
+
Use all-feature workspace verification plus affected standalone feature slices:
|
|
675
720
|
|
|
676
721
|
```bash
|
|
677
722
|
cargo check --workspace --all-features
|
|
@@ -680,16 +725,22 @@ cargo nextest run --workspace --all-features
|
|
|
680
725
|
cargo build --workspace --all-features
|
|
681
726
|
```
|
|
682
727
|
|
|
728
|
+
Direct Cargo commands are low-level backend development paths: they do not build
|
|
729
|
+
the frontend and may embed no UI in a clean checkout. Use `just build` or
|
|
730
|
+
`just install` to produce a complete gateway binary. `just check`, `just test`,
|
|
731
|
+
and `just lint` do not invoke the frontend build; `just web-build` is an optional
|
|
732
|
+
frontend-only command, not a prerequisite users need to run separately.
|
|
733
|
+
|
|
683
734
|
CI uses the same posture and runs nextest with its CI profile. Use `cargo test`
|
|
684
735
|
only for narrow local slices or when a tool specifically requires it.
|
|
685
736
|
|
|
686
737
|
Frontend changes should also run the relevant `pnpm` scripts under
|
|
687
|
-
`apps/
|
|
738
|
+
`apps/web`, and `just web-build` when exported assets matter.
|
|
688
739
|
|
|
689
740
|
### Host Gateway Runtime
|
|
690
741
|
|
|
691
742
|
The recommended self-hosted gateway runtime is the Incus system container
|
|
692
|
-
provisioned by `
|
|
743
|
+
provisioned by `labby host incus setup --version vX.Y.Z` and converged
|
|
693
744
|
in-box with `labby setup --provision`. Bare metal uses the same provisioner and
|
|
694
745
|
system unit when the host or VM is dedicated to Labby. The default service is
|
|
695
746
|
`/etc/systemd/system/labby.service`, running as `User=labby`, `Group=labby`, with
|
|
@@ -701,15 +752,17 @@ remains the rebuild-and-restart developer shortcut.
|
|
|
701
752
|
Release Please maintains the version/changelog pull request and creates the
|
|
702
753
|
stable tag plus draft GitHub release when that pull request merges. The stable
|
|
703
754
|
tag triggers the heavy GitHub-hosted candidate workflow. It builds Linux and
|
|
704
|
-
macOS archives with checksums,
|
|
705
|
-
publishes the npm launcher, and publishes Labby's
|
|
755
|
+
macOS archives with checksums, publishes the npm launcher, and publishes Labby's
|
|
706
756
|
`server.json` metadata to the official MCP Registry. Only after qualification
|
|
707
757
|
and publication succeed does the workflow promote the draft GitHub release.
|
|
758
|
+
Incus substrate images build and publish independently through
|
|
759
|
+
`.github/workflows/incus-image.yml`; normal binary releases do not build an image.
|
|
708
760
|
|
|
709
761
|
### Plugin Setup
|
|
710
762
|
|
|
711
|
-
|
|
712
|
-
|
|
763
|
+
`plugins/labby` supplies usage skills; `plugins/install-labby` owns the installer
|
|
764
|
+
skill, MCP configuration, and `userConfig`. Neither bundles the Labby binary
|
|
765
|
+
or automatic lifecycle hooks. The former
|
|
713
766
|
`plugins/labby/hooks/hooks.json` (SessionStart / ConfigChange shims) has been
|
|
714
767
|
removed; operators run `labby setup` themselves. Do not reintroduce a `hooks/`
|
|
715
768
|
directory, bundle a binary under `plugins/labby/bin/`, or add
|
package/lib/platform.js
CHANGED
|
@@ -15,6 +15,14 @@ function targetFor(platform = process.platform, arch = process.arch) {
|
|
|
15
15
|
};
|
|
16
16
|
}
|
|
17
17
|
|
|
18
|
+
if (platform === "linux" && arch === "arm64") {
|
|
19
|
+
return {
|
|
20
|
+
asset: "lab-aarch64-unknown-linux-gnu.tar.gz",
|
|
21
|
+
binary: "labby",
|
|
22
|
+
archiveType: "tar.gz",
|
|
23
|
+
};
|
|
24
|
+
}
|
|
25
|
+
|
|
18
26
|
if (platform === "darwin" && arch === "arm64") {
|
|
19
27
|
return {
|
|
20
28
|
asset: "lab-aarch64-apple-darwin.tar.gz",
|
|
@@ -24,7 +32,7 @@ function targetFor(platform = process.platform, arch = process.arch) {
|
|
|
24
32
|
}
|
|
25
33
|
|
|
26
34
|
throw new Error(
|
|
27
|
-
`Unsupported platform ${platform}/${arch}. Supported targets: linux/x64, darwin/arm64.`,
|
|
35
|
+
`Unsupported platform ${platform}/${arch}. Supported targets: linux/x64, linux/arm64, darwin/arm64.`,
|
|
28
36
|
);
|
|
29
37
|
}
|
|
30
38
|
|
|
@@ -46,6 +54,10 @@ function installRoot() {
|
|
|
46
54
|
return path.resolve(__dirname, "..", "vendor");
|
|
47
55
|
}
|
|
48
56
|
|
|
57
|
+
function companionRoot() {
|
|
58
|
+
return path.join(installRoot(), "tailcat");
|
|
59
|
+
}
|
|
60
|
+
|
|
49
61
|
function binaryPath(platform = process.platform, arch = process.arch) {
|
|
50
62
|
const target = targetFor(platform, arch);
|
|
51
63
|
return path.join(installRoot(), target.binary);
|
|
@@ -53,6 +65,7 @@ function binaryPath(platform = process.platform, arch = process.arch) {
|
|
|
53
65
|
|
|
54
66
|
module.exports = {
|
|
55
67
|
binaryPath,
|
|
68
|
+
companionRoot,
|
|
56
69
|
downloadUrl,
|
|
57
70
|
installRoot,
|
|
58
71
|
packageVersion,
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@dinglebear/labby",
|
|
3
|
-
"version": "2.
|
|
3
|
+
"version": "2.6.0",
|
|
4
4
|
"license": "AGPL-3.0-only",
|
|
5
5
|
"description": "Rust MCP gateway with Code Mode, authentication, setup, logs, CLI, HTTP API, and operator web UI.",
|
|
6
6
|
"homepage": "https://github.com/dinglebear-ai/labby#readme",
|
package/scripts/check-package.js
CHANGED
package/scripts/install.js
CHANGED
|
@@ -158,7 +158,8 @@ async function main() {
|
|
|
158
158
|
const target = targetFor();
|
|
159
159
|
const destination = binaryPath();
|
|
160
160
|
|
|
161
|
-
|
|
161
|
+
recoverInstallation(installRoot());
|
|
162
|
+
if (installationValid(installRoot(), target, releaseVersion())) {
|
|
162
163
|
log(`${path.basename(destination)} already installed for ${releaseVersion()}`);
|
|
163
164
|
return;
|
|
164
165
|
}
|
|
@@ -171,14 +172,90 @@ async function main() {
|
|
|
171
172
|
log(`downloading ${url}`);
|
|
172
173
|
await download(url, archive);
|
|
173
174
|
await verifyChecksum(url, archive);
|
|
174
|
-
|
|
175
|
-
fs.chmodSync(destination, 0o755);
|
|
175
|
+
installArchive(archive, installRoot(), target, releaseVersion());
|
|
176
176
|
log(`installed ${destination}`);
|
|
177
177
|
} finally {
|
|
178
178
|
fs.rmSync(tempDir, { recursive: true, force: true });
|
|
179
179
|
}
|
|
180
180
|
}
|
|
181
181
|
|
|
182
|
+
function requiresCompanions(version) {
|
|
183
|
+
const match = /^v?(\d+)\.(\d+)\.(\d+)$/.exec(version);
|
|
184
|
+
if (!match) throw new Error("invalid release version");
|
|
185
|
+
// Published v2.5.0 archives contain only the binary. Later releases require the bundle.
|
|
186
|
+
const [, major, minor, patch] = match.map(Number);
|
|
187
|
+
return major > 2 || (major === 2 && (minor > 5 || (minor === 5 && patch > 0)));
|
|
188
|
+
}
|
|
189
|
+
|
|
190
|
+
function validateInstallation(root, target, version) {
|
|
191
|
+
const binary = path.join(root, target.binary);
|
|
192
|
+
if (!fs.lstatSync(binary).isFile()) throw new Error("release binary is not regular");
|
|
193
|
+
const companions = path.join(root, "tailcat");
|
|
194
|
+
if (!fs.existsSync(companions)) {
|
|
195
|
+
if (requiresCompanions(version)) throw new Error("release companions missing");
|
|
196
|
+
return;
|
|
197
|
+
}
|
|
198
|
+
if (!fs.lstatSync(companions).isDirectory()) throw new Error("invalid companion directory");
|
|
199
|
+
const manifestPath = path.join(companions, "manifest.json");
|
|
200
|
+
if (!fs.lstatSync(manifestPath).isFile() || fs.statSync(manifestPath).size > 2 * 1024 * 1024) throw new Error("invalid companion manifest");
|
|
201
|
+
const manifest = JSON.parse(fs.readFileSync(manifestPath, "utf8"));
|
|
202
|
+
if (manifest.schemaVersion !== 1 || manifest.protocol !== 1 || manifest.version !== version.replace(/^v/, "") || manifest.target !== target.asset.replace(/^lab-/, "").replace(/\.tar\.gz$/, "") || !Array.isArray(manifest.components) || manifest.components.length > 8192) throw new Error("companion release mismatch");
|
|
203
|
+
const expected = new Set();
|
|
204
|
+
let total = 0;
|
|
205
|
+
for (const entry of manifest.components) {
|
|
206
|
+
if (typeof entry.path !== "string" || !entry.path || entry.path.includes("\\") || entry.path.split("/").some(part => !part || part === "." || part === "..") || path.isAbsolute(entry.path) || expected.has(entry.path) || !/^[a-f0-9]{64}$/.test(entry.sha256)) throw new Error("invalid companion entry");
|
|
207
|
+
expected.add(entry.path);
|
|
208
|
+
let file = companions;
|
|
209
|
+
for (const part of entry.path.split("/")) {
|
|
210
|
+
file = path.join(file, part);
|
|
211
|
+
if (fs.lstatSync(file).isSymbolicLink()) throw new Error("symlink companion");
|
|
212
|
+
}
|
|
213
|
+
const stat = fs.statSync(file);
|
|
214
|
+
total += stat.size;
|
|
215
|
+
if (!stat.isFile() || stat.size > 128 * 1024 * 1024 || total > 512 * 1024 * 1024 || crypto.createHash("sha256").update(fs.readFileSync(file)).digest("hex") !== entry.sha256) throw new Error("companion checksum mismatch");
|
|
216
|
+
}
|
|
217
|
+
let count = 0;
|
|
218
|
+
function inventory(directory, prefix = "", depth = 0) {
|
|
219
|
+
if (depth > 64) throw new Error("companion depth exceeded");
|
|
220
|
+
for (const entry of fs.readdirSync(directory, { withFileTypes: true })) {
|
|
221
|
+
if (++count > 16384) throw new Error("companion inventory exceeded");
|
|
222
|
+
const relative = prefix + entry.name;
|
|
223
|
+
if (entry.isDirectory()) inventory(path.join(directory, entry.name), relative + "/", depth + 1);
|
|
224
|
+
else if (!entry.isFile() || (relative !== "manifest.json" && !expected.has(relative))) throw new Error("unlisted companion");
|
|
225
|
+
}
|
|
226
|
+
}
|
|
227
|
+
inventory(companions);
|
|
228
|
+
for (const required of ["native/tailcat-bridge", "browser/hook.mjs", "browser/transport.mjs", "browser/http.mjs", "browser/wasm.mjs", "browser/tailcat.wasm", "browser/tailcat.wasm.gz", "browser/wasm_exec.js", "browser/THIRD_PARTY_NOTICES.md", "adapter/server.mjs", "adapter/cleanup.mjs", "adapter/package.json", "adapter/package-lock.json"]) {
|
|
229
|
+
if (!expected.has(required)) throw new Error("incomplete companion inventory");
|
|
230
|
+
}
|
|
231
|
+
}
|
|
232
|
+
|
|
233
|
+
function installationValid(root, target, version) {
|
|
234
|
+
try { validateInstallation(root, target, version); return true; } catch { return false; }
|
|
235
|
+
}
|
|
236
|
+
|
|
237
|
+
function recoverInstallation(root) {
|
|
238
|
+
const backup = root + ".previous";
|
|
239
|
+
if (!fs.existsSync(root) && fs.existsSync(backup)) fs.renameSync(backup, root);
|
|
240
|
+
}
|
|
241
|
+
|
|
242
|
+
function installArchive(archive, root, target, version) {
|
|
243
|
+
fs.mkdirSync(path.dirname(root), { recursive: true });
|
|
244
|
+
const stage = fs.mkdtempSync(path.join(path.dirname(root), ".labby-install-"));
|
|
245
|
+
const backup = root + ".previous";
|
|
246
|
+
try {
|
|
247
|
+
extract(archive, stage, target.archiveType);
|
|
248
|
+
validateInstallation(stage, target, version);
|
|
249
|
+
fs.chmodSync(path.join(stage, target.binary), 0o755);
|
|
250
|
+
// Preserve the prior complete directory until the new pair has been published.
|
|
251
|
+
if (fs.existsSync(backup)) fs.rmSync(backup, { recursive: true, force: true });
|
|
252
|
+
if (fs.existsSync(root)) fs.renameSync(root, backup);
|
|
253
|
+
try { fs.renameSync(stage, root); }
|
|
254
|
+
catch (error) { recoverInstallation(root); throw error; }
|
|
255
|
+
fs.rmSync(backup, { recursive: true, force: true });
|
|
256
|
+
} finally { fs.rmSync(stage, { recursive: true, force: true }); }
|
|
257
|
+
}
|
|
258
|
+
|
|
182
259
|
if (require.main === module) {
|
|
183
260
|
main().catch((error) => {
|
|
184
261
|
log(error.message);
|
|
@@ -187,6 +264,10 @@ if (require.main === module) {
|
|
|
187
264
|
}
|
|
188
265
|
|
|
189
266
|
module.exports = {
|
|
267
|
+
extract,
|
|
268
|
+
installArchive,
|
|
269
|
+
installationValid,
|
|
270
|
+
recoverInstallation,
|
|
190
271
|
powershellExpandArchiveCommand,
|
|
191
272
|
powershellLiteral,
|
|
192
273
|
};
|