Arcane OS Docs Development only

Build

Application-building SOP

Required shared-core boundary, theme order, contracts, examples, tests, and capability declarations.

  • Build

Mandatory use: Follow this SOP every time a human or artificial-intelligence (AI) agent is asked to create, copy, or materially change an Arcane app, component, module, entity, style system, asset, model, adapter, service, or other runtime capability. Complete the decision process before implementation begins. Verification follows the current development profile in development-lifecycle.md; release evidence is not required for ordinary development.

Quick execution checklist

Use this checklist for every applicable request. The later sections explain each step and provide the review standard.

  • Restate the need as: “I need to make a capability that allows a user or system to _____.”
  • Search arcane/, example/, and relevant apps/ code for an existing capability to reuse or extend.
  • Decide whether the capability could be useful to another application.
  • List the business logic that is specific to the requested app.
  • Choose how to extract that business logic from the reusable core.
  • Record shared and app-specific file placement before creating files.
  • For visual work, identify the Arcane base theme, user-theme loading, and CSS layer order before writing custom styles.
  • Define or extend the public contract without silently breaking existing consumers.
  • Route every application AI request through the shared provider-neutral AI data-access and normalization boundary; do not construct provider payloads in app code.
  • Treat speech-first interaction as an optional application recommendation; use Arcane Core speech methods and shared playback/transcription mechanics instead of app-local provider code.
  • For corpus work, define the authoritative store, stable full-record batching, independent settlement, partial-success result, actual-item progress, and warning channel before implementation.
  • Give every page-owned asynchronous operation one AbortSignal that reaches the bridge, Core, native host, and actual upstream operation; cancel queued, retry, and continuation work when its page detaches.
  • For a terminal conversation flow, define one always-available closeout tool, one strict final-message schema, separately consented remembered actions, one provenance-purpose gate, and an irreversible completed UI state.
  • Represent validation and provenance modes with centralized closed policy enums and one decision point instead of scattered booleans, bypass flags, or duplicate checks.
  • Complete the work-amplification review: state the cardinality and loop multiplier, classify expensive work, estimate its cold-path count/bytes/time, and design out redundant repetitions.
  • For every integrity claim, name the attacker and independent authenticity anchor; classify adjacent, self-generated, and same-authority digests as consistency evidence only.
  • Define the immediate acknowledgement, owned background execution, bounded concurrency/backpressure, progress/heartbeat, cancellation, and safe retry/resume contract for long work.
  • Implement the shared core first, then the app adapter and orchestration.
  • Name every function, including callbacks, so stack traces identify the operation and its exit condition.
  • Add focused shared and app tests as applicable; add a synthetic example when it materially improves reuse.
  • Import repository JavaScript test registration from the shared vanilla-test 2.1.0 adapter and use node:assert/strict; do not create a second test-runner lifecycle in an app.
  • Update package allowlists, cache references, versions, and machine capabilities only when the changed boundary requires them.
  • Select the source, cache-reference, dist, package, native rebuild, signing, and push gates that the requested artifact actually crosses; do not turn them into an unconditional all-app chain.
  • For local AI, author one localAIModelPolicy in apps/<id>/arcane-package.json, keep every declared Modelfile app-owned, and leave admission and catalog filtering to Core.
  • For an actual demo package, build and verify only the selected app. Run an app's full suite only for that app's release, and run the full Arcane OS gate only for an explicit Arcane OS release.
  • Update docs/arcane-api.md for every added or changed application-facing Arcane native bridge method, following docs/developer-reference-sop.md.
  • Run relevant verification and include the completed capability decision in the handoff.

If any answer is unclear, stop designing files and clarify the boundary. Do not use uncertainty as permission to default to an app-local implementation.

How humans and AI agents use this SOP

Human implementers and reviewers

The implementer completes the required design record in the issue, work note, or pull request before substantive implementation. Reviewers use the definition of done and review gate before approval.

AI agents

An AI agent must read this SOP before taking implementation action on an applicable request. The agent must inspect the repository rather than relying only on the requested filename or assumed architecture. It must make reasonable boundary decisions autonomously when the repository provides enough evidence, and ask the user only when a missing business decision would materially change the result.

The AI agent's final handoff must state, at minimum:

  • the reusable core created, reused, or extended;
  • the app-specific business logic and where it remains;
  • the extraction mechanism used, such as configuration, events, adapters, slots, providers, or record mapping;
  • how the app or component inherits the Arcane base theme and preserves the user's appearance choices;
  • the measured work multiplier, invariant work hoisted or cached, and any justified per-item repetition;
  • how the foreground acknowledges immediately, which owner observes background-task completion, and how progress, cancellation, and errors surface;
  • how provider-neutral AI, authoritative corpus state, terminal closeout, and centralized policy boundaries were preserved when those capabilities are involved;
  • which conditional source, cache-reference, package, native-build, signing, and remote-delivery gates were selected, with the exact artifact state verified at each selected boundary;
  • the verification performed and any checks not run.

If no shared artifact is created for a generally useful capability, the agent must explicitly justify that exception against this SOP.

Verification by lifecycle stage

Source-tree success is not package evidence, and package evidence is not release evidence. Use the smallest applicable boundary:

Rapid development

  • Run the closest focused tests while iterating.
  • Run npm run check before push or handoff.
  • Do not regenerate every dist/ package merely because shared source changed.
  • Record packaging or full-platform work as deferred when it is irrelevant to the current development question.

Internal app demonstration

Run npm run demo:check -- <app-id> for the selected app. The generated package must:

  1. include its declared app and shared payload;
  2. consume applicable build-time placeholders;
  3. pass its package policy, adapter, inventory, and integrity verification;
  4. exclude private, secret, source-only, and undeclared material;
  5. remain explicitly identified as development/demo output.

Use synthetic data and development-only providers. A demo does not require production signing, a formal security/privacy or accessibility review, all-app regeneration, clean-machine acceptance, or release traceability.

Application or Arcane OS release

For an application release:

  1. run only that application's complete behavior suite;
  2. regenerate and review only that application's checked-in package;
  3. verify generator completion and package-policy completeness;
  4. exercise the actual packaged entry and critical interaction;
  5. bind the app version, content inventory, hashes, entry point, and deployment source to the tested output.

For an Arcane OS release, run npm run release:check:arcane-os. The OS gate covers the shared runtime, native hosts, isolation, signing-mode policy, build mechanics, distribution integrity, and generic admission of app-published dist/<app-id>/ARCANE_APP_RELEASE.json inventories. It may validate packaged-app identity, declared capabilities, entry point, exact files, sizes, hashes, safe topology, and catalog admission because those are OS boundaries. It must not read apps/<app-id> as its payload, import app adapters or source verifiers, or run app-owned content/business-behavior suites. Ordinary development, setup, pre-push, and continuous integration remain on the fast invariant profile.

The full release, security/privacy, accessibility, signing, and acceptance SOPs apply only at their explicit promotion boundary.

Purpose

This Standard Operating Procedure (SOP) governs the creation and modification of Arcane applications, components, modules, entities, styles, assets, models, adapters, and other runtime capabilities.

Arcane applications must be thin compositions of shared platform capabilities. Reusable behavior belongs in the repository-level arcane/ runtime. An application under apps/<id>/ should contain only its business-specific policy, language, data definitions, routes, and orchestration.

This is a required design and review process, not an optional refactoring exercise after an app is complete.

Core rule

Before creating any file or copying an existing implementation, write down answers to these questions in order:

  1. I need to make a _____. Describe the user-facing capability or domain behavior, not the proposed filename or technology.
  2. Could this be useful to another application? Consider current and plausible future Arcane applications, not only the app being changed today.
  3. Does it contain business logic specific to this application? Identify app-specific terminology, rules, permissions, prompts, schemas, routes, persistence choices, and workflows.
  4. Can that business logic be extracted from the core behavior? Prefer configuration, adapters, callbacks, events, slots, or injected providers so the core remains reusable.

If the core behavior can be useful elsewhere, it must be created in or moved to the appropriate shared arcane/ layer. The app may configure and orchestrate it; the app must not own a private copy.

Procedure

1. Define the capability

Complete this statement in plain language:

I need to make a capability that allows a user or system to _____.

Describe inputs, outputs, state changes, failure states, permissions, and user-visible behavior. Do not begin with “I need a component named…” because that assumes the solution before the boundary is understood.

2. Search before creating

Inspect the existing shared runtime and examples before adding a new implementation:

  • arcane/components/ for reusable visual and interactive behavior.
  • arcane/modules/ for reusable state, integration, storage, processing, and service behavior.
  • arcane/entities/ for reusable domain-neutral records, validation, and value behavior.
  • arcane/css/ for shared tokens, layouts, and interface primitives.
  • arcane/img/ and arcane/models/ for shared assets and model definitions.
  • example/ for documented usage and extension patterns.
  • apps/ for existing app orchestration that may reveal a capability ready to be extracted.

