# Plugin Systems

Plugins, user scripts, formulas, and webhooks-as-code all share one problem: the
author is not you. Secure Exec lets each one run with exactly the access you
decide, and no way to affect the others.

## Declare what a plugin gets

secure-exec/examples/plugins/src/index.ts:

```ts
// Plugins are user-authored source you do not trust. Each one declares what it
// needs, and you decide what it gets.
interface Plugin {
	name: string;
	source: string;
	network: boolean;
}

const plugins: Plugin[] = [
	{
		name: "shout",
		source: `(() => inputs.text.toUpperCase())()`,
		network: false,
	},
	{
		name: "spin",
		source: `(() => { while (true) {} })()`,
		network: false,
	},
];
```

## Run each plugin in its own VM

secure-exec/examples/plugins/src/index.ts:

```ts
// Every plugin runs in its own VM, so plugins cannot see each other's state, and
// a plugin that hangs or crashes only fails its own call.
for (const plugin of plugins) {
	const result = await evaluate<string>(plugin.source, {
		inputs: { text: "hello" },
		permissions: { network: plugin.network ? "allow" : "deny" },
		timeoutMs: 1_000,
	});
	console.log(
		plugin.name,
		result.outcome === "succeeded" ? result.value : result.outcome,
	);
}
// shout HELLO
// spin timed_out
```

- **No shared state.** Each call is a fresh VM, so one plugin cannot read or
  corrupt another's data.
- **Failures stay contained.** A plugin that hangs returns `timed_out`. A plugin
  that throws returns `failed`. Your process keeps running.
- **Per-plugin policy.** `permissions`, `limits`, and `mounts` are set per call,
  so a trusted plugin can have the network while the rest cannot.

## Giving plugins files and packages

Mount read-only data or a shared `node_modules` with
[mounts](/secure-exec/docs/filesystem). For plugins that keep state across
invocations, give each plugin its own [VM](/secure-exec/docs/vms).
