Embodied Task Program#
Embodied Task Program is a declarative orchestration and execution DSL for embodied tasks. It accepts bounded source programs, validates them against provider-free scene and robot contracts, compiles Semantic Calls, and lowers those calls to executable Atomic Skills through an explicit integration.
Semantic Calls are the language’s internal high-level instructions. They are not a separate product, package entry point, or independently executable API.
Human / MLLM / Agent
|
v
JSON/YAML/Python TaskProgramCfg
|
v
language -> decode / validate -> compiler
|
v
Semantic Calls -> semantic lowering -> Atomic Skills
|
v
simulation / robot -> Gym lifecycle / recording
Ownership boundaries#
The public API is split deliberately:
Package |
Owns |
Does not own |
|---|---|---|
|
Schema/AST values, strict decoding, validation, and loading |
Live providers or execution |
|
Semantic Calls plus scene, robot-profile, effect, and evidence contracts |
An independent action API |
|
AST compilation and Semantic Call lowering |
Gym stepping or simulator ownership |
|
Semantic Call execution state and parallel scheduling |
Episode lifecycle or recording |
|
Immutable registrations and explicit environment/simulation assembly |
Core language rules |
|
|
Compiler, catalog, or simulation assembly |
|
Executable Atomic Skills, planning, commands, recovery, and verification requests |
Task-language sequencing |
The stable language API is re-exported from embodichain.lab.task_program.
Provider-specific applications import task_program.integrations; Gym bridge
types are intentionally kept under gym.envs.task_program.
Semantic layer#
The semantics subpackage is internal to Task Program but its typed contracts are public for integration authors:
Contract family |
Main types |
Responsibility |
|---|---|---|
Semantic Calls |
Immutable object-centric task intent. |
|
Scene semantics |
Canonical identity, topology, affordances, and provider-free snapshots. |
|
Robot semantics |
Embodiment resources, Atomic Skill bindings, policies, and effect assurance. |
|
Effects and evidence |
|
Typed postconditions and measured-evidence routing. |
The built-in call catalog contains Pick, Place, and HandOver. Extensions
use a declarative RegisteredSemanticCall; the trusted integration, never the
program payload, owns the corresponding lowerer. See Scene registry and
Robot skill profiles for the two main integration contracts.
Program schema#
An in-memory TaskProgramCfg contains one program_id, an exact trusted
TaskProgramIntegrationCfg selection, optional named targets, and one
bounded program tree. A program authored for a componentized deployment omits
the integration selection from its serialized YAML. The deployment injects
the selected scene-registry, robot-profile, and policy-preset IDs before strict
decoding, which keeps the source program portable across compatible
embodiments.
Supported program nodes are SequenceCfg, RepeatCfg,
SegmentCfg, InvokeCfg, and ParallelCfg. A
BarrierCfg belongs to its enclosing parallel node. Built-in call
configs are PickCfg, PlaceCfg, and HandOverCfg;
RegisteredSemanticCallCfg is the allowlisted extension form.
Example:
program_id: repeated_cube_pick_place
targets:
drop_pose:
kind: cyclic_pose
values:
- position: [-0.40, 0.48, 0.10]
quaternion_wxyz: [1.0, 0.0, 0.0, 0.0]
- position: [-0.42, -0.08, 0.10]
quaternion_wxyz: [1.0, 0.0, 0.0, 0.0]
program:
kind: repeat
count: 3
body:
kind: segment
name: move_cube
steps:
kind: sequence
items:
- kind: invoke
call:
kind: pick
object: cube
- kind: invoke
call:
kind: place
object: cube
at: {kind: target_ref, target: drop_pose}
Serialized input is strict: unknown fields, duplicate keys, non-finite values,
invalid discriminators, excessive depth or expansion, executable values, and
unresolved references fail before live providers are touched. External formats
do not carry a schema_version field.
Load and compile#
Use the provider-independent package for both file and programmatic input:
from embodichain.lab.task_program import (
TaskProgramIntegrationCfg,
TaskProgramCompiler,
load_task_program,
)
program = load_task_program(
"task_program/program.yaml",
integration=TaskProgramIntegrationCfg(
robot_profile="ur5_dh_pgi_140_80",
scene_registry="task_program_repeated_pick_place",
runtime_preset="trajectory",
),
)
compiled = TaskProgramCompiler(scene_manifest).compile(program)
Compilation observes no live simulator state. It resolves canonical scene
references, expands bounded repeats and cyclic targets, assigns stable segment
and call indices, preserves parallel branches, and returns an immutable
CompiledTaskProgram.
The compiler does not generate controller actions. Live grounding and atomic planning begin only after an environment adapter has verified that the registration still matches the compiled scene/profile/catalog snapshots.
Configure a simulation environment#
Configuration-defined Task Programs separate the reusable physical environment from the runnable task deployment:
repeated_pick_place/
├── env.yaml
├── task.franka.yaml
├── task.ur5.yaml
└── task_program/
├── integration.yaml
└── program.yaml
env.yaml owns the physical scene and ordinary environment values. It has an
environment_id for component identity but deliberately has no runnable id,
robot, sensor, or Task Program selection:
environment_id: repeated_pick_place
max_episode_steps: 1200
simulation:
rigid_object:
- uid: cube
# Physical shape, dynamics, and initial pose.
env:
sim_steps_per_control: 4
events: {}
dataset: {}
A runnable task.<embodiment>.yaml selects the environment, all three Task
Program components, and one reusable embodiment:
id: TaskProgramRepeatedPickPlace-v1
environment:
component: env.yaml
task_program:
program: task_program/program.yaml
integration: task_program/integration.yaml
execution_policy: ../../../components/execution_policies/trajectory_open_loop.yaml
embodiment:
component: ../../../components/embodiments/ur5_dh_pgi_140_80.yaml
The callable-free integration.yaml owns the semantic scene binding and
task-specific profile additions. Its canonical identities map explicitly to
UIDs in the physical environment:
integration_id: repeated_pick_place_v1
program_id: repeated_cube_pick_place
requires:
scene_contract: repeated_pick_place_scene_v1
embodiment_contract: single_arm_parallel_gripper
scene_binding:
contract_id: repeated_pick_place_scene_v1
registry_id: task_program_repeated_pick_place
rigid_objects:
- entity_id: cube
simulation_uid: cube
dynamics: dynamic
semantic_type: cube
affordances:
- entity_id: cube_grasp
kind: antipodal_grasp
profile:
defaults: {}
action_options: {}
effect_monitors: {}
The abbreviated profile mappings above must be populated for the calls used by
the program. See env.yaml, task.ur5.yaml, and
task_program/integration.yaml under
embodichain_tasks/configs/tasks/manipulation/repeated_pick_place/ for the
complete reference composition.
Scene affordances are authored as children of their owning entry in
rigid_objects, articulations, or links. The parent’s entity_id names the
physical scene entity; the child’s entity_id is a separate, globally unique
semantic feature that can be selected explicitly by a program or parent
default. Nesting is the only way to declare ownership: scene-level
antipodal_grasps, support_surfaces, and containers, and child
object_id/parent_id fields, are rejected. The loader derives that parent
relation from the YAML structure and normalizes the declarations into the flat,
globally indexed Scene Registry.
The task integration accepts only closed scene bindings, profile additions,
monitor mappings, and allowlisted runtime-service kinds. Robot resources come
from the embodiment component, while motion and runner policy come from the
execution-policy component. Their composed integration does not accept dotted
imports or arbitrary callables. The configured integration loader lives in
task_program/integrations/configured.py; Gym registration remains the small
concern of gym/envs/task_program/registration.py.
config_to_cfg() resolves every component reference relative to the runnable
deployment, expands the physical environment and embodiment, validates each
semantic simulation_uid against the physical scene, composes the immutable
integration catalog, validates the program, and registers the common
EmbodiedEnv under the deployment-owned ID. A task-specific Python environment
module is not required. The pure env.yaml can also be selected by a
handwritten task because it contains no Task Program fields.
Run a selected program with:
embodichain run-env \
--gym_config path/to/task.ur5.yaml \
--task-program path/to/program.yaml
The CLI override changes the program only. It cannot replace the integration, execution policy, environment, or embodiment selected by the runnable task deployment.
Runtime lifecycle#
The environment adapter compiles or accepts a trusted CompiledTaskProgram,
assembles fresh live providers, and creates one TaskProgramDemoBridge.
EmbodiedEnv.create_demo_segments() exposes lazy actions; the bridge never
calls env.step() itself. The normal demo executor owns the step handshake,
recording, rewards, and reset lifecycle.
compile program
-> provider-aware preflight
-> prepare next semantic call from fresh observation
-> lower to ActionInvocation
-> AtomicActionEngine + ExecutionRunner
-> verify or project the declared effect
-> post-policies
-> segment validators
-> publish final completion mask
Keep three acceptance boundaries separate:
Boundary |
Meaning |
|---|---|
Semantic effect monitor |
Establishes whether one physical call achieved its postcondition and participates in recovery. |
Segment post-policy |
Advances environment behavior after motion, for example waiting for an object to settle. |
Segment validator |
Determines whether the resulting task or dataset segment is acceptable. |
Effect assurance is mandatory#
Every selected robot policy preset explicitly chooses
effect_assurance: verified or effect_assurance: projected.
verifiedadvances semantic state only from typed measured evidence. Curated Pick, Place, and HandOver calls require an explicit monitor mapping.projectedadvances the action plan’s expected symbolic state after command completion and forbids monitor mappings. It is suitable for trajectory-only demonstrations, not proof of physical success.
No monitor set is installed implicitly. A missing assurance field is a decode error, and a verified curated call without a monitor fails static compilation.
Held-object guards and phase-effect gates remain observational. They may block a named atomic segment or invalidate an action-authorized symbolic relation; they never attach objects, freeze bodies, or overwrite poses.
Parallel programs#
Parallel blocks require:
disjoint resource claims and runtime targets;
aligned command frames on the environment control grid;
conflict-free symbolic writes;
an authoritative
ParallelCommandSafetyValidator; andan explicit fail-fast barrier.
Resource disjointness alone is not physical-safety evidence. Missing or inconclusive safety validation fails closed. Nested parallel blocks are rejected.
Registered calls#
RegisteredSemanticCallCfg carries only declarative data. The immutable
simulation registration must declare exactly one matching lowerer factory and
include that declaration in its integration fingerprint. Each live assembly
receives a fresh lowerer instance and revalidates its call ID, revision, and
target descriptor.
Use registered calls to reuse a shared Atomic Skill from configuration. Do not put task-local motion generation in a lowerer or create another semantic runtime.
Reference tasks#
Environment |
Assurance |
What it demonstrates |
|---|---|---|
|
projected |
Bounded repeat and cyclic targets over Pick and Place. |
|
projected |
An allowlisted registered call lowered to atomic Slide. |
|
verified |
Coordinated dual-resource HandOver with measured evidence, settling, and final-target validation. |
|
projected |
Registered held-object transport and Pour calls composed after Pick. |
Projected examples demonstrate planning and command generation only. They must not be presented as physically qualified task-success integrations.
Recommended change sites#
Change |
Owning location |
|---|---|
Schema and AST dataclasses |
|
Strict decoding and validation |
|
File loading and resource bounds |
|
Provider-free compilation |
|
Semantic Call lowering |
|
Sequential and parallel execution |
|
Semantic declarations |
|
Registration and environment assembly |
|
Gym bridge and segment lifecycle |
|
Dynamic Gym ID registration |
|
Atomic planning and execution |
|
Focused validation#
Run:
pytest -q tests/lab/task_program
pytest -q tests/gym/envs/task_program
pytest -q tests/sim/atomic_actions
python docs/scripts/check_api_docs.py
Physical qualification additionally requires real-environment runs with measured evidence, controlled seeds/randomization, task validators, and saved completion metadata.
Further reading#
Scene registry — canonical scene identities, affordances, and live providers
Robot skill profiles — robot resources, Atomic Skill bindings, and assurance
Atomic actions — direct typed atomic-action planning and execution
Authoring a Task Program in Python — author and compile a Task Program in Python
Configure and Run an Embodied Task Program — configure and run an embodied Task Program