Prefer extending a compatible shared contract over creating a near-duplicate. Do not change a shared contract in a way that silently breaks its existing consumers.

3. Apply the reuse test

Treat a capability as reusable when its purpose can be described without the name of one app, customer, case type, program, or business workflow.

Examples of reusable behavior include:

  • displaying, editing, selecting, uploading, previewing, or organizing data;
  • opening and closing dialogs;
  • storing preferences or files;
  • validating common value shapes;
  • invoking mail, artificial-intelligence, speech, or storage providers through neutral interfaces;
  • reporting progress, errors, status, or results;
  • importing HTML and coordinating component readiness.

The fact that only one app needs the capability today is not sufficient reason to keep a generally useful implementation app-local.

4. Identify app-specific business logic

Mark each requirement that depends on the app. Common business-specific concerns are:

  • product names, domain terminology, instructions, and prompts;
  • workflow ordering and decisions unique to the app;
  • domain schemas, scoring rules, legal or clinical meaning, and record relationships;
  • app permissions, publication policy, and capability requests;
  • app routes and navigation;
  • which provider, repository, or persistence policy the app selects;
  • transformations between the app's domain records and a neutral shared contract;
  • app-specific success, escalation, and failure actions.

Business logic belongs in apps/<id>/. Visual mechanics, generic state transitions, provider-neutral integrations, and domain-neutral validation do not become app-specific merely because an app uses them.

5. Extract the reusable core

Separate mechanism from policy using one or more of these boundaries:

  • Configuration: labels, options, schemas, limits, feature flags, and initial state supplied through configure(...), properties, or data attributes.
  • Events: shared components emit domain-neutral CustomEvent messages; the parent app decides what the event means and what happens next.
  • Callbacks or adapters: the app supplies conversion, persistence, authorization, or provider operations to a shared capability.
  • Slots or child content: the app supplies business-specific content without forking the shared visual shell.
  • Injected providers: shared modules depend on a narrow interface rather than app credentials, endpoints, or global business policy.
  • Record mapping: app code converts domain records into shared entity or component input shapes and converts results back when necessary.

A shared implementation must have useful neutral defaults, validate its public inputs, expose predictable outputs, and avoid importing from apps/.

6. Place each responsibility

Responsibility Location Boundary
Reusable user interface or interaction arcane/components/ Parent-controlled data, labels, actions, and persistence
Reusable state, service, integration, or processing behavior arcane/modules/ Provider-neutral interface with explicit errors and outputs
Reusable record, value object, or validation behavior arcane/entities/ Domain-neutral data contract and invariants
Shared tokens, layouts, and interface primitives arcane/css/ Neutral styling that apps may compose without duplicating
Shared image or model asset arcane/img/ or arcane/models/ No app-specific branding or private content unless intentionally platform-wide
App schema, prompt, route, policy, wording, or orchestration apps/<id>/ May depend on arcane/; must not redefine it
Reusable usage demonstration example/<type>_<name>/ Minimal, synthetic, and independent of an app's private data
Cross-app behavioral contract test test/ Covers the shared contract and reuse boundary
App-specific business behavior test apps/<id>/test/ or the established app suite Covers domain policy and orchestration

Dependencies flow from an app to arcane/. Shared Arcane code must never import app code or assume a particular app is present.

System appearance follows the same dependency rule. Applications consume the shared theme manager and named design tokens. User-created skins are validated data, not arbitrary CSS, so they remain portable and cannot introduce selectors or network resources into another app.

7. Start every user interface with the Arcane theme

Every app and shared visual component must use the Arcane theme as its base. This preserves the user's selected appearance across Arcane OS while still allowing each app and component to develop an appropriate visual identity.

Use this cascade order:

  1. Optional shared layout: include arcane/css/layout.css first when the shared application layout is appropriate.
  2. Arcane theme: every app must load arcane/css/theme.css, which supplies the canonical light/dark variables and user-preference selectors.
  3. Arcane primitives and shared feature styles: load arcane/css/primitives.css and any other reusable Arcane styles required by the capability.
  4. App styles: load apps/<id>/...css after all shared Arcane styles.
  5. Component styles: apply component-specific CSS after the shared base within the component while continuing to consume Arcane variables.
  6. Narrow overrides: place route, state, or instance overrides last and keep their scope as narrow as possible.

The resulting order should be visible in an app document:

<link rel="stylesheet" href="./arcane/css/theme.css?v=1">
<link rel="stylesheet" href="./arcane/css/primitives.css?v=1">
<link rel="stylesheet" href="./arcane/css/<shared-feature>.css?v=1">
<link rel="stylesheet" href="./apps/<id>/<app>.css?v=1">

Paths and version values may differ, but the shared-to-specific order must not.

Apps must load arcane/modules/ThemeBootstrap.js to apply the user's shared appearance through ThemeManager. Do this early enough to avoid presenting a conflicting app-default theme before the saved preference is applied. Apps that provide a theme switcher or editor must use the shared Arcane theme components and persistence rather than establishing an app-only preference that other apps cannot respect.

Custom CSS must consume the Arcane theme variables, including shared surface, text, action, border, focus, status, spacing, and radius tokens, whenever those concepts apply. App and component styles may add new semantic variables, but their defaults should derive from Arcane variables. For example:

:root{
    --case-priority:var(--arcane-warning);
}

.case-card{
    background:var(--arcane-surface-raised);
    border:1px solid var(--arcane-border);
    border-radius:var(--arcane-radius-large);
    color:var(--text-color);
}

Write new color values with rgb(...) or rgba(...) rather than hexadecimal notation. RGB and RGBA keep channel values explicit and make color and opacity transitions easier to animate. Existing hexadecimal values may be migrated when their surrounding code is changed; do not perform unrelated palette rewrites solely for notation.

Overrides are allowed and expected when they serve an app or component. They must be layered on top of the Arcane base, remain compatible with light, dark, system, and custom user themes, and preserve accessible contrast and focus visibility. Do not replace the Arcane theme with a fixed app palette or use hard-coded colors for concepts already represented by theme tokens.

8. Define the contract before implementation

For every new shared capability, document:

  • its purpose and non-goals;
  • accepted inputs, configuration, and defaults;
  • public methods or exported functions;
  • emitted events, returned values, and error behavior;
  • required providers or browser capabilities;
  • accessibility and keyboard behavior for user interfaces;
  • security, privacy, and persistence boundaries;
  • compatibility expectations for existing consumers.

Use arcane/modules/ComponentContracts.js when multiple components or consumers need the same validated option shape or a testable domain-neutral transformation.

Shared components should allow the parent to supply domain data and decisions. A component must not silently select business policy, persist to an app-specific location, or call an app route unless that behavior is explicitly injected.

9. Implement the smallest complete split

A normal implementation consists of:

  1. the reusable mechanism in arcane/;
  2. the app-specific adapter or orchestration in apps/<id>/;
  3. focused tests for both sides of the boundary;
  4. a synthetic example and usage notes when a new public shared contract is introduced;
  5. updated package allowlists, cache references, or machine capabilities when required.

Do not build the full feature app-local with a promise to extract it later. Establish the boundary as part of the first implementation.

10. Complete the work-amplification review

Before implementation, draw the work graph for any setup, build, package, test, model, app, or runtime path the change creates or materially alters:

  1. State the cardinality and loop multiplier: platforms, architectures, applications, models, assets, targets, test cases, retries, or other items over which work repeats.
  2. Inventory expensive operations such as downloads, extraction, compilation, linking, hashing, signing, integrity scans, package generation, model acquisition, service initialization, and tests. Estimate their representative cold-path invocation count, bytes processed or transferred, and elapsed time.
  3. Classify each operation as invariant across the loop, identity-bound per item, or batchable. Hoist invariant work out of the loop and execute it once. Batch compatible work instead of paying per-item startup and scan costs.
  4. Reuse or cache an output only when its cache key binds all relevant source hashes, toolchain, platform, architecture, configuration, policy, and signing identity. Verify that cryptographic and identity binding before reuse; efficiency must not weaken integrity, isolation, or freshness.
  5. Enforce one check per trust fact per artifact state. When bytes, policy, identity, location, and toolchain are unchanged, reuse immutable hash-bound evidence and do not rerun the check. When assembly changes only placement or inventory, verify only that changed boundary instead of rechecking unchanged payload facts.
  6. For every digest or inventory comparison, identify the attacker and independent authenticity anchor. A value generated from, stored beside, fetched from the same authority as, or writable with the payload is consistency evidence only. It may detect corruption, drift, or an incomplete transaction; it must not authorize bytes, assert publisher identity, or produce a verified/trusted result.
  7. Measure one representative cold path and compare its actual operation count, bytes, and time with the design estimate. Add a focused count or work-graph regression when redundant work could return unnoticed.
  8. Eliminate redundant downloads, scans, builds, signatures, and tests before adding progress UI. Progress is not a remedy for unnecessary work. For work that remains necessary, preserve streaming visibility with the current phase and item, completed/total count or bytes, elapsed time, throughput when meaningful, and an honest ETA when calculable.

