@letterblack/lbe-exec
v1.2.20
Published
Local host-signed execution layer for LetterBlack LBE.
Downloads
2,689
Readme
@letterblack/lbe-exec
LBE puts a local policy gate between what an AI agent proposes and what the system actually executes. Every action — file write, shell command, anything — is validated locally before it runs. No cloud service. No daemon.
lbe-exec is the full in-process controller. It handles signing, execution, and auditing for you — your agent code just calls lbe.writeFile() or lbe.runShell().
Used in production: LBE is the safety engine inside Letterblack for After Effects — every AI-generated script and automation command passes through it before touching a live project.
Which package do you need?
| I want… | Package |
|---|---|
| LBE to handle file writes and shell commands for me (full controller) | @letterblack/lbe-exec ← you are here |
| Just the allow/deny decision — I'll execute it myself | @letterblack/lbe-sdk |
Install
npm install @letterblack/lbe-exec
npx lbe-exec initnpx lbe-exec init creates lbe.policy.json in observer mode, generates CLAUDE.md and .github/copilot-instructions.md so AI agents automatically discover and follow governance, and writes .lbe/AGENT_CONTRACT.md as a machine-readable contract.
Requires Node.js ≥ 20.9.0.
Quick start
import { createLocalExecutor } from '@letterblack/lbe-exec';
const lbe = createLocalExecutor({ rootDir: process.cwd() });
// Every call routes through the full 7-gate pipeline automatically
await lbe.writeFile('output/report.md', content);
await lbe.readFile('src/config.json');
await lbe.patchFile('src/index.js', patch);
await lbe.deleteFile('tmp/scratch.txt');
await lbe.runShell('node', ['scripts/build.js']);
// Result shape — same for every method
// { ok: true, decision: 'allow', executed: true, auditId: '...' }
// { ok: false, decision: 'deny', executed: false, error: { code, message } }No knowledge of the pipeline, request format, or policy internals required. All signing, validation, and auditing happens automatically.
Options
const lbe = createLocalExecutor({
rootDir: process.cwd(), // sandbox root — no writes escape this path
mode: 'observe', // 'observe' (log only) or 'enforce' (block)
shell: {
allowCommands: ['node', 'npm'], // only these commands may run
denyCommands: ['rm', 'curl'], // always blocked regardless of policy
maxRequests: 20 // per-minute shell rate limit
}
});Policy management
Only the host application writes policy. Agents may propose a rule — the proposal is returned as a plain object for the host to review. Until the host explicitly accepts and writes it, the proposal has no effect.
// Propose a rule — returns an object for the host to review, writes nothing
const proposal = lbe.policy.proposeRule({
effect: 'deny',
type: 'path',
pattern: 'secrets/**',
from: 'agent: these files should not be modified'
});
// Host accepts and writes the rule
lbe.policy.addRule(proposal);
// Read current policy
const policy = lbe.policy.read();
// Verify the audit chain has not been tampered with
lbe.audit.verify();Observer mode — start here
Not ready to block? Start in observer mode. Every request is fully validated and logged exactly as it would be in enforcement — but nothing is blocked. Watch what the agent is doing before you decide what to deny.
npx lbe-exec init # create lbe.policy.json in observer mode
npx lbe-exec enforce # switch to blocking
npx lbe-exec observe # switch back to advisoryCLI reference
| Command | Purpose |
|---|---|
| npx lbe-exec init | Bootstrap governance — policy, keys, agent files |
| npx lbe-exec status | Show mode, rule count, audit entry count |
| npx lbe-exec policy | List active rules |
| npx lbe-exec observe | Set advisory (log-only) mode |
| npx lbe-exec enforce | Set blocking mode |
| npx lbe-exec execute | Pipe a JSON request from stdin or --input <file> |
How the gate pipeline works

Every request enters a 7-gate pipeline. A failure at any gate returns a structured denial — the remaining gates are not evaluated.
[1] Schema required fields and structural validity
↓
[2] Timestamp permitted clock-skew window (±10 minutes)
↓
[3] Key lifecycle trusted key, active, not expired
↓
[4] Signature Ed25519 request authenticity (signed locally, no network)
↓
[5] Rate limit per-requester sliding-window limit
↓
[6] Nonce single-use replay protection
↓
[7] Policy configured authorization (deny-wins)
↓
allow / deny / error — structured result returned to hostThe executor signs every request with a host-held key before validation. No key material leaves the process.
When a request is approved

- The agent calls a convenience method —
lbe.writeFile(),lbe.runShell(), etc. - The executor constructs and signs the request locally with a host-held Ed25519 key.
- All seven gates pass. The project policy approves the action.
- The write or command executes inside the configured project root.
- The audit chain is extended — every approved action appends a hash-linked entry to
.lbe/audit.jsonl, permanently verifiable, impossible to silently remove. - A structured result returns: whether it succeeded, which rules matched, and the audit entry identifier.
When a request is blocked

- The agent attempts an action — whether by mistake, misconfiguration, or a deliberate bypass attempt.
- The policy gate closes immediately. The request is denied before any adapter is reached.
- The shell is untouched. The filesystem is unchanged.
- The denial is written to the immutable audit log — chain sealed, evidence preserved.
No partial execution. No silent failures. Denial is a first-class outcome, not an error.
What this covers
| Threat | Gate | |---|---| | Agent writes outside the project root | Scope — sandbox path check | | Replayed or stale request | Identity — nonce and timestamp | | Tampered or expired key | Identity — key lifecycle | | Excessive requests | Identity — rate limit | | Action not permitted by project policy | Policy — deny-wins evaluation | | Unauthorized shell command | Scope — explicit command allowlist | | Injected payload (eval, exec, proto) | Content scan before pipeline |
What ships
dist/index.js In-process executor — createLocalExecutor()
dist/cli.js Local CLI (npx lbe-exec)
dist/lbe_engine.wasm Verified WASM runtime binary
dist/wasm.lock.json Runtime integrity lock (SHA-256 of wasm binary)
assets/lbe-gates.jpg Gate sequence diagram
assets/story-allow.jpg Approved-request storyboard
assets/story-deny.jpg Blocked-request storyboard
assets/runtime-boundary.svg Runtime boundary diagram
assets/lbe-gates.png Gate sequence diagram (full resolution)
assets/story-allow.png Approved-request storyboard (full resolution)
assets/story-deny.png Blocked-request storyboard (full resolution)
types.d.ts TypeScript declarationsSource code, tests, keys, and runtime state are not included.
Limits
This package governs actions routed through its executor. It does not provide kernel-level process isolation, network-egress control, multi-tenant separation, or a hosted control plane.
For the raw WASM runtime without a controller, see @letterblack/lbe-sdk.
