On this page
arcane-os/native/portable-provider owns the portable native payload in the SDK
package. It does not load Arcane OS source, choose models or compile an
executable. An application's explicit native.localAI selection can include
its selected upstream runtimes through the SDK local-AI installer. Without that
selection, assembly does no local-AI runtime preparation. Windows, Linux and macOS hosts may compose this
Node-based payload; Android needs its separate native host adaptation. The
current CLI's portable platform selections include Windows, Linux and macOS. A portable
artifact is not a Windows executable, Linux package or Android application.
loadArcaneNativeProvider({target:'portable'}) selects the installed SDK provider
without an arcaneRoot. Supplying an explicit arcaneRoot retains the existing
checkout-provider route. The SDK also owns the windows-x64 executable provider
described below. Other native targets remain with their actual platform
providers; the loader does not substitute this payload for an unavailable host.
Provider and selected input
The default export and arcaneNativeBuilderProvider are the same provider.
createPortableNativeProvider({services,packagedWeb=false,webKitDocumentLifecycle=false}) creates one with application-owned
service configuration. Without that override, the provider uses the selected
app descriptor's native.services, or an empty selection when omitted. An
explicit services:[] overrides the descriptor with no app services.
The Mac provider selects packagedWeb:true to compose the SDK's packaged-web
Core service and webKitDocumentLifecycle:true for the canonical classic-client
activation/replay contract. Both default to false, preserving ordinary portable
and Windows composition.
All implement arcane-native-builder/1:
describe()identifies the portable target andexecutable:false.doctor({targetRequest, signal, onEvent})reports missing SDK Core source files.prepare({targetRequest, signal, onEvent})returns the selected SDK version and package root. Neither operation builds or imports application services.build(request)assembles one selected release and its explicit dependencies.verify({artifact, targetRequest, signal, onEvent})explicitly reads its semantic manifest and observes that the listed output files exist. It does not execute a host or establish native behavior. Build does not implicitly run verification.run()reportsARCANE_NATIVE_RUN_UNSUPPORTED; portable is not an executable.
Use the existing createNativeBuildPlan() / executeNativeBuildPlan() public
contract. Build receives appDescriptor, appReleaseRoot, release,
readReleaseFile, dependencies, minimumCoreVersion, protectedRoots,
outputRoot, targetRequest, selectedSdk, signal and onEvent. Dependencies provide their
appId, releaseRoot, release and readReleaseFile. The selected release's
files inventory is copied completely through its supplied reader. Direct
callers may supply the release root for ordinary file reads instead.
Both the current flat signing selection and the CLI's nested signing selection
are accepted by the planning boundary. Portable assembly adds no signing,
receipts, hashes, content limits or security policy. The package-relative source
root comes from the provider module's own location, not toolchainRoot or an
Arcane OS machine bundle.
Native-only application resources
Select application service modules and their complete local source closure in
the authored schema-2 descriptor's package.nativeResources, separately from
its browser include/exclude selection:
{
"package": {
"nativeResources": {
"include": ["native", "src", "package.json"],
"exclude": ["native/drafts"]
}
}
}
This is a descriptor excerpt for the app-owned service example below. The
projected schema-1 field is top-level nativeResources. Paths are literal and
app-relative; directories include descendants. Omission or an empty include
keeps previous selection and output behavior. The app supplies every required
source file explicitly; packaging does not discover or execute services.
Paired buildApplication() passes the actual native target to the selected app
and every explicitly bundled app. With a nonempty native include list, their
input releases use dist/.native/<target>/<app-id> instead of the saved browser
output, preserving existing browser/PWA artifacts. Each app's own selection is
applied; complete releases and actual roots are forwarded to the provider.
The provider then copies them unchanged into its artifact layout described below.
At the low-level packageApp() boundary, target defaults to 'browser' and
is independent of moduleFormat. Nonbrowser selection disables generated PWA
content. Native-only files bypass browser document/module/asset transformations;
a file also in the ordinary browser selection retains that existing processing.
An explicit low-level outputDirectory still wins. Inspect the emitted input
with verifyApp({workspaceRoot,appId,outputDirectory:release.output}); neither
that inventory verification nor packaging launches the service or platform host.
See the complete selection contract.
Output and host contract
Each build assembles in a fresh temporary directory beneath outputRoot, then
publishes the complete artifact to one stable app-specific child. Portable and
Windows outputs use <outputRoot>/<app-id>/; macOS uses
<outputRoot>/<app-id>.app/. The result remains {app, target, manifest}, with
its actual payload directory at target.rootDir and the macOS bundle directory
also returned as bundleRoot. A later successful build replaces that app's
previous generated output instead of accumulating completed build directories.
Windows device-name spellings such as con receive an underscore in the output
folder name (_con or _con.app) on every build host; the app ID stays unchanged.
Assembly leaves the current output available. Publication uses same-filesystem
renames and retains the previous output in a temporary backup until the
native.payload.completed callback accepts the new final paths. A callback
rejection or cancellation restores the previous output; a successful build
removes its backup and temporary assembly. The completion callback runs before
build acceptance, including the following cancellation check; receiving that
event alone does not establish an accepted build. native.payload.started identifies
the temporary assembly, while native.payload.completed identifies the final
payload and, on macOS, final bundle. Manifest paths stay relative to that payload;
application content and explicitly supplied configuration paths stay unchanged.
Only final replacement of the same app is reserved; independent assemblies and
other apps remain concurrent. A competing publication reports the exact
.arcane-publish-<app-output-name> reservation so its owner can finish before
retrying. If recovery or backup cleanup fails, the error identifies the actual
output, assembly and reservation paths, and whether publication committed.
The reservation's owner.json records the process, acquisition time, advisory
five-minute TTL/expiry and recovery locations. Expiry never permits automatic
takeover or deletion. After an interrupted build, inspect those paths before restoring the previous
output or removing the reservation. A running or locked app may prevent Windows
replacement; close that app and retry the build after the reported failure.
Replacement applies only to the matching app's generated artifact directory. Source/release roots, unrelated outputs, host/runtime download caches and the host's separate saved profile/model directories remain outside replacement. Existing randomly named outputs from earlier SDK versions are left untouched; the new stable-output lifecycle does not sweep old directories or user data.
The selected app is copied unchanged under app/. Dependencies are copied
unchanged under dependencies/<index>/; the manifest relates each directory to
its actual app identifier and selected release. No HTML, payload, line ending,
application import, or base URL is rewritten by this provider. Dependency
navigation and service imports remain explicit host/application composition;
the payload does not invent cross-app routes.
node_modules/arcane-os/ contains the SDK consumer source, runtime, schemas,
commands, package metadata and legal files. Its installed published runtime
dependency tree is included with licenses and actual nested dependency
resolution. The generated Core entry uses the ordinary public
arcane-os/core/host import. Application service modules can use those public
SDK exports through Node's normal package resolution. Existing app-owned
node_modules content remains authoritative where the selected app supplies it;
its own dependency completeness remains part of that app's selected release.
For the direct installed browser layout, the ordinary native selection also
supplies selectedSdk:{packageRoot,packageSource} from the application's actual
installed SDK. Assembly completes its browser-only package directory with
missing files and dependencies from that selected package, preserving every
selected file. It never fills an older projection with the builder's newer
package metadata. An already-supplied package.json remains app-owned, without
replacement or automatic completion. manifest.appSdk identifies this app
package separately from the builder SDK. Low-level callers composing services
with a partial direct SDK projection must supply the actual selected package
source; a file inventory alone does not identify its version or Node exports.
No dependency installer or package script runs. No OS model, Shell, Provisioner,
catalog, prompt, or native compiler is added.
The semantic arcane-native.json names the web root, selected start URL, Node
Core entry, classic client, dependencies and complete file inventory. A native
host must:
- Mount
app/at the root of its local application URL origin, preserving the selected start path and all navigable documents. - Inject
runtime/arcane-api.jsat document creation. It is produced by the canonicalcreateCoreClassicSource()generator withreplayRuntimeState:true. Once its transport listener is attached, each document requests the current Core and service state without starting services again. - Start
runtime/arcane-core.mjswith the host's supported Node runtime and connect the existing framed stdin/stdout transport. - Close input and await Core's drain before terminating the child process.
The selected release must contain one shared sdk/event-manager.mjs path,
possibly nested under its SDK payload directory, or the direct installed
node_modules/<package-or-alias>/browser-runtime/event-manager.mjs path.
The classic client imports that
same owner with an origin-root URL, including on nested pages. It does not create
a second event implementation. A plain file-URL launch without this host mapping
is not the native serving contract. No host is launched during packaging.
App-owned runtime entry
The generated runtime/arcane-core.mjs also accepts
--arcane-app-entry <app-relative-module>. This explicit mode imports the
selected file from the artifact's app/ directory before ordinary launch-context
or service initialization. It preserves the complete original process.argv
and converts the native path to a file URL without treating filename characters
as URL query or fragment syntax. Missing/empty selections and actual import
failures propagate; there is no fallback to ordinary Core.
Use the existing Windows runtime/ArcaneCore.exe with that flag and module path
directly. On macOS, use bundled runtime/node with runtime/arcane-core.mjs
followed by the flag and module path. Portable payloads use the host's supported
Node executable with that same generated entry. The macOS artifact root is its
.app/Contents/Resources directory. This mode needs no new executable, SEA
loader, GUI launcher, or copied runtime.
The app includes the module and its complete source closure through
package.nativeResources. The imported
entry starts its own top-level work, not an import.meta.main-guarded entry or
an automatically invoked export. It owns any explicit launch-context read,
application services, MCP tools, signals and shutdown. No ordinary Core host,
shared-host bridge, manifest services, model startup or Core pipe framing is
started by this branch. Static SDK definition imports remain available; the
ordinary parallel service imports and host lifetime stay unchanged when the
flag is absent.
For complete client command arrays, optional --arcane-launch-config handling,
and MCP STDIO lifetime ownership, see
launch from a native package.
Explicit application services
For the ordinary SDK build command, select native service modules in the
application's authored descriptor. Include their source closure through
package.nativeResources as described above:
{
"native": {
"services": [
{"module":"native/moon-ledger.mjs", "options":{"ledgerName":"Cheese debts"}}
]
}
}
Direct SDK compositions can instead pass that selection to the provider:
import {createPortableNativeProvider} from 'arcane-os/native/portable-provider';
const nativeBuilder = createPortableNativeProvider({
services: [{module:'native/moon-ledger.mjs', options:{ledgerName:'Cheese debts'}}]
});
Each module default-exports a synchronous factory returning the existing Core
service definition. Its first argument is the complete authored options record;
its second is the shared launch context described below. Options must be JSON-serializable data. Module imports
and factories run only when the generated Core entry is launched, never during
packaging. Put asynchronous initialization in start(), not a top-level await
or asynchronous factory, so unrelated services and dispatcher readiness remain
independent. Factories own product configuration and any service dependencies;
the packager does not discover, install or execute them.
// native/moon-ledger.mjs, owned by the application
export default function createMoonLedger({ledgerName}) {
return {
name: 'moon-ledger',
methods: {
'moon.describe': function describeLedger() {
return {name:ledgerName, message:'The cheese debts are astronomical.'};
}
}
};
}
startCoreHost({application, version, services, input, output, onError, signal})
is also available directly from arcane-os/core/host. It returns the existing
stdio owner's {runtime, closed, close} without another lifecycle controller.
An optional abort signal invokes that same idempotent drain. Dispatcher readiness
does not wait for service/model readiness. Accepted lifetime:'service' work
survives renderer cancellation and is drained before shutdown. Errors remain
observable through onError and closed; no process is killed or forcibly exited.
See the Core runtime contract for request and service lifetime
details and the client contract for native bridge integration.
Launch-time locations
An application can select defaults for ordinary double-click launch in its descriptor, without a replacement launcher or a required command-line file:
{
"native": {
"launchContext": {
"sharedHost": {},
"dispatch": {"destination": "Moon Cheese Receiving Dock"}
}
}
}
This is the native fragment of the application's complete descriptor. The
optional native.launchContext object is copied intact to the portable
manifest and generated Core entry. Its presence explicitly selects native
location defaults. sharedHost:{} opts into the shared Core endpoint and log;
omitting sharedHost retains stdio-owned Core lifetime. Omitting
native.launchContext retains the previous generated-entry behavior entirely.
Windows and macOS launchers use the same packaged defaults for native state
selection, so an ordinary executable launch and external MCP can select the
same app-owned Core.
To expose the actual window-owned Core to an external local client while
preserving that stdio lifetime, select
native.launchContext:{coreListener:{endpoint:"APPLICATION-SELECTED-LOCAL-ENDPOINT"}}
instead. The generated entry calls
startCoreListener({runtime:host.runtime,endpoint}) after creating its ordinary
stdio host. It reuses that exact service set and launch context, including the
existing origin, profile and state root; no headless runtime is created. The
listener endpoint has no default and its parent directory must already exist
where required by the operating system. coreListener and sharedHost are
alternative selections; supplying both reports TypeError.
That same coreListener opt-in registers one
createModelObservationService() after startCoreHost()
and before binding the listener. It receives host.runtime and the exact
already-created service objects exposing localai.status, image.status and
decisions.status; a configurable decision-service name remains supported.
Absent owners are null. Composition creates no model or second runtime,
performs no service lookup and adds no model-readiness wait. Ordinary stdio
without this opt-in and the existing sharedHost branches retain their behavior.
The application separately calls attachModelObservation() with its existing
renderer owners and Core client; native composition cannot infer those objects.
Observers select onDiagnostic to receive complete live model failure frames
in their developer diagnostic surface. Observation does not start inference or
establish that an existing model failure has been corrected.
Clients use connectSharedCoreHost({endpoint}) with start omitted and close
only their own connection. This listener provides no host-shutdown RPC. Closing
the window still drains its Core, including accepted service-owned operations,
and then closes the listener. Signal-driven host shutdown remains observed while
the listener is binding; a bind failure drains the newly created stdio host and
reports the failure. The generated entry joins listener closure without changing
the existing shared-host/headless branches. See
the existing-runtime listener contract
for direct composition, correlation, cancellation and complete error behavior.
resolveNativeLaunchContext({appId,context={}}) from arcane-os/core/host is
the public, synchronous location owner for native applications and external MCP.
It returns a new complete context and fills only omitted fields:
| Field | SDK default |
|---|---|
stateRoot on Windows |
%LOCALAPPDATA%/Arcane/<appId>; standard home AppData/Local fallback when the environment value is absent |
stateRoot on macOS |
~/Library/Application Support/Arcane/<appId> |
stateRoot on Linux |
Absolute $XDG_DATA_HOME/Arcane/<appId>, otherwise ~/.local/share/Arcane/<appId> |
modelsDirectory on Windows |
%LOCALAPPDATA%/Arcane/Models, with the same standard home fallback |
modelsDirectory on macOS |
~/Library/Application Support/Arcane/Models |
modelsDirectory on Linux |
Absolute $XDG_DATA_HOME/Arcane/Models, otherwise ~/.local/share/Arcane/Models |
modelsDirectory on other adapted hosts |
<resolved stateRoot>/Models unless the host supplies an explicit shared location |
workspaceRoot |
<resolved stateRoot>/Workspace |
sharedHost.endpoint, only when sharedHost is selected |
Windows named pipe \\.\pipe\Arcane- followed by the URL-encoded complete resolved state path; Linux/macOS socket <resolved stateRoot>/core.sock |
sharedHost.logFile, only when sharedHost is selected |
<resolved stateRoot>/Core.log |
Windows/macOS roots retain the existing native host locations. Linux is the
portable Node host convention; an external composing host supplies its actual
state root when it selects another location. Android and other host adaptations
must supply stateRoot explicitly and own native IPC/process adaptation.
The resolver never reads saved preferences, creates directories, changes the
environment, starts services, or migrates existing data. The generated opted-in
shared entry creates its selected state directory because its socket/log need
that parent; application services continue to own workspace I/O. Custom
endpoint/log parent directories retain the existing shared-host requirements.
Models default to one directory per operating-system user, independent of the application ID or app-private state root. Apps selecting the same sources and shared model store reuse the SDK acquisition owner. Preferences, profiles, chat history, workspace and IPC remain app-scoped. Existing app-local models are not moved or deleted: callers can discover and open them in place.
Explicit stateRoot, modelsDirectory, workspaceRoot, endpoint, log filename
and additional fields remain authored values. The resolver derives app-private
paths from the absolute selected state location. Relative explicit paths retain the caller's
working-directory meaning, so UI and MCP callers must select the same location.
No hashing, app-local OS path composition, directory scanning, or new repository
location rule is involved. resolveArcaneDataPaths() continues to own its
separate ArcaneData/Repos contract. A selected native context needs a nonempty
string appId and state directory; a selected sharedHost must be an object.
Malformed resolver inputs report TypeError; ordinary OS endpoint requirements
remain at the IPC operation.
For one app-owned Core shared by the native window and a separate MCP process,
the launch context may explicitly select sharedHost:{endpoint,logFile}. The
generated native child then connects through a stdio bridge, starting an
independent headless Core only when the selected endpoint is absent. Its
endpoint claim precedes application service imports/factories. Closing a native
window disconnects its bridge; explicit shared-host shutdown drains services.
Omitting sharedHost preserves the existing stdio-owned Core lifetime.
See shared Core host ownership for exact startup,
connection, cancellation, diagnostics, endpoint, and platform contracts.
The packaged-web service exposes current() as its active {origin,url,port}
or null; the shared host replays that current listener to a newly attached
macOS bridge, without restarting the server or retaining historical events.
The generated Core entry accepts --arcane-launch-config <path>. The public
readCoreLaunchContext({argv=process.argv.slice(2),defaults={},appId}={})
function in arcane-os/core/host reads that explicitly selected JSON object.
Precedence is packaged defaults, then the native host's actual state-root
argument, then every complete top-level field from the explicit JSON object.
Nested records replace their default field as a whole; they are not deep-merged.
An appId explicitly opts the result into resolveNativeLaunchContext; the
generated entry supplies it only when native.launchContext is present.
A native host
can separately supply --arcane-host-state-root <directory> for the reader's
stateRoot default. Every field in the explicit JSON object takes precedence
unchanged, including an explicitly present stateRoot with a relative, null or
other application-owned value on the ordinary non-resolving reader. With neither
argument nor defaults/appId the reader still returns {}.
Missing files, missing argument values and malformed JSON report their actual
errors; the reader does not search for configuration, resolve or validate the
state directory, rewrite the file or change the process environment. The
explicitly opted-in resolver supplies its documented defaults after this merge.
The generated entry supplies an artifact-derived appRoot and then applies the
complete explicit launch context. Every service factory receives that same
object as its second argument, preserving its authored first argument. A
launcher can supply the user's selected workspaceRoot and writable
stateRoot at launch instead of embedding this machine's paths in an app
package. Explicit product selections take precedence over the opted-in SDK
location defaults. The SDK chooses no saved preference filename or model. JSON values and additional
application-owned fields remain unchanged, including an app-selected
preferencesFile. The state directory supplies no preference filename and
triggers no stored-data discovery or migration. Linux and other composing hosts
may pass the same separate argument; the ordinary reader chooses no platform
directory until native resolution is explicitly selected.
Selected local-AI runtimes
When appDescriptor.native.localAI is present, portable assembly calls the
SDK's bundleLocalAIRuntimes() owner with its runtimes selection and the
requested target platform/architecture. Its reusable installation directory is
<outputRoot>/local-ai-runtimes; each new payload receives the complete selected
runtime trees beneath runtime/local-ai/. Runtime preparation and app copying
proceed independently and both settle before assembly can clean up an incomplete
output. No application service or model executes during packaging.
manifest.core.localAIRuntimes records the bundled runtime locations relative
to the artifact root. Only the explicitly configured entry imports
createLocalAIService from arcane-os/core/local-ai. It resolves those bundled
locations against the installed artifact and supplies them in the launch
context's runtimes array, alongside appRoot, before applying explicit launch
configuration. It passes chat/ONNX requirements to that factory and routes
selected image requirements to their separate service as described below.
Applications without that selection have no generated local-AI import
or service. Availability of a particular engine belongs to the selected
local-AI installer and service; a generic ONNX runtime is not a speech model.
Selected onnx bundles its complete managed onnxruntime-node dependency tree.
For the SDK-selected Windows x64 ONNX 1.30.0 distribution, that tree includes
the corrected native libraries and its runtime record retains
nativeDistributionRevision: '1.30.0-directml-reshape-1'. See
ONNX runtime preparation for selection,
release-asset acquisition and existing-installation behavior.
Its modulePath resolves against the artifact root just as a server runtime's
executable does. Library/module records need no executable. The generated Core
service exposes retained worker sessions through onnx.load/run/unload/status;
model files remain caller-selected application resources. See
native ONNX sessions.
Selecting ONNX, image generation, or both composes one shared
createModelAssetService from arcane-os/core/model-assets. Native application
services obtain that same definition with await context.getService('model-assets').
They obtain the selected local-AI owner with await context.getService('local-ai')
and its current native ONNX handle with getONNXRuntime(). These lookups await
only their selected service startup, independently of renderer readiness. See
native service ownership and cleanup.
Selected stable-diffusion.cpp additionally composes createLocalImageService
from arcane-os/core/image. The image factory receives the full authored
selection plus that same model-assets instance.
Library, Koffi binding and variant paths resolve from the artifact root;
ordinary browser imports use arcane-os/ai/core-image and
arcane-os/ai/core-model-assets through the managed import map.
The runtime bundle preserves the complete selected native distribution and binding tree. It does not load or download a model. Original model URL descriptors remain available for preparation after launch; runtime-contained model paths relocate with the artifact. An external native working path reports its portability incompatibility. Supply those files through the application's native resources or the shared stored-model projection. Native use retains that projection until actual unload or shutdown completes. See local image generation for selection, complete results and CPU/Metal platform boundaries.
Injected native speech engines
Selecting whisper.cpp in native.localAI.runtimes composes the SDK's retained
Whisper engine as STT in the shared speech service. Portable assembly retains
the selected helper, runtime variants and their libraries, FFmpeg decoder and
configured model files under the app's native runtime tree. The executable
host, helper, decoder and models remain separate files; selecting speech does
not embed them inside one application executable. Runtime paths relocate with
the payload. The default Windows x64 preparation uses the matching SDK release's
helper plus its MSVC/OpenMP redistributable closure. Other platforms require
their matching helper, runtime variants and decoder; the public helper builder
uses matching Whisper headers/libraries with the caller's native toolchain.
See native Whisper preparation and packaging. Assembly is
distinct from execution on the target host.
An application-owned service factory can return
createSpeechService({stt,tts,signal}) from arcane-os/core/speech, supplying
either role or both. Include that factory through the existing
native.services and package.nativeResources composition above. The host
constructs its selected engines; this shared service installs no engine,
downloads no model and selects no browser or native speech default.
Core starts both configured role loads independently and remains responsive.
speech.status and replaying service subscriptions report actual loaded-model
state separately for transcription and synthesis. Complete requests/results
are forwarded unchanged. Request cancellation reaches its engine independently
of the service lifetime; close/drain abort and join both engines and their
pending work. Engines must settle cancelled inference before Core reaches
service cleanup. See the engine interface, progress and shutdown contract.
Windows executable
The ordinary application command is:
npm exec -- arcane build --target windows-x64
loadArcaneNativeProvider({target:'windows-x64'}) selects the SDK's own
arcane-os/native/windows-provider without an OS checkout or arcaneRoot.
Its default export and arcaneNativeBuilderProvider are the same provider;
createWindowsNativeProvider({services,hostDirectory}) permits explicit
same-project composition. Service selection follows the portable provider's
descriptor/override contract above.
The provider assembles the selected app with the precompiled host asset
arcane-native-windows-x64.tar.gz from the numeric GitHub release matching the
builder's installed SDK version. The asset contains the launcher, WebView2
support libraries, Node SEA Core executable and required license files. It does
not select the newest host independently of that package. Downloads occur only
during build(), use the caller's output directory, and are reused from
<outputRoot>/.arcane-native-hosts/<sdk-version>/windows-x64. The build machine
needs the standard tar command for extraction; application builds do not need
a C# compiler, system Node installation for the generated executable, or host
source scripts. The SDK build command itself still runs through the application's
normal Node/npm toolchain.
An explicit hostDirectory selects an already-built complete host tree instead
of downloading one. This is useful for SDK collaborators verifying the next
host output; downstream applications use the published package and matching
release asset. doctor() reports the selected prerequisites and missing files;
it does not download the host or probe the installed WebView runtime.
The assembled directory contains the app-named launcher, its matching
.exe.config, the unchanged app/ payload, Core runtime and semantic
arcane-native.json. manifest.host.executable is the authoritative relative
launcher name for shortcuts and direct launch. Assembly uses
appDescriptor.displayName plus .exe, such as Moon Cheese Hotline.exe;
low-level compositions without a nonempty string display name use the app ID.
Windows-reserved filename characters and controls become underscores, and
reserved DOS device basenames receive an underscore prefix. Supported Unicode,
case and spaces remain; the original descriptor and title are unchanged.
The reusable host archive/cache retains Arcane.exe and Arcane.exe.config;
the internal runtime/ArcaneCore.exe also keeps its original name.
Launch the manifest-selected executable on Windows x64 with the Microsoft
Edge WebView2 Runtime installed. It opens the selected
app in WebView2 and owns its framed connection to the bundled Core process.
verify() observes the assembled files and manifest; it does not execute the
window or prove application behavior. run() reads the saved manifest and
launches that executable, so existing generic-name artifacts remain usable. It
observes complete diagnostics and exit. Cancelling that operation closes its
input, allowing the window and accepted Core service work to drain without a
forced process termination.
Initial native window size
An application can select its initial client area, resizing behavior and state in
arcane-app.json, independently of its page layout:
{
"native": {
"type": "app",
"icon": "img/icon.png",
"order": 100,
"bundledApps": [],
"window": {"width": 1280, "height": 800, "resizable": true, "state": "normal"}
}
}
This is the native portion of the existing app descriptor. Each window
member is optional. width and height are positive integral client dimensions
in logical pixels at 96 DPI; resizable is a boolean. Optional state is
normal, maximized, or fullscreen. These example dimensions are an explicit
application choice, not SDK-wide defaults. Omitting a member retains the host's
existing choice, and omitting window preserves existing startup.
The native registry projection preserves the record; the browser package
projection gains no window controls. Portable and Windows assembly copy the
record to arcane-native.json as window, without changing page or service
content.
The matching Windows host applies the dimensions once on initial load, using
the display DPI and fitting the outer window within the selected monitor's
usable work area. This fit does not impose a persistent maximum size. Explicit
resizable:false uses a fixed frame and disables the maximize control; true
permits ordinary resizing and maximizing. The selected initial state is applied
after this normal-window sizing, so those normal bounds remain available when
returning from maximized or fullscreen. Fullscreen uses a borderless window at
the selected monitor's full bounds, including the taskbar area, without setting
TopMost or requesting activation. Returning to normal restores the retained
normal bounds and original frame, minimize/maximize and control-box settings.
Selecting maximized from fullscreen restores them before maximizing.
Later app/user resizing remains untouched. A composing launcher's Load handler
runs after the initial sizing and optional state selection. Applications can
read or change their own window through
Arcane.window.state() and setState({state}).
The application's saved Settings and their application remain application-owned;
the SDK adds no saved-state or saved-bounds store and does not delay rendering
for those settings. The window's profile, origin and Core lifetime are unchanged.
Direct Windows host composition uses nullable ArcaneHostOptions members
InitialClientWidth, InitialClientHeight, Resizable, and optional string
InitialWindowState with the same semantics. Older precompiled Windows hosts
do not read these options; use the
matching SDK host archive when rebuilding an application. The portable record
is available to platform adapters; this addition implements its Windows host
behavior and leaves window sizing/state on other platforms unchanged. The current
other-platform hosts do not implement this state selection.
Application icon and window colors
appDescriptor.native.icon selects the application's existing app-relative
image. Windows assembly converts PNG images, including a 512-pixel source,
into a derived runtime/arcane-app.ico with 16, 32, 48 and 256-pixel images.
Aspect ratio and transparency are preserved. An ICO selection keeps its
authored image set. The original application asset remains unchanged.
The provider embeds the selected images in the copied app-named executable and records
manifest.host.icon and manifest.host.executableIcon:true. It replaces the
executable's main icon group while preserving other groups, languages, resources
and file content. Conversion uses Node standard capabilities on every assembly
platform; it adds no application compiler, image library or Windows-only build
step. The selected host cache and Core executable remain unchanged.
JPEG/JPG, WebP and other existing descriptor formats retain ordinary assembly.
They currently report native.icon.unsupported through the builder's onEvent
callback, as does a selected executable whose PE layout cannot accommodate the
derived icon. The event identifies the app, icon, target, code and complete
message; manifest.host.executableIcon:false reports that the executable keeps
its prior icon. host.icon then points to the original selected image. This is
an explicit unsupported branding result, not a claim that a generic icon was
replaced. Unreadable files and malformed supported image data report their
ordinary filesystem or image-parser error.
The matching Windows launcher reads host.icon and loads it independently of
Core and page startup. ICO and standard Windows image codecs supply the window
and taskbar icon; JPEG/JPG can therefore work at runtime even while executable
embedding is unsupported. WebP is outside the host's standard image codecs;
runtime support is not promised. A runtime icon error preserves ordinary startup
and reaches complete developer diagnostics as ARCANE_WINDOW_ICON_UNAVAILABLE.
Hosts built before this option was introduced do not read the new icon field.
Arcane.window.setTheme(presentation,{signal}?) changes only the requesting
native window's chrome. The shared ThemeBootstrap supplies computed application
background and text colors without delaying application CSS or rendering.
Direct callers may supply backgroundColor and textColor, each either
{red,green,blue,alpha} or null to restore the platform default. RGB channels
are finite numbers from 0 through 255 and alpha is from 0 through 1. Omitted
fields remain unchanged. The complete presentation follows the existing Core
request transport; the window host handles window.setTheme before forwarding
other methods to Core. No system appearance setting changes.
Windows 11 build 22000 and later support titlebar background and text colors through DWM. The normal titlebar and window controls remain in place. DWM accepts opaque colors, so alpha values other than exactly 1 report that field as unsupported. RGB values round to the nearest integer, with midpoint values rounded upward. Older Windows versions report the requested fields unsupported.
The result is {platform:'windows',supported,applied,unsupported}. applied
contains only fields accepted during that call, including rounded channels or
null for a successful default reset. supported is true when at least one
field applied; unsupported lists requested fields the platform could not
apply. These results report platform acceptance rather than measured pixels.
An invalid argument uses INVALID_ARGUMENT; a platform API failure uses
ARCANE_WINDOW_THEME_FAILED, preserving complete native details and any
earlier changes in error.details.applied and error.details.unsupported.
The call is not atomic across fields. Existing request cancellation and document
lifetime semantics remain in effect; an already accepted native color change
is not rolled back by later cancellation. See the Core client
for the facade and browser behavior.
Launch configuration
For explicit user-selected workspace/state locations, launch:
"Moon Cheese Hotline.exe" --arcane-launch-config path/to/launch.json
The complete JSON object reaches the service factories as their second
argument. A supplied stateRoot also owns the WebView2 profile and diagnostic
directory. Otherwise the launcher uses the current user's local application
data under Arcane/<app-id>. It forwards that actual host selection through
--arcane-host-state-root, so ordinary double-click startup supplies stateRoot
to every Core service factory. The complete explicit launch context still takes
precedence without rewriting its fields. The launcher does not invent an
application workspace. Relative launch-file paths resolve from the invocation's working
directory. --close-on-stdin-eof is an explicit process-owner option used by the
SDK runner; an ordinary double-clicked window closes through its own UI.
Windows host source and selected output
The SDK's src/core/hosts/windows/ArcaneCoreProcess.cs owns an explicitly
selected executable, argument string and working directory. It reads complete
framed Core messages and diagnostics, acknowledges ordered asynchronous writes,
and closes stdin before awaiting accepted Core work, final output and process
exit. It does not kill the child on an ordinary close.
ArcaneHost.cs composes that process with a WebView2 window through
ArcaneHost.Run(options,onDiagnostic,onError) or ArcaneHostForm. Options
select the app root/start path, stable virtual HTTPS origin, profile directory,
title, optional IconPath, canonical classic-client source and Core process
inputs. The form exposes Ready, Completion and CloseAsync(). Page navigation, transport connection,
Core readiness and service readiness are separate states. Accepted work drains
before the window closes; complete engineering errors go to the supplied
diagnostic/error callbacks. Callbacks must not synchronously wait for the
window's lifetime promises.
A WebView2 BrowserProcessExited failure retains its complete diagnostic,
fails a pending Ready, and begins the existing Core drain and window close.
It does not wait for a user to close a blank window or invoke document callbacks
and script cleanup in the closed browser. The launcher reports the failure
after that drain. Main-renderer exits and Core-only transport failures retain
their existing handling. This terminal-flow correction does not identify or
prevent the underlying browser-process exit, restart the application, or change
its profile and saved data.
ArcaneLauncher.cs supplies the executable entry point for that composition.
An explicit native.launchContext.appControl.endpoint enables the current
Windows window's background document-control listener. The public client and
CLI inspect, capture and act on that existing WebView without selecting a desktop
window or changing its Core/profile. See native application control
for launch configuration, document generations, cancellation and platform scope.
tools/build-core-windows-host.mjs builds the selected SDK host output from the
approved WebView2 package, existing .NET Framework compiler and selected Node
SEA output. It retains complete compiler diagnostics and produces a fresh
directory rather than overwriting an earlier artifact. The host requires
.NET Framework 4.6.2 or later. This is SDK release tooling, not an application
build requirement. Source compilation, selected host execution and real
application behavior are separate evidence boundaries; an assembled app is not
an installer or proof of its domain behavior.
Linux, macOS, Android dispatch and each platform's output verification retain their separate delivery boundaries. Published consumers must adopt the numeric package that includes this increment; a source checkout or a successful source push is not that public package authority.
macOS process source
src/core/hosts/macos/ArcaneCoreProcess.h and .m provide a Foundation-only
adapter for macOS 11 or later, compiled with Objective-C ARC and blocks. A
composing host explicitly supplies the executable URL, arguments, working
directory and delegate; startup is asynchronous. Delegate callbacks deliver
every raw stdout/stderr chunk and complete opaque framed JSON bodies, plus
launch, error, exit and final completion observations. Each stream and accepted
write retains its own order; UI dispatch belongs to the host. Callbacks must
return normally and must not wait for another callback or completion.
sendJSONData:completion:error: accepts an ordered write or reports a
synchronous rejection. Write completion means the frame reached stdin, not that
the RPC succeeded. closeInput rejects new sends, finishes accepted writes and
closes stdin, then keeps observing output and child exit without a forced
termination deadline. The delegate is retained through final completion.
The AppKit ArcaneHost and launcher compose that source as described below.
Compilation and execution on macOS remain separate evidence from the selected
Windows output.
macOS application composition
arcane-os/native/macos-provider exports
createMacOSNativeProvider({services,hostDirectory}={}), its named
arcaneNativeBuilderProvider, and the same provider as default. The six-method
contract accepts macos-arm64 or macos-x64, platform:'macos', format:'app'
and the existing unsigned local development selection. Ordinary CLI routing
uses the SDK package, not an Arcane OS checkout:
npm exec -- arcane build --target macos-arm64
npm exec -- arcane run --target macos-arm64
Select macos-x64 for Intel. The descriptor must declare the selected target.
Source implementation does not establish that an architecture's host artifact
has been built, executed or published. Consumer assembly needs the exact numeric
SDK release asset arcane-native-macos-<architecture>.tar.gz; unavailable assets
produce their actual download error. SDK collaborators may select an existing
hostDirectory explicitly. There is no fallback to source checkout, another
version, another architecture or a browser-only artifact.
The complete unchanged portable payload lives at
<outputRoot>/<app-id>.app/Contents/Resources/. That directory remains target.rootDir and
contains arcane-native.json, app/, dependency releases, installed SDK files,
Core entry/client and runtime/node. The additive bundleRoot identifies the
.app directory. Contents/MacOS/Arcane and Contents/Info.plist belong to the
bundle rather than the web root; the Mac owner checks these separately from the
Resources file inventory. Application identity supplies the stable bundle ID
org.arcane.<app-id>. Executable permissions are preserved for the launcher and
selected Node runtime.
The launcher opens its window immediately and starts one Core child. The
generated Core entry starts the packaged-web service alongside application
services, without waiting for models. Only core.web.ready, emitted after the
actual listener is ready and the initial port is saved, supplies the application
URL to WebKit. It serves the complete manifest.webRoot at / and resolves the
complete manifest.start, including query and fragment, against that origin.
The classic client selects current-document activation and sticky state replay;
navigation does not restart the Core service or replay retired requests.
The host's main-thread readonly isClosing accessor exposes its existing close
intent; an unsolicited Core exit is therefore reported separately from an
ordinary user-requested drain, even when the process exits successfully.
createPackagedWebService({artifactRoot}, context={}) is available from
arcane-os/core/packaged-web. It uses the existing
startDevServer({mode:'packaged',http:true,host:'127.0.0.1',port,releaseRoot})
owner and published node-http-server, not a second HTTP implementation.
context.stateRoot takes precedence over the launcher's separate
--arcane-host-state-root argument. The launcher defaults to
~/Library/Application Support/Arcane/<app-id>; an explicitly supplied launch
file remains unchanged and is forwarded to Core. The shared launch reader also
supplies that host default to every application service factory, with explicit
launch fields taking precedence. The first successful listener
stores its selected port in packaged-web-origin.json. Later launches reuse it;
a port conflict or unreadable saved record is reported without changing origins
or discarding stored state.
The app's persistent default WKWebsiteDataStore uses its bundle identity.
stateRoot selects Core state and diagnostics, not a custom WebKit profile
directory. Browser API availability, OPFS and secure-context behavior remain
WebKit-owned and require actual Mac verification; the SDK bypasses no browser
policy. Startup failures use core.service.state for name:'packaged-web';
unexpected listener closure or failure uses core.web.failed with the complete
serialized error. Native alerts show a concise outcome, with full diagnostics
outside the conversation. Core drains accepted work and the listener before
the native close completes. The optional runner stdin-EOF signal uses that same
path; ordinary double-click startup does not wait on stdin.
tools/build-core-macos-host.mjs is SDK host-release tooling, not an application
compiler requirement. It accepts an explicit Darwin Node executable and its
license, compiler path, arm64 or x64, and output directory. It uses Objective-C
ARC/blocks and Apple's Foundation, AppKit and WebKit frameworks. The host source
targets macOS 11; the selected Node runtime may require a newer macOS version.
Its actual runtime/platform/architecture and the SDK Node engine requirement
must agree. Compiler/runtime execution and redistribution belong to the
separately authorized selected host output. This source increment runs none of
them and claims no Mac build or execution result.