@lllanyard/cli 0.1.0 → 0.1.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (2) hide show
  1. package/README.md +22 -56
  2. package/package.json +4 -4
package/README.md CHANGED
@@ -34,9 +34,9 @@ export OPENAI_BASE_URL=http://127.0.0.1:3000/openai/v1
34
34
  export OPENAI_API_KEY=lly_...
35
35
  ```
36
36
 
37
- Compatibility notes (verify against each tool's own docs):
38
- - Claude Code reads its base URL and key from these environment variables; if `ANTHROPIC_AUTH_TOKEN` is also set it may take precedence, so unset it. Only API-key mode is proxied, not subscription logins. The Claude Desktop app reportedly ignores these variables; for Desktop (and subscription use generally) see [Claude Desktop](#3-claude-desktop-and-subscription-chat-apps) below.
39
- - Cursor makes some model calls from its own servers, so a localhost base URL may not work there. Test before promising support.
37
+ Compatibility notes:
38
+ - Claude Code reads its base URL and key from these environment variables; if `ANTHROPIC_AUTH_TOKEN` is also set it may take precedence, so unset it. Only API-key mode is proxied, not subscription logins. The Claude Desktop app ignores these variables; for Desktop (and subscription use generally) see [Claude Desktop](#3-claude-desktop-and-subscription-chat-apps) below.
39
+ - Cursor makes some model calls from its own servers, so a localhost base URL may not work there.
40
40
 
41
41
  ## Commands
42
42
 
@@ -47,7 +47,7 @@ Compatibility notes (verify against each tool's own docs):
47
47
  | `exec <command> [args…]` | Run a script with the keys it uses: `lllanyard exec pwsh -File ./Onboard-Client.ps1 -DryRun`. LLLanyard reads the script, and the helper files it loads (quoted paths, `source`/`.` lines, Python imports), for your keys' variable names and passes only those, for that run only. Keys in the output are redacted; each run is logged and shown by `usage`. `exec --keys trmm,itflow -- <command>` names the keys yourself (needed for programs that aren't scripts). Run from a terminal, the script gets a real terminal of its own (prompts like `Read-Host`, colours and window size work) on macOS, Linux and Windows, and its output is still redacted. |
48
48
  | `list`, `remove`, `rotate`, `status` | Manage keys; `status` shows rotation due dates and exits 1 if anything is overdue (cron/CI friendly). |
49
49
  | `agent create <name> [--client N] [--providers a,b]` / `list` / `revoke` | Placeholder tokens. `--client acme` pins an agent to the `acme` key; `--providers` limits which APIs it may reach (least privilege). |
50
- | `provider add <id> --upstream https://… [--auth bearer\|header --header NAME --prefix TXT]` / `list` / `remove` | Teach the proxy a new API host (GitHub, Slack, your own service). Built-ins: openai, anthropic, gemini, openrouter, github, slack, stripe, notion (confirm each against the vendor's docs). |
50
+ | `provider add <id> --upstream https://… [--auth bearer\|header --header NAME --prefix TXT]` / `list` / `remove` | Teach the proxy a new API host (GitHub, Slack, your own service). Built-ins: openai, anthropic, gemini, openrouter, github, slack, stripe, notion. |
51
51
  | `tool add <name> --env VAR=provider[:label] [--allow-host H] [--kill-on-leak] [--pass-env V] [--inherit-env] [--no-scrub] -- <command> [args…]` / `list` / `remove` | Approve a command (e.g. an MCP server) to receive keys as environment variables, with the safeguards below. |
52
52
  | `run <name> [-- args…]` | Run an approved tool with its keys injected and scrubbed from its output. Extra args are appended only if the tool was approved with `--allow-args`. For script tools (python, node, sh, pwsh…) the script file is pinned by hash at approval and `run` refuses if it has changed since; `--allow-args` is refused for bare interpreters (`python3 -c`, `-m`) and launchers (`env`, `xargs`, `sudo`, `npx`). `run --env … -- <cmd>` is a one-off that needs a human to confirm at a terminal. |