Arcane OS-owned artifacts must be prepared once per compatible OS build or installation, not once per application. This includes shared hosts and runtimes, PipeGuard and other OS security tools, browser and media runtimes, model services, dependency trees, shared integrity scans, signing preflights, and OS-owned smoke tests. An application release owns any genuinely app-specific compiled host or package; Arcane OS admits its prebuilt published inventory through the generic application boundary and does not compile or test the application during OS setup.

Any operation or check intentionally repeated must prove that its underlying artifact state changed or that an independent verification is explicitly mandated. Document the changed item-specific input or identity, the independent mandate when applicable, why batching or safe reuse is impossible, the multiplier, and the measured cost. "Defense in depth" is not a justification for checking an identical trust fact against unchanged evidence. Convenience, loop-local placement, and an existing implementation are not justifications.

Verification receipt lifecycle

Every expensive integrity, signature, publisher, package, catalog, or installed-tree decision has one verification owner for one exact artifact state. The owner retains the verified file and directory handles or an equally strong immutability boundary and issues an immutable receipt binding canonical location and filesystem identity, content and inventory hashes, policy, toolchain, platform and architecture, signing identity and trust result, and a receipt generation. Every downstream status, catalog, install, update, launch, and package consumer authenticates and reuses that receipt. Generic defense in depth never justifies repeating the same trust check against unchanged state.

Invalidate the receipt before any bound byte, identity, location, policy, toolchain, signer, inventory, or generation changes. Stop new consumers, drain or cancel active consumers, close retained handles only at the mutation boundary, then write, rename, activate, repair, roll back, or replace and verify the new state into a new generation. A path, timestamp, size, time-to-live, or process-local cache key alone does not prove unchanged state.

Cross-process reuse on Microsoft NT requires a shared Arcane host, broker, or service that retains the verified handles, authenticates pipe peers through kernel process identity, and binds each delegation to the consumer process and receipt generation. Environment variables, command-line claims, unauthenticated pipes, and an administrator-protected receipt file alone are insufficient authority. The UI or CLI acknowledges before receipt acquisition or cache-miss verification, while the owner emits progress, heartbeat, and surfaced failure.

11. Preserve foreground responsiveness

The responsiveness invariant applies to every user interface and command-line interface (CLI), including setup, startup, integrity verification, builds, model pulls, app installation, and runtime initialization:

  1. Acknowledge immediately. Create or activate the UI, or print a CLI start/status record, before the first potentially blocking operation. Show the phase and a durable error/log destination when available. A splash or status surface must exist before a required serialized boundary begins.
  2. Keep waits off the foreground. Network, disk, hashing, compilation, process, model, and integrity waits must not block UI creation, event dispatch, painting, input, or the foreground thread. Use event-driven background workers for CPU-bound or blocking APIs and genuine asynchronous I/O where the platform provides it.
  3. Do not disguise blocking code. async/await is allowed for genuinely asynchronous operations, but declaring a function async, returning a promise/task, or using await does not make synchronous filesystem, hashing, compiler, child-process, or network work nonblocking. The blocking call itself must leave the foreground execution path.
  4. Bound concurrency and apply backpressure. Set explicit worker, process, network, memory, and queue limits appropriate to the resource. Do not use unbounded fan-out, unbounded Promise.all, or uncontrolled process spawning. Producers must pause or queue when consumers reach capacity.
  5. Publish live progress. Emit event-driven phase, item, completed/total count or bytes, and elapsed updates. Emit a heartbeat while a necessary operation cannot report granular progress so a user can distinguish work from a hang. Coalesce updates when needed to avoid overwhelming the foreground.
  6. Support control safely. Provide cancellation and safe retry or resume when the underlying operation can preserve transactional, integrity, and security guarantees. Define cleanup of partial output and make non-cancellable trust or transaction sections short and explicit.
  7. Own every task. Every background operation must be awaited, joined, registered with a supervisor, or otherwise have an explicit lifecycle owner. Surface failures through the visible operation state, durable log, and CLI exit status. Unobserved fire-and-forget work is prohibited.
  8. Serialize only proven boundaries. Serialize only when a trust decision, atomic transaction, shared mutable state, or external protocol requires it. Document that boundary and its duration. Do not serialize an entire workflow for convenience, and never begin serialization before visible status exists.

Focused tests must prove the acknowledgement precedes blocking work, foreground events continue during a representative slow operation, concurrency stays within its bound, progress or heartbeat remains live, cancellation leaves a supported state, and worker failure reaches the caller.

12. Name every function and callback

Every function must have a meaningful name, including callbacks passed to event listeners, timers, promises, array methods, task runners, provider calls, and other functions. The name should describe the callback's role or terminal condition so stack traces, diagnostics, and natural-language debugging identify the actual operation instead of reporting only <anonymous>.

Do not use an anonymous arrow or anonymous function merely because the callback is short. A concise named function expression is acceptable when a separate declaration would obscure a useful local closure.

The road to callback hell is paved by missing the exit to callback heaven: name the callback.

Cross-application AI, corpus, cancellation, and terminal-workflow contracts

The following contracts apply to every Arcane application that uses the same class of capability. Historical app implementations are evidence for improving the shared contract, not sources of app-specific exceptions.

Keep this SOP synchronized with the authoritative public shapes in arcane-ai-contracts.md, the native methods in arcane-api.md, the package boundary in app-packaging.md, the test ownership rules in os-testing.md, and the conditional signing and promotion rules in build-release.md. Diagnose failures through debugging.md; do not turn a diagnosis into a speculative contract change.

Shared AI is the provider-neutral data-access and normalization boundary

arcane/modules/AI.js is the shared artificial-intelligence data-access object (DAO) and normalization boundary for application inference. An app owns domain messages, tool meaning, a strict domain result schema, presentation, and orchestration. The shared AI module owns provider selection, provider request construction, message normalization, structured-output translation, provider response normalization, and stable error/cancellation behavior. The Arcane bridge, Core, and native provider own capability enforcement, transport admission, model admission, and termination of native upstream work.

Use the object-form request APIs for all new application code:

const response=await ai.fetchRequest({
    messages,
    structuredOutput:SEARCH_RESULT_SCHEMA,
    parallelToolCalls:false,
    signal
});

Use streamRequest({...}) for streaming work and pass the same owned AbortSignal. Positional fetch(...) and streamMessage(...) signatures are compatibility internals; do not add new app consumers of them.

Application code must not:

  • call an OpenAI HTTP endpoint, Arcane.ollama.chat(...), or another provider inference endpoint directly;
  • construct provider fields such as model, stream, format, response_format, think, reasoning_effort, options, provider tool-call envelopes, authorization headers, or provider-specific response paths;
  • normalize Ollama and OpenAI results independently or branch on provider wire shapes;
  • copy shared AI request construction into an app-local helper;
  • attach a request diagnostic callback that serializes messages, prompts, tools, schemas, credentials, or the complete provider body.

Direct Ollama inventory and management methods remain platform, Settings, Shell, or Terminal diagnostic/administrative surfaces governed by their documented capabilities. They are not an alternate inference DAO for an application.

The shared AI boundary must:

  • validate the closed object request and reject an invalid policy before provider dispatch;
  • translate one app-supplied JSON Schema to the selected provider's native structured-output field;
  • strip persistence-only and renderer-only message metadata before provider dispatch;
  • normalize tool calls, text, usage, model identity, errors, and cancellation into the documented shared result;
  • invoke application callbacks only while the request remains current and attached;
  • preserve a stable provider-neutral error code and AbortError identity;
  • keep provider additions inside the shared adapter so app callers do not change when a provider changes.

Required focused tests use provider doubles at the shared boundary and prove the exact provider translation, normalized result, rejection before dispatch, metadata stripping, and identical application-facing behavior for every supported provider. App tests assert that the app supplies only domain messages, schema, tools, policy, callbacks, and an AbortSignal; source-contract checks should reject inline provider payload construction.

Speech-first interaction is an application recommendation

Speech-first interaction can improve hands-free use, accessibility, review, and attention-sensitive workflows, but it is not an Arcane OS product rule. Each application decides whether spoken output or voice input fits its users and domain. The app owns narration timing, consent, labels, interruption behavior, privacy wording, and the equivalent visual or text workflow.

Arcane Core owns the app-neutral Arcane.speech.status(), Arcane.speech.synthesize(...), and Arcane.speech.transcribe(...) capability boundary. Shared runtime modules own bounded playback, sequencing, supersession, object-URL cleanup, and reusable transcription interaction. An application must use those shared contracts rather than connect to a speech provider directly or copy the mechanics into app-local code.

A speech-first design must remain usable when speech is unavailable, denied, muted, interrupted, or only partly ready. Keep the full visual text available, provide an immediate stop/mute control, never start microphone capture without the applicable user action and capability, and expose synthesis and transcription readiness independently. Spoken output is presentation, not authorization, acknowledgement, or proof that a person heard or accepted it.

