Skip to content

Scaffold, sign, install

Seven steps from nothing to a running plugin. None of them require touching Yano. Select a step to see its command and what it checks.

From scaffold to every memberConcept
BUILD AND SIGN · PUBLISHERDEPLOY · OPERATORScaffoldplugin scaffoldImplement + testcodec, rules, testsSignplugin signBuild + validateplugin validatePin into a projectinit --plugin-jarCheck readinessdoctor --distributionInstall onevery membercopy to plugins/Node loads itstart-up checkssigned JARBUILD AND SIGN · PUBLISHERDEPLOY · OPERATORScaffoldplugin scaffoldImplement + testcodec, rules, testsSignplugin signBuild + validateplugin validatePin into a projectinit --plugin-jarCheck readinessdoctor --distributionInstall on every membercopy to plugins/Node loads itstart-up checkssigned JAR
  • Build and sign · publisher: Scaffold, Implement + test, Sign, Build + validate.
  • Deploy · operator: Pin into a project, Check readiness, Install on every member, Node loads it.
  • Scaffold → Implement + test.
  • Implement + test → Sign.
  • Sign → Build + validate.
  • Build + validate → Pin into a project (signed JAR).
  • Pin into a project → Check readiness.
  • Check readiness → Install on every member.
  • Install on every member → Node loads it.
