@letterblack/lbe-exec 1.2.3 → 1.2.5
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 +137 -58
- package/package.json +1 -1
package/README.md
CHANGED
|
@@ -2,9 +2,12 @@
|
|
|
2
2
|
|
|
3
3
|
**Local-first execution governance for AI agents.**
|
|
4
4
|
|
|
5
|
+
> Use `@letterblack/lbe-exec` if you want LBE to control agent actions in a workspace.
|
|
6
|
+
> Use `@letterblack/lbe-sdk` if you only need validation decisions inside your own tool.
|
|
7
|
+
|
|
5
8
|
Every action any agent proposes — file write, shell command, anything — passes
|
|
6
|
-
through a local validation gate before it can execute. One
|
|
7
|
-
zero cloud dependency.
|
|
9
|
+
through a local validation gate before it can execute. One package, any agent,
|
|
10
|
+
zero cloud dependency, no daemon required.
|
|
8
11
|
|
|
9
12
|
---
|
|
10
13
|
|
|
@@ -26,22 +29,29 @@ dependency, no daemon required.
|
|
|
26
29
|
|
|
27
30
|

|
|
28
31
|
|
|
29
|
-
Every request the agent produces enters a gate
|
|
30
|
-
|
|
31
|
-
**Policy** — does the current project policy allow this action? Deny rules
|
|
32
|
-
always win. If any deny rule matches, the gate closes before any other check
|
|
33
|
-
runs.
|
|
32
|
+
Every request the agent produces enters a 7-gate pipeline. A failure at any
|
|
33
|
+
gate returns a structured denial — the remaining gates are not evaluated.
|
|
34
34
|
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
35
|
+
```
|
|
36
|
+
[1] Schema required fields and structural validity
|
|
37
|
+
↓
|
|
38
|
+
[2] Timestamp permitted clock-skew window (±10 minutes)
|
|
39
|
+
↓
|
|
40
|
+
[3] Key lifecycle trusted key, active, not expired
|
|
41
|
+
↓
|
|
42
|
+
[4] Signature Ed25519 request authenticity (signed locally, no network)
|
|
43
|
+
↓
|
|
44
|
+
[5] Rate limit per-requester sliding-window limit
|
|
45
|
+
↓
|
|
46
|
+
[6] Nonce single-use replay protection
|
|
47
|
+
↓
|
|
48
|
+
[7] Policy configured authorization (deny-wins)
|
|
49
|
+
↓
|
|
50
|
+
allow / deny / error — structured result returned to host
|
|
51
|
+
```
|
|
42
52
|
|
|
43
|
-
|
|
44
|
-
|
|
53
|
+
The executor signs every request with a host-held key before validation.
|
|
54
|
+
No key material leaves the process.
|
|
45
55
|
|
|
46
56
|
---
|
|
47
57
|
|
|
@@ -51,20 +61,17 @@ where something is actually written to disk or a command actually runs.
|
|
|
51
61
|
|
|
52
62
|
When a request clears every gate:
|
|
53
63
|
|
|
54
|
-
1. The agent
|
|
55
|
-
2. The executor signs
|
|
56
|
-
|
|
57
|
-
3. The project policy is evaluated. The action is approved.
|
|
64
|
+
1. The agent calls a convenience method — `lbe.writeFile()`, `lbe.runShell()`, etc.
|
|
65
|
+
2. The executor constructs and signs the request locally with a host-held Ed25519 key.
|
|
66
|
+
3. All seven gates pass. The project policy approves the action.
|
|
58
67
|
4. The write or command executes inside the configured project root.
|
|
59
|
-
5. The audit chain is extended
|
|
60
|
-
entry to
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
and the audit entry identifier.
|
|
68
|
+
5. The audit chain is extended — every approved action appends a hash-linked
|
|
69
|
+
entry to `.lbe/audit.jsonl`, permanently verifiable, impossible to silently remove.
|
|
70
|
+
6. A structured result returns: whether it succeeded, which rules matched, and
|
|
71
|
+
the audit entry identifier.
|
|
64
72
|
|
|
65
|
-
The application stays in control. The executor
|
|
66
|
-
|
|
67
|
-
back.
|
|
73
|
+
The application stays in control. The executor decides whether the action was
|
|
74
|
+
permitted and hands the answer back.
|
|
68
75
|
|
|
69
76
|
---
|
|
70
77
|
|
|
@@ -100,32 +107,27 @@ is an agent that can grant itself permission.
|
|
|
100
107
|
|
|
101
108
|
---
|
|
102
109
|
|
|
103
|
-
## Observer mode — start here
|
|
104
|
-
|
|
105
|
-
Not ready to block? Start in observer mode. Every request is fully validated
|
|
106
|
-
and logged exactly as it would be in enforcement — but nothing is blocked.
|
|
107
|
-
|
|
108
|
-
Watch what the agent is doing before you decide what to deny. Your rules take
|
|
109
|
-
effect the moment you switch to enforcement.
|
|
110
|
-
|
|
111
|
-
```bash
|
|
112
|
-
npx lbe-exec init # create lbe.policy.json — starts in observer mode
|
|
113
|
-
npx lbe-exec status # see mode, rule count, audit entry count
|
|
114
|
-
npx lbe-exec enforce # switch to blocking
|
|
115
|
-
```
|
|
116
|
-
|
|
117
|
-
---
|
|
118
|
-
|
|
119
110
|
## What this covers
|
|
120
111
|
|
|
121
112
|
| Threat | Gate |
|
|
122
113
|
|---|---|
|
|
123
|
-
| Agent writes outside the project root | Scope — path check |
|
|
114
|
+
| Agent writes outside the project root | Scope — sandbox path check |
|
|
124
115
|
| Replayed or stale request | Identity — nonce and timestamp |
|
|
125
116
|
| Tampered or expired key | Identity — key lifecycle |
|
|
126
117
|
| Excessive requests | Identity — rate limit |
|
|
127
118
|
| Action not permitted by project policy | Policy — deny-wins evaluation |
|
|
128
119
|
| Unauthorized shell command | Scope — explicit command allowlist |
|
|
120
|
+
| Injected payload (eval, exec, __proto__) | Content scan before pipeline |
|
|
121
|
+
|
|
122
|
+
---
|
|
123
|
+
|
|
124
|
+
## Observer mode — start here
|
|
125
|
+
|
|
126
|
+
Not ready to block? Start in observer mode. Every request is fully validated
|
|
127
|
+
and logged exactly as it would be in enforcement — but nothing is blocked.
|
|
128
|
+
|
|
129
|
+
Watch what the agent is doing before you decide what to deny. Your rules take
|
|
130
|
+
effect the moment you switch to enforcement.
|
|
129
131
|
|
|
130
132
|
---
|
|
131
133
|
|
|
@@ -136,13 +138,15 @@ npm install @letterblack/lbe-exec
|
|
|
136
138
|
npx lbe-exec init
|
|
137
139
|
```
|
|
138
140
|
|
|
139
|
-
`npx lbe-exec init` scans the project, writes `lbe.policy.json` in observer
|
|
140
|
-
generates `CLAUDE.md` and `.github/copilot-instructions.md` so every AI
|
|
141
|
-
automatically discovers and follows governance
|
|
142
|
-
|
|
141
|
+
`npx lbe-exec init` scans the project, writes `lbe.policy.json` in observer
|
|
142
|
+
mode, generates `CLAUDE.md` and `.github/copilot-instructions.md` so every AI
|
|
143
|
+
agent automatically discovers and follows governance, and creates
|
|
144
|
+
`.lbe/AGENT_CONTRACT.md` as a machine-readable contract.
|
|
143
145
|
|
|
144
146
|
Requires Node.js ≥ 20.9.0.
|
|
145
147
|
|
|
148
|
+
---
|
|
149
|
+
|
|
146
150
|
## Use in agent code
|
|
147
151
|
|
|
148
152
|
```js
|
|
@@ -150,27 +154,102 @@ import { createLocalExecutor } from '@letterblack/lbe-exec';
|
|
|
150
154
|
|
|
151
155
|
const lbe = createLocalExecutor({ rootDir: process.cwd() });
|
|
152
156
|
|
|
157
|
+
// Every call routes through the full 7-gate pipeline
|
|
153
158
|
await lbe.writeFile('output/report.md', content);
|
|
154
159
|
await lbe.readFile('src/config.json');
|
|
155
160
|
await lbe.patchFile('src/index.js', patch);
|
|
156
161
|
await lbe.deleteFile('tmp/scratch.txt');
|
|
157
162
|
await lbe.runShell('node', ['scripts/build.js']);
|
|
158
163
|
|
|
164
|
+
// Result shape
|
|
159
165
|
const result = await lbe.writeFile('output/result.md', data);
|
|
160
|
-
// { ok: true,
|
|
161
|
-
// { ok: false, decision: 'deny', error: { message
|
|
166
|
+
// { ok: true, decision: 'allow', executed: true, auditId: '...' }
|
|
167
|
+
// { ok: false, decision: 'deny', executed: false, error: { code, message } }
|
|
168
|
+
```
|
|
169
|
+
|
|
170
|
+
No knowledge of the pipeline, request format, or policy internals required.
|
|
171
|
+
All signing, validation, and auditing happens automatically.
|
|
172
|
+
|
|
173
|
+
### Options
|
|
174
|
+
|
|
175
|
+
```js
|
|
176
|
+
const lbe = createLocalExecutor({
|
|
177
|
+
rootDir: process.cwd(), // sandbox root — no writes escape this path
|
|
178
|
+
mode: 'observe', // 'observe' (log only) or 'enforce' (block)
|
|
179
|
+
shell: {
|
|
180
|
+
allowCommands: ['node', 'npm'], // only these commands may run
|
|
181
|
+
denyCommands: ['rm', 'curl'], // always blocked regardless of policy
|
|
182
|
+
maxRequests: 20 // per-minute shell rate limit
|
|
183
|
+
}
|
|
184
|
+
});
|
|
162
185
|
```
|
|
163
186
|
|
|
164
|
-
|
|
165
|
-
|
|
166
|
-
|
|
187
|
+
### Policy management
|
|
188
|
+
|
|
189
|
+
```js
|
|
190
|
+
// Propose a rule — returns an object for the host to review, writes nothing
|
|
191
|
+
const proposal = lbe.policy.proposeRule({
|
|
192
|
+
effect: 'deny',
|
|
193
|
+
type: 'path',
|
|
194
|
+
pattern: 'secrets/**',
|
|
195
|
+
from: 'agent: these files should not be modified'
|
|
196
|
+
});
|
|
197
|
+
|
|
198
|
+
// Host accepts and writes the rule
|
|
199
|
+
lbe.policy.addRule(proposal);
|
|
200
|
+
|
|
201
|
+
// Read current policy
|
|
202
|
+
const policy = lbe.policy.read();
|
|
203
|
+
|
|
204
|
+
// Verify the audit chain has not been tampered with
|
|
205
|
+
lbe.audit.verify();
|
|
206
|
+
```
|
|
207
|
+
|
|
208
|
+
---
|
|
209
|
+
|
|
210
|
+
## CLI reference
|
|
211
|
+
|
|
212
|
+
```bash
|
|
213
|
+
npx lbe-exec init # create lbe.policy.json in observer mode
|
|
214
|
+
npx lbe-exec status # show mode, rule count, and audit entry count
|
|
215
|
+
npx lbe-exec enforce # switch to blocking
|
|
216
|
+
npx lbe-exec observe # switch back to advisory
|
|
217
|
+
npx lbe-exec policy # list active rules
|
|
218
|
+
```
|
|
219
|
+
|
|
220
|
+
| Command | Purpose |
|
|
221
|
+
|---|---|
|
|
222
|
+
| `npx lbe-exec init` | Bootstrap governance — policy, keys, agent files |
|
|
223
|
+
| `npx lbe-exec status` | Show mode, rule count, audit entry count |
|
|
224
|
+
| `npx lbe-exec policy` | List active rules |
|
|
225
|
+
| `npx lbe-exec observe` | Set advisory (log-only) mode |
|
|
226
|
+
| `npx lbe-exec enforce` | Set blocking mode |
|
|
227
|
+
| `npx lbe-exec execute` | Pipe a JSON request from stdin or `--input <file>` |
|
|
167
228
|
|
|
168
229
|
---
|
|
169
230
|
|
|
170
231
|
## What ships
|
|
171
232
|
|
|
172
|
-
|
|
173
|
-
|
|
174
|
-
|
|
233
|
+
```
|
|
234
|
+
dist/index.js In-process executor — createLocalExecutor()
|
|
235
|
+
dist/cli.js Local CLI (npx lbe-exec)
|
|
236
|
+
dist/lbe_engine.wasm Verified WASM runtime binary
|
|
237
|
+
dist/wasm.lock.json Runtime integrity lock (SHA-256 of wasm binary)
|
|
238
|
+
assets/lbe-gates.png Gate sequence diagram
|
|
239
|
+
assets/story-allow.png Approved-request storyboard
|
|
240
|
+
assets/story-deny.png Blocked-request storyboard
|
|
241
|
+
assets/runtime-boundary.svg Runtime boundary diagram
|
|
242
|
+
types.d.ts TypeScript declarations
|
|
243
|
+
```
|
|
244
|
+
|
|
245
|
+
Source code, tests, keys, and runtime state are not included.
|
|
246
|
+
|
|
247
|
+
---
|
|
248
|
+
|
|
249
|
+
## Limits
|
|
250
|
+
|
|
251
|
+
This package governs actions routed through its executor. It does not provide
|
|
252
|
+
kernel-level process isolation, network-egress control, multi-tenant separation,
|
|
253
|
+
or a hosted control plane.
|
|
175
254
|
|
|
176
|
-
|
|
255
|
+
For the raw WASM runtime without a controller, see `@letterblack/lbe-sdk`.
|