@dinglebear/labby 1.8.6
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/LICENSE-MIT +21 -0
- package/README.md +541 -0
- package/bin/labby.js +34 -0
- package/lib/platform.js +60 -0
- package/package.json +64 -0
- package/scripts/check-package.js +529 -0
- package/scripts/install.js +192 -0
- package/scripts/sync-readme.js +26 -0
package/LICENSE-MIT
ADDED
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
MIT License
|
|
2
|
+
|
|
3
|
+
Copyright (c) 2025 Jacob Magar
|
|
4
|
+
|
|
5
|
+
Permission is hereby granted, free of charge, to any person obtaining a copy
|
|
6
|
+
of this software and associated documentation files (the "Software"), to deal
|
|
7
|
+
in the Software without restriction, including without limitation the rights
|
|
8
|
+
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
|
9
|
+
copies of the Software, and to permit persons to whom the Software is
|
|
10
|
+
furnished to do so, subject to the following conditions:
|
|
11
|
+
|
|
12
|
+
The above copyright notice and this permission notice shall be included in all
|
|
13
|
+
copies or substantial portions of the Software.
|
|
14
|
+
|
|
15
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
16
|
+
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
17
|
+
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
|
18
|
+
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
|
19
|
+
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
|
20
|
+
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
|
21
|
+
SOFTWARE.
|
package/README.md
ADDED
|
@@ -0,0 +1,541 @@
|
|
|
1
|
+
# Labby
|
|
2
|
+
|
|
3
|
+
Rust MCP gateway with Code Mode, authentication, setup, logs, CLI, HTTP API, and operator web UI.
|
|
4
|
+
|
|
5
|
+
Canonical remote: `git@github.com:dinglebear-ai/labby.git`.
|
|
6
|
+
|
|
7
|
+
The root README is the public entrypoint. The topic docs in
|
|
8
|
+
[docs/](./docs/README.md) own the detailed contracts; when this file and a topic
|
|
9
|
+
doc disagree, fix the topic doc first and then refresh this summary.
|
|
10
|
+
|
|
11
|
+
## Contents
|
|
12
|
+
|
|
13
|
+
- [What Labby Does](#what-labby-does)
|
|
14
|
+
- [Quick Start](#quick-start)
|
|
15
|
+
- [Core Workflows](#core-workflows)
|
|
16
|
+
- [Runtime Surfaces](#runtime-surfaces)
|
|
17
|
+
- [Configuration](#configuration)
|
|
18
|
+
- [Current Catalogs](#current-catalogs)
|
|
19
|
+
- [Architecture](#architecture)
|
|
20
|
+
- [Development](#development)
|
|
21
|
+
- [Documentation](#documentation)
|
|
22
|
+
|
|
23
|
+
## What Labby Does
|
|
24
|
+
|
|
25
|
+
Labby is centered on the current gateway/operator surface:
|
|
26
|
+
|
|
27
|
+
- **MCP gateway** - connect HTTP and stdio upstream MCP servers, inspect their
|
|
28
|
+
tools/resources/prompts, apply exposure filters, publish protected MCP routes,
|
|
29
|
+
and optionally collapse the upstream catalog into Code Mode `search` and
|
|
30
|
+
`execute`.
|
|
31
|
+
- **Authentication and protected routes** - run bearer or OAuth authentication,
|
|
32
|
+
manage route-scoped access, authorize upstream OAuth connections, and publish
|
|
33
|
+
protected MCP endpoints.
|
|
34
|
+
- **Code Mode snippets** - author, store, and run reusable JavaScript snippets
|
|
35
|
+
against the upstream catalog, with artifacts persisted under `$LABBY_HOME`.
|
|
36
|
+
- **Setup and doctor** - bootstrap `~/.labby`, provision the host service, and
|
|
37
|
+
run a health audit across env, reachability, auth, and versions.
|
|
38
|
+
- **Filesystem service** - scoped, path-safety-checked file operations exposed
|
|
39
|
+
through the same action dispatch as every other service.
|
|
40
|
+
- **Server logs** - search and tail the local `labby serve` log stream.
|
|
41
|
+
- **Incus and bare-metal setup** - provision and operate a dedicated Labby
|
|
42
|
+
gateway host without introducing a separate fleet or deployment product.
|
|
43
|
+
- **Generated discovery** - publish code-owned service, action, environment,
|
|
44
|
+
API route, OpenAPI, MCP help, CLI help, and feature-matrix artifacts under
|
|
45
|
+
[docs/generated](./docs/generated/README.md).
|
|
46
|
+
|
|
47
|
+
The registered services on this branch are exactly `doctor`, `fs`, `gateway`,
|
|
48
|
+
`lab_admin`, `server_logs`, `setup`, and `snippets`. The older
|
|
49
|
+
`marketplace`/`stash`/`acp`/`nodes`/`deploy`/`logs`/`device` product services
|
|
50
|
+
were removed by the "Slim labby gateway host" pass; their domain types survive
|
|
51
|
+
in `labby-runtime`/`labby-apis` but are no longer registered services and have
|
|
52
|
+
no CLI commands. Use the generated catalogs below for the current surface
|
|
53
|
+
instead of copying command or action lists by hand.
|
|
54
|
+
|
|
55
|
+
## Quick Start
|
|
56
|
+
|
|
57
|
+
### Install A Release
|
|
58
|
+
|
|
59
|
+
Linux/macOS:
|
|
60
|
+
|
|
61
|
+
```bash
|
|
62
|
+
curl -fsSL https://raw.githubusercontent.com/dinglebear-ai/labby/main/scripts/install.sh | sh
|
|
63
|
+
labby setup
|
|
64
|
+
labby serve --host 127.0.0.1 --port 8765
|
|
65
|
+
```
|
|
66
|
+
|
|
67
|
+
MCP clients that prefer npm launchers can run Labby through the Node wrapper:
|
|
68
|
+
|
|
69
|
+
```bash
|
|
70
|
+
npx -y @dinglebear/labby mcp
|
|
71
|
+
```
|
|
72
|
+
|
|
73
|
+
Windows PowerShell:
|
|
74
|
+
|
|
75
|
+
```powershell
|
|
76
|
+
irm https://raw.githubusercontent.com/dinglebear-ai/labby/main/scripts/install.ps1 | iex
|
|
77
|
+
labby setup
|
|
78
|
+
labby serve --host 127.0.0.1 --port 8765
|
|
79
|
+
```
|
|
80
|
+
|
|
81
|
+
The install scripts download the requested GitHub Release asset, verify its
|
|
82
|
+
checksum, and install `labby` onto the user PATH. They do **not** perform
|
|
83
|
+
operator provisioning or environment setup. The scripts only install the binary
|
|
84
|
+
(from a release or fallback source build); all first-run provisioning is handled
|
|
85
|
+
inside `labby` via `labby serve` bootstrap and `labby setup`.
|
|
86
|
+
|
|
87
|
+
Override install behavior with `LABBY_INSTALL_DIR`, `LABBY_INSTALL_VERSION`, or
|
|
88
|
+
`LABBY_INSTALL_REPO`.
|
|
89
|
+
|
|
90
|
+
### Build From Source
|
|
91
|
+
|
|
92
|
+
Prerequisites:
|
|
93
|
+
|
|
94
|
+
- Rust 1.97.1 or newer. CI/release verifies with Rust 1.97.1.
|
|
95
|
+
- `just` for repo commands.
|
|
96
|
+
- `cargo-nextest` for the main test suite.
|
|
97
|
+
- `pnpm 9.15.9` for the Labby web UI. The repo pins this in
|
|
98
|
+
[.mise.toml](./.mise.toml) and
|
|
99
|
+
[apps/gateway-admin/package.json](./apps/gateway-admin/package.json).
|
|
100
|
+
- `openssl` if you want to generate a bearer token manually.
|
|
101
|
+
|
|
102
|
+
```bash
|
|
103
|
+
git clone git@github.com:dinglebear-ai/labby.git
|
|
104
|
+
cd labby
|
|
105
|
+
just install
|
|
106
|
+
just web-build
|
|
107
|
+
labby serve --host 127.0.0.1 --port 8765
|
|
108
|
+
```
|
|
109
|
+
|
|
110
|
+
`just install` builds the all-features release binary and symlinks it to
|
|
111
|
+
`~/.local/bin/labby`.
|
|
112
|
+
|
|
113
|
+
### First Run
|
|
114
|
+
|
|
115
|
+
For loopback development, `labby serve` can bootstrap a missing bearer token for
|
|
116
|
+
you. If `LABBY_MCP_HTTP_TOKEN` is absent and `LABBY_AUTH_MODE` is not `oauth`, it
|
|
117
|
+
generates a token, writes a minimal `~/.labby/.env`, reloads it into the running
|
|
118
|
+
process, prints the setup URL, and continues. The token itself is stored in
|
|
119
|
+
`~/.labby/.env` rather than printed.
|
|
120
|
+
|
|
121
|
+
Bootstrap writes these required `setup` keys if no env exists yet:
|
|
122
|
+
|
|
123
|
+
- `LABBY_MCP_HTTP_TOKEN` (generated random 64-character hex token)
|
|
124
|
+
- `LABBY_MCP_TRANSPORT=http`
|
|
125
|
+
- `LABBY_MCP_HTTP_HOST=127.0.0.1`
|
|
126
|
+
- `LABBY_MCP_HTTP_PORT=8765`
|
|
127
|
+
- `LABBY_AUTH_MODE=bearer`
|
|
128
|
+
|
|
129
|
+
It also enforces secure file creation via Lab's `env_merge` path (`0600` perms on
|
|
130
|
+
Unix) and then skips creating anything else until the web wizard runs.
|
|
131
|
+
|
|
132
|
+
For explicit setup:
|
|
133
|
+
|
|
134
|
+
```bash
|
|
135
|
+
mkdir -p ~/.labby
|
|
136
|
+
printf 'LABBY_AUTH_MODE=bearer\nLABBY_MCP_HTTP_TOKEN=%s\n' "$(openssl rand -hex 32)" > ~/.labby/.env
|
|
137
|
+
chmod 600 ~/.labby/.env
|
|
138
|
+
labby setup
|
|
139
|
+
labby serve --host 127.0.0.1 --port 8765
|
|
140
|
+
```
|
|
141
|
+
|
|
142
|
+
Open `http://127.0.0.1:8765/`.
|
|
143
|
+
Build static Labby assets with `just web-build` first when running from a source
|
|
144
|
+
checkout.
|
|
145
|
+
|
|
146
|
+
### Self-Host The Gateway
|
|
147
|
+
|
|
148
|
+
The recommended self-hosted gateway substrate is an amd64 Ubuntu 24.04 Incus
|
|
149
|
+
system container. Bare metal is the secondary supported shape for a dedicated
|
|
150
|
+
gateway host or VM. Docker is retained for explicit development/image smoke,
|
|
151
|
+
but it is not the recommended production boundary for Labby because stdio MCP
|
|
152
|
+
servers and agent CLIs are installed and launched at runtime.
|
|
153
|
+
|
|
154
|
+
```bash
|
|
155
|
+
scripts/incus-bootstrap.sh --version vX.Y.Z
|
|
156
|
+
incus exec labby -- systemctl status labby --no-pager
|
|
157
|
+
incus exec labby -- curl -fsS http://127.0.0.1:8765/ready
|
|
158
|
+
```
|
|
159
|
+
|
|
160
|
+
See [docs/runtime/INCUS.md](./docs/runtime/INCUS.md) for the full Incus
|
|
161
|
+
runbook, bare-metal variant, `/dev/net/tun` Tailscale passthrough, manual
|
|
162
|
+
`claude`/`codex`/`gemini` login checklist, and rollback commands.
|
|
163
|
+
|
|
164
|
+
## Core Workflows
|
|
165
|
+
|
|
166
|
+
### Start Labby
|
|
167
|
+
|
|
168
|
+
```bash
|
|
169
|
+
labby serve --host 127.0.0.1 --port 8765
|
|
170
|
+
labby mcp
|
|
171
|
+
```
|
|
172
|
+
|
|
173
|
+
`labby serve` starts the hosted HTTP runtime: `/v1` product APIs, `/mcp`
|
|
174
|
+
streamable HTTP MCP, auth routes, OAuth relay endpoints, and static Labby web
|
|
175
|
+
assets when an export is available. `labby mcp` is the stdio MCP entrypoint for
|
|
176
|
+
local MCP clients.
|
|
177
|
+
|
|
178
|
+
### Manage Upstream MCP Gateways
|
|
179
|
+
|
|
180
|
+
```bash
|
|
181
|
+
labby gateway add \
|
|
182
|
+
--name github \
|
|
183
|
+
--url https://example.com/mcp \
|
|
184
|
+
--bearer-token-env GITHUB_MCP_TOKEN \
|
|
185
|
+
-y
|
|
186
|
+
|
|
187
|
+
labby gateway reload
|
|
188
|
+
labby gateway list
|
|
189
|
+
```
|
|
190
|
+
|
|
191
|
+
Stdio upstreams execute local commands when tested or reconciled, so gateway
|
|
192
|
+
tests and config mutations use the shared destructive-action confirmation gate.
|
|
193
|
+
The stdio spawn guard allows known runtimes such as `npx`, `uvx`, `docker`,
|
|
194
|
+
`node`, `python`, `python3`, `deno`, `pipx`, and `dnx`; customize it in
|
|
195
|
+
`[gateway]` inside `config.toml`.
|
|
196
|
+
|
|
197
|
+
### Use Code Mode
|
|
198
|
+
|
|
199
|
+
When `[code_mode].enabled = true`, Labby hides raw proxied upstream tools from MCP
|
|
200
|
+
`list_tools()` and exposes the canonical synthetic `codemode` tool.
|
|
201
|
+
|
|
202
|
+
```bash
|
|
203
|
+
labby gateway code status
|
|
204
|
+
labby gateway code enable
|
|
205
|
+
labby gateway code exec --code 'async () => tools.length'
|
|
206
|
+
```
|
|
207
|
+
|
|
208
|
+
MCP call shapes:
|
|
209
|
+
|
|
210
|
+
```json
|
|
211
|
+
{ "code": "async () => (await codemode.search(\"github issues\")).results" }
|
|
212
|
+
```
|
|
213
|
+
|
|
214
|
+
```json
|
|
215
|
+
{ "code": "async () => callTool(\"github::search_issues\", {\"query\":\"repo:dinglebear-ai/labby gateway\"})" }
|
|
216
|
+
```
|
|
217
|
+
|
|
218
|
+
```json
|
|
219
|
+
{ "code": "async () => codemode.run(\"gateway-summary\", {\"includeHealth\": true})" }
|
|
220
|
+
```
|
|
221
|
+
|
|
222
|
+
Code Mode can call exposed upstream MCP tools only. It cannot call Labby actions
|
|
223
|
+
from inside the sandbox.
|
|
224
|
+
|
|
225
|
+
### Work With Code Mode Snippets
|
|
226
|
+
|
|
227
|
+
```bash
|
|
228
|
+
labby snippets list
|
|
229
|
+
labby snippets get gateway-summary
|
|
230
|
+
labby snippets create --name my-snippet --file ./my-snippet.js
|
|
231
|
+
labby snippets validate my-snippet
|
|
232
|
+
labby snippets exec my-snippet
|
|
233
|
+
labby snippets test my-snippet
|
|
234
|
+
```
|
|
235
|
+
|
|
236
|
+
Snippets are stored per-user under `$LABBY_HOME` and executed through the
|
|
237
|
+
gateway Code Mode runner, so they can reach exposed upstream tools but not Lab
|
|
238
|
+
actions. The `snippets` service is gateway-gated: it is unavailable in builds
|
|
239
|
+
without the `gateway` feature.
|
|
240
|
+
|
|
241
|
+
### Audit Health And Logs
|
|
242
|
+
|
|
243
|
+
```bash
|
|
244
|
+
labby doctor # audit every configured service
|
|
245
|
+
labby doctor system # local env vars, Docker, disk, toolchain
|
|
246
|
+
labby doctor auth # auth/OAuth env vars, files, permissions
|
|
247
|
+
labby doctor proxy # public Lab and protected MCP proxy endpoints
|
|
248
|
+
labby doctor oauth-relay
|
|
249
|
+
labby health # lightweight liveness/readiness probe
|
|
250
|
+
labby logs # tail the active deployment's service journal
|
|
251
|
+
```
|
|
252
|
+
|
|
253
|
+
`labby doctor --json` is the CI-friendly form; the exit code reflects the worst
|
|
254
|
+
severity found.
|
|
255
|
+
|
|
256
|
+
> **Removed surfaces.** Earlier releases documented `labby marketplace`,
|
|
257
|
+
> `labby stash`, `labby nodes`, and `labby deploy`, along with ACP chat, the MCP
|
|
258
|
+
> Registry browser, and device/fleet runtimes. Those products have been deleted
|
|
259
|
+
> from source, manifests, packaging, and CI — not merely feature-gated.
|
|
260
|
+
> `scripts/check-retired-features.sh` guards against reintroduction, and the
|
|
261
|
+
> historical designs are archived under
|
|
262
|
+
> [docs/references/retired-labby](./docs/references/retired-labby/). Plugin
|
|
263
|
+
> marketplace assets now live in the separate
|
|
264
|
+
> [dendrite](https://github.com/dinglebear-ai/dendrite) repo.
|
|
265
|
+
|
|
266
|
+
### Drive The API
|
|
267
|
+
|
|
268
|
+
Generic action dispatch:
|
|
269
|
+
|
|
270
|
+
```bash
|
|
271
|
+
curl -s -X POST http://127.0.0.1:8765/v1/gateway \
|
|
272
|
+
-H "Authorization: Bearer $LABBY_MCP_HTTP_TOKEN" \
|
|
273
|
+
-H "Content-Type: application/json" \
|
|
274
|
+
-d '{"action":"gateway.list","params":{}}'
|
|
275
|
+
```
|
|
276
|
+
|
|
277
|
+
Dedicated product routes also exist for catalog discovery (`/v1/{service}/actions`),
|
|
278
|
+
setup, doctor, snippets, filesystem, server logs, gateway OAuth
|
|
279
|
+
(`/v1/gateway/oauth/*`), OAuth relay, auth allowlists (`/v1/auth/allowed-emails`),
|
|
280
|
+
`/v1/openapi`, and the browser session routes under `/auth/*`. See
|
|
281
|
+
[generated API routes](./docs/generated/api-routes.md) and
|
|
282
|
+
[OpenAPI](./docs/generated/openapi.json).
|
|
283
|
+
|
|
284
|
+
## Runtime Surfaces
|
|
285
|
+
|
|
286
|
+
| Surface | Entry Point | Notes |
|
|
287
|
+
| --- | --- | --- |
|
|
288
|
+
| CLI | `labby <command>` | Current commands are generated in [docs/generated/cli-help.md](./docs/generated/cli-help.md). Use `--json` for machine-readable output and `--color auto|plain|color` for human output styling. |
|
|
289
|
+
| MCP stdio | `labby mcp` | Local editor/desktop MCP clients. |
|
|
290
|
+
| MCP HTTP | `labby serve` plus `/mcp` | Streamable HTTP MCP with bearer or OAuth JWT auth. |
|
|
291
|
+
| HTTP API | `labby serve` plus `/v1/*` | Generic `POST /v1/{service}` action dispatch plus dedicated product routes. |
|
|
292
|
+
| Web UI | `labby serve` plus exported assets | Main routes are `/` (overview), `/gateways`, `/gateway`, `/snippets`, `/usage`, `/settings` (with `core`, `services`, `services/[service]`, `surfaces`, `features`, `doctor`, `extract`, `advanced` subpages), `/docs`, `/design-system`, and `/mcp/code-mode`. |
|
|
293
|
+
|
|
294
|
+
MCP service tools use the shared action shape:
|
|
295
|
+
|
|
296
|
+
```json
|
|
297
|
+
{
|
|
298
|
+
"action": "mcp.list",
|
|
299
|
+
"params": { "search": "postgres", "limit": 10 }
|
|
300
|
+
}
|
|
301
|
+
```
|
|
302
|
+
|
|
303
|
+
Every service tool also supports `help` and `schema` through the shared
|
|
304
|
+
dispatcher. Destructive MCP actions use elicitation when the client supports it;
|
|
305
|
+
headless clients pass `"confirm": true` inside `params`.
|
|
306
|
+
|
|
307
|
+
## Configuration
|
|
308
|
+
|
|
309
|
+
Configuration is split deliberately:
|
|
310
|
+
|
|
311
|
+
| Data | Location | Examples |
|
|
312
|
+
| --- | --- | --- |
|
|
313
|
+
| Secrets and endpoint values | `~/.labby/.env` | `LABBY_MCP_HTTP_TOKEN`, `LABBY_GOOGLE_CLIENT_SECRET`, upstream bearer token env values |
|
|
314
|
+
| Preferences | `config.toml` | transport, CORS, auth mode, workspace root, gateway spawn guard, and upstream behavior |
|
|
315
|
+
|
|
316
|
+
`config.toml` is searched in this order:
|
|
317
|
+
|
|
318
|
+
1. `./config.toml`
|
|
319
|
+
2. `~/.labby/config.toml`
|
|
320
|
+
3. `~/.config/labby/config.toml`
|
|
321
|
+
|
|
322
|
+
Startup loads the first `config.toml`, initializes tracing, then loads
|
|
323
|
+
`~/.labby/.env` and a CWD `.env` if present. Runtime precedence is:
|
|
324
|
+
|
|
325
|
+
1. CLI flags
|
|
326
|
+
2. Environment variables
|
|
327
|
+
3. `config.toml`
|
|
328
|
+
4. Built-in defaults
|
|
329
|
+
|
|
330
|
+
Useful environment variables:
|
|
331
|
+
|
|
332
|
+
| Variable | Purpose |
|
|
333
|
+
| --- | --- |
|
|
334
|
+
| `LABBY_MCP_HTTP_TOKEN` | Static bearer token for protected admin/API/MCP routes. |
|
|
335
|
+
| `LABBY_AUTH_MODE` | `bearer` or `oauth`. |
|
|
336
|
+
| `LABBY_PUBLIC_URL` | Public base URL for OAuth metadata, issuer/audience, callbacks, and allowed-host derivation. |
|
|
337
|
+
| `LABBY_GOOGLE_CLIENT_ID` / `LABBY_GOOGLE_CLIENT_SECRET` | Google OAuth credentials for OAuth mode. |
|
|
338
|
+
| `LABBY_AUTH_ADMIN_EMAIL` | Bootstrap admin email; required in OAuth mode. |
|
|
339
|
+
| `LABBY_OAUTH_ENCRYPTION_KEY` | Base64 32-byte key required for encrypted upstream OAuth credentials. Rotation requires reauthorizing affected upstreams. |
|
|
340
|
+
| `LABBY_WEB_ASSETS_DIR` | Override static Labby export directory. |
|
|
341
|
+
| `LABBY_WEB_UI_AUTH_DISABLED` | Development-only browser auth bypass. |
|
|
342
|
+
| `LABBY_LOG` / `LABBY_LOG_FORMAT` / `LABBY_LOG_COLOR` | Tracing filter, text/json format, and non-TTY color policy. |
|
|
343
|
+
| `LABBY_LOG_DIR` | Optional rolling JSON file log directory. |
|
|
344
|
+
| `LABBY_ACTOR_KEY_SECRET` | Stable secret for redacted actor correlation in logs. |
|
|
345
|
+
| `LABBY_ADMIN_ENABLED` | Runtime opt-in for the `lab_admin` tool. |
|
|
346
|
+
|
|
347
|
+
Bearer auth is an operator/admin shortcut for Lab routes. Public protected MCP
|
|
348
|
+
routes validate route-scoped Lab OAuth JWTs; do not treat `LABBY_MCP_HTTP_TOKEN` as
|
|
349
|
+
a public resource credential.
|
|
350
|
+
|
|
351
|
+
When driving the web UI with automation while OAuth is enabled, pass the bearer
|
|
352
|
+
token as a same-origin header. `/auth/session` recognizes that token and returns a
|
|
353
|
+
synthetic admin session:
|
|
354
|
+
|
|
355
|
+
```bash
|
|
356
|
+
TOKEN=$(awk -F= '/^LABBY_MCP_HTTP_TOKEN=/{print $2}' ~/.labby/.env)
|
|
357
|
+
agent-browser open http://127.0.0.1:8765/gateways \
|
|
358
|
+
--headers "{\"Authorization\":\"Bearer $TOKEN\"}"
|
|
359
|
+
```
|
|
360
|
+
|
|
361
|
+
See [runtime configuration](./docs/runtime/CONFIG.md),
|
|
362
|
+
[environment variables](./docs/runtime/ENV.md), and
|
|
363
|
+
[OAuth](./docs/runtime/OAUTH.md).
|
|
364
|
+
|
|
365
|
+
## Current Catalogs
|
|
366
|
+
|
|
367
|
+
Do not maintain action, feature, env, or coverage inventories by hand in this
|
|
368
|
+
README. The generated artifacts are authoritative for the current branch:
|
|
369
|
+
|
|
370
|
+
| Artifact | Purpose |
|
|
371
|
+
| --- | --- |
|
|
372
|
+
| [service-catalog.md](./docs/generated/service-catalog.md) | Registered services, exposure, features, categories, and surfaces. |
|
|
373
|
+
| [action-catalog.md](./docs/generated/action-catalog.md) | Per-service actions and destructive metadata. |
|
|
374
|
+
| [env-reference.md](./docs/generated/env-reference.md) | Env vars generated from service metadata. |
|
|
375
|
+
| [api-routes.md](./docs/generated/api-routes.md) | Mounted HTTP routes. |
|
|
376
|
+
| [openapi.json](./docs/generated/openapi.json) | OpenAPI 3.1 schema. |
|
|
377
|
+
| [feature-matrix.md](./docs/generated/feature-matrix.md) | Cargo feature invariants. |
|
|
378
|
+
| [mcp-help.md](./docs/generated/mcp-help.md) | MCP help projection. |
|
|
379
|
+
| [cli-help.md](./docs/generated/cli-help.md) | Clap command help snapshot. |
|
|
380
|
+
|
|
381
|
+
Refresh and verify them with:
|
|
382
|
+
|
|
383
|
+
```bash
|
|
384
|
+
just docs-generate
|
|
385
|
+
just docs-check
|
|
386
|
+
```
|
|
387
|
+
|
|
388
|
+
`docs-check` verifies generated-artifact freshness and invariants. It is not a
|
|
389
|
+
Markdown link checker, live health check, or onboarding policy audit.
|
|
390
|
+
|
|
391
|
+
## Architecture
|
|
392
|
+
|
|
393
|
+
The workspace has 11 members and uses Rust 2024, resolver 3, a single
|
|
394
|
+
`[workspace.package]` version, shared `[workspace.dependencies]`, and shared
|
|
395
|
+
`[workspace.lints]` (`unsafe_code = "forbid"`, `mod_module_files = "deny"`,
|
|
396
|
+
`disallowed_macros = "deny"`). The MCP SDK is pinned exactly as
|
|
397
|
+
`rmcp = "=3.1.0"`.
|
|
398
|
+
|
|
399
|
+
| Path | Role |
|
|
400
|
+
| --- | --- |
|
|
401
|
+
| [crates/labby-primitives](./crates/labby-primitives) | Dependency-free leaf crate: `ActionSpec`/`ParamSpec`, `PluginMeta`/`EnvVar`/`Category`, `UiSchema`, static SSRF checks. |
|
|
402
|
+
| [crates/labby-apis](./crates/labby-apis) | Shared SDK contracts for core HTTP behavior, setup, and doctor. |
|
|
403
|
+
| [crates/labby-auth](./crates/labby-auth) | OAuth/JWT/session middleware, route support, and upstream OAuth runtime. |
|
|
404
|
+
| [crates/labby-runtime](./crates/labby-runtime) | Surface-neutral contracts and helpers: `ToolError`, gateway config DTOs, dispatch helpers, redaction, path safety, and security helpers. |
|
|
405
|
+
| [crates/labby-codemode](./crates/labby-codemode) | Client-neutral Code Mode runner kernel, broker, result shaping, snippets, and TypeScript descriptor generation. |
|
|
406
|
+
| [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. |
|
|
407
|
+
| [crates/labby-openapi](./crates/labby-openapi) | OpenAPI 3.1 schema assembly for the HTTP surface. |
|
|
408
|
+
| [crates/labby-web](./crates/labby-web) | Embedded/filesystem web asset serving with symlink escape defense. |
|
|
409
|
+
| [crates/labby](./crates/labby) | Product binary crate: CLI, MCP, HTTP API, config loading, gateway dispatch, logs, setup, snippets, filesystem access, and output rendering. |
|
|
410
|
+
| [crates/labby-winjob](./crates/labby-winjob) | Windows Job Object process-tree support, isolated so the main workspace can keep `unsafe_code = "forbid"`. |
|
|
411
|
+
| [crates/xtask](./crates/xtask) | Repo automation tasks; not published. |
|
|
412
|
+
| [apps/gateway-admin](./apps/gateway-admin/README.md) | Labby web UI, statically exported and served by `labby serve`. |
|
|
413
|
+
| [packages/labby-mcp](./packages/labby-mcp) | npm launcher wrapper behind `npx -y @dinglebear/labby mcp`. |
|
|
414
|
+
| [plugins](./plugins) | Claude/Codex plugin assets and skills. |
|
|
415
|
+
| [docs](./docs/README.md) | Topic documentation and generated inventories. |
|
|
416
|
+
|
|
417
|
+
Shared behavior belongs in the shared execution layer. Upstream/domain logic
|
|
418
|
+
belongs in `labby-apis`; reusable gateway/runtime/code-mode behavior belongs in
|
|
419
|
+
the extracted `labby-*` crates; product dispatch belongs in
|
|
420
|
+
`crates/labby/src/dispatch`; CLI, MCP, HTTP, and web adapters stay thin. See
|
|
421
|
+
[Architecture](./docs/ARCH.md) and [Dispatch](./docs/dev/DISPATCH.md).
|
|
422
|
+
|
|
423
|
+
## Development
|
|
424
|
+
|
|
425
|
+
Prefer the `just` aliases:
|
|
426
|
+
|
|
427
|
+
```bash
|
|
428
|
+
just check # cargo check --workspace --all-features
|
|
429
|
+
just test # cargo nextest run --workspace --all-features
|
|
430
|
+
just test-integration # cargo nextest run --workspace --all-features --run-ignored ignored-only
|
|
431
|
+
just lint # skill drift + cargo wrapper smoke + clippy -D warnings + fmt check
|
|
432
|
+
just deny # cargo deny check
|
|
433
|
+
just build # cargo build --workspace --all-features
|
|
434
|
+
just build-release # release build, bin/labby install, ~/.local/bin symlink
|
|
435
|
+
labby setup host-service install --install-self -y # install current binary + start system service
|
|
436
|
+
labby setup host-service restart --install-self -y # reinstall current binary + restart service
|
|
437
|
+
labby setup host-service status --json # inspect the host Labby gateway service
|
|
438
|
+
just host-sync # repo dev shortcut: rebuild + install binary + restart host service
|
|
439
|
+
just dev-container # explicit Docker compatibility/prod-like smoke path
|
|
440
|
+
just dev-container-debug # explicit Docker debug binary path
|
|
441
|
+
just web-build # cd apps/gateway-admin && pnpm build
|
|
442
|
+
just web-watch # rebuild web assets when frontend files change
|
|
443
|
+
just run -- help # cargo run --all-features -- <args>
|
|
444
|
+
just chat-local # local Labby admin UI workflow with browser auth disabled
|
|
445
|
+
just dev-up # start the explicit Docker compatibility stack
|
|
446
|
+
just dev # alias for just dev-container
|
|
447
|
+
just dev-debug # alias for just dev-container-debug
|
|
448
|
+
just install # build-release + symlink ~/.local/bin/labby
|
|
449
|
+
just prod-run # local prod-like image smoke on port 18765
|
|
450
|
+
just mcp-token # rotate LABBY_MCP_HTTP_TOKEN in .env
|
|
451
|
+
```
|
|
452
|
+
|
|
453
|
+
Authoritative Rust verification is all-features:
|
|
454
|
+
|
|
455
|
+
```bash
|
|
456
|
+
cargo check --workspace --all-features
|
|
457
|
+
cargo clippy --workspace --all-features -- -D warnings
|
|
458
|
+
cargo nextest run --workspace --all-features
|
|
459
|
+
cargo build --workspace --all-features
|
|
460
|
+
```
|
|
461
|
+
|
|
462
|
+
CI uses the same posture and runs nextest with its CI profile. Use `cargo test`
|
|
463
|
+
only for narrow local slices or when a tool specifically requires it.
|
|
464
|
+
|
|
465
|
+
Frontend changes should also run the relevant `pnpm` scripts under
|
|
466
|
+
`apps/gateway-admin`, and `just web-build` when exported assets matter.
|
|
467
|
+
|
|
468
|
+
### Host Gateway Runtime
|
|
469
|
+
|
|
470
|
+
The recommended self-hosted gateway runtime is the Incus system container
|
|
471
|
+
provisioned by `scripts/incus-bootstrap.sh --version vX.Y.Z` and converged
|
|
472
|
+
in-box with `labby setup --provision`. Bare metal uses the same provisioner and
|
|
473
|
+
system unit when the host or VM is dedicated to Labby. The default service is
|
|
474
|
+
`/etc/systemd/system/labby.service`, running as `User=labby`, `Group=labby`, with
|
|
475
|
+
`ExecStart=/usr/local/bin/labby serve`. From a source checkout, `just host-sync`
|
|
476
|
+
remains the rebuild-and-restart developer shortcut. Docker remains available
|
|
477
|
+
for prod-like image smoke and adapter-container work, but it is no longer the
|
|
478
|
+
recommended agent gateway runtime.
|
|
479
|
+
|
|
480
|
+
### Dev Container
|
|
481
|
+
|
|
482
|
+
The Compose stack is a trusted local operator environment, not a hardened
|
|
483
|
+
generic deployment. It bind-mounts Labby state, the repository, and built web
|
|
484
|
+
assets; secrets are loaded from the mounted `/home/labby/.labby/.env`. The image
|
|
485
|
+
installs pinned Claude, Codex, and Gemini CLIs for stdio upstreams that invoke
|
|
486
|
+
provider tools. It does not install ACP adapters or mount ACP-specific state.
|
|
487
|
+
|
|
488
|
+
### Releases
|
|
489
|
+
|
|
490
|
+
Release Please maintains the version/changelog pull request and creates the
|
|
491
|
+
stable tag plus draft GitHub release when that pull request merges. Publishing
|
|
492
|
+
the release triggers the heavy GitHub-hosted x86_64 workflows. They build Linux
|
|
493
|
+
and Windows archives with checksums, build and scan the GHCR image, build and
|
|
494
|
+
smoke the Incus image, publish the npm launcher, and publish Labby's
|
|
495
|
+
`server.json` metadata to the official MCP Registry.
|
|
496
|
+
|
|
497
|
+
### Plugin Setup
|
|
498
|
+
|
|
499
|
+
The `plugins/labby` plugin ships skills, an MCP config, and `userConfig` — not a
|
|
500
|
+
`labby` binary, and no Claude Code hooks. The former
|
|
501
|
+
`plugins/labby/hooks/hooks.json` (SessionStart / ConfigChange shims) has been
|
|
502
|
+
removed; operators run `labby setup` themselves. Do not reintroduce a `hooks/`
|
|
503
|
+
directory, bundle a binary under `plugins/labby/bin/`, or add
|
|
504
|
+
Docker/systemd bootstrap logic to plugin assets.
|
|
505
|
+
|
|
506
|
+
`labby setup plugin-hook` remains a CLI command for on-demand audit and settings
|
|
507
|
+
sync (`--no-repair` for read-only), exercised by `just validate-plugin`.
|
|
508
|
+
|
|
509
|
+
## Related Servers
|
|
510
|
+
|
|
511
|
+
- [soma](https://github.com/dinglebear-ai/soma) - RMCP runtime for provider-backed MCP servers.
|
|
512
|
+
- [unifi-rmcp](https://github.com/dinglebear-ai/runifi) - UniFi controller REST API bridge.
|
|
513
|
+
- [tailscale-rmcp](https://github.com/dinglebear-ai/rtailscale) - Tailscale API bridge for devices, users, and tailnet operations.
|
|
514
|
+
- [unraid](https://github.com/dinglebear-ai/unraid) - Unraid monorepo; the Rust GraphQL bridge (`runraid`) lives in `unraid-rs/`.
|
|
515
|
+
- [apprise-rmcp](https://github.com/dinglebear-ai/rapprise) - Apprise notification fan-out bridge for many delivery backends.
|
|
516
|
+
- [gotify-rmcp](https://github.com/dinglebear-ai/rgotify) - Gotify push notification bridge for sends, messages, apps, and clients.
|
|
517
|
+
- [arcane-rmcp](https://github.com/dinglebear-ai/rarcane) - Arcane Docker management bridge for containers and related resources.
|
|
518
|
+
- [ytdl-rmcp](https://github.com/dinglebear-ai/rytdl) - Media download and metadata workflow server.
|
|
519
|
+
- [synapse-rmcp](https://github.com/dinglebear-ai/synapse) - Local Synapse workflow server for scout and flux actions.
|
|
520
|
+
- [cortex](https://github.com/dinglebear-ai/cortex) - Syslog and homelab log aggregation MCP server.
|
|
521
|
+
- [axon](https://github.com/dinglebear-ai/axon) - RAG, crawl, scrape, extract, and semantic search project.
|
|
522
|
+
- [lumen](https://github.com/dinglebear-ai/lumen) - Local semantic code search MCP server.
|
|
523
|
+
|
|
524
|
+
## Documentation
|
|
525
|
+
|
|
526
|
+
Start at [docs/README.md](./docs/README.md). High-value entrypoints:
|
|
527
|
+
|
|
528
|
+
- [Architecture](./docs/ARCH.md)
|
|
529
|
+
- [Configuration](./docs/runtime/CONFIG.md)
|
|
530
|
+
- [Environment](./docs/runtime/ENV.md)
|
|
531
|
+
- [OAuth](./docs/runtime/OAUTH.md)
|
|
532
|
+
- [Transport](./docs/surfaces/TRANSPORT.md)
|
|
533
|
+
- [Gateway](./docs/services/GATEWAY.md)
|
|
534
|
+
- [Setup](./docs/services/SETUP.md)
|
|
535
|
+
- [Server Logs](./docs/services/SERVER_LOGS.md)
|
|
536
|
+
- [Testing](./docs/dev/TESTING.md)
|
|
537
|
+
- [Operations](./docs/OPERATIONS.md)
|
|
538
|
+
|
|
539
|
+
## License
|
|
540
|
+
|
|
541
|
+
Workspace metadata declares `MIT OR Apache-2.0`.
|
package/bin/labby.js
ADDED
|
@@ -0,0 +1,34 @@
|
|
|
1
|
+
#!/usr/bin/env node
|
|
2
|
+
"use strict";
|
|
3
|
+
|
|
4
|
+
const fs = require("node:fs");
|
|
5
|
+
const path = require("node:path");
|
|
6
|
+
const { spawnSync } = require("node:child_process");
|
|
7
|
+
const { binaryPath } = require("../lib/platform");
|
|
8
|
+
|
|
9
|
+
function fail(message) {
|
|
10
|
+
process.stderr.write(`labby: ${message}\n`);
|
|
11
|
+
process.exit(1);
|
|
12
|
+
}
|
|
13
|
+
|
|
14
|
+
const binary = binaryPath();
|
|
15
|
+
|
|
16
|
+
if (!fs.existsSync(binary)) {
|
|
17
|
+
const installer = path.resolve(__dirname, "..", "scripts", "install.js");
|
|
18
|
+
const install = spawnSync(process.execPath, [installer], { stdio: "inherit" });
|
|
19
|
+
if (install.status !== 0) {
|
|
20
|
+
fail("binary is not installed; postinstall may have failed");
|
|
21
|
+
}
|
|
22
|
+
}
|
|
23
|
+
|
|
24
|
+
const child = spawnSync(binary, process.argv.slice(2), { stdio: "inherit" });
|
|
25
|
+
|
|
26
|
+
if (child.error) {
|
|
27
|
+
fail(child.error.message);
|
|
28
|
+
}
|
|
29
|
+
|
|
30
|
+
if (child.signal) {
|
|
31
|
+
process.kill(process.pid, child.signal);
|
|
32
|
+
} else {
|
|
33
|
+
process.exit(child.status ?? 1);
|
|
34
|
+
}
|
package/lib/platform.js
ADDED
|
@@ -0,0 +1,60 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
|
|
3
|
+
const path = require("node:path");
|
|
4
|
+
|
|
5
|
+
function packageVersion() {
|
|
6
|
+
return require("../package.json").version;
|
|
7
|
+
}
|
|
8
|
+
|
|
9
|
+
function targetFor(platform = process.platform, arch = process.arch) {
|
|
10
|
+
if (platform === "linux" && arch === "x64") {
|
|
11
|
+
return {
|
|
12
|
+
asset: "lab-x86_64-unknown-linux-gnu.tar.gz",
|
|
13
|
+
binary: "labby",
|
|
14
|
+
archiveType: "tar.gz",
|
|
15
|
+
};
|
|
16
|
+
}
|
|
17
|
+
|
|
18
|
+
if (platform === "win32" && arch === "x64") {
|
|
19
|
+
return {
|
|
20
|
+
asset: "lab-x86_64-pc-windows-msvc.zip",
|
|
21
|
+
binary: "labby.exe",
|
|
22
|
+
archiveType: "zip",
|
|
23
|
+
};
|
|
24
|
+
}
|
|
25
|
+
|
|
26
|
+
throw new Error(`Unsupported platform ${platform}/${arch}. Supported targets: linux/x64, win32/x64.`);
|
|
27
|
+
}
|
|
28
|
+
|
|
29
|
+
function releaseVersion(env = process.env) {
|
|
30
|
+
const raw = env.LABBY_VERSION || env.LABBY_BINARY_VERSION || packageVersion();
|
|
31
|
+
return raw.startsWith("v") ? raw : `v${raw}`;
|
|
32
|
+
}
|
|
33
|
+
|
|
34
|
+
function releaseBaseUrl(env = process.env) {
|
|
35
|
+
const repo = env.LABBY_REPO || "dinglebear-ai/labby";
|
|
36
|
+
return env.LABBY_RELEASE_BASE_URL || `https://github.com/${repo}/releases/download`;
|
|
37
|
+
}
|
|
38
|
+
|
|
39
|
+
function downloadUrl(target, env = process.env) {
|
|
40
|
+
return `${releaseBaseUrl(env)}/${releaseVersion(env)}/${target.asset}`;
|
|
41
|
+
}
|
|
42
|
+
|
|
43
|
+
function installRoot() {
|
|
44
|
+
return path.resolve(__dirname, "..", "vendor");
|
|
45
|
+
}
|
|
46
|
+
|
|
47
|
+
function binaryPath(platform = process.platform, arch = process.arch) {
|
|
48
|
+
const target = targetFor(platform, arch);
|
|
49
|
+
return path.join(installRoot(), target.binary);
|
|
50
|
+
}
|
|
51
|
+
|
|
52
|
+
module.exports = {
|
|
53
|
+
binaryPath,
|
|
54
|
+
downloadUrl,
|
|
55
|
+
installRoot,
|
|
56
|
+
packageVersion,
|
|
57
|
+
releaseBaseUrl,
|
|
58
|
+
releaseVersion,
|
|
59
|
+
targetFor,
|
|
60
|
+
};
|