kernel/time/FactInvalidationEngine

Summary: FactInvalidationEngine.js — namespaced `invalidatedBy` rules layered on the monotonic FactStore (engine/state/facts): adding a fact whose predicate has invalidation rules TOMBSTONES (never deletes) currently-live facts with the listed predicates. e.g. rule('planReady', ['planDraft']) — a new planReady fact revokes any live planDraft facts. History stays intact.


kernel/time/IdempotencyManager

Summary: IdempotencyManager.js — bounded process-local replay for settled tool and storylet results. Concurrent callers for one key share a single execution. Durable mutation replay safety is provided by the task-graph dispatch fence, not by this TTL/LRU cache.


IdempotencyCapacityError

class IdempotencyCapacityError extends Error


kernel/time/ParallelTaskScheduler

Summary: ParallelTaskScheduler.js — executes async tasks respecting dependency order (via DependencyScheduler) with a bounded concurrency limit. A failed task marks its transitive dependents blocked rather than aborting unrelated branches.


kernel/time/ReplayEngine

Summary: ReplayEngine.js — rebuild materialized state by folding the hash-chained EventLog through a reducer (event sourcing), optionally starting from a CheckpointManager checkpoint. The chain is verified BEFORE replay: tampered history refuses to replay rather than materializing a lie.


kernel/time/RetryManager

Summary: RetryManager.js — bounded exponential-backoff retry with jitter for transient AI/tool failures. Retries are attempts, not new intents: pair with IdempotencyManager keys so a retried effect is never applied twice.


kernel/time/RollbackEngine

Summary: RollbackEngine.js — the generic compensation runner: wraps engine/state/workflow/Saga.js (forward + compensating actions, irreversible pivot). Domain layers (e.g. storylets/StoryletFailureHandler.js) build on this rather than re-wrapping Saga themselves.


kernel/time/TickClock

Summary: TickClock.js — thin wrapper over engine/state/time/TimeModel.js (TIME_MODES/createTimeSource). Manages NAMED time sources: an AI task only "has time" if it subscribes to a source, and each source advances per its mode (causal steps, oscillator dt, irreversible change, observation, …) — never a global `time++`.


kernel/time/TimeAuthority

Summary: Disciplined civil-time authority. Network samples are transient observations. A consensus decision is accepted only after collapsing endpoints into independent operator groups, finding a majority interval, and combining the surviving offsets by uncertainty. The CSE records semantic transitions; it never treats timestamps as authority.


selectTimeConsensus

selectTimeConsensus(samples, options = {})

Summary: Select one robust time estimate from already-filtered source samples. Each operator gets at most one vote even when it exposes many hostnames.


kernel/time/TimeEngine

Summary: TimeEngine.js — Phase 7 facade (kernel.timeEngine) composing the Time Engine's CSE wrappers around ONE shared, hash-chained EventLog: authority   TimeAuthority (NTP consensus + slew) — disciplined physical time causal      CausalClock (HLC)                    — causal ordering ticks       TickClock (TimeModel sources)        — per-mode progression eventLog    engine/state EventLog                — the single OS AI log (Phase 9's AuditLog views the same log) timeline    TimelineExporter                     — tamper-evident export checkpoints CheckpointManager                    — compaction + restore replay      ReplayEngine                         — event-sourced rebuild idempotency IdempotencyManager                   — at-most-once effects cooldowns   CooldownManager                      — reservations + escrow rollback    RollbackEngine (Saga)                — compensation scheduler   Dependency/ParallelTaskScheduler     — ordered execution retry       RetryManager                         — bounded backoff expiry      ExpirationManager                    — TTL sweep facts       engine/state FactStore (direct reuse — no FactRegistry) invalidation/conflicts — rules layered on the monotonic FactStore


kernel/time/TimelineExporter

