Exercise · Nervous System

A short, guided task. Complete it before moving on to the lab. All snippets use the provider-neutral message vocabulary; no broker, credentials, or network calls are required.

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.

Task

For a Pico you have been modeling across Part 3, write:

  1. a discovery advertisement for the Pico;
  2. one message of each semantic type (observation, event, command, delegation, result, presence);
  3. a small authorization decision that treats broker authentication and Open Engineering authorization as separate concerns.

Example shapes (keep them provider-neutral — no MQTT topic strings, no broker client IDs, no credentials):

# discovery.yaml
pico:
  identity:
    id: pico-alice
  kind: garden-detective
  capabilities:
    - garden.moisture.read
    - garden.watering.request
  protocols:
    - pico-agent-transport
  status:
    state: online
# messages.yaml
messages:
  - type: observation
    source: pico-alice
    subject: garden/soil
    payload: { moisture: 32 }
  - type: event
    source: pico-alice
    subject: garden/soil/dry
    payload: { threshold: 40 }
  - type: command
    source: pico-alice
    target: pico-bob
    subject: garden.watering.request
    payload: { duration_s: 60 }
  - type: delegation
    source: pico-alice
    target: pico-bob
    subject: mission.investigate_dry_zone
    correlation: corr-001
  - type: result
    source: pico-bob
    subject: mission.investigate_dry_zone
    correlation: corr-001
    payload: { status: completed }
  - type: presence
    source: pico-bob
    payload: { state: online }
# authorization.yaml
transport_authentication:
  broker_session_ok: true          # a Transport concern
open_engineering_authorization:
  actor: pico-alice
  capability: garden.watering.request
  target: pico-bob
  decision: allow                  # an Open Engineering concern

Answer the reflection questions below.

Note

There is no single correct answer. The goal is to internalize the semantic vocabulary and the transport-substitution posture: message types stay the same whether the underlying transport is MQTT, A2A, or an in-process bus.

Success criteria

Automatable check

Save the snippet under a scratch working directory and confirm it is well-formed YAML with the expected shape. These are Nervous System governance and message artefacts, not Hello Pico Rules, so the check uses python3 rather than pico parse (which only accepts the flat Rule shape taught in Part 1). No broker or external service is contacted.

mkdir -p scratch-nervous
cat > scratch-nervous/messages.yaml <<'EOF'
messages:
  - { type: observation, source: pico-alice, subject: garden/soil, payload: { moisture: 32 } }
  - { type: event,       source: pico-alice, subject: garden/soil/dry }
  - { type: command,     source: pico-alice, target: pico-bob, subject: garden.watering.request }
  - { type: delegation,  source: pico-alice, target: pico-bob, subject: mission.x, correlation: c1 }
  - { type: result,      source: pico-bob,   subject: mission.x, correlation: c1, payload: { status: completed } }
  - { type: presence,    source: pico-bob,   payload: { state: online } }
EOF
python3 - <<'PY'
import sys, yaml
doc = yaml.safe_load(open("scratch-nervous/messages.yaml"))
msgs = doc.get("messages") or []
required = {"observation","event","command","delegation","result","presence"}
seen = {m.get("type") for m in msgs if isinstance(m, dict)}
ok = required <= seen and all(m.get("source") for m in msgs)
print("OK: message envelope covers all six semantic types" if ok else f"FAIL missing={required - seen}")
sys.exit(0 if ok else 1)
PY

The command exits with status 0 and prints an OK: line when the envelope covers all six semantic types.

Reflect

  • Why does a command name garden.watering.request rather than an MQTT topic like picos/bob/cmd?
  • What does “a valid broker session must not imply authorization” mean for a Pico that can technically publish to any topic?
  • Why must a result share a correlation value with the original delegation, but an observation typically does not?
  • If EMQX/MQTT were replaced by a different transport tomorrow, which of your files would need to change, and which would not?

Next

Continue with the Lab.