@amail/plugin-host
v0.1.0
Published
Worker-thread sandbox host for AMail plugins. Enforces manifest-declared permissions at the worker boundary.
Downloads
30
Readme
@amail/plugin-host
Worker-thread sandbox host for AMail
plugins. Enforces manifest-declared permissions at the worker boundary using
Node 24's --permission flag and an in-process ctx_request/ctx_response
protocol over MessagePort.
End users rarely import this directly — it's loaded by the AMail runtime to
dispatch plugin tools. Plugin authors do import it via the
./testing subpath to drive their integration tests.
Installation
pnpm add -D @amail/plugin-hostRequires Node ≥ 24 (the --permission flag is stable from 24.x).
What's in dist/
index.js/index.d.ts—PluginHost,bootPlugin, errorsworker-entry.mjs— the worker entrypoint thatWorkerspawns; not a user-facing APItesting.js/testing.d.ts— theboot({ pkgRoot, fixtures? })helper
Testing helpers
import { boot } from "@amail/plugin-host/testing";
const host = await boot({
pkgRoot: new URL("..", import.meta.url),
fixtures: { /* AttachmentRef stubs etc. */ },
});
const result = await host.callTool("parse_compliance_csv", { /* ... */ });
await host.shutdown();The helper hides the ~50 lines of boot boilerplate that Phase 4 flagged as a
papercut. It loads plugin.manifest.yaml from pkgRoot, spawns the worker
with the declared permissions, and provides an in-process implementation of
ctx.attachments, ctx.s3, ctx.llm, and ctx.logger against the
fixtures.
Permission enforcement
| Surface | Enforcer | Where |
|---|---|---|
| Filesystem read/write | Node --permission --allow-fs-read/--allow-fs-write flags computed from manifest paths | Host process spawn args |
| Network outbound | fetch wrapped inside the worker; networkAllowsHost check on every URL | Worker process |
| Child process spawn | Not granted (--allow-child-process is never set) | Node permission model |
| Worker spawn | Granted (workers can spawn nested workers only via Node's API; AMail's plugins are single-worker) | --allow-worker |
| Env vars | Only INSTANCE_ID, AMAIL_AGENT_EMAIL, plus permissions.env.required are forwarded | Host filters the spawn env |
| S3 / attachments / LLM | No raw SDKs reachable; everything goes through ctx_request round-trip | ctx-server.ts |
The defense in depth is intentional: the SDK shim is the only surface plugin code sees, and the Node permission model blocks the syscalls that would let a plugin escape the shim.
Versioning + breaking changes
Released via Changesets alongside @amail/plugin-sdk. Major bumps follow a
6-month deprecation window with two preview releases (per plan.md #14). Pin
to a major in production; the SDK is the contract, the host is the
enforcement.
License
MIT — see LICENSE.