53
53
  | `scan [paths] [--import --apply [--redact]]` | Find plaintext keys in `.env` files, MCP/IDE configs and shell profiles, then move them into the keychain. Dry run unless `--apply`. |
@@ -155,11 +155,9 @@ lllanyard doctor # reports whether a sandbox works on this machine
155
155
  - Run it from the project folder: only the current directory is writable, and running from your home directory is refused.
156
156
  Credential folders (`~/.ssh`, `~/.aws`, `~/.gnupg`, ...) cannot be shared even with `--share-ro/--share-rw`.
157
157
  - Linux needs `sudo apt install bubblewrap`. Ubuntu 24.04+ restricts unprivileged user namespaces; `doctor` explains the fix.
158
- - **Windows:** no sandbox yet. Use WSL2 (Debian/Ubuntu) to get the Linux one. Docker mode is on the roadmap.
159
- - **Verification status:** the argument/profile generation, mount safety, fail-closed behaviour and the egress bridge are
160
- unit-tested, and a test proves in a real Linux network namespace that a process has no route to the host or internet and
161
- can reach only allowlisted hosts through the bridge. **Not yet run against a real `bwrap` or on macOS** (neither was
162
- available where this was built). Treat the first release as beta on those paths and run `lllanyard doctor` first.
158
+ - **Windows:** no sandbox. Use WSL2 (Debian/Ubuntu) to get the Linux one.
159
+ - **Beta.** The sandbox is tested in CI on Linux and macOS, but it is the newest part of LLLanyard. Run `lllanyard doctor`
160
+ first.
163
161
 
164
162
  Honest limits:
165
163
 
@@ -183,7 +181,7 @@ git; prompt-injected agents echoing their "key" (it is only a placeholder); runa
183
181
 
184
182
  **Does NOT protect against:** malicious code running *as your OS user*. A fully compromised agent that can run shell
185
183
  commands can ask the OS keychain for the key directly (macOS prompts; Windows and Linux generally do not). For
