# Core, subsystems and manifests

Choose optional entry points and declare each app contract in a file, the shell or its module.

This page describes WU Framework `4.0.0`. Read the [Framework 4.0 and CLI 1.2 migration guide](/docs/guides/releases/) before upgrading an existing project.

<span id="elegir-el-runtime"></span>

<span class="section-anchor" id="section-1"></span>

## Choose the runtime

`wu-framework` loads optional subsystems on first use. `wu-framework/core` requires explicit imports in the shell. CLI `1.0.0` shares the core entry between the shell and apps in both development and production.

```js
import { wu } from 'wu-framework/core';
import 'wu-framework/timeline';
import 'wu-framework/ports';

await wu.init({ apps: [] });
const timeline = await wu.timelineReady();
```

| Feature | Shell import |
| --- | --- |
| AI | `wu-framework/ai` |
| Timeline | `wu-framework/timeline` |
| Devtools | `wu-framework/devtools` |
| MCP | `wu-framework/mcp` |
| `strict` | `wu-framework/sandbox/iframe` |
| `eval` | `wu-framework/sandbox/html-parser` + `wu-framework/sandbox/iframe` |
| Store sync | `wu-framework/store-sync` |
| Shadow | `wu-framework/shadow` |
| Windows | `wu-framework/windows` |
| Drag and drop | `wu-framework/dnd` |
| Ports / remote | `wu-framework/ports` |
| `.wuapp` | `wu-framework/wuapp` |

When an import is missing, `WU_OPTIONAL_NOT_BUNDLED` identifies the subsystem and entry to add. Add it once in the shell and rebuild. Importing an entry registers the subsystem; it does not grant app permissions.

<span id="tres-fuentes-de-manifest"></span>

<span class="section-anchor" id="section-2"></span>

## Three manifest sources

`manifest: "fetch"` is the default and loads `wu.json`. A `manifest` object declares the same information in the shell. With `manifest: "define"`, the module calls `wu.declare` or passes `{ manifest }` as the third argument to `wu.define`; configure `entry` because no earlier file identifies the module.

```js
// shell.js
import { wu } from 'wu-framework/core';
await wu.init({ apps: [{
  name: 'greeting', url: '/apps/greeting/',
  manifest: 'define', entry: 'entry.js', grants: [],
}] });
await wu.mount('greeting', '#greeting-slot');
```

```js
// apps/greeting/entry.js
import { wu } from 'wu-framework/core';
wu.define('greeting', {
  mount(container) { container.textContent = 'Hello from WU'; },
  unmount(container) { container.replaceChildren(); },
}, { manifest: { wu: { permissions: [] } } });
```

The shell HTML must contain `#greeting-slot`; the app module must import the same WU instance as the shell. All three modes validate the manifest and apply host grants. Declaring it in JavaScript does not make the code secret or create a security boundary.

<span id="identidad-al-cargar"></span>

<span class="section-anchor" id="section-3"></span>

## Identity during loading

`definesAs` registers another instance of a module that keeps its original name. During loading, WU redirects `define` and `declare` to the new registration. Only one load can be active per redirected name: `WU_DEFINE_REDIRECT_BUSY`. If a module defines the wrong name, `WU_DEFINE_NAME_MISMATCH` reports the observed names without repeating a timeout that cannot fix the mismatch.

<span id="montar-dentro-de-otro-shadow-dom"></span>

<span class="section-anchor" id="section-4"></span>

## Mount inside another Shadow DOM

`mount(name, target)` accepts a selector or an `HTMLElement`. Pass the element when it belongs to a Shadow DOM: document selectors do not cross that boundary. Recovery and unmount retain the same host; `inspect()` returns `containerSelector: null` for an element mount.

```js
// The shell has already registered and initialized the editor app.
const shell = document.querySelector('my-shell');
const slot = shell.shadowRoot.querySelector('[data-editor-slot]');
await runtime.mount('editor', slot);
// Later, when the shell releases this view:
await runtime.unmount('editor', { force: true });
```

<span id="instancias-con-recursos-propios"></span>

<span class="section-anchor" id="section-5"></span>

## Instances own their resources

Each `new WuCore()` has its own store, memory cache, timing entries and resource hints. `destroy()` releases those resources while preserving other instances. A cache injected with `new WuCore({ cache })` belongs to the caller and is not automatically cleared. For persistence, create a `WuCache` with explicit storage and `namespace`, and decide when to clear it.

Register lifecycles with `runtime.define(...)` on the appropriate instance. Importing the global `wu` singleton registers against the shared host. On an independent instance, await `runtime.timelineReady()` before recording changes. This pattern composes trusted demos in the same page; it does not create a security boundary for arbitrary code.

See [supervision, recovery and replay](/docs/framework/runtime-reliability/) for `superviseApp`, `createReplaySession` and the scoped `reportError`, `now` and `random` methods.

`destroy()` revokes host-minted ports, returns apps from detached windows and releases that instance’s drag and drop, shadow, health, replay and timeline resources. Drag offers and targets are also released when an app’s lease is revoked, including unmount or quarantine.