Keyboard shortcuts

Press or to navigate between chapters

Press S or / to search in the book

Press ? to show this help

Press Esc to hide this help

Tools and Editors

AutoCore modules expose their configuration as a JSON Schema, and the IDE renders that as a form. Some modules need more than a form — the labelit vision module, for example, needs an image viewer with edge-detection overlays, draggable scan regions, and live placement preview. Those richer editors, and standalone utilities in general, are delivered as tools.

A tool is a standalone program — usually a small web server — that the platform knows about through the tool registry. The registry lets:

  • autocore-server supervise long-running tools (start them with the server, stop them on shutdown, restart them on demand);
  • autocore-ide discover which module domains have a rich editor and offer an Open editor action for them;
  • packages register and unregister tools automatically on install/remove.

The first tool is labelit-studio, the configuration editor for the vision (labelit) module. This chapter explains the registry, how to operate and configure tools, and how to add new ones.

Tools versus modules

ModuleTool
Connects to the server over IPCYesNo
Receives its config on the command lineYes (--config)No
Participates in the control loopYesNo
Typically a…hardware/service driverweb UI / editor / utility
Discovered fromproject.json modulesthe tool registry (tools.d/)
Examplesmodbus, ethercat, ni, labelitlabelit-studio

A tool is independent of any one project — its editor is available even when no project is loaded. The vision module (labelit) runs the camera and label placement; the vision tool (labelit-studio) edits that module’s config.

The registry on disk

Everything lives under the AutoCore config directory (/srv/autocore/config on a deployed machine; AUTOCORE_CONFIG_DIR overrides it):

/srv/autocore/config/
├── config.ini                          # server + module config
├── tools.d/                            # MANIFESTS — owned by the installing package
│   └── labelit-studio.json
└── tool-settings/                      # SETTINGS — runtime, survive upgrades
    └── labelit-studio.json

Two ideas matter:

  1. The manifest is package-owned; the settings are not. A manifest describes what a tool is (its executable, what it edits, defaults) and is shipped inside the .deb, so an upgrade replaces it freely. Settings are what an admin chose (the actual port, enabled/disabled, bind address) and live in a separate directory the package never touches, so upgrades never reset a field-configured port.
  2. dpkg owns the manifest file. A package contributes a tool simply by shipping its manifest into tools.d/. Installing the package registers the tool; removing it deregisters — handled by the package manager, with no shared file to edit.

So there are three distinct kinds of config; don’t confuse them:

ScopeLives inWho writes it
Module operational configproject.jsonmodules.<name>.configthe editor / the IDE
Tool manifesttools.d/<tool>.jsonthe installing package
Tool settingstool-settings/<tool>.jsonadmin / the tool

Manifest format

{
  "schema_version": 1,
  "name": "labelit-studio",
  "version": "1.1.3",
  "description": "Vision-pipeline configuration editor for autocore-labelit",
  "executable": "/opt/autocore/bin/modules/labelit-studio",
  "serves_http": true,
  "ui_path": "/",
  "launch": {
    "mode": "service",
    "default_port": 7878,
    "autostart": true,
    "args": []
  },
  "editors": [
    { "target_domain": "labelit", "target_path": null, "label": "Vision Editor" }
  ]
}
FieldMeaning
nameUnique tool id (kebab-case); must match the file stem.
executableAbsolute path to the binary.
serves_http / ui_pathWhether it serves a web UI, and the root path. Drives the security gate and lets a browser/IDE point at it.
launch.modeservice (long-running; the server supervises it) or on_demand (invoked by the IDE/CLI; never auto-started).
launch.default_portDefault HTTP port; the effective port comes from settings.
launch.autostartDefault for starting with the server; effective value comes from settings.
launch.argsExtra arguments inserted before the standard --port/--bind.
editors[]The config editors the tool contributes. Each binds to a module target_domain and an optional target_path (a JSON pointer into that module’s config). null path = the whole module config. One tool may contribute several.

Settings format

{
  "launch": {                 // the SERVER reads exactly these fields
    "enabled": true,
    "port": 7878,
    "bind": "127.0.0.1",
    "autostart": true
  },
  "extra": {                  // free-form, tool-private; the server never parses it
    "last_image_dir": "/home/me/snaps"
  }
}

The file is created on first run, seeded from the manifest’s launch defaults. After that, on-disk values win — so an admin’s port choice survives upgrades.

Security gate. A serves_http tool is an unauthenticated surface (it can edit config and, on a target, trigger the camera). Until AutoCore adds user authentication, bind defaults to 127.0.0.1 (loopback only). Binding a tool to a routable address is a deliberate admin choice — prefer reaching it over Tailscale rather than exposing it on the LAN.

How the server runs tools

On startup the server scans tools.d/. For every manifest with launch.mode = "service" whose settings have it enabled with autostart, it launches:

<executable> [launch.args...] --port <settings.port> --bind <settings.bind>

and stops it on shutdown — the same lifecycle as a module, but discovered from the registry instead of project.json. on_demand tools are not auto-started.

