@letterblack/lbe-core 1.3.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.
Files changed (79) hide show
  1. package/.githooks/pre-commit +2 -0
  2. package/.githooks/pre-push +2 -0
  3. package/CHANGELOG.md +57 -0
  4. package/LICENSE +1 -0
  5. package/README.md +506 -0
  6. package/Release-README.md +339 -0
  7. package/WORKSPACE.md +422 -0
  8. package/_proof.mjs +246 -0
  9. package/assets/lbe-gates.jpg +0 -0
  10. package/assets/lbe-gates.png +0 -0
  11. package/assets/runtime-boundary.svg +36 -0
  12. package/assets/story-allow.jpg +0 -0
  13. package/assets/story-allow.png +0 -0
  14. package/assets/story-deny.jpg +0 -0
  15. package/assets/story-deny.png +0 -0
  16. package/bin/lbe.js +12 -0
  17. package/config/identity.config.json +3 -0
  18. package/config/policy.default.json +24 -0
  19. package/dist/cli/lbe.js +4274 -0
  20. package/dist/hooks/register.cjs +505 -0
  21. package/dist/state/appendCentral.cjs +87 -0
  22. package/dist/state/index.cjs +101 -0
  23. package/exec/cli.js +472 -0
  24. package/exec/index.js +2 -0
  25. package/index.js +24 -0
  26. package/lbe.audit.jsonl +46 -0
  27. package/package.json +76 -0
  28. package/release/README.md +216 -0
  29. package/release/TRUST.md +90 -0
  30. package/release/exec-README.md +215 -0
  31. package/release/exec-types.d.ts +50 -0
  32. package/release-exec/LICENSE +1 -0
  33. package/release-exec/README.md +215 -0
  34. package/release-exec/assets/lbe-gates.jpg +0 -0
  35. package/release-exec/assets/lbe-gates.png +0 -0
  36. package/release-exec/assets/runtime-boundary.svg +36 -0
  37. package/release-exec/assets/story-allow.jpg +0 -0
  38. package/release-exec/assets/story-allow.png +0 -0
  39. package/release-exec/assets/story-deny.jpg +0 -0
  40. package/release-exec/assets/story-deny.png +0 -0
  41. package/release-exec/dist/cli.js +2841 -0
  42. package/release-exec/dist/index.js +1835 -0
  43. package/release-exec/dist/lbe_engine.wasm +0 -0
  44. package/release-exec/dist/wasm.lock.json +4 -0
  45. package/release-exec/hooks/register.cjs +473 -0
  46. package/release-exec/package.json +35 -0
  47. package/release-exec/types.d.ts +50 -0
  48. package/runtime/engine.js +322 -0
  49. package/runtime/lbe_engine.wasm +0 -0
  50. package/src/cli/commands/auditVerify.js +36 -0
  51. package/src/cli/commands/dryrun.js +175 -0
  52. package/src/cli/commands/health.js +153 -0
  53. package/src/cli/commands/init.js +306 -0
  54. package/src/cli/commands/integrityCheck.js +57 -0
  55. package/src/cli/commands/logs.js +53 -0
  56. package/src/cli/commands/openState.js +44 -0
  57. package/src/cli/commands/policyAdd.js +8 -0
  58. package/src/cli/commands/policyMode.js +7 -0
  59. package/src/cli/commands/policySign.js +72 -0
  60. package/src/cli/commands/proof.js +122 -0
  61. package/src/cli/commands/run.js +342 -0
  62. package/src/cli/commands/status.js +73 -0
  63. package/src/cli/commands/verify.js +144 -0
  64. package/src/cli/main.js +176 -0
  65. package/src/cli/parseArgs.js +114 -0
  66. package/src/exec/localExecutor.js +289 -0
  67. package/src/hooks/register.cjs +505 -0
  68. package/src/state/appendCentral.cjs +87 -0
  69. package/src/state/fileIndex.js +140 -0
  70. package/src/state/index.cjs +101 -0
  71. package/src/state/index.js +65 -0
  72. package/src/state/intentRegistry.js +83 -0
  73. package/src/state/migration.js +112 -0
  74. package/src/state/proofRunner.js +246 -0
  75. package/src/state/stateRoot.js +40 -0
  76. package/src/state/targetRegistry.js +108 -0
  77. package/src/state/workspaceId.js +40 -0
  78. package/src/state/workspaceRegistry.js +65 -0
  79. package/types.d.ts +175 -0
