Agent skill

Test Via API

by LunCoSim in LunCoSim/lunco-sim

How to verify luncosim changes end-to-end without asking the user to click.

Apache-2.0Auto-check passedTesting & QA

Install Test Via API

skills CLI
$ npx skills add LunCoSim/lunco-sim --skill test-via-api -a claude-code

Project install by default; add -g for ~/.claude/skills/.

GitHub CLI
$ gh skill install LunCoSim/lunco-sim test-via-api --agent claude-code

Project scope by default; add --scope user for a personal install. Needs GitHub CLI 2.90.0 or later (public preview).

Manual copy
$ git clone --depth 1 https://github.com/LunCoSim/lunco-sim.git skills-src && mkdir -p .claude/skills && cp -r skills-src/skills/test-via-api .claude/skills/test-via-api && rm -rf skills-src

Use ~/.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/

Facts

Skill name
test-via-api
GitHub stars
105
Token cost
~7.8k tokens
SKILL.md length
3,331 words
Files
1
Skills in repo
38
Repo updated
First seen
Licence
Apache-2.0

At a glance

How to verify luncosim changes end-to-end without asking the user to click.

  • Works in 2 steps: InspectActiveDoc → are the components… → If components exist: their TYPES…
  • Ever a UI flow needs verification — a new diagram
  • SKILL.md covers Mode policy, Live shader iteration, Tutorial and Rhai iteration and Live runtime HTML/CSS iteration, plus 9 more sections
  • Calls curl, jq and python

What it does

Test Via API is an agent skill from LunCoSim/lunco-sim. How to verify luncosim changes end-to-end without asking the user to click. Trigger whenever a UI flow needs verification — a new diagram, a fix to drill-in, a screenshot to confirm a regression, a smoke test of any reflect-registered Event command. The workbench exposes a small HTTP API on --api PORT; this skill is the runbook for driving it from curl, capturing screenshots, diagnosing failures, and adding new commands when the existing surface isn't enough. Also trigger when you catch yourself about to pkill…

Its SKILL.md is about 7.8k tokens, which your agent loads only when the skill is triggered. It is a single SKILL.md file with no bundled scripts.

It sits in Testing & QA, covering REST APIs, QA and bug reports and Runbooks and postmortems. The repository describes itself as: Collaborative Multiphysics Cosimulator For Space Missions 🌎🚀🌚. The licence is Apache-2.0.

When your agent uses it

  • Ever a UI flow needs verification — a new diagram
  • A fix to drill-in
  • A screenshot to confirm a regression
  • A smoke test of any reflect-registered Event command

Example prompts

  • “can you check the screenshot?”
  • “/test-via-api”

Requirements

  • Python 3

Workflow steps

2 steps, taken from the first numbered list in SKILL.md.

  1. InspectActiveDoc → are the components really there in the AST?
  2. If components exist: their TYPES probably aren't in

What it can do on your machine

Read from SKILL.md and the folder at commit d1c6f00. It shows what the files ask for, not the result of running them.

  • Tool permissions

    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.

  • Runs code

    Shell commands in SKILL.md call:

    • curl
    • jq
    • python
    • cargo

    From the folder's file list and the shell code blocks in SKILL.md.

  • Network

    No URLs in SKILL.md. Its commands use curl, which can reach the network depending on how they are called.

    From URLs in SKILL.md, links to its own repository left out.

  • Credentials

    Names no API keys, tokens, secrets or passwords.

    From names ending in _API_KEY, _TOKEN, _SECRET, _KEY or _PASSWORD in SKILL.md.

Context cost

Test Via API loads about 7.8k tokens when it runs. Until then it costs about 189 tokens; SKILL.md has 3,331 words of instructions outside code blocks.

Always · name and description, kept in context so the agent knows when to use it
~189
When it runs · the whole SKILL.md, loaded when a task matches
~7.8k

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.

Safety

Auto-check passed

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.

SKILL.md

The full file from LunCoSim/lunco-sim at commit d1c6f00, republished under its Apache-2.0 licence (© LunCoSim). 3,331 words, ~7,756 tokens.

