Mysten Incubation
Features

Plugins

Current plugin-author entry points.

A plugin is a function that returns a stack member. The root package exports the authoring helpers; contracts and substrate are internal source modules, not package subpaths for app or plugin author imports.

A plugin returned by definePlugin(...) is a { id, role, section, dependsOn?, start, capabilities? } bundle.

  • id — graph identity and the default resource id; the resolved value is published under this id.
  • role — lifecycle classification. 'service' means a long-lived resource (a container, an HTTP process); 'task' means the body runs once at acquire and reaches "done" when start resolves (account, action, package publish). The supervisor uses the role to decide stop semantics.
  • sectionrequired dashboard bucket the plugin's rows belong to: 'service' | 'package' | 'account' | 'action' | 'app' | 'other'. The supervisor stamps this onto every row at acquire-time so the renderer never has to pattern-match on plugin-name substrings. A long-lived resource is usually 'service'.
  • dependsOn — a single plugin/ref, an array, or an object of plugin/refs. Resolved upstream values are passed to start in the same shape — single, positional array, or keyed object.
  • start — the Effect that produces the resolved value. May yield substrate services (ContainerRuntimeService, IdentityContext, StackPathsService) the supervisor provides.
  • capabilities — optional array (or factory) of capability decls: codegenable, snapshotable, routable, strategy contributors, etc.
import { Effect } from 'effect';
import { account, codegenable, definePlugin, sui } from '@mysten-incubation/devstack';

interface CacheResolved {
	readonly url: string;
	readonly tokenAddress: string;
}

export const cache = (signer: ReturnType<typeof account>) =>
	definePlugin({
		id: 'cache',
		role: 'service',
		section: 'service',
		// Resolved values arrive in the shape of `dependsOn`. Here the object
		// keys (`sui`, `signer`) match the keys the start body destructures.
		dependsOn: { sui: sui(), signer },
		start: ({ sui, signer }) =>
			Effect.succeed({
				url: 'http://127.0.0.1:6379',
				tokenAddress: signer.address,
			} satisfies CacheResolved),
		capabilities: ({ value }) => [
			codegenable({
				emitterName: 'cache',
				outputPath: 'cache.ts',
				emit: (ctx) =>
					Effect.sync(() => {
						ctx.exportConst('cache', value);
						return ctx.done();
					}),
			}),
		],
	});

Compose the plugin like any built-in factory:

import { account, defineDevstack, sui } from '@mysten-incubation/devstack';
import { cache } from './devstack/cache.js';

const publisher = account('publisher');
export default defineDevstack({ members: [sui(), publisher, cache(publisher)] });

Use direct plugin/resource references for cross-plugin dependencies — accept the upstream plugin as a value and put it in dependsOn. The resolved value arrives in start in the same shape dependsOn declared.