add-new-modality

Implements new ResoniteIO modalities across proto, C# Core, C# Mod, Python client, CLI, and tests.

3|Updated Jun 7, 2026
One-click install
npx skills add https://github.com/MLShukai/ResoniteIO --skill add-new-modality-mlshukai
Or copy as Structured Prompt for Agent
Please help me install this Agent Skill.
Skill: add-new-modality
Source: https://github.com/MLShukai/ResoniteIO/tree/main/.agents/skills/add-new-modality
Command: npx skills add https://github.com/MLShukai/ResoniteIO --skill add-new-modality-mlshukai

SYSTEM DOCUMENTATION & REQUIREMENTS

What problem does it solve? Adding a new modality to the ResoniteIO bridge requires coordinated changes across six mirrored layers (proto, C# Core Service and Bridge interface, C# Mod FrooxEngine bridge, Python client, CLI, and tests), and missing any convention causes build failures, CS0436 duplicate-type errors, or gRPC cancel exceptions. ## Core Features & Use Cases - Mirroring conventions: Enforces the modality-unit directory and naming layout across proto, C# Core/Mod, Python, CLI, and test trees. - Layered implementation rules: Codifies Core/Mod separation, Bridge interfaces returning Core POCOs, engine-thread dispatch via World.RunSynchronously, and three-stage gRPC cancel exception handling. - Incremental 9-step workflow: Guides proto-first generation with just gen-proto, Kestrel round-trip Core tests, in-process Python gRPC tests, SafeShutdown chain registration, and docs updates. - Use Case: When adding a Grabber-style modality, follow the skill to create IGrabberBridge, GrabberService, FrooxEngineGrabberBridge, the Python GrabberClient, a flat CLI command, and matching tests without breaking the build. ## Quick Start Add a new modality called Tracking to resonite-io following the add-new-modality conventions, starting from the proto definition through the Python client and tests.

Frequently Asked Questions about add-new-modality

High-intent search queries and answers about installing and using this skill.

FAQPage Schema
How do I add a new modality to ResoniteIO?

Follow the incremental workflow: write the proto first and run just gen-proto, implement I<Modality>Bridge and <Modality>Service in C# Core, add Kestrel round-trip tests, build the Python client, implement the FrooxEngine bridge in the Mod layer, register it in the SafeShutdown chain, and add the CLI command.

What is the Core and Mod layering in a Resonite BepInEx mod?

Core contains gRPC services and bridge interfaces with no engine dependency, while Mod contains FrooxEngine bridge implementations and the plugin. Dependencies flow Core ← Mod only, and the gRPC server runs on a separate thread so it never blocks the FrooxEngine main thread.

Why does my gRPC streaming server throw IOException on client cancel?

With Grpc.AspNetCore over Kestrel UDS, client cancellation can surface as IOException instead of OperationCanceledException. Catch both with a when (ct.IsCancellationRequested) filter so expected cancellations are absorbed without error logs.

Why do I get CS0436 duplicate type warnings after generating proto files?

The Core test project generates client stubs that duplicate the server-side generated types. Add <NoWarn>$(NoWarn);CS0436</NoWarn> only to the test csproj, and keep proto generation centralized in the Core project referenced by the Mod project.

Can the bridge interface return proto message types directly?

No. Bridge interfaces must return Core POCO types, with the Service mapping them to proto via MapToProto. Returning proto types causes CS0738 failures when fake bridges implement the interface for testing.

How should Python client-streaming modalities be structured?

Follow the Locomotion and Microphone pattern: expose an async context manager whose session accepts send() calls, and retrieve the result summary after the context exits. Keep internal attributes private with underscore prefixes and export public API via __all__.