Required focused tests cover unavailable and partially available roles, stop/supersede behavior, cancellation on page detach, visual-text parity, microphone denial, and the absence of direct app-to-provider speech calls.

Structured output, exact enums, and model-owned defaults

When application logic consumes machine-readable output, structuredOutput must be a concrete closed JSON Schema object, not merely a prose instruction or loose JSON mode. Define the schema once in an importable app-domain module and use that same definition for shared-AI translation and runtime validation.

A result schema must:

  • declare the top-level type and every nested type;
  • use additionalProperties:false at every object level that the app interprets;
  • list every required property explicitly;
  • bound arrays, strings, numbers, and integers where the domain has a real bound;
  • reject unknown, duplicate, missing, or out-of-domain identifiers after parsing;
  • preserve one canonical field name and type across providers;
  • describe every enum value exactly, including when each value is valid and what it means.

For example, an enum description must say “Use exactly user_commitment when the user explicitly committed to act; use exactly optional_homework only when the user explicitly agreed to carry optional homework forward.” A description such as “type of follow-up” is not an adequate contract. Keep the runtime validator at least as strict as the schema because provider-side schema enforcement is not application authorization.

The system prompt describes the task, evidence rules, and decision semantics. It must not contain a second hand-written copy of the response JSON shape that can drift from the schema. Do not ask the model to infer a schema version, tolerate extra fields, or repair its own invalid output silently.

App-owned Modelfiles own normal generation defaults such as context size, temperature, prediction limits, and other model behavior. The shared AI/provider layer owns provider defaults when no Modelfile applies. An app must not send options, estimate context tokens, count serialized request bytes, or override model defaults merely to make a request appear tuned.

An app-side size or generation option is allowed only when a documented hard boundary truly requires it—for example, a native IPC maximum, a storage quota, an explicit product response limit, or a provider field whose value changes required domain semantics. Enforce that boundary once in the shared DAO or Core whenever it is provider- or transport-wide. Record the limit, owner, units, rejection behavior, and focused boundary test. Heuristic byte targets, guessed token ratios, and per-app num_ctx overrides are prohibited.

Required focused tests cover schema closure, required fields, exact enum semantics, bounds, unknown/duplicate IDs, invalid provider output, no duplicated prompt schema, Modelfile-owned defaults, and absence of app-side byte/context/options logic unless the design record names the hard boundary.

DBOPFS-defined complete corpora and stable independent batches

For an Arcane application corpus stored in DBOPFS, the allowed DBOPFS file keys present for the operation define the corpus. A manifest may supply titles, provenance, access metadata, or packaging information, but it does not make an absent body searchable and it does not exclude an allowed DBOPFS record merely because metadata is missing. Do not refetch bundled document bodies after DBOPFS hydration.

Use this operation contract:

  1. Enumerate the allowed DBOPFS keys once for the operation and sort them by the documented stable key order.
  2. Resolve metadata without changing membership, then read each available document body in full. An unreadable or concurrently removed file becomes a bounded warning associated with that file; it does not cause a bundled-body fetch or hidden substitution.
  3. Form stable fixed-count groups from the readable ordered documents. The count is an app-domain constant. Do not change group membership based on serialized bytes, guessed tokens, provider speed, or document length, and do not truncate a document to make it fit a heuristic target.
  4. Launch each group as an independently owned asynchronous request without awaiting the preceding group. When corpus cardinality is not already bounded, use a shared bounded scheduler with explicit backpressure; do not restore serial dependency or unbounded fan-out.
  5. Await all launched requests with Promise.allSettled semantics. Retain every successful result, convert each non-cancellation failure to one structured warning, and merge successful results deterministically using score plus original corpus order for ties.
  6. Return explicit coverage containing the actual corpus count, readable/evaluated IDs, relevant IDs, failed group indexes/IDs, and whether coverage is complete. Partial success is a valid result, not a disguised full success and not an all-or-nothing failure.

A representative orchestration shape is:

const corpus=await loadCompleteCorpusFromDBOPFS();
const groups=stableFixedCountGroups(corpus.documents,FILES_PER_GROUP);
const outcomes=await Promise.allSettled(
    groups.map(function launchIndependentGroup(group,index){
        return requestGroup({group,index,signal});
    })
);
const result=mergeSettledCorpusResults({corpus,groups,outcomes});

Progress must come from actual file counts. The initial total is the number of enumerated DBOPFS files in scope. Completed work is the number of unreadable/skipped files whose load has settled plus each settled readable group's real length. Unless cancellation stops the operation, the final completed count must equal the enumerated total. Do not derive user-visible progress from a manifest count, configured maximum, guessed batch size, response order, or byte estimate. A progress callback is observational: an exception in it must not change the search result.

Corpus and group warnings stay outside model prompts. Show them in the local UI and, when needed, a privacy-safe console diagnostic. Within the corpus/tool-result payload, keep the verbatim user request and successful grounded records available alongside otherwise authorized prompt context, but do not inject “the search was incomplete” or raw failure text. Warning text can change inference and cause the model to answer the diagnostic instead of the user.

Cancellation is not partial success. If the page-owned signal aborts, stop launching queued work, terminate active requests, suppress later progress, and return the normalized cancellation outcome rather than warnings for every cancelled group.

Required focused tests prove DBOPFS key authority, metadata-only manifests, no body refetch, complete document content, stable fixed-count groups including a very long document, independent launch, bounded scheduling where applicable, all-settled partial success, deterministic merge order, actual-file progress, warning/prompt separation, and cancellation without later progress.

Verbatim user intent and privacy-safe diagnostics

Capture the latest real user-role message from the immutable request snapshot before tool execution and propagate that exact string to retrieval. Validate emptiness with a trimmed view if needed, but return and send the original text unchanged, including punctuation, whitespace, line breaks, names, and qualifiers.

The model may decide whether a retrieval tool is appropriate, but it must not author, summarize, “improve,” normalize, or replace the retrieval query. Tool schemas therefore must not request a rewritten query, user_goal, known_context, or similar model-generated substitute when the original user message is available. Synthetic timebox, retry, closeout, and continuation instructions are internal control messages and must never become the user's search text.

Required tests use a request with leading/trailing whitespace, embedded newlines, punctuation, and meaningful qualifiers; they assert character-for-character propagation and prove that conflicting model tool arguments cannot replace it.

Diagnostics are local, transient, minimal, and purpose-specific:

  • emit a response or failure record only when it helps diagnose the boundary;
  • correlate with opaque request ID, operation, group index, attempt, document count or bounded opaque IDs, duration, status, and stable error code;
  • do not serialize or persist prompts, messages, tools, schemas, credentials, request bodies, raw document content, raw model response content, or sensitive user payloads;
  • do not add application telemetry, files, database rows, or durable logs merely to retain a debugging payload;
  • keep expected cancellation out of warning/error logs;
  • make diagnostic failure non-fatal to the user operation.

A local console label plus a small metadata object is normally sufficient. A temporary developer inspection mode that exposes sensitive content requires an explicit bounded design, user awareness where applicable, no persistence, and removal before delivery.

Page-owned cancellation must terminate the actual upstream operation

Every page or similarly detachable application surface owns one parent AbortController for its asynchronous lifetime. Register a one-shot pagehide or equivalent detach handler before launching page-owned work. That handler aborts the parent controller, clears page timers, disposes subscriptions/timeboxes, and prevents new work from being queued. An independently cancellable operation may own a child controller linked to the parent detach signal; cancelling that child must not cancel unrelated page work, while detaching the page must still abort every linked child.

The same signal must propagate through the whole path:

page/app adapter -> shared AI DAO -> Arcane frontend bridge -> Core request owner -> native/provider adapter -> actual network socket, response stream, inference job, process, or worker

Local promise rejection is not cancellation if upstream inference continues. Each provider adapter must retain the handle that can stop its real operation and invoke it on abort—for example AbortController.abort(), request/response destruction, socket close, native job cancellation, or child-process-tree termination. If a provider cannot cancel safely, document that limitation, prevent all downstream effects, and do not claim upstream cancellation.

The frontend bridge uses exact control messages for one request and for every request owned by a detached page. A pre-aborted request sends no normal request frame. Pending entries own their abort listener and timeout, remove both on every terminal path, notify Core without awaiting a slow transport acknowledgement, reject locally with a stable AbortError, and ignore late replies. Core owns one controller per admitted request, validates request IDs and exact control-frame keys, aborts all active controllers when its input/session closes, and never emit success after abort.

Every queued, retry, and continuation boundary must check the signal:

  • before enqueueing and before provider dispatch;
  • after model/resource admission and every awaited dependency;
  • before a retry, timer callback, automatic greeting, tool continuation, or follow-up request;
  • before progress, persistence, speech, navigation, or UI mutation;
  • after the provider returns but before invoking the app callback.

