Tessera

Tessera is a native desktop UI host embedding Aster. Agents submit ordinary Endor scripts through a local namespace API. Aster parses, compiles and executes them; ui.page().render(root) selects a Tessera UI tree. Tessera extracts a native tree, lays it out and draws it using the existing software renderer. The initial page is empty.

Source and library integration

vendor/aster is an unmodified Git submodule, pinned to an exact published commit. Cargo path dependencies directly use its frontend, compiler and core (library name endor_core) packages, which bring in objects. The Aster workspace and history remain independent. See vendor for initialization and version updates, and src for the implementation map.

The runtime now uses Aster's Reader, Parser, AST, Compiler and VM. Tessera's former experimental namespace / export scene / render parser has been removed. Host UI integration lives in Tessera; Aster needs no Tessera-specific changes. Lyra CLI and Hestia Server are independent hosts and are not application dependencies.

Native build and start

Use Rust 1.91 or newer. Initialize the source submodule following the dedicated codex-bot SSH identity instructions in vendor, then build:

git submodule update --init --recursive
cargo build --release --locked
./target/release/tessera

Cargo compiles the required Aster libraries together with Tessera. No separate Aster build, service or deployment is required. Local builds download dependencies from official crates.io by default. A temporary dependency mirror may be used when the official source is unavailable, without changing global configuration. Docker and automated tests are not used locally. The command above produces a native executable. To create a Finder-launchable development app on macOS, run:

sh scripts/build-macos-app.sh

Open target/release/Tessera.app. See packaging; this local bundle does not include distribution signing, notarization or an installer.

The API listens only on 127.0.0.1:4737. Start integrations with its live guide:

curl http://127.0.0.1:4737/agent

Submit Endor

The active namespace starts as app.main:

GET    /v1/namespaces/app.main/code
PUT    /v1/namespaces/app.main/code
DELETE /v1/namespaces/app.main/code

Submit the complete example:

curl --request PUT --header 'Content-Type: text/plain; charset=utf-8' \
  --data-binary @examples/page.endor \
  http://127.0.0.1:4737/v1/namespaces/app.main/code

A minimal program is:

let heading = ui.text("Hello Endor", 2, "#242422")
let rectangle = ui.rect(240, 80, 12, "#DCE8FF")
let myui = ui.page()
myui.render(ui.column(24, 12, heading, rectangle))

The namespace comes from the request path. ui is a host global declared to Aster's compiler and injected into the candidate VM. Top-level variables share that VM's globals within this source submission. No main wrapper is generated. Complete top-level inputs are separated by newlines; multiline calls and function bodies are grouped before being handed to Aster's existing Interactive parser and compiler. Expression continuations such as a member read on the following line remain in the same input. Aster still owns every token, syntax rule, AST and bytecode operation; the host only batches inputs and restores original AST offsets.

The older main-returning-View example and the richer function example remain supported. A source consisting entirely of function declarations uses Aster's Module entry and calls zero-argument main. Mixed function declarations, bindings and expression statements use Interactive inputs in source order. Type annotations remain syntactic in Aster; Tessera checks actual UI values. The sample files are client-side material; the API itself stores source by namespace.

UI host API

All arguments are positional. Defaults below describe omitted trailing arguments, not Endor keyword argument syntax.