Two server commands manage this at runtime (also reachable with acctl, below):

CommandEffect
system.list_toolsList registered tools with live running state and URL. Used by the IDE to discover editors.
system.rescan_toolsRe-read the registry: start newly installed service tools, stop removed/disabled ones, leave the rest running.

acctl tools

acctl tools list      # what the server discovered, with running state + URL
acctl tools rescan    # reconcile running tools with the registry, no restart

acctl tools list prints each tool, whether it is running, its URL, and the module domains it edits. acctl tools rescan is what package scripts call so an install or uninstall takes effect on a running server without a restart.

Registering a tool from a package

A .deb registers a tool with two pieces:

  1. Ship the manifest as a packaged file into tools.d/. In Cargo.toml (cargo-deb):

    [package.metadata.deb]
    assets = [
        ["target/release/labelit-studio", "/opt/autocore/bin/modules/", "755"],
        ["packaging/tools.d/labelit-studio.json",
         "/srv/autocore/config/tools.d/labelit-studio.json", "644"],
    ]
    

    Because dpkg owns the file, install registers and remove deregisters — no maintainer-script logic needed for the registration itself.

  2. Poke a running server so the change is live, from postinst/postrm:

    poke_rescan() {
        for ACCTL in acctl /opt/autocore/bin/acctl; do
            if command -v "$ACCTL" >/dev/null 2>&1; then
                "$ACCTL" tools rescan >/dev/null 2>&1 || true
                return 0
            fi
        done
    }
    

    This is best-effort: if the server is down or acctl is absent, the tool is picked up on the next server start anyway.

labelit-studio: the worked example

labelit-studio is a web-based editor for the vision pipeline — it loads images, runs the exact production pipeline the labelit module runs, shows each stage (edges, masks, placement) with overlays, has TM-X-style tools (Canny, threshold, HSV mask, pixel probe), drag-to-set scan/background regions, and the calibration wizards (checkerboard, known-size, auto-canny). What it shows for a given config is, by construction, what the module will do with that config.

It runs in three contexts — the same binary every time:

1. Standalone (laptop / conference demo)

No server, no project. Build it (or install the .deb) and run it against local images:

# from an autocore-labelit checkout
cargo build --release --bin labelit-studio
./target/release/labelit-studio --config project.json --images ./snaps --port 7878
# then open http://localhost:7878/

--config points at any project.json (or a module-level config export); --images is a file or folder; you can also open files from inside the UI. Use --bind 0.0.0.0 only if you want another device on the network to reach it.

2. On a target (server-supervised)

Install autocore-labelit on the machine. The deb ships the binary and its manifest, and the running server starts it automatically (loopback, port 7878 by default). An operator with only a browser opens it:

http://<target>:7878/

To change the port, enable/disable it, or bind it wider, edit /srv/autocore/config/tool-settings/labelit-studio.json and run acctl tools rescan (or restart the server). Remember the security gate before changing bind.

3. In the IDE (autocore-ide)

Open your project in VS Code / VS Codium. In the autocore Project view, the labelit module shows an $(preview) Open editor action. It spawns labelit-studio as a local sidecar against your workspace project.json and hosts its UI in a panel — fully offline, no server needed. The IDE remains the sole writer of project.json (it preserves your comments and formatting). See the autocore-ide manual for details and the autocore.labelit.studioPath / autocore.labelit.imagesDir settings.

Building a self-contained studio

For a binary that runs on a clean machine with no apt install (the field .deb, or bundling into the IDE .vsix), labelit-studio is built camera-free and against a static OpenCV:

  • The studio never opens a camera directly (on a target it snaps through the module over IPC), so Aravis/GLib is behind the default-on camera feature and is dropped with --no-default-features.
  • A minimal static OpenCV removes the libopencv runtime dependency.
# in the autocore-labelit repo
OPENCV_VERSION=4.10.0 PREFIX=/opt/opencv-static ./scripts/build-static-opencv.sh
PREFIX=/opt/opencv-static ./scripts/build-studio-selfcontained.sh
# -> target/release/labelit-studio, ldd shows only glibc / ld-linux

The full recipe (and how to wire the result into the deb and the vsix) is in the autocore-labelit repo’s doc/static-build.md.

Adding a new editor

To give another module (say an EtherCAT slave-tree editor) a rich editor:

  1. Build the tool as a standalone HTTP server that accepts --port and --bind. (It can be anything — the registry only cares about the manifest.)
  2. Write a manifest declaring serves_http: true, launch.mode: "service", and an editors entry whose target_domain is the module domain it edits.
  3. Ship it in the tool’s package: the binary plus the manifest as a dpkg-owned file in tools.d/, and a postinst/postrm rescan poke.
  4. (Optional) Teach the IDE about it offline by adding it to the IDE’s bundled fallback list, so the Open editor action appears without a live server connection.

The server will discover and supervise it; the IDE will offer it for that module domain; acctl tools list will show it. No changes to autocore-server or autocore-ide core are required to add a tool.