CLI#
libby is the command-line front for keyword peers. Verbs:
libby show <group>.<daemon>.<keyword> # read a keyword (% wildcard in keyword)
libby modify <group>.<daemon>.<keyword>=V # write a keyword (exact keyword)
libby list <group>.<daemon>.<pattern> # list keyword names (% wildcard in keyword)
libby describe <group>.<daemon>.<keyword> # metadata for one keyword (exact keyword)
libby waitfor '$<group>.<daemon>.<keyword> > V' # block until a comparison holds
<group>.<daemon> is the address of one daemon: group is its group_id
and daemon is its peer_id (e.g. peer_id: adc, group_id: hsfei in the
daemon’s config is addressed as hsfei.adc). Libby.rabbitmq() /
Libby.zmq() build the actual wire identity from those two fields via
libby.naming.qualified_peer_id, so a daemon config never needs to
concatenate them by hand. group/daemon are case-insensitive (HSFEI.ADC
and hsfei.adc reach the same daemon); the keyword isn’t. Cross-peer
fanout is not supported. req and sub are kept for raw RPC / topic
debugging.
Examples#
$ libby show hsfei.pickoff.positionvalue
hsfei.pickoff.positionvalue = 79.0 mm
$ libby show hsfei.pickoff.is%
hsfei.pickoff.isconnected = True
hsfei.pickoff.isloopclosed = True
hsfei.pickoff.ismoving = False
hsfei.pickoff.isreferenced = True
$ libby modify hsfei.pickoff.softmax=120
hsfei.pickoff.softmax = 120.0 mm
$ libby modify hsfei.pickoff.softmax=null # or hsfei.pickoff.softmax=
hsfei.pickoff.softmax = None mm
$ libby describe hsfei.pickoff.positionvalue
hsfei.pickoff.positionvalue:
type float
readonly False
writeonly False
nullable False
units mm
description Stage position in engineering units.
$ libby list hsfei.pickoff.%min
hsfei.pickoff.hardmin
hsfei.pickoff.softmin
$ libby waitfor '$hsfei.pickoff.ismoving == false' --timeout 30
hsfei.pickoff.ismoving = False (satisfied after 4.2s)
$ libby waitfor '$hsfei.pickoff.positionvalue > 15' --timeout 5 # exit code 4
libby: $hsfei.pickoff.positionvalue > 15: still false after 5.0s; hsfei.pickoff.positionvalue = 11.0
Add --json to any verb for machine-readable output (objects for show /
modify / describe, list of objects for show <pattern>, list of strings
for list).
Modify syntax#
key=valueorkey value(positional) both work.Empty (
key=) andnullclear nullable values.Coercion is heuristic:
true/false→ bool, integer-looking → int, decimal-looking → float, else string.The CLI consults
keys.describefor the keyword’stimeout_smetadata before sending the modify, so slow operations (e.g. stage motion) get a longer wait automatically.--timeout <s>overrides.
waitfor#
waitfor blocks until a keyword
satisfies a comparison. Because libby daemons don’t broadcast keyword changes,
it polls the keyword over RPC rather than waiting on a monitor — --poll sets
the interval (default 0.1s).
libby waitfor '$<group>.<daemon>.<keyword> <op> <value>'
<op>is one of==,!=,<,<=,>,>=. Quote the whole expression so your shell doesn’t eat the$,<, or>.Keyword references are
$-prefixed, as in KTL.-d/--daemon <group>.<daemon>sets a default daemon so the expression can name a keyword bare:libby waitfor '$ismoving == false' -d hsfei.pickoff.KTL writes conditions parenthesized (
'($foo.BAR > 15)'); that form works too, and so does putting the keyword on the right ('15 < $foo.bar.baz').Values coerce like a
modifyvalue —falseis a bool,15an int,nullisNone. Quote to keep a value a string:'$status == "15"'. A value only needs quoting if it contains whitespace, starts with$, or looks like an operator.String comparisons are case-insensitive, matching
ktl.waitFor’scase=Falsedefault.--casecompares exactly.--timeouthere is the total time to wait, not the per-request RPC timeout, and it defaults to waiting indefinitely. Exit code is 0 if the comparison came true, 4 if the timeout expired with it still false.A keyword that has no value yet (a nullable one the daemon hasn’t populated) counts as “not true yet” and the wait continues, as in KTL. A rejected read — unknown or write-only keyword — fails immediately, since no amount of waiting resolves it.
and / or / not, arithmetic, and multi-keyword expressions are not supported yet.
Config#
The CLI looks for ~/.libby/cli_config.yaml by default; override the path
per call with --config <path>. An example template ships with the package
at libby/cli/cli_config.example.yaml — copy it and edit:
mkdir -p ~/.libby
cp $(python -c "import libby.cli, os; print(os.path.dirname(libby.cli.__file__))")/cli_config.example.yaml ~/.libby/cli_config.yaml
Schema:
transport: rabbitmq # zmq | rabbitmq
rabbitmq_url: amqp://localhost
# Used only when transport=zmq:
peers:
hsfei_pickoff: tcp://hispec.caltech.edu:5555
All keys are optional. Missing file is fine — defaults are
transport: rabbitmq / rabbitmq_url: amqp://localhost.
Precedence: --transport / --rabbitmq-url flags override yaml; yaml
overrides built-in defaults. Flags must appear after the subcommand
(libby show --transport zmq foo, not the other way).
Exit codes#
Code |
Meaning |
|---|---|
0 |
success |
1 |
argument / parse error |
2 |
RPC or response error (e.g. read-only, unknown keyword, transport failure) |
3 |
wildcard |
4 |
|