Lucky Robots Blog Open Roles

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.

Engine impls: Hazel/src/Hazel/Net/ Proto defs: luckyrobots/grpc/proto/ Threading: gRPC pool, not main loop Doc source: Architecture-LuckyEngine.md § Part 6
Python clients Engine: gRPC services Engine internals LuckyRobots SDK Session, gRPC stubs LuckyLab (retired) RL/IL framework gRPC channel AgentService MujocoService / MujocoSceneService SceneService TelemetryService CameraService ViewportService DebugService MujocoSceneInstance mj_step / qpos / ctrl Scene / ECS entities, components, mode Observer / Recorders qpos, ctrl per step SceneRenderer capture, final-pass image dashed edges marshal via GrpcStepSystem / GrpcCapturePool
Python clients (LuckyRobots SDK; LuckyLab historical) cross a gRPC channel to the engine's service implementations, which fan out to MuJoCo, Scene/ECS, Observer, and SceneRenderer. Handler-to-internal arrows are deferred onto the engine's main loop at safe TimeManager checkpoints.

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 / RPCEngine handler maps to
AgentService.StepMujocoSceneInstance::SimulatePhysics (steps MuJoCo, returns observation)
AgentService.ResetAgentMujocoSceneInstance::Reset + SimulationContract DR application
AgentService.GetAgentSchemaRobotAgent buffer metadata (observation / action names + sizes)
MujocoService.GetJointStateMujocoSceneInstance::GetData()qpos / qvel
MujocoService.SendControlMujocoSceneInstance::ApplyJointStates (writes mjData->ctrl)
MujocoSceneService.GetModelInfoMujocoSceneComponent joint + actuator descriptors; reports nbody/nsite/ngeom
MujocoSceneService.GetFullState / StreamFullStatemjData->qpos / qvel / ctrl (optional joint / actuator filter)
MujocoSceneService.SetControl / SetQpos / SetActuatorGains / SetQfrcAppliedDirect mjData->ctrl / qpos / actuator_*prm / qfrc_applied writes; gated against PolicySlot + RL-agent ownership
MujocoSceneService.ListBodies / ListSites / ListGeomsmjModel enumeration (name, parent, mass, free-joint qpos_adr, type / group / size); pose optional via include_pose
MujocoSceneService.GetBodyPose / GetSitePose / GetGeomPosemjData->xpos / xquat, site_xpos / xmat, geom_xpos / xmat lookup by name or index
MujocoSceneService.StreamBodyPosesPer-frame BodyDescriptor + pose stream; optional name / index filter
MujocoSceneService.ResetSceneMujocoSceneInstance::ResetToInitialState (qpos → keyframe, vel / ctrl zero, PD reseed)
SceneService.SetSimulationModeScene::SetSimulationMode (TimeManager mode)
DebugService.DrawDebugRenderer
TelemetryService.StreamTelemetryData::Observer (qpos / ctrl per step)
CameraService.StreamCameraSceneRenderer capture
ViewportService.StreamViewportSceneRenderer::GetFinalPassImage

gRPC threading

Handlers run on gRPC's pool, not the engine main loop

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 fieldEngine effect
friction_range, restitution_rangeMujocoSceneInstance geom material randomization
mass_scale_range, com_offset_rangeBody inertia randomization
motor_strength_range, motor_offset_rangeActuator gain / bias perturbation
push_interval_range, push_velocity_rangeExternal disturbance scheduler
vel_command_x / y / yaw_rangeCommand sampling in the observation vector
terrain_type, terrain_difficultyTerrain 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:

Engine C++ Wire (proto) Python MujocoSceneInstance qpos, qvel, sensors RobotAgent ObservationBuffer AgentFrame observations[] (proto) luckyrobots ObservationResponse luckylab EntityData / OM term MujocoSceneInstance → RobotAgent.ObservationBuffer → AgentFrame.observations[] → ObservationResponse → EntityData → ObservationManager term
Observation vector flow from MuJoCo state to Python-side observation manager terms.

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.

ChangeLuckyEngineLuckyRobotsLuckyLab
New gRPC service / RPCServer impl in Hazel/src/Hazel/Net/Proto + stubs + client methodsIf used by env
New observation fieldAgent observation assemblySchema namingObservationSchema + EntityData
New actuator typeMujocoActuatorrobots.yaml action spaceActionTerm subclass
New component typeComponents.h + serialization
New SimulationContract fieldDR handlersim_contract.py builderCurriculumManager term
New robot configScene + MJCFrobots.yaml entryTask config
Note on LuckyLab

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.

  • Threading — the GrpcStepSystem / GrpcCapturePool marshalling rules in full.
  • Data / Observation — the engine-side schema and observer that backs TelemetryService.
  • Physics (MuJoCo) — what MujocoSceneInstance exposes, in detail.
  • .claude/docs/Architecture-LuckyEngine.md § Part 6 — canonical source.
  • .claude/docs/Architecture-LuckyRobots.md — Python SDK side.