Normalize page-owned cancellation to name:'AbortError' plus the documented shared code. Treat it as expected control flow: clear placeholders and ownership, but do not show a service-failure message, create partial-success warnings, retry, or persist an assistant response.

Native hosts must cancel all page-owned Core requests on trusted top-level reload/navigation, renderer or web-process termination, host close, and Core disposal. Cancelling only an app promise while leaving the bridge, Core queue, or model generation alive means the changed interaction is incomplete and must not be handed off.

Required tests cover pre-abort, in-flight abort, exact per-request cancellation, page-wide cancellation, listener/timer cleanup, slow transport acknowledgement, ignored late response, cancellation during admission, destruction/cancellation of the actual upstream handle, host navigation/termination, no retry/continuation after detach, no late progress or persistence, and provider parity.

Terminal conversation closeout tools

A terminal closeout is a provider-neutral tool contract, not an app-specific prose convention. Put generic tool construction, strict normalization, and sole-call classification in a shared module such as arcane/modules/ConversationClosingReport.js. The app adapter supplies only its tool name, domain wording, semantic trigger policy, optional consent/persistence adapter, presentation preference, and terminal UI transition.

The closeout tool is offered on every eligible conversational request until completion is successfully committed. Do not remove it because a user disabled a decorative closeout preference or remembered-action preference; those preferences control presentation and optional persistence, not whether the model can report a semantic ending. After completion, remove the tool because the conversation accepts no further request.

Trigger on semantic user-ending intent: the user expresses that they are ending, finished, wrapping up, leaving, or selects the app's explicit Complete action. Do not use an exact phrase, a keyword proxy such as “recap,” response length, elapsed time, or a vague “clearly” test. Do not close while requested work remains open or after a routine answer. A manual Complete action may add a bounded internal instruction for the current inference, but must not rewrite or persist it as user-authored text.

The model emits exactly one complete final_message plus optional remembered_actions. This illustrative schema is derived from the shared constructor; use its exported constants rather than copying the literal bounds into application code:

const TERMINAL_CLOSEOUT_SCHEMA={
    type:'object',
    additionalProperties:false,
    properties:{
        final_message:{type:'string',minLength:1,maxLength:5000},
        remembered_actions:{
            type:'array',
            maxItems:6,
            items:{
                type:'object',
                additionalProperties:false,
                properties:{
                    text:{type:'string',minLength:1,maxLength:500},
                    basis:{
                        type:'string',
                        enum:['user_commitment','optional_homework'],
                        description:'Use exactly user_commitment for an explicit user commitment. Use exactly optional_homework only for optional homework the user explicitly agreed to carry forward.'
                    }
                },
                required:['text','basis']
            }
        }
    },
    required:['final_message']
};

Do not split the final response into rigid model fields such as outcome, progress, next steps, and warm closing. Those optional rhetorical elements belong inside the one model-authored final_message; a multi-field template creates brittle assembly, duplicated prose, and schema drift.

The runtime parser independently enforces a bounded JSON/plain object, exact keys, one nonblank bounded final message, bounded remembered actions, exact action fields and enum values, and no raw control text. Freeze the normalized result. The terminal tool must be the sole tool call; reject mixed or unoffered calls as a whole and do not partially execute them. A manual closeout request forces that tool and disables parallel tool calls. Suppress unvalidated streamed closeout text so a malformed draft never reaches the transcript.

Remembered actions are not implied by model output. Include only a commitment or optional homework the user explicitly agreed to carry into a later conversation, then request separate, fresh consent before local persistence. Report saved, failed, or declined status in the same terminal message. Declining or failing persistence must not prevent the final message from closing the conversation. The tool itself performs no action, navigation, notification, email, task creation, or external delivery.

A closeout does not require links. The absence of a URL, email address, telephone link, or source citation must never make a valid terminal closeout fail. When a source is useful, an exact document title can be sufficient. If a closeout contains a link, apply the centrally selected terminal provenance purpose; do not invent a second closeout-only bypass or require grounded-response evidence accidentally.

Use this single terminal commit sequence:

  1. Confirm every returned tool name was offered for this exact request.
  2. Classify the sole terminal call and strictly normalize its arguments once.
  3. Ask separately for remembered-action consent and incorporate the local result into one terminal message.
  4. Apply the central provenance-purpose decision exactly once to the final visible message.
  5. Through one response commit coordinator, persist and render that same accepted message before marking the UI complete.
  6. Only after successful persistence/rendering, dispose timers and pending work, enter the terminal UI state, and reject every later submission.

The completed shared chat state expands and retains the transcript, hides the timer, composer, upload, speech, language, and completion controls, disables every input/send path, moves focus to the transcript without losing content, and scrolls the terminal message into view. Guard both the visible controls and the programmatic submission API; disabling a button alone is insufficient. Page-owned abort and response revision guards must prevent an older request, retry, tool continuation, automatic greeting, or speech callback from adding post-close output.

Required focused tests cover always-offered-until-complete behavior, semantic triggers and false positives, forced manual sole-tool use, unoffered/mixed tool rejection, strict schema and runtime normalization, exactly one final message, separate remembered-action consent and every save outcome, no link requirement, one central provenance gate, persistence-before-completion order, transcript expansion/control hiding/focus, disabled visible and programmatic submissions, and no late post-close work.

Centralized policy enums and one decision point

Represent a finite policy choice with one frozen enum and one normalizer/decision function. A representative response-purpose policy is:

const RESPONSE_PURPOSE=Object.freeze({
    GROUNDED:'grounded-response',
    TERMINAL_CLOSEOUT:'validated-conversation-closeout'
});

The decision function validates the closed enum, computes the applicable rules, and returns one immutable result containing the purpose, outcome, reason code, and bounded audit metadata. Unknown values fail closed. Downstream persistence, rendering, or delivery consumes that result; it does not reinterpret the purpose or rerun the same check.

Do not spread related decisions across flags such as skipValidation, allowUnsupportedLinks, isCloseout, linksRequired, bypassGrounding, or displayCloseout. Do not validate a serialized tool report and then validate its extracted message again. Do not let a presentation preference become a safety-policy switch. One policy fact for one artifact/message state gets one owner and one pass, consistent with the repository verification-receipt rule.

Required tests exercise every enum member, reject unknown values, prove each purpose's complete rule set, count exactly one gate invocation, and demonstrate that downstream code uses the immutable decision rather than a parallel boolean branch.

Shared placement and loose coupling

Place provider translation, normalized AI requests/results, generic terminal-tool construction/validation, response provenance mechanics, abort/error normalization, bounded schedulers, and shared terminal chat state under the appropriate arcane/ layer. Keep app-specific prompts, schemas, corpus metadata rules, result ranking meaning, tool names, consent wording, persistence adapters, and UI orchestration in apps/<id>/.

Shared modules accept narrow records, callbacks, policy enums, and AbortSignal; they do not read app globals or import app files. App adapters compose shared exports; they do not copy their bodies or expose provider wire details. When two apps need a variation, extend one neutral shared contract and verify all consumers instead of forking inline code.

Focused contract tests belong with the shared mechanism under test/; app business-policy and orchestration tests stay in the app-owned suite. A source-regex contract may guard placement or prevent a dangerous code shape, but runtime behavior should be tested at the cheapest real boundary whenever practical.

Vanilla-test 2.1.0 convention

Every repository JavaScript test case uses the shared vanilla-test 2.1.0 adapter at test/support/vanilla-test.mjs, reached through the correct repository-relative import. Use node:assert/strict for equality, throws, and rejection semantics. Do not import node:test directly from an app or test file and do not instantiate VanillaTest outside the shared lifecycle support.

The shared adapter owns exactly one strict vanilla lifecycle per Node-orchestrated case and settles it once. Node remains the only orchestrator for discovery, suites, hooks, nested tests, filtering, isolation, timeouts, cleanup, concurrency, reporting, and exit status. Preserve the original failure and stack; consume the immutable vanilla report without printing a second ANSI report. A callback-style case has arity exactly two and must not also return a Promise. No library or case calls process.exit().

When adding tests for the contracts above:

  • import test, describe, it, and hooks from the shared adapter;
  • name every case body and callback;
  • prefer strict behavioral assertions and provider/transport doubles with observable call counts;
  • prove success, malformed input, boundary rejection, cancellation, partial success, and late-callback suppression;
  • keep synthetic content free of credentials and protected user data;
  • let the runner own cleanup, timeout, and exit behavior.

Conditional source, package, native-build, signing, and push gates

These gates are conditional artifact boundaries, not one mandatory chain for every source edit. Select the smallest path that proves the requested state. Do not restore the obsolete practice of regenerating or verifying every app package on every push.

