Skip to content
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
6 changes: 5 additions & 1 deletion AGENTS.md
Original file line number Diff line number Diff line change
Expand Up @@ -133,6 +133,9 @@ Test docs:
- `/tests/AGENTS.md`
- `/tests/agent_llm_performance/AGENTS.md`
- `/tests/browser_component_harness/AGENTS.md`
- `/tests/fixtures/AGENTS.md`
- `/tests/fixtures/component_context_menu_bundle/AGENTS.md`
- `/tests/fixtures/customware_bundle_example/AGENTS.md`

## Programming Guide

Expand Down Expand Up @@ -178,7 +181,7 @@ Top-level structure:
- `commands/`: CLI command modules such as `serve`, `help`, `get`, `set`, `version`, and `update`
- `app/`: browser runtime, layered customware model, shared frontend modules, and browser test surfaces
- `server/`: thin local infrastructure runtime, with page shells, request routing, API hosting, fetch proxying, file-watch indexes, auth/session infrastructure, and Git support code
- `tests/`: repo-level verification harnesses, prepared evaluation fixtures, and saved result artifacts
- `tests/`: repo-level verification harnesses, prepared evaluation fixtures such as `tests/fixtures/`, and saved result artifacts
- `packaging/`: optional Electron host and packaging scripts; native hosts should stay thin

Project concepts:
Expand All @@ -188,6 +191,7 @@ Project concepts:
- browser modules are namespaced as `mod/<author>/<repo>/...`
- frontend extensibility is a core runtime primitive; the framework installs `space.extend` first and the browser runtime grows by loading modules and extension points deterministically
- the layered browser model is `app/L0` firmware, `app/L1` group customware, and `app/L2` user customware
- customware bundles are ordinary installed `L1` or `L2` modules that include a `space.bundle.yaml` manifest; the server discovers them through the same module index and permission model, and the browser uses `space.bundles` for metadata reads, removable action handlers, and external bridge-state sync points
- `app/L1` and `app/L2` are the logical writable layers; on disk they default to `app/L1` and `app/L2`, but when `CUSTOMWARE_PATH` is set the backend stores them under `CUSTOMWARE_PATH/L1` and `CUSTOMWARE_PATH/L2`
- writable layer content is transient runtime state and is gitignored when it lives under the repo; do not treat it as durable repo-owned sample content
- `L2/<username>/user.yaml` stores user metadata such as `full_name`; auth state lives under `L2/<username>/meta/`
Expand Down
8 changes: 8 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -134,6 +134,14 @@ node space supervise HOST=0.0.0.0 PORT=3000 # zero downtime auto-update

Run `node space help` to see the full command surface and built-in help for each from [`commands/params.yaml`](./commands/params.yaml).

## Customware bundles

Reusable customizations can ship as customware bundles: ordinary `L1` or `L2` modules with a root `space.bundle.yaml` manifest.

Bundles stay inside Space Agent's existing browser-first model. They add UI through `ext/html`, behavior through `ext/js` and `space.extend(...)`, skills through `ext/skills`, theme or landing-background CSS through `_core/framework/theme/end`, and removable browser actions through `space.bundles.actions`. The manifest exposes metadata such as id, version, capabilities, config defaults, compatibility, extension points, and action descriptions.

Install, update, or remove a bundle the same way you manage any customware module under `L1/<group>/mod/<author>/<repo>/` or `L2/<user>/mod/<author>/<repo>/`. Direct runtime injection is discouraged because it depends on private implementation details; when a customization needs a new stable seam, add or propose that seam instead.

## AI-driven development and documentation

Space Agent is developed by AI agents, including its documentation.
Expand Down
9 changes: 5 additions & 4 deletions app/AGENTS.md
Original file line number Diff line number Diff line change
Expand Up @@ -115,7 +115,7 @@ Current browser entry surfaces are served from `server/pages/`:

Current major first-party modules under `app/L0/_all/mod/_core/`:

- `framework/`: frontend bootstrap, runtime primitives, component loader, extension system, shared utilities
- `framework/`: frontend bootstrap, runtime primitives, component loader, extension system, customware-bundle runtime helpers, shared utilities
- `agent-chat/`: headless shared chat helpers that belong to first-party agent features rather than the platform layer, currently including repeated-assistant-message evaluation helpers and hook implementations reused by overlay and admin chat
- `login_hooks/`: headless authenticated-bootstrap lifecycle hooks for first-login and same-origin `/login` arrival events, with a client-owned `~/meta/login_hooks.json` marker and feature-owned onboarding hooks such as the spaces module's first-login `Big Bang` onboarding-space bootstrap
- `visual/`: shared visual language, canvas, chrome, buttons, dialog helpers, conversation rendering primitives, and reusable authenticated-app imagery under `visual/res/`; pre-auth `/login` and `/enter` keep their mirrored astronaut asset under `server/pages/res/`
Expand Down Expand Up @@ -175,7 +175,7 @@ Current boot flow:

