The /app/lab mount
The single most confusing thing about this repo. Read this once and the stray lab/ prefixes stop looking like typos.
The rule
The whole repo is bind-mounted read-only into the worker container at /app/lab.
The worker SDK image’s WORKDIR is /app. So a path that the worker resolves is relative to /app and needs a lab/ prefix to reach into this repo; a path that the host resolves is relative to the repo root and must not have one.
| Context | Path | Correct? |
|---|---|---|
Makefile recipe, host shell |
./gen_clab_topology |
✅ |
Makefile recipe, host shell |
./lab/gen_clab_topology |
❌ |
docker compose exec worker python3 … |
lab/wait_devices |
✅ |
docker compose exec worker python3 … |
wait_devices |
❌ |
| env var read by the container | DIR_FUNCTION_BLOCKS: lab/function_blocks,neops/fb |
✅ |
| env var read by the host | anything with lab/ |
❌ |
Put plainly: a lab/ inside a docker compose exec or a container-read env var is correct; a lab/ in a Makefile recipe or a host script is a bug.
Why it exists
This repo was extracted from neops-worker-sdk-py/lab/. In the SDK repo the lab genuinely was a subdirectory called lab/, and the mount reproduced that path inside the container. When the directory became its own repository, its contents were flattened to the repo root — there is no lab/ subdirectory here any more — but the mount point stayed /app/lab, because the in-container layout is what DIR_FUNCTION_BLOCKS and every exec line depend on.
The result is an asymmetry that looks like an inconsistency and is not.
Where you meet it
DIR_FUNCTION_BLOCKS — the worker’s function-block search path, lab/function_blocks,neops/fb. The first entry is this repo’s function_blocks/ through the mount; the second is /app/neops/fb, baked into the image. See Discovery.
Device readiness — make local-lab-up and make local-lab-discover both run:
That is this repo’s wait_devices script, executed inside the worker container. It runs there rather than on the host for a network reason, not a path reason — see Troubleshooting.
Two consequences worth knowing
The mount is read-only
:ro. A function block cannot write into the repo from inside the worker,
and neither can anything else in that container. Generated output belongs
in generated/, written by the host script.
neops/fb is not mounted from here
The base function blocks come from the image, not from this repo. If
discovery fails with Function block … not found, the question is not
“is my mount right” but “does the NEOPS_WORKER_SDK_IMAGE I pinned carry
/app/neops/fb”.
The first lists what the image ships; the second should show this repo’s
root — topology.json, function_blocks/, wait_devices, and so on.