Gate Select it when Required evidence It does not prove or require
Source Every implementation or documentation change Focused contract/behavior tests, reviewed source diff, and npm run check before push or handoff Current dist, a native executable, or release readiness
Cache reference Served/imported source bytes changed and a cache-busting reference is part of that delivery path Update every affected ?v= or equivalent reference and its focused consumer contract; verify the current page loads the new bytes An app semantic version change; query values are cache identities, not release versions
Selected dist A demo, package investigation, or app release requires packaged browser bytes Package only <app-id>, verify ARCANE_APP_RELEASE.json, exact inventory/hashes, source-to-package parity, and review source/generated diffs together All-app regeneration or an OS release
App release The app is explicitly being released Run that app's complete owned suite, then run npm run app:release -- <app-id> and reuse its package-verification receipt. For a non-release package path, use npm run app:package -- <app-id> followed by npm run app:check -- <app-id> instead. Commit intended source and generated dist/<app-id> together A duplicate check of unchanged bytes, another app's behavior, or Arcane OS release acceptance
Native rebuild The user requested or the changed boundary requires a native artifact Build only the selected app/target from the intended verified package, stop on failure, verify exact output identity/inventory, and launch that new output when a demo is required Other targets, production signing, or a full machine distribution
Signing The selected native artifact requires a declared signing mode Keep unsigned-local-test, development-signed, and production-signed commands separate; verify the exact executable set and declared mode. Production requires an explicit promotion request and trusted-signer preflight A development signature is not production identity or release approval
Push Remote repository delivery is selected Recheck main, coordinate overlapping dirty files, fetch current remote state, stage/commit only intended paths, push without force, fetch again, and prove the fetched remote contains the exact commit. When branch-tip equality is explicitly required, also prove local HEAD equals the fetched origin/main Authority to include unrelated work, rewrite history, or bypass branch/reviewer policy

For rapid development, the normal verification path is source -> focused test -> npm run check, with package/native/signing work explicitly reported as not selected. When remote delivery is selected, follow with an intentional exact-path commit and push. A stale development dist tree is then expected and must not be described as the new source artifact.

For a current browser demo, use source -> affected cache references -> npm run demo:check -- <app-id> -> serve and inspect that selected verified package. Stop there unless a native artifact or remote delivery was also requested.

For a requested native executable, use source -> affected cache references -> selected app package and package verification -> selected native rebuild -> exact signing-mode verification when the selected mode requires it -> launch/inspect the exact rebuilt artifact. Add an intentional commit/push only when remote delivery is selected. Skipping tests at the user's request never means launching a stale executable: package and rebuild the current source first, then omit only the tests the user actually waived and report that omission.

Before any selected commit in a shared dirty checkout, re-read git status, confirm the active branch is main, identify the owner of every unrelated change, and stage exact intended pathspecs only. Do not pull, rebase, stash, reset, clean, package shared payloads, or otherwise mutate another owner's active work merely to make delivery convenient. After a selected push, prove the fetched remote branch contains the exact local commit; a successful push message by itself is not delivery evidence. Prove exact tip equality as an additional gate when the delivery contract requires it.

Required gate tests and review prove cache-reference coverage, package/source parity when selected, rejection of stale or hand-edited generated manifests, current-output launch rather than stale-output fallback, signing-mode separation, fail-closed build status, fetched-remote commit containment when push is selected, and exact tip equality when the delivery contract requires it. Do not run an all-app, all-platform, or production gate merely to make a development handoff look stronger.

Corrected anti-patterns

Reject these patterns during design and review:

Anti-pattern Required correction
An app calls a provider or builds {model, messages, format, think, options} inline Call the shared object-form AI DAO with domain messages, one schema, tools/policy, callbacks, and AbortSignal
A prompt says “return JSON” or duplicates a hand-written result example Supply one closed JSON Schema and keep the prompt about task semantics
An enum lists values without exact meaning Describe when to use every exact value and enforce the same semantics at runtime
An app sends num_ctx, temperature, prediction limits, guessed token counts, or serialized-byte targets by default Let the Modelfile/shared provider own defaults; add only a documented hard-boundary control
A model rewrites the user's retrieval query Snapshot and propagate the latest real user message verbatim
A manifest or bundled fetch silently defines a DBOPFS corpus Enumerate DBOPFS keys; use the manifest only for metadata and read full stored bodies
Variable byte-packed/truncated or serial document requests Use stable fixed-count full-document groups with independent asynchronous settlement
One failed group discards every successful group Return deterministic partial success plus structured coverage/warnings
Manifest counts, byte estimates, or configured maxima drive progress Count actual enumerated and settled files
Warning/error text is appended to the next model prompt Keep warnings in UI/local diagnostics and prompts grounded only in successful records
A request or response body is logged for debugging Log only correlated, bounded, non-sensitive response/failure metadata when needed
Aborting rejects the renderer promise but leaves model generation running Propagate the signal and terminate the provider's actual upstream handle
Detach allows a timer, retry, queued batch, or tool continuation to run Check the signal at every queue/await/effect boundary and cancel page-wide work
A closeout preference removes the terminal tool Offer it until completion; use preferences only for presentation and separately consented persistence
Exact words, “recap,” response length, or “clearly” trigger closeout Evaluate semantic user-ending intent or the explicit Complete action
A closeout is assembled from many rigid model fields Require one complete final_message plus optional remembered actions
Closeout succeeds only when it contains a link Make no-link closeouts valid and choose one central provenance purpose
Validation is controlled by several booleans or run twice Normalize one closed policy enum and apply one gate to the final artifact/message
The UI hides one button but programmatic submissions remain possible Enter one terminal state that hides controls, disables every path, focuses the transcript, and rejects submissions
A user asks to launch without tests and the old executable is opened Repackage/rebuild current bytes first; waive only the test step
Every push regenerates all apps or signs every target Select conditional artifact gates and keep invariant work outside app loops
A test imports node:test or creates its own vanilla lifecycle Import the shared adapter; keep Node orchestration and one vanilla lifecycle per case

Focused implementation checklist

Before implementing an affected feature, record and complete the applicable items:

  • Shared AI DAO method and object request chosen; no app-built provider payload.
  • One strict JSON Schema and equally strict runtime validator defined.
  • Every enum value has exact semantics; prompts do not duplicate the schema.
  • Modelfile/shared defaults retained; every app option or size count tied to a documented hard boundary.
  • Latest real user message captured and propagated verbatim.
  • DBOPFS corpus membership, stable order, full-document load, and fixed group count defined.
  • Independent settlement, partial-success coverage, deterministic merge, actual-file progress, and warning channel defined.
  • One page-owned AbortSignal reaches every layer and the actual upstream operation.
  • Queue, retry, timer, continuation, progress, persistence, and UI boundaries recheck cancellation/current revision.
  • Terminal tool always offered until completion, uses one final_message, and is the sole call.
  • Remembered actions require explicit prior agreement plus separate persistence consent.
  • No-link closeout accepted; one central provenance-purpose enum and one final-message gate used.
  • Successful terminal message commits before controls hide; every post-close submission path fails.
  • Reusable mechanisms live under arcane/; app files contain only domain policy and orchestration.
  • Tests import the shared vanilla-test 2.1.0 adapter and use strict assertions.
  • Focused behavioral and contract tests cover malformed, failure, cancellation, partial, and late-result cases.
  • Conditional source/cache/dist/release/native/signing/push gates selected and non-selected gates documented.
  • When commit/push is selected, intended files are coordinated in the live working tree, exact paths are committed, the fetched remote contains that commit, and any explicitly required tip equality is verified.

Rules by artifact type

Shared components

A shared component must:

  • use domain-neutral names and default language;
  • accept parent data and configuration instead of reading app globals;
  • expose a documented readiness signal and stable methods when asynchronous HTML import is involved;
  • emit domain-neutral events with documented detail shapes;
  • let the app own persistence, routing, authorization, and business outcomes;
  • resolve its own shared dependencies from a stable component or module-relative base;
  • support keyboard use, focus behavior, accessible labels, empty states, loading states, and errors;
  • load the Arcane visual base and use shared theme variables and style primitives;
  • layer component-specific styles after the Arcane base without resetting or overriding the user's theme at document scope;
  • remain legible and operable under the supported light, dark, system, and custom Arcane themes;
  • be usable by a synthetic example that contains no app-specific data.

An app may wrap or configure a shared component. It may not copy the component merely to change labels, data sources, persistence, actions, or layout options that can reasonably be expressed through the public contract.

Shared modules

A shared module must:

  • perform one coherent, reusable responsibility;
  • accept configuration or narrow dependencies instead of app-specific imports;
  • avoid embedded credentials, private endpoints, and app-only environment assumptions;
  • validate inputs and make failure behavior observable;
  • keep long operations off the foreground execution path and expose an owned asynchronous lifecycle with progress and cancellation where safe;
  • avoid uncontrolled global side effects;
  • export testable behavior when browser-independent logic exists;
  • document whether operations are synchronous, asynchronous, persistent, destructive, or networked.

Shared entities

A shared entity must:

  • represent a reusable record or value concept rather than an app workflow;
  • define defaults, normalization, serialization, and validation deliberately;
  • keep app-specific scoring, labels, permissions, and workflow transitions outside the entity;
  • remain usable without loading a particular app;
  • preserve backward compatibility or include an explicit migration when its stored shape changes.