186
- untrusted agents, run the proxy under a separate OS user or on another machine (the planned self-hosted shared proxy).
184
+ untrusted agents, run the proxy under a separate OS user or on another machine (see [Sharing with a team](#sharing-with-a-team-pro)).
187
185
 
188
186
  Built-in hardening:
189
187
  - Zero runtime dependencies in the proxy (Node built-ins only); the only native dependency is `@napi-rs/keyring`.
@@ -211,10 +209,10 @@ Keys that sat in plaintext should be treated as exposed: after `scan --import`,
211
209
  - **Debian/Ubuntu:** needs a Secret Service: `sudo apt install gnome-keyring libsecret-1-0`, inside a desktop/D-Bus session.
212
210
  Headless servers are not supported yet.
213
211
 
214
- ## Tiers (planned)
212
+ ## Tiers
215
213
 
216
- Free: up to 10 keys, local only. Pro: shared directories via a self-hosted shared proxy (keys stay on the host's keychain)
217
- and later an end-to-end-encrypted cloud option, plus dashboard, rotation assistant and local-LLM helper.
214
+ Free: up to 10 keys and 5 agent tokens, local only. Pro and Team ([pricing](https://lllanyard.app/pricing)) raise the key
215
+ limit and add the shared proxy for a team and the usage dashboard.
218
216
 
219
217
  ### Desktop app and rotation assistant
220
218
 
@@ -231,7 +229,6 @@ tokens, usage, proxy start/stop, license, and the **rotation assistant**.
231
229
  nonce. All text is inserted with `textContent`, never as HTML.
232
230
  - Honest limits: any program running as your user could still read the session secret from the process list or the printed
233
231
  link, as it could read your keychain; this protects against web pages and other websites, not against local malware.
234
- The Tauri shell has not been compiled yet (see `apps/desktop/README.md`).
235
232
 
236
233
  ### MCP server for agents
237
234
 
@@ -267,7 +264,7 @@ Teammates point their tools at `https://keys.example.com:3443/openai/v1` and use
267
264
  | Per-person scope | Each token is limited to a client (`--client`), optionally to providers, and can expire (`--expires`) |
268
265
  | Audit trail | Every request is logged with agent name and caller address; `lllanyard usage` breaks it down by agent and client |
269
266
  | Rate limits + kill switch | Per token, as before |
270
- | Seats | Free: 5 agent tokens. Licensed: 3 tokens per seat (`AGENTS_PER_SEAT`, a pricing hypothesis) |
267
+ | Seats | Free: 5 agent tokens. Licensed: 3 tokens per seat |
271
268
 
272
269
  Put it behind a VPN (Tailscale, WireGuard) or a firewall if you can; the lockout and TLS are a second layer, not a reason to
273
270
  expose it to the whole internet. `X-Forwarded-For` is deliberately ignored, so a reverse proxy in front shows as one address.
@@ -285,8 +282,8 @@ lllanyard add openai --stdin < key.txt && lllanyard serve --host 0.0.0.0 ...
285
282
 
286
283
  On a terminal with no passphrase file you are prompted instead (hidden). Under systemd use `LoadCredential=` and point
287
284
  `LLLANYARD_VAULT_PASSPHRASE_FILE` at `$CREDENTIALS_DIRECTORY/pass`. Honest limit: it protects the vault at rest (backups,
288
- disk images, other users); someone who can read both the vault and the passphrase file as your user can open it. For
289
- stronger custody use a cloud KMS or a hardware token, a later step. Changing the passphrase is not implemented yet.
285
+ disk images, other users); someone who can read both the vault and the passphrase file as your user can open it. The
286
+ passphrase can't be changed once the vault is created.
290
287
 
291
288
  ### Usage and dashboard
292
289
 
@@ -316,13 +313,8 @@ this off; each renewed key is also emailed.
316
313
  Pro lifts the key cap to 250, Team to 500 (`TIER_LIMITS` in `packages/core/src/license.ts`). An expired license drops
317
314
  back to free: existing keys keep working, you just can't add past the free cap.
318
315
 
319
- **Vendor setup (once):** `node tools/issue-license.mjs gen-keys ~/lly-keys` creates a keypair; paste the public key into
320
- `LICENSE_PUBLIC_KEY`, keep the private key offline. Issue a customer license with
321
- `node tools/issue-license.mjs issue --key ~/lly-keys/license-private.pem --tier pro --days 365 --sub order-123`.
322
- Until `LICENSE_PUBLIC_KEY` is set, no license validates.
323
-
324
- **Honest limit:** a local check can be patched in private. The BSL license (see License) forbids it and makes such use
325
- unlicensed, but the features worth paying for (shared proxy, cloud sync) should also live where a local patch can't reach.
316
+ **Honest limit:** a local check can be patched in private. The license (see License) forbids it and makes such use
317
+ unlicensed.
326
318
 
327
319
  ## License
328
320
 
@@ -337,42 +329,16 @@ In plain words (the license text is what counts):
337
329
  - You may not resell it as a hosted/embedded competing product.
338
330
  - Each version converts to Apache 2.0 four years after its release.
339
331
 
340
- The Business Source License is a *licence*, not technical protection: it makes patching out the checks a breach (a legal and
341
- commercial remedy), but cannot physically stop someone doing it in private. Keep the genuinely valuable features (shared
342
- proxy operations, cloud sync, support, updates) where only you can provide them.
343
-
344
- Before publishing: fill in the licensing contact email in `LICENSE.md`, and have a lawyer review the **Additional Use Grant**
345
- (it is my drafting, not boilerplate) and the Change License choice. The BSL body text was taken from a published BSL 1.1 copy
346
- (HashiCorp's) because the official page was unreachable; compare it with mariadb.com/bsl11, which also includes a
347
- "Covenants of Licensor" section you should keep if you use the name "Business Source License". PolyForm Shield and
348
- Noncommercial texts remain in `docs/license-options/` as alternatives; note Shield does **not** forbid patching out checks.
332
+ Licensing questions: sales@lllanyard.co.uk.
349
333
 
350
334
  ## Verifying on your machine
351
335
 
352
336
  `node tools/smoke.mjs` (add `--keychain` to also test your real OS keychain once) runs the real CLI, proxy, UI and MCP server
353
- against a throwaway vault and prints PASS/FAIL plus a one-line report for bug reports. See `RELEASING.md` for the full
354
- pre-launch checklist.
337
+ against a throwaway vault and prints PASS/FAIL plus a one-line report for bug reports.
355
338
 
356
339
  ## Tests
357
340
 
358
- `npm test` (tsx + node:test, 109 tests): storage, tokens, scanner/redaction, rotation, provider and tool validation, the output
359
- scrubber (split chunks, base64/hex/URL forms), the `run` engine with real child processes (minimal environment, leak warning
360
- and kill, egress wiring), the egress proxy (allow/deny, auth, private-address blocking), and 15 proxy integration tests
361
- against a fake upstream (key injection, SSE streaming, redirects, Host/Origin checks, path tricks, rate limit, SSRF guard,
362
- agent scoping, log hygiene). A manual end-to-end pass of the CLI, a custom provider and the live proxy also succeeded using
363
- a file-backed stand-in for the keychain.
364
- CI (`.github/workflows/ci.yml`) runs the suite on Linux, macOS and Windows with Node 22 and 24, installs bubblewrap on Linux so
365
- the real-sandbox test runs, and does a full type-check and `npm audit`. Not covered locally: real keychains on each OS, real provider endpoints, and the Windows shell path for `npx` (logic is unit-tested
366
- with a simulated platform, not on Windows).
367
-
368
- ## Roadmap
369
-
370
- 1. Compile and sign the Tauri app; bundle Node as a sidecar so no separate install is needed.
371
- 2. E2E-encrypted cloud sync; vault passphrase change; KMS/hardware-token vault backends.
372
- 3. Docker sandbox mode (Windows).
373
- 4. Auto-rotation via provider admin APIs. Honeytoken keys need a hosted callback service, so they belong in a paid cloud tier.
374
-
375
- ## Naming
376
-
377
- The name is a placeholder pending a trademark check. To rename: edit `packages/core/src/constants.ts` and the `@lllanyard`
378
- package scope. Changing `SERVICE` orphans keys already stored under the old name.
341
+ `npm test` runs the suite (tsx + node:test): storage, tokens, scanner and redaction, rotation, provider and tool validation,
342
+ the output scrubber, the `run` engine with real child processes, the egress proxy, the sandbox, and proxy integration tests
343
+ against a fake upstream. CI (`.github/workflows/ci.yml`) runs it on Linux, macOS and Windows with Node 22 and 24, with a full
344
+ type-check and `npm audit`.
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@lllanyard/cli",
3
- "version": "0.1.0",
3
+ "version": "0.1.1",
4
4
  "description": "Keep API keys out of AI agents: keys live in your OS keychain and agents only see placeholder tokens.",
5
5
  "type": "module",
6
6
  "bin": {
@@ -10,9 +10,9 @@
10
10
  "dist"
11
11
  ],
12
12
  "dependencies": {
13
- "@lllanyard/core": "^0.1.0",
14
- "@lllanyard/proxy": "^0.1.0",
15
- "@lllanyard/ui": "^0.1.0"
13
+ "@lllanyard/core": "^0.1.1",
14
+ "@lllanyard/proxy": "^0.1.1",
15
+ "@lllanyard/ui": "^0.1.1"
16
16
  },
17
17
  "license": "BUSL-1.1",
18
18
  "engines": {