Online edits
nautilus has two planes. The cold plane — connections, the tag manifest, scan classes, server wiring — is Go, and changes ship through CI/CD as a new binary. The hot plane — the IEC program and tag values — can change live, the way you online-edit a traditional PLC. Because the program is data on a VM, a warm swap carries retained state (PID integrals, timers, counters) across by name and type; a failed compile leaves the running program untouched, so a typo can never fault the controller.
Enable it per controller (off by default — pushing logic is code execution on a control system):
srv := server.New(rt, server.Options{OnlineEdits: true})Then from VS Code: Download Program to Controller warm-swaps your open program, Diff Program with Controller shows running-vs-workspace, and a status-bar indicator flags when the controller runs something other than the committed file.
b3fbc32 · VS Code 1.139.1 · PASS · rig nightly · C01 on the proof pageWithout a retain store, a restart
reverts to the program the binary embeds. With retain: configured, online
edits survive a restart (or a failover) of the same build: the edited source
is saved and reloaded before the first scan. A deploy of a different build
replaces them, as a download does on a PLC: when the binary’s program for a
task has changed since the edit was made, the edit is discarded (logged, and
named in the diagnostics as retainDiscardedEdits) and the deployed program
runs. The discarded source is kept in the retain store under
discardedPrograms.<task> (the last one per task, never applied), so an
edit deployed over by mistake can still be recovered:
jq -r '.discardedPrograms.main' retain.json # file storekubectl get configmap <name>-retain -o jsonpath='{.data.state}' \ | jq -r '.discardedPrograms.main' # in a clusterPull an edit into git before you deploy over it; committing the program to git is the only way an edit becomes permanent. The rule of thumb falls out of the two planes: logic you want to tune online, write in IEC; infrastructure, write in Go.
Tag values are the other half of the hot plane: Set Live Value writes a tag once, and a force holds one against the field and the logic until it is removed — see Forcing, which also covers jumping a running SFC chart to a step.
Pulling field edits back
Section titled “Pulling field edits back”Pulling a field edit back to git closes the loop. Pull Program from
Controller (VS Code) or naut pull --host <controller> writes the
running program back into your program file — the inverse of download — so
you review it with git diff and commit. Only the program file is rewritten;
generated type files are never touched. naut pull --check reports drift
and exits non-zero, so CI can fail a build when a controller has un-pulled
edits. Composition is a single definition shared by the runtime, the language
server, download, and pull, so a program round-trips losslessly.
In VS Code, Pull previews the change and asks before writing. If the program file is open, the pull goes through its editor — the text and any diagram view show the controller’s program, and the file is saved — so the editor and the disk never disagree. If the file has unsaved edits, the confirmation says so: Overwrite replaces them with the controller’s program, and Show Diff puts the controller’s program beside your buffer instead, so you can take lines across by hand and pull nothing.
b3fbc32 · VS Code 1.139.1 · PASS · rig nightly · C09 on the proof pageWhat a download sends is the program’s composition: the project’s
library prelude — every PROGRAM-less .st file in the root and under lib/,
verbatim, then every PROGRAM-less .ld / .fbd file transpiled to ST — then
the program file as written (a .ld program stays ladder; the controller
transpiles it and reports the original). VS Code asks the CLI for it rather
than re-deriving it, so a program that calls a block written in ladder
downloads with that block; it needs naut 0.13.0 or newer. To see exactly
what a download of a program will send, run naut compose <program file>
(--json splits it into prelude, program, POU, and library paths).
Working against a remote controller
Section titled “Working against a remote controller”All of this — live values, online edits, pull — works over the network, not
just against a local process. A scaffolded controller binds loopback by
default; set NAUTILUS_ADDR=0.0.0.0:8080 to expose the tag API to other
machines, and point the editor at it with the nautilus.runtimeUrl setting
(naut pull takes --host). Exposing the API on the network also
exposes its write surface, so set NAUTILUS_TOKEN on the controller and the
matching nautilus.token in the editor — reads and naut pull stay
open, but tag writes and online edits then require the token.
Every program, both directions
Section titled “Every program, both directions”Programs are addressed by POU name — PROGRAM <Name> is a program’s
identity. GET /api/program lists the resource’s programs; a PUT routes
automatically by the POU name in the submitted source, and ?pou= / ?task=
select one explicitly for GET/rollback. In VS Code that means a workspace
with one program file per task Just Works: open the file, Download/Diff/
Rollback target that task’s program, retained state carries across the swap.
And naut pull reconciles the whole resource: every controller program
pulls back into the workspace file declaring its POU (a new program lands in
<POU>.st/.fbd), so a field edit to any task is reviewable and
committable — --check fails CI on drift in any of them.
Editing against history
Section titled “Editing against history”The controller also carries its own git provenance: every commit that touched the project, reviewable as diffs and warm-swappable as a whole — “run the logic from three commits ago” is one request, with the same gates, state migration, and rollback as any online edit. See Program history.