If an entity name only makes sense inside one application's business domain, it normally belongs in that app. Extract reusable value objects or validators from it when possible.

Applications

An application must:

  • compose shared Arcane capabilities rather than duplicate them;
  • load Arcane base styles before all app-specific styles;
  • load and apply the user's shared Arcane theme instead of imposing an app-only default palette;
  • build app-level visual customization and overrides from Arcane theme variables;
  • keep only app-specific policy, content, routes, schemas, and orchestration locally;
  • map app records into neutral shared contracts at the app boundary;
  • request only the machine capabilities it needs;
  • use an arcane-package.json positive allowlist when distributable;
  • keep private source material, credentials, and development-only files outside public packages;
  • explain why every app-local component, module, or entity is business-specific;
  • publish app-owned compiled output through the application's release process rather than making Arcane OS setup compile it;
  • consume OS-owned runtimes and tools without rebuilding, redownloading, extracting, signing, hashing, or smoke-testing them once per app;
  • render or acknowledge before long work and keep that work in a bounded, owned background operation.

Core-only application local-AI policy

Local-model authority is package policy enforced by the app-scoped Core. It is not renderer configuration. An app that supports local inference authors one field, and only one alias-to-definition list, in apps/<id>/arcane-package.json:

{
  "localAIModelPolicy": {
    "verified_only": true,
    "models": [
      {
        "name": "EXAMPLE:8b",
        "definition": "Example-8B.Modelfile"
      }
    ]
  }
}

Use this procedure:

  1. Put each product Modelfile directly under its owning apps/<id>/ directory, add it to the app's positive package include rules, and declare one unique canonical Ollama name and one unique app-relative Modelfile basename for it. Do not put product definitions in another app or in the platform model directory.
  2. Use verified_only: true when the app may infer only with its declared models. An installed alias must match the exact app-owned definition before it can run. After native resource admission, Core may create or repair that managed alias from an admitted installed base, or pull the base only when its bounded registry-manifest/config and GGUF-prefix preflight supplies integrity-bound size and model metadata. A prefix is not full layer-integrity proof: Ollama must complete the full-digest-verified pull before Core creates or verifies the alias for inference.
  3. Use verified_only: false only when the product requirement explicitly permits inference with any already-installed model that passes native resource admission. The native app descriptor must also grant ai.models.unverified.inference. This mode is read-only for unverified models: it never pulls, creates, repairs, copies, pushes, or deletes one. Granting that capability while verified_only is true, or omitting it while the value is false, is a package error.
  4. Package the app through the normal app-owned release. The packager validates the exact policy shape and declared regular Modelfiles and writes the policy to ARCANE_APP_RELEASE.json as native admission metadata. The native OS packager verifies that the app-owned Modelfile set exactly matches the declaration. Platform-owned Arcane definitions remain under arcane/models/ and are projected only to native app/shared/.
  5. The generated dist/<id>/ARCANE_APP_RELEASE.json physically contains the normalized policy at the release root. Keep that record out of any public public browser inventory and the native renderer payload, and never consume or project its policy through browser manifests, catalogs, generic application metadata APIs, or application JavaScript. The native packager injects it only into the compiled Core application descriptor as aiModelPolicy. A static host serving the release root must deny and verify access to the release record before claiming it is not fetchable. The admitted model records returned by Arcane.localAI.status() are a Core result, not projection of the authored mapping.
  6. Populate local-model controls from the ordered, already filtered Arcane.localAI.status().models.ollama catalog. Render that authoritative Core result without a second app-owned size, GPU-name, alias, or family filter. Grant ai.inference for this admitted status API; do not grant ai.models.read merely to populate an application model picker. Raw model inventory is restricted to Settings, Terminal, and Shell diagnostics. Core evaluates actual installed model bytes and metadata, requested context and K/V-cache cost, current free system and GPU memory, loaded-model residency, and pull storage when applicable. Missing evidence fails closed.
  7. Without an app-scoped Core, the browser application is OpenAI-only. It must not probe or call Ollama directly, infer local availability from a loopback port, or expose a local-model choice. OpenAI prompting may still use an app-owned canonical prompt source; that is content, not renderer authority over local-model policy.

Focused coverage must prove policy-schema rejection, exact Modelfile ownership, policy/capability parity, release-manifest emission, public-inventory/native- renderer omission, no browser-runtime consumption or metadata projection, Core-only projection, authoritative catalog rendering, browser OpenAI-only behavior, bounded registry/GGUF preflight, full-digest pull completion, definition verification, and fail-closed resource admission. Do not duplicate the declared model list in renderer code or a second manifest to make a test convenient.

Decision examples

Example: business-specific editor

Need: “Allow a user to draft and save a case analysis.”

  • Reusable core: Markdown editing, preview, validation hooks, save state, and accessible controls.
  • App-specific logic: the case-analysis schema, prompt text, authorization, case identifier, storage location, and post-save workflow.
  • Placement: editor in arcane/components/; contract normalization in arcane/modules/ if shared; case adapter and persistence orchestration in apps/<id>/.

Example: app dashboard

Need: “Let users choose which operational panels appear.”

  • Reusable core: render available definitions, track selection state, emit changes, and display neutral empty/error states.
  • App-specific logic: available panels, their business meaning, user permissions, and where preferences are stored.
  • Placement: configuration component in arcane/components/; definitions and persistence adapter in apps/<id>/.

Example: domain record

Need: “Represent a legal matter with parties, deadlines, and filing status.”

  • App-specific entity: the legal matter and its workflow belong in the legal app.
  • Reusable extraction: generic file descriptors, people/contact values, date validation, and persistence interfaces may belong in arcane/entities/ or arcane/modules/ if their contracts are genuinely cross-app.

Prohibited shortcuts

Do not:

  • copy a shared component or module into an app to make a small variation;
  • put app names, domain terminology, hard-coded routes, private endpoints, or credentials in shared code;
  • make shared code import from apps/;
  • load app or component CSS before the Arcane base and depend on accidental cascade behavior;
  • replace the user's Arcane theme with a fixed app palette;
  • hard-code colors where an Arcane theme token expresses the same purpose;
  • reset shared theme variables at broad scope merely to brand one component;
  • use an app global when configuration, an event, or an injected provider provides a clear boundary;
  • create a second entity for the same record shape because an app uses different labels;
  • let a shared component decide domain authorization, persistence, or workflow completion;
  • expose a breaking shared contract change without updating and verifying every consumer;
  • publish repository roots or broad directories in place of positive package allowlists;
  • place invariant downloads, extraction, compilation, hashing, signing, integrity scans, or tests inside a per-app, per-model, per-asset, or per-target loop;
  • rerun a trust check when its artifact bytes, policy, identity, location, and toolchain are unchanged, or cite generic defense in depth as a reason to do so;
  • describe an adjacent, self-generated, or same-authority checksum as authentication, publisher proof, or authorization;
  • regenerate a digest from untrusted current bytes and use the result to re-baseline, restore, execute, activate, or label those bytes verified;
  • add progress reporting as a substitute for removing provably redundant work;
  • delay UI creation or initial CLI status until after network, disk, hashing, compilation, process, model, or integrity work;
  • call synchronous blocking work from an async function on the foreground thread, use unbounded concurrency, or start unobserved fire-and-forget work;
  • serialize an entire workflow when only a narrow trust or transaction boundary requires ordering;
  • defer obvious reuse extraction until after release.

Verification

Verification must be proportional to the change and must exercise the actual boundary.

For a shared capability:

  • add focused tests under test/ for input normalization, outputs, errors, and compatibility;
  • test that shared sources remain domain-neutral when practical;
  • add or update a browser example for interactive behavior;
  • verify component lifecycle, readiness, events, accessibility, and nested-route asset resolution;
  • verify visual behavior against the Arcane base and supported user themes, including focus and contrast-sensitive states;
  • run the consumers most likely to expose contract regressions.

For an app:

  • test its adapter, mapping, policy, and orchestration independently from the shared mechanism;
  • verify that Arcane styles load before app styles and that shared appearance preferences are applied;
  • inspect the app with default, light, dark, system, and custom themes when visual styling changes;
  • inspect the effective package with npm run app:inspect -- <app>;
  • build or dry-run the package as appropriate;
  • verify the packaged output with npm run app:check -- <app> after packaging.

Before completion, run the narrow relevant tests and the current development gate:

npm run check

Use npm run check:integration only for explicit portable Arcane OS integration work, and npm run release:check:arcane-os only for an explicit Arcane OS release. That gate admits the app-published ARCANE_APP_RELEASE.json payload but never imports app adapters or runs app source/content/business verification. Run an application's complete suite only when releasing that application.

Required design record

Use this short record in an issue, pull request, implementation note, or review description:

### Arcane capability decision