Download SKILL.mdSave it as .claude/skills/test-via-api/SKILL.md (or your agent's skills folder).
name
test-via-api
description
How to verify luncosim changes end-to-end without asking the user to click. Trigger whenever a UI flow needs verification — a new diagram, a fix to drill-in, a screenshot to confirm a regression, a smoke test of any reflect-registered Event command. The workbench exposes a small HTTP API on `--api PORT`; this skill is the runbook for driving it from curl, capturing screenshots, diagnosing failures, and adding new commands when the existing surface isn't enough. Also trigger when you catch yourself about to `pkill lunica`, write a temp `.rs` test binary to inspect rumoca state, chain a `sleep 30 && tail` poll, or ask the user "can you check the screenshot?". The right move is always: send a command, take a screenshot, read it, decide.

Test the workbench via API

The production luncosim exposes a reflect-registered Event API on --api PORT (default 4101). Always pass this flag when launching the luncosim, including visual checks; use another explicit free port if 4101 is occupied. UI verification — diagrams rendering, drill-ins, simulations, file ops — should be driven from this API rather than asking the user to click.

Mode policy

Use a headful windowed luncosim session by default whenever the work concerns a scene, Editor, viewport, UI, motion, layout, or any result the user needs to watch. Start the production binary with --api PORT and a graphical display; do not add --no-ui, --offscreen, or another windowless flag. Keep that window alive while iterating so the user can see each coherent change.

Use --no-ui/luncosim-server only for explicitly numeric or API-only checks where there is no visual acceptance claim. Use --offscreen only when the user specifically requests an offscreen recording or a graphics test that is meant to run without a visible window. If a requested visual check cannot run headfully, stop and report the display/session blocker instead of silently falling back to headless mode.

Live shader iteration

Shader source edits are a live-test path. Keep the production luncosim running, edit the WGSL under assets/shaders/, then dispatch ReloadShader through the same API. A bare engine path such as shaders/starfield.wgsl resolves the active default-source or lunco:// asset identity; an explicit lunco://… or twin://… path is exact. An empty path reloads every currently loaded WGSL asset, not an arbitrary hard-coded file list. The response reports the queued paths and fails if no active asset matches. Confirm the command result, then inspect the unchanged window; shader compiler errors remain in the render log. Do not relaunch the app just to pick up a shader edit.

Tutorial and Rhai iteration

For Twin lifecycle regressions, open an editor document in Twin A, replace it with Twin B, and inspect ListOpenDocuments plus USD preview state. No old document ID or preview may survive; repeat OpenTwin on B to verify fresh admission. A rejected Twin path must preserve the current documents. Twin replacement closes loose/library editor documents as well as Twin-owned files; RestartScene preserves editable documents and tests a different lifecycle. Pending editor and workspace-restore work must not recreate old tabs after replacement. Modelica CloseDocument is owned by the headless core, so exercise scratch-document closure in both headless and windowed hosts.

The maintained document-close scene gate is scenes/tests/twin_session_retirement/twin_session_retirement.usda with verdict channel TWIN_DOCUMENT_CLOSE. Run it through $LUNCOSIM_BIN test. The gate covers dirty SysML drafts as well as Modelica scratch documents; assert actual domain retirement rather than only removal from workspace metadata. The windowed switch/reopen/rejected-candidate gate is python scripts/api/test_twin_session_retirement.py; set LUNCOSIM_BIN and an explicit free LUNCOSIM_API_PORT. Its assertions are authored in assets/scenarios/tests/twin_session_retirement.rhai, and its process wrapper verifies API Exit and port release.

Tutorial behavior is authored in assets/tutorials/**/*.rhai and should be tested through its production scene gate in assets/scenes/tests/ with the observer in assets/scenarios/tests/. After editing either Rhai file, rerun ./scripts/run_scene_tests.sh --no-build --exact <scene-name> for a single scene, or ./scripts/run_scene_tests.sh --no-build <scene-substring> for a group; the runner uses four independent headless processes by default, and -j/--jobs N changes that bound (-j 1 is the serial diagnostic mode). This does not change each gate process's deterministic --threads 1 --jitter 0, and graphics assertions remain a separate serial offscreen pass. Do not rebuild the Rust core for a script-only change. The observer must verify public cmd:* events plus the resulting live state and emit a real verdict. Parsing or --validate is only preflight evidence.

The generic model-authoring facades have the same production gate. The focused fixture is model_authoring:

bash
./scripts/run_scene_tests.sh --no-build --exact model_authoring -j 4

Its Rhai observer exercises model_context, readiness_report, scene_recipe, port_graph, wiring_plan, and publish_component, including fail-loud missing endpoint, control, asset, identity, and provenance cases. Use this narrow gate after changing the tool or its authored fixture; a parse pass alone does not prove the namespaced calls work in production.

The live port-owner collision contract is covered the same way:

bash
./scripts/run_scene_tests.sh --no-build --exact port_owner_collision -j 4

Its USD fixture owns the duplicate and clean control cases; the Rhai observer calls RunLint and verifies the structured LintReport winner, shadowed owner, property paths, and precedence. Prefer this authored pair for observable lint behavior instead of embedding USDA or fake backend components in Rust tests.

Public USD query-provider behavior belongs in authored .usda fixtures and Rhai scene gates, exercised through the production query bridge. Keep Rust tests for provider internals only when the behavior cannot be observed through that public surface; do not construct DocumentRegistry worlds with inline USDA to duplicate inspection, target-resolution, or synchronization behavior. The usd_query_api gate covers those public contracts, while the assembly proposal lifecycle gate covers edit-session inspection.

Editor material edits belong in an authored USD fixture plus an editor Rhai scenario, not a Rust test with a multiline USDA string. The usd_material_edit_projection fixture exercises typed material edits, whole-source replacement, and the preview's projected-generation lifecycle through the production editor runner. Keep Rust coverage for the focused USD-to-render-intent mapping mechanism, where the mapping itself is the subject.

For source-preview isolation, run scripts/api/test_usd_source_isolation.py with an exact --scene, --source, composed --selection-path, free --port and --log. Its RunScenarioAsset invocation supplies all required parameters to assets/scenarios/tests/usd_source_isolation.rhai and requires eight authored checks, including invalid-source rejection, unchanged Twin/topology and advancing physics. --screenshot records the exact viewport/selection context; the shared ProductionSession.capture_screenshot requires fresh publication before API Exit. Pair the resulting image with those handles when checking Prim-tree reveal and highlight.

For spatial safety coverage, keep malformed authored transforms in the USD projection layer: that layer must reject them before ECS materialization. Test runtime-state admission at the lunco-usd-avian bridge owner, where a finite but f32-unrepresentable pose must raise a named RuntimeFaults record and PhysicsHolds::SAFETY_FAILURE before Avian runs. Test public Raycast and GroundHeight with a finite but unrepresentable query origin through an authored production scene; the expected result is {hit:false}, not a terminal simulation fault. This distinction keeps query-input validation from masking an engine-state failure and avoids duplicating guards in sensors, terrain, and vehicle callers.

For terminal runtime-fault recovery, verify the two owners separately and then the lifecycle seam. RuntimeFaults must pause Time<Physics> with a zero delta while leaving Time<Virtual> available for diagnostics and teardown. The bad scene is not repaired or resumed. SceneTeardown clears only the outgoing scene's terminal fault and PhysicsHolds::SAFETY_FAILURE; the physics owner also resets scene-owned holds, deliberate-step debt, and the physics clock before replacement admission. The focused regression names are terminal_runtime_fault_pauses_physics_until_cleared in lunco-physics and fault_then_scene_reload_can_admit_a_replacement_runtime in lunco-usd-sim.

The multi-process scene-test runner cannot prove same-process replacement: its expected terminal-fault process exits when the authored verdict is observed. Use a lifecycle test or a live API session that explicitly submits teardown, loads the replacement, and checks the new scene's admission/status. Do not add an automatic repair, retry, process restart, or fault-clearing fallback to make the invalid scene continue.

Scene, render, and editor acceptance runs are isolated by default and use a fresh production process. Their launchers keep settings in memory and disable runtime-overlay reads and writes regardless of Twin policy. The production scene runner fails before scenario start if a file-backed authored USD document is already dirty; runtime setup must not turn a clean fixture into unsaved authored work.

For a one-shot assertion that needs the currently loaded USD stage, use ./scripts/api/run_rhai_test.sh <port> <test.rhai> [probe-prim]. It prepends the test libraries and delegates to the native luncosim rhai --stdout client, which calls RunRhai on the existing production session. Editing and rerunning the test does not restart the app. Use ./scripts/api/run_scenario.sh when the assertion should remain attached as a persistent observer.

When a test depends on a Twin-scoped Rhai tool, register or reload that library in the same session first, confirm it with ListToolLibraries/GetToolLibrary, and make a minimal namespaced call before running the real observer. Discovery does not prove that the current Rhai engine has rebuilt its static module set. For a user-requested same-session workflow, use RunRhai or an attached RunScenario; do not substitute the multi-process scene-test runner.

For an interactive lesson, keep one production session and use RunScenarioAsset through /api/commands, then inspect the HUD and event stream. RunScenario is the live hot-reload path for a script attached to an existing host. Restart only when changing Rust or when a clean scene lifecycle is itself under test.

To exercise a discrete semantic action, address the target's api_id and send one SimulateIntentEdge command; do not model a pulse as two API requests:

json
{
  "type": "ExecuteCommand",
  "command": "SimulateIntentEdge",
  "params": {
    "target": 1234,
    "intent": "release",
    "edge": "pulse",
    "producer_id": 4123
  }
}

The response includes the canonical intent, edge, producer_id, correlation_id, and command id. Reuse the same nonzero producer_id for commands from one API producer. API submissions also include admission with the committed scene generation, effective simulation tick, and per-tick sequence. Confirm delivery through the intent.edge telemetry event (source, value.target_gid, and value.correlation_id identify the same target/action); its admission fields carry the same stamp. Use the returned correlation_id for the exact edge's trace, even when the scene emits later edges:

json
{
  "type": "ExecuteCommand",
  "command": "CausalTrace",
  "params": {"target": 1234, "correlation_id": 5678}
}

The response composes the authored binding, selected PortRegistry owner, USD connection/native-joint admission, current retained measurements, and the producer's admission stamp. An empty/pending stage is a real incomplete path. A target-scoped command still passes the normal ownership/authority gate; an acknowledgement alone does not prove that a consuming Twin policy acted on the edge.

For a held control, send one SimulateIntent command with held: true or false and a stable nonzero producer_id, reusing that ID for later commands from the same API producer. An external command targeting fixed-simulation state returns a correlation id and next-tick admission stamp; verify the matching intent.hold event has the same producer, target, held value, and stamp. The held state changes at that fixed tick. Local-embodiment commands remain on the interaction cadence.

Live runtime HTML/CSS iteration

The native luncosim UI watches the retained runtime surfaces under assets/ui/. Edit a surface's .html or .css in place and inspect the same window; HUI rebuilds the affected template and Flair reapplies the stylesheet without a binary rebuild or relaunch. Editing runtime_surfaces.json rebuilds the registered surface roots and action bindings. Rust exposure producers and action observers still require a rebuilt production binary.

Use ReadExposures to verify the data side independently of the pixels:

bash
curl -s -X POST http://127.0.0.1:4101/api/commands \
  -H 'content-type: application/json' \
  -d '{"type":"ExecuteCommand","command":"ReadExposures","params":{"surface":"driven-vessel"}}' | jq .

The response's revision changes only when an exposed value or visibility flag changes. If it is stable, an unchanged runtime surface should not rebuild its view-model. Use CaptureScreenshot for the visual check. ReloadShader and RunScenario reload WGSL and Rhai respectively; neither reloads HTML/CSS.

Runtime UI is a small native HUI/Flair language, not a browser DOM. Do not expect JavaScript, forms, text inputs, full CSS, or host-font fallback. Read the runtime UI skill for the supported surface contract, placement/dock ownership, font rules, and performance gates.

Session lifecycle

Each agent doing runtime work owns a luncosim session on a distinct explicit free API port. Concurrent agent sessions are allowed on different ports. Launch from the same repository checkout and working directory as that agent's terminal, using that checkout's production binary. Before replacing your own session, send Exit and verify its process and port are gone; never control another agent's session or reuse an occupied port. Keep your current process for live shader/Rhai edits; restart only when a rebuilt binary or an explicit clean session is required.

Lifecycle (start → drive → stop)

bash
# 1. Resolve the production binary in this checkout, choose a free API port
#    owned by this agent, and start it from this checkout's working directory.
#    Keep it alive in the runner's background session.
"$LUNCOSIM_BIN" --api 4101

# 2. Wait for the readiness contract, not just an open socket:
until curl -s http://127.0.0.1:4101/api/ready 2>/dev/null \
  | jq -e '.data.ready == true and .data.world_hold == false and .data.pending_count == 0' >/dev/null; do
  sleep 1
done

# 3. Send commands (see catalog below).

# 4. Stop with Exit, NEVER pkill / kill (user has to confirm those):
curl -s -X POST http://127.0.0.1:4101/api/commands \
  -H "Content-Type: application/json" \
  -d '{"type":"ExecuteCommand","command":"Exit","params":{}}'

After Exit, verify that the process and :4101 listener are gone before starting another session. A queued command or a reachable socket is not proof that a scene is ready; /api/ready is the gate for scene load, Modelica compile and participant initialization. For scene replacements that change ActivePhysicsFrame, also query each new dynamic body with QueryPhysicsState and require physics_pose_seeded == true before declaring admission complete; this catches a physics clock blocked before the replacement scene's first pose is written.

Curl shape

Every typed command uses the tagged envelope {"type":"ExecuteCommand","command":"<Name>","params":{...}}. Include params even for parameterless commands. Built-in discovery and entity listing use their own explicit type values.

bash
curl -s -X POST http://127.0.0.1:4101/api/commands \
  -H "Content-Type: application/json" \
  -d '{"type":"ExecuteCommand","command":"OpenClass","params":{"qualified":"Modelica.Blocks.Continuous.PID"}}'

Successful fire-and-forget response: {"data":{"accepted":true}}. A result-returning typed command puts its command-specific payload in the same data envelope. Malformed envelopes are rejected at the transport boundary, and invalid typed parameters return HTTP 422. A deferred command may resolve its acknowledgement on the same request, but that is not necessarily completion of the domain work. RunExperiment returns its exact experiment_id once registered; the numerical solve remains asynchronous and is read through RunStatus and GetExperimentResult using that id. Rhai's in-process cmd may expose a pending command id; command_result(id) resolves that deferred command acknowledgement only. There is no generic HTTP command-id polling endpoint, and callers must not guess the run from its label or newest position.

Show full SKILL.md (1,312 more words)Show less
Loading a scene or model

Choose the command that owns the address type and check its result:

commandtakesnotes
OpenTwina folder containing twin.tomlauto-loads [usd] default_scene
LoadScenea root-qualified twin:// or lunco:// addressmounts a scene address; it is not a filesystem opener
OpenFilea filesystem path or supported URIextension-routes the document to its owning domain; USD paths resolve their Twin root

Passing the .usda file to OpenTwin fails the twin.toml check and is refused with a warn!.

LoadScene is not a general file opener. Bare and absolute filesystem paths are refused with

[scene] `…` is not a root-qualified scene address — LoadScene takes `lunco://…` or `twin://…`

The command returns a terminal rejection before admission; the currently mounted scene remains active. Read the command result and query the active scene before trusting a screenshot. Use OpenFile for a filesystem path; it resolves the workspace layer and preserves the document-first mounting contract.

CaptureScreenshot returns the PNG as the response body; write those bytes yourself rather than relying on save_to_file.

Validate an asset without loading it

ValidateAsset prepares fresh file facts without mounting a scene. Its initial query returns pending with an operation_id; poll the same query with only that ID. The consumed ready result contains report and actual source_revisions; failed contains a terminal diagnostic. Retired or consumed IDs reject. Do not resubmit the initial path while waiting.

bash
curl -s -X POST http://127.0.0.1:4101/api/commands \
  -H "Content-Type: application/json" \
  -d '{"type":"ExecuteCommand","command":"ValidateAsset","params":{"path":"lunco://models/LunCo/Electrical/Battery.mo"}}'

The native CLI uses the same validators without constructing an app:

bash
"$LUNCOSIM_BIN" --validate assets/models/LunCo/Electrical/Battery.mo

Full runbook — per-extension checks, exit codes, and the CWD path-resolution trap: validate-assets.

Validate a Twin namespace without loading a scene

ValidateTwin is the read-only Twin-wide counterpart. Pass an explicit local folder and use policy: "error" in CI when a resolver collision must fail:

bash
curl -s -X POST http://127.0.0.1:4101/api/commands \
  -H "Content-Type: application/json" \
  -d '{"type":"ExecuteCommand","command":"ValidateTwin","params":{"path":"/work/rover-twin","policy":"error"}}'

Poll the returned operation_id; ready.report contains indexed entries, resolver scopes, collisions, source-read errors, and namespace findings. For a mounted browser Twin pass its current twin://<assigned-authority> instead of a native folder. For the active Twin after OpenFolder/OpenTwin, use cmd("RunLint", #{scope: "twin", policy: "warn"}) and read query("GetDiagnostics", #{scope: "twin"}) for the returned lint revision. The queued Ack is admission information; the scope's pending/ready/failed state is the terminal report. Native and mounted browser Twin lint share the same async preparation. Unreadable or invalid sources fail the scope even with policy: "warn"; retirement or supersession discards the exact operation. Loaded-stage lint remains available on both platforms.

Command ownership

This skill owns the generic API envelope, runtime lifecycle, screenshots, and end-to-end evidence. For Modelica-specific loading, compile/run, experiment, and plot commands, use run-modelica; keep that catalog in one place.

Verification workflow

1. Start workbench (run_in_background:true).
2. Monitor until READY.
3. OpenFile or OpenClass to load model.
4. Wait ~3-5s for rumoca parse + projection (background tasks).
5. OpenClass or drill action if scoping to a sub-class.
6. Wait ~3-5s for the post-drill projection to land.
7. FitCanvas + sleep 1.
8. CaptureScreenshot → /tmp/foo.png.
9. Read the PNG to inspect.
10. Check the process log for lines like `[Projection] import done in Xms: N nodes M edges`.
11. Exit when done.

## Rover modeling loop: reload the live scene, then measure it

For a world-direction tracker, use the API to verify one complete coordinate
chain after reload: target vector in the mount frame, controller setpoint,
measured joint angle, and rendered boresight. Do not accept a controller's
internal `locked` state alone; it can be self-consistent with an incorrect axis
or boresight convention.

Keep one luncosim process running while iterating on a rover. Edit the USD, then
use `OpenFile` for a file-backed asset, `RestartScene` for the mounted scene, or
`ApplyUsdOp` for an in-place authored opinion. Reattach a diagnostic script with
`RunScenario`; this hot-reloads only that script. Read `ScriptInspect`,
`QueryEntity`, `rover_status`, and relevant ports while the simulation is live.

A rover test must report measured telemetry and movement, not merely compile or
compare two values at rest. Use `luncosim test` for deterministic CI verdicts,
but keep the live API check because it exercises the production reload and
command paths. Do not add a second reload command or a standalone rover test
binary.

For presentation work, establish the acceptance chain in order: builtin
raycast drive first (`DRIVETRAIN PARITY: PASS`), then the Modelica drive-law
overlay (`MODELICA DRIVE LAW: PASS`), then optional power/thermal/autonomy.
Never use a visual screenshot as a substitute for either verdict: a rover that
does not move, or one still driven by the builtin kernel after a failed Modelica
overlay, can look plausible in a parked frame.

Partial USD object/reference reload is intentionally not exposed yet. Until its
composition, connection, and Modelica-worker lifecycle are implemented as one
operation, use the full `RestartScene` reload for rover tests. A successful full
reload must re-run USD prim projection, cosim model creation/compilation, and
connection rewiring before the test verdict is trusted.

For a placed rover, also query the composed USD transform after reload. Check that every authored rotation op appears in xformOpOrder and that the effective heading comes from one placement layer. For a fixed solar panel, list the composed SolarPanel, Battery and rover-root network entities, then read the rover-root boundary ports. Presence of a panel mesh is not a power verdict: require positive solar_power/panel power_out, a valid incidence, and battery current or changing soc.

Production tutorial tests

Tutorial acceptance belongs to the production $LUNCOSIM_BIN binary. Build that binary in the worktree, run the scene-test command directly, and capture its exit code and authored verdict. --validate proves only USD parsing; a successful acknowledgement proves validation and dispatch, not that the simulation has finished its work. A live API check must also wait for /api/ready to report ready:true, world_hold:false, and pending_count:0.

Autopilot checks should observe the same AcquireControl and port-write events as a human control sequence, plus a real movement/port predicate and the final goal. Keep declared cosim topology separate from current samples: a connection may resolve before the first sample, but an absent value is not a valid zero. The complete boundary is in tutorial-autopilot-and-port-contracts.

For source-backed program authoring, query ListOpenDocuments for the USD document, dispatch AttachProgram, then verify ListPorts, CosimStatus, and GetBrokenConnections. The production Rhai gate is:

bash
"$LUNCOSIM_BIN" test \
  --scene scenes/tests/program_attach_command.usda --max-ticks 3000

It proves both a declared Modelica participant and the visible error status for an attached source with no port contract. Do not treat a prim appearing in the scene tree or a fire-and-forget command acknowledgement as a running model.

Diagnosing common failures

  • Non-Unicode native CLI arguments: the process rejects them with exit code 2 before startup. Use the storage-owned file URI conversion when a native filesystem address must cross a Unicode command boundary.
  • "0 nodes 0 edges" after drill-in: the target class resolved but conversion dropped nodes. Check:
    1. InspectActiveDoc → are the components really there in the AST? If not, parse failed.
    2. If components exist: their TYPES probably aren't in local_classes_by_short or the source-library palette. The diagram-builder registers the target's nested + sibling classes (sibling-pass in panels/canvas_projection.rs, the local_classes_by_short registration); connector types need to be in library_index.json (regenerate via cargo run -p lunco-modelica-assets --bin modelica_library_indexer).
  • "Command 'X' not found or not API-accessible": the Event isn't reflect-registered. Put a shared Modelica-facing payload in lunco-modelica-ui-core; keep its observer in the owning UI package, give its observer the #[on_command(X)] attribute, and list that observer in the register_commands!(...) block in crates/lunco-modelica-ui/src/ui/commands/mod.rs (see § Add a command).
  • API returns 500 / silent no-op: check params includes the empty object {} even for parameterless commands.
  • Projection deadline exceeded (60s): rumoca parse stall, usually from a synchronous library load inside the worker pool. Move heavy loads to a separate std::thread::spawn and use the cache-only source-aware resolver in the projection (peek_class_cached).
  • A rebuilt binary is not visible: replace the session through Exit, verify port 4101 is free, then start the rebuilt production binary.

Add a command

When testing reveals a missing API surface, add the command immediately rather than asking the user:

  1. Put a shared command payload in its domain's contract crate when another package must emit it (for example, Modelica-facing payloads in lunco-modelica-ui-core, or shared scene-edit payloads in lunco-scene-command-contracts). Define it with #[Command]. Keep the observer in the behavior-owning package and mark it with #[on_command(...)] (both attributes come from lunco_core). For the Modelica UI, the observer file is under crates/lunco-modelica-ui/src/ui/commands/:
    rust
    use lunco_core::{Command, on_command};
    
    #[Command(default)]              // or `#[Command]` if you impl Default
    pub struct MyCommand { pub foo: String }
    
    #[on_command(MyCommand)]
    pub fn on_my_command(trigger: On<MyCommand>, mut commands: Commands) {
        let foo = trigger.event().foo.clone();
        commands.queue(move |world: &mut World| { /* ... */ });
    }
    #[Command] emits the Event/Reflect/reflect(Event) derives and #[on_command] generates the register_type + add_observer wiring — you don't write them by hand.
  2. Add the observer fn to the register_commands!(...) list in crates/lunco-modelica-ui/src/ui/commands/mod.rs (use the module::fn path form, e.g. inspect::on_my_command).
  3. Build, restart workbench, curl it.

What NOT to do

  • Don't pkill -f lunica. The user has to confirm; use Exit command.
  • Don't write standalone test binaries / temp .rs files to verify rumoca behaviour. Add an Inspect* command if the workbench can't already surface what you need.
  • Don't chain sleep 30 && tail .... Use Monitor with an until loop.
  • Don't ask the user to take a screenshot or check anything visually unless API verification is genuinely impossible.
Native mouse look

InjectWindowInput distinguishes absolute PointerMove { x, y } from raw relative MouseMotion { delta_x, delta_y }. Cursor coordinates drive picking and egui; raw motion drives the native camera input map. For mouse look, hold the configured input_binding("look_button"), emit raw motion, and release the button. Cursor positioning alone does not rotate a camera. The bridge emits both the native WindowEvent::MouseMotion and typed Bevy MouseMotion message.

For path interoperability, run the production twin_search_paths scene gate: it exercises layer/Twin search precedence and imports, tool discovery, and timeline discovery with literal #, %, and spaces in filenames. Distinguish Linux runtime evidence from Windows-native CI tests. Root resolution and application builders are fallible; an invalid LUNCO_ASSET_ROOT must exit with a diagnostic rather than panic or silently discover another library.

python scripts/api/test_path_interoperability.py uses an owned windowed production session on LUNCOSIM_API_PORT (default 4193) and a fresh temporary Twin below target/. Its Rhai observer verifies Modelica documents through literal filenames, canonical-root and case-only renames, rejected existing or nonportable targets, and save/readback at the renamed path. It authors a USD document through typed document operations, saves it with a literal filename, and admits it through the Twin's default scene to verify its Modelica source equation and loaded canonical stage. API Exit must release both the process and port.

© 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

Files

Just SKILL.md in skills/test-via-api of LunCoSim/lunco-sim.

Open the folder on GitHubat commit d1c6f00

Compare with similar skills

Test Via API 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.

Test Via API compared with similar skills
SkillStarsUsed inTokensAuto-checkLicenceRepo updated
Test Via API this skillLunCoSim/lunco-sim105—~7.8kAutomated safety check: PassApache-2.0
Viewer Smokeiopsystems/rezolus275—~849Automated safety check: PassCustom licence
Fleet SupervisorApra-Labs/apra-fleet101—~3.6kAutomated safety check: PassCustom licence
QA Metricspetrkindlmann/qa-skills165—~5.3kAutomated safety check: PassMIT
Use Yaakmountain-loop/yaak19k—~1.9kAutomated safety check: PassMIT
Testing Mwaa Workflowaws/agent-toolkit-for-aws2.8k—~3.8kAutomated safety check: PassApache-2.0

Similar skills

  • Viewer Smoke

    iopsystems/rezolus

    Run the end-to-end viewer smoke test (tests/viewersmoke.sh).

    275 GitHub stars~849 tokensUpdated yesterday
    Testing & QAAuto-check passed
  • Fleet Supervisor

    Apra-Labs/apra-fleet

    How to start/smoke-test the supervisor process itself, and start, check, and kill fleet-sprints via its HTTP API only (POST /api/sprints on localhost:8787).

    101 GitHub stars~3.6k tokensUpdated yesterday
    Testing & QAAuto-check passed
  • QA Metrics

    petrkindlmann/qa-skills

    Define, track, and act on QA metrics: test coverage percentage, flakiness rate, defect escape rate, MTTR, test execution time trends, automation ROI, quality gates, and SLAs for test suites.

    165 GitHub stars~5.3k tokensUpdated 4 mo ago
    Testing & QAAuto-check passed
  • Use Yaak

    mountain-loop/yaak

    A skill your agent uses when the user mentions Yaak, a Yaak workspace, or the yaak command, or asks to call, hit, or smoke test HTTP/REST endpoints, save or organize API requests for reuse or manual…

    19k GitHub stars~1.9k tokensUpdated 2 days ago
    Backend & APIsAuto-check passed
  • Testing Mwaa Workflow

    aws/agent-toolkit-for-aws

    Official

    Tests Amazon MWAA workflow execution end-to-end: trigger a run and monitor it to completion for Provisioned (Python DAG, via Airflow REST API) and Serverless (YAML workflow, via StartWorkflowRun).

    2.8k GitHub stars~3.8k tokensUpdated yesterday
    Backend & APIsAuto-check passed
  • Linecanary Monitor

    CALLE-AI/awesome-phone-call-agents

    Monitor business phone lines and deployed voice agents with LineCanary — scheduled CALL-E test calls that walk the caller journey, assert structured results, diff against baselines and alert on…

    106 GitHub stars~1.2k tokensUpdated yesterday
    Testing & QAAuto-check passed

More from LunCoSim/lunco-sim

All 38 skills in this repo
  • Nightly Changelog

    LunCoSim/lunco-sim

    Generate concise LunCoSim nightly GitHub release notes with platform downloads, installation guidance, an AI-agent mission prompt, and a changelog link.

    105 GitHub stars~1.1k tokensUpdated yesterday
    Auto-check passed
  • Build or repair a reusable scene component through a live LunCoSim Editor session.

    105 GitHub stars~4.4k tokensUpdated yesterday
    Auto-check passed
  • Assembly Quality

    LunCoSim/lunco-sim

    Build or review a componentized LunCoSim USD assembly with a realistic, dimensionally checkable presentation.

    105 GitHub stars~1.6k tokensUpdated yesterday
    Auto-check passed
  • Author Rhai Tests

    LunCoSim/lunco-sim

    Author and review LunCoSim behavioral, asset-backed, component, mission, visual, and requirements-verification tests.

    105 GitHub stars~3.5k tokensUpdated yesterday
    Auto-check passed
  • Author Rhai Tool

    LunCoSim/lunco-sim

    Create, extend, register, or debug a reusable LunCoSim Rhai tool library for live USD authoring, component linting, inspection, or test support.

    105 GitHub stars~5.2k tokensUpdated yesterday
    Auto-check passed
  • Author Tutorial

    LunCoSim/lunco-sim

    Author an interactive tutorial, guided lesson, onboarding flow, coach-mark tour, or objectives checklist in LunCoSim.

    105 GitHub stars~1.4k tokensUpdated yesterday
    Auto-check passed

Questions about Test Via API

What does Test Via API do?

How to verify luncosim changes end-to-end without asking the user to click. Test Via API is an agent skill from LunCoSim/lunco-sim. How to verify luncosim changes end-to-end without asking the user to click.

When should I use Test Via API?

Test Via API fits situations like: ever a UI flow needs verification — a new diagram; A fix to drill-in; A screenshot to confirm a regression; A smoke test of any reflect-registered Event command.

How do I install Test Via API in Claude Code?

Run `npx skills add LunCoSim/lunco-sim --skill test-via-api -a claude-code`. Or copy the skill folder (skills/test-via-api in LunCoSim/lunco-sim) into .claude/skills/test-via-api in your project. Claude Code loads it when a task matches its description.

How do I install Test Via API in Codex?

Run `npx skills add LunCoSim/lunco-sim --skill test-via-api -a codex`. Or copy the skill folder (skills/test-via-api in LunCoSim/lunco-sim) into .agents/skills/test-via-api in your project. Codex loads it when a task matches its description.

Can I use Test Via API in Cursor, Gemini CLI or GitHub Copilot?

Cursor, Gemini CLI, GitHub Copilot and OpenCode also load SKILL.md folders. With the skills CLI, run `npx skills add LunCoSim/lunco-sim --skill test-via-api -a cursor` (or -a gemini-cli, github-copilot or opencode for the others). To copy it by hand, put the folder in .cursor/skills/test-via-api, .gemini/skills/test-via-api, .github/skills/test-via-api and .opencode/skills/test-via-api in your project.

What does Test Via API need to run?

Going by SKILL.md and its folder, Test Via API needs the command-line tools its instructions call (curl, jq, python and cargo). Our summary lists: Python 3.

Does Test Via API access the network?

SKILL.md contains no URLs. Its commands use curl, which can reach the network depending on how they are called. This is read from the text; nothing was executed.

Is Test Via API safe to install?

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.

What licence does Test Via API use?

Test Via API 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.

How many tokens does Test Via API use?

About 7.8k tokens (SKILL.md is roughly 31k characters). Agents keep only the skill's name and description in context until a task matches; then they load SKILL.md in full.

What are the alternatives to Test Via API?

Skills that share tags, products or a category with Test Via API: Viewer Smoke (iopsystems/rezolus, 275 stars), Fleet Supervisor (Apra-Labs/apra-fleet, 101 stars), QA Metrics (petrkindlmann/qa-skills, 165 stars) and Use Yaak (mountain-loop/yaak, 19k stars). The comparison table on this page puts their stars, adoption, token cost, safety result and licence side by side.

Who maintains Test Via API?

LunCoSim (a GitHub organization) maintains it in LunCoSim/lunco-sim, which has 105 GitHub stars. The repository holds 38 skills in this directory. The repository was last updated on October 7, 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.