# Native desktop execution

Bind declared native actions to typed inputs, trusted execution and retained output receipts.

# Native desktop execution

A Block declaring `manifest.desktopTools`, `permissions.desktop: ["native.tools"]`, or a package-level `desktop` mapping requires a trusted desktop executor. Its JavaScript or recipe cannot establish that a native application ran. The generic JavaScript worker and synchronous recipe runner reject these packages with `DESKTOP_EXECUTION_REQUIRED`.

This guard applies conservatively to existing native packages too. Their immutable source, release identity and installed pins are unchanged. A legacy package without the mapping below can retain its reviewed interactive tool controls, but generic connected execution requires a new mapped release. Do not rewrite old package bytes or treat `return {video: input.video}` as a render.

## Declarative input and output mapping

The package's optional `desktop` object is stored as `src/desktop.json` in an editable SDK folder. The package must remain a stateless JavaScript or recipe package with its original sandbox rules, an approved `native.tools` declaration and desktop-only platforms. Version 1 currently supports only Natron adapter 1's `project.render` action:

```json
{
  "schemaVersion": 1,
  "tool": "org.natron.Natron",
  "action": "project.render",
  "arguments": {
    "projectId": {"input": "projectId"},
    "input": {"input": "video"},
    "reader": {"input": "reader"},
    "writer": {"input": "writer"},
    "firstFrame": {"input": "firstFrame"},
    "lastFrame": {"input": "lastFrame"}
  },
  "outputs": {"video": "asset"}
}
```

Each mapped port must be declared in the manifest. `projectId`, `reader`, and `writer` are text; `video` is a video reference; frame ports are integers. All six values must be present after declared defaults and input resolution. Map every declared output to a compatible approved result field; Natron's `asset` is a video. Constants, extra arguments, commands, executable paths, environment variables and scripts are not supported. New native actions require a reviewed host adapter and a corresponding SDK argument/result contract.

The same mapping survives JSON packages, portable archives, editable source downloads, folder/ZIP imports, CLI packaging and verified GitHub SDK-folder import. A mapping alone grants no permission and does not install or launch the application.

## Trusted host execution

The custom interface calls `StillMade.run` with the connected input and render settings. The host supplies the executor to `runPackageAsync`; package code cannot install this callback:

```js
await runPackageAsync(pkg, inputs, {
  signal,
  desktop: async (pinnedPackage, validatedInput, {signal, request}) => {
    const invocation = desktopInvocation(pinnedPackage, validatedInput);
    // Host-owned integration: check exact-source consent, project and media
    // ownership, saved settings, approved operation, completion and artifact.
    const completed = await authorizedNativeHostRun(invocation, {signal});
    const outputs = desktopOutputs(pinnedPackage, completed.result);
    return {
      outputs,
      desktopReceipt: {
        schemaVersion: 1,
        requestId: request.requestId,
        packageDigest: request.packageDigest,
        inputDigest: request.inputDigest,
        outputDigest: await digest(outputs),
        tool: pinnedPackage.desktop.tool,
        adapterVersion: 1,
        action: pinnedPackage.desktop.action,
        executionId: completed.executionId
      }
    };
  }
});
```

`authorizedNativeHostRun` is illustrative host code, not an SDK API. It must perform the real approved native invocation, enforce cancellation and revocation, verify the output artifact and register its media identity before returning. It must not accept a receipt, output URL or claimed process success from Block code as authority. The Block cannot choose the executable, arbitrary path, credentials or permission scope.

`desktopInvocation(pkg, inputs)` returns the declared `tool`, `operation` (`tool.project.render`), bounded argument mapping and output mapping. `desktopOutputs(pkg, nativeResult)` extracts and type-checks the declared results. The SDK pins copied package bytes and validated inputs before calling the host, creates a fresh cryptographic UUID request identity, and checks receipt source/input/action/output bindings and cancellation before returning. `RunPackageResult.desktopReceipt` must be retained with outputs.

Receipt validation proves the envelope's bindings. It is not a cryptographic attestation of Natron, an independent check of stored media bytes, or permission to access another project's output. The trusted host still owns those checks. Host fixture mocks must never be described as native render proof.

## Connected execution, reuse and admission

Native Steps require an interactive connected plan and executor. They form a runtime-approval boundary in ordinary local, independent or background plans. A connected native result without its receipt is rejected even when a caller-supplied generic executor returns correctly typed passthrough output. Retained successful results must keep the receipt bound to the exact package, actual validated inputs and output. `validateDesktopExecutionRecord` checks those bindings during resume/adoption without running the application; host ownership checks remain required. Changes to input, source or output invalidate reuse.

A reviewed condition or failure policy can still skip a Step. Such a record has `skipped: true` and no native receipt: it establishes a skip or fallback, not completed native work.

Offline `validate`, `test`, `pack`, `admitLocalPackage` and `admitPackage` without a desktop executor perform source and fixture-contract checks only. Reports carry `execution: "not-run"`, `tests: 0`, `fixtureContracts`, `liveVerified: false` and `reviewRequired: true`. CLI `preview` and `testPackage` require the real executor to run; an unavailable executor never counts as a passing render. A supplied desktop executor can exercise contract fixtures, but SDK reports still do not claim independent live verification. Execute a representative authorized source through the real application, inspect the exported artifact, and verify downstream receipt and media identity before reporting integration complete.
