Version: 1.0.0
| Capability | Integration point |
|---|---|
| Robot read or calculation | Gateway Query ToolSpec + ToolEndpoint operation |
| Robot effect | Gateway Action ToolSpec + ToolEndpoint operation |
| Stateful capability lifecycle | Gateway Session ToolSpec + ToolEndpoint operation |
| Dora nodes and deployment assets | Manifest-v2 Skill Bundle and locked Node artifacts |
| Workflow instructions | SKILL.md discovered by SkillsLoader |
| User-task success | Generic TaskVerificationContract and AgentTask finalize |
| New model provider | Existing provider registry/configuration |
| Non-robot Agent capability | Existing Agent ToolRegistry or dynamic MCP |
Do not connect Agent code directly to robot SDKs, Dora nodes, simulators, or legacy Gateway Session/Policy routes outside the governed Tool API.
Every ToolSpec has a stable tool_id, implementation and endpoint binding, operation,
semantics: query|action|session, description, strict input/output JSON schemas, readiness requirements,
and a robot frame profile when spatial inputs are involved.
tool_id: motion.resolve_relative_pose
implementation_id: motion.integration
endpoint_id: motion.relative_pose
operation: resolve
semantics: query
description: Resolve a relative end-effector delta into an absolute target pose.
input_schema:
type: object
additionalProperties: false
required: [translation_frame, translation_m]
properties:
translation_frame: {enum: [tcp, base]}
translation_m:
type: object
additionalProperties: false
required: [x, y, z]
properties:
x: {type: number}
y: {type: number}
z: {type: number}
output_schema:
type: object
robot_frame_profile:
base_frame: arm_base
tool_frame: tcpUse Query for synchronous reads or deterministic resolution without a robot effect. Use Action for
bounded physical effects and Session for explicitly owned, stateful lifecycles. Define Endpoint operation max_concurrency at
the execution owner; PAOS does not create a cross-Tool lease.
Query calls are resolved from ToolSpec and invoked at:
POST /tools/{endpoint_id}/{operation}:invoke → HTTP 200
Action admission uses:
POST /tools/{tool_id}:invoke → HTTP 202 + invocation_id + attempt_id
GET /invocations/{invocation_id}
GET /invocations/{invocation_id}/result
POST /invocations/{invocation_id}/cancel
Session admission uses the same POST /tools/{tool_id}:invoke contract. Reconcile it through the
common invocation routes and stop it with POST /invocations/{invocation_id}/stop. Declare whether
the Session is task-owned, shared, or runtime-owned; do not let one owner stop another owner's
Session.
Action status/result must expose an explicit lifecycle. Result may remain pending with HTTP 202. Cancellation acceptance reports control handling only. When execution truth cannot be recovered, return an explicit unknown outcome rather than fabricating cancellation or success.
Inputs and outputs must be finite JSON and satisfy ToolSpec. Spatial Tools must state frames,
units, tolerances, and orientation behavior. Avoid hidden defaults that the Agent cannot inspect
through forge_tool_context.
An installed Skill Bundle contains:
<skill>/
├── skill.yaml
├── SKILL.md
├── start.sh # optional external-resource preparation before Dora
├── archive-manifest.json # generated by the packaging script
├── profiles/<profile>/dataflow.yaml
├── profiles/<profile>/...
└── assets/...
Minimal manifest structure:
manifest_version: 2
name: example-skill
version: "1.0.0"
description: Example robot workflow.
skill_document: SKILL.md
gateway_url: http://127.0.0.1:19002
required_tools: [example.query, example.action]
profiles:
sim:
dataflow: profiles/sim/dataflow.yaml
# optional: overrides the Skill-wide required_tools; omit to inherit
required_tools: [example.query]
required_binaries: [gateway, example_node]
required_assets: [assets/scene.xml]
required_environment: []
environment: {}
artifacts:
resolver: registry
nodes:
gateway:
artifact_id: gateway-1.0.0-linux-x86_64
version: "1.0.0"
platform: linux
arch: x86_64
artifact_type: executable_tar_gz
entrypoint: gateway
sha256: <64-character-sha256>All paths are relative and contained by the Bundle. Each Node archive has the locked SHA-256.
An executable_tar_gz archive contains exactly one root-level executable with the locked
filename; a directory_tar_gz archive contains exactly one root directory named after the
entrypoint that holds the same-named executable and its runtime tree (tree-internal relative
symlinks only). The installer records the
extracted binary hash in its receipt. The Bundle archive inventory must
cover every file with SHA-256. Links, path traversal, collisions, oversized expansion, and unlisted
content are rejected.
When startup must download weights or prepare other external resources, the Bundle may provide a
root-level start.sh. PAOS invokes it as bash <bundle>/start.sh <name> <version>, preserves the
caller's working directory, and inherits terminal stdio. The script should resolve Bundle files
relative to its own location, tolerate repeated execution, and return non-zero on failure. Such a
Bundle requires Bash on the host PATH. PAOS_SKILL_NAME and PAOS_SKILL_VERSION are available as
dataflow placeholders and in Dora process environments.
Hook environment contract: PAOS also passes PAOS_SKILL_PROFILE (the profile being started),
PAOS_SKILL_ROOT (the Bundle root), and PAOS_HOOK_PYTHON (the interpreter running PAOS Core).
PAOS_HOOK_PYTHON is only guaranteed to import Core's own dependencies, not any model-runtime
dependency: create your own virtual environment or call an external tool when the hook must prepare
CUDA PyTorch, transformers, or similar.
profiles.<profile>.required_tools is optional: when present it overrides the Skill-wide
required_tools, and a profile that omits it inherits that list. The field carries two contracts at
once - the Tool set the startup and status health checks require, and the Tool allowlist the AgentTask
may call (forge/binding.py freezes the same list into the AgentTask). One Bundle can therefore
expose a different Tool surface per profile while both checks stay in agreement for a given profile.
profiles.<profile>.required_tools needs a PAOS Core that knows the field. An older Core, including
v1.0.0, rejects the whole Bundle with
profiles.<profile> has unknown field(s): required_tools, so Bundles using it should state their
minimum Core version.
The repository script regenerates archive-manifest.json, builds a deterministic archive with
fixed metadata, and safely extracts it through ArchiveValidator for final verification:
python scripts/package_skill.py /path/to/example-skill --output-dir dist/skillsThe output name comes from name and version in skill.yaml; the script prints the archive
SHA-256 and byte size. It refuses to replace an existing output unless --force is supplied; use
that option only before publication. The script rejects links and excludes version-control, cache,
and node_modules directories. Do not put credentials, presigned URLs, machine caches, logs, or
runtime state in the source directory.
Before upload, run the same public local loop that users depend on:
paos skill install dist/skills/example-skill-1.0.0.tar.gz --local
paos forge-node verify example-skill gateway
paos skill inspect example-skill
paos skill start example-skill --profile sim
paos skill status example-skill
paos skill stop example-skillA local Bundle uses the same archive, manifest, and Node-lock validation as a Registry Bundle. Missing Nodes still resolve through the configured Registry or static index. Installers stage, validate, atomically replace, and roll back on failure. Never require callers to disable digest verification.
- Publish and register every Node artifact first. An
executable_tar_gzarchive contains only one root-level executable named byentrypoint; adirectory_tar_gzarchive contains only one root directory named byentrypoint(holding the same-named executable and its runtime tree). Put the final archive SHA-256 in the Skill lock. - Freeze the
skill.yamlname/version, profiles, and Node locks, package the Bundle, and retain the printed Bundle SHA-256 andsize_bytes. - Upload the Bundle to a non-overwritable, long-lived HTTPS object key. Read it back from the final URL and verify size and SHA-256. Corrections require a new version instead of overwriting bytes.
- Register the current Skill name, URL, SHA-256, and size in the Resource Registry, and ensure every
Node
artifact_idresolves through its Node endpoint. An equivalent schema-v3 static index is also supported. - From a clean PAOS HOME, repeat Registry install, start, status, and stop. Confirm that no source checkout path or development-machine cache is required.
The public Registry returns the current Skill entry by name and has no historical-version subpath.
The version in paos skill install <name> --version <version> is a client constraint: after the
Bundle download, PAOS verifies its manifest version and rejects a mismatch before Node download or
installation commit. Preserve old versions through immutable URLs, static indexes, or local
archives; do not treat --version as a Registry history query.
Develop and validate the currently distributed Forge Skill profiles with Dora CLI v0.4.1 and
dora-message v0.7.0. Keep Node builds on that protocol generation until the Skill locks and host
baseline are upgraded together.
The dataflow should give each node explicit inputs/outputs and use the Gateway Tool request/response ports declared in its profile. Required executables are resolved from the immutable Runtime environment. Assets remain in the Skill Bundle and are referenced with relocatable paths.
RuntimeManager creates a deterministic flow name, verifies Dora and required files, starts the
flow, then waits for Gateway /tools and every required Tool context. A Gateway already listening
at the manifest URL is not silently adopted.
When Tool API is the physical execution plane, disable the Gateway Agent API in the profile:
agent:
enabled: false
tools:
enabled: trueSKILL.md should tell the Agent when to activate the Skill, which contexts to inspect, the Query →
Action/Session ordering, task binding, ownership, terminal reconciliation, verification checkpoints, and safe recovery
rules. It must not embed secrets, Registry URLs, task-specific coordinates, or instructions to
bypass Gateway/verification.
For a verified workflow, activate the primary Skill in the current turn, create one AgentTask from that activation, bind every contributing Query/Action/Session to the same task, finalize after all task-owned executions terminate, and append a PlanRevision only when recovery verdict allows it.
Robot capability integration should expose Tool execution facts, not action-specific verifier code. PAOS captures configured image/state sources and applies the generic verification contract at AgentTask finalize. Tool output schemas should contain useful terminal result semantics, final state/error data, and tolerances where relevant.
If authoritative evidence is introduced later, version the evidence contract explicitly. Do not upgrade best-effort WebSocket association by convention.
Before real hardware or simulation, use a mock HTTP transport to test:
- Tool list/spec/context and Query binding resolution;
- activation candidate revalidation and ToolSpec/runtime drift rejection;
- Action HTTP 202 admission with invocation and attempt identities;
- Session admission, ownership, status/result, and stop;
- pending status/result and known terminal results;
- cancellation requested/accepted without false stop;
- timeout and unknown without blind retry;
- endpoint concurrency rejection behavior;
- diagnostic Query and bound calls through identical routes;
- AgentTask one-active constraint, revisions, evidence, and aggregate verification;
- archive traversal/link/collision/digest attacks and transactional rollback;
- startup with and without
start.sh, missing Bash, and non-zero hook exit; - Skill identity injection into dataflow/Dora environments and rematerialization after profile content or dataflow-path changes;
- cross-process start/stop/install/remove conflicts for one Skill;
- Runtime start/status/log/stop and availability propagation.
Then run a complete simulated workflow. Real robot or MuJoCo acceptance must identify the exact Bundle, node digests, profile, and environment used.
- Tool semantics and schemas are explicit and strict.
- Frame, unit, tolerance, and readiness conventions are inspectable.
- Gateway operation owns
max_concurrency. - Query, Action, and Session use the documented HTTP contracts.
- Skill/Runtime/ToolSpec binding is frozen and revalidated for every governed execution.
- Invocation and attempt IDs remain separate from PAOS task IDs.
- Cancel, stop, timeout, and unknown do not imply physical stop or trigger a blind POST retry.
- Bundle and Node artifacts have immutable size/digest metadata.
- The Bundle passes repository packaging and the local install loop, and Registry Skill and Node endpoints all resolve.
- Optional startup-hook arguments, failure state, repeated execution, and external-resource digests are verified.
- Runtime profile starts from a clean environment and reaches all Tool contexts.
- Gateway Agent API is disabled for the Tool-only profile.
- General Agent tools, verification, experience, and evolution require no capability-specific fork.