Developing Yano X
This is the contributor track. If you only want to run Yano X, you want Build from source instead — it needs no flags and no Yano checkout.
You are here because you are changing Yano X itself, or changing Yano and Yano X together.
Two repositories
Section titled “Two repositories”bloxbean/yano the host: Cardano data node, minimal app-chain host, public plugin SPI, generic runtime/REST/operations, anchoring and proofs, OrderedLog. GraalVM is its primary deployment target; it also publishes Java artifacts and an ordinary JVM ZIP for Yano X.
bloxbean/yano-x JVM extensions and products. Dependency direction is strictly yano-x -> yano.Coordinated local development
Section titled “Coordinated local development”When your change spans both repositories, publish the Yano inputs first:
# In the Yano repository.cd /path/to/yano./gradlew publishToMavenLocal :app:yanoDistZip -PskipSigning=true --no-parallelThen build Yano X against exactly that version:
cd /path/to/yano-x./gradlew test verifyArtifactInventory verifyJvmOnlyBuild \ -PyanoVersion=<published-yano-version> \ -PuseMavenLocal=true --offlinemavenLocal() is disabled unless -PuseMavenLocal=true. The Maven version and
the JVM ZIP identity must match exactly; for a SNAPSHOT or staged version also
pass -PyanoJvmDist=/absolute/path/to/yano-<build-identity>.zip.
The gates
Section titled “The gates”Choose gates in proportion to the change, but do not stop at unit tests when a plugin, catalog, distribution, persistence, consensus, proof, anchor, or cross-node behavior changed.
# Focused, while iterating../gradlew :state-machines:stdlib:test -PyanoVersion=<v>./gradlew :tooling:devtools:test -PyanoVersion=<v>./gradlew integrationTest -PyanoVersion=<v>./gradlew cryptoTest -PyanoVersion=<v>
# A full clean build, which also validates the release archives../gradlew clean build -PyanoVersion=<v> -PskipSigning=true
# Release rehearsal: publish every coordinate to a NEW EMPTY directory../gradlew publishAllPublicationsToInternalRepository \ -PinternalRepository=/absolute/path/to/empty/yano-x-staging \ -PyanoVersion=<v> -PskipSigning=true| Gate | Run it when |
|---|---|
verifyArtifactInventory | Any module, publication, manifest, bundle, or contribution change. Checks that each module has exactly one declared artifact identity and that runtime plugins have bundle publications. |
verifyJvmOnlyBuild | Build topology changes. Rejects accidental native-image tasks. |
integrationTest / cryptoTest | Their domains changed. |
distributionCheck or a clean build | Dependency, bundle, class-isolation, launch, or packaging changes. |
| Showcase contracts | Showcase changes: ./gradlew :examples:showcase:showcaseScriptContract :examples:showcase:showcaseDistributionContract |
Runtime and persistence changes
Section titled “Runtime and persistence changes”Validate a real multi-node cluster: identical chain height, root, profile, genesis, and capability-manifest digest across members; finality certificates; proof retrieval; catch-up and restart; and anchor state where applicable.
Persistence changes additionally require apply, rollback, replay, restart, and
root-parity checks. Derived indexes must never advance beyond authoritative
app-chain state, and must remain separate from L1 chainstate.
Architecture invariants
Section titled “Architecture invariants”These are the rules a reviewer will hold you to. The full list lives in
AGENTS.md.
- Every optional behavior added to a running node crosses the plugin catalog boundary — stock state machines, capabilities, connectors, effects, observers, indexers, and product runtime behavior.
- Pure libraries, DTOs, clients, codecs, testkits, CLIs, on-chain validators, and deterministic helpers are not runtime plugins unless the host independently selects or manages them.
- Runtime activation goes through
PluginProviderRegistryand a schema-v1 manifest. No rawServiceLoader, direct host construction, product switches, or product-specific host CDI/REST activation. - Runtime plugins publish dependency-complete bundles, do not embed host SPI classes, declare compatible Yano API major and min/max levels, and have bounded lifecycle cleanup.
- Package names remain
com.bloxbean.cardano.yano.appchain.*; repository and artifact names useyano-x. - The plugin directory property is
yano.plugins.directory. Do not reintroduceyaci.plugins.directory. - Yano X is JVM-only.
- The app-chain feature has not had a public release: remove obsolete adapters, aliases, and duplicate activation paths rather than preserving accidental compatibility. Preserve documented Cardano node, OrderedLog, wire/storage, proof, replay, and distribution invariants.
- Do not duplicate the artifact inventory in build logic or documentation.
Update
config/artifacts-v1.jsonand its verification tests.
Coding conventions
Section titled “Coding conventions”- Java 25, four-space indentation, lines at most 120 characters.
- Prefer package imports to fully qualified names.
- SLF4J for logging.
- JUnit 5, Mockito, AssertJ. Unit tests in
src/test/java; integration tests in the configured integration source sets, normally named*IT. - License: MIT.
For deterministic state, avoid wall-clock time, randomness, environment-dependent iteration order, network calls, and node-local mutable decisions. Version any change to consensus semantics, state encoding, commitment profile, proof subject, or genesis-selected configuration — see Consensus rules.
Working-tree and Git safety
Section titled “Working-tree and Git safety”- Inspect
git status --shortbefore editing. Preserve unrelated or overlapping user changes. - Never stage or commit automatically. Before committing, show the exact files and diff intended and get approval.
- Do not delete retained clusters, state, keys, or staging repositories without
reviewing the exact path and obtaining explicit authorization.
stoppreserves state;reset --yesis destructive. - Keep ADRs, implementation, tests, artifact inventory, and user docs aligned when architecture or behavior changes.
- Preprod operations submit real test-network transactions and spend test ADA. Require explicit authorization before fresh deployment, anchor bootstrap, settlement bootstrap, or smoke traffic. Never print seed contents, signing material, API credentials, or effect secrets.
Working on this documentation site
Section titled “Working on this documentation site”The site lives in docsite/ and is independent of the Gradle build — it reads
repository text files only, so it needs no Java and no Yano artifacts.
cd docsitenpm cinpm run dev # imports repo docs, then serves on localhost:4321npm run build # imports, builds to dist/, generates the AI artifactsnpm run import regenerates the imported tutorial and state-machine pages from
docs/, mirrors the App-Chain Studio into public/studio/, and re-renders every
<!-- catalog:... --> block from the repository’s JSON catalogs. An unresolvable
relative link in an imported document fails the build rather than shipping a
404.
Edit the sources under docs/ for imported pages, and
docsite/src/content/docs/ for authored ones. Never hand-edit content between
catalog anchors — it is regenerated.
The site’s content strategy and design decisions are recorded in ADR-038, in
the repository’s adr/ directory.
Sources of truth
Section titled “Sources of truth”Read only what the task needs:
| Topic | Source |
|---|---|
| Repository split and ownership | ADR-030, in adr/refactoring/ |
| Plugin SPI and lifecycle | ADR-011, in adr/app-layer/ |
| Composition and portable proofs | ADR-031, in adr/app-layer/ |
| Module topology | settings.gradle |
| Artifact ids and bundle ids | config/artifacts-v1.json |
| Build workflows | BUILD_AND_TEST, BUILD_DISTRIBUTIONS |
| Open work | adr/app-layer/open_item.md |