On this page
This is the deep reference behind the compact availability notes elsewhere. Application developers should start with the availability and normalization guide, call one documented API, and treat the protocols below as implementation detail.
Layer map
application code
|-- Node SDK API ----------------- arcane-cli-events/1 + SDK results
|-- EventManager ----------------- synchronous bus + arcane-event-stack/1
|-- browser-local AI ------------- WebGPU/WASM/Workers/DBOPFS; no Core grant
`-- globalThis.Arcane
|-- development host -------- development HTTP bridge
|-- Microsoft NT native ----- WebView2 host bridge
|-- Linux native ------------ WebKitGTK host bridge
`-- Android native ---------- Android WebView message bridge
|
`-- Arcane Core/provider boundary
|-- platform services
|-- ArcaneOllama loopback service
`-- explicitly selected cloud APIs
Each downward boundary can add authority and platform capability. None can be inferred merely from a function existing in shared JavaScript.
SDK package and CLI protocols
The npm package API is ordinary Node.js ESM. The CLI and programmatic toolchain share one headless operation implementation. Long-running operations accept before blocking work, own their task, stream structured events with bounded backpressure, emit progress or heartbeats, support cancellation where the underlying operation can do so safely, and surface failure through rejection or a nonzero CLI status.
Machine output uses arcane-cli-events/1. Native planning and providers use:
arcane-target-adapter/1for target adapters;arcane-native-build-plan/1for single-attempt native plans;arcane-native-builder/1for injected native builders;arcane-integrated-toolchain/1for the fixed integrated shared/Core provider.
These protocols normalize orchestration and results. They do not normalize a Windows EXE, Linux DEB, Android APK, and portable directory into the same artifact kind.
Managed browser imports have three supported control-plane entrypoints. The CLI
uses arcane import-map; Node callers use
executeOperation('import-map', options) or
createToolchain(defaults).importMap(options). These are three routes to the
same app-scoped operation, not three import-map formats. Each route discovers
the selected descriptor's directly navigable admitted .html/.htm documents
through the package include/exclude rules and writes one canonical map to the
artifact plus every such document. The current marker is exactly one matching
meta[name="arcane-app-id"]; an unmarked secondary page with an active base
remains admitted under the current secondary-document rule. Wrong or duplicate
explicit identity fails, and the selected page then must pass exact path-relative
base validation.
Included HTML with neither signal is a component fragment and remains a
complete package file.
arcane-os/preference-store and arcane-os/speech-playback are the two
portable subpaths that resolve directly to canonical runtime-module namespaces
from both Node package exports and managed browser keys;
arcane/PreferenceStore and arcane/SpeechPlayback remain their established
browser import-map names. The additional portable arcane-os/speech-text
subpath owns shared speech-input cleanup and has the same
managed browser key. There is
no exported importMapApplication() function, generateImportMap() function, or
arcane-os/import-map package subpath.
The application dependency boundary is conditional. Only an application that
actually consumes Arcane declares one exact published arcane-os version in
its own package.json and resolves it through that project's normal install
into its own node_modules. An application that does not currently consume
Arcane adds no arcane-os dependency solely because of this rule; the user or
governing task may direct that application to adopt Arcane later, at which point
the same app-owned package, install, projection, and artifact boundary applies.
An Arcane consumer never depends on a global install, link or symlink, or
another Arcane OS/SDK checkout. The explicit --sdk-runtime-source checkout is
a temporary development server input only: its path and mutable authority are
not persisted in application package metadata, lockfiles, managed import maps,
or dist. Distribution instead uses the app's installed package and
materializes the complete required SDK runtime,
browser-runtime, and managed-import-map closure inside that app's own artifact.
No application polls for SDK changes.
Installed SDK runtime materialization
materializeInstalledSdkRuntime() is the Node entrypoint for refreshing one
external workspace's checked-in arcane/ projection from its one exact
installed SDK declaration. Import the function through the dependency key that
the workspace actually declares: arcane-os for the canonical package name or,
for example, arcane-sdk for the exact npm:arcane-os@<version> alias. No
application- or Arcane OS-local copier owns this operation.
The operation resolves that declaration while holding the shared
workspace-operation lock, copies the complete runtime and browser-runtime
content, and returns the installed-package location plus the materialized
workspace runtime paths. After the complete runtime replacement, it writes or
replaces semantic arcane.lock.json metadata from the actual installed
dependency name, package name, package version, and alias source.
Materialization writes a complete staging tree before the commit boundary, moves any prior runtime to an owned backup, installs the new tree, and restores the prior tree if commit fails. Cancellation remains effective through the last pre-commit check. Successful whole-tree replacement removes paths absent from the selected runtime content. The lock document describes the selected installation and projected roots; it is not a content-identity or admission record.
upgradeApplication() and arcane upgrade run the application's ordinary
npm upgrade command. They do not independently reconcile the installed SDK
projection, semantic Arcane lock, or managed import map.
Central events and time-travel data
arcane-os/event-manager is host-neutral JavaScript. Its live event path is
synchronous, in-process event-pubsub; it does not select WebView2,
WebKitGTK, Android, HTTP, Core, or a kernel boundary. Optional history uses the
arcane-event-stack/1 data format. That protocol names a diagnostic document,
not a network channel and not the arcane/1 Core RPC
protocol.
Live listeners receive the original arguments. Recording separately snapshots
complete payloads and metadata while redacting credentials and explicitly
protected private fields. Exported stacks can be moved between Node and browser
hosts because parseEventStack() rejects genuinely malformed data before
playback. Review mode emits records, events mode deliberately
re-emits recorded event types, and neither mode restores external host side
effects or DOM state.
Event-stack structure and privacy boundary
Each document carries protocol, sessionId, createdAt, and ordered
events. Each record repeats the protocol/session and carries sequence,
timing, nesting/causation, source/category, payload, metadata, status, and
failure evidence. Recording retains the complete selected session until the
caller clears it or disables recording. Import rejects genuinely malformed or
unsafe structure and grants no Core capability or provider authority.
See EventManager and time-travel review for the callable surface, DOM privacy defaults, playback modes, and recovery behavior.
Browser runtime delivery
External and modern integrated workspaces keep the same application URLs and a
browser-standard import map. Each selected app owns
apps/<id>/modules/arcane.importmap.json; the exact canonical JSON is also
embedded in its HTML entry as a managed <script type="importmap" data-arcane-import-map>. The map follows <base> and precedes module scripts,
classic scripts, and module preloads, so application code can use stable named
imports such as:
import ollama from 'arcane/Ollama';
The physical-v1 tree lives entirely beneath arcane/. SDK 0.5.17 projects the
complete canonical runtime and browser runtime selected by the installed SDK
package. Runtime dependencies stay under
arcane/dependencies/; the SDK event and browser-AI closure stays under
arcane/sdk/. This URL-key separation prevents runtime and SDK dependency
versions from aliasing one another.
The physical workspace route keeps its established route count and order. The
external route includes components, css, dependencies, entities, img,
modules, and sdk, followed by optional trailing security when that
directory exists; its external license route remains second. The modern
integrated physical route uses the same ordered include list in its one route.
Omitting only that final optional entry is compatible. Removing, reordering, or
renaming any preceding entry changes the physical contract.
The 0.5.17 map derives its complete entries from the selected runtime graph;
application source imports do not select a fixed entry count. The operation
result reports imports, entryCount, and excludedModules; reached-file
traversal remains internal. The
managed graph exposes arcane-os/event-manager, arcane-os/ai/browser-wasm,
arcane-os/ai/browser-speech, arcane-os/preference-store, and
arcane-os/speech-playback plus arcane-os/speech-text; dependency compatibility mappings are added when
runtime or SDK root traversal observes them.
The focused physical targets remain stable when their bindings are reached:
| Browser specifier | Physical target |
|---|---|
arcane-os/event-manager |
./arcane/sdk/event-manager.mjs |
arcane-os/ai/browser-wasm |
./arcane/sdk/ai/browser-wasm.mjs |
arcane-os/ai/browser-speech |
./arcane/sdk/ai/browser-speech.mjs |
arcane-os/speech-text |
./arcane/sdk/speech-text.mjs |
arcane-os/preference-store |
./arcane/modules/PreferenceStore.js |
arcane-os/speech-playback |
./arcane/modules/SpeechPlayback.js |
event-pubsub |
./arcane/sdk/dependencies/event-pubsub/index.js |
./node_modules/strong-type/index.js |
./arcane/dependencies/strong-type/index.js |
There is no arcane-os package-root mapping, bare strong-type mapping, or
catch-all arcane/ prefix. Classic scripts, workers, stylesheets, and other
non-ESM assets use their documented URL or host loading contract rather than
invented package bindings. Development serves the selected app plus the
complete selected tree.
Packaging copies the same map, app entry, and physical content into dist/<id>;
targets never resolve through the consumer workspace's root node_modules/.
The two lowercase static runtime package specifiers above and the shared
speech-text helper are exact npm package exports, so Node and managed-browser
source can share those specifiers
without data URLs, copied modules, or a consumer-owned loader.
generateImportMap() is an internal toolchain operation, not a package export.
The shared app-document owner derives the configured entry plus the
deterministic admitted .html/.htm inventory from the descriptor's package
include/exclude rules. import-map, development, and packaging all reuse that
discovery. One transaction writes the artifact and the same managed
JSON into every selected document. The result reports
documentPaths, documentCount, and files: artifact first, configured entry
second, then additional documents as role:"document". The public CLI keeps
its existing two-option command; callers never maintain a separate page list.
An external package and development server expose the runtime
inventory at /ARCANE_RUNTIME_PROJECTION.json:
const result = {
schemaVersion: 1,
kind: 'arcane-app-runtime-projection',
sdkVersion,
pathPrefix: 'arcane/',
files: [{path}]
};
The projection contains the complete public paths relative to its declared
pathPrefix:'arcane/' (for example, modules/... and sdk/...). It does not
expose the private /ARCANE_APP_RELEASE.json. Genuinely malformed projection
data fails ARCANE_RUNTIME_PROJECTION_INVALID.
External validateWorkspace() results also expose sdkInstallation with
exactly dependencyName, packageSource,
canonicalPackageRoot, packageName, packageVersion, runtimeRoot,
and browserRuntimeRoot. A
workspace may use the canonical dependency name or one exact npm alias such as
npm:arcane-os@0.5.17; the physical package manifest must still identify
exactly as arcane-os@0.5.17. Canonical-plus-alias duplicates, multiple aliases,
links/junctions, indirect package roots, or version drift are reported.
For external workspaces, arcane dev serves the projected arcane/ root,
including arcane/sdk and arcane/dependencies, alongside the selected
application. Integrated workspaces retain their configured physical routes.
The explicit live-source development mapping remains a separate development
path and does not rewrite the installed projection.
The imported module can be pure browser logic, standard-Web-API logic, or a
client of globalThis.Arcane. Import-map resolution is not a new Arcane wire
protocol, Core capability, network authority, or provider fallback. Import
transport and host RPC remain separate layers.
Refresh lifecycle and managed-file commit behavior
Scaffolding (new and init) creates the map. dev refreshes once before
binding. import-map refreshes every admitted document explicitly.
Non-dry-run package, browser build, and paired native packaging refresh
before collecting source. Packaging does not run tests or checks automatically.
Explicit test and check operations read the existing map without rewriting it;
verify, bundle, and browser run do not refresh. Dry-run packaging/build
validates an existing map without rewriting it, and import-map itself has no
supported dry-run.
Generation stages the artifact and every selected HTML document beside their
destinations and uses backups to restore the prior managed files after a
handled pre-commit failure. Success reports committed: true and the complete
managed path inventory. Cleanup failures after commit remain warnings. This is
a handled-error transaction, not a claim of one filesystem-atomic rename for
all files and not a durable crash journal.
When tests are explicitly selected, external app tests receive an
arcane-test-import-map/1 context for that app's managed map. Each isolated
Node child uses the existing loader for managed names and URL-like compatibility
keys. Materialized
modules such as arcane/TimeGuard and arcane/DBOPFS resolve their canonical
arcane-os/event-manager self-import through this managed map; raw Node import
of projected arcane/** files is not a separate public resolution contract.
Unmapped arcane/* and #arcane/* names fail
ARCANE_IMPORT_MAP_UNRESOLVED; ordinary Node exports and test runs without an
app context retain their existing resolution.
No app watches, polls, downloads, or self-updates this map. An active operation's heartbeat is event telemetry only and never regenerates browser state.
Portable AI provider runtime
Application code should select a normalized role, not an internal protocol.
The exported
getAIProviderRuntime() singleton
comes from the selected runtime and owns independent llm, stt, and
tts selections. This SDK release ships browser-WASM LLM and browser
speech provider/2 adapters and also adapts selected TWiN Cloud LLM,
Core-backed Ollama LLM, on-device Whisper STT, and on-device Kokoro TTS routes
into provider/2. There is no cloud speech route;
other native, Core, or cloud routes require an externally supplied compatible
adapter. The singleton itself is not an authentication or capability token. It
normalizes inspection, model authority,
load/unload/dispose, cancellation, stream cleanup, status, and startup
barriers. Each selected provider retains its real execution requirements.
localOnly creates no fallback, and failure in one role never authorizes a Core,
cloud, or different-provider fallback.
For a browser-only LLM,
arcane-os/ai/browser-wasm exposes createArcaneAI()
and an adapter into the same provider-neutral lifecycle. For browser speech,
arcane-os/ai/browser-speech creates independent
Whisper STT and Kokoro TTS providers that register directly with the normalized
runtime. The SDK supplies mechanism; applications retain model/runtime choice,
licenses, prompts, tools, voices, and disclosure policy.
Browser-WASM LLM lifecycle
The shipped browser runtime contains the Wllama JavaScript/WASM engine and its
provider/cache/controller mechanism. It contains no model
weights, default model catalog, CDN fallback, native provider, speech model, or
application profile. The caller supplies each model as a source with
a nonempty ordered file list, so monolithic and split GGUF models use the same
contract. HTTPS redirects are followed and the final HTTPS URL is recorded.
Each member may optionally declare positive bytes for progress reporting and
HTTP Range planning. Declared and observed byte measures remain transfer-local
telemetry; they never validate, admit, identify, hash, or decide cache reuse for
model content.
On load, the DBOPFS store preserves descriptor order while one bounded worker
pool fetches split members or ranges within the selected member. A split member
may use one Range worker, allowing an interrupted shard to resume without
multiplying the configured concurrency. Download progress
retains its existing completed-file fields and adds raw aggregate bytes,
remaining bytes, rolling bytes per second, ETA seconds, active transfer
workers, the transfer limit, and the active transfer mode. Chunk-driven changes
are coalesced on a 250 ms cadence; start, plan/total, active-worker, and
completion boundaries may publish immediately. A source member that receives a redirected 200 probes the final URL
directly before reusing the original response as its single-fetch fallback.
Confirmed support uses deterministic OPFS Range parts of roughly 4 MB each, up
to 4,096 parts per member, with bounded active workers; completed parts and
split-model members survive interruption so a retry fetches only missing work.
Only unfinished active parts restart after refresh. Without usable range support
or an observable or declared total it falls back to one full fetch. A normal
cache miss may fetch only the
caller-supplied HTTPS sources; offline:true performs no model request and uses
only a compatible completed cache, otherwise it rejects with
ARCANE_AI_MODEL_OFFLINE_MISS. Unload releases the active Wllama session but
does not silently delete the app-owned cache. A complete whole member supersedes
its current resumable fragments. Cleanup failure is warned without hiding the
usable model.
SDK 0.5.17 requires WebGPU. Load requests full offload and waits for the runtime
to report a loaded model. navigator.gpu presence alone is
not readiness. There is no CPU fallback, partial-offload success mode, or
silent switch to native/Core/cloud inference.
Browser speech lifecycle
The browser-speech package contains plain-JavaScript authority, DBOPFS store,
provider, client, and Worker machinery. It redistributes no Whisper, Kokoro,
ONNX, model, voice, third-party license, or corresponding-source payload.
Default upstream integrations use createBrowserSpeechAuthority() with a
version-pinned npm/package runtime entry and optional upstream wasmPaths;
the selected runtime then downloads models and voices through its normal
provider fetch and browser cache behavior after explicit load().
createBrowserSpeechArtifactGraph() is an ordinary materialization descriptor.
Browser speech uses the caller-selected upstream runtime, model, voice, Fetch,
cache, and Worker behavior.
Ordinary module routing preserves bare import specifiers for native import-map
resolution and leaves bare fetch, caches, and Worker calls unchanged when
the module declares a shadowing binding with the same name. Explicit
globalThis or self calls continue through the materialized-file router.
The speech Worker uses its ordinary global Worker message boundary directly for
requests, results, errors, and cancellation. It creates no private
MessageChannel and publishes no Worker progress transport.
Worker operations use arcane-ai-speech-worker/1. The public Worker client
supports load, use, status, unload, and dispose; the transport host
additionally supports its internal cancel control. Every other operation
rejects with code ARCANE_AI_INVALID_REQUEST, message
The speech worker operation is not part of its protocol., and role-specific
reason stt-worker-operation-unknown or tts-worker-operation-unknown.
Failures use the separate
arcane-ai-speech-worker-error/1 envelope. Its cause-free form has the four data
properties code,message,protocol,reason; the diagnostic form may add one cause
data property containing the complete serialized diagnostic, including cycles.
The protocol, registered code, nonempty message, reason, role, and operation
must agree. A foreign, incomplete, extra-keyed, accessor-bearing, cross-role,
or cross-operation error envelope is rejected and terminates that role Worker.
Nested module Workers use
arcane-ai-browser-speech-artifact-module-worker/1 and report bootstrap
rejection only as artifact-module-worker-bootstrap-rejected.
If the platform cannot clone an exotic cause, the Worker keeps the complete
raw failure in its console diagnostics and retries settlement with the
cause-free four-field envelope. Nested Workers are terminated during role teardown.
Kokoro receives the exact selected webgpu or wasm device through
KokoroTTS.from_pretrained() and retains the caller-selected dtype. Its WASM
path is configured through namespace.env.wasmPaths; Transformers is configured
through namespace.env.backends.onnx.wasm.wasmPaths. Ordinary mode may use a
caller-selected version-pinned upstream directory and preserves the runtime's
browser cache. Optional numThreads is caller-owned and
Transformers-STT-only; a Kokoro declaration rejects with
ARCANE_AI_KOKORO_ENV_NUM_THREADS_FIELD_NOT_EXPOSED /
kokoro-env-num-threads-field-not-exposed. Missing or rejected namespace
shapes report distinct *-unavailable and
*-assignment-rejected reasons for each setting; the Worker never
substitutes a different namespace. The caller also owns dtype, STT input sample
rate, TTS output sample rate, default voice, and the complete voice inventory.
Kokoro execution defaults to {device:'auto',maxConcurrentRequests:4} and may
be overridden with webgpu or wasm and an integer capacity from 1 through 4.
Automatic selection attempts a complete WebGPU pool only when WebGPU is exposed,
then tears it down and forms a complete WASM pool if WebGPU loading rejects. It
does not change the selected runtime, model, dtype, or voice.
Each capacity slot owns one Worker/model session. The provider-neutral runtime admits the first four requests and retains segment 5 and later in its FIFO queue without dropping content. Synthesis may finish out of order; high-level AI playback waits for earlier segments and schedules the contiguous ready prefix in exact input order. More sessions trade memory for latency, without promising physical GPU kernel overlap.
Applications using AI.configureBrowserSpeech() can read
ai.providerRuntime.status('tts', {execution:true}).execution instead of
reaching into provider internals. The optional provider snapshot exposes
Kokoro's requestedDevice, selectedDevice, maxConcurrentRequests, and
activeRequestCount. The default status() retains its original sticky-state
behavior; explicit execution inspection does not load a provider or emit a
state event. See browser speech for complete examples.
The SDK is not the distributor of the selected upstream speech packages or provider assets and does not republish their legal/source payloads. Package, model, voice, and version selection belongs to each consuming application, not to a shared SDK component ledger or execution/publication gate.
Whisper stt and Kokoro tts each own catalog, inspect, status, load, request,
unload, and dispose state. They load, cancel, unload, fail, and recover
independently from the LLM and from one another. Whisper owns one Worker and one
request. Kokoro owns a bounded pool of distinct Workers and loaded model
sessions because the selected browser adapter serializes inference inside one
JavaScript isolate. Pool loading first completes one model session, then loads
the remaining Worker sessions concurrently against the same prepared artifact
selection. One Kokoro request cancellation suppresses only that result and
sends the targeted Worker cancel control; upstream may still finish work
already inside generate(). Kokoro unload terminates the whole pool. Whisper
cancellation after Worker use begins retains destructive Worker teardown. If
shared STT Blob decoding is cancelled before Worker use, the request rejects
while the loaded provider remains ready.
Speech failure neither disables text chat nor retries through another local,
native, or cloud provider. The provider/Worker layer is event-neutral: it
exposes promises, AbortSignal, and precise lifecycle/status records, but owns
no event bus or listener registry. The provider/2 load context accepts an
optional progress callback for interface compatibility; the current
browser-speech artifact and Worker transport publishes no progress records.
Persistent chat and document context
The SDK runtime owns
DBOPFSDocumentLibrary,
DocumentLexicalSearch, and
PersistentAIChatSession.
DBOPFS JSONL parsing preserves every nonblank unreadable row as its original
string. Persistent chat can therefore expose the complete saved transcript for
application-owned inspection and recovery while rejecting that row from
provider-facing history with a coded persistence error.
Document bootstrap is explicit and schema-driven, commits a completed
generation last, and returns complete search results with partial read failures
disclosed. evaluate() can instead score a caller-owned source set without
persisting its bodies.
A chat session never searches the corpus unless the application
deliberately wires a document context builder into the request; generated
document context remains labeled untrusted.
Persistent chat maintains recurring model context plus a sanitized ChatEntity
transcript according to the caller's persistence choice. Structural calls, IDs,
argument envelopes, and raw results exist only through the one active provider
continuation that requires them. When that continuation settles, recurring
model context replaces the protocol exchange with its complete user-facing call
messages, any supplied public result messages, and the model's visible response.
Reasoning, request metadata, raw protocol, and raw tool returns do not recur.
Durable user and assistant turns retain only role, complete visible content, and
timestamp.
Durable tool turns retain only role, the required user-facing message as
content, and optional public name and result status. System prompts remain in
the live session only. Existing stored files are not rewritten on load. A turn
with persist:false participates in its one request and response only, then
remains absent from subsequent model context, the retained transcript, memory
extraction, and DBOPFS.
For an automatic model-authored conversation opening, the application calls the
persistent session's open() operation with its internal bootstrap message.
That bootstrap participates in the one provider request only. The operation
durably appends only the complete nonblank assistant response, so the opening
survives reload without a fabricated or retained user turn. A system prompt by
itself is not a retained conversation turn; an existing retained user,
assistant, or tool sequence prevents another opening.
Cancellation and structural tools
Cancellation is part of the provider lifecycle, not just a UI decision.
AbortSignal, the normalized role cancel operation, and stream-handle
cancel(reason) propagate to the selected provider. Browser-WASM inference
requires positive llama cancellation acknowledgement when cancellation is
required. Browser Whisper cancellation terminates its Worker after Worker use
begins. Browser Kokoro uses request-targeted cancellation so one synthesis does
not terminate sibling pool slots; delivery suppression is immediate, while
engine preemption remains upstream-cooperative. Cancellation during shared
browser decoding leaves the loaded Worker ready. Unload always cancels every
active role request before releasing that role's execution state, and
superseded late results are rejected rather than committed or retried through
another provider.
Interactive requests enter a FIFO lane independently for each role. Provider
capacity defaults to 1. A TTS provider may declare a positive safe-integer
maxConcurrentRequests; the runtime admits that many oldest requests and queues
overflow without discarding content. LLM and STT remain capacity 1. A caller
signal cancels only its own queued or active request, while explicit role
cancellation targets the oldest active request. Request-specific ownership
prevents canceled or superseded callbacks from clearing or restoring sibling
state. The runtime revalidates selected-provider readiness and never reloads,
switches, or falls back implicitly. Generic provider-promise settlement is not
a claim that underlying work stopped; only a provider's documented positive
acknowledgement or destructive worker teardown can prove that stronger fact.
startAIRuntime({startLanguageModel:false,startTranscription:false}) is the
explicit startup boundary for browser-WASM LLM and default STT activation. It
leaves the selected LLM unloaded until the shared chat control publishes an
explicit user load intent; the
startup barrier then reports chatReady:false and roles.llm.requested:false
instead of beginning a browser-WASM download. The omitted/default
startLanguageModel:true preserves existing provider startup behavior. The
default startTranscription:false also declines to request a startup STT load
and does not unload a role already started through another
explicit lifecycle action. A selected unloaded
transcription provider remains selected and unloaded until a user lifecycle
intent or explicit startTranscription:true opt-in asks the provider owner to
load it. Neither state observation nor either shared speech component imports a
model or selects a fallback. speech.html and voice-transcription.html consume
one shared createSTTActivationController() contract for selected, unloaded,
loading, unloading, error, and ready presentation plus cancelable user intent.
Both keep capture unavailable until sticky STT state is exactly ready.
Each shared speech component owns an AbortController for its STT request and
passes its signal through AI.fetchSTT(). voice-transcription.html also adds
that signal to the existing injected transcribe(file,context) callback
context. Cancel, readiness loss, superseding capture, and component teardown
abort the owned signal and suppress late delivery. Whether the provider's
underlying computation stops remains governed by its own cancellation contract.
User TTS unmute calls AI.setSpeechMuted(false) before
or with its load intent so the runtime records the unmuted lifecycle preference;
an initialMuted:false component configuration preserves that intent across an
unselected or loading TTS route and exposes unmuted state only after readiness;
mute calls AI.setSpeechMuted(true), cancels active synthesis, and unloads TTS.
The selected local TTS model catalog owns defaultVoice. AI.js never forwards
a saved OpenAI-route voice to Core or browser Kokoro.
LLM tool calls are structural result data only. The SDK never executes a handler. The application owns schema validation, authorization, side-effect policy, dispatch, and the matching tool-result turn.
Ordinary streaming publishes complete nonstructural content and reasoning from every provider choice in order. Complete provider chunks and terminal records remain independently available through the data callbacks. Structural deltas stay private until terminal validation; terminal-only calls are valid, while any observed call must keep the same choice, order, identity, exact argument string, and extension fields at settlement. Awaiting a terminal result before iterating does not stall the private provider stream; projected chunks remain available to the later consumer.
Every first-party function-tool declaration includes
function.parameters.properties.message as a required nonempty string, and
every emitted call includes that plain-language user-facing value in the JSON
encoded by function.arguments.message. The application uses message for the
call's progress, question, or next step; it does not treat raw tool envelopes,
arguments, internal sequencing state, or protocol failures as ordinary
transcript content. An explicitly selected developer inspection surface may
show the raw structure separately. This message does not replace domain
fields such as a closing report's final_message. One assistant response may
contain an ordered array of calls with unique IDs. Display does not settle any
call: one atomic result batch must provide exactly one matching nonblank
executed, declined, cancelled, or not-executed role:'tool' turn for every
pending ID before another user or provider turn.
Portable AI protocol disclosure
The normalized runtime protocol is arcane-ai-runtime/2; registered adapters
implement arcane-ai-provider/2 and select a model before load. The
browser-WASM component protocol is arcane-ai-browser-wasm/2; its
direct controller adapter uses arcane-ai-adapter/1, and
adaptV1LlmProvider() projects that surface into the provider/2 LLM role.
Browser speech stores identify themselves as
arcane-ai-browser-speech-artifacts/1. Direct authorities use
arcane-ai-model-authority/1. Optional browser-speech graphs use
arcane-ai-browser-speech-artifact-graph/1, kind
browser-speech-authenticated-artifact-graph. Those identifiers describe
lifecycle contracts; none is by itself a capability grant.
These identifiers normalize lifecycle records. They do not erase provider availability: browser providers still require their browser capabilities, native providers still require an admitted host and Core method, and cloud providers still require explicit selection, network policy, and credentials.
Arcane application protocol
globalThis.Arcane.protocol is arcane/1. The shared API wraps transport
selection, request ids, JSON-safe values, promise settlement, Arcane.Error,
and renderer events. The current transport snapshot is synchronous:
const {connected, transport, native, managedLocalAI} =
globalThis.Arcane.runtime.current();
Transport values are webview2, webkitgtk, android-webview,
development-http, and standalone. connected means a callable transport
was initialized. It does not prove that Core answered, the method is admitted,
or a dependency is ready.
Native host transports
Microsoft NT / WebView2
The renderer uses the WebView2 host messaging surface. The host binds one app identity and native policy to the session before Core dispatch. Microsoft NT can expose managed-service and privileged platform operations that do not exist in an ordinary browser.
Linux / WebKitGTK
The renderer uses the WebKitGTK host bridge with the same application-facing
Arcane protocol. Linux can implement the same normalized methods through
different host code. Some administrator-owned service settings intentionally
return unsupported/manual guidance rather than imitating Microsoft NT mutation.
Android / Android WebView
Android injects a main-frame, origin-bound bridge for the packaged application. Its generated registry binds application identity, package version, entry, grants, and method policy. Android exposes a narrower surface, including an admitted user-managed local-AI chat projection where configured. Desktop model management is not projected merely because a user-managed Ollama listener is reachable.
macOS
No macOS target, native bridge, Core host, artifact, or run contract is exposed by this SDK version. A browser may still run browser-only application code, but that does not create a native Arcane host or satisfy a native capability.
Development and remote HTTP transport
The development HTTP bridge makes the same application-facing request shape available without pretending the browser is a native host. It is a development transport, not a production isolation or authority boundary. A remotely operated client can use an expressly configured web transport only when the host, origin, application identity, and policy admit it; Arcane does not silently swap native calls to arbitrary remote HTTP endpoints.
When transport changes while the public method remains the same, request settlement and public errors stay normalized. Host-specific availability and result detail remain documented by the method.
Core dispatch and capability admission
The host binds the caller's application identity. Core checks the exact method, required capability, allowed application type/id, privilege, mutation exclusivity, request bounds, and relevant package policy. Renderer-supplied app ids or grants never replace that bound identity.
Arcane.capabilities.list() is the Core-side application preflight. It reports
current grants and admitted methods but does not reserve authority for a later
call. Each call is checked again.
Arcane Ollama protocol path
The safe application path is:
renderer Ollama.js or Arcane.ollama
-> arcane/1 host request
-> Core capability and package-policy admission
-> managed ArcaneOllama loopback service
-> complete Ollama HTTP operation
Applications never connect directly to localhost:11434. Core owns loopback
endpoint selection, method policy, stream ids,
chunk events, model-policy checks, native resource admission, and managed
mutation workflows.
Direct Ollama methods preserve the complete provider-native success envelope.
Arcane normalizes the outer promise/error and stream lifecycle. chatText,
generateText, and readiness are helper-level normalizers.
Explicit cloud provider path
arcane/AI can use an explicitly selected and configured cloud
profile over HTTPS. That path is not Core transport fallback. The module adapts
the selected provider into its high-level application behavior, while provider
diagnostics and optional fields can remain provider-specific. Native policy and
network policy still govern a native renderer's outbound access.
Local failure never authorizes cloud disclosure. The user or owning application must select and configure the cloud provider explicitly.
Events, streaming, and cancellation
Renderer-visible Core events are listed in
the Arcane event reference. Durable
transport.ready and core.ready completions can be observed after the fact
with Arcane.events.when(). Ordinary progress, stream, terminal, and appearance
events are future-only.
Ollama streaming correlates chunks to the originating request. A renderer abort or timeout can stop observation without proving that a non-cooperative host mutation stopped. Method guides state whether Core cooperatively cancels, whether partial provider state can remain, and which status call must be refreshed before retry.
Cross-kernel normalization boundary
The common contract ends where platform truth must remain different:
- API names, promise/error behavior, host capability policy, and public operation events are normalized;
- host availability, privilege model, installation/service mechanism, native artifact kind, and some diagnostic/result fields remain platform-specific;
- unsupported platforms fail or return a documented unsupported state; they do not run an unrelated browser implementation as a substitute;
- this SDK version requires a selected checkout and Core to provide the current native plan's protocol, version, feature, capability, method, and provider;
- that current-build compatibility does not promise that a future SDK will accept this Core or that this SDK will accept a future Core.
Complete-content boundary
SDK runtime, app releases, import-map files, bundles, native plans, providers, and artifacts preserve their complete selected content. Required credential protection, genuinely malformed input rejection, applicable law, external protocol requirements, and host platform safety remain in effect.