Skip to main content

labcode

CI PyPI

The lc command-line interface for the labcode dialect of the Object-flow Programming Language. Installing this one package pulls in the ofplang toolchain and exposes it under a single command:

lc validate ...   # check a workflow is well-formed portable v0
lc schedule ...   # compute a schedule for a workflow
lc run ...        # execute a workflow on the labcode backend

labcode is where a site-specific dialect and a custom runner (real lab hardware) are developed on top of the ofplang toolchain. lc validate and lc schedule forward to the ofplang siblings unchanged; lc run is the labcode dialect's own runner: it drives the workflow on the labcode backend, running each device operation's script — supplied in the environment as an x-labcode.script extension on a process mode — out-of-process on a wall clock, so a long-running real operation never blocks the replan loop. See SPECIFICATIONS.md for the x-labcode extension.

# in the execution environment: how a (process, mode) is carried out
processes:
  measure_od:
    modes:
      - id: v0
        duration: 45
        x-labcode:
          script:
            language: python
            code: |
              return {"od": read_plate(plate)}

Install

pip install labcode

Requires Python 3.10+. lc validate and lc schedule are dispatched to the ofplang sibling packages unchanged; lc run is this package's own runner, built on them:

The language is defined in the ofplang/spec repository, and what labcode adds to it in SPECIFICATIONS.md.

What lc run brings of its own, beyond dispatching:

  • the labcode backend — each device operation's x-labcode.script runs out-of-process on a wall clock (§1.2, §1.3), so a real operation that takes minutes does not block the replan loop, and an operation that never returns is stopped by op_timeout (§1.8; --op-timeout / --no-op-timeout).
  • the dialect front door — the environment's x-labcode extension is validated before anything runs, on top of the portable-v0 check lc validate performs (§1, §2).
  • availability probing — each machine is checked as often as its probe policy says, and one that cannot be reached is taken out of the environment the scheduler plans against, so the run routes around it (§1.5; --no-probe).
  • object identity — the reserved _id view key is declared on Object types and minted per object, so a physical thing can be followed through a run (§4).
  • flavor: sila2 — a script that speaks SiLA2 gets its clients opened around it (§1.6). The client library itself is the sila2 extra: pip install labcode[sila2], installed into whichever interpreter runs the scripts.
  • recording a run — with --trace, what the run did is recorded as OpenTelemetry traces: one trace per run, a span per operation, and a span per SiLA2 connection and command measured inside the process that issued it. Off by default; the extra is pip install labcode[otel].

Usage

Each subcommand keeps its own options, exit codes, and --help:

lc --help            # top-level help
lc <command> --help  # command-specific options
lc --version

lc can also be run as a module: python -m labcode <command> ....

lc validate and lc schedule are the ofplang siblings' own CLIs unchanged, so their options are documented in those repositories. lc run is this package's own, and is described below.

lc run

lc run <workflow> --env <env>
    [--boundary DOC] [-o OUT] [--boundary-out FILE] [--observation-out FILE]
    [--seconds-per-tick S] [--op-timeout S | --no-op-timeout] [--no-probe]
    [--trace] [--mission-id ID] [--object-ids seeded|real]
  • <workflow> — the portable v0 workflow: what happens.
  • --env (required) — the labcode environment: the execution environment (spec §5) plus the x-labcode extension saying how each operation is carried out.
  • --boundary DOC — the whole-workflow I/O as one document: a boundary: mapping with a {spot, view} descriptor per entry input / final output port. spot says where a boundary Object sits; view supplies an input's value. A workflow with Object-bearing entry inputs needs one, since each must be placed on a spot and only the operator knows where the labware is.
  • -o OUT — write the final execution status (spec §6/§7) here; the default is stdout.
  • --boundary-out FILE — write the result boundary: the same schema as --boundary, with each produced output's view filled in, including the _id its Object was minted with (§4) — which is how one checks that the plate that came back is the plate that went in.
  • --observation-out FILE — stream the observation document: each completed activity's concrete input / output view values, appended as it finishes. What the instruments reported, as against the status document's timings.
  • --seconds-per-tick S — real seconds per environment time tick (default 20). Durations in the environment are counted in ticks, and this is what maps them onto the wall clock. The default is deliberately coarse, so that a real operation's dispatch → running → completed reads as discrete, observable steps; a demo against a fast mock wants a small value.
  • --op-timeout S / --no-op-timeout — how long one operation may run before it is stopped and failed (§1.8). The default is the environment root's x-labcode.op_timeout, else 7200 real seconds. The two forms exclude each other.
  • --no-probe — ignore the environment's x-labcode.probe policies and treat every machine as reachable (§1.5). The documents are still validated.
  • --trace — record what the run did (see below). Off by default.
  • --mission-id ID — the campaign this run belongs to. Recorded with the run and given no meaning by labcode: several runs may share one, and nothing here reads it back.
  • --object-ids seeded|real — how Object _ids are minted: seeded is reproducible (the same workflow yields the same ids every run, which is what keeps the examples' recorded output stable), real is unique per run. Unset, it follows --trace.

Exit codes: 0 the run completed, 1 it failed (an activity failed, a contract was violated, an operation timed out, or a replan became infeasible), 2 a usage or input error — including a workflow or an x-labcode extension the front doors reject.

A complete invocation, against this repository's examples/ (--seconds-per-tick small because that example's scripts return instantly):

lc run examples/plate_line.workflow.yaml --env examples/plate_line.env.yaml \
  --boundary examples/plate_line.boundary.yaml --seconds-per-tick 0.2