Summary: TimelineExporter.js — export view over engine/state/integrity/EventLog.js (append-only, hash-chained). Filters + serializes a range of the SHARED OS event log (the same log Phase 9's AuditLog views — one log, not two) with the chain verification result attached, so an exported timeline is tamper-evident.


kernel/tools/CapabilityAttenuator

Summary: CapabilityAttenuator.js — thin wrapper over engine/state Capability.attenuate() for narrowing a capability before handing it to a single tool call. Never widens a capability (attenuate() itself enforces this).


kernel/tools/ContextTaintTracker

Summary: ContextTaintTracker.js — tracks which OS.ai() request contexts have absorbed untrusted (tool/webpage/model) content, so prompt assembly can keep the CSE prompt-injection boundary visible downstream instead of silently blending untrusted text into "instructions".


kernel/tools/HiddenParameterDetector

Summary: HiddenParameterDetector.js — flags AI-supplied tool-call arguments that are NOT declared in the tool's schema (potential smuggled/hidden parameters) and prototype-pollution-shaped keys.


kernel/tools/MetadataRugPullDetector


kernel/tools/ToolCallSchemaValidator

Summary: ToolCallSchemaValidator.js — validates AI-supplied tool call arguments against the tool's declared JSON schema, reusing the existing webgpu-os/kernel/schema/SchemaValidator.js (no parallel validator).


kernel/tools/ToolPermissionChecker

Summary: ToolPermissionChecker.js — gates AI-initiated tool calls through kernel.permissions (RuleGraph), on top of (not instead of) the per-tool AffordanceRegistry.capabilityRequired check done by ToolRouter.


kernel/tools/ToolResultIngestAdapter

Summary: ToolResultIngestAdapter.js — the single chokepoint every AI-invoked tool result passes through on its way into the world model. Delegates to engine/state/worldmodel/UntrustedBoundary.js (no parallel wrapper); a tool result is always trusted:false and can never mint authority.


kernel/tools/ToolRouter

Summary: ToolRouter.js — AI Tool Firewall. The single entrypoint the AI Hub's tool-calling loop uses to run a registered tool on behalf of an app. Delegates actual tool registration/execution/history to the existing ToolDriver.js (kernel.toolDriver) — this class never duplicates that machinery, it wraps it with the checks an *AI-initiated* call needs before it's safe to run: permission check, rug-pull detection, hidden-parameter detection, schema validation, and affordance/capability gating. Every result is then ingested through the CSE prompt-injection boundary (ToolResultIngestAdapter → engine/state UntrustedBoundary) before it's handed back — a tool result is observation, never authority.


packages/AppCompiler

Summary: AppCompiler.js — compile an ingested source bundle into a signed `.prpkg`. Two paths: 1. NATIVE — the folder already has a valid `manifest.json` + JS entry. Files are packaged as-is under `files/`. 2. AUTO   — any HTML/WebGPU app. We probe it (engine/compat), generate a compatibility profile, an embedded source module (`__compat_source.js`), and a bootloader entry (`index.js`) that calls `engine.compat.boot(...)` at mount time. A normal WebGPU app → an engine-native, signed OS app. Output uses PackageBuilder.buildV2 (signed + encrypted + merkle + cert). With a developer (self-signed) key the package verifies as the community/unofficial tier; a root-issued cert promotes it to trusted.


packages/CapabilityMap

Summary: CapabilityMap.js — OS-adaptive bridge between the compat static probe and the kernel's capability vocabulary. The kernel's RuleGraph is the single source of truth for what capabilities exist (`KNOWN_CAPABILITIES`) and how risky each one is (`CAPABILITY_LABELS`). This module classifies EVERY known capability into one disposition and, for the statically-detectable ones, maps a compat probe signal (`profile.uses` / `profile.gpu`) onto it. Dispositions: - 'free'    — universally allowed by the default rule graph; never emitted (the app already has it). - 'auto'    — detectable + low/medium risk → auto-added when the probe sees it. - 'suggest' — detectable + high risk → SURFACED for review, never silently added. - 'declare' — grantable but not statically inferable → author opts in. - 'system'  — privileged / system-trust → never auto-added under any path. - 'runtime' — kernel-mediated ephemeral consent token → never accepted from or emitted into an application manifest. Least-privilege is preserved: only 'auto' caps are granted without review; high-risk and privileged caps always require an explicit decision. IMPORTANT — this is a BUILD-TIME ADVISORY layer, not a security boundary. Static source scanning has unavoidable false negatives (minification, obfuscation, dynamically-constructed API calls, runtime behavior that differs from source). The authoritative gate is the kernel's runtime complete-mediation stack: `guardSyscalls` default-deny + per-call `Permissions.require` + the `PermissionPortal`. Auto-added caps only ever cover low/medium-risk APIs, so a missed or spoofed signal cannot silently escalate to a high-risk capability. A module-load guard logs any kernel capability that is missing a disposition, so the table can never silently drift behind a newly-added kernel cap; the Security Doctor surfaces the same check (`auditCapabilityMap`) at boot.


policyOf

Summary: Resolve a capability's disposition string ('free'|'auto'|'suggest'|'declare'|'system'|'runtime'|'unknown').


riskOf

Summary: Risk level for a cap, read from the kernel's CAPABILITY_LABELS (default 'medium').


detectCapabilities

Summary: Run every detector against probe signals. Detectors are wrapped so a single malformed signal or detector bug can never throw during a build — a failing detector is treated as "not detected" and a one-time warning is logged. (Static detection is best-effort UX; the kernel's runtime guard remains the authoritative boundary — see module header.)


classifyPermissions

classifyPermissions({ signals, declared = [], granted = [] } = {})

Summary: Classify a probe against what is already declared/granted and produce the final permission list + a reconciliation report.


unclassifiedCapabilities

Summary: Kernel capabilities that have no disposition in this table (should be empty).


staleCapabilities

Summary: Capabilities classified here that no longer exist in the kernel vocabulary (stale entries).


auditCapabilityMap

Summary: Self-audit for the Security Doctor / boot self-test. Returns coverage counts and any drift (kernel caps with no disposition, or table entries that are no longer kernel caps). `ok` is true only when there is no drift in either direction.


Summary: Disposition + (for detectable caps) a `detect(signals)` predicate, keyed by the exact capability string from KNOWN_CAPABILITIES. A bare string is shorthand for `{ policy: <string> }` (no detector).


packages/FolderIngestor

Summary: FolderIngestor.js — turn any developer source into a { files, entry } bundle that AppCompiler can package. Sources: • Directory picker (File System Access `showDirectoryPicker`) • <input type="file" webkitdirectory> FileList • A single HTML File • A `.zip` (Uint8Array/ArrayBuffer/File) via Zip.parse • The OS VFS (a folder path or single file) via StorageManager • A remote URL (single-file HTML; CORS-aware) Output: { files: Map<string, string|Uint8Array>, entry: string, sourceType: string, name: string } Text files are decoded to strings; binary files stay as Uint8Array.


packages/Gzip

Summary: Gzip.js — gzip compress/decompress via the browser-native Compression Streams API. This is the SAME approach `bundle_engine.py` uses for the runtime bundle (`*.min.js.gz`) and its `--encrypt` loader: gzip the payload, then (optionally) AES-GCM it, and decompress in-browser with `DecompressionStream('gzip')`. No custom container format — a `.prpkg` payload is just `gzip(JSON)`. gzip carries its own whole-stream CRC-32 (validated by DecompressionStream), and we layer per-file SHA-256 + a signed Merkle root on top, so integrity is covered.


gzip

Summary: Gzip-compress a string or bytes.


gunzip

Summary: Gunzip to bytes, with a decompressed-size cap (zip-bomb guard).


gunzipText

Summary: Gunzip to a UTF-8 string.


packages/PackageBuilder

Summary: PackageBuilder.js — build a signed .prpkg from a folder of files. Output format (JSON envelope — zip support planned): { format:    'prpkg-v1', manifest:  { ... },          // manifest.json with files hash map blockmap:  { files: {...} }, // sha256 per file signature: { pubKey, sig },  // ECDSA P-256 over blockmap JSON files:     { path: content } // all file contents as strings } Usage: const pkg = await PackageBuilder.build({ id: 'os.my-app', name: 'My App', version: '1.0.0', publisher: 'local', entry: 'files/app.html', permissions: ['gpu'], files: { 'files/app.html': '<html>...' } }, cryptoDriver);


packages/PackageCrypto

Summary: PackageCrypto.js — AES-GCM payload encryption for .prpkg v2 containers. SECURITY NOTE (acknowledged in the plan): in a browser the decryption key must ship with the OS, so this encryption is OBFUSCATION / a licensing-and-guard hook — NOT true secrecy. Package *authenticity* comes from the ECDSA signature + the ring-0 trust chain (Phase 2), not from this encryption. Container binary layout (`.prpkg` v2): bytes 0..5   magic  "PRPKG2" byte  6      version (0x02) byte  7      flags  (bit0 = encrypted) bytes 8..19  AES-GCM IV (12 bytes)        [only if encrypted] bytes 20..   ciphertext (AES-GCM, tag appended)  | or plaintext gzip if not encrypted The inner plaintext is gzip(JSON{manifest, blockmap, files}) — the same gzip codec the bundler uses, decompressed in-browser via DecompressionStream('gzip'). ── Single-file layout (`.prpkg`, embeds the envelope) ────────────────────── A v2 package historically shipped as TWO files (the binary container + a `.prpkg.json` sidecar envelope). `embed()` fuses both into ONE self-describing `.prpkg`, so there is a single artifact to move around and verify: bytes 0..5    magic "PRPKGS" byte  6       version (0x01) byte  7       reserved (0x00) bytes 8..11   envelope length (uint32, little-endian) bytes 12..    envelope JSON (UTF-8) then          the full PRPKG2 container bytes (as produced by seal()) `split()` reverses it. The envelope is the PUBLIC, signed metadata; the embedded container is cross-verified against it by PackageVerifier.parseV2 (manifest + blockmap equality, signed blockmap.manifestHash, AES-GCM AAD = id@version, and the ECDSA signature) — so tampering with either half is detected.


packages/PackageLoader

Summary: PackageLoader.js — load an installed .prpkg app's entry module from OPFS. Installed packages live at: /os/packages/installed/{appId}/{version}/files/{relPath} Loading strategy: 1. Gather every file under the package's files/ dir. 2. Apply enabled PatchManager overlays (file-overlay layer) on top of base files. 3. Build a blob-URL module graph: each JS module's *relative* import/export specifiers are rewritten to the blob URL of the corresponding packaged file, resolved in dependency order (best-effort for cycles). 4. import() the entry blob URL and return the module namespace. Why rewrite specifiers instead of an import map? Import maps must exist before the first module loads; we resolve packages at runtime, so we inline the graph by rewriting relative specifiers to blob URLs. Blob URLs are retained for the lifetime of the loaded app and revoked when the package is reloaded or removed.


packages/PackageManager

Summary: PackageManager.js — install, remove, update, verify, repair, rollback .prpkg packages. Package lifecycle: download/pick → stage → verify → install → register → (update → rollback) Storage layout: /os/packages/installed/{appId}/{version}/   ← active package files /os/packages/staging/{appId}/{version}/     ← in-progress installs /os/packages/rollback/{appId}/{version}/    ← previous version for rollback /os/packages/locks/{appId}.lock.json        ← prevents concurrent installs /os/packages/chunks/sha256-{hash}           ← chunk cache (CacheDriver)


packages/PackageRegistry

Summary: PackageRegistry.js — IndexedDB-backed registry of installed packages. Each record in the 'packages' store: { id:          'os.shader-lab', name:        'Shader Lab', version:     '1.0.0', activeRootHash: 'a1b2c3d4...', // content-addressed install directory rollbackRootHash: '...',        // previous activation root hash rollbackVersion: null, rollbackAvailable: false, publisher:   'local', installedAt: 1234567890, updatedAt:   1234567890, entryPath:   '/os/packages/installed/os.shader-lab/a1b2c3d4.../files/app.html', manifest:    { ...full manifest... }, format:      'prpkg-v1', trustVerdict: 'trusted', pinned:      false, pinnedVersion: null, sourceUrl:   null,           // URL to check for updates }


packages/PackageScanner

Summary: PackageScanner.js — heuristic static pre-scan of package contents. This is an EARLY-WARNING badge, not a guarantee: novel obfuscation will evade heuristics. The real containment is default-deny egress + sandboxed execution (see PermissionPortal / guardSyscalls). The scanner flags the patterns seen in real 2025–2026 supply-chain payloads: heavy obfuscation, base64 blobs, dynamic code execution, credential/secret access, network exfiltration, and payloads hidden inside non-code assets. scan(pkg) → { risk: 'low'|'medium'|'high', findings: [{ level, code, file, msg }] }


packages/PackageVerifier

Summary: PackageVerifier.js — verifies .prpkg package integrity. Verification steps: 1. Validate manifest schema (format, required fields) 2. Verify each file's SHA-256 hash against blockmap 3. Verify ECDSA P-256 publisher signature over blockmap hash The publisher key fingerprint is stored in the manifest. Trusted publishers are managed by kernel.permissions.


packages/PublisherKeyManager

Summary: PublisherKeyManager.js — the developer's portable package-signing key. Distinct from `CryptoDriver` (the device identity), whose private key is NON-extractable and therefore cannot be backed up, moved between machines, or rotated with a lineage. A publisher who ships packages needs a key they can: - generate once and KEEP SAFE (encrypted export the dev stores offline), - re-import on another machine / after reinstall, - ROTATE while proving continuity (old key signs the new key — see kernel/SigningLineage.js), so app updates stay verifiable and isolated. The keypair is ECDSA P-256, **extractable**, stored locally (JWK in the IDB kv store) for day-to-day signing, plus an AES-256-GCM (PBKDF2-SHA256) encrypted backup the dev downloads and keeps. Signatures are raw IEEE-P1363 (WebCrypto default), the same format `CryptoDriver.verify` / CollabIdentity `verifyData` expects, and fingerprints are computed via `cryptoDriver.fingerprintOf` so the publisher fingerprint scheme matches the rest of the trust system.


packages/UpdateManager

Summary: UpdateManager.js — block-level differential update engine (MSIX-style, web-native). Update flow: check(appId)   → fetch remote blockmap from sourceUrl, diff against installed blockmap, return UpdateJob with changed/removed file lists. apply(appId)   → download only changed chunks, verify each sha256, verify package ECDSA-P256 signature, atomic-swap installed dirs, save previous version to rollback slot, update registry. rollback(appId)→ delegate to PackageManager.rollback() checkAll()     → check all installed packages that have a sourceUrl setSource()    → delegate to PackageManager.setSource() Remote blockmap format (served at {sourceUrl}/blockmap.json): { "appId":          "os.my-app", "version":        "1.2.0", "files": [ { "path": "index.js",      "sha256": "hex...", "size": 8192 }, { "path": "manifest.json", "sha256": "hex...", "size":  512 } ], "signature":      "base64-ecdsa-der...",   // optional — over canonical payload "signerPublicKey": { "kty":"EC","crv":"P-256", ... }  // optional JWK } Storage layout (under /os/packages/): .updates/{appId}/remote-blockmap.json  ← cached remote blockmap post-check .updates/{appId}/staged/               ← downloaded changed files installed/{appId}/{version}/           ← live package (PackageManager layout) rollback/{appId}/{version}/            ← previous version slot


packages/Zip


shell/Desktop

Summary: Desktop.js — the OS shell compositor. Owns: - Plauna workspace (virtual desktops, panel chrome, window management). - Taskbar (bottom bar: start menu + running apps + status tray). - NotificationCenter (toast/banner delivery). - Routing of kernel 'ui:open-panel' events to WorkspaceManager. Phase 2 adds AppManifestLoader → dynamic app registration. Phase 3 adds GPU panel wiring (canvas surface allocation per app).


createProvisionalMountHandoff

createProvisionalMountHandoff({ controller = new AbortController()

Summary: Own teardown while an async app mount is still provisional. Cancellation calls an attached cleanup synchronously, so the app observes its AbortSignal before the panel is removed. Any cleanup promise continues in the background while a pending close returns immediately. Once the mount has settled, callers replace this handoff with the real app and retain the normal awaited-unmount contract.


guardMountRegistrations

guardMountRegistrations(namespace, signal, methods = [], label = 'app capability')


shell/DialogManager

Summary: DialogManager.js — OS-level dialog system. Handles kernel `ui:modal` events and renders styled alert / confirm / prompt dialogs as a layered overlay above all panels. API (via kernel.events or syscalls.ui.*): ui:modal  { type, title, message, icon, buttons, defaultValue, resolve } Promise-returning syscalls (see Syscalls.js): syscalls.ui.alert(msg, opts)               → Promise<void> syscalls.ui.confirm(msg, opts)             → Promise<boolean> syscalls.ui.prompt(msg, default, opts)     → Promise<string|null>


shell/NotificationCenter

Summary: NotificationCenter.js — routes kernel ui:notify events to Plauna's ToastManager. Uses Plauna ToastManager directly (the same underlying system NotificationSystem uses). Falls back to a minimal DOM toast only if Plauna has not mounted yet.


shell/PackageHostRealm

Summary: PackageHostRealm.js — run an installed NATIVE package app inside an opaque-origin sandboxed iframe, bridging the kernel syscalls over a nonce-bound postMessage RPC. WHY: `PackageLoader` imports a package's entry module straight into the OS origin (S2). Trusted/root packages may keep that fast shared realm, but pinned/untrusted packages must NOT touch `window`, the OS DOM, localStorage, the extension bridge, or any accidental globals. This realm gives them an `allow-scripts` (NO `allow-same-origin`) iframe — a true origin boundary — and proxies the syscall surface back to the host's GUARDED syscalls for that app. BRIDGE SCOPE (honest limits): - Async, structured-cloneable syscalls (fs.*, storage.*, ui.notify/alert/ confirm/prompt, log.*, sandbox.*, net send/fetch, pkg reads, etc.) work: each call round-trips to the host, which invokes the real guarded method. - Subscriptions / callbacks (`.on`, `.onChange`, `.onEvent`, …) CANNOT cross the boundary; the in-iframe proxy returns a no-op unsubscribe so apps that register listeners do not crash (they simply receive no host events yet). - Raw `GPUDevice` / GPU surfaces cannot cross an opaque-origin boundary, so GPU-panel apps are NOT isolated here (the launcher keeps them shared). SECURITY: the host only ever services RPC bearing the exact per-instance nonce from the iframe it created, and only invokes `this._syscalls` (already guarded + capability-checked for THIS appId). Unknown namespaces/methods are refused.


shell/StartMenu


shell/StatusTray

Summary: StatusTray.js — rightmost section of the taskbar. A thin orchestrator: it composes stateless tray widgets (see ./tray/ tray-widgets.js) and owns the per-frame update loop. It does NOT render the calendar — clicking the clock requests the Calendar app's flyout surface. Layout (left → right): GPU stat | FPS stat | 🔍 | ⚡ | Clock | 🔔


shell/Taskbar

Summary: Taskbar.js - bottom shell coordinator. Rendering and behavior live in shell/taskbar modules so the taskbar can grow without becoming another monolithic desktop controller.


shell/WindowSizer

Summary: WindowSizer.js — Viewport-aware window sizing and placement. Computes default window dimensions and screen position based on: 1. The LIVE available desktop area (viewport minus taskbar) — not device type. 2. The app manifest's `category` (and optional `sizingHint`) to pick a sizing profile. 3. The manifest's `defaultWidth/defaultHeight` treated as design-time values at a 1440px reference viewport, then scaled proportionally to the actual viewport. Windows are centered in the available desktop area, with a configurable cascade offset for stacking multiple windows. ── Viewport contexts (based on available desktop width) ────────────────── compact   < 640px   — very constrained (browser in half-screen, etc.) medium    640–1024  — tablet / laptop / small desktop window wide      1024–1440 — typical desktop ultrawide > 1440    — large monitor / maximized on 4K ── Sizing profiles (per manifest category / sizingHint) ────────────────── compact   → small, fixed-size utility (calculator, clock) utility   → small utility panel tools     → medium tool (settings, pkg-manager) system    → medium-large system panel (sysmon, task-manager, terminal, files) debug     → narrow + tall (devconsole, log-viewer) creative  → large workspace (paint, notepad) webgpu    → large with canvas (fractal, particles, gpu-manager) games     → large, prefers square-ish (minesweeper, snake, solitaire) workspace → near-full (browser, heavy editors)  [sizingHint override] full      → fills entire desktop area            [sizingHint override]


availableDesktop

Summary: Returns the current available desktop dimensions (px).


computeWindow

computeWindow(manifest, cascadeIndex = 0)

Summary: Compute the optimal window { width, height, x, y } for a given manifest.


shell/WindowStateStore

Summary: WindowStateStore.js — Persist and restore per-app window position/size. Stored in localStorage under 'os.windowStates' as a versioned envelope whose `states` field maps appId → state. The historical bare map remains readable. Validates a restored state against the current viewport before using it; if the position is out of bounds or the size is unreasonable the saved state is silently ignored and the app opens at its computed default.


validateState

Summary: Validate a saved state for corruption only (finite, positive size). Position reachability is no longer a reject reason — clampToViewport() moves an off-screen window back into view instead of discarding the saved state.


clampToViewport

Summary: Reposition a state so a reachable strip of its titlebar stays inside the work area. Handles smaller screens / resolution changes / disconnected monitors — the window is pulled back on-screen rather than left unclickable.


clampStateSize

Summary: Clamp a state's width and height so neither falls below 15% nor exceeds 100% of the available desktop area.  Position is preserved as-is.


loadState

Summary: Load the saved window state for an app. Returns null when nothing is stored yet.


saveState

saveState(appId, { x, y, width, height, maximized = false })

Summary: Persist the current window state for an app.


clearState

Summary: Remove the saved window state for an app (e.g. after a reset).


clearAllStates

Summary: Remove every persisted window geometry record.


shell/app-icon

Summary: app-icon.js — custom app icons: emoji/glyph OR an uploaded/online image, animated GIF/WebP, or a short video. A manifest `icon` value may be ANY of: • an emoji / short glyph     — "🧩"  (default; what the shell drew before) • a still image data/URL     — data:image/… or https://…/x.png • an ANIMATED image          — animated GIF / WebP (plays via <img>) • a short video              — data:video/… or https://…/x.webm (muted loop) renderAppIcon() paints the right element into a container — drop-in for the old `el.textContent = manifest.icon`. Media icons size to the container's font-size (1em square), so each call site keeps its existing sizing. fileToIcon()/urlToIcon() turn a chosen file or remote URL into a compact, self-contained data URL (downscaled + size-capped; animation preserved when it fits) suitable for embedding in a manifest at compile time.


renderAppIcon

renderAppIcon(container, icon, { fallback = '▪' } = {})

Summary: Render `icon` into `container` (cleared first). Emoji/glyph → text (so the caller's font-size applies); image/video → a 1em-square media element.


fileToIcon

Summary: Turn a chosen File into a compact icon data URL. • video      → kept as-is if ≤ VIDEO_CAP (muted loop). • animated   → kept as-is if ≤ FULL_CAP (preserves animation); else flattened. • SVG        → kept as-is if small; else rasterised. • other img  → center-cropped + downscaled to a 128² WebP.


bytesToIcon

async bytesToIcon(bytes, filename = 'icon')

Summary: Build an icon data URL from raw bundled file bytes (Uint8Array/ArrayBuffer) or a string (SVG/text), inferring the MIME type from the filename. Used to auto-detect an icon from an app's own files at ingest time.


urlToIcon

async urlToIcon(url, { fetchImpl = null } = {})

Summary: Fetch a remote image/video URL and embed it as a compact data URL (so the icon is self-contained — no live remote dependency, no privacy leak at render time). Cross-origin hosts that block CORS will reject; the caller should suggest downloading + uploading instead.


shell/desktop/WindowLayoutEngine

Summary: Pure window-layout geometry shared by the desktop shell and Theme Manager.


computeLayoutRect

computeLayoutRect(layout, inputArea, inputGap = 8)

Summary: Compute a pixel rect for a named layout. Gaps are applied at outer and inner edges.


detectEdgeLayout

detectEdgeLayout(pointer, inputArea, threshold = 34)

Summary: Resolve an edge/corner pointer position into a snap layout.


shell/desktop/shellEnhancements


shell/desktop/windowActions


shell/gpu-ui/GPUTextRenderer

Summary: GPUTextRenderer.js — Level-4 GPU-native text. The browser gives us no GPU text primitive, so we rasterize each glyph ONCE with Canvas2D (white on transparent) and pack it into the engine's VGPUTextureAtlas. Drawing a string then becomes a run of tinted textured quads sampled from that atlas — fully GPU-composited, no DOM. Glyphs are cached per (sizePx, weight, char). Whitespace stores advance-only (no atlas region). Coordinates are CSS pixels, top-left origin, matching the compositor's quad space.


shell/gpu-ui/GPUUICompositor

Summary: GPUUICompositor.js — Level-4 GPU-native UI compositor (3D by default). Renders the desktop's windows as tinted textured quads in a real perspective scene on a full-screen WebGPU canvas. There is NO DOM in this path: text is rasterized into a glyph atlas (GPUTextRenderer) and everything — window surfaces, titlebars, glyphs — is one unified quad primitive. Camera: a perspective camera placed on +Z at d = (vpH/2)/tan(fov/2) so the z=0 plane maps 1:1 to CSS pixels. A window at z=0 with no tilt is therefore pixel-perfect and fully usable, yet it's a genuine 3D quad — depth (z) and tilt are first-class, focused windows come forward, and a subtle pointer parallax sells the 3D space. Coordinate spaces: - window-local px: origin top-left, +x right, +y down (what widgets author) - world units == CSS px, origin = viewport center, +Y up, desktop on z=0 - per-window model matrix maps local px → world (bakes centering + Y-flip) Transparency uses painter's order (windows sorted far→near, widgets in emit order) so there is no depth buffer and no coplanar z-fighting. Engine tech reused (no duplication): VirtualGPU (isolated instance), VGPUTextureAtlas (glyph/solid atlas), engine/core/math (camera + unproject).


shell/gpu-ui/GPUWindow

Summary: GPUWindow.js — a GPU-native window for the Level-4 3D UI. The window is authored entirely in LOCAL pixel space (origin = top-left, +x right, +y down) and emits tinted atlas quads through the compositor's sink. It knows nothing about the camera: the compositor builds a per-window model matrix from this window's desktop-space rect + 3D placement (z/tilt) and applies the shared viewProj. This keeps widgets camera-agnostic so the same window is pixel-perfect head-on (z=0) or tilted in the immersive spread. Hit-testing is done in local space (compositor unprojects the pointer ray onto the window plane, then asks the window what was hit).


shell/gpu-ui/GPUWindowCapture

Summary: GPUWindowCapture.js — live per-window content via the Element Capture API. Chrome 132+ lets us restrict a getDisplayMedia track to a single DOM element (RestrictionTarget + track.restrictTo), yielding a live MediaStream of just that element's rendered subtree (no occlusion / "hall of mirrors"). We take ONE getDisplayMedia('this tab') stream, clone its track per window, restrict each clone to that app's panel element, and feed a hidden <video>. The GPU compositor then copyExternalImageToTexture()s each video frame into the window's content-atlas region every frame → fully live GPU windows. Requirements (per spec) on each captured element: it must form a stacking context (isolation:isolate) and be flattened (transform-style:flat) with an opaque background. Desktop applies these before attaching. Gracefully unsupported on non-Chromium / older builds (supported=false) so callers fall back to extension snapshot, then native chrome.


Summary: Immersive3DCompositor.js — Level-3 GPU compositor (Exposé-style 3D desktop). Captures every live DOM panel to a GPU texture (via PanelCapture), then renders each as a textured quad in a perspective 3D scene on a full-screen WebGPU overlay canvas. ALL matrix/camera math comes from the engine's direct-named shader-math library (engine/core/math) — we only add the WebGPU plumbing and the DOM→bitmap bridge the browser doesn't provide. Coordinate system (pixel-perfect at immersion=0): - World units == CSS pixels. Origin at viewport center, +Y up, desktop on z=0. - Camera sits on +Z at distance d = (vpH/2)/tan(fov/2) so the z=0 plane fills the viewport exactly. A panel quad at z=0 therefore maps 1:1 to its DOM rect. - immersion ∈ [0,1] pushes panels apart in Z by stacking order and adds a gentle mouse-driven camera yaw/pitch for parallax — the "3D world" feel. Lifecycle: const c = new Immersive3DCompositor({ device, getPanels }); c.mount();                 // create overlay canvas + pipeline await c.enter();           // capture panels, hide DOM, animate in await c.exit(panelId?);    // animate out, restore DOM (focus panelId if given) c.unmount();               // full teardown Engine math used: mat4Identity, mat4Translate, mat4Scale, mat4Multiply, mat4LookAt, mat4PerspectiveDegWebGPU.


shell/immersive/PanelCapture

Summary: ⚠ SUPERSEDED for GPU use. The bitmaps this produces are PERMANENTLY cross-origin-tainted (SVG <foreignObject> rule) and are REJECTED by `copyExternalImageToTexture`. The immersive compositor now captures the viewport via the extension bridge (chrome.tabs.captureVisibleTab → Desktop._captureViewport), which yields untainted, GPU-uploadable pixels. This file is kept only for display-only canvas uses (which tolerate taint). PanelCapture.js — live DOM element → ImageBitmap via SVG foreignObject. Everything else in the immersive compositor (3D quads, perspective camera, texture upload) is done with the engine's shader-math + WebGPU stack. But the browser provides no API to turn an arbitrary <div> (text + Plauna widgets) into pixels — `createImageBitmap` only accepts <img>/<canvas>/<video>/Blob. The zero-dependency route is SVG <foreignObject>: clone the element, inline its computed styles (a standalone SVG blob has no access to the page's stylesheets), serialize to XHTML, wrap in an SVG, rasterize through an <img>, then `createImageBitmap`. The resulting bitmap is uploaded by the engine's TextureManager (`copyExternalImageToTexture`). Known limitations (inherent to foreignObject, documented for callers): - <canvas>/<video> children don't serialize (their live pixels are lost). - Cross-origin images taint and are skipped by the browser. - `backdrop-filter` is not honored inside foreignObject. - Custom web fonts must already be loaded (we don't embed font files). Usage: const cap = new PanelCapture(); const bitmap = await cap.capture(panel.element, { scale: devicePixelRatio }); // → upload bitmap via engine TextureManager._uploadBitmap(bitmap, label) bitmap.close();


shell/overlay/AIOverlay

Summary: AIOverlay.js — shell-owned approval and elicitation popup. The surface is hidden unless the shared ElicitationManager has a pending request. It deliberately has no ambient bar, chat console, task browser, or timeline. Approval notes are bound to the exact request and elicitation and recorded before the resumed task can observe the decision promise.


shell/overlay/AdaptationReviewPolicy

Summary: The shell gives adaptation reviews distinct trusted UI only when the request is the exact AI Echo operation. Caller-controlled schema labels alone are never enough to obtain privileged wording or non-blocking decision behavior.


shell/overlay/ApprovalCard

Summary: ApprovalCard.js — overlay card for a pending AI tool-call approval. Driven through the SAME ElicitationManager as questions (an approval is a boolean elicitation whose schema carries { kind:'approval', toolName, params, risk }) — no parallel approval queue. Parameters are shown through ParameterPreviewer (Phase 5) so secrets are masked before they ever hit the DOM.


createApprovalCard

createApprovalCard(elicitation, { onApprove, onDeny })


shell/overlay/ElicitationCard

Summary: ElicitationCard.js — overlay card for a mid-task AI question to the user (Phase 4 ElicitationManager). Renders a text input, or buttons when the schema declares an enum of options. Answer → respond(); dismiss → decline().


taskCheckpointChoices

Summary: Validate the kernel-owned checkpoint envelope before exposing choices. The UI does not infer choices or authority from prompts. It only renders the exact bounded values supplied by the active task elicitation.


createElicitationCard

createElicitationCard(elicitation, { onRespond, onDecline })


shell/start-menu/actions


shell/start-menu/apps


shell/start-menu/constants


shell/start-menu/contextMenu


shell/start-menu/dom


shell/start-menu/state


shell/start-menu/vfsPins


shell/start-menu/views


shell/taskbar/appButtons


shell/taskbar/devBadge


shell/taskbar/showDesktop

Summary: showDesktop.js — the far-right "Show desktop" sliver (Windows-style). Click once to minimize every open window; click again to restore the same set. Mirrors the Win+D peek/minimize-all corner button. We track which panels are currently minimized via the kernel's panel events so the toggle stays correct even as the user opens/closes/minimizes windows manually.


shell/taskbar/startButton


shell/tray/system-tray

Summary: system-tray.js — the notification-area icon strip. Renders app-registered status icons (kernel.tray) inline, collapsing extras into an overflow popup (the "^" chevron) just like Windows' notification area. Left click runs the icon's onClick; right click opens its menu (if any). createSystemTray(kernel) -> { el, dispose }


shell/tray/tray-widgets

Summary: tray-widgets.js — stateless builders for the status-tray DOM widgets. Un-nested from StatusTray so the tray class stays a thin orchestrator. Each factory returns plain DOM (plus refs where the tray needs to update them); none of them hold tray state.


makeStatPill

Summary: Stat pill with a status dot + text (used for GPU / FPS readouts).


makeIconButton

Summary: Square icon button (search / quick-settings / bell).


makeBellButton

Summary: Bell button with an unread badge. Returns { wrap, badge, setCount }.


makeClockButton

Summary: Clock button (time + date stacked). Returns { btn, tick, dispose }. `tick()` refreshes the displayed time; `dispose()` clears its interval.


storage/AppDataReadbackService

Summary: OS-wide catalog and encrypted readback coordinator for durable app data.


storage/AppSandbox

Summary: AppSandbox.js — Per-app isolated, AES-256-GCM encrypted IndexedDB storage. Each app runs in its own IndexedDB database:  os.sandbox.<appId> completely separate from the kernel database (os.kernel). ── Isolation guarantees ───────────────────────────────────────────────────── • Different IDB database per app  → app A can never query app B's IDB. • AES-256-GCM encryption at rest → even if raw IDB is accessed directly, values are unreadable without the derived key. • Key is PBKDF2-derived from: OS fingerprint (ECDSA public key hash) + appId → keys are device-bound AND app-bound; exporting the raw IDB to another OS instance or another appId produces only garbage. ── API ────────────────────────────────────────────────────────────────────── const sb = new AppSandbox('os.calculator', cryptoDriver); await sb.init(); await sb.set('lastResult', 42);       // encrypt + store const v = await sb.get('lastResult'); // decrypt + return (null if missing) const keys = await sb.list();         // returns key names (not values) await sb.delete('lastResult'); await sb.clear();                     // wipe all of this app's data const info = sb.info();               // { appId, dbName, encrypted: true } ── Syscall surface (apps see syscalls.sandbox.*) ──────────────────────────── Created by createSandboxSyscalls(sandbox) exported below. Apps never receive a reference to AppSandbox directly.


createSandboxSyscalls

Summary: Wrap an AppSandbox as the `syscalls.sandbox` namespace for an app. Apps receive this — they never get a reference to the AppSandbox itself. Usage in app code: await syscalls.sandbox.set('prefs', { theme: 'dark' }); const p = await syscalls.sandbox.get('prefs'); const keys = await syscalls.sandbox.list(); await syscalls.sandbox.delete('prefs'); await syscalls.sandbox.clear(); const { appId, dbName, encrypted } = syscalls.sandbox.info();


storage/AppSettingsFile

Summary: Shared, Files-visible settings document used by OS apps.


readAppSettings

async readAppSettings(syscalls, { migrate = true } = {})


patchAppSetting

async patchAppSetting(syscalls, appId, value)


storage/BoundedTraversal

Summary: Breadth-first, paged traversal shared by OPFS and mounted folders.


StorageTraversalLimitError

class StorageTraversalLimitError extends Error


isIgnoredEntry

isIgnoredEntry(name, rules = [], path = '')


walkPaged

async walkPaged(rootPath, listPage, options = {}, defaultIgnore = [])


storage/CacheDriver

Summary: CacheDriver.js — Cache API wrapper for rebuildable assets. Used for content that can always be re-downloaded/rebuilt: - CDN assets and web dependencies - Downloaded package chunks (sha256-keyed) - App bundles and compiled shaders - Prefetched update manifests Keys are URLs or opaque cache keys like "chunk:sha256-abc123". All methods are async.


storage/IndexedDBDriver

Summary: IndexedDBDriver.js — IndexedDB-backed metadata store. The driver waits for transaction completion, closes connections when another tab upgrades the database, and refuses to reuse such stale connections. Store owners may opt into per-record schema metadata and synchronous migrations; unregistered stores retain their original record shape.


IndexedDBDriverError

class IndexedDBDriverError extends Error


IndexedDBBlockedError

class IndexedDBBlockedError extends IndexedDBDriverError


IndexedDBStaleConnectionError

class IndexedDBStaleConnectionError extends IndexedDBDriverError


IndexedDBRecordVersionError

class IndexedDBRecordVersionError extends IndexedDBDriverError


storage/KernelMetadataReadback

Summary: Encrypted readback snapshot for the structured `webgpu-os` metadata DB. Non-extractable CryptoKeys and native directory handles are represented by safe descriptors; their browser security boundary is intentionally retained.


storage/LegacyStorageReadback

Summary: LegacyStorageReadback.js — encrypted VFS readback for durable localStorage. Older OS modules still use localStorage directly. Rewriting every caller at once would create migration risk, so this service mirrors the durable keys into an AppSandbox. AppSandbox then publishes one authenticated, device-bound ciphertext container under /user/app-data. Raw names and values never appear in Files. OPFS fallback records and rebuildable caches are deliberately excluded because their authoritative data already lives elsewhere.


storage/MountDriver

Summary: MountDriver.js — File System Access API driver for user-mounted folders. Manages persistent directory handles for: /mnt/engine    — local engine source folder /mnt/assets    — local asset folder /mnt/projects  — local projects folder /mnt/apps      — local user app folder Directory handles are persisted via IndexedDB (idbDriver) so mounts survive page reloads without re-prompting the user (if permission granted). All read/write methods are async.


storage/MountGraph

Summary: Ordered provider layers with GMod-style read fallthrough and one write layer.


storage/MountRegistry

Summary: Case-insensitive registry for provider-neutral mount metadata.


validateMountAlias

Summary: Return a portable, single-segment mount alias without changing its case.


storage/OPFSDriver

Summary: OPFSDriver.js — Origin-Private File System driver. Uses navigator.storage.getDirectory() to provide a private OS disk that: - survives page reloads and browser restarts - is not subject to the 5 MB localStorage quota - supports byte-level writes and sync access from workers - is not visible or accessible to other origins All methods are async. Paths are POSIX-style: /os/state/foo.json


storage/RealmContentStore


storage/StorageCoordination

Summary: Same-origin storage coordination shared by tabs and workers. BroadcastChannel keeps observers coherent; Web Locks serializes lifecycle mutations. Both degrade to an in-process queue when unavailable.


StorageCoordinationUnavailableError

class StorageCoordinationUnavailableError extends Error


storage/StorageManager

Summary: StorageManager.js — unified storage facade. Routes filesystem paths to the correct backend: /os/*        → OPFSDriver  (OS internal files, packages, patches, logs) /user/*      → OPFSDriver  (user documents, settings, projects) /run/*       → OPFSDriver  (ephemeral runtime state — cleared on boot) /mnt/*       → MountDriver (user-mounted native folders via FSAA) /cache/*     → CacheDriver (rebuildable assets, package chunks) (other)      → OPFSDriver  (fallback) IndexedDB (idbDriver) is NOT path-routed — it is accessed directly by structured subsystems (PackageManager, PermissionManager, etc.). This is the backend for kernel/VirtualFS.js (which keeps its sync-friendly public API and delegates here for persistence).


StorageAtomicConflictError

class StorageAtomicConflictError extends Error


StorageAtomicUnsupportedError

class StorageAtomicUnsupportedError extends Error


StorageAtomicOutcomeUnknownError

class StorageAtomicOutcomeUnknownError extends Error


StorageAtomicAbortError

class StorageAtomicAbortError extends Error


RecycleBinSafetyError

class RecycleBinSafetyError extends Error


StorageContractError

class StorageContractError extends Error


storage/StorageSafety

Summary: Browser-file validation and secret detection. Files remain untrusted after validation.


StorageContentValidationError

class StorageContentValidationError extends Error


assertNoSecrets

assertNoSecrets(value, { path = 'managed file' } = {})


validateImportedFile

async validateImportedFile(blob, name = '')


storage/StorageWorker


storage/StorageWorkerClient


StorageWorkerUnavailableError

class StorageWorkerUnavailableError extends Error


storage/SystemFS

Summary: SystemFS.js — read-only virtual filesystem for the compiled-in OS. The engine, Plauna shell, editor, AGI runtime and the built-in apps are packaged directly into the OS bundle (ES modules compiled into the runtime). They are NOT stored in OPFS or IndexedDB, so they can never be edited, moved, or deleted — they are part of the system image. This driver surfaces them as a browsable, read-only tree mounted at `/system` so the Files app can SHOW where they live and clearly mark them immutable, while user/installed content (OPFS + IndexedDB) stays fully writable. Every entry returned carries `{ system: true, readOnly: true }` so the UI and the StorageManager guards can treat it as immutable. All methods are async to match the other storage drivers.


storage/UserDataPaths

Summary: Canonical user-owned locations shown and managed by the Files app.


appDataReadbackPath

Summary: Device-bound encrypted readback container for an app-owned sandbox.


cleanUserFileName

cleanUserFileName(value, fallback = 'untitled')


storage/WorkspaceOutputTerminology

Summary: Presentation-only terminology for canonical Workspace Output references.


workspaceOutputPresentation

workspaceOutputPresentation(entry, outputContracts = [])

Summary: Classify an indexed output for human-facing UI without changing its signed identity or treating a derived index entry as a second copy of the file.


workspaceOutputContractPresentation

Summary: Human-facing catalog projection for settings and Files coverage views.


storage/system-docs

Summary: system-docs.js — the "examples database" surfaced as the read-only /system tree. Goal: expose HOW to use each part of the compiled-in OS (engine, Plauna shell, editor, AGI runtime, built-in apps) WITHOUT shipping the proprietary source. Every leaf here is a usage/recipe document — it shows the public API and example calls a developer would write, not the implementation. Shape — a recursive node: { icon?:  string,                  // shown in the Files app files?: { '<name>': '<text>' },  // leaf docs (markdown / example text) dirs?:  { '<name>': <node> },    // sub-folders } Notes for authors: - Use 4-space-indented code blocks (NOT triple backticks) so content stays valid inside these template-literal strings. - Only document verified, public API surface (syscalls, app lifecycle, manifest schema, VFS). Keep deep internals conceptual. - This is a database: add files/dirs freely — SystemFS renders them as-is.