Your first plugin
This tutorial creates a small native plugin in its own directory. Install the
cargo-dokime extension through Cargo from the Git revision published with
your release. Rust supplies rustc and cargo; Cargo discovers the extension
when you type cargo dokime.
The desktop installer installs the GUI and
the dokime CLI side by side and puts both on your PATH; cargo-dokime is
a separate Cargo install.
cargo install --git https://gitlab.com/stokker-technologies/open-source/dokime.git --rev <release-revision> --locked cargo-dokimeUse the full source revision recorded by the release in place of
<release-revision>.
1. Check your development tools and source access
Section titled “1. Check your development tools and source access”Install Rust with rustup, Git, and the native build tools. On Windows, use Rust’s MSVC toolchain with Visual Studio Desktop development with C++ build tools and the Windows SDK. Restart your terminal or editor after installation so it sees the updated PATH.
rustc --versioncargo --versiongit --versioncargo dokime --versionThe starter depends on the Dokime SDK from Git, pinned to the full revision
recorded in crates/sdk-pin.rs and embedded in your CLI. This committed pin
is independent of local commits, forks, and environment variables. It also
fetches Dokime’s pinned Harmos dependency.
Your GitLab account and local Git authentication must allow access to both
repositories:
git ls-remote https://gitlab.com/stokker-technologies/open-source/dokime HEADgit ls-remote https://gitlab.com/stokker-technologies/open-source/harmos HEADIf either command reports an authentication or access failure, configure your Git credential helper and obtain repository access before building. A successful application installation does not grant GitLab source access. The release’s SDK revision must remain available from its Git source for a fresh build to work. Keep the generated Git dependency when starting from this release.
If Git authentication works but Cargo cannot fetch the same repository, Cargo
can use your Git CLI credential setup. Add this to .cargo/config.toml in the
plugin project, merging it with any existing configuration:
[net]git-fetch-with-cli = true2. Generate the plugin
Section titled “2. Generate the plugin”From an existing parent directory:
cargo dokime new my-plugincd my-pluginnew generates from templates embedded in the installed CLI and does not need
network access. The first Cargo build fetches the SDK and its dependencies.
The directory name becomes the package name; use --name NAME to choose another
name. The command refuses to overwrite an existing destination.
The project is one native plugin crate holding a small thermal bench. src/lib.rs
names the catalogs of types the plugin contributes and implements
dokime::Plugin — its configuration, error and resource types, its settings,
and the handles it opens once; src/main.rs starts the native process;
src/error.rs holds the one error type every fallible signature answers with —
a domain variant per thing the bench can discover, plus Sdk(#[from] dokime::Error)
wrapping every SDK boundary the template reaches (a setting, a secret, a
prompt, a captured record, an evidence file) once, instead of one variant per
boundary;
src/bench.rs is the simulated sensor and heater, which is the one file that
pretends and the first to replace with a real driver; and src/suites/soak/hold.rs
is the procedure — its parameters, the handles one attempt owns, the
traceability it states, its steps, its own sampler, its two criteria and its
cleanup. The layout is vertical for the rest: src/samplers/, src/listeners/
and src/routes/ each hold a mod.rs with nothing but the catalog enum, and
one file per contribution — a sampler beside the row type it measures, a
listener, a route. The generated README explains the rest. Keep the SDK
Git revision in Cargo.toml and commit the generated Cargo.lock after
resolving dependencies so teammates build from the same sources.
Two curated preludes are the canonical opening of those two kinds of file.
src/lib.rs, and every file under src/samplers/, src/listeners/ and
src/routes/, open with the plugin’s own:
use dokime::plugin::prelude::*;src/suites/soak/hold.rs, and every template file, open with the one a
template writes against:
use dokime::prelude::*;Each glob names everything that kind of file typically needs — the lifecycle
trait and its contribution traits on the plugin side, the six stage grants
and the document types on the template side — so one import replaces the
handful of dokime::execution::…, dokime::document::… and
dokime::plugin::… paths an earlier SDK required. Keep a named import
beside it for anything a file uses outside that set; neither prelude carries
Error, Result, Value, Parameter, a builder type, or a raw map,
because a plugin declares its own Error and Result and a glob that
shadowed either is the one collision that bites.
The embedded starter is the primary starting point and uses every part of the authoring surface. The shipped Synthetic example is a fuller application and device bench; use it when you need an embedded Harmos runtime.
3. Run the desktop smoke check
Section titled “3. Run the desktop smoke check”cargo dokime devBefore compilation, the CLI reports the selected host and the CLI, host, and SDK
versions and checks their supported compatibility series. By default it finds the
Dokime installed by the desktop installer automatically; pass --dokime PATH to
point it at a different host explicitly. Passing this early check still leaves
normal bundle validation and runtime catalog admission to the host.
The command builds a bundle and starts an isolated development backend. The
GUI attaches to its native gRPC readiness endpoint and closes with the
supervised backend. Use cargo dokime dev --headless for terminal-only
development. To attach a separate GUI, run cargo dokime gui --endpoint http://127.0.0.1:8765
with the printed native endpoint. Select another backend port with cargo dokime dev --port 8766.
In Plan, select the Thermal Soak suite and the Hold at Temperature template. Start the cycle from Execution. Check that the steps run through to Operator Check and that Temperature stayed in band passes, and look at the Traceability card for the serial number and firmware the template read off the simulated heater. Turn the Ask the operator to sign off parameter on to see the checkpoint prompt. This confirms that the generated catalog was admitted, the native plugin executed, and its evidence reached the desktop GUI.
The Telemetry view carries more than the soak’s own sampler. The template
attribute in src/suites/soak/hold.rs names samples(host::System), which asks
the host to lease the machine channel — cpu, memory and battery — for every
execution of this template, so its rows are captured as that run’s evidence
beside the ones the soak measures itself. Name the other host channels there in
the same way when a bench correlates the machine’s radios against the unit:
host::Network, host::Wifi, host::WifiLatency, host::WifiChannelOccupancy
and host::Bluetooth. Nothing in that list states a cadence, because the
cadence is not the requester’s to choose: each channel’s sampler declares how
often it measures, and every execution leasing it shares the one running
instance and its tick. The Traceability card also carries a derived
Leases section naming which channels the attempt held and for how long.
The development host uses temporary runtime data and loads only the plugin
bundle under development. Add --state-dir PATH if you want to retain
development history between sessions. For an existing Cargo workspace, select the member from its root:
cargo dokime dev -p my-pluginPlugin secrets and .env
Section titled “Plugin secrets and .env”If your plugin declares a settings catalog secret with an environment
default, the development host resolves it the same way the installed CLI
does: an already-exported variable always wins, otherwise it searches
upward from its working directory for a .env file — the same directory
cargo dokime dev was invoked from, unless you pass --cwd DIR. This
walk-up can silently pick up an unrelated .env from a parent directory
(for example, a monorepo root) with a stale value for the same variable
name, which reaches your plugin without any error — the classic way a
variable you are sure you “set” still shows up wrong.
Use cargo dokime dev --env-file PATH to pin exactly one file instead of
searching; a missing file is refused rather than silently skipped. The dev
banner states where the environment comes from — the explicit file, the
.env the walk-up found, or that none was found — and lists the name of
every environment secret your plugin’s settings declare, with whether each
is present and non-empty in the environment the host will get. Names only:
values are never printed. The host reads its environment once, at startup,
so editing the file or re-exporting a variable requires restarting dev
(type q and Enter, then run it again) — a hot reload alone does not pick
up the change.
4. Edit and rebuild
Section titled “4. Edit and rebuild”Keep dev running. In src/suites/soak/hold.rs, change the Hold step label,
save, and watch the terminal. Dev rebuilds while the current host
continues serving. Once the build succeeds, it cancels this plugin’s active
executions, waits for their evidence and resources to settle, and replaces only
the plugin. The host, browser connection, selected case, and entered inputs stay
available. Use Re-run to execute the new build; previous attempts keep their
original snapshots and evidence.
Add --rerun to automatically re-run the most recently executed case from this
plugin after each successful reload. First select and run a case in the browser.
Each automatic re-run adds an attempt with the retained case inputs and the new
plugin catalog. Automatic execution is off by default.
An initial compilation or metadata failure leaves dev watching for your fix.
If a rebuild fails after a host has started, that host remains available. Fix the
error and save again; the next successful build can replace it. An invalid bundle
leaves the old plugin running. If replacement initialization fails after the old
plugin stops, the host stays available and dev waits for a fix. Type r and Enter
to retry without editing a file, or q and Enter to stop.
The terminal shows build, cancellation, reload, and readiness phases with full
iteration timing. A failed step prints its message, its cause chain, the source
location, and the spans it happened inside; a panic inside a step prints the same
block rather than killing the plugin process. See
what a failure carries. Add --verbose
for detailed runtime tracing. Cargo diagnostics
appear live on stderr. Use --color never for plain logs or --color always to
force color; the default is --color auto.
Cargo compilation and metadata have no default timeout, including the first
build’s dependency downloads and compilation. To impose a deadline, use
--cargo-timeout SECONDS, such as cargo dokime dev --cargo-timeout 1200.
The limit applies separately to every Cargo invocation. Catalog export and the
rustc host probe retain their own bounded deadlines.
Press Ctrl-C to stop development work and shut down the development host. The generated project also runs its whole procedure without the browser:
cargo testtests/soak.rs is that test, and it is written the way the plugin is used.
dokime::plugin::testing::Harness supplies what a host would have supplied and
hands back a typed report of what the run produced:
use dokime::plugin::testing::Harness;use dokime::host::ToolConnectionAcquired;
let report = Harness::template("my-plugin.soak.hold") .parameter("hold_samples", 3) .setting("sensor_port", "sim") .publish(ToolConnectionAcquired { resource_id: "sim-chamber-1".into(), resource_kind: "chamber".into(), connection_transport: None, connection_endpoint: None, status_message: None, }) .run::<my_plugin::Plugin>(my_plugin::Config::default()) .await .expect("the soak runs");
assert!(report.passed(), "{}", report.diagnostics());assert_eq!(report.traceability("dut").row("firmware").text(), "sim-1.0");.parameter, .setting and .secret are the case and the admitted values;
.publish files a record the way the host files one — as the declared type
itself, so the test names no id — and a step that waits for another party finds
it; .answer(prompt_type, action, values) decides an operator question, and a
prompt nobody answers is continued from the template’s own declaration rather
than left hanging. The report exposes passed(), criteria(),
samples::<C>() and records::<R>() read back through the same declarations the
run published through, traceability(section), artifacts() and the
diagnostics() of a failure. It tests authored execution
in process; the desktop check still exercises host admission and transport.
Generated starters retain the API supported by their published SDK pin.
Before troubleshooting a first build, run cargo dokime doctor (with -p NAME
in a workspace). It checks tools, host compatibility, SDK dependency access, and
watched paths without compiling the plugin.
Both build and dev accept --features, --all-features, --no-default-features,
--locked, and --offline. Use --watch PATH for extra build inputs and
--ignore PATH for generated files. Workspace Cargo configuration and toolchain
files are watched automatically. An unchanged bundle does not interrupt a plugin.
5. Build and install a release bundle
Section titled “5. Build and install a release bundle”cargo dokime build --releasecargo dokime inspect target/dokime/my-plugin-0.1.0.dokimeUse the output path printed by build if you changed the package name, version,
or target directory. Build diagnostics go to stderr; stdout contains the final
bundle path. inspect writes JSON describing the verified bundle without
running its executable.
Stop dev, start your normal Dokime application, then install into that host through its native gRPC endpoint:
cargo dokime install target/dokime/my-plugin-0.1.0.dokime --endpoint http://127.0.0.1:8765Use your application’s actual native endpoint if it differs. Review the destination, package, executable owners, and requested authorization before consenting. You can also upload the bundle through Settings → Plugins. Restart the normal application to activate the installation; installation consent does not restart it for you. Repeat the soak in that application after restart.
See plugin bundles for multiple executables, assets, installation recovery, and the complete build and activation contract.