- I need to make a: [user-facing capability]
- Could other applications use it: [yes/no and why]
- App-specific business logic: [policy, terms, routes, domain schemas, provider-policy constraints, or none]
- Reusable core: [mechanism and neutral contract]
- Extraction boundary: [configuration/events/adapters/slots/providers/record mapping]
- AI boundary: [shared object-form DAO method, domain input/schema, provider-neutral normalized result, or not applicable]
- Structured-output contract: [closed JSON Schema, exact enum semantics, runtime validator, and model/default owner]
- Corpus contract: [authoritative store, stable full-document grouping, concurrency bound, partial-success coverage, actual-count progress, or not applicable]
- User-intent and diagnostic handling: [verbatim request source plus bounded non-sensitive response/failure correlation]
- Cancellation chain: [page-owned signal, bridge/Core/native propagation, actual upstream termination, and detached-work suppression]
- Terminal closeout: [always-offered tool, semantic trigger, strict final-message schema, remembered-action consent, central provenance purpose, and terminal UI]
- Central policy decision: [frozen enum, single owner/pass, immutable decision, and rejected boolean/bypass alternatives]
- Arcane theme base: [shared styles and theme loader]
- CSS layer order: [Arcane base -> shared feature -> app/component -> narrow override]
- User-theme verification: [themes and states checked]
- Shared files: [arcane paths or none]
- App files: [apps/<id> paths or none]
- Contract and compatibility impact: [new/extended/unchanged and affected consumers]
- Verification: [tests, example, app checks, packaging checks]
- JavaScript test convention: [shared vanilla-test 2.1.0 adapter, Node orchestration, and node:assert/strict]
- Delivery gates selected: [source / cache reference / selected dist / app release / native rebuild / signing / push, with non-selected gates]
- Work cardinality and loop multiplier: [items x nested items]
- Expensive-operation budget: [representative cold-path count, bytes, and time]
- Work classification: [invariant / identity-bound per item / batchable]
- Trust-fact evidence reuse: [one check per artifact state; immutable hash-bound evidence]
- Authenticity anchor: [attacker, independently authenticated expected value, and why payload authority cannot rewrite it; or consistency-only]
- Verification receipt lifecycle: [single owner, exact binding and generation, consumers, authenticated cross-process delegation, invalidation and mutation drain]
- Hoisting, caching, and batching: [what runs once; cache identity and verification]
- Justified repeated work: [item-specific reason and measured cost, or none]
- Remaining-work visibility: [phase/item/count/bytes/elapsed/rate/ETA as applicable]
- Immediate acknowledgement: [UI/CLI state visible before blocking work]
- Async owner and error path: [worker/task supervisor, visible error, log, exit status]
- Concurrency and backpressure: [explicit limits and queue behavior]
- Progress and heartbeat: [events, cadence, coalescing]
- Cancellation and retry/resume: [safe boundaries and partial-output handling]
- Required serialization: [true trust/transaction boundary and why]

If “Shared files” is none for a generally useful behavior, the record must explain why extraction is not currently safe or coherent. Convenience and schedule alone are not sufficient reasons.

Definition of done

A new capability is complete only when all applicable statements are true:

  • The four core questions have written answers.
  • Existing Arcane capabilities were checked before new code was created.
  • Reusable mechanism and app-specific business logic are separated.
  • Shared code is domain-neutral and has no dependency on an app.
  • Applications use the shared object-form AI DAO and contain no provider request construction or provider response normalization.
  • Structured model output has one closed JSON Schema, exact enum semantics, equally strict runtime validation, and Modelfile/shared defaults unless a recorded hard boundary requires an override.
  • Retrieval propagates the real user request verbatim; diagnostics correlate only bounded response/failure metadata and never persist prompts, bodies, credentials, or sensitive payloads.
  • A DBOPFS corpus is defined by its allowed stored keys, reads complete documents, uses stable fixed-count independently settled groups, preserves partial success, reports actual-file progress, and keeps warnings out of model prompts.
  • One page-owned AbortSignal reaches the shared AI DAO, bridge, Core, native host, and provider's actual upstream operation; detach prevents queued, retried, continued, and late-effect work.
  • A terminal closeout tool remains offered until completion, uses a semantic user-ending trigger and one strictly validated final_message, requires separate consent for remembered actions, accepts no-link closeouts, and passes the final message through one central provenance-purpose gate.
  • Terminal UI state is committed only after the accepted final message, expands the transcript, hides and disables controls, and rejects visible, programmatic, queued, retried, and late post-close submissions.
  • Finite policy choices use one centralized enum and decision point, without scattered booleans, bypasses, or duplicate validation.
  • Public inputs, outputs, events, errors, and defaults are documented.
  • Shared visual behavior is configurable and accessible.
  • Every app and visual component starts from the Arcane theme, applies saved user appearance preferences, and layers custom CSS afterward.
  • App and component overrides derive from Arcane tokens and remain usable across supported themes.
  • App-local files can be justified as business-specific orchestration or policy.
  • Every new or modified function and callback is named for useful stack traces and diagnostics.
  • The work-amplification review records cardinality, loop multipliers, and a representative cold-path operation/byte/time budget before implementation.
  • Invariant expensive work runs once, batchable work is batched, reusable output is cryptographically and identity-bound, and every necessary repetition is justified and measured.
  • Each trust fact is checked once per artifact state; unchanged evidence is reused, and placement/inventory-only assembly changes verify only that changed boundary.
  • Expensive trust decisions have one receipt owner, exact artifact-state binding, authenticated downstream reuse, and invalidation before mutation; cross-process reuse uses the shared host, broker, or service boundary.
  • Redundant scans and operations are removed before progress is added, and necessary long-running work remains visibly active.
  • UI and CLI acknowledgement precedes potentially blocking work; long operations use genuine asynchronous I/O or an owned background worker and do not block UI creation or the foreground thread.
  • Concurrency is bounded with backpressure, progress or heartbeat remains live, cancellation and retry/resume are supported where safe, and every worker failure reaches an observer.
  • Serialization is limited to documented trust or transaction boundaries entered only after visible status exists.
  • Focused shared and app tests cover the boundary.
  • JavaScript tests use the repository's shared vanilla-test 2.1.0 adapter, keep Node as orchestrator, and use node:assert/strict.
  • A synthetic example documents a new shared public contract when it materially improves reuse.
  • Package allowlists, cache references, capabilities, and versioned asset references are updated when the changed boundary requires them.
  • Focused tests and the development gate pass; selected demo packages or promotion gates pass only when those outputs are in scope.
  • Source, cache-reference, selected-package, release, native-build, signing, and push gates are selected explicitly; an ordinary development edit does not regenerate or verify every app package.

Review gate

Reviewers must be able to explain every app-local component, module, and entity as business-specific policy or orchestration. If an app-local file implements a general form control, persistence adapter, file browser, modal, status panel, provider wrapper, record validator, or other reusable mechanism, the change is not ready until that behavior is moved to the shared Arcane layer or a specific exception is documented and approved.

For visual work, reviewers must also confirm that the Arcane theme is the first layer, the user's saved appearance is applied, app and component CSS follows the shared layer, and overrides do not defeat user taste, accessibility, or cross-app consistency.

For setup, build, package, test, model, app, or runtime work, reviewers must also compare the implementation to the recorded multiplier and cold-path measurement. A change is not ready when invariant OS-owned work appears inside an app loop, expensive operations exceed the justified count, unchanged trust facts are checked again, reuse lacks complete identity binding, or progress UI merely makes redundant work visible.

Reviewers must also reject foreground blocking hidden behind async/await, delayed UI or CLI acknowledgement, unbounded fan-out, missing backpressure, silent fire-and-forget tasks, progress without a heartbeat during opaque waits, unsafe cancellation, or broad serialization that begins before visible status.

For AI, corpus, cancellation, and terminal-workflow changes, reviewers must reject app-built provider payloads, positional request APIs in new code, loose structured output, ambiguous enum descriptions, unrecorded app-side generation options or byte/token heuristics, model-rewritten retrieval queries, manifest-defined or truncated DBOPFS corpora, serial or all-or-nothing group handling, estimated-file progress, warning text in model prompts, and prompt/body diagnostics.

Reviewers must trace one page-owned signal through every transport and confirm abort stops the provider's actual upstream work as well as local effects. A change is not ready when detach can leave a queued group, retry, continuation, timer, persistence callback, or UI mutation alive.

For terminal closeout, reviewers must prove the tool remains available until successful completion, the trigger is semantic rather than keyword-based, the sole call parses to one complete final message, remembered actions receive separate consent, no-link messages remain valid, one centralized provenance-purpose policy runs exactly once, the terminal transcript commits before controls disappear, and every post-close submission path fails.

Reviewers must also reject scattered policy booleans, bypass flags, duplicate gate passes, app-local copies of shared provider or terminal mechanisms, direct node:test imports, private vanilla lifecycles, and unconditional all-app package/native/signing work. The selected artifact gates and fetched remote-equality evidence must match the actual delivery claim.

Repository and reviewed source access