@plurnk/plurnk-execs
v4.0.3
Published
Framework + contract for the @plurnk/plurnk-execs-* runtime executor packages.
Maintainers
Readme
plurnk-execs
Lean framework and contract for @plurnk/plurnk-execs-* runtime packages. Core
uses it to discover runtime tags, admit calls, and stream each runtime's output
under its own tag-addressed scheme. The default service manifest, not this
framework, owns the standard installed extensions ({§bundled-set}).
Install
npm install @plurnk/plurnk-execsInstall executor extensions beside the framework to assemble a standalone host. Any compatible third-party extension remains discoverable without changing the framework or service.
Documentation
SPEC.md— authoritative executor author and consumer contract.- plurnk-contracts — the execution AST and shared runtime-neutral contracts.
- plurnk-schemes — universal operation results and derived output-scheme contract.
Write an executor
Publish a package under any scope with plurnk.kind === "exec", one or more
runtime declarations, and a default-exported BaseExecutor subclass.
Declare runtime tags
{
"plurnk": {
"kind": "exec",
"runtimes": [
{
"name": "cobol",
"glyph": "🗄",
"summary": "Run a COBOL program.",
"invocation": {
"body": { "role": "COBOL program", "required": true },
"example": { "body": "DISPLAY 'HELLO'." }
}
}
]
}
}One package may claim several tags; the consumer instantiates and probes each
tag independently. A name uses lowercase URI-scheme syntax
[a-z][a-z0-9+.-]*; only is reserved by runtime policy. summary is the
one-line capability description. invocation defines the body and optional
target buckets used for dispatch enforcement and a canonical example for its
generated worker:///_plurnk/plurnk/<tag>.md document. A docs/<tag>.md file supplies
supplemental detail. See {§executor-runtime-declaration}.
For JSON inputs, supply invocation.inputSchema instead of an authored example
or signature. The shared renderer lists required top-level fields and links to
the complete raw schema and description; nested and optional inputs stay in
that on-demand document ({§executor-input-schema-preview}).
Implement the executor
| Runtime shape | Base class | Author-owned hooks |
| --------------------- | -------------------- | --------------------------------------------------------------------------------------- |
| Subprocess | SubprocessExecutor | spawnArgs() and normally binary; stdout/stderr, abort, env, and exit are inherited. |
| Logical or in-process | BaseExecutor | channels, run(), and optional probe() / effect(). |
run() receives only the inputs and consumer-owned sinks in
{§executor-sinks}. Return a universal result; expected failures carry RFC 9457
Problem Details and leave affected channels errored. Honor signal, write
only declared channels, and retain no state between runs.
effect(target) declares one admission fact for the consumer-canonical logical
target. host is proposal-gated; read and pure are automatically accepted.
The consumer preserves the fact rather than asking again after target
materialization. All three then use the same background stream path—automatic
acceptance is not a same-turn result. See {§executor-effect}.
Understand the target
The execution's (target) slot is runtime-specific:
| Runtime shape | Typical mapping |
| -------------- | ----------------------------------------------------------------- |
| Data | Target is input; body is the program (jq, SQLite, WebAssembly). |
| Executable | Target is the program; body is its stdin (shell, Python 3). |
The consumer supplies both cwd and a resolved target; the executor maps them
to its tool rather than reconstructing filesystem or scheme policy.
Own invocation metadata
prepare(input) validates the tool's raw header metadata before admission and
returns the effective cwd. run(args) receives that cwd and the original
metadata, separately from the unchanged body. Source acquisition never inherits
execution metadata. BaseExecutor supplies [{"cwd": "..."}]; SubprocessExecutor adds
literal script arguments with [{"args": ["arg",...]}]. Override preparation for
tool-specific options. See {§executor-metadata}.
Receive live input
In-process executors may call args.registerInput?.(async ({ body, metadata,
signal }) => result) once during run(). Keep the receiver local to that
invocation, honor cancellation, and return a standard SchemeResult for each
delivery. The consumer routes SEND to the existing execution address and owns
ordering, deadlines, permissions, and proposals. This does not expose Worker
identity or grant access to stored output.
SubprocessExecutor supplies this receiver when launched with [{"stdin": "open"}], and
its preparation declares it (input: "open") so the consumer knows a receiver is coming.
SEND writes exact UTF-8 input; [{"eof": true}] ends stdin. No option means ordinary
batch EOF. See the live-input contract.
Address output
The runtime tag is also the output scheme. A subprocess result is therefore
read at an address such as sh:///ab3d5678#stdout, while a structured result may
be sqlite:///f2c49a10#results. Executors only produce channels; the consumer
owns storage and every later READ/FIND. See {§executor-output-address}.
Discovery and policy
discover(options?) scans scoped and unscoped packages under the nearest
node_modules, applies trust before importing any runtimes function, applies boot policy, and
returns { registry, packageAttributions, skipped, disabled }. Tag collisions
fail hard. Static attribution is normalized once per represented package; an
executor may additionally decide per provider attempt whether its synchronous
attributions(context) hook returns no, one, or many opaque tags
({§extension-attribution}).
| Policy | Result |
| ----------------------------------- | --------------------------------------------- |
| PLURNK_EXECS_<TAG>=0 or false | Tag is not registered. |
| PLURNK_EXECS_ONLY=<list> | Only named tags remain; empty registers none. |
| Policy.enabledAcross(tag, layers) | Every layer must admit the tag. |
Policy is subtractive; a downstream layer cannot restore a removed tag. See {§executor-discovery}, {§executor-trust}, and {§executor-policy}.
Exports
BaseExecutor,SubprocessExecutor, andSpawnArgs.discover,Policy,RuntimeTag, and runtime discovery types.ErrorDetailandPLURNK_EXECS_ERROR_DETAIL_LIMIT.- Executor arguments, channel, availability, and effect types.
Results, result types, and runtime-neutral Notice types.
Tests
test:lint, test:unit.
