--- name: capability-discovery description: > Find existing LunCoSim capabilities before declaring a feature missing, unsupported, or impossible. Use when a request sounds like a gap, a command or UI action is hard to locate, a build or runtime error suggests an API is absent, or an agent is about to propose a new mechanism or fallback. --- # Discover LunCoSim capabilities Use this runbook before writing “LunCoSim cannot do X”, “X is not implemented”, or adding a replacement mechanism. A failed first search is not evidence of absence: the capability may be named after its owner, exposed only through a registration, available in a skill, or implemented in a different format. ## 1. Start from the current checkout Confirm the worktree, branch, and dirty state. Treat old reports, another worktree, a stale binary, and a failed build as leads rather than current capability evidence. Preserve unrelated changes. Translate the request into several search terms: the user's phrase, the likely architecture noun, a probable crate or schema, and a command/query/tool name. Then search generated-output-free paths: ```bash rg -n -i --glob '!target/**' '' \ AGENTS.md skills docs specs crates assets scripts rg -n -i --glob '!target/**' '' \ skills docs crates assets scripts ``` Read only the routed material, but always begin with: - [`skills/README.md`](../README.md) for skill routing and cross-cutting rules; - [`docs/README.md`](../../docs/README.md) for the documentation map; - [`docs/crates-index.md`](../../docs/crates-index.md) for ownership; - [`docs/apps/README.md`](../../docs/apps/README.md) for binaries and launch modes; - the relevant architecture document, specification, skill, crate README, and authored asset examples. If the first vocabulary is empty, search synonyms, the owning domain, standard USD schema/property names, and likely `Command`, query, observer, registration, or Rhai tool names. Do not conclude from one README, one crate, or one failed symbol lookup. ## 2. Trace the authoritative owner For each promising result, follow the complete path: ```text format or authored asset -> loader/composer/parser -> owner and registration -> public caller/API/query/command -> runtime projection or execution -> test, example, or acceptance evidence ``` Check the maintained dependency when the question concerns OpenUSD, Bevy, Avian, Modelica/Rumoca, wgpu, or another library. Search Cargo features and registration macros as well as function names. A source file without a registration or caller is not the same as a usable capability; a missing name in one crate is not proof that the capability is absent. For live behavior, use the production binary and its API. Start a rebuilt `$LUNCOSIM_BIN` with an explicit free `--api PORT`, then use: ```bash curl -s http://127.0.0.1:PORT/api/commands/schema | jq . curl -s -X POST http://127.0.0.1:PORT/api/commands \ -H 'content-type: application/json' \ -d '{"type":"DiscoverSchema"}' | jq . ``` Use `ListEntities`, `ScriptingCatalog`, `ListToolLibraries`, `GetToolLibrary`, and the relevant typed query/command to verify a live surface. `--validate` proves parsing/preflight only; it does not prove runtime behavior. Use a production authored scene test, API verdict, or headful visual capture when that is what the requested capability requires. ## 3. Know the format boundary Choose the format whose owner already matches the requested fact: | Format or layer | Use it for | Do not use it for | |---|---|---| | `twin.toml` | Twin identity and active default stage | equations or mission policy | | USD (`.usda`, composed stage) | parts, identity, transforms, variants, materials, topology, typed ports, connections, and authored physics | continuous integration or scenario sequencing | | Modelica (`.mo`) | continuous equations, state, energy balance, and solved outputs | USD traversal or mission policy | | Rhai (`.rhai`) | events, commands, sequencing, policy, authored tests, and reusable tools | continuous dynamics or a second engine core | | Rust crates | generic engine mechanisms, projection, scheduling, and hot paths | model-specific names, hidden policy, or a duplicate authoring API | | WGSL | shader stages and visual computation | simulation state ownership | | runtime HTML/CSS-like UI | Twin-authored presentation and semantic UI actions | direct mutation of domain state | | API JSON / MCP | transport of typed commands, queries, and discovery | a second persistent domain format | A composed USD stage is data; it does not by itself execute Modelica, Rhai, physics, or rendering. Standard USD schemas and properties own authored facts before a custom `lunco:` field is considered. Asset identity and storage use the existing asset resolver and `@lunco://...@` references. ## 4. Use dynamic Rhai tools when the capability is policy LunCoSim can gain reusable authoring, inspection, lint, and test behavior without a Rust rebuild. Before creating a tool, query `DiscoverSchema`, `ListToolLibraries`, and `GetToolLibrary`, then search: - shared libraries in `assets/scripting/tools/`; - Twin-scoped libraries in `/tools/`; - prelude helpers and the relevant `author-rhai-tool` skill; - `docs/scripting-guide.md` and its tool-library section. Compose or minimally extend an existing library when possible. Use a new library only for a reusable contract, missing generic operation composition, or repeatable report/test boundary. Keep one owner: a tool may choose policy and produce typed plans, but USD/document owners apply edits, Rust owns generic engine mechanisms, and Modelica owns continuous equations. A one-off mission belongs in a scenario, not a shared tool. The normal dynamic-tool cycle is: ```text edit .rhai -> RegisterToolLibrary { name, source } -> ListToolLibraries / GetToolLibrary -> minimal RunRhai or RunScenario call -> authored scene test or runtime evidence ``` Registration validates the source in the production Rhai engine and, with an active Twin, persists it in the Twin tool directory. Tool/source changes do not need a Rust rebuild; Rust observers, command types, schemas, and projection changes do. Discovery is not invocation proof: verify the exact function from the actual execution context. ## 5. Follow the normal development cycle Use this sequence for a capability request or implementation: 1. **Frame the intent.** Define the observable result, format/domain, and evidence needed. Choose the primary skill from `skills/README.md`. 2. **Discover before designing.** Search skills/docs, then owner source, registrations/callers, maintained dependencies, assets, and live API surfaces. Record the existing mechanism or the bounded gap. 3. **Establish a baseline.** Reproduce the current behavior with the narrowest relevant test, production binary, API call, or visual capture. 4. **Change the owner.** Extend the existing mechanism in its authoritative layer. Keep policy in Rhai, authored identity/topology in USD, equations in Modelica, and generic engine work in Rust. 5. **Validate the smallest sufficient path.** Use `--validate` for asset preflight, the owning Rust target for low-level mechanisms, authored Rhai scene tests for observable behavior, and the production `luncosim` binary for runtime/visual evidence. Reuse valid evidence when inputs are unchanged. 6. **Review integration.** Search callers, docs, skills, registrations, tests, and examples for stale names. Check `git diff --check`; remove retired paths, shims, fallbacks, and duplicate owners. 7. **Hand off.** Report exact files/symbols, commands, revision, evidence type, and remaining blockers. For non-trivial LunCoSim work, keep the Trello card in the correct lifecycle state and do not claim acceptance without observed evidence. ## Bounded answers to common questions **“I cannot find the feature. Is it missing?”** Not yet established. Search the routed skills and docs, trace the owner and registration, search alternate vocabulary and maintained dependencies, then check the live API or production test when applicable. Report what was searched. **“The API command or UI action is not in the source file I opened.”** Use `DiscoverSchema`; commands and providers self-register and may be owned by another plugin or adapter crate. Trace the registration and public caller before adding a new command or UI path. **“The docs say one thing and runtime does another.”** Verify the current branch, build the production binary from that checkout, and prefer current source plus observed registration/runtime evidence. Update the canonical documentation in the same change; do not preserve two contradictory contracts. **“Can I add a quick Rust workaround?”** Only if the missing piece is a generic engine mechanism that cannot be composed through an existing authored/API surface. First check the relevant skill, standard USD owner, existing Rhai tool, and maintained dependency. Do not add a model-specific Rust path, compatibility alias, silent fallback, or second owner. **“Do I need a rebuild?”** Usually not for authored `.rhai` scenarios/tools or WGSL shader source when the existing reload surface covers the change. A new Rust command, observer, projection path, schema, or dependency requires a focused rebuild and a replacement production session. Use API `Exit` before replacing a session. **“Which file format should I use?”** Use the ownership table above and the existing authoring skill. If the fact is scene identity/topology, start in USD; if it is continuous state, Modelica; if it is mission policy or an authored verdict, Rhai. Keep API JSON as transport, not as a new source of truth. **“Does `--validate` prove that it works?”** No. It proves asset parsing, resolution, and authored preflight/lints. Runtime behavior needs a production scene test, API observation, or visual evidence. **“Where should the test go?”** Put behavior and policy assertions in `assets/scenarios/tests/*.rhai` and run them through the production scene-test binary. Reserve Rust tests for generic mechanisms that the public Rhai/API surface cannot observe, such as parsing, serialization, schema/composition, or pure lowering/math. **“When may I say ‘impossible’?”** Only after the relevant current owner, registrations/callers, maintained dependency, and runtime surface have been checked and a concrete contract, dependency, platform, or permission limit is demonstrated. Otherwise say “not found in the searched scope”, “implemented but unwired”, “not verified”, or “externally blocked”, with the evidence. ## Result categories Every discovery report should use one of these bounded outcomes: - **Found and usable:** exact path, symbol, command/query, tool, or workflow. - **Implemented but unwired:** owner exists; name the missing registration, feature, caller, asset reference, or runtime integration. - **Present elsewhere:** exact branch, commit, worktree, or version mismatch. - **Not found in the searched scope:** list paths, terms, owner, and evidence checked; do not generalize to the whole product. - **Externally blocked:** exact dependency, platform, permission, or environment error, plus the owner that would resolve it. Link the relevant skill and documentation in the handoff. If discovery finds an existing capability, switch to that capability's implementation or usage skill instead of creating a parallel mechanism.