XS · gRPC / Cross-System Integration
LuckyEngine is the C++ physics simulation backend for Python-side clients. gRPC is the wire boundary: every observation, action, reset, and stream crosses it. This page indexes the services, the threading contract on the engine side, and the change-where matrix for cross-system features.
gRPC service boundary
Engine-side gRPC implementations live under Hazel/src/Hazel/Net/. Proto definitions are sourced from luckyrobots/grpc/proto/. The table below maps each RPC to the engine handler that fulfils it.
| Proto service / RPC | Engine handler maps to |
|---|---|
AgentService.Step | MujocoSceneInstance::SimulatePhysics (steps MuJoCo, returns observation) |
AgentService.ResetAgent | MujocoSceneInstance::Reset + SimulationContract DR application |
AgentService.GetAgentSchema | RobotAgent buffer metadata (observation / action names + sizes) |
MujocoService.GetJointState | MujocoSceneInstance::GetData() → qpos / qvel |
MujocoService.SendControl | MujocoSceneInstance::ApplyJointStates (writes mjData->ctrl) |
MujocoSceneService.GetModelInfo | MujocoSceneComponent joint + actuator descriptors; reports nbody/nsite/ngeom |
MujocoSceneService.GetFullState / StreamFullState | mjData->qpos / qvel / ctrl (optional joint / actuator filter) |
MujocoSceneService.SetControl / SetQpos / SetActuatorGains / SetQfrcApplied | Direct mjData->ctrl / qpos / actuator_*prm / qfrc_applied writes; gated against PolicySlot + RL-agent ownership |
MujocoSceneService.ListBodies / ListSites / ListGeoms | mjModel enumeration (name, parent, mass, free-joint qpos_adr, type / group / size); pose optional via include_pose |
MujocoSceneService.GetBodyPose / GetSitePose / GetGeomPose | mjData->xpos / xquat, site_xpos / xmat, geom_xpos / xmat lookup by name or index |
MujocoSceneService.StreamBodyPoses | Per-frame BodyDescriptor + pose stream; optional name / index filter |
MujocoSceneService.ResetScene | MujocoSceneInstance::ResetToInitialState (qpos → keyframe, vel / ctrl zero, PD reseed) |
SceneService.SetSimulationMode | Scene::SetSimulationMode (TimeManager mode) |
DebugService.Draw | DebugRenderer |
TelemetryService.StreamTelemetry | Data::Observer (qpos / ctrl per step) |
CameraService.StreamCamera | SceneRenderer capture |
ViewportService.StreamViewport | SceneRenderer::GetFinalPassImage |
gRPC threading
RPC handlers must not directly mutate Scene / EditorAssetManager or call MuJoCo APIs that assume a single owning thread. Marshal the work to a safe checkpoint via GrpcStepSystem / GrpcCapturePool; the engine drains marshalled work during the Acquisition or Validation TimeManager phase. Read from the per-tick capture / snapshot the engine produces — never block a handler waiting for a future tick. See Threading § gRPC.
SimulationContract (Domain Randomization)
SimulationContract (in agent.proto) was sent by LuckyLab's CurriculumManager on each reset. The mapping below remains the engine-side contract for any client that produces the same proto.
| Contract field | Engine effect |
|---|---|
friction_range, restitution_range | MujocoSceneInstance geom material randomization |
mass_scale_range, com_offset_range | Body inertia randomization |
motor_strength_range, motor_offset_range | Actuator gain / bias perturbation |
push_interval_range, push_velocity_range | External disturbance scheduler |
vel_command_x / y / yaw_range | Command sampling in the observation vector |
terrain_type, terrain_difficulty | Terrain generation (when implemented) |
Observation vector flow
Observations originate in MuJoCo and flow through several layers before becoming a typed term inside the Python framework. The full pipeline:
Change-where matrix
Use this to scope a cross-system change before opening the file. Each row lists what has to change in each repo. Rows that mention LuckyLab are kept for historical reference — see the callout below.
| Change | LuckyEngine | LuckyRobots | LuckyLab |
|---|---|---|---|
| New gRPC service / RPC | Server impl in Hazel/src/Hazel/Net/ | Proto + stubs + client methods | If used by env |
| New observation field | Agent observation assembly | Schema naming | ObservationSchema + EntityData |
| New actuator type | MujocoActuator | robots.yaml action space | ActionTerm subclass |
| New component type | Components.h + serialization | — | — |
New SimulationContract field | DR handler | sim_contract.py builder | CurriculumManager term |
| New robot config | Scene + MJCF | robots.yaml entry | Task config |
LuckyLab (the historical RL / IL framework, with CurriculumManager, ObservationManager, EntityData) is no longer part of the active system. The rows referencing it are preserved because the engine-side proto surface still accepts the same shapes — any new client (including a successor framework) plugs into the same contract. Treat LuckyLab-specific class names as a historical reference, not a live integration point. See CLAUDE.md.
Related docs
- Threading — the
GrpcStepSystem/GrpcCapturePoolmarshalling rules in full. - Data / Observation — the engine-side schema and observer that backs
TelemetryService. - Physics (MuJoCo) — what
MujocoSceneInstanceexposes, in detail. .claude/docs/Architecture-LuckyEngine.md§ Part 6 — canonical source..claude/docs/Architecture-LuckyRobots.md— Python SDK side.