Scaffold
./yano.sh appchain plugin scaffold --mode state-machine --id shipment --package com.example.shipment --output shipment-plugin writes a small buildable project: a provider, its ServiceLoader entry, a runtime manifest and a product catalog. Modes are state-machine, composite-role, effect-executor and sink.
Implement + test
Write the codec, the admission check and the deterministic transitions, then climb the testing ladder. The generated provider does no business work until you implement it. Testing and deployment →
Sign
plugin sign signs the exact catalog, runtime manifest and optional configuration metadata with a publisher seed passed by file. The signature authenticates those bytes. It does not approve the code. SPI and manifest →
Build + validate
Build the JAR, then plugin validate <jar> --trust-key <key-id>=<public-key> verifies the signature and exports a data-only catalog snapshot. It loads no provider class.
Pin into a project
appchain init --plugin-jar <jar> --trust-key … stores the signed snapshot under component-catalogs/. appchain.lock pins the catalog, runtime manifest, configuration metadata and complete JAR digests.
Check readiness
Copy the pinned JAR into the distribution's plugins/, then appchain doctor <project> --distribution /opt/yano-x re-verifies the snapshot. A pinned JAR that is missing or different fails artifact readiness.
Install on every member
Copy the exact pinned JAR into plugins/ on every member, then run tools/yano-plugins/bin/yano-plugins validate plugins/*.jar. A member with a different JAR can compute a different root and stall.
Node loads it
At start-up the node snapshots, scans and correlates the JAR, checks its API range, and builds one shared loader before any plugin code runs. It does not verify the publisher signature. How plugins load →
A publisher builds and signs the bundle; an operator pins it into a project, checks readiness and installs the same JAR on every member. Yano itself is never rebuilt.
  • publisher
  • operator
  • node
Terminal window
./yano.sh appchain plugin scaffold \
--mode state-machine \
--id shipment \
--package com.example.shipment \
--yano-version <matching-yano-host-version> \
--output shipment-plugin

Replace <matching-yano-host-version> with the exact Yano version in your distribution manifest (see the current version table). This is the host version, not the Yano X plugin version.

Modes are state-machine, composite-role, effect-executor, and sink. All four share the same runtime manifest, signed product catalog, and ServiceLoader conventions.

The generated provider deliberately does no business work: state-machine admission is closed and executor/sink factories return no instances until you implement them. The tool refuses a non-empty output directory.

Write the codec, the admission check, and the transitions. A state machine’s only execution entry point is apply(AppBlockExecutionContext, AppStateWriter, AppEffectEmitter); Tutorial 8 shows a complete machine. Before you write it, read Determinism rules — the constraints are strict and the failure mode (a cluster that stops finalizing) is expensive to debug.

Then work up the testing ladder.

Sign the exact catalog, runtime manifest, and optional configuration metadata.

Terminal window
./yano.sh appchain plugin sign \
--catalog shipment-plugin/src/main/resources/META-INF/yano/appchain-component-catalog-v1.json \
--runtime-manifest shipment-plugin/src/main/resources/META-INF/yano/plugins/plugin-bundle.shipment.json \
--seed-file /secure/publisher.seed \
--key-id example-release-2026 \
--output shipment-plugin/src/main/resources/META-INF/yano/appchain-component-catalog-v1.sig.json

The scaffold ships no Gradle wrapper, so install a Gradle that supports Java 25 (9.1 or later) or add your organization’s wrapper first. Sign before you build: the signature is packaged inside the JAR.

Terminal window
cd shipment-plugin && gradle jar && cd ..
./yano.sh appchain plugin validate shipment-plugin/build/libs/shipment-yano-plugin.jar \
--trust-key example-release-2026=<64-hex-public-key> \
--output shipment-catalog.json

inspect prints the same verified catalog and its capabilities.

Neither command loads provider classes, runs plugin code, fetches a registry, or installs the JAR. The exported snapshot is the safe, data-only local-import format used by Studio and by generated projects.

Terminal window
./yano.sh appchain init --non-interactive \
--recipe custom-plugin --network devnet --members 3 --runtime jvm \
--capability state:shipment \
--plugin-jar shipment-plugin/build/libs/shipment-yano-plugin.jar \
--trust-key example-release-2026=<64-hex-public-key> \
--output shipment-chain
./yano.sh appchain config validate --mode project shipment-chain

The project stores the signed data-only snapshot under component-catalogs/. Its lock pins the snapshot, the catalog, the runtime manifest, the configuration metadata, and the complete plugin-JAR digests. Rendering and doctor reverify the project snapshot automatically.

6. Check readiness against a real distribution

Section titled “6. Check readiness against a real distribution”

doctor checks the distribution you will run, so copy the pinned JAR into its plugins/ directory first:

Terminal window
cp shipment-plugin/build/libs/shipment-yano-plugin.jar /opt/yano-x/plugins/
./yano.sh appchain doctor shipment-chain --distribution /opt/yano-x

A missing or different JAR fails artifact readiness with pinned plugin digest is absent from distribution plugins/. A native distribution reports a direct incompatibility, because Yano X plugins target the JVM host.

Copy the exact pinned JAR into plugins/ in every member’s distribution, then validate the resulting set from the distribution root:

Terminal window
tools/yano-plugins/bin/yano-plugins validate plugins/*.jar

The plugin directory property is yano.plugins.directory. Restart the nodes; Yano is not rebuilt. At start-up each node checks the JAR again before any plugin code runs; How plugins load lists those checks.

Adding a member or a node is routine. Changing what a plugin computes is not — see Consensus rules. In short:

  • Give every bundle a stable plugin id and a semantic version.
  • Never silently change semantics behind an existing machine or component id.
  • Use activation heights and profile governance for compatible evolution.
  • Use a new namespace and a migration plan for incompatible state.

Save the current lock before you change the blueprint, so there is something to compare against:

Terminal window
cp shipment-chain/appchain.lock previous.lock
# ...edit the blueprint and re-render the project...
./yano.sh appchain diff previous.lock shipment-chain/appchain.lock
./yano.sh appchain migrate shipment-chain --dry-run
./yano.sh appchain drift shipment-chain --peer http://node-a:8080/api/v1/ \
--api-key-env YANO_OPERATOR_API_KEY

drift reads node identities through the privileged API, so set YANO_OPERATOR_API_KEY to one of the keys in the nodes’ YANO_APPCHAIN_API_KEYS; without it the nodes answer HTTP 401. The key is read only from the environment, never from the command line.

diff classifies a blueprint change before you apply it. drift compares a project against running nodes when identities are available, including each node’s plugin catalog fingerprint — the fastest way to find the one member that is out of step.