Member Arguments and defaults
ui.text String, integer size (default 1, range 1..8), color (default #242422)
ui.rect Width, height, radius (default 0), color (default #DCE8FF)
ui.column Padding, gap, followed by zero or more UI children
ui.row Padding, gap, followed by zero or more UI children
ui.spacer Size
ui.page No arguments; creates a page with a bound render(root) member

Colors are #RRGGBB or #RRGGBBAA. Dimensions are finite numbers in 0..1000000. A namespace has one displayed page. If a script creates several pages or renders more than once, its final successful render selects the visible root. Rendering does not publish partial execution: a later error rejects the entire submission.

Aster keeps its exact numeric representation; conversion occurs only at the UI boundary. Text is shaped and antialiased with COSMIC Text and Swash, using installed system fonts and per-glyph fallback (including Chinese when a CJK font is installed). UI text uses a proportional sans-serif font; developer source uses a monospace font. The existing size argument remains a 1..8 multiplier: size 1 is 14 logical pixels with a 20-pixel line height; size 2 is 28/40. Row/Column layout uses measured text advances and multiline height. Device scale remains fractional, and glyphs are rasterized at the actual display resolution rather than enlarged. The application does not bundle proprietary OS fonts. Linux installations need fonts such as DejaVu Sans/Mono and Noto CJK; the remote test image installs these.

Candidate execution and publication

A dedicated worker performs source parsing, AST budget checks and compilation in a fresh candidate VM. It executes each script input with shared globals (or module initialization and zero-argument main for function-only source), checks the selected UI root, extracts native data, builds and validates the frame, then cleans up all VM roots. The window receives no VM handles. It relays out the owned native tree during redraw and display scale changes without rerunning Endor.

The existing callback interface has no allocator access. Tessera therefore preallocates 4096 real UI node objects plus a separate 64-page pool with bound render callbacks per candidate. Each constructed node is initialized once. Constructors return those borrowed handles; Aster retains call results under its existing rules. Native child data owns its own lifetime and contains no managed VM edges. This bounded pool is for snapshot construction, not a persistent dynamic UI.

Limits are 1 MiB source, 10000 visited AST nodes with a 64-level visitor depth, 4096 constructed UI nodes, 64 pages, 64 UI levels, 10000 expanded layout visits and 16 KiB per text. Every execution has a 128-frame limit. Script inputs each receive an equal share of a total 1000000-instruction allowance; function-only module initialization and main execution each retain a 1000000-instruction budget. Repeated children count again during layout, preventing a small shared tree from expanding without bound. The build queue holds eight pending requests.

GET reads the last successful source while the worker executes. PUT waits for its result; a successful response includes submission and committed revision numbers. Parsing, compilation, execution, argument or layout errors return 422 with explanations and preserve the last successful document. Source diagnostics include line, column and byte ranges; VM tracebacks currently identify function starts and instruction offsets, not an exact source location for every instruction.

A newer accepted PUT invalidates older work. DELETE clears the document immediately and invalidates both queued and executing candidates. Superseded requests return 409 and cannot republish their page. A full or unavailable queue returns 503; rejected queue entries do not invalidate accepted work. Failed builds do not increment the committed revision. A worker-caught panic discards the entire candidate and returns 500, retaining the previous document.

This stage supports static snapshot UI. Event callbacks, persistent running VMs, window-size language inputs and process isolation are future work. Worker threads, source budgets and VM instruction limits are not a complete untrusted-code sandbox.

Developer tools

Toggle developer tools with Command-Option-I or F12 on macOS, Control-Shift-I or F12 on Windows/Linux. The compact Console, Sources, Network and Settings tabs share a draggable dock edge. Console's editor boundary, the Sources tree/source boundary and Network's request/details boundary can also be dragged. Each content area has independent vertical and horizontal scrolling, draggable scrollbar thumbs, and trackpad support. Shift-wheel scrolls horizontally. Layout uses logical pixels and the actual display scale; resize clamps pane sizes to keep controls reachable.

Console is the default execution transcript. Type an expression, press Enter to run, or Shift-Enter for a newline. Switch to Script mode to PUT a complete source replacement that renders a page. Arrow keys, Home/End, grapheme-safe deletion, selection of all input, macOS copy/cut/paste and IME composition are supported. Up/Down recall single-line history; Command/Control-Up/Down also recall history in multiline input. Clicking the editor positions the caret. HTTP requests from other clients appear in the same transcript with input, result, error and diagnostics. Clear hides the displayed transcript; history stays in memory for this window. Transport failures are shown beside the editor and restore an otherwise empty draft.

Expression mode sends POST /v1/namespaces/app.main/evaluate as text/plain. It accepts exactly one Aster expression and returns JSON with value, execution: "isolated-expression" and persistent: false. It uses a disposable VM, without ui or previous bindings, and never changes the page or committed revision. For example, "Hello Endor" and 42 return values. Language operations unsupported by the pinned Aster compiler (currently including numeric arithmetic bytecode) produce actual diagnostics. Evaluation shares the eight-entry execution queue. Persistent REPL sessions are not connected. Console history is a transcript, not VM state; Tessera never replays old input to simulate persistence.

Sources shows the full last successful source snapshot with line numbers, Aster's AST and selected source ranges. Selecting an AST node scrolls to its location while keeping the entire file available. Cloud files has a separate file navigator and source viewer, initially disconnected. The CloudSourceProvider boundary in src/sources.rs supplies file identities/paths and full source on open; there is no cloud backend, fake file listing or source persistence in this release.

Network observes only HTTP requests handled by this Tessera process on 127.0.0.1:4737, including pending requests, method, path, status, server duration, request/response headers and bodies. Filter matches method, path or status. Clear clears the Network view without changing the document or Console transcript. A bounded ring retains 80 requests with explicitly marked 32 KiB body previews. Request headers are allowlisted to Content-Type and Content-Length; credentials and cookies are not captured. No external browser or operating-system traffic is represented. Console and Network share the bounded capture ring and have independent clear markers. Clicking a Console record opens its Network details and restores that view.

Settings applies six accent presets or a custom six-digit hex color immediately. Very bright custom colors are darkened to keep accents visible on white. Execution separators, selected tabs and focus indicators use the accent, while text keeps its readable neutral/error/success colors. Settings and source remain in memory only.

Validation

Local native builds and window runs are allowed; do not run local automated tests or Docker. Remote CI on ces-control runs the existing renderer checks and the new Aster script/module execution, page rendering, UI layout, source-range, lifetime, budget, failed-update and deletion-invalidation regressions, plus Clippy. The API regressions use actual HTTP requests, including DELETE while the worker is occupied and a queued PUT is superseded. Linux CI does not verify macOS window presentation. Aster has no standalone CI/CD; Lyra CI explicitly validates the pinned engine itself. CI uses official Cargo sources and standard HTTPS checkout without custom SSH secrets. Font checks cover proportional/monospace advances, fractional scaling, multiline height, Chinese fallback, grapheme-safe truncation, antialiasing and alpha blending.

S
Description
No description provided
Readme 19 MiB
Languages
Rust 99.5%
JavaScript 0.4%
Shell 0.1%