1. A page shell in `server/pages/` loads shared framework CSS and `/mod/_core/framework/js/initFw.js`.
2. The shell exposes one top-level HTML anchor in the body.
3. `initFw.js` installs the runtime, injects the framework-owned `_core/framework/head/end` HTML seam into `document.head`, runs the extensible framework bootstrap step in `_core/framework/js/initializer.js`, including framework-wide navigation interception for same-origin `_blank` app opens and best-effort current-tab cross-origin escape blocking, then installs Alpine helpers and shared bootstrap behavior.
3. `initFw.js` installs the runtime, injects the framework-owned `_core/framework/theme/end` and `_core/framework/head/end` HTML seams into `document.head`, runs the extensible framework bootstrap step in `_core/framework/js/initializer.js`, including framework-wide navigation interception for same-origin `_blank` app opens and best-effort current-tab cross-origin escape blocking, then installs Alpine helpers and shared bootstrap behavior.
4. The first mounted module owns the next seam and exposes more anchors or wrapped functions.
5. Other modules compose into those explicit seams instead of patching private internals.

Expand Down Expand Up @@ -203,7 +203,7 @@ HTML extension anchors:
- HTML callers name only the seam; the runtime loads `<x-extension>` tags from the module's `ext/html/` tree automatically
- thin extension files should usually mount the real component from the module root instead of containing the entire feature directly
- root page anchors such as `body/start` and `page/admin/body/start` are fixed shell contracts; module-owned anchors should be named after the owning module path, for example `_core/router/shell_start`
- `_core/framework` also creates `_core/framework/head/end` in `document.head` during bootstrap so layers can add declarative head-side tags or inline bootstraps without editing page shells or adding a JS hook
- `_core/framework` also creates `_core/framework/theme/end` and `_core/framework/head/end` in `document.head` during bootstrap so layers can add declarative theme CSS, head-side tags, or inline bootstraps without editing page shells or adding a JS hook
- runtime discovery watches the whole document tree, so `x-extension` and `x-component` insertions under `head` are supported the same way as body-mounted seams
- `_core/onscreen_menu` owns a reserved centered header bar from `_core/router/shell_start`; it keeps `_core/onscreen_menu/bar_start` on the left and `_core/onscreen_menu/bar_end` on the right for shell-level controls, allows route-owned `x-inject` content to target the existing left-side `[id="_core/onscreen_menu/bar_start"]` container when a feature wants ephemeral controls that disappear with the route but the shell seam may mount later, keeps a persistent Home button that routes to the empty route `#/` so the router default decides the home screen, and exposes `_core/onscreen_menu/items` as the dropdown action seam for non-Home feature buttons, whose modules contribute thin button adapters with numeric `data-order` values while `_core/onscreen_menu` sorts them automatically and keeps only the auth exit action local after the seam; `_core/dashboard` is the current first-party example of a route-owned wrapper that injects into `bar_start` and then exposes ordered dashboard-local seams for dashboard-only topbar actions
- `_core/web_browsing` is the current first-party example of a module that uses both `_core/onscreen_menu/items` and `page/router/overlay/end`: it contributes a Browser menu action at `data-order="250"`, opens a new floating browser window each time the action is used, keeps each browser surface on a unique internal `browser-N` id while the public `space.browser` runtime surface exposes numeric ids such as `1`, lets widgets or other screen DOM create registered surfaces with plain `<x-browser src="...">` markup, keeps that public runtime surface top-level and id-based only instead of exposing per-window handles, auto-settles open or state or navigation or inspection helpers internally so they can return fresh browser state snapshots without a separate `sync(...)` step while ref-targeted actions return `{ action, state }` with visible-effect flags such as `reacted`, `noObservedEffect`, `validationTextAdded`, or `domChanged`, requires navigation-capable helpers to wait for an observed browser-side navigation or loading transition before they accept a new snapshot, blocks stale old-guest bridge reads during that handoff, exposes `space.browser.setLogLevel(...)` as the runtime-side override for browser diagnostics while leaving the default app browser log level at `error`, persists each open browser window's URL, geometry, minimized state, and stacking data in browser-local storage so reloads can reopen the same window set, reuses the same viewport-fit pass for both live resize and restore so reopened windows clamp back onto the current screen when the viewport changed, and raises a focused browser window to the top of the browser stack even when the click lands inside the iframe or desktop webview page content. It spawns new windows below the fixed shell bar near the left edge of the centered router-stage column at approximately that column width while still allowing later drag movement all the way to the viewport top edge, renders popup windows through `<x-browser controls="true">` with Back, Forward, Reload, and address controls while inline surfaces may omit controls or opt in with the same attribute, keeps its page-side browsing bridge self-contained through `/mod/_core/web_browsing/browser-frame-inject.js` plus matching host helpers, and may also extend the onscreen-agent transient sections seam with a brief `currently open web browsers` status block plus prompt-time `last interacted web browser` content when the remembered interacted browser surface is still open; browser sessions render an iframe fallback inside that element, packaged desktop runs now prefer a DOM `<webview>` inside that same element so modal, widget, and other renderer-owned placement clipping stays aligned with the shell, the desktop host installs a tiny document-start browser guest kernel into the top page and all iframe descendants so shadow roots and nested documents stay crawlable later, the renderer then injects the bridge bootstrap plus an extensible guest runtime script list built through `space.extend(...)`, desktop `_blank` and `window.open(...)` requests are routed back into new in-app browser modals instead of separate OS windows, and the injected runtime must stay transport-agnostic so later browser-extension injection can reuse the same page-side request handlers while readable `content(...)` output stays in the lean typed-ref form like `[disabled muted button 18] Continue`, `[checked checkbox 7] Email updates`, `[error button 9] Delete`, or `[input text 30] Search placeholder=Hledat value=Ethereum` and omits obviously non-visible DOM or CSS-hidden content such as `hidden`, `aria-hidden`, `display:none`, `visibility:hidden|collapse`, `content-visibility:hidden`, or `opacity:0` subtrees
Expand All @@ -215,7 +215,7 @@ JS extension hooks:
- wrapped functions become async and should be awaited by callers
- JS hook files live at `mod/<author>/<repo>/ext/js/<extension-point>/*.js` or `*.mjs`
- JS callers name only the seam; the runtime loads hooks from the module's `ext/js/` tree automatically
- framework-backed pages expose `_core/framework/initializer.js/initialize`; use `_core/framework/head/end` when the work can stay as declarative head HTML or inline bootstrap code, and prefer the initializer `/end` hook when the setup must stay imperative instead of editing page shells
- framework-backed pages expose `_core/framework/initializer.js/initialize`; use `_core/framework/theme/end` for declarative theme or background CSS, use `_core/framework/head/end` when the work can stay as other declarative head HTML or inline bootstrap code, and prefer the initializer `/end` hook when the setup must stay imperative instead of editing page shells
- framework-backed pages centrally grant `/enter` tab access to same-origin `/` and `/admin` windows opened through normal `target="_blank"` link clicks or `window.open(..., "_blank")`, and they also intercept same-tab cross-origin `http(s)` escapes through the Navigation API `navigate` event when available plus fallback anchor or `window.open(..., "_self")` and `location`-based hooks so web runtime can move those requests into a new tab while packaged desktop runtime blocks them before the Electron main-window origin guard needs to recover; location-bar navigations and manual browser opens such as context-menu, middle-click, or modifier-key opens are not intercepted and still route through `/enter` or the host guard
- use `callJsExtensions("name", data)` only when the seam is an explicit event rather than a function lifecycle
- `_core/login_hooks` is a first-party example of an explicit event seam: it runs from `_core/framework/initializer.js/initialize/end`, checks `~/meta/login_hooks.json`, then dispatches `_core/login_hooks/first_login` once per user and `_core/login_hooks/any_login` when the authenticated shell was reached from `/login`; `_core/spaces` currently uses that first-login seam to copy or reuse the module-owned `Big Bang` onboarding space and rewrite the main-shell default route before the router falls back to `#/dashboard`
Expand Down Expand Up @@ -278,6 +278,7 @@ Runtime guidance:
- framework-backed pages that boot through `/mod/_core/framework/js/initFw.js` already initialize the runtime before feature modules mount
- `globalThis.space` is scoped to the current window or iframe only; do not publish it into other browsing contexts
- use `space.api` for authenticated backend calls
- use `space.bundles` for installed customware-bundle metadata, removable browser-side action handlers, and bridge-state sync points owned by external integrations instead of patching framework or feature internals
- prefer the shared `space.api` helpers over feature-local request batching; same-tick `fileRead(...)` calls coalesce automatically, preserve per-call missing-file behavior by retrying individually when a combined batch fails, and identical in-flight file, identity, and extension-load requests are deduped by the runtime
- use `space.api.folderDownloadUrl(...)` when a folder download should stay as a browser attachment instead of fetching the archive blob into frontend memory
- first-party framework, shell, skill-helper, and bundled demo assets required for normal app use must be local `/mod/...` files, server page assets, or inline code; do not load required scripts, styles, fonts, images, or other framework assets from CDNs
Expand Down
2 changes: 1 addition & 1 deletion app/L0/_all/mod/_core/documentation/AGENTS.md
Original file line number Diff line number Diff line change
Expand Up @@ -16,7 +16,7 @@ Current structure:

- `ext/skills/documentation/SKILL.md`: the required entry skill that lists every documentation page by relative path, name, and short description and tells the agent how to read focused docs
- `docs/architecture/`: repo-wide runtime, desktop-host packaging, and documentation-system orientation
- `docs/app/`: frontend runtime, admin-agent, browser-side WebLLM and Hugging Face runtime docs, extension, and spaces documentation
- `docs/app/`: frontend runtime, customware bundle, admin-agent, browser-side WebLLM and Hugging Face runtime docs, extension, and spaces documentation
- `docs/agent/`: onscreen-agent runtime, prompt, execution, and skill-system documentation
- `docs/server/`: router, page, API, auth, layered-filesystem, and writable-layer history documentation, including auth-preserving rollback rules
- `docs/cli/`: CLI command and runtime-parameter documentation
Expand Down
Loading