# Control a World from Node

Use the `World` class when your own tool needs to start a World, run an application command,
read its changes and stop compute. The application still uses its real SDKs. `World.run`
supplies its World environment; importing `World` alone does not redirect the parent program.

## Prepare the app

Use Node 22.6 or newer and an app with a selected, initialized World. Follow
[existing-app setup](./use-with-an-existing-app.md) or a complete [example](../../cookbook/README.md)
first. Local use needs no platform account.

The app must have `@volter/world` installed locally. A global CLI installation does not make
the library importable from your app. Keep an existing exact pin; when adding the library to
a new project, use the version selected with your twins in the
[catalog](https://world.volter.ai/twins). Commit its manifest and lockfile.

This program owns the selected branch's compute for its entire run. Start with that World
stopped and stop any app or viewer consumers first. Ordinary `down` retains state.

## Run your command through the library

Save this file in your app folder as `world-workflow.mjs`:

```js
import { World } from '@volter/world';

const command = process.argv.slice(2);
if (!command.length) throw new Error('Usage: node world-workflow.mjs <command> [args...]');
const world = World.open();
if (world.status().running) {
  throw new Error('This program owns boot and teardown. Stop the World and its consumers first.');
}

try {
  await world.up();
  const exitCode = await world.run(command);
  for (const change of world.log()) {
    console.log(change.service, change.operation, change.subject.id);
  }
  process.exitCode = exitCode;
} finally {
  await world.down();
}
```

Pass the application's usual command as separate arguments. For example, after setting up the
[authored AI answer](../../cookbook/ai-messages/README.md#author-the-answer-your-app-needs)
and stopping that World:

```console
$ node world-workflow.mjs node authored-message.mjs
```

The app prints its normal and streamed `billing` answers and handler matches. The program
waits for the app, forwards its exit code and stops the World in `finally`, including when a
library operation throws. It does not reset or purge retained state. A model response is not
a stored conversation, so that example has no vendor mutations to print from `log()`.

For your own app, use its command and inspect the stored changes its SDK calls actually make.
Avoid `process.exit()` in the parent program: it can skip asynchronous teardown. A child
failure is an app result; a thrown library error is a separate lifecycle or routing failure.
[Recovery](./recover-a-failed-call.md) owns diagnosis.

The [SDK reference](../reference/sdk.md) owns methods, arguments, clocks and branch selection.
If another workflow owns an already-running World, use `run` with that owner rather than
having this program take over its lifecycle.
