Mysten Incubation
Internals

Lifecycle

How the current runtime boots and stops a stack.

defineDevstack(...) is synchronous. It builds a static stack handle and performs composition-time checks. The runtime path starts when a surface consumes that handle.

Runtime surfaces:

  • devstack up starts a supervisor and stays attached.
  • devstack apply publishes apply.requested to the live supervisor when this stack is already attached; otherwise it starts the same supervisor path in one-shot mode.
  • runStack(stack, opts) embeds the supervisor in another TypeScript program.
import { Effect } from 'effect';
import { account, defineDevstack, runStack, sui } from '@mysten-incubation/devstack';

const stack = defineDevstack({ members: [sui(), account('alice')], stackName: 'embedded' });
const handle = runStack(stack, {
	runtimeRoot: '.devstack',
	identity: { app: 'demo', stack: 'embedded' },
	// Optional: the sanctioned typed seam for extending the run context.
	extendContext: (ctx) => Effect.succeed(ctx),
});

await Effect.runPromise(handle.start);
await Effect.runPromise(handle.stop);
await Effect.runPromise(handle.awaitShutdown);

extendContext is the sanctioned typed seam for layering extra services onto the run context: it receives the built-in plugin context and returns an Effect yielding an extended Context. It replaced the removed { layers } option — reach for it when an embedding program needs to inject its own capability into the supervised stack.

Boot order is derived from dependsOn edges. Members that need Sui depend on the shared sui resource, so the stack includes one concrete sui(...) provider. wallet({ accounts: 'all' }) is expanded after the full member list is known, so it depends on every account member in the final stack.

The supervisor claims roster.json while attached, publishes typed events, maintains a live projection, writes the manifest, emits generated files, and serves commands from the attached TUI and filesystem command channel. Shutdown is attached to the running process: quit the TUI or interrupt devstack up, then scope finalizers run and the roster claim is released.