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.
- 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.
Select a step to see its command and what it checks.
- Scaffold
./yano.sh appchain plugin scaffold --mode state-machine --id shipment --package com.example.shipment --output shipment-pluginwrites a small buildable project: a provider, its ServiceLoader entry, a runtime manifest and a product catalog. Modes arestate-machine,composite-role,effect-executorandsink.- 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 signsigns 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 undercomponent-catalogs/.appchain.lockpins the catalog, runtime manifest, configuration metadata and complete JAR digests.- Check readiness
- Copy the pinned JAR into the distribution's
plugins/, thenappchain doctor <project> --distribution /opt/yano-xre-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 runtools/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 →
- publisher
- operator
- node
1. Scaffold
Section titled “1. Scaffold”./yano.sh appchain plugin scaffold \ --mode state-machine \ --id shipment \ --package com.example.shipment \ --yano-version <matching-yano-host-version> \ --output shipment-pluginReplace <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.
2. Implement and test
Section titled “2. Implement and test”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.
3. Sign
Section titled “3. Sign”Sign the exact catalog, runtime manifest, and optional configuration metadata.
./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.json4. Build and validate
Section titled “4. Build and validate”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.
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.jsoninspect 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.
5. Pin it into a project
Section titled “5. Pin it into a project”./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-chainThe 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:
cp shipment-plugin/build/libs/shipment-yano-plugin.jar /opt/yano-x/plugins/./yano.sh appchain doctor shipment-chain --distribution /opt/yano-xA 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.
7. Install on every member
Section titled “7. Install on every member”Copy the exact pinned JAR into plugins/ in every member’s distribution, then
validate the resulting set from the distribution root:
tools/yano-plugins/bin/yano-plugins validate plugins/*.jarThe 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.
Changing a plugin later
Section titled “Changing a plugin later”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.
Compare, then apply
Section titled “Compare, then apply”Save the current lock before you change the blueprint, so there is something to compare against:
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_KEYdrift 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.