Lab · Give a Pico Hands

See the Open Engineering Language Server (OELS) onboarding guide for the local install and editor setup.

TipOELS in your editor

While you work through this content, keep the Open Engineering Language Server (OELS) active in VS Code (or any LSP-capable editor). See the OELS onboarding guide linked at the top of this page (also linked from the academy Resources page) for the one-time install and configuration steps.

What OELS validates. OELS only recognizes OE-shaped YAML/JSON: files with a mapping root that declare an apiVersion beginning with open-engineering.io/, a non-empty kind, and a DNS-1123 metadata.name. Ordinary academy metadata.yaml, Quarto/QMD pages and front matter, Kubernetes/Crossplane/runtime manifests, JSON payload samples, and shell scripts are intentionally non-OE — OELS ignores them silently and you should not add synthetic apiVersion/kind headers to force recognition.

Where you see diagnostics. OELS surfaces UnknownProperty, MissingRequiredProperty, IncorrectType, InvalidEnumValue, MalformedIdentifier, UnknownDefinition, and reference-shape hints in the editor Problems panel as you type. These are independent of quarto render: OELS diagnostics do not block rendering, and Quarto errors do not appear in the Problems panel.

The executable check still comes from this exercise. OELS speeds up editing, but the exercise’s own parser, verifier, or verify.sh (for example the pico parse … command shown below) remains the authoritative success check. Run it as usual.

In this lab you will author one artefact per stage of a Hand invocation — Composer equipment, Pico decision, Policy authorization, Hand selection, Provider execution, Evidence, and Action event — and validate the local YAML with the pico CLI.

The scenario follows the memo progression: a Pico observes a condition, evaluates a rule, decides on an action, its Hand carries the action out, an evidence record is kept, and an action event is published.

ImportantNo external calls in this wave

Every step in this lab operates on local YAML only. No step contacts Composio, GitHub, Kubernetes, or any other external service. The provider mapping in Step 6 is a labeled, optional, non-runnable annex — nothing in it executes.

Setup

mkdir -p scratch/hands

Step 1 — Composer equipment (Pico definition with Hands)

Create scratch/hands/pico.yaml. This is what the Composer puts on the Pico. It says only what capabilities are available, not what is permitted.

# scratch/hands/pico.yaml
apiVersion: open-engineering.io/v1alpha1
kind: Pico
metadata:
  name: issue-reporter
spec:
  hands:
    - name: external
      provider: local          # provider-neutral placeholder
      capabilities:
        - github.issue.read
        - github.issue.create
    - name: cluster
      provider: local          # provider-neutral placeholder
      capabilities:
        - kubernetes.resource.read

Step 2 — Pico decision (governed action request)

Create scratch/hands/action.yaml — the “identity before action” boundary. This is the Pico’s decision to invoke a capability, not yet the authorization or the execution.

# scratch/hands/action.yaml
actor:
  pico: issue-reporter
principal:
  type: user
  id: user.example
action:
  capability: github.issue.create   # provider-neutral
authorization:
  capability: github.issue.create

Step 3 — Policy authorization (rules with constraints)

Create scratch/hands/rules.yaml. These are the Open Engineering rules that decide whether the Pico’s decision is permitted in this context.

# scratch/hands/rules.yaml
rules:
  - capability: github.issue.create
    effect: allow
    constraints:
      repositories:
        - academy-test/*
  - capability: kubernetes.resource.read
    effect: allow
  - capability: kubernetes.resource.delete
    effect: deny
  - capability: github.issue.create
    effect: deny
    constraints:
      repositories:
        - production/*

Step 4 — Hand selection

Create scratch/hands/selection.yaml. This records which specific Hand on the Pico is bound to carry out the authorized capability.

# scratch/hands/selection.yaml
selection:
  capability: github.issue.create
  hand: external
  rationale: "only 'external' declares github.issue.create in step 1"

Step 5 — Provider execution (simulated)

Create scratch/hands/execution.yaml. This is a simulated provider result. Nothing is actually contacted — the artefact just describes what a provider would return so later stages can consume it.

# scratch/hands/execution.yaml
execution:
  hand: external
  capability: github.issue.create
  provider: local              # simulated; no external call
  status: succeeded
  provider-reference: "sim://issue/42"

Step 6 — Evidence

Create scratch/hands/evidence.yaml. Evidence is a signed, retainable record of what happened, distinct from the action itself.

# scratch/hands/evidence.yaml
evidence:
  actor: issue-reporter
  principal: user.example
  capability: github.issue.create
  authorized-by: rules/rules.yaml#0
  hand: external
  execution-reference: "sim://issue/42"
  outcome: succeeded
  observed-at: 2026-01-01T00:00:00Z

Step 7 — Action event

Create scratch/hands/event.yaml. This is the Pico’s Voice reporting a state transition after the Hand acted. Other Picos, services, or humans can subscribe to it.

# scratch/hands/event.yaml
event:
  type: pico.hand.executed
  source: issue-reporter
  capability: github.issue.create
  outcome: succeeded
  evidence-reference: evidence/evidence.yaml

Step 8 — Validate all seven

Every file is local YAML. No network is used. These are Hands governance artefacts rather than Hello Pico Rules, so the check uses python3 to confirm each file is well-formed YAML — pico parse only accepts the flat Rule shape (id/kind/value) taught in Part 1.

python3 - <<'PY'
import sys, yaml, pathlib
root = pathlib.Path("scratch/hands")
failed = False
for name in ("pico", "action", "rules", "selection", "execution", "evidence", "event"):
    path = root / f"{name}.yaml"
    try:
        doc = yaml.safe_load(path.read_text())
    except yaml.YAMLError as exc:
        print(f"FAIL: {path} — {exc}", file=sys.stderr); failed = True; continue
    if not isinstance(doc, dict) or not doc:
        print(f"FAIL: {path} — expected a non-empty YAML mapping", file=sys.stderr)
        failed = True; continue
    print(f"OK: {name}.yaml parses")
sys.exit(1 if failed else 0)
PY

Step 9 — Optional annex · Composio provider mapping (non-runnable)

WarningOptional and non-runnable in this wave

This annex illustrates what a provider mapping for Composio could look like. It is not executed and is not a prerequisite for completing the lab. No credentials, tokens, or Composio account are needed.

# scratch/hands/composio-mapping.yaml   (illustrative only — do not run)
provider: composio
mappings:
  github.issue.create: GITHUB_CREATE_ISSUE
  email.send:          GMAIL_SEND_EMAIL

The Pico rules in Step 3 still name only github.issue.create. Swapping the provider means swapping this mapping — nothing else changes.

For a deeper walk-through of this mapping — including a mock contract check that runs on local YAML and asserts rules stay provider-neutral, no credential-shaped strings appear, and the Composio-specific vocabulary is confined to the adapter surface — see the optional, non-runnable follow-up page: Composio as a Hands provider.

Step 10 — Reflect

Answer, using your files:

  • Which file expresses what the Pico can be equipped to do (equipment)?
  • Which file expresses what the Pico is permitted to do in a given context (policy authorization)?
  • Why is the action request tied to an actor and capability rather than only a provider tool?
  • Why do evidence and action event exist as separate artefacts?
  • What extra constraint would you add to require human approval for a production github.issue.create?

What you will produce

Seven local YAML artefacts — one per stage of the Hand invocation — plus an optional, non-runnable Composio mapping annex. Together they show Hands as governed execution with clear separation between equipment, decision, authorization, selection, execution, evidence, and action events.

Next

Continue with the Summary.