@@ -0,0 +1,2 @@
1
+ #!/bin/sh
2
+ node letterblack-sentinel/scripts/mainhead-guard.mjs
@@ -0,0 +1,2 @@
1
+ #!/bin/sh
2
+ node letterblack-sentinel/scripts/mainhead-guard.mjs
package/CHANGELOG.md ADDED
@@ -0,0 +1,57 @@
1
+ # Changelog
2
+
3
+ ## 1.3.0 — 2026-06-23
4
+
5
+ ### Added
6
+ - Central local workspace state, proof summaries, and one-time import of legacy
7
+ `.lbe/events.jsonl` entries while preserving the original local log.
8
+
9
+ ## 1.2.0 — 2026-06-20
10
+
11
+ ### Added
12
+ - **Real JS governance engine** — `createLBE()` now uses the full 7-gate validation pipeline (schema → key lifecycle → timestamp skew → rate limit → nonce replay → policy) with backup, rollback, and audit. Previously backed by a thin WASM wrapper.
13
+ - **Observer mode** — `createLBE({ mode: 'observe' })` or `npx lbe observe`. All gates run silently, audit log is written, nothing is blocked. Default for new and half-built projects.
14
+ - **Policy file** (`lbe.policy.json`) — human-readable rule store per project. Records `effect`, `type`, `pattern`, the original user message (`from`), and timestamp (`at`). Deny always wins over allow.
15
+ - **New CLI commands:**
16
+ - `npx lbe observe` — switch to observer mode
17
+ - `npx lbe enforce` — switch to enforcement mode
18
+ - `npx lbe policy` — list all rules with source context
19
+ - **Universal CLI interface** — non-JS projects (Python, Rust, Go, any language) can pipe JSON to `npx lbe execute`. Exit 0 = allowed, exit 1 = denied, exit 2 = error.
20
+ - **Language-agnostic design** — WASM runtime path documented as the path to non-JS bindings. JS engine is the current production runtime.
21
+
22
+ ### Changed
23
+ - `LBEResult` now includes `commandId`, `stage`, `risk`, `output` fields.
24
+ - `LBEOptions` removes `policy_mode` / `timeout_ms` — these are managed by the governance engine internally.
25
+ - `wrapTools().dispatch()` now returns `Promise<LBEResult>` (async) to match the real engine contract.
26
+ - Types updated throughout to reflect observer mode result shape (`LBEObservedResult`).
27
+
28
+ ---
29
+
30
+ ## 1.0.4 — 2026-06-19
31
+
32
+ ### Removed
33
+ - MCP execution surface — `lbe-mcp` command, MCP adapter, and configuration examples removed.
34
+ An MCP server only offers LBE as one optional tool; agent hosts with native tools can act outside that boundary, so it cannot enforce the governance boundary. See `docs/decisions/ADR-001-remove-mcp-execution-surface.md`.
35
+ - HTTP server surface — `lbe-serve` command and HTTP adapter removed.
36
+ An HTTP endpoint replicates governance in a separate process and creates a second attack surface without guaranteeing the calling agent routes through it. See `docs/decisions/ADR-002-remove-http-server-surface.md`.
37
+
38
+ ### Changed
39
+ - Established SDK-only product boundary: LBE ships as one local SDK and CLI embedded in the caller's application. No daemon, host platform, Docker deployment, or companion system. See `docs/decisions/ADR-003-sdk-only-product-boundary.md`.
40
+ - Workspace pruned to SDK-only source; all optional execution surfaces removed from `src/`, `bin/`, and CI config.
41
+ - Public package identity (`LBE_PUBLIC_PACKAGE_NAME`, `LBE_PUBLIC_PACKAGE_VERSION`) is now parameterised via environment variables in the build script.
42
+ - Test command made portable across Node.js versions (no `--experimental-vm-modules` flag needed).
43
+
44
+ ### Public surface
45
+ The public package (`@letterblack/lbe-sdk`) exports exactly one function:
46
+
47
+ ```ts
48
+ export function execute(input: string): string;
49
+ ```
50
+
51
+ No server, daemon, MCP surface, or optional execution layer ships in the public package.
52
+
53
+ ---
54
+
55
+ ## 1.0.3 and earlier
56
+
57
+ Pre-release development. No public changelog maintained.
package/LICENSE ADDED
@@ -0,0 +1 @@
1
+ SEE LICENSE IN LICENSE
package/README.md ADDED
@@ -0,0 +1,506 @@
1
+ # LetterBlack LBE
2
+
3
+ LBE is local execution control for AI agents. It evaluates file and shell
4
+ actions routed through its execution boundary, records local evidence, and
5
+ returns an allow/deny outcome before the governed action runs.
6
+
7
+ LBE is not an AI model, IDE, full OS sandbox, or cloud monitor. It does not
8
+ control direct actions outside its execution boundary.
9
+
10
+ ## Install and start
11
+
12
+ ```bash
13
+ npm install @letterblack/lbe-sdk
14
+ npx lbe init
15
+ npx lbe status
16
+ npx lbe logs
17
+ npx lbe proof --public
18
+ npx lbe open-state
19
+ ```
20
+
21
+ `init` creates project policy material. `status` shows the local central state
22
+ for the current workspace; `logs` reads its event history; `proof` shows the
23
+ latest proof result; and `open-state` opens the central state folder.
24
+
25
+ ## Local state and proof
26
+
27
+ LBE keeps state locally in a central per-user state folder. Each workspace has
28
+ a stable workspace ID and its own event log. In v1.3, an existing
29
+ `.lbe/events.jsonl` remains local fallback truth and is imported into central
30
+ state once; the source file is preserved.
31
+
32
+ Proof combines an intent, optional target, file index, LBE events, and
33
+ `proof/latest.json`. Use `lbe proof --public` for a redacted proof summary.
34
+ Non-inspectable targets can produce `WEAK_PROOF` rather than a stronger claim.
35
+
36
+ ## Limits
37
+
38
+ Only actions routed through LBE are controlled. Central writes are best-effort,
39
+ logs remain local, and LBE does not provide process isolation or network
40
+ egress control.
41
+
42
+ ---
43
+
44
+ # Internal source workspace
45
+
46
+ This workspace is not the public npm package. It contains readable source,
47
+ tests, and release tooling. The public package is generated into
48
+ `release-public/` as `@letterblack/lbe-sdk`.
49
+
50
+ Every AI action passes through a local gate before it can execute.
51
+
52
+ **Local-first execution governance for AI agents.**
53
+ Deterministic execution. Workspace context. Audit. Rollback.
54
+
55
+ Everything runs on your machine. No cloud required.
56
+
57
+ **Distribution model:** this private package owns source truth. The public SDK
58
+ package ships only the generated public surface: bundled/minified `dist/`
59
+ entrypoints, `types.d.ts`, README, default policy template, and the WASM runtime.
60
+ LBE is SDK-only and local-only. It does not ship an MCP server, daemon, HTTP
61
+ API, hosted service, deployment infrastructure, or companion platform.
62
+
63
+ ---
64
+
65
+ ## Private/Public Release Contract
66
+
67
+ Do internal development here:
68
+
69
+ ```bash
70
+ npm install
71
+ npm run lint
72
+ npm test
73
+ npm run pack:check
74
+ ```
75
+
76
+ Build the public SDK package here:
77
+
78
+ ```bash
79
+ npm run build:engine
80
+ npm run validate:all
81
+ npm run verify:public-sdk
82
+ ```
83
+
84
+ Before publishing, install the generated tarball in a clean temporary project
85
+ and exercise the supported CLI workflow (`lbe init`, `lbe status`, `lbe policy`,
86
+ and `lbe enforce`). Publish only from `release-public/` after that test passes.
87
+
88
+ ### Public repository release
89
+
90
+ `../.github/workflows/release-public.yml` publishes only the generated
91
+ `release-public/` tree to `Letterblack0306/LetterBlack-Sentinel`; it never
92
+ pushes this private source repository, its history, or its internal files.
93
+
94
+ Set `PUBLIC_REPO_TOKEN` and `NPM_TOKEN` as Actions secrets in this repository.
95
+ The former needs Contents read/write permission to the public repository; the
96
+ latter needs npm publish permission for `@letterblack/lbe-sdk`. Push a matching
97
+ `v<package-version>` tag from current `main` to release automatically, or run
98
+ the workflow manually with the same tag value. The workflow verifies the
99
+ artifact and tests first, publishes npm, replaces the public repository working
100
+ tree with the release artifact, then creates its tag and GitHub release. It
101
+ blocks release unless the checked-out commit is the current `main` head.
102
+
103
+ ## Source authority
104
+
105
+ Only `main` in the primary working tree is a source of truth. Do not develop,
106
+ commit, validate, or push from feature branches, detached HEADs, or linked Git
107
+ worktrees. Run `npm run hooks:install` after cloning; see
108
+ [`docs/governance/mainhead.md`](docs/governance/mainhead.md) for the blocker
109
+ rules.
110
+
111
+ Publish only from:
112
+
113
+ ```text
114
+ release-public/
115
+ ```
116
+
117
+ The generated public package must not contain:
118
+
119
+ ```text
120
+ src/core/
121
+ src/adapters/
122
+ src/cli/
123
+ scripts/
124
+ test/
125
+ keys/
126
+ data/
127
+ node_modules/
128
+ *.map
129
+ ```
130
+
131
+ ---
132
+
133
+ ## Install
134
+
135
+ Internal source workspace:
136
+
137
+ ```bash
138
+ npm install @letterblack/lbe-core
139
+ ```
140
+
141
+ Public users install:
142
+
143
+ ```bash
144
+ npm install @letterblack/lbe-sdk
145
+ ```
146
+
147
+ Requires Node.js ≥ 20.9.0.
148
+
149
+ The current preview uses the audited JavaScript governance engine. The commercial
150
+ runtime target is a compiled engine loaded locally through WASM, with the same
151
+ public SDK and CLI surface.
152
+
153
+ ---
154
+
155
+ ## After install
156
+
157
+ ```bash
158
+ npx lbe execute --input input.json
159
+ ```
160
+
161
+ `input.json` must contain a signed LBE execution request. You can also pipe the
162
+ same JSON request through stdin:
163
+
164
+ ```bash
165
+ cat input.json | npx lbe execute
166
+ ```
167
+
168
+ ---
169
+
170
+ ## Quick Start
171
+
172
+ ```js
173
+ import crypto from 'node:crypto';
174
+ import { execute } from '@letterblack/lbe-sdk';
175
+
176
+ const buildRequest = (name, payload = {}) => ({
177
+ version: '1.0',
178
+ request_id: crypto.randomUUID(),
179
+ timestamp: Math.floor(Date.now() / 1000),
180
+ actor: { id: 'agent:local', role: 'agent' },
181
+ intent: { type: 'command', name, payload },
182
+ context: { workspace: process.cwd(), env: {}, history: [] },
183
+ constraints: { policy_mode: 'strict', timeout_ms: 5000 },
184
+ auth: { signature: 'provided-by-host', nonce: crypto.randomUUID() }
185
+ });
186
+
187
+ const output = execute(JSON.stringify(buildRequest('status')));
188
+ console.log(JSON.parse(output));
189
+ ```
190
+
191
+ The public contract is `execute(input: string): string`. This repo still
192
+ contains the private source package and its internal SDK helpers below, but the
193
+ published surface is the generated `@letterblack/lbe-sdk` package.
194
+
195
+ ---
196
+
197
+ ## Add what you need
198
+
199
+ **Audit — see exactly what changed and when:**
200
+ ```js
201
+ const sb = sandbox('./workspace', { audit: true });
202
+ // appends to ~/.lbe/workspaces/<id>/audit.log.jsonl
203
+ ```
204
+
205
+ **Rollback — undo failed writes automatically:**
206
+ ```js
207
+ const sb = sandbox('./workspace', { audit: true, rollback: true });
208
+ // backs up before every write, restores on failure
209
+ ```
210
+
211
+ **State stays local** — all runtime state (audit logs, nonce store, backups) goes to
212
+ `~/.lbe/workspaces/<workspace-id>/` by default. Never inside your project, never sent anywhere.
213
+
214
+ To keep state inside the project instead (for team sharing):
215
+ ```js
216
+ const sb = sandbox('./workspace', { state: 'workspace' });
217
+ // writes to .lbe/ inside your project root
218
+ ```
219
+
220
+ ---
221
+
222
+ ## Integration boundary
223
+
224
+ LBE is embedded directly in the user's existing application through
225
+ `execute(input)` or `createLBE().execute()`. It requires no companion service
226
+ or separate runtime system. The calling code submits structured action requests
227
+ and remains responsible for giving the SDK-governed path exclusive authority.
228
+
229
+ The Model Context Protocol integration was removed because an MCP server only
230
+ offers LBE as an optional tool; an agent host with native tools can act outside
231
+ the governed execution boundary.
232
+ See [`docs/decisions/ADR-001-remove-mcp-execution-surface.md`](docs/decisions/ADR-001-remove-mcp-execution-surface.md).
233
+
234
+ ---
235
+
236
+ ## Agent Safe Execution
237
+
238
+ LBE Agent Safe Execution intercepts Node.js file and shell actions before they mutate the workspace.
239
+
240
+ Choose the integration path that matches how your agent runs:
241
+
242
+ ### 1. Agents you own — direct integration at the dispatch point
243
+
244
+ If you control the agent's dispatch loop, integrate `lbe-exec` at the point where actions are issued. No preload hook needed — LBE governs each action directly through the SDK.
245
+
246
+ ```js
247
+ import { createLocalExecutor } from '@letterblack/lbe-exec';
248
+
249
+ const lbe = createLocalExecutor({ rootDir: process.cwd(), mode: 'enforce' });
250
+
251
+ await lbe.writeFile('src/output.ts', content);
252
+ await lbe.deleteFile('src/old.ts');
253
+ await lbe.runShell('npm', ['test']);
254
+ ```
255
+
256
+ Every call passes through the full 7-gate pipeline: local policy, key lifecycle, signature, rate limit, nonce, and audit.
257
+
258
+ ### 2. Node agents you launch — `run-node`
259
+
260
+ Use `run-node` to launch any Node.js agent under the preload hook. The hook patches `fs` and `child_process` before the agent's entry module runs — including actions taken by the agent's own npm dependencies.
261
+
262
+ ```bash
263
+ npx lbe-exec run-node ./agent.js
264
+ npx lbe-exec run-node --mode enforce ./agent.js
265
+ ```
266
+
267
+ Patched APIs: `fs.writeFile`, `fs.writeFileSync`, `fs.rm`, `fs.rmSync`, `fs.unlink`, `fs.unlinkSync`, `fs.rename`, `fs.renameSync`, `fs.promises.*` variants, `child_process.spawn`, `spawnSync`, `exec`, `execSync`.
268
+
269
+ ### 3. Existing npm scripts — `lbe-exec npm`
270
+
271
+ Inject the hook into any npm script via `NODE_OPTIONS`:
272
+
273
+ ```bash
274
+ npx lbe-exec npm run agent
275
+ ```
276
+
277
+ > **Note:** `NODE_OPTIONS`-based injection is less reliable than `run-node`. Some runtimes strip or override `NODE_OPTIONS`. Use `run-node` when the agent entry point is known.
278
+
279
+ ### 4. Opaque or external agents — sandbox mode (future)
280
+
281
+ For agents that run outside Node.js, inside containers, or as opaque binaries — sandbox mode is planned. Not available in this release.
282
+
283
+ ---
284
+
285
+ ### Init — non-destructive script injection
286
+
287
+ ```bash
288
+ npx lbe-exec init
289
+ ```
290
+
291
+ Detects agent scripts in `package.json` and adds `:lbe` and `:lbe:enforce` variants alongside them. Originals are never overwritten.
292
+
293
+ Input:
294
+ ```json
295
+ { "scripts": { "agent": "node ./src/agent.js" } }
296
+ ```
297
+
298
+ Output:
299
+ ```json
300
+ {
301
+ "scripts": {
302
+ "agent": "node ./src/agent.js",
303
+ "agent:lbe": "lbe-exec run-node --mode observe ./src/agent.js",
304
+ "agent:lbe:enforce": "lbe-exec run-node --mode enforce ./src/agent.js",
305
+ "lbe:status": "lbe-exec status",
306
+ "lbe:audit": "lbe-exec audit"
307
+ }
308
+ }
309
+ ```
310
+
311
+ ### Status and audit
312
+
313
+ ```bash
314
+ npx lbe-exec status # hook state, PID liveness, patched function table
315
+ npx lbe-exec audit # stream .lbe/events.jsonl as a formatted table
316
+ ```
317
+
318
+ `status` reads `.lbe/runtime/hook-status.json` written by the hook at preload time and checks PID liveness in a separate process — no shared memory required.
319
+
320
+ ---
321
+
322
+ ## Full governance
323
+
324
+ For teams, compliance workflows, or named actors with distinct permission sets:
325
+
326
+ ```js
327
+ import { createLBE, generateKeyPair, createKeyStore } from '@letterblack/lbe-core';
328
+
329
+ const { secretKey, publicKey } = generateKeyPair();
330
+
331
+ const lbe = createLBE({
332
+ secretKey,
333
+ keyId: 'prod-key',
334
+ keyStore: createKeyStore({ publicKey, keyId: 'prod-key' }),
335
+ policy: {
336
+ version: 1,
337
+ default: 'DENY',
338
+ requesters: {
339
+ 'agent:writer': {
340
+ allowCommands: ['write_file', 'read_file'],
341
+ allowAdapters: ['file'],
342
+ filesystem: {
343
+ roots: ['./output/'],
344
+ denyPatterns: ['*.key', '*.env']
345
+ }
346
+ }
347
+ }
348
+ }
349
+ });
350
+
351
+ const result = await lbe.execute({
352
+ actor: 'agent:writer',
353
+ intent: 'write_file',
354
+ target: './output/report.md',
355
+ content: '# Report\n',
356
+ transaction: { backup: true, rollbackOnFailure: true, audit: true }
357
+ });
358
+
359
+ console.log(result.ok); // true | false
360
+ console.log(result.stage); // 'executed' | 'validate' | 'invariant_gate' | ...
361
+ console.log(result.commandId); // matches audit log entry
362
+ ```
363
+
364
+ Zero-config alternative — auto-generates keys and policy for `rootDir`:
365
+
366
+ ```js
367
+ const lbe = createLBE({ rootDir: process.cwd() });
368
+ await lbe.writeFile('data/output.txt', 'result\n');
369
+ const text = await lbe.readFile('data/output.txt');
370
+ ```
371
+
372
+ ---
373
+
374
+ ## How it works
375
+
376
+ ```
377
+ Agent
378
+ │ proposes intent
379
+
380
+ Invariant Gate ── key present? policy signed? keyStore loaded?
381
+
382
+
383
+ 7-Gate Validation
384
+ ├── schema
385
+ ├── key lifecycle
386
+ ├── timestamp skew
387
+ ├── signature
388
+ ├── rate limit
389
+ ├── nonce replay
390
+ └── policy (deny-by-default)
391
+
392
+ ▼ all gates pass
393
+ Adapter ── file | shell | noop
394
+
395
+
396
+ Audit Log ── SHA-256 hash-chained JSONL, append-only
397
+ ```
398
+
399
+ The controller is the only authority. Adapters execute — they do not decide.
400
+
401
+ ---
402
+
403
+ ## Public SDK surface
404
+
405
+ The published package (`@letterblack/lbe-sdk`) exposes one function:
406
+
407
+ ```ts
408
+ export function execute(input: string): string;
409
+ ```
410
+
411
+ `input` is a JSON-serialized `LBEExecuteInput`. The return value is a
412
+ JSON-serialized `LBEExecuteOutput`. Full type definitions are in `types.d.ts`.
413
+
414
+ ```ts
415
+ interface LBEExecuteOutput {
416
+ ok: boolean;
417
+ result: { type: 'allowed' | 'denied' | 'error'; action: string; data: Record<string, unknown> };
418
+ policy: { decision: 'allow' | 'deny' | 'escalate'; reason: string; rules: string[] };
419
+ trace: { id: string; steps: unknown[]; hash: string };
420
+ error: null | { code: string; message: string };
421
+ }
422
+ ```
423
+
424
+ ---
425
+
426
+ ## Internal source API (private package only)
427
+
428
+ These helpers exist in `@letterblack/lbe-core` (this private package) for
429
+ repository development and testing. They are **not** exported from the public
430
+ `@letterblack/lbe-sdk` package.
431
+
432
+ ### `sandbox(root, opts?)` → `{ write, read, patch, lbe }`
433
+
434
+ | Option | Default | Description |
435
+ |---|---|---|
436
+ | `audit` | `false` | Append to audit log on every operation |
437
+ | `rollback` | `false` | Back up before write; restore on failure |
438
+ | `state` | `'local'` | `'local'` → `~/.lbe/` · `'workspace'` → `.lbe/` inside project |
439
+
440
+ ### `createLBE(options)` → `{ execute, writeFile, readFile, exportLogs }`
441
+
442
+ | Option | Type | Description |
443
+ |---|---|---|
444
+ | `rootDir` | `string` | Auto-configure keys, policy, and state for this directory |
445
+ | `secretKey` | `string` | Ed25519 secret key (base64) |
446
+ | `keyId` | `string` | Key identifier |
447
+ | `policy` | `object` | Inline policy object |
448
+ | `state` | `string` | `'local'` (default) · `'workspace'` · `{ adapter }` |
449
+ | `logLevel` | `string` | `DEBUG` · `INFO` · `WARN` · `ERROR` |
450
+
451
+ ### Additional exports
452
+
453
+ ```js
454
+ import { AVAILABLE_ADAPTERS } from '@letterblack/lbe-core/adapters';
455
+ // → ['noop', 'shell', 'file']
456
+
457
+ import {
458
+ validateCommand,
459
+ appendAudit,
460
+ createBackup, restoreBackup,
461
+ signEd25519, verifyEd25519, generateKeyPair,
462
+ createLogger, deepFreeze,
463
+ checkInvariants, assertInvariants, InvariantGateError
464
+ } from '@letterblack/lbe-core';
465
+ ```
466
+
467
+ ## CLI
468
+
469
+ | Command | Description |
470
+ |---|---|
471
+ | `npx lbe execute --input input.json` | Execute one JSON request through the public runtime |
472
+ | `cat input.json \| npx lbe execute` | Execute one JSON request from stdin |
473
+
474
+ ---
475
+
476
+ ## Security model
477
+
478
+ - **Ed25519 signatures** — every proposal is signed; the controller verifies before any gate runs
479
+ - **Nonce replay protection** — each `commandId` is single-use; replays are hard-rejected
480
+ - **Rate limiting** — per-requester, configurable window
481
+ - **Timestamp skew guard** — rejects proposals outside ±10 minutes
482
+ - **Policy signature verification** — the policy file itself is signed; tampering fails the invariant gate
483
+ - **Immutable audit trail** — SHA-256 hash-chained JSONL; any deletion or edit is detectable
484
+ - **Atomic writes** — all state files use write-then-rename; no partial state
485
+
486
+ **What is never committed:**
487
+ `keys/secret.key` · `keys/*.key` · `config/keys.json` · `config/policy.sig.json` · `data/`
488
+
489
+ **Scope — what this hardens against:**
490
+ Accidental writes outside allowed roots. Replay attacks. Policy drift. Audit log tampering. Rollback on failure.
491
+
492
+ **Not in scope:**
493
+ Kernel-level process isolation. Network egress control. Multi-tenant workload separation.
494
+ This SDK does not sandbox the agent process — it governs the actions that agent routes through the SDK.
495
+
496
+ ---
497
+
498
+ ## Changelog
499
+
500
+ See [`CHANGELOG.md`](CHANGELOG.md).
501
+
502
+ ---
503
+
504
+ ## License
505
+
506
+ MIT — LetterBlack 2026