Port to Your Robot

Thea keeps robot-specific SDKs, policies, and sensing backends outside the Harness package. A deployment connects those capabilities through public protocols and returns one Harness from an importable factory.

Start from examples/port-template/. Copy the directory to an importable package such as my_robot, then replace its explicit adapter boundaries.

The three deployment files

File

Responsibility

my_robot/profile.md

Record stable properties of the active embodiment.

my_robot/tools.py

Register navigation and manipulation tools through ToolRegistry.

my_robot/factory.py

Connect resources and compose the public Harness dependencies.

1. Describe the embodiment

The Embodiment Profile has three validated sections:

Section

Required items

Operational Envelope

Base Footprint, Base Mobility, Reachable Workspace

Perception Configuration

Sensor Modalities, Model-Visible Views

Base-Relative Positions

Camera Positions, Initial Gripper Positions

Select the copied file in config.yaml:

embodiment_profile_file: my_robot/profile.md

The profile contains stable body-specific context. Current robot pose, clearance, images, and task state belong to Refreshed context instead.

2. Register physical tools

Register each capability with a precise name, description, input schema, and post-condition when the tool requires Evaluation as Exit Codes:

registry.register(
    BuiltinTool(
        name="pick_object",
        description="Pick one confirmed object ref using current evidence.",
        input_schema=pick_schema,
        fn=robot.pick_object,
        post_condition="The requested object is secured by the robot.",
    )
)

An in-process SDK adapter may use BuiltinTool. A separately deployed policy server may expose the same tool definition through MCPTool. The model sees the same protocol in either case.

3. Compose the factory

The Lark runtime calls the factory once per channel session with the validated configuration and a ChannelSessionContext. The factory must return one Harness:

def create_harness(config, session_context):
    robot = connect_robot()
    registry = ToolRegistry()
    register_robot_tools(registry, robot)

    scene_graph = build_scene_graph(robot)
    register_scene_graph_query_tools(registry, scene_graph)

    return Harness(
        config,
        model=build_model(config),
        observation_provider=build_observation_provider(robot),
        base_clearance_provider=build_base_clearance_provider(robot),
        registry=registry,
        scene_graph=scene_graph,
        evaluator=build_evaluator(config),
        post_execution_observation_provider=build_evidence_provider(robot),
        owned_resources=(robot,),
    )

owned_resources are closed with the Harness session. Keep shared process-wide resources outside this tuple and manage their lifetime in the deployment.

Launch the deployment

The factory path uses module:callable syntax. The root robot mode is a Feishu/Lark-hosted deployment, so configure the channel credentials before launching it:

./run.sh --mode robot \
  --harness-factory my_robot.factory:create_harness

Use --check first to validate imports and configuration without constructing robot resources:

./run.sh --mode robot --check \
  --harness-factory my_robot.factory:create_harness

An application that does not use Lark should compose the same dependencies in its own process, construct Harness, and call run_stream() directly instead of using --mode robot.

Connect boundaries incrementally

Use the Deployment Guide to replace one boundary at a time. A practical order is model, one read-only tool, Observation, Scene Graph, physical tools, post-execution evidence, evaluator, Memory and Skills, then the user channel.

The Harness safety checks are orchestration safeguards, not a certified safety system. Emergency stops, actuator limits, collision avoidance, and low-level motion control must remain independent of the model.