Update V8 Version
openinterpreter/openinterpreter
Bumps the pinned v8 and rusty_v8 versions in Codex, validates the release-candidate path with the v8-canary check, and traces failures to upstream build changes.
Review or build a LunCoSim feature that crosses USD, Modelica, Avian, Rust, or Rhai.
$ npx skills add LunCoSim/lunco-sim --skill luncosim-architecture -a claude-codeProject install by default; add -g for ~/.claude/skills/.
$ gh skill install LunCoSim/lunco-sim luncosim-architecture --agent claude-codeProject scope by default; add --scope user for a personal install. Needs GitHub CLI 2.90.0 or later (public preview).
$ git clone --depth 1 https://github.com/LunCoSim/lunco-sim.git skills-src && mkdir -p .claude/skills && cp -r skills-src/skills/luncosim-architecture .claude/skills/luncosim-architecture && rm -rf skills-srcUse ~/.claude/skills/ instead of .claude/skills for a personal install. The folder must contain SKILL.md.
Claude Code skills documentation · loads skills from .claude/skills/
Install the "luncosim-architecture" agent skill from https://github.com/LunCoSim/lunco-sim/tree/main/skills/luncosim-architecture into .claude/skills/luncosim-architecture/ in this project. Copy the whole folder (SKILL.md and every file beside it), keep the folder name "luncosim-architecture", then confirm the skill loads.Claude Code copies the folder itself, the same result as the manual copy. Check what it changed before you commit it.
$skill-installer install https://github.com/LunCoSim/lunco-sim/tree/main/skills/luncosim-architectureType this inside Codex. $skill-installer <name> installs a curated skill from openai/skills. The installer writes to $CODEX_HOME/skills (default ~/.codex/skills). Restart Codex if the skill does not show up.
$ npx skills add LunCoSim/lunco-sim --skill luncosim-architecture -a codexProject install goes to .agents/skills/; add -g for ~/.codex/skills/.
$ gh skill install LunCoSim/lunco-sim luncosim-architecture --agent codexProject scope by default (.agents/skills/); add --scope user for a personal install.
$ git clone --depth 1 https://github.com/LunCoSim/lunco-sim.git skills-src && mkdir -p .agents/skills && cp -r skills-src/skills/luncosim-architecture .agents/skills/luncosim-architecture && rm -rf skills-srcUse ~/.agents/skills/ instead of .agents/skills for a personal install.
Codex skills documentation · loads skills from .agents/skills/
Install the "luncosim-architecture" agent skill from https://github.com/LunCoSim/lunco-sim/tree/main/skills/luncosim-architecture into .agents/skills/luncosim-architecture/ in this project. Copy the whole folder (SKILL.md and every file beside it), keep the folder name "luncosim-architecture", then confirm the skill loads.Codex copies the folder itself, the same result as the manual copy. Check what it changed before you commit it.
$ npx skills add LunCoSim/lunco-sim --skill luncosim-architecture -a cursorProject install goes to .agents/skills/; add -g for ~/.cursor/skills/.
$ gh skill install LunCoSim/lunco-sim luncosim-architecture --agent cursorProject scope by default (.agents/skills/); add --scope user for a personal install.
$ git clone --depth 1 https://github.com/LunCoSim/lunco-sim.git skills-src && mkdir -p .cursor/skills && cp -r skills-src/skills/luncosim-architecture .cursor/skills/luncosim-architecture && rm -rf skills-srcUse ~/.cursor/skills/ instead of .cursor/skills for a personal install.
Cursor skills documentation · loads skills from .cursor/skills/, .agents/skills/, .claude/skills/, .codex/skills/
Install the "luncosim-architecture" agent skill from https://github.com/LunCoSim/lunco-sim/tree/main/skills/luncosim-architecture into .cursor/skills/luncosim-architecture/ in this project. Copy the whole folder (SKILL.md and every file beside it), keep the folder name "luncosim-architecture", then confirm the skill loads.Cursor copies the folder itself, the same result as the manual copy. Check what it changed before you commit it.
$ gemini skills install https://github.com/LunCoSim/lunco-sim.git --path skills/luncosim-architecture--scope user (default) or --scope workspace; --path is the subfolder of the repo that holds the skill; --consent skips the security confirmation prompt.
$ npx skills add LunCoSim/lunco-sim --skill luncosim-architecture -a gemini-cliProject install goes to .agents/skills/; add -g for ~/.gemini/skills/.
$ gh skill install LunCoSim/lunco-sim luncosim-architecture --agent gemini-cliProject scope by default (.agents/skills/); add --scope user for a personal install.
$ git clone --depth 1 https://github.com/LunCoSim/lunco-sim.git skills-src && mkdir -p .gemini/skills && cp -r skills-src/skills/luncosim-architecture .gemini/skills/luncosim-architecture && rm -rf skills-srcUse ~/.gemini/skills/ instead of .gemini/skills for a personal install, then run /skills reload.
Gemini CLI skills documentation · loads skills from .gemini/skills/, .agents/skills/
Install the "luncosim-architecture" agent skill from https://github.com/LunCoSim/lunco-sim/tree/main/skills/luncosim-architecture into .gemini/skills/luncosim-architecture/ in this project. Copy the whole folder (SKILL.md and every file beside it), keep the folder name "luncosim-architecture", then confirm the skill loads.Gemini CLI copies the folder itself, the same result as the manual copy. Check what it changed before you commit it.
$ gh skill install LunCoSim/lunco-sim luncosim-architectureInstalls for Copilot at project scope by default; add --scope user for a personal install. Preview a skill first with gh skill preview. Needs GitHub CLI 2.90.0 or later (public preview).
$ npx skills add LunCoSim/lunco-sim --skill luncosim-architecture -a github-copilotProject install goes to .agents/skills/; add -g for ~/.copilot/skills/.
$ git clone --depth 1 https://github.com/LunCoSim/lunco-sim.git skills-src && mkdir -p .github/skills && cp -r skills-src/skills/luncosim-architecture .github/skills/luncosim-architecture && rm -rf skills-srcUse ~/.copilot/skills/ instead of .github/skills for a personal install. Commit .github/skills so cloud agent and code review can use it.
GitHub Copilot skills documentation · loads skills from .github/skills/, .claude/skills/, .agents/skills/
Install the "luncosim-architecture" agent skill from https://github.com/LunCoSim/lunco-sim/tree/main/skills/luncosim-architecture into .github/skills/luncosim-architecture/ in this project. Copy the whole folder (SKILL.md and every file beside it), keep the folder name "luncosim-architecture", then confirm the skill loads.GitHub Copilot copies the folder itself, the same result as the manual copy. Check what it changed before you commit it.
$ npx skills add LunCoSim/lunco-sim --skill luncosim-architecture -a opencodeOpenCode documents no install command of its own. Project install goes to .agents/skills/; add -g for ~/.config/opencode/skills/.
$ gh skill install LunCoSim/lunco-sim luncosim-architecture --agent opencodeProject scope by default (.agents/skills/); add --scope user for a personal install.
$ git clone --depth 1 https://github.com/LunCoSim/lunco-sim.git skills-src && mkdir -p .opencode/skills && cp -r skills-src/skills/luncosim-architecture .opencode/skills/luncosim-architecture && rm -rf skills-srcUse ~/.config/opencode/skills/ instead of .opencode/skills for a personal install.
OpenCode skills documentation · loads skills from .opencode/skills/, .claude/skills/, .agents/skills/
Install the "luncosim-architecture" agent skill from https://github.com/LunCoSim/lunco-sim/tree/main/skills/luncosim-architecture into .opencode/skills/luncosim-architecture/ in this project. Copy the whole folder (SKILL.md and every file beside it), keep the folder name "luncosim-architecture", then confirm the skill loads.OpenCode copies the folder itself, the same result as the manual copy. Check what it changed before you commit it.
luncosim-architectureReview or build a LunCoSim feature that crosses USD, Modelica, Avian, Rust, or Rhai.
Luncosim Architecture is an agent skill from LunCoSim/lunco-sim. Review or build a LunCoSim feature that crosses USD, Modelica, Avian, Rust, or Rhai. Use this when adding a reusable component, sensor, actuator, controller, generated Modelica network, USD schema, or runtime projection, and when removing legacy paths, shims, compatibility fallbacks, or custom fields that duplicate an OpenUSD standard.
Its SKILL.md is about 19k tokens, which your agent loads only when the skill is triggered. The skill folder holds 2 other files, including reference files (for example `references/usd-standard-map.md`).
It works with Rust. The repository describes itself as: Collaborative Multiphysics Cosimulator For Space Missions 🌎🚀🌚. The licence is Apache-2.0.
4 steps, taken from the first numbered list in SKILL.md.
Read from SKILL.md and the folder at commit 43f1301. It shows what the files ask for, not the result of running them.
Pre-approves nothing: there is no allowed-tools line, so your agent's usual permission prompts apply.
From allowed-tools in the SKILL.md frontmatter.
Shell commands in SKILL.md call:
kindcargopython3From the folder's file list and the shell code blocks in SKILL.md.
No URLs in SKILL.md.
From URLs in SKILL.md, links to its own repository left out.
Names no API keys, tokens, secrets or passwords.
From names ending in _API_KEY, _TOKEN, _SECRET, _KEY or _PASSWORD in SKILL.md.
Luncosim Architecture loads about 19k tokens when it runs, and up to ~20k if it reads all its reference files. Until then it costs about 90 tokens; SKILL.md has 10,184 words of instructions outside code blocks.
Estimates: characters ÷ 4, the usual rule of thumb; real counts depend on the model's tokenizer. Scripts and assets cost tokens only if the agent reads them.
The automated check found no risky patterns in SKILL.md.
Automated static check — not a guarantee. Review scripts before installing. It scans the text of SKILL.md for risky patterns (piping downloads into a shell, reading credential files, hidden Unicode, destructive commands); files beside SKILL.md are not scanned.
The full file from LunCoSim/lunco-sim at commit 43f1301, republished under its Apache-2.0 licence (© LunCoSim). 10,184 words, ~19,257 tokens.
.claude/skills/luncosim-architecture/SKILL.md (or your agent's skills folder). This skill also uses 1 other file; get the full folder from GitHub.Use this skill before changing a reusable engine feature. Keep the authored system declarative and composable, and make each concern live in its native representation:
Before calling an architectural capability missing or impossible, use capability-discovery. Search the relevant skills and architecture docs, identify the standard or project owner, inspect registrations and callers, check maintained dependencies, and verify the production/API surface when relevant. Classify the result as found, implemented-but-unwired, present on another branch/version, not found in the searched scope, or externally blocked. Do not create a second owner, fallback, or compatibility shim because the first search was incomplete.
| Concern | Authoritative owner | Runtime role |
|---|---|---|
| Scene structure, identity, topology, frames, connections, component parameters | USD | Rust projects the composed stage; it does not invent missing topology |
| Continuous equations, state, control laws, filters, physical networks | Modelica | Rumoca compiles and steps the model |
| Rigid-body collision, contacts, forces, torques, joints | Avian through USD-authored physics | Rust exposes the engine's generic mechanics and executes them |
| Mission phases, events, policy, objectives | Rhai or behaviour trees | Task/event orchestration in production; on_tick is test-only for sampled verdicts |
| Engine mechanisms, projection, scheduling, hot paths | Rust | Generic implementation; no vehicle- or sensor-name special cases |
For cross-domain execution, read
62-deterministic-runtime-and-async-boundaries.md.
Keep parsing, source resolution, and immutable preparation off the UI/fixed
schedule when inputs can be captured by revision. Admit results only at an
owner boundary in stable identity order. Keep live-world hooks and physics
inside their deterministic schedule. The required Rhai USD composition policy
decides incomplete initial stage and newly mounted reference closures before
their respective admission and projection boundaries. A Rhai scenario that
depends on Modelica
ports or events declares the participating entity ids in
simulation_dependencies(me, ctx), where ctx is the validated scenario
parameter map. The hook returns a map with modelica_entities: [ids],
entity_reads: [ids], entity_writes: [ids],
query_reads: ["PublicQueryName"], and
required_inputs: [#{ owner, identity }]. All five arrays are required even
when empty. The owner resolves all declared ids once per
source/parameter revision. modelica_entities ids must identify live Modelica
participants and grant both directions of access. Directional read/write ids
may identify any live entity; a Modelica entity in either set also joins the
shared causal barrier. Unresolved ids fail that source revision with a visible
diagnostic.
Every simulation-clock Modelica port access must be covered by the calling
scenario's own plan, including get, port, and
query("ReadPorts", #{ api_id, port_names });
aggregate barrier membership from USD wiring or another scenario does not
authorize the read or write. The owner enforces this at the port, query,
targeted-command, and event-delivery boundaries.
Generic reflected reads and direct mutations also require the matching
entity_reads or entity_writes declaration. After a typed simulation
command materializes an entity whose id was not available during plan
preparation, track_entity_read(id) or track_entity_write(id) adds the
directional access in serialized simulation order before the entity is used.
Tracked Modelica entities join the same barrier when they enter the current
Modelica projection.
Entity-targeted API query providers report their live target ids through
simulation_entity_reads; the scripting bridge checks them against the
scenario's read plan before execution. Broad spatial/world queries use an
explicit coarse declaration by public provider name in query_reads.
Mounted-scene USD queries without doc_id use the active committed Twin
generation. Unknown query providers default to the broad declared scope, and
broad queries cannot run while simulation_dependencies is resolving.
Required input keys refer to producer namespaces registered in the generic
SimulationDependencyStates resource. The scenario holds its existing
ScriptPreparation key until every required input is Ready; it retries only
after an owner-published state revision, and the visible wait reason names the
input. A missing producer is a terminal diagnostic; a producer's Failed state
reports its errors. Omitting the hook declares no Rhai dependencies. The plan
runs before mutable top-level initialization, so derive it from me, scenario
parameters, and read-only world queries. Top-level initialization runs in its
own Initialization phase after the plan commits. Dependency planning may
resolve identities but cannot access live ports, issue commands, mutate the
world, or emit events. Invalid or unresolved ids fail that source revision
with a diagnostic. Unbarriered port access and Modelica event delivery
fail visibly. Connected Modelica event edges are sampled only while the
simulation clock advances, after SimTickSet and before Rhai; this gives an
initially active output its producer tick after scenario readiness. USD
simulation projection uses stable logical stage source, optional instance-root
path, and authored prim path for bounded admission, topology-preparation order,
and dynamic-body promotion; missing or ambiguous identities fault, remain
queued, or stay kinematic.
Physics operations that can accumulate into shared bodies use PhysicsOrderKey
from the stable logical stage source, instance root, and authored prim path.
Joint solving, motor warm-start, custom prismatic correction, raycast and jointed tire forces,
and raycast mass-property folds consume stable key order.
The production multi_rover_stress Rhai gate selects a profile from typed
scene-test parameters and compares only the requested reference row at each
sample. Rust loads the portable JSON at the --determinism-reference PATH
process boundary and exposes typed values through the existing Rhai query
bridge. Rhai owns profile matching and exact comparison (numeric_tolerance=0)
for six physics checkpoints, selected Modelica and articulated checkpoints,
and the explicit final physics, Modelica, and articulated state. The test keeps
only checkpoint tick numbers and the first mismatch; it also verifies Rhai
rejects a deliberately altered physics row and does not emit or retain a trace
bundle. The Bash and PowerShell matrices in
scripts/test-deterministic-physics-profiles.sh and
scripts/test-deterministic-physics-profiles.ps1 invoke regular production
luncosim test processes and trust their exit status. They leave --tick-hz
unset, so the default fixed step is 60 Hz; the runner advances the manual clock
without wall-time pacing. This remains fixture-specific evidence. Do not claim
whole-simulation replay determinism while the remaining reviewed gaps are open.
Reflected commands sent through ApiCommandEvent retain whether they came from
an API transport or a Rhai evaluation; generated CommandOccurred facts carry
that origin. The workbench uses PanelCtx::trigger_command to carry an
explicit local-user SessionId across deferred UI dispatch; the port inspector
therefore enters fixed-tick input admission. Direct typed Bevy triggers without
an explicit origin remain unclassified, and the occurrence fact still lacks
command parameters, target, scene generation, effective tick, and per-tick
input order. Rhai scenario origins carry their stable actor id and source
execution sequence.
SimulateIntentEdge preserves the complete origin through its typed semantic
edge into the bounded CausalTrace query; Rhai records include owner route,
phase, generation, sequence, and actor id. API, application-Rhai, and direct
typed discrete edges receive a committed scene generation, next SimTick, and
per-tick sequence, then reach the event bus from the fixed-step owner.
Simulation-clock Rhai edges remain derived behavior and do not receive this
external-input stamp. The queue is bounded to 4,096 pending records and clears
on scene teardown; the trace is not durable replay storage. External held
SimulateIntent changes share the bounded queue and per-tick order with edges.
API, direct typed, and actorless Rhai producers provide a stable nonzero
producer_id; Twin Rhai retains its route and stable actor identity. Held
acknowledgements, telemetry, CausalTrace, and session records retain producer
identity. drive_from_bindings captures physical
ActionState<UserIntent> into a by-value PhysicalIntentFrame semantic
snapshot. Admission requires the local input SessionId, target
GlobalEntityId, and committed scene generation. The fixed-step owner stamps
the frame with those identities, the current SimTick, and a sequence from
the shared lunco-control-core::SimulationInputOrderAllocator before
controller translation. The allocator resets on scene teardown so producers
share one per-tick order space. Admitted external semantic payloads wait in
lunco-core-session::PendingSessionInputs; core-session clears that queue on
scene teardown. Its fixed-step coordinator validates and captures due records,
then publishes typed commit events in shared sequence order while simulation
time is running; a pause leaves inputs queued for the next running tick. The
controller applies semantic payloads before physical input sampling.
Raw-file runtime spawns also enter this commit boundary; the scene-command
owner checks the current frame and catalog and inserts the reserved root
identity before identity admission. Physical frames remain sampled at their
consuming fixed tick through the same per-tick allocator. Missing facts or
duplicate target/session order keys hold input with a structured runtime
error; ordering does not fall back to Bevy Entity bits. An active
SessionInputStream captures sorted canonical intent ids, admitted controls,
lifecycle input-hold releases, and raw-file spawn records.
ControlAuthorityChanged queues ReleaseControlInputs for the next fixed
tick. At its ordered commit, the co-simulation owner clears controller-owned
port holds and the controller clears held semantic intents; authored program
setpoints, endpoint values, and physics state remain intact. The release writes
no stop value. Twin policy owns any stop setpoint and issues explicit named
SetPorts writes. Capture retains the ordered lifecycle record when active.
Missing target, generation, tick, or order facts produce a runtime error and
leave existing holds intact. Spawn records retain producer,
correlation, stable scene-root and active-frame identities, original f64 pose,
admission stamp, and reserved root id; acknowledgements expose that stamp.
Document-backed SpawnEntity still authors only ApplyUsdOps into the Twin
journal. Capture remains bounded and in-memory; baseline manifests, playback,
and other typed commands remain open.
The persistent canonical WorldGrid has deterministic content provenance, so
the default active physics frame also has a stable GlobalEntityId.
Scenario actor compile submission, completion commit, and hook execution use the
source-owned GlobalEntityId component directly; the Update-synchronized API
lookup index is not an ordering source. A local-only host without that component
uses its Bevy entity key only within the current World and has no cross-session
replay identity. Author observable multi-actor ordering checks in Rhai scene
tests; reserve Rust tests for the generic ordering and async commit mechanisms.
For file-backed documents, use PreparedFileBacked with the shared
DocumentRegistry::open_prepared_file path when source parsing moves to a
worker. The registry remains authoritative for path identity, dirty-document
preservation, and lifecycle events. Owners fence results against the exact
source/document revision before committing them. The default USD Twin scene
uses this path for native USDA parse and persistent-source serialization;
runtime sidecar restore and the browser worker transport remain separate open
boundaries.
Twin teardown releases domain documents and browser preparations before the
replacement is admitted. Reopening keeps logical source identity but receives
a fresh load authority. Resolve authored dependencies through
lunco-assets-core::asset_path::load_asset_path with the admitted live origin;
retired origins fail before rebinding, and origin-free requests keep exact
transport authority. Background file snapshots resolve logical source names
and fence publication by scope and mount revision. See
61-scene-lifecycle-and-teardown.md.
Lifecycle work that changes authoritative scene state participates in
lunco-core-runtime::SimulationProgress. Acquire with a typed owner/operation
key, carry that identity through async preparation, and release it only after
the owning terminal result has been committed. Scene load/restart/clear use
SceneTransitionId; same-path transitions still have distinct identities.
The coordinator advances the shared scene generation only for the matching
successful transition and emits SceneTransitionCommitted. Scenario and other
Twin-scoped cycle owners read that committed generation; do not maintain a
subsystem-local scene counter or arm lifecycle work from a stale completion.
Lifecycle hooks receive a discrete owner context keyed to the exact transition.
For example, scene.time.select runs as Twin/Lifecycle/Preparation with no
elapsed clock, and its typed result carries the same SceneTransitionId through
application. The time owner ignores stale results and terminal edges after a
replacement begins. One-shot policy inspection uses Application/Repl/Evaluation.
Keep participant readiness and PhysicsHolds in their owners: they control
local/world physics admission, while SimulationProgress controls whether the
shared causal tick may advance. UsdSceneRuntimePlugin installs this shared
resource when selected and holds active reference spawns on the mounted primary
scene through closure preparation and live ECS projection. Preview and additive
mounts retain diagnostics without pausing or faulting the primary simulation. A
terminal primary reference failure retains its exact hold and publishes a path
diagnostic plus RuntimeFault until scene teardown; inactive or removed,
nonfaulted operations release their own keys. Surface the active wait reason
through the existing status bus. Async data that changes authoritative physics,
including a mounted DEM download/build, also holds an exact terrain entity key
through the committed collider/oracle result; on web the hold spans the coarse
preview and full worker result. The DEM bridge and readiness scan run in
PreUpdate before SimulationAdmissionSet, including while a Twin manifest scan is
pending, so the first eligible fixed tick cannot precede terrain admission.
UI and presentation schedules remain live.
Persistent edits to the mounted primary USD document hold one coalesced
UsdDocumentProjection key from the observed registry revision through the
matching ECS projection commit; disposable view-layer edits do not hold world
time when their typed operation suffix is available; an unavailable suffix is
conservatively treated as causal. Change detection admits UI/command edits in
the SimulationProgressAdmissionSet after entity indexing and before the
PreUpdate simulation-admission boundary, and admits edits issued inside a
fixed Rhai/event pass in that lane in FixedLast. The fixed runner completes
the current cycle, then preserves its remaining overstep until the projected
revision is committed. Do not poll
document contents on steady frames or release the hold from a stage-only cursor
before ECS projection completes.
Physics readiness then admits bodies and joints on fixed steps. An active USD Modelica participant remains
readiness-held through its first successful communication point; a compiled,
intentionally paused model is ready without being stepped. Keep that participant
readiness separate from the shared SimulationProgress lifecycle gate.
First-compile intent is admitted by request_modelica_compiles in the lifecycle
cycle while solver stepping stays in FixedUpdate, so compilation can be
requested while virtual simulation time is held. The Modelica execution owner
consumes typed CompileRequested intent, validates its pinned document runtime
lifetime, and owns same-owner source gathering and worker dispatch; the UI command only chooses the class and publishes intent.
On native, source-root installation, compile requests, Reset, parameter updates,
and cache-invalidating Step auto-init share one single-owner Rumoca actor FIFO.
Results return asynchronously and commit in submission order; actor requests
and solve preparations use bounded admission. A Step that requires a rebuild
resumes only after the matching session and library generation commit.
Compile results must match both worker session and captured document
generation. A result for an edited source revision is discarded, and an active
model keeps its compile-run intent until a current result commits. The execution
owner reconciles active causal models into SimulationProgress before
SimulationAdmissionSet and releases each exact entity key only after the matching
compile result has been committed. Intentionally paused and noncausal models do
not hold world time. Their first normal co-simulation step uses the per-step
barrier after activation. The root USD loader composes the available dependency
closure before publishing the stage asset, and scene admission ends after
structural projection. CPU mesh construction stays on the presentation path.
Keep owner-specific clock gates separate; production acceptance must still
prove that the first authoritative fixed tick observes each dependency declared
by the scene and scenario, independent of worker completion order.
For engineering requirements, keep the same split at the numerical boundary:
SysML owns typed intent, units, normative tolerances, and requirement/
verification identity; USD owns realized geometry and standard scene facts;
Modelica/Rumoca owns equations and continuous state; Rhai owns the selected
mechanical relation, orchestration, and evidence; Rust owns only reusable,
hot, type-safe f64 mechanisms. The authored
assets/scripting/tools/mechanical_relations.rhai library is the extension
point for CAD-like predicates such as distance, coincidence, parallelism,
under/clearance, mirroring, and symmetry. Do not grow a Rust registry of
relation names or product-specific checks.
Use the existing Rhai standard math surface for ordinary scalar operations and
the native Rust bridge for f64 vector validity, dot/cross, clamped cosine,
angle, and native component access. Keep native values in hot loops; arrays are
only explicit interchange boundaries. Use typed predicates (f64_only,
array_is, map_is, string_is, vec3_is_native) instead of string-based
runtime type protocols. Numerical settings are explicit per dimension and are
resolved once per report/solve; they do not replace a source-owned SysML
tolerance or become a global epsilon.
For Avian-backed physics, keep one numeric admission contract at
lunco-physics::avian_backend. The BigSpace bridge owns lifecycle admission of
f64 poses and collider support geometry before the Avian step, GridSpatialQuery
reuses the converted-ray predicate, and USD projection reuses shape/AABB and
leaf structure predicates before ECS insertion. Convex colliders are checked by
their actual support points; composite or non-convex shapes use the conservative
AABB boundary. A failed live invariant raises the
shared scene-scoped runtime fault and gates the remaining nested physics
phases. Do not turn these checks into per-call query fallbacks or lint-only
warnings.
Task leaves accept anonymous closures (|me| ...) or named script callbacks
(Fn("name"), declared fn name(me)). me is the host entity id; both forms
receive persistent state as the driver-bound this. The native task driver owns
progression and state transfer. Rhai map parameters are value/copy-on-write
values: a helper that assigns a state field must return the updated map, and
the lifecycle callback must assign it back to this. Do not rely on helper
side effects to persist task state.
Use a domain CorePlugin for headless-safe state, lifecycle, commands, and
runtime mechanisms, then add a separate UI plugin only for panels and visual
presentation. Do not create a UI plugin merely to host API queries. If a
provider belongs to a core domain but importing the API crate would create a
dependency cycle, put the provider in a small *-api adapter crate and have
each API-capable composition root install it explicitly. Keep the data/core
crate independent of transport and presentation layers.
For dynamic providers, keep lunco-hooks as the single reflected contract and
invocation owner. HookInvocation carries the typed runtime context with the
validated values. lunco-hooks-plugin-api owns the stable edition-2024 ABI v2
and typed invocation wire helpers; lunco-hooks-native owns libloading, unsafe
admission, callback limits, and exact-registration teardown. Enable that path
only from an application composition feature. A Twin must explicitly approve a
provider with a Twin-relative [[native_plugins]] manifest entry. Reject rooted,
volume-relative, traversal, and alternate-stream paths; resolve through the asset
owner's canonical containment check before loading. USD and Rhai
source do not load shared libraries. Native code is trusted process code, so
untrusted bundles require deployment-level signature and isolation controls.
A provider may implement only an existing reflected, installable hook and must
return typed data or a validated action plan. It must not mutate ECS/USD or add
a second domain registry. The owner invokes it through lunco_hooks::invoke
with a typed HookInvocation: cycle-owned callers supply their runtime
context, while discrete boundaries explicitly use an unclassified context.
The owner validates the result and reports a fault or unconfigured state
according to the hook contract. Policy manifests may mark an optional
feature-owned hook with skip_when_hook_unavailable; the runtime reports that
capability in policy_status().unavailable, while compile and activation
failures remain in failed. Put an eventual expensive terrain provider at the
consumed lunco-terrain-bake kernel boundary; keep lunco-terrain-core projection-free
and leave lunco-terrain-surface as the runtime projection owner. See
native-hook-providers.md.
Keep stateful per-entity Rhai scenarios on their owning Simulation lane. For a
stateless Rhai decision at another cadence, prefer an existing owner-invoked
hook with typed facts and context over adding more lifecycle callbacks to the
scenario runtime. Cross-cycle results return as typed owner actions; a scenario
this map never moves between cycles.
Keep the workbench split at the dependency boundary: lunco-workbench-core
owns renderer-independent panel/menu/perspective/registration contracts, tab
navigation, source-view commands, scene display state, pending tab-close state,
and the published WorkbenchSnapshot; lunco-workbench-widgets owns
shell-independent egui controls;
lunco-workbench owns egui_dock, bevy_egui, viewport rendering,
persistence, source editing, and command observers; and
lunco-workbench-guided-ui owns the optional Rhai-driven HUD, spotlight,
coach-mark, and guided-recovery surfaces; and
lunco-workbench-browser owns the optional Twin/Files panels, browser state,
and built-in filesystem/library sections without depending on the concrete
shell. Rename payloads belong to lunco-doc-bevy or lunco-workspace according
to the identity they address; the shell retains only picker/execution
observers. Domain UI crates implement contracts from the core crate, read
layout facts from the snapshot, and depend on the concrete shell only when
they use those presentation services. Do not expose or consume the shell's
private WorkbenchLayout outside that crate.
Keep application-edge presentation separate from the reusable shell:
lunco-luncosim-presentation owns the final status/environment, terrain-horizon,
USD camera/light, capture, and scene-presentation bridges, while
lunco-luncosim-ui owns window/plugin composition and installs that package at
the boundary. Native updater startup and its rendered surface belong to the
optional lunco-updater package, not to the ordinary UI closure. Celestial
body projection and cadence belong to lunco-celestial-spatial; ordinary
moving scene objects use standard USD timeSamples through
lunco-usd-bevy-animation. Do not create a mission-only trajectory component
or clock when composed USD animation expresses the motion.
Celestial state uses the one lunco-time::CelestialTime sample, an affine
child of WorldTime. It drives ephemerides, body rotation, solar irradiance,
lighting, shadows, geometry queries, and target positions consumed by the
generic EnvironmentProbe direction resolver. SunState contains irradiance;
it is not a parallel direction source. A rate up to 100,000× leaves Avian and Modelica at their ordinary
fixed-step cadence. From lunar ground, Earth stays near one sky position
because the Moon is tidally locked; its axial spin still advances the day/night
pattern. BigSpace propagates both the changed Earth grid pose and rotation to
GlobalTransform; one cadence gate commits the CelestialTime sample it read.
Static authored-light rays are selected only after the active composed root's
celestial projection has classified its source ownership. A celestial root owns
the finite body target exclusively; any static ray seeded before classification
must be withdrawn before probe resolution.
The celestial hierarchy must not wait on interactive input bindings: invalid
bindings may withhold the optional observer camera, but must not suppress the
finite targets consumed by physics and Modelica.
Use the shared lunco_runtime_context::RuntimeScope and
lunco_core::RuntimeCycleSet vocabulary when
placing a cross-cutting system. Core, Application, and Twin describe
ownership; Lifecycle, Simulation, Interaction, Command, Repl, Telemetry,
Ui, Presentation, and Visualization describe cadence. These are schedule labels and typed route
metadata, not a new global event bus. Twin-owned resources and completions must
carry their mount generation and be retired at Twin teardown.
Cycle labels do not create independent clocks, CPU isolation, or execution
cadence. Rust plugin composition decides which capabilities a host installs;
Bevy's owning schedules provide the actual execution boundary. A typed
RuntimeExecutionContext carries the current owner route, cycle, phase, clock
sample, logical sequence, and optional event producer stamp into synchronous
Rhai calls. Scenario hooks and one-shot REPL/tool calls use their owning
contexts: RunRhai runs as Application/Repl, while typed UI tool callbacks
run as Application/Ui after picking in PreUpdate and before fixed
simulation. execution_context() exposes a read-only Rhai map. Generic hook
calls carry HookInvocation; nested invoke_hook forwards its active context,
and an isolated Rhai hook reads it from the immutable runtime_context map.
The shared hook registry rejects a clock that does not belong to its cycle,
missing or invalid clock samples, and non-zero Core/Application generations
before invoking either Rhai or native policy.
twin.lifecycle uses the mounted Twin's TwinId as its Twin/Lifecycle
generation, with explicit Start, Event, or Stop phase and no elapsed
clock; policy_status().lifecycle.runtime_context exposes the exact stamp.
Rust call sites without a classified owner use the explicit unclassified hook
entry point. The physics escape policy is a scheduled core simulation hook and
receives its Behavior context from SimTick and Time<Fixed>; its authored
policy rejects off-cycle calls. The scheduled readiness.action policy uses
Core/Simulation/Behavior with Time<Fixed> and the latest SimTick, and its
authored policy rejects calls from other cycles. sim_tick(),
dt(), and elapsed_seconds() reject calls outside the simulation cycle as
invocation errors, while missing mandatory simulation clock resources remain
runtime faults. An unclassified invocation has no route; Rhai exposes its
scope, cycle, and generation as unit instead of inventing an owner. Add a
separate schedule driver only when a cycle needs independent cadence or
overload semantics, and keep expensive calculations off
the UI/physics-critical thread.
Native immutable preparation uses lunco_core_runtime::AsyncWorkAdmission;
do not add another per-crate priority queue. Each request carries its scope
generation, stable owner identity, source revision, and operation id. Priority
selects which queued job starts; the owner still validates and commits its
typed result at its own boundary. WebAssembly's Bevy async-compute pool runs
cooperatively on the browser main thread, so expensive web work needs an
explicit worker transport rather than this native dispatcher.
Native terrain cover analysis and streamed tile-mesh bakes share this admission.
Tile bakes use Interactive priority and a stable owner-selected nearest-first
rank; the terrain owner fences completions by operation key and publishes meshes
in stable coordinate order under its frame budget. Surface changes and owner
removal withdraw queued work, and already-running stale results are discarded.
Keep the browser tile-cache path explicit until Web Worker transport is
available.
Serialize each Modelica step's input assignments in variable-name order;
never let hash-map iteration choose a worker command's observable order.
File-backed Rhai source assets are parsed and const-folded by the asynchronous
asset loader, which publishes their canonical id, exact text, AST, and literal
import dependencies together. Activation owners commit the complete loaded
dependency graph before binding or starting a source; Bevy can report graph
readiness before its Added messages are consumed. Startup/Twin tools and the
prelude reuse that AST; scenario workers reuse it only when the source bytes
match, and parse inline roots or uncommitted sources inside shared admission.
Do not compile loaded tool or prelude source synchronously during registration.
The asset publisher retains each loaded AssetId's canonical URI and retires it
on AssetEvent::Removed, because AssetServer::get_path may fail after the
last handle is released. Ignore the earlier Unused edge, and prevent a stale
asset removal from deleting a replacement source with the same URI.
Twin SysML analysis follows the same boundary: twin.lifecycle selects the
checked manifest source set, PrepareTwinSysmlAnalysis loads source assets and
prepares one immutable snapshot through shared admission, and runtime
twin:// queries read only the current Twin-id/root/operation result. Pending,
failed, and unprepared snapshots remain visible. This read-only active-Twin work
uses Interactive priority and never holds SimulationProgress; a scenario
that requires SysML facts declares the typed owner key in its dependency plan.
Open SysML documents use the same bounded Interactive admission. Lifecycle
events capture immutable source/origin facts, and SysmlDocumentAnalyses
commits only for the exact current document generation and origin URI.
InspectSysmlDocument returns analysis_state as pending, ready, or
failed; pending diagnostics and error fields are null. Rhai editor verification
must return a retryable pending result and must not call it clean. These editor
analyses do not hold simulation progress. Browser worker transport is explicit
and remains unsupported by this native dispatcher. The Twin analysis producer
registers sysml.twin-analysis and publishes each mounted Twin's state under
its exact name. A scenario that needs those facts lists
#{ owner: "sysml.twin-analysis", identity: twin_name } in
required_inputs; only that scenario's activation hold waits for the async
analysis. The analysis worker itself remains read-only and never acquires a
world-time hold.
Telemetry samples are captured with the fixed tick, then delivered through the
plugin-owned bounded Telemetry cycle. Never run subscription, retention, or
logging observers inline with fixed physics; report queue loss through the
telemetry status query and keep simulation progress independent.
The GUI installs TerrainSurfaceVisualizationPlugin; server and scene-test
compositions keep terrain physics/query support but omit camera-driven LOD,
visual-map baking, and overlays entirely. A system hidden behind a server-mode
run_if still exists in that schedule and is not equivalent to omitting it.
Application builders install the selected capabilities automatically; authors
should not assemble Bevy schedules by hand. Rhai currently declares peer-role
selection through @peer host|client|both, with simulation as its supported
timing. An unknown execution target, unsupported timing, or unknown metadata
directive disables only that scenario and publishes one document error for its
source generation instead of breaking the host, defaulting to host, or guessing
a clock. Cycle and clock selection come
from the Rust owner, not a script directive. A callback error remains visible
and local to its owner; required authoritative hooks hold/fault their owner.
Never panic or silently report success for a failed hook.
The initial camera policy receives Application/Presentation/Preparation with
the Time<Real> presentation clock. Its RuntimeCycleSet::Presentation labels
are ordering metadata inside Update; they do not give UI or visual LOD an
independent cadence. The runtime UI recording selector receives
Application/Ui/Preparation with the Application clock in its PostUpdate
owner chain; it runs only when its revisions change, not as a separate cadence.
The authored runtime-surface visibility/property policies receive typed
Application/Ui/Preparation context from exposure publication; camera-status
properties receive Application/Presentation/Initialization or
Application/Presentation/Event from the camera-status publisher. Add a
policy guard and verify both the scheduled owner context and an off-cycle call
when assigning context to another hook. The route_lifecycle production gate
checks ReadExposures for an authored program-browser surface after metadata
admission.
The rendering-quality catalog receives
Application/Presentation/Initialization on startup and
Application/Presentation/Preparation for stale-policy refreshes, both using
Time<Real>. The render shadow-warning policy receives Presentation
Preparation context from its PostUpdate owner when its configuration changes.
The Presentation cycle set remains ordering metadata and does not add a
separate cadence.
The event-driven usd.component_refresh owner supplies
Twin/Lifecycle/Preparation with the active or committed generation for a
mounted-Twin document, and Application/Lifecycle/Preparation for a preview-
only document. The owner requires a generation for a mounted Twin; a missing
generation rejects that policy-controlled refresh visibly.
Cycle labels identify ordering and ownership; they do not imply that every owner
already publishes timing and queue metrics. Expose bounded aggregates at task
boundaries where measurements are needed, then use them to target a Tracy
capture and measure frame responsiveness in a separate unprofiled run. Do not
feed a per-frame diagnostics firehose through the simulation telemetry sampler.
CosimStatus exposes per-session Modelica solver-step duration, dispatch-to-
response latency, and the native worker's pending-task count at step start.
Pass include_values: false for a bounded fleet view without input/output maps
or verbose model/error details; status, counts, and timing remain available.
Rhai profilers can pass include_entities: false to read aggregate worker
metrics without constructing a string-bearing row for every participant.
Response latency includes queueing, transport, and owner response handling; it
is not a pure queue-wait measurement. The browser worker does not expose its
internal queue depth.
Keep telemetry's two lanes distinct: authoritative events used by Rhai retain their producer tick and deterministic delivery order; continuous samples are bounded observations of committed state. The fixed sample boundary captures due channels into a small typed record. A cached channel plan still requires a fixed-path walk and live port reads; its samples then go through a bounded post-simulation cycle. Logging, subscriber fan-out, formatting, serialization, persistence, and UI plot decimation run outside the physics transaction. Reducing fixed-path sampling work and measuring its effect on throughput remain open owner-level work, not a completed guarantee.
Commands and one-shot Rhai/REPL evaluations have independent application
clocks. Record command cadence from the shared CommandOccurred publication
and REPL cadence from actual drain_world_scripts evaluation. Both use the
wall clock, never simulation time; a queued script is not counted as evaluated
until the exclusive REPL owner runs it. Publish their sequence and timing
through ApplicationCadence/application-cadence so consumers do not add
their own timers or infer cadence from render frames.
World-bound one-shot Rhai requests remain serial because their verbs read and
mutate the live World. The REPL owns a bounded FIFO (64 pending requests by
default), evaluates one request per Update, and applies a 100,000-operation
ceiling per invocation. Queue overflow is a terminal command error. Keep
scenario and hook execution in their owning clocks; do not parallelize callbacks
that still use live-world access.
Publish each fact through its one domain boundary before adding a consumer:
scalar co-simulation endpoints use PortRegistry; presentation-ready values
use EngineExposures; lifecycle occurrences use typed events or revisioned
resources. Status bars, authored HUDs, telemetry adapters, API readers, and
recorders consume those publications. They must not independently scan engine
diagnostics, query a physics owner, or introduce a widget-specific registry.
The fixed-step and rollback co-simulation paths share one propagation function
and compiled cache; transform propagation remains a separate spatial owner.
Rollback is an instantaneous replay cycle over recorded inputs, so systems in
RollbackReplay must not be gated by the live virtual clock's paused/running
condition. Keep its actuation ordering aligned with the fixed path and test the
real replay schedule while Time<Virtual> is paused. This body prediction
replay does not reconstruct whole-session commands, Rhai state, or Modelica
state; do not claim whole-simulation replay determinism from it.
For a ShaderLook with vertex_shader, treat the fragment and vertex sources as
one linked material contract: both stages read the same @binding(0) uniform
block, so their Material fields, order, and WGSL types must agree. The
fragment schema is the packed layout; do not invent a second vertex schema or
silently select a replacement shader. Validate the requested stage positively:
sourceAsset needs @fragment and vertex_shader needs @vertex; a combined
WGSL module is valid for either role. A missing or invalid stage is a structured
runtime diagnostic and an unbound material. Rust must not install a
StandardMaterial, neutral shader, or another guessed source as recovery. If a
scenario needs recovery, make it an explicit Rhai policy that can be replaced
or disabled without rebuilding the renderer. Add a cross-file ABI test when
maintaining a multi-stage shader pair. See
shader-layers-and-params.md.
Treat an illumination-bearing grayscale orthophoto as measured imagery, not
intrinsic reflectance. The native lunco-assets-processing kind = "albedo" pipeline
removes its low-frequency illumination field, anchors local detail at a
neutral material base, and sRGB-encodes the resulting linear colour for the
8-bit PNG contract. The texture loader decodes that material back to linear;
terrain shaders use it directly and have no orthophoto compensation function.
kind = "map" remains an analysis/display contrast map and must not be bound
directly as inputs:albedo_map. When weight_albedo is authored, it owns
terrain colour variation; scale procedural dust/mottle by 1 - weight_albedo,
while keeping relief normals, roughness, ambient occlusion, and photometry
independent. Heavy raster math stays in Rust; Rhai assembly policy selects and
authors the standard USD material inputs.
The packed surface map's G channel is ambient occlusion: route it through the
shared terrain_surface_occlusion helper into Bevy's
PbrInput.diffuse_occlusion, never into base albedo. AO is indirect-light
visibility; multiplying it into albedo creates broad false colour patches and
darkens direct sunlight.
The render-side ShaderLook binder owns event-driven preparation of filterable
authored RGBA8 maps: it deduplicates off-thread mip generation by image asset
version,
filters colour in linear light, averages scalar maps linearly, renormalizes
normal vectors, and then enables trilinear/anisotropic sampling. Do not skip a
zero-weight map at load time: authored weights are live inputs, while mip
preparation is the separate renderer-owned image lifecycle.
Project-owned persistence policy belongs to the active Twin manifest's generic
settings boundary. A domain may define one namespaced scalar key and expose it
through the existing SetTwinSetting path; it must not add a global settings
section or a second cache reader/writer for the same artifact.
The local avatar is a runtime kinematic camera embodiment. Its collision
movement uses Avian's existing MoveAndSlide query against standard
UsdPhysics colliders in ActivePhysicsFrame; it does not need a second USD
body schema or a separate collision representation. An explicit Twin setting
may select a documented unsafe policy, but the movement owner reads that
setting directly and remains safe when the setting is omitted, malformed, or
the Twin closes.
The shared semantic input contract lives in lunco-control-core, while the
persisted device-to-intent map lives in lunco-input-core, and is not
avatar-only: the workbench
owns one app-level local intent surface for editor actions when an isolated
preview has no avatar. Shared actions such as CancelIntent read that surface
through the same InputBindingsSettings map, while avatar control continues to
use its own surface; neither path may introduce a raw-key or duplicate binding.
InputBindingsSettings::default() is a valid neutral override: it has no key or
pointer overrides and uses the schema-defined Right look button until the
application overlays its authored defaults. The authored document remains the
source of product bindings, and persisted explicit values take precedence. An
explicit invalid runtime value must be rejected, diagnosed in the status bar, and
clear every live semantic input map so a stale map cannot continue controlling the
simulation. The Workbench host remains alive with input disabled until settings are
corrected. Invalid persisted sections are removed with a settings warning before
the authored defaults are installed.
AttachProgram is the one authoring boundary for binding a .mo, .py,
.rhai, or behaviour-tree source to an existing USD prim. Rust owns the
generic command and lowers a complete ProgramAttachSpec into one journalled
USD change set. The spec carries the source asset, explicit scalar inputs and
outputs, defaults, native USD connections, and the explicit realtimeSafe
promise.
The Models palette, Rhai assembly_edit::attach_program(...), HTTP callers, and the Assembly
editor all use this command. None may insert an ECS marker or maintain a
second program registry. An empty port contract is a valid source-only
attachment, but it is not a running scalar cosim participant; the author must
declare the interface before wiring or stepping it.
Authoring review is a Rhai policy over generic typed substrate. The shipped
authoring_inspection library owns candidate comparison, diagnostic grouping,
diagnostic navigation, unified inspection records, and inspection-mode policy;
it does not know about rovers, landers, or other product nouns. Rust only
provides the reusable mechanisms: document-scoped QueryUsdPrim and
InspectUsdDocument reads, exact preview selection/framing, generic
SetDiagnosticLayers, and settings-backed view-only camera presets.
Keep the ownership split explicit:
FrameUsdPreviewSelection
frames one exact composed path and must not fall back to a whole-stage frame
when the requested path is unavailable.Use exact DocumentId, UsdPreviewId, UsdPreviewViewId, edit target, and
projection generation at every boundary. A document-local Editor fork may be
queried through its composed document stage even when it has no mounted Twin
projection; a stale mapped Twin document must still fail visibly. Missing
collision or provenance is an explicit diagnostic record, not a fabricated
default. Keep positive and negative contracts in the production Rhai scene
gate; do not duplicate these observable assertions in Rust unit tests.
Document-private viewport mounts are recorded separately from workspace/preview
leases in DocBackedTwinScenes. Release them at DocumentClosed, or when the
final preview lease ends with no workspace projection owner. The projection
synchronizer must not consume that closure bookkeeping. Catalog mount-set
changes also prune private authorities before replacement scans.
Asset enumeration belongs to lunco_assets_runtime::discovery and runs through the
shared asynchronous catalog listing owned by lunco-scene-catalog. USD,
WGSL, Modelica, and Python projections are published from one root snapshot;
they must not add a second filesystem walk or a UI-thread scan. A new
manifest/Twin snapshot advances the listing generation, reopens the USD read
set, and drops older metadata completions. This keeps a Twin opened during an
initial scan complete without allowing stale work to populate its catalog.
TwinClosed retires closed-mount metadata, spawn and shader choices before
replacement. It invalidates pending listing/metadata generations while retaining
engine and surviving-mount entries; late completions cannot republish a retired
source.
Asset provisioning follows the same dependency split: lunco-assets-datasets
owns declarations and lifecycle state, lunco-assets-transport owns native
HTTP retry/resume, lunco-assets-download owns verification/extraction and
atomic installation, and lunco-assets-processing owns native decode and
baking. lunco-assets is only the explicit Bevy worker/CLI composition root.
Its ProcessorRegistry selects heavy Rust implementations by authored
ProcessConfig.kind; Rhai owns dataset selection and sequencing, with extra
processor values carried in process.parameters. Do not grow a central Rust
match or make ordinary runtime readers depend on this provisioning stack.
For derived 3D annotations such as a waypoint route, keep one reusable
presentation tool between authored/runtime facts and presentation consumers.
Resolve authored identities through the authoritative binding map and write the
derived USD view to @view@ only when the route changes or the view is first
materialized. Keep durable route edits in @runtime@, separately from the
source scene. Use standard USD geometry and the existing renderer for depth and
occlusion; do not create a Twin-specific ribbon prim or a per-frame document
edit. A reusable route may be a separate composed USD plan; the tool follows
the selected program's canonical parent scope rather than assuming /Route.
The disposable view must use the typed transient USD projection command, so
it is generation-checked and OpenUSD-backed without entering authored undo,
save, or Twin journal history. Marker-root placement, annotation geometry,
labels, and look remain separate owners. Stable frames must do no route
parsing, binding lookup, mesh generation, or marker writes; camera-dependent
label projection is the only remaining per-frame presentation work.
Terrain strokes use producer-owned segment IDs and the mutable
lunco-terrain-surface index. Ordinary edits publish dirty texels through
lunco-materials::float_texture and the renderer's partial-upload adapter;
capacity growth follows the shared image descriptor and material refresh path.
See docs/architecture/50-usd-driven-visuals.md for the ownership and lifecycle
contract.
The same boundary applies across document domains: user Rhai/Modelica edits
use their DocumentHost operation path, while file-backed, USD-embedded, and
generated source refreshes use the shared FileBacked::reload_base contract.
External refreshes advance the live generation and invalidate consumers but do
not create a second undo/journal entry. Never replace a host to hot-swap source;
that discards history and breaks the canonical document identity.
Failure-path acceptance must use an owner-local, transient fixture or typed test
command. For example, the Scenarios menu may inject its unavailable presentation
state without removing or replacing TwinRoots, the active Twin, or scene data;
the default production path remains unchanged and the detailed cause still flows
through the shared StatusBus.
Repeated presentation solvers must also be value-idempotent: compare derived
Transform/CellCoord values before assignment. Bevy marks mutable component
access as changed even when the value is equal, and BigSpace consumes those
signals for dirty-subtree propagation. Guarding an equal write at the producer
is part of the ownership contract; it is not permission to hide a real dirty
input or to add an alternate propagation path.
Use the same owner-local revision/cursor shape for other stable projections:
the Modelica document registry wakes engine sync, telemetry producers pace by
their authoritative model/fixed time and capture a live GlobalEntityId in the
render-free SignalRegistry before a source can become archived, behavior target paths are cached per
entity and invalidated by authored XML or active-frame ancestry, terrain
curvature reacts to its input components, and globe LOD caches pure selection
until camera/LOD/handoff/residency inputs change. These cursors suppress work;
they do not become a second data source or a compatibility fallback.
Apply this contract to all camera pose owners, including shared interaction easing, mounted USD followers, cinematic path followers, and the persistent camera origin. Camera selection/mode policy stays in the application; BigSpace owns only precision representation and derived transform propagation.
Celestial body frames, the sky-time readout, and celestial geometry queries use
CelestialTime. Terrain, stations, and links remain attached to their physical
body frames, which follow that same sample. Unbound USD animation uses the
interpolated physical-time sample. Keep each station and marker on the one
body-fixed grid; do not add a parallel presentation grid or marker copy.
Scenario telemetry is collected only while ScenarioExecutionGate is open.
That gate waits for all initial scene readiness holds because scenarios may
reference entities outside their owner subtree. After admission, entity holds
idle only scenarios inside the held owner subtree. Fixed-step delivery after
SimTickSet releases only events stamped before the current tick; paused
Update delivers discrete events without advancing that tick. A new scenario
reads current owner state in on_start rather than replaying events from before
its lifecycle. Clear the outgoing scene's pending batch when a scene transition
closes the gate.
Workbench perspectives publish scene visibility as layout intent. A perspective
that uses the full window as its 3D presentation must opt into
Perspective::scene_visible_when_docked() so opening a transient side or
bottom panel does not deactivate the selected scene camera or paint the themed
backdrop over the whole frame. Central editor perspectives remain hidden unless
their slot intent includes ViewportPanel; the Workbench still never writes
Camera::is_active, and lunco-usd-bevy remains the sole camera reconciler.
Temporary camera/collider/dynamics diagnostics are runtime presentation, not
USD facts. Reuse the existing Gizmos systems and one Twin-scoped
DiagnosticVisualLease store: Rhai/API/UI selects an explicit target and
policy, while Rust resolves SceneViewport, StageView, Avian collider
realization, BigSpace render poses, bounded snapshots, and lifecycle cleanup.
Do not add a diagnostic USD schema, temporary physics entity, per-frame USD
edit, second camera selector, or global name-only registry. Handles must carry
the Twin/root/mount generation and become stale on SceneTeardown, reload,
target deletion, or TwinClosed; missing targets and unsupported shapes are
visible errors. The draw pass reads finalized render transforms and never writes
physics or scene state. Existing separate debug toggles must converge on this
lease boundary when the feature is implemented rather than gaining another
toggle API. See
docs/architecture/temporary-diagnostic-visuals.md.
Assembly editing starts from the existing document system. Use
DocumentRegistry::fork and the domain's ForkableDocument implementation to
make an untitled document with a fresh identity; do not create a second scene
model or copy a registry. The document implementation copies authored layers
and invalidates private derived state, while DocumentHost copies undo/redo
history by value. The registry attaches a recorder for the new id to the same
Twin journal. Save-As is the first path binding. A derived cache must be
document-owned and keyed by all authoritative layer revisions; full USD
composition and dependency resolution stay with lunco-usd-compose and its
existing resolver path.
Native Assembly Editor view-models are keyed by the existing UsdPreviewId
session. Derive one prim tree, connection canvas, Inspector subview, and
authored USD subview per open session, then paint the session selected by the
focused UsdPreviewViewId. Views share the projected stage but own their
camera/render target and never become document identity. Hidden view cameras
remain inactive, and visible targets are bounded by UsdPreviewRenderBudget
(2048 px per axis, 4,194,304 pixels per view, and 8,388,608 visible pixels per
frame by default). The shared ECS
selection is only the focused-session projection; keep selection and drilled
targets in editor-owned session state so focus changes cannot apply a command
to a same-named prim in another document. Always carry the session's explicit
DocumentId, LayerId, and projection generation into a typed USD command.
The editor's path-selection command is SelectUsdPrim: it requires the
focused UsdPreviewId and resolves through that lease's stage and preview-root
hierarchy.
When the work is an agent-driven human asset edit, use the interactive Assembly Editor runbook. The authoring session is headful and remains visible to the user; every coherent change is applied through the existing typed/journal path, inspected through the focused preview and a screenshot, and reviewed with the user before the next material change or save. This is an operating mode over the existing ownership model, not a new assembly API.
The render-side camera binder also owns Bevy's clustered-light policy.
Use Bevy's ClusterConfig::Single for automatic cameras while the ECS topology
has no point lights, spot lights, light probes, or clustered decals, and follow
those component lifecycle events back to Bevy's normal configuration when one
appears. The camera reconciler must also wait for a positive computed viewport
and positive Clusters dimensions before activating a new window camera,
because GPU extraction receives active cameras before the first cluster
assignment. Preserve an explicit ClusterConfig; do not add a scene-name
check, per-frame light scan, or alternate lighting implementation.
Light shadow intent follows the same standard-schema boundary: read
UsdLuxShadowAPI.inputs:shadow:enable from the composed stage for every light.
Application possession or graphics settings must not overwrite that authored
intent; renderer-owned resource budgets publish facts and let the authored Rhai
render policy report unmet limits, never suppressing authored casters at the
admission boundary.
Scene-root UsdPrimPath values may be empty until the stage is parsed. Resolve
that sentinel through the shared USD defaultPrim resolver before any domain
projector reads the path; visual and celestial projection must not each invent
their own deferred-path handling or permanently mark an unresolved root.
Before creating LunCo*API or a lunco:* property:
crates/lunco-usd-document/schema/core/ and
the maintained USD/PhysX schema that actually owns the concept.UsdGeom for transforms, geometry,
cameras, visibility and purpose; UsdShade for connectable graphs and
materials; UsdLux for lights and shadows; UsdPhysics for bodies, mass,
collision, joints, limits and drives; USD metadata and assetInfo for
descriptions and asset identity; USD connections for graph edges.The mapping and the current keep/remove decisions are recorded in
references/usd-standard-map.md. The
authoritative engine architecture is
docs/architecture/clean-architecture-and-usd-standards.md.
When a report says a capability is missing, verify it against the target checkout before accepting the claim. Search the shipped asset library, reusable Modelica packages, composing scenes, and authored tests; read the closest production exemplar and its consumer. Classify the result as:
engine substrate | reusable asset | mission assembly | external dependency | evidence gapAn absent mission asset is not an absent engine capability. A source parse or documented feature is not runtime evidence. Record the exact source path and the strongest observed state separately: parsed, composed, contract-ready, solver-running, numerical behavior, or visual behavior. Only an infrastructure gap that survives an authored fixture justifies a Rust design.
assets/; keep scene-specific opinions in the composing scene layer.kind = "component"; give a
composed vehicle kind = "assembly". Use doc, displayName, assetInfo,
UsdGeom, UsdPhysics, UsdShade, and UsdLux before adding namespaced
duplicates.parameter is not a runtime input. USD defaults for parameters go to the
parameter set; only actual Modelica input variables enter runtime wiring.
A missing required port is an authoring error with a diagnostic, not a
fallback to an alternate name or a fabricated zero.manual flag or bypass the control surface.Generated models are a first-class reusable composition boundary:
One CollectionAPI:components network root produces one generated Modelica
participant with one public boundary. The synthesizer may partition its graph
into several generated Modelica units, but those units remain inside the same
root and are not additional ECS participants.
After validating a generated source, publish it with its parsed interface and link it to the normal Modelica document. Lifecycle compile admission dispatches the compile once that document is current, using the same generation/session fences as authored models. USD projection must not send a direct worker compile.
Scene lifecycle projection, stable entity identity assignment, and API/path
index publication run in that order in PreUpdate, before
SimulationAdmissionSet. ClockProjectionSet gates the following virtual
delta sample, and the fixed runner checks admission before each full tick. Do
not add a separate startup identity pass or readiness
poll; a projected reference must resolve by path on the first resumed tick.
Keep acausal conservation connectors (Pin, HeatPort, FluidPort, Flange,
and equivalent domain connectors) inside the root whose solver owns their
algebraic equations. A typed scalar USD connection between two roots is causal
and may have a macro-step or one-step delay. It is not an acausal connect().
USD connection projection caches immutable endpoint facts by composed-stage
generation and runtime-instance identity. Reconciliation retains unchanged
SimConnection entities and bindings; edited edges use the normal add/remove
lifecycle. Endpoint lifecycle observers, USD edits, and authority changes feed
the shared UsdWiringDirty latch, so stable updates do not scan endpoint
populations for Added<T> filters. Domain source-class completion invalidates
only roots that use that source. A root is not synthesized until every
referenced member class has a terminal verdict, avoiding repeated graph
extraction across asynchronous asset arrivals. Scene teardown clears the
scene-owned reverse index, pending candidates, and in-flight synthesis tasks;
resolved member-class facts remain asset-owned and reusable. Cosim source discovery and Python
readiness share one lifecycle-coalesced pending-prim set rather than probing
all USD prims for unprocessed markers on stable updates.
Synthesis hooks run with the owning Twin/Lifecycle/Preparation context and
active-or-committed scene generation, without an elapsed clock. Capture that
typed context before async dispatch and pass it unchanged to the hook; the
synchronous live-projection path uses the same contract. Fence async results
by that Twin generation and the owning USD generation or prepared plan. Keep
the policy's context check in Rhai and cover off-cycle rejection plus
generated-source publication in a production scene test.
If zero-delay bidirectional coupling is required, move the coupled components into one generated Modelica root and solve the combined DAE. Do not add a Rhai polling loop, duplicate state, or hidden cross-root fallback. Automatic island fusion is an optional future mechanism; correct network authoring is the current default.
if for “electrical”, “hydraulics”, or one vehicle..mo wrapper. Add new equations only when the maintained
package and its public contract cannot express the requirement.Icon and Diagram annotations, policy-owned placements, and any
domain-specific presentation belong there. Rust may provide generic source
loading, class resolution, and typed projection metadata, but must not encode
a domain poster or duplicate the policy's graph.Line waypoints and a policy-owned diagram rail. Use adaptive,
extent-aware placement for repeated members. Derive the visual hub from
graph incidence, using the typed LunCoModelicaTopologyAPI storage role
only to break equal-incidence ties; place source and load roles on
opposite deterministic banks and pack neutral members onto the shorter
bank. Do not branch on component class names or let a fixed demo layout
imply a direct source-to-load wire when the composed graph has many members.
These roles are presentation metadata, not Modelica solver direction:
acausal flow can reverse at runtime. Keep source/load lane ranges disjoint
around the hub so a horizontal route cannot imply a direct connection.
Member coordinates are local to the
owning unit diagram; root coordinates place unit instances.flow Real such as LunCo.Electrical.Pin.i must be discovered by connector
metadata and sampled from live node state; Rhai emits ordinary Pin/
connect(...) equations and must not grow a generated-electrical animation
branch. Non-zero signed flow animates in the resolved direction; zero or
missing state remains idle/diagnostic.NodeMoved event and persisting standard
Placement annotations through ModelicaOp::SetPlacement. A generated
document stays read-only because USD plus Rhai owns its source; expose
Duplicate to edit instead of accepting a non-persistent drag.source, units, layout.units,
layout.members, source_roots, and member_output_aliases fields, no
undeclared root/unit causal ports, promotions only for outputs present in the
loaded member class, non-overlapping policy placements, complete policy units,
native members nested in their owning units, and no direct native members on
the root. Member-placement overlap is invalid within one unit coordinate
system; different unit diagrams may legitimately reuse local coordinates.
Treat missing or loading class definitions as explicit resolver
states in the canvas, never as a fabricated resolved node.generated/ document origin, retire it on removal/despawn, and keep
authored document cleanup separate. Structured packages under
assets/models/<Root>/package.mo and Twin-declared [modelica].paths are
ordinary Modelica search-path roots: the compiler/editor discovers the root
segment of a qualified reference generically and loads that package through
the shared Modelica engine. A Twin without that section derives package roots
from its indexed .mo files. Each live compile admits required roots through
the LoadSourceRoot worker path before Compile; file-backed source assets
derive requirements from their prepared AST interface, and generated-model
policies return the required source_roots manifest. That manifest does not
replace composed USD facts for class discovery, and Rust must not name a
particular library. The live worker rejects unadmitted roots and reports
failed roots to dependent compiles rather than synchronously rediscovering
them. Reproject from the generic completion signal.member_output_aliases promotion table, including
the explicit empty-table case. Rust may validate known member/output pairs and
identifier uniqueness, but must not choose aliases or emit visual source for a
policy.assets/scenarios/tests/; reusable standalone assertions may remain under
assets/scripting/tests/ and run through scripts/api/run_rhai_test.sh.
The Rust host supplies composed facts and invokes the shipped policy; Rhai
owns assertions about generated source, topology, layout, and presentation.
Literal top-level Rhai constants are supported inside policy helper functions
by the shared hook binding, so presentation policy can remain editable without
adding Rust-side layout parameters.SimConnections is explicit causal feedback: the fixed-step exchange may
have a one-step delay, but it is not an unresolved algebraic loop and must not
emit an algebraic-loop warning. Do not add a Rhai polling bridge. If
zero-delay continuous feedback is required, synthesize one Modelica network
and solve it as one system; force-producing cycles remain subject to the
explicit realtime-safety contract.When a mechanism is wrong, perform a clean cutover:
generatedSchema.usda and plugInfo.json from the authoritative
source where applicable. Never edit generated schema by hand.--validate proves syntax only; it does not prove runtime wiring.Permitted defaults are only semantic defaults declared by the authoritative USD or Modelica schema. A numerical guard such as a positive epsilon is not a compatibility fallback and must be named as a numerical guard.
Run the smallest relevant checks first, then the production binary:
python3 scripts/gen_schema.py
RUSTC_WRAPPER= cargo fmt --all -- --check
python3 scripts/gen_schema.py
"$LUNCOSIM_BIN" test --scene scenes/tests/sensor.usda
RUSTC_WRAPPER= cargo test -p lunco-usd-sim --test usd_connection_mechanics -j 4
CARGO_INCREMENTAL=1 RUSTC_WRAPPER= cargo build -p lunco-luncosim --bin luncosim -j 4For a live feature, launch only $LUNCOSIM_BIN with an explicit free
API port, verify readiness, inspect ports and composed connections, and run the
scene through the real executable. Report separately:
Keep long USD fixtures and asset-specific assertions in authored .usda and
Rhai scene tests. Rust test stages should be minimal and programmatic, and only
cover mechanisms that the production query/command surface cannot observe.
Never claim that a source parse or unit test proves the scene is physically correct.
© LunCoSim, Apache-2.0. Rendered from Markdown: HTML in the file is shown as text, images as links, and headings moved down two levels. Raw file
SKILL.md and 1 other file (references) in skills/luncosim-architecture of LunCoSim/lunco-sim.
Open the folder on GitHubat commit 43f1301
Luncosim Architecture next to the 5 skills that share the most tags, products or categories with it. Stars are the repository's; “used in” counts other GitHub owners with a copy.
| Skill | Stars | Used in | Tokens | Auto-check | Licence | Repo updated |
|---|---|---|---|---|---|---|
| Luncosim Architecture this skillLunCoSim/lunco-sim | 107 | — | ~19k | Automated safety check: Pass | Apache-2.0 | |
| Update V8 Versionopeninterpreter/openinterpreter | 69k | 2 repos | ~845 | Automated safety check: Pass | Apache-2.0 | |
| Firecrawl Page Scrape Integrationfirecrawl/firecrawl | 190k | 1 repos | ~944 | Automated safety check: Pass | ISC | |
| Migrate Core Code to Submodulestinyhumansai/openhuman | 42k | — | ~2.6k | Automated safety check: Pass | GPL-3.0 | |
| Rust TDD Workflowrtk-ai/rtk | 83k | — | ~753 | Automated safety check: Notes | Apache-2.0 | |
| OpenLogi macOS Permissions TriageAprilNEA/OpenLogi | 23k | — | ~2.5k | Automated safety check: Notes | Apache-2.0 |
openinterpreter/openinterpreter
Bumps the pinned v8 and rusty_v8 versions in Codex, validates the release-candidate path with the v8-canary check, and traces failures to upstream build changes.
firecrawl/firecrawl
Adds Firecrawl's /scrape endpoint to application code to pull markdown, HTML, links, screenshots or structured data from a single known URL.
tinyhumansai/openhuman
Plans and carries out moving non-host-specific code and its tests from the OpenHuman core into vendored tiny submodule libraries, then releases the submodule and re-pins the host.
rtk-ai/rtk
Enforces red-green-refactor for Rust work, with idiomatic test patterns, a naming convention and a pre-commit gate of cargo fmt, clippy and test.
AprilNEA/OpenLogi
Decides whether an OpenLogi device problem on macOS is a privacy-permission (TCC) problem, using agent log lines, and says which identity needs which grant.
farm-fe/farm
Guide for writing idiomatic Rust code based on Apollo GraphQL's best practices handbook.
LunCoSim/lunco-sim
Generate concise LunCoSim nightly GitHub release notes with platform downloads, installation guidance, an AI-agent mission prompt, and a changelog link.
LunCoSim/lunco-sim
Build or repair a reusable scene component through a live LunCoSim Editor session.
LunCoSim/lunco-sim
Build or review a componentized LunCoSim USD assembly with a realistic, dimensionally checkable presentation.
LunCoSim/lunco-sim
Author and review LunCoSim behavioral, asset-backed, component, mission, visual, and requirements-verification tests.
LunCoSim/lunco-sim
Create, extend, register, or debug a reusable LunCoSim Rhai tool library for live USD authoring, component linting, inspection, or test support.
LunCoSim/lunco-sim
Author an interactive tutorial, guided lesson, onboarding flow, coach-mark tour, or objectives checklist in LunCoSim.
Works with
Review or build a LunCoSim feature that crosses USD, Modelica, Avian, Rust, or Rhai. Luncosim Architecture is an agent skill from LunCoSim/lunco-sim. Review or build a LunCoSim feature that crosses USD, Modelica, Avian, Rust, or Rhai.
Run `npx skills add LunCoSim/lunco-sim --skill luncosim-architecture -a claude-code`. Or copy the skill folder (skills/luncosim-architecture in LunCoSim/lunco-sim) into .claude/skills/luncosim-architecture in your project. Claude Code loads it when a task matches its description.
Run `npx skills add LunCoSim/lunco-sim --skill luncosim-architecture -a codex`. Or copy the skill folder (skills/luncosim-architecture in LunCoSim/lunco-sim) into .agents/skills/luncosim-architecture in your project. Codex loads it when a task matches its description.
Cursor, Gemini CLI, GitHub Copilot and OpenCode also load SKILL.md folders. With the skills CLI, run `npx skills add LunCoSim/lunco-sim --skill luncosim-architecture -a cursor` (or -a gemini-cli, github-copilot or opencode for the others). To copy it by hand, put the folder in .cursor/skills/luncosim-architecture, .gemini/skills/luncosim-architecture, .github/skills/luncosim-architecture and .opencode/skills/luncosim-architecture in your project.
Going by SKILL.md and its folder, Luncosim Architecture needs the command-line tools its instructions call (kind, cargo and python3).
SKILL.md contains no URLs. Any network use would come from the scripts or tools the agent runs. This is read from the text; nothing was executed.
Our automated static check of SKILL.md found no risky patterns, such as piping downloads into a shell, reading credential files or hidden Unicode. It is not a guarantee. Review the folder before installing.
Luncosim Architecture is published under the Apache-2.0 licence (the repository's licence). It allows redistribution, so the full SKILL.md is shown on this page.
About 19k tokens (SKILL.md is roughly 77k characters). Agents keep only the skill's name and description in context until a task matches; then they load SKILL.md in full. Its references folder adds about 786 tokens, read only when the agent opens those files.
Skills that share tags, products or a category with Luncosim Architecture: Update V8 Version (openinterpreter/openinterpreter, 69k stars), Firecrawl Page Scrape Integration (firecrawl/firecrawl, 190k stars), Migrate Core Code to Submodules (tinyhumansai/openhuman, 42k stars) and Rust TDD Workflow (rtk-ai/rtk, 83k stars). The comparison table on this page puts their stars, adoption, token cost, safety result and licence side by side.
LunCoSim (a GitHub organization) maintains it in LunCoSim/lunco-sim, which has 107 GitHub stars. The repository holds 40 skills in this directory. The repository was last updated on October 10, 2026.
Source: LunCoSim/lunco-sim on GitHub. Facts on this page come from the repository at the commit we read; the author's words are quoted as theirs.