On this page
The arcane and arcane-os executables invoke the same headless SDK toolchain.
Use the command name that is unambiguous in the current project; project-local
scripts should resolve the exact package version pinned by the app's lockfile.
Every potentially blocking operation acknowledges before it begins, owns its
work, emits progress or heartbeat records, observes cancellation where safe,
and exits nonzero on failure. Machine output is defined by
arcane-cli-events/1.
app-control is the dedicated native-window client described in
native application control. It writes a running JSON
acknowledgement to stderr, then complete result JSON to stdout, or complete error
JSON to stderr and a nonzero exit. Capture writes its image to the explicit
--output filename and returns metadata. Its options are scoped to that command;
the general output-format parser below applies to the other commands.
Inspection accepts either --selector or --request <json-file>; the latter
reads the complete inspection object, including an explicit shadowPath through
open shadow roots. Actions, fixed keys and Normal-window resizing use --request
for their complete parameter object. Keys require the observed document
generation; resize returns actual previous native client dimensions for an
explicit restoration request.
Command inventory
| Command | Scope and result |
|---|---|
arcane new <id> |
Creates one external app workspace. |
arcane init [id] |
Initializes one app in an external or integrated workspace without rewriting unrelated files. |
arcane doctor |
Reads and reports Node/tooling, SDK runtime, workspace, optional Arcane source recognition, and supported managed ArcaneOllama readiness. |
arcane import-map |
Refreshes one app's managed browser import map and every directly navigable descriptor-selected HTML/HTM document. |
arcane upgrade |
Runs the external application's ordinary npm upgrade command. |
arcane dev |
Starts one owned browser development server for one selected app. |
arcane test |
Runs one app test boundary or one explicit integrated shared test file. |
arcane check |
Validates one app boundary or the canonical integrated shared check. |
arcane package |
Creates one browser release, or plans it with --dry-run. |
arcane verify |
Validates one explicitly selected existing browser release. |
arcane bundle |
Creates one deterministic external-app release archive. |
arcane verify-bundle |
Verifies one deterministic external-app release archive without extraction. |
arcane native-doctor |
Diagnoses one explicit native provider and host. |
arcane native-prepare |
Runs one standalone provider toolchain preparation diagnostic. |
arcane build |
Packages, plans, and builds one target artifact. |
arcane run |
Serves an existing browser release, or packages, plans, builds, and launches one paired native artifact. |
arcane update-check |
Performs one explicit, read-only npm dist-tag query for the installed SDK version. |
arcane targets |
Lists target ids, declared status, formats, architectures, signing profiles, methods, and pairing reason. |
arcane app-control status\|inspect\|capture\|act\|key\|resize |
Connects to an explicit running native window endpoint for document inspection, viewport capture, targeted DOM actions, fixed keys or Normal-window client resizing. |
arcane repo status\|pull\|push |
Runs one selected repository operation for the current app workspace. |
arcane mail key set\|status\|delete |
Manages one server-only Resend API-key profile in .arcane.env.json. |
arcane mail send |
Performs one explicit, idempotency-keyed Resend attempt from a complete JSON report on redirected stdin. |
arcane mail serve |
Starts one Arcane-to-Resend gateway with a server-only provider profile, a selected listener, and optional CORS and recipient configuration. |
Parser-wide options
The parser recognizes these names before the selected command applies its own meaning and cardinality rules:
| Option | Value / form | Meaningful commands |
|---|---|---|
--path |
directory | new |
--display-name |
string | new, init |
--workspace |
directory | Commands that select an external or integrated workspace; defaults to .. |
--app |
app id or label | Workspace/app operations except shared scope and verify-bundle; optional diagnostic label for mail serve. |
--apps-root |
. or apps |
new, init; standalone setup defaults to the repository root. |
--sdk-runtime-source |
SDK checkout directory | dev only; maps live SDK source through the selected browser destinations for that server process. |
--local-ai |
comma-separated runtime IDs | dev only; adds llama.cpp, ollama, onnx and/or stable-diffusion.cpp requirements to application configuration and prepares missing runtimes alongside serving. See local AI through Core. |
--arcane-root |
directory | doctor, native build/run, native-doctor, native-prepare |
--host / --port |
host / integer 0–65535 | Browser dev/run default to HTTPS at 127.0.0.1:8000; mail serve defaults to HTTPS with HTTP/2 at 0.0.0.0:4433 and accepts an explicit bind host. |
--http-port |
integer 0–65535 | Browser dev/run HTTP redirect listener; defaults to 0, which selects an available port. |
--public |
flag | dev; binds to 0.0.0.0 unless --host explicitly selects another address. |
--http |
flag | dev only; serves source and PWA routes on one HTTP listener selected by --port, without TLS. |
--https |
flag | Browser dev/run; explicitly selects the default HTTPS transport. |
--cert / --key |
PEM file paths | Browser dev/run; supply both for an explicit certificate chain and private key. Relative paths resolve from the workspace. |
--target |
target id | new, init, native diagnostics, build, run |
--format / --signing |
target-supported values | Native diagnostics, build, run |
--output-root |
directory | Native build and run |
--scope |
app or shared |
test, check; defaults to app. |
--test-file |
repository-relative .test.mjs |
test --scope shared only |
--artifact |
bundle path | bundle, verify-bundle |
--profile |
credential profile id | mail send, mail serve |
--from |
optional sender override | mail send, mail serve; otherwise the report or provider template supplies the sender. |
--origin |
optional exact browser origin | mail serve; selects an explicit CORS allowed origin. |
--allow-to |
optional comma-separated addresses | mail serve |
--report-key |
nonempty string | mail send; caller-owned stable Resend idempotency key, forwarded unchanged |
--request-timeout |
optional integer from 1 through 2147483647 milliseconds | mail send, mail serve |
--output |
human, json, ndjson |
General toolchain invocations; the final occurrence wins. app-control capture instead uses its command-specific output filename. |
--git |
flag | new |
--skip-tests |
flag | check --scope app |
--dry-run |
flag | package; parser-supported on build with the boundary below |
--require-local-ai |
flag | doctor |
--overwrite |
flag | bundle only |
--secret-stdin |
flag | mail key set; requires redirected input |
--report-stdin |
flag | mail send; requires redirected JSON input |
--help, -h |
flag | Prints help and exits zero. |
--version, -v |
flag | Prints the exact SDK version and exits zero. |
Value options accept --name value and --name=value; a bare -- ends option
parsing. Repeated value options currently use the last value, and repeated flags
are idempotent. Unknown names, missing values, excess positionals, invalid
command-specific enums/cardinality, and the explicitly rejected cross-command
cases fail before work begins.
Other recognized but inapplicable options are not yet uniformly rejected. They can be parsed and then ignored by a command. Do not depend on that permissive behavior: pass only the options listed for the selected command.
Output and exit contract
Human mode writes progress and terminal diagnostics to stderr and the selected result to stdout. JSON mode writes accepted/running event envelopes to stderr and exactly one final JSON success or error envelope to stdout. NDJSON mode writes every ordered event, including its one terminal event, to stdout.
Structured payload normalization converts bigint to decimal text and errors
to the public error record, omits functions, symbols, undefined, and cycles,
and keeps repeated non-cyclic values. Exit status is 0 for success, 1 for an
ordinary usage/operation failure, and 130 for cancellation. The separate
arcane-test infrastructure runner uses status 2 for its own infrastructure
failure; it is not an arcane command.
arcane new
Overview
Creates one repository-shaped external application workspace and the selected app. It never creates more than one app or silently installs a global SDK.
arcane new <id> [--path <directory>] [--apps-root apps|.] [--display-name <name>] [--target <target>] [--git]
Options and result
--path selects the new workspace, --display-name sets presentation text,
--target declares one initial target, and --git initializes that exact
directory as a repository. Native target scaffolds also retain browser and
include the required icon. The result reports the workspace, app, descriptor,
target, and created paths.
Each standalone app's root is its repository root. The default --apps-root .
uses the installed npm SDK directly. Explicit --apps-root apps selects a
multi-app workspace with each app beneath apps/<id>. Root setup
does not install dependencies or copy a runtime: run npm install, then
npm run import-map. Until installation, its result reports the import map as
pending with reason sdk-install-required.
Example
npm exec -- arcane new hello-arcane --path ./hello-arcane --target portable --git
arcane init
Overview
Adds missing Arcane application files to one existing workspace. Integrated
initialization writes only the selected apps/<id>/ boundary and does not add
an SDK dependency to the Arcane OS repository.
arcane init [id] [--workspace <directory>] [--app <id>] [--apps-root apps|.] [--display-name <name>] [--target <target>]
Errors and safety
Existing conflicting files, invalid ids, an ambiguous app selection, or an incompatible workspace fail rather than being overwritten. Initialization is idempotent only for files whose existing content satisfies the scaffold contract.
--apps-root . selects root setup for a standalone workspace. Omission retains
the configured layout, or . for a new standalone configuration. init never moves an
existing application or converts the integrated Arcane OS layout.
Example
npm exec -- arcane init reports --target browser
arcane doctor
Overview
Performs read-only Node, npm, Git, SDK runtime, workspace, optional Arcane source-checkout recognition, and supported ArcaneOllama managed-service assessment. It reports unavailable optional capabilities without turning them into packaging failures.
arcane doctor [--workspace <directory>] [--app <id>] [--arcane-root <directory>] [--require-local-ai]
Availability
The SDK/runtime checks are Node. --arcane-root only checks for the
expected Arcane development-lifecycle source marker; it does not load or
diagnose a native target provider. Use native-doctor --target ... for that
boundary. Managed ArcaneOllama inspection currently runs on Windows and reports
unsupported elsewhere. Doctor never installs, repairs, starts, or mutates
Ollama. --require-local-ai changes an otherwise optional local-AI readiness
failure into a failed doctor result.
Example
npm exec -- arcane doctor --workspace . --arcane-root "../Arcane OS"
arcane import-map
Overview
Refreshes one selected application's browser runtime map, generates its standard
browser import map, and prepares the map artifact plus the selected managed
.html/.htm documents before writing them in order. Optional
package.documents in arcane-app.json selects literal app-root-relative HTML
paths that are already included and not excluded. The entry is always first;
[] selects only the entry. Omitting the field retains automatic selection of
the entry and included secondary pages with an active <base>. An app identity
meta tag does not select a page. The renderer requires one path-correct active
base for each selected document.
The schema-1 package projection carries this field as documents, preserving
the distinction between omission and []. With explicit selection, other
included HTML documents keep their exact content, including originals referenced
through iframes. Selection does not change serving, packaging or offline resource
membership; component processing and shared runtime-resource traversal retain
their existing behavior. Inspection, packaging and development use the same
document-selection contract.
Packaging consumes the saved managed import maps in selected source pages.
arcane import-map [--workspace <directory>] [--app <id>]
--workspace defaults to the current directory. --app selects one app when
the workspace does not already identify exactly one. The command accepts no
positional arguments and supports app scope only. arcane-os import-map is the
identical executable alias.
The generated artifact is modules/arcane.importmap.json at a standalone
app's repository root, or apps/<id>/modules/arcane.importmap.json for an
explicit multi-app workspace. Its exact JSON is also installed in
the configured entry and every other admitted browser document as <script type="importmap" data-arcane-import-map> before module loading. The complete
runtime map derives its entries from the selected runtime and browser-runtime
inventories. It intentionally has no package-root mapping;
portable runtime subpaths such as arcane-os/preference-store and
arcane-os/speech-playback instead map directly to their canonical runtime
modules. The result reports the complete map written to the selected
application; no fixed entry count is a release contract.
For appsRoot: ".", managed imports use the installed package paths and enabled
PWA files are written beside the root entry. The SDK generates no nested
apps/<id>/ redirects or duplicate PWA files and no repository-root arcane/
projection. App and installation identity, saved data, and selected authored
files remain unchanged. The same layout applies to arcane dev and
arcane package. Generated and offline app files are committed; GitHub Actions
consume those committed files. See root generated output.
An existing authored source-host index.html suppresses the generated /
navigation alias even when the page is outside the application or offline
selection. It is not automatically added to either inventory or given managed
maps or PWA bootstrap. The selected app entry and installation identity remain
unchanged; see authored host roots.
The supported physical layout preserves its route count and ordered include
list. External and modern integrated physical routes require components, css,
dependencies, entities, img, modules, and sdk; a physical workspace
may omit only an optional trailing security include. The external license
route remains separate and second.
External applications can instead select the four ordered
installed-v1 routes in
arcane-packager.json. This reads directly from the installed SDK package and
requires neither a workspace arcane/ directory nor arcane.lock.json.
Direct routes use the actual node_modules/<dependency>/... browser paths;
an npm alias selects that alias's folder. Earlier virtual routes retain
arcane/, arcane/sdk/, and arcane/dependencies/strong-type/ destinations.
The SDK version comes from the installed package. Existing physical workspaces
and explicitly selected nested scaffolds remain supported.
Result and safety
Success returns the normal selected-workspace wrapper:
const result = {
workspaceRoot,
workspaceMode, // 'external' or 'integrated'
appId,
importMap:{
appId,
artifactPath,
artifactRelativePath,
entryPath,
documentPaths,
documentCount,
imports,
excludedModules:[],
committed:true
}
};
For the direct CLI command, documentPaths contains the configured entry first.
Other selected paths follow in deterministic lexical order without duplicates.
The authored documents declaration remains as supplied, including [].
The generated artifact is written first, followed by the selected documents.
A write failure or cancellation can leave earlier writes in place; the operation
does not restore them automatically. After successful
writes, an observer failure preserves delivery with
eventDelivery.status === 'degraded' and ARCANE_EVENT_DELIVERY_FAILED; it
does not roll back complete application content.
Root new reports a pending map until the SDK is installed. Root init generates
the map when the installation is available and otherwise reports the same pending
state; explicit nested scaffolds generate it during setup. dev refreshes all
selected documents once before binding. package consumes the saved source
and maps; use import-map to refresh them explicitly before selecting output
that needs updated maps. Packaging does not run tests or checks automatically.
Browser build and paired native packaging reuse the package flow.
Explicit test and check operations read the existing map without regenerating it;
verify, bundle, and browser run do not regenerate it. There is no
watcher, polling, scheduled refresh, download, or self-update behavior.
There is no supported --dry-run for import-map: do not pass that parser-wide
flag because this command writes the selected files. Import-map-specific failures
use ARCANE_IMPORT_MAP_INVALID, ARCANE_IMPORT_MAP_UNRESOLVED, or
ARCANE_IMPORT_MAP_COLLISION. Workspace, policy, usage, busy, and
cancellation failures retain their normal SDK codes.
Example
npm exec -- arcane import-map --workspace . --app hello-world --output json
Deep details: browser runtime delivery.
arcane upgrade
Overview
Runs the selected external application's normal npm upgrade command in its
workspace root.
arcane upgrade [--workspace <directory>] [--app <id>]
The SDK delegates dependency selection, registry access, lockfile updates, and installed package changes directly to npm. It does not add a custom Arcane lock, runtime-projection authentication, or import-map reconciliation workflow. Integrated workspaces reject this command.
Example
npm exec -- arcane upgrade --workspace . --app hello-world
arcane dev
Overview
Starts one development server for one selected app and maps the exact
workspace/runtime routes. It defaults to HTTPS on localhost; --public enables access
from other devices on the network, using HTTPS by default.
For an external workspace, the server exposes the selected SDK routes alongside
the application. Direct installed-v1 routes serve the real
/node_modules/<dependency>/... URLs without creating a workspace runtime
directory. Earlier virtual /arcane installed routes remain supported.
Existing physical-v1 workspaces serve
their projected arcane/ root. Integrated workspaces retain their configured
physical routes.
An explicit live-source SDK mapping follows the selected browser destinations
while reading canonical SDK source; it never replaces installed files.
arcane dev [--app <id>] [--public] [--http | --https] [--cert <file> --key <file>] [--host <address>] [--port 8000] [--http-port 0] [--sdk-runtime-source <sdk-root>] [--local-ai llama.cpp,ollama,onnx]
--local-ai saves the selected requirements in native.localAI, or in
arcane-package.json.localAI for a package-only app. Later development runs
reuse them. Available services and executables are reused; missing runtimes
are installed inside the application while serving starts independently.
Applications choose their model files and optional browser Core connection.
--local-ai stable-diffusion.cpp prepares the selected native image runtime;
configure its models separately in the application's runtime record.
The image service reports installation and model
readiness independently, with complete PNG results and explicit cancellation.
See local AI through Core for configuration and native bundling.
Lifecycle
Startup refreshes the selected authored arcane-app.json projection into
arcane-package.json, then refreshes its managed import maps under one
development-refresh operation lock. The lock is released before the server
starts. Package-only apps retain their existing manifest. This operation does
not package the app or produce dist output. With PWA enabled, the server
generates the installation and offline manifests directly; see
PWA development and versioning.
Ordinary operation acquisition can recover a workspace-operation lock whose
recorded process is confirmed absent, including before its six-hour expiry.
Retry the intended command through its usual public entrypoint; no separate
unlock command or caller-created lease is needed. A live or indeterminate owner
remains ARCANE_WORKSPACE_BUSY, with an indeterminate process-probe error
retained as the cause. Recovery rechecks cancellation, nonce, PID and owner
presence after asynchronous observation, preserving a replacement detected
there. This cooperative read-then-remove protocol does not provide an
atomic compare-and-delete across competing processes.
The startup URL remains the selected app entry. At /, the server serves an
existing authored host-root index.html and suppresses the app-entry redirect
and PWA alias. A root outside the selected app mapping is served unchanged only
through this exact-root route; /index.html and other resource URLs retain their
existing selection rules. A selected root follows its existing document
classification. Root presence does not expand either inventory or cause
bootstrap injection. With no host index, the app-entry redirect remains.
Root-file creation or removal is reflected in subsequent root-navigation and
generated-PWA requests without a restart or a descriptor edit.
The command reports acceptance before bind/start work, emits the final URL,
owns the server until cancellation, and restores failure to the process exit.
The default host is 127.0.0.1. --public selects 0.0.0.0 (all IPv4
interfaces); an explicit --host takes precedence. The command prints the
local URL and available network URLs. Use a printed network URL on the other
device, since localhost refers to that device and 0.0.0.0 is a bind address.
Network URLs come from one interface snapshot at startup and do not establish
remote reachability through the machine's firewall or network.
HTTPS is the default for development and packaged browser previews.
The published node-http-server 10.0.0 integration negotiates HTTP/2 or HTTP/1.1
on the same HTTPS port using the configured PEM pair. Source routes, generated
PWA resources, and conditional responses use the same serving pipeline.
Static files retain the module's complete MIME map, including PDF, Markdown,
audio and video. Generated representations use the same published map;
unknown extensions retain application/octet-stream. No application MIME
override is needed for these supported types.
--https remains accepted but is no longer needed to select the transport.
--port selects the HTTPS application port. A second HTTP listener returns
308 redirects to that HTTPS port, preserving the requested path and query.
--http-port selects its port; the default 0 lets the operating system choose
an available port. Both listeners use the selected host and must be ready
before startup completes. Cancellation or a listener failure closes both.
Human output prints HTTP redirect: <url> alongside the HTTPS application URL;
JSON/NDJSON server results include httpPort, httpOrigin, and httpUrl for
the redirect endpoint.
Supplying both --cert and --key selects an explicit PEM pair. The command
does not configure a firewall, router forwarding, or an internet tunnel.
Explicit HTTP development
--http selects source development over HTTP. Combine it with --public or
--host to use a LAN address, and choose the content listener with --port:
npm run dev -- --app hello-world --public --http --port 8000
The command starts one HTTP listener through node-http-server, skips all TLS
file reads, and serves the same selected source files, generated manifest,
service worker and offline inventory. PWA configuration and caching are
unchanged. Startup prints the actual HTTP local and network URLs. Structured
results contain protocol:'http:'; httpPort, httpOrigin, and httpUrl
identify that content listener and equal port, origin, and url.
There is no separate redirect endpoint. Cancellation and listener failure
close the owned HTTP listener and settle the same lifecycle.
--http is supported only by dev. Combining it with --https, --cert,
--key, or --http-port is a usage error. Omitting it preserves HTTPS;
certificate errors never select HTTP automatically.
The public startDevServer() API also accepts http:true in packaged mode;
this does not add a CLI preview command or change dev into packaged serving.
See the API contract.
A LAN HTTP origin does not receive the browser's localhost secure-context
exception. For Chrome development, Chromium documents
chrome://flags/#unsafely-treat-insecure-origin-as-secure with the exact HTTP
origin, such as http://192.0.2.10:8000; see
Chromium's development guidance.
The developer owns that browser setting. The SDK does not change it, alter
certificate validation, or claim a PWA is installable merely because its server
started. HTTP and HTTPS are distinct origins with separate browser storage and
registrations; existing HTTPS data is preserved.
Development HTTPS setup
Before starting HTTPS arcane dev or a packaged browser preview, place the server's
PEM certificate chain at .arcane/dev/server-cert.pem and its PEM private key at
.arcane/dev/server-key.pem, relative to the workspace. Alternatively, pass
--cert <file> --key <file> together. The certificate must cover localhost or the LAN IP
address or hostname opened by each device. Certificate creation and renewal
belong to the developer's certificate tooling; the server does not generate a
CA or alter device trust stores. Keep .arcane/dev/ ignored by Git and keep the
private key on the development computer.
The server reads the selected pair during startup, before binding. Missing files or certificate/key parse errors produce a startup error; Arcane never silently falls back to HTTP. Certificate/key contents are not included in operation events or JSON/NDJSON output. Restart the server after replacing its certificate pair; ordinary app source edits still appear on refresh without restarting.
DBOPFS uses OPFS, which requires a secure context. HTTP localhost is a special case on the device running the server; a LAN HTTP address does not receive that exception. For HTTPS issued by a development CA, each accessing device must trust that CA and use an address covered by the server certificate.
On Android Chrome, transfer only the public CA certificate to the phone. In Android Settings, open the security settings, then **Encryption & credentials
Install a certificate > CA certificate**, and select that public certificate.
Samsung devices may label the entry Install from device storage. Menu names vary by device; Google's Android CA installation instructions show these paths. Then open the printed HTTPS network URL in Chrome. The CA installation is a device action; server readiness does not prove Android trust or remote reachability.
Example
npm exec -- arcane dev --app hello-world --port 8000
# Forward the public option through an existing dev script, for any app id.
npm run dev -- --app hello-world --public
# Equivalent direct CLI invocation, with an optional port.
npm exec -- arcane dev --app hello-world --public --port 8000
# Select a stable HTTP entry that redirects to HTTPS on port 8000.
npm exec -- arcane dev --app hello-world --port 8000 --http-port 8080
arcane test
Overview
Runs exactly one test scope.
arcane test [--app <id>] [--scope app]
arcane test --scope shared --test-file <repo-relative.test.mjs>
Scope
App scope selects only the external workspace test boundary plus the selected
app tests, or only the selected integrated app's tests. Shared scope is
integrated-only and admits one exact repository-relative .test.mjs through
Arcane's fixed provider. It cannot run an arbitrary command, glob every test,
or cross into another app.
External and modern integrated app scope reads the existing managed import map
and selected HTML documents before starting isolated test files. The
Node loader honors only exact managed entries, including arcane/*,
#arcane/*, reached arcane-os/*, and URL-like dependency compatibility keys.
An unmapped reserved Arcane name is rejected before import. The compact map locator is
removed from the isolated child's environment before app test code imports.
Example
node ../arcane-os-sdk/bin/arcane.mjs test \
--workspace "../Arcane OS" \
--scope shared \
--test-file test/component-contracts.test.mjs
arcane check
Overview
Runs the canonical validation boundary for one app, or the one canonical integrated shared development check.
arcane check [--app <id>] [--scope app] [--skip-tests]
arcane check --scope shared
Test behavior
--skip-tests is app-scope-only and skips the selected app test stage without
weakening descriptor, runtime, or source checks. Shared check owns Arcane's
canonical development check and does not accept a custom command.
Example
npm exec -- arcane check --app hello-world
arcane package
Overview
Creates one complete browser release in the app's selected output directory,
defaulting to dist/<id>/, and preserves the prior output until the replacement
is complete. It consumes saved source and managed
import maps, keeps standalone app files at the output root, and retains the
configured shared route destinations. Explicit multi-app workspaces retain
their selected app beneath apps/<id>/. A selected authored output-root
index.html is preserved and suppresses the deployment-root PWA navigation
alias. When selected content supplies no root index, the SDK generates a launcher
and retains the app-entry alias. An excluded source-host root does not change
that package selection.
Source document bases and resource URLs therefore retain their development
layout. Packaging does not run tests or checks automatically.
Set "outputDirectory": "ai" in the selected app's arcane-package.json
to emit directly to <workspace>/ai; the SDK appends no app ID. Omit the field
to retain the default. There is no new CLI flag. The selected directory is
wholly replaced, not merged; choose a directory dedicated to the release.
Changing this setting preserves the old output and its siblings. Source/input
overlap fails before output writes. App identity, source layout, and saved
data remain unchanged. See the output contract.
For installed-v1, the same four configured source routes supply the complete
selected SDK content directly from node_modules. Only the portable output
receives copies; no workspace arcane/ projection is required. Its runtime URLs,
managed import-map targets, and PWA inventory destinations match source serving.
With appsRoot: ".", the planned and actual output retain root-relative app
files and direct npm package paths. The SDK adds no nested app redirects or
duplicate PWA worker/inventory files. Explicitly selected authored resources
and the default packaged installation identity remain unchanged.
arcane package [--app <id>] [--dry-run]
Result
The result includes the release root, manifest, and complete selected inventory.
ARCANE_APP_RELEASE.json keeps the authored app-relative app.entry and records
the package launch URL in app.start: ./index.html for a root app with that
entry, or ./apps/hello-world/index.html for a nested app. The complete file
inventory follows the selected layout and includes the root index.html.
Only selected records supplying an authored output-root index add
app.rootDocument: "./index.html". This optional generated release fact selects
root-document serving in preview; it is not an app configuration or CLI option
and does not change app.start.
--dry-run plans the package without refreshing source, running tests, or
replacing output.
Example
npm exec -- arcane package --app hello-world
arcane verify
Overview
Explicitly validates one selected browser release against the app descriptor, package policy, complete inventory, and malformed-artifact rules.
arcane verify [--app <id>]
Evidence boundary
Verification proves consistency for the exact observed release state. It does not prove publisher authorization, native signing, installation, launch, or release acceptance.
Example
npm exec -- arcane verify --app hello-world
arcane bundle
Overview
Bundles one already packaged external app into the documented
.arcane-app.tar.gz contract.
arcane bundle [--app <id>] [--artifact <file>.arcane-app.tar.gz] [--overwrite]
Replacement behavior
The default archive is <id>-<version>.arcane-app.tar.gz beside the app's
selected package directory. With the default package location, this remains
dist/<id>-<version>.arcane-app.tar.gz. Bundling reads the same selected release
root used by packaging and preview. An existing path
is refused unless --overwrite is explicit. Even then, the prior artifact is
retained until the replacement is complete. A conflicting or uncertain path is
preserved rather than overwritten.
Example
npm exec -- arcane bundle --app hello-world
arcane verify-bundle
Overview
Parses one selected release bundle without extracting it.
arcane verify-bundle <file.arcane-app.tar.gz>
Validation
The verifier rejects genuinely malformed archives, unsafe or colliding paths, unsupported archive members, trailing data, and inconsistent descriptor or inventory structure.
Example
npm exec -- arcane verify-bundle dist/hello-world-1.0.0.arcane-app.tar.gz
arcane native-doctor
Overview
Loads the SDK package provider for portable or windows-x64 by default, or
the fixed provider from an explicitly selected Arcane OS checkout. It diagnoses
selected prerequisites without building an app. Windows uses the matching
precompiled SDK host; Linux and Android retain their checkout/toolchain routes.
arcane native-doctor --target <native-target> [--arcane-root <directory>]
Availability
This is a Node orchestration command with Native provider behavior. The provider fails honestly when the selected platform, architecture, or toolchain is unavailable; it never returns a browser package as a substitute.
Example
npm exec -- arcane native-doctor \
--target windows-x64
arcane native-prepare
Overview
Runs the provider's standalone toolchain preparation diagnostic for one target.
It is not a prerequisite command to repeat immediately before build; build
prepares its own selected toolchain state.
arcane native-prepare --target <native-target> [--arcane-root <directory>]
Example
npm exec -- arcane native-prepare \
--target linux-x64 \
--arcane-root "../Arcane OS"
arcane build
Overview
Packages one app, prepares one provider, creates one plan, and builds one target.
arcane build --target <target> [--arcane-root <directory>] [--output-root <directory>] [--format <format>] [--signing <mode>] [--dry-run]
Cardinality and outputs
The command selects one workspace, app, target, architecture, format, signing
profile, and output root. Current providers emit a portable directory,
Windows x64 EXE bundle, Linux x64/ARM64 DEB, or development-signed Android APK.
The output remains target-specific inside the common plan contract.
Portable uses the SDK package without an OS checkout, copies complete selected
app/dependency payloads and generates the Core entry/classic client source.
It adds no executable platform host or automatically discovered app services.
Windows x64 uses the SDK package provider and its matching precompiled release
asset without an OS checkout or application-side native compilation. See
Windows requirements and artifact layout.
An explicit --arcane-root continues to select the checkout provider.
Integrated builds retain an output root outside the OS checkout; only an
explicit checkout provider must share the workspace root.
The app's outputDirectory selects its packaged browser-content input;
native --output-root independently selects native build output.
--dry-run is implemented for the browser build path. Native builds reject it
rather than returning a fictional native artifact plan.
Example
npm exec -- arcane build \
--target windows-x64 \
--output-root "../arcane-native-output"
arcane run
Overview
For --target browser, starts the existing release in the app's configured
outputDirectory, or dist/<app> when omitted; it
does not package, rebuild, test, check, or verify that release automatically.
It opens the release manifest's app.start URL. Older flat releases without
that field continue to open their app.entry path.
Requests to / serve the explicit app.rootDocument when that generated
release field is present. With no field, including older releases and app-only
packages with a generated launcher, / retains its 302 redirect to
app.start or the older app.entry fallback, preserving the request query.
Preview does not infer root ownership from HTML content.
The preview always uses HTTPS with the workspace certificate pair. Supply
--cert <file> --key <file> together to use another pair; see
development HTTPS setup.
--port selects the HTTPS application port, and --http-port selects the
paired HTTP 308 redirect port. The HTTP port defaults to an available port;
the CLI prints its actual redirect URL and reports both listener endpoints.
The preview uses the same complete node-http-server MIME map as source
development, including PDF, Markdown and supported audio/video types.
For a paired native target, it performs package, prepare, plan, build, launch,
readiness, and owned cancellation in one process.
arcane run [--target <target>] [--app <id>] [--cert <file> --key <file>] [--port 8000] [--http-port 0] [--arcane-root <directory>] [--output-root <directory>] [--format <format>] [--signing <mode>]
Availability
Browser run is Node control plane / browser data plane and requires an
existing packaged release (run arcane package first). Windows, Linux, and
Android providers expose supported paired native run paths. Portable output is
a directory and intentionally cannot run. Android run requires one
connected physical/native ARM64 device for the current target.
windows-x64 uses the package provider by default, launches Arcane.exe, and
streams complete diagnostics. Its cancellation closes input and waits for the
window/Core's accepted work to drain; it does not force-kill that host after a
timer. WebView2 Runtime and .NET Framework 4.6.2 or later must be available on
the Windows execution machine. Linux/Android retain their explicit provider
requirements. Build/launch completion does not prove application domain behavior.
Example
npm exec -- arcane run \
--target linux-x64 \
--arcane-root "../Arcane OS" \
--output-root "../arcane-native-output"
arcane update-check
Overview
Performs one explicit, on-demand check of the installed Arcane SDK version against its matching npm distribution tag.
arcane update-check
This is a maintainer/user query, not app runtime behavior. The command never polls, downloads a package, installs dependencies, changes files, mutates npm configuration, or self-updates. Arcane applications do not run it automatically.
Request boundary
The command makes one ordinary HTTPS GET to the default
registry.npmjs.org origin for the arcane-os dist-tag document and accepts
JSON. The CLI does not expose registry or package overrides; callers of the
public function may select another HTTP or HTTPS npm registry URL.
An installed prerelease version selects the npm dev tag. A stable installed
version selects latest.
Result
Success returns:
const result = {
packageName:'arcane-os',
currentVersion:'0.2.1',
registryVersion:'0.2.2',
tag:'latest',
status:'update-available', // or 'current' or 'ahead'
updateAvailable:true,
registry:'https://registry.npmjs.org',
checkedAt:'2026-08-24T04:00:00.000Z'
};
current means the installed and registry versions match. ahead means the
installed version is newer than the selected registry tag. update-available
means the selected registry version is newer; the boolean is true only for that
status. Reporting availability does not authorize or perform installation.
Events, errors, and cancellation
The normal CLI envelope emits operation.accepted, then
update.check.started. Success emits update.check.completed followed by the
terminal operation.completed result. HTTP failure, timeout,
non-JSON/invalid UTF-8 content, malformed dist tags, or invalid semantic
versions emit update.check.failed and terminate as operation.failed with
ARCANE_UPDATE_CHECK_FAILED and exit status 1.
SIGINT or SIGTERM cancels the owned request. Cancellation terminates as
operation.cancelled with exit status 130; it does not masquerade as an update
failure. Output framing follows the global human/JSON/NDJSON contract above.
Example
npm exec -- arcane update-check --output json
arcane targets
Overview
Lists the current target descriptors without building. Descriptors report
protocol, id, display name, declared status, platforms, architectures, formats,
signing modes, advertised adapter methods, and the reason a target is deferred
or requires pairing. The methods list describes the adapter interface; it is
not a live runnable/readiness probe. Use native-doctor for an explicit
provider/host assessment, and note that portable output intentionally rejects
run even though adapters share the common method shape.
Example
npm exec -- arcane targets --output json
arcane repo
Overview
Runs one repository action for the selected application workspace.
arcane repo status|pull|push
Behavior
status is read-only. pull and push use the repository's already configured
remote and credentials, stream the owned child process, and surface nonzero
failure. The command does not create credentials, choose another repository, or
loop across workspaces.
Example
npm exec -- arcane repo status
arcane mail
Configuration and provider credentials
Mail reads nonsecret settings from arcane.config.json.mail and the Resend key
from .arcane.env.json.mail.apiKey in the invocation directory on Windows,
Linux, and macOS. See Mail CLI parameters for the
complete parameter, configuration-field, default, and precedence reference.
The credential subcommands manage the provider key:
arcane mail key set [profile] [--secret-stdin]
arcane mail key status [profile]
arcane mail key delete [profile]
key set reads the Resend API key from a hidden terminal prompt. The
--secret-stdin form is for deliberately redirected non-interactive input and
rejects a TTY before reading. The key is written to .arcane.env.json and is never
accepted in argv or returned in status output. The optional credential-command
profile defaults to mail, independently of the send/serve configuration.
The minimal .arcane.env.json is:
{
"mail": {
"apiKey": ""
}
}
Fill in the key before starting mail, and add .arcane.env.json to the project's
.gitignore; the SDK repository already ignores it. Keep nonsecret listener
settings, including certificate file paths, in arcane.config.json.mail.
Named profiles remain an optional CLI/toolchain compatibility feature for
selecting another stored Resend key. An exact name selects
mail.profiles[name].apiKey; the name is independent of incoming application
names, domains, and subscription keys. One server process uses one selected
Resend key for all its requests. An absent named key never falls back to the
default account. Existing root RESEND_API_KEY and
MAIL_PROFILES[name].RESEND_API_KEY remain fallbacks when the corresponding
nested key property is absent. A nested property containing null or an empty
string means the selected key is absent and takes precedence over a root or profile key.
Set and delete preserve the file's other settings and profile containers. New
keys are written to the nested mail member. Existing root or profile keys are updated
in place unless the selected nested key property exists; delete removes both
representations of only the selected key. Status returns the selected profile,
provider:'resend', storage:'.arcane.env.json', and exists. Delete returns
exists:false for both a removed and an already-absent credential.
Programmatic createToolchain().mail(...) resolves both files from the directory
selected by cwd ?? workspaceRoot ?? process.cwd(), with no upward search.
This uses ordinary Node file
access rather than platform-specific credential processes. An Android host
supplies a compatible Node runtime and an accessible configuration directory.
Existing Windows Credential Manager records remain untouched; the JSON reader
does not migrate or fall back to them. Mail reads JSON directly and does not
populate or depend on process environment variables for this key.
The SDK's installation directory does not affect this location. With an SDK
under my-site/arcane-os-sdk/, run the command from my-site/ and keep
my-site/arcane.config.json and my-site/.arcane.env.json alongside that
directory. Existing deployments using
SDK 0.22.1 or earlier must rename .env.json to .arcane.env.json while
preserving its contents; the loader reads only the new name.
Each file is an optional configuration source. Missing or empty selected keys
stop send and serve with the
configuration path and exact JSON setting to fill in. Invalid JSON and file
access failures remain observable without printing credential content.
Machine output for key set requires --secret-stdin. Raw CLI arguments are
not included in acceptance events, and usage errors do not echo unknown option
or positional values.
One-shot provider send
mail send performs exactly one Resend provider attempt without starting a
server:
arcane mail send [--profile <profile>] [--from <verified-sender>] --report-key <id> --report-stdin [--request-timeout <ms>]
--report-stdin is mandatory and rejects a terminal before attaching input
listeners. It reads one complete UTF-8 JSON object using the gateway report
shape:
{
"type": "report",
"to": ["recipient@example.com"],
"subject": "Example",
"text": "Message content"
}
The CLI forwards the complete provider fields, including template requests.
Resend owns their accepted shape. The adapter removes the application-only
type field and applies the shared sender from --from or mail.from when
supplied; otherwise the report or provider template supplies the sender. Direct
CLI sending has no configured fallback recipients and requires no listener TLS
paths. It consumes the configured provider timeout and retry guidance.
The Resend credential comes from the selected .arcane.env.json entry.
An explicit --profile overrides arcane.config.json.mail.profile; omitting
both selects the default mail.apiKey, with the root-key fallback described
above. Neither the key nor report content is accepted through argv or process
environment variables.
The caller owns the nonempty --report-key, which is forwarded unchanged.
Reuse the same key only with the same
logical report when deliberately reconciling or retrying an
ambiguous attempt. The CLI never retries automatically.
Exit zero means Resend returned a successful response with a valid provider acceptance id. The result preserves the complete report, provider request, provider response, and available outcome detail without exposing the Resend API key. It proves provider API acceptance, not inbox delivery. Permanent, retryable, and ambiguous outcomes exit nonzero with that same complete available request and outcome detail. Cancellation before the provider attempt exits 130 without sending; cancellation, timeout, or transport loss after the attempt begins is ambiguous because Resend may have accepted it.
Mail gateway
mail serve starts one owned HTTPS gateway with HTTP/2:
arcane mail serve [--profile <profile>] [--from <verified-sender>] [--app <label>] [--origin <exact-origin>] [--allow-to <addresses>] [--host 0.0.0.0] [--port 4433] [--request-timeout <ms>]
The selected .arcane.env.json entry supplies only the server-side Resend API
key. An explicit --profile overrides arcane.config.json.mail.profile;
omitting both selects the default key.
Add the listener's certificate paths to arcane.config.json:
{
"mail": {
"certPath": ".arcane/mail/fullchain.pem",
"keyPath": ".arcane/mail/private-key.pem"
}
}
Supply an existing PEM certificate chain and its private key. Paths resolve
relative to the selected configuration directory, or may be absolute. They
belong to the listener regardless of the provider key selected. Existing root
MAIL_TLS_CERT_PATH and MAIL_TLS_KEY_PATH in .arcane.env.json remain
fallbacks for omitted config paths. Explicit programmatic certPath and
keyPath options override those files. Missing TLS settings name the fields
to fill in before a listener
opens; the TLS owner reports PEM file errors. Keep private-key material outside
tracked source. The SDK repository already ignores .arcane/ and .arcane.env.json.
The selected node-http-server module negotiates HTTP/2 with HTTP/1.1 fallback
on the same HTTPS port, default 4433, with no plain-HTTP listener. Callers use
a hostname covered by the certificate, such as
https://mail.example.com:4433/v1/mail; 0.0.0.0 identifies the bind address.
Restart the gateway after replacing renewed certificate files. Certificate
issuance and renewal remain with the deployment's certificate owner.
The CLI does not read a browser app key. Its optional --app value labels the
server; the incoming request's X-Mail-App identifies the application for
subscription verification. The HTTP authentication contract pairs that
application with Authorization: Bearer <subscription_key>.
Subscription verification is disabled when no callback is configured. The
programmatic createToolchain().mail({action: 'serve', ...}) path accepts
verifySubscription({appName, subscriptionKey, signal}); supplying that callback
enables verification for requests whose actual connection source IP differs
from the server-side IP of that connection. The gateway compares the native
request.socket.remoteAddress with request.socket.localAddress. A nonempty,
equal requester IP skips subscription verification and needs neither a bearer
key nor an application header for that check. No environment setting or domain
lookup is involved. Local development qualifies under the same rule; another
machine on an intranet still needs verification. Missing connection metadata
does not qualify. CORS and the remaining mail requirements still apply.
For requests requiring verification, the callback must resolve to true
to accept the request. An invalid subscription receives 401; verifier service
failure receives retryable 503; cancellation stops verification before sending.
The callback connects the actual TWiN Stripe endpoint when its contract is
ready. There is no guessed URL, response schema, or command-line endpoint flag.
The listener defaults to 0.0.0.0:4433; mail.host and mail.port configure
the listener, and explicit --host and --port override them. Browser mail
defaults to /v1/mail on the current domain. mail.origins supplies an exact
origin array; --origin replaces it with one origin. Repeated --origin
options keep the last value. An absent or empty list selects the current
request authority. Other Origins receive 403 mail_origin_not_allowed;
requests without an Origin continue normally. This CORS configuration does
not filter client IPs or give loopback special treatment.
mail.recipientAllowlist supplies the recipient list; --allow-to replaces it
with a comma-separated list. CLI parsing preserves supplied address spelling
and repeated entries. Programmatic errorTo or mail.errorRecipients selects
fallback recipients for error reports. When neither is supplied, the effective
recipient allowlist supplies that fallback; an explicit empty array supplies
none. The Mail CLI parameters reference also
documents programmatic aliases and list-replacement precedence.
--request-timeout overrides mail.providerTimeoutMs and accepts 1 through
2147483647 milliseconds, the Node timer range. An absent effective timeout
adds no provider deadline; programmatic/configured null also selects no
deadline. mail.bodyTimeoutMs selects the optional request-body deadline.
After binding, server.ready reports lifecycle fields such as
protocol, optional app label, bind address, port, URL, and callerAuthentication
(none or subscription). Human output states whether verification is disabled
or configured; configured verification includes the automatic same-IP exception.
The command owns the server until its lifecycle ends or SIGINT/SIGTERM
cancels it. The server's Resend credential remains outside results and events;
per-request observer events preserve the complete delivery, report, provider
outcome, and failure detail available to the gateway.
See Mail gateway and durable outbox for request, retry, idempotency, DBOPFS, and provider-acceptance semantics.
Machine output
--output json returns one complete JSON document after structured progress is
collected. --output ndjson emits one event record per line as work proceeds.
Human output is presentation only; automation should consume the versioned
machine fields and tolerate documented additive detail.
Every record identifies the CLI event protocol, sequence, operation, phase, level, message, and structured detail as applicable. Acceptance precedes blocking work, terminal completion/failure closes the owned stream, and stdout in machine modes contains no unframed child-process text.
Deep details: SDK/CLI protocols.
Programmatic-only operation names
executeOperation() also accepts plan and native-verify. The CLI parser has
no arcane plan or arcane native-verify route in this SDK version. Call the
documented JavaScript operations directly when that lower-level lifecycle is
required; do not present those names as user commands or infer them from the
parser's recognized option set.