The remaining options tune the replan loop rather than describe the run — --poll-interval, --margin, --seed, --speed, --max-ticks, --no-validate — and are covered by lc run --help.

Recording a run

--trace records what the run did as OpenTelemetry traces. It needs the extra, in the interpreter that drives the run — which is also the one that runs the scripts, since labcode launches each with sys.executable:

pip install 'labcode[otel]'
lc run <workflow> --env <env> --trace --mission-id M-2026-001

One run is one trace, and the id it can be found by is printed to stderr as the run starts:

run                                  mission.id, and the failure if it stopped on one
├─ process Seal                      which node, process and mode; the plan's interval;
│  │                                 which Objects it handled
│  ├─ sila2.connect                  the address, measured in the process that connected
│  └─ sila2 SealerControl.Seal       the command, from its start to its real completion
└─ transport                         the route and the transporter

An operation's span is opened when it is dispatched and closed when a poll finds it finished, so its end is late by up to one poll period; what an instrument actually spent is in the command spans, which are measured where the commands are issued. ofp.object.id lists the _ids an operation handled, including one it created — which is what makes "everything that happened to this plate" a single query.

Where the record goes is configured by the standard OTEL_* environment variables (OTEL_EXPORTER_OTLP_ENDPOINT, OTEL_RESOURCE_ATTRIBUTES, OTEL_SERVICE_NAME, …), so labcode adds no settings of its own; service.name falls back to labcode if nothing sets it. LC_TRACE_FILE=path additionally writes the spans to a file as JSON lines, one file per process (the name gets the process id), which is how a record can be read without standing up a collector.

Two things to know before pointing a run at a collector. --trace makes Object _ids real rather than reproducible unless --object-ids says otherwise, since a reproducible id is the same on every run and would collapse several runs' plates into one. And a collector that is configured but does not answer delays each operation, by as long as OpenTelemetry's own export timeout allows: labcode sets no timeout of its own, so OTEL_EXPORTER_OTLP_TIMEOUT is the knob, and it belongs to whoever pointed the run there.

Examples

examples/ holds three worked runs: plate_line, an Object-bearing line driven entirely by environment scripts and runnable with no hardware, and sila2_seal and sila2_plate_cycle, which drive the reference lab's SiLA2 servers for real. sila2_seal also walks through what a run does when a machine stops answering — before an operation, and in the middle of one.

License

MIT

Download files

Download the file for your platform. If you're not sure which to choose, learn more about installing packages.

Source Distribution

labcode-0.1.7.tar.gz (165.5 kB view details)

Uploaded Source

Built Distribution

If you're not sure about the file name format, learn more about wheel file names.

labcode-0.1.7-py3-none-any.whl (78.3 kB view details)

Uploaded Python 3

File details

Details for the file labcode-0.1.7.tar.gz.

File metadata

  • Download URL: labcode-0.1.7.tar.gz
  • Upload date:
  • Size: 165.5 kB
  • Tags: Source
  • Uploaded using Trusted Publishing? Yes
  • Uploaded via: twine/7.0.0 CPython/3.13.14

File hashes

Hashes for labcode-0.1.7.tar.gz
Algorithm Hash digest
SHA256 67109fd94060cbcff27a8791bd527aa8c7132db3a11f9693a0ead19a599867fa
MD5 1530a8f2c6045373fa2ccc1c45542a89
BLAKE2b-256 971527a04526e3118ee845ce0ff50adac1d49eeeb2c422998d304530683997e7

See more details on using hashes here.

Provenance

The following attestation bundles were made for labcode-0.1.7.tar.gz:

Publisher: publish.yml on ofplang/labcode

Attestations: Values shown here reflect the state when the release was signed and may no longer be current.

File details

Details for the file labcode-0.1.7-py3-none-any.whl.

File metadata

  • Download URL: labcode-0.1.7-py3-none-any.whl
  • Upload date:
  • Size: 78.3 kB
  • Tags: Python 3
  • Uploaded using Trusted Publishing? Yes
  • Uploaded via: twine/7.0.0 CPython/3.13.14

File hashes

Hashes for labcode-0.1.7-py3-none-any.whl
Algorithm Hash digest
SHA256 a9b5ff86439b4d451749183928a3444c2ba3e8a9d7833f9ac98d1e9eec5e890e
MD5 dcc1efacd31dcc816a6b041b549fea8b
BLAKE2b-256 9ee75d279a0d79bbe51cd21fe4b43c5435312256094a5873f916a8eca691b998

See more details on using hashes here.

Provenance

The following attestation bundles were made for labcode-0.1.7-py3-none-any.whl:

Publisher: publish.yml on ofplang/labcode

Attestations: Values shown here reflect the state when the release was signed and may no longer be current.

Release history Release notifications | RSS feed

0.7.0

2 files

0.6.0

2 files

0.5.0

2 files

0.4.0

2 files

0.3.1

2 files

0.3.0

2 files

0.2.0

2 files

0.1.8

2 files

This release

0.1.7 This release

2 files

0.1.6

2 files

0.1.5

2 files

0.1.4

2 files

0.1.3

2 files

0.1.2

2 files

0.1.1

2 files

0.1.0

2 files

0.0.1

2 files

Anthropic, PBC Visionary sponsor Bloomberg Visionary sponsor Hudson River Trading Visionary sponsor Meta Visionary sponsor NVIDIA Visionary sponsor Microsoft Sustainability sponsor Depot Continuous Integration AWS Cloud computing and Security Sponsor Datadog Monitoring Fastly CDN Google Download Analytics Sentry Error logging StatusPage Status page