Imported from decentralized-identity/didwebvh-java (
docs/AGENTS.md). Install upstream withnpx skills add decentralized-identity/didwebvh-java --skill docs. Copyright stays with the author.
Agent and Contributor Guide
This document provides instructions for AI agents and human contributors working on the didwebvh-java project.
Project Overview
This is a Java 11+ library implementing the did:webvh v1.0 specification. It enables creating, resolving, updating, and deactivating did:webvh DIDs with pluggable key management.
Guiding Principles
- Simplicity over abstraction. A developer should be able to read through the codebase and understand it without tracing through many layers. Use design patterns only when they earn their keep (e.g., the
Signeradapter pattern, builders for log entry composition). - SOLID, but not academic. Single Responsibility and Dependency Inversion are key (the
Signerinterface is a good example). Don't create interfaces for things that will only ever have one implementation. - Java 11 baseline. No
varin public API. No records. No sealed classes. Use standard Java 11 features. Dependencies must also support Java 11. Newer JDKs may run the library, but code must remain Java 11-compatible. - Spec fidelity. The spec TXT (
docs/spec/Webvh v1.0.txt) is the source of truth. When in doubt, follow the spec literally. Reference spec section numbers in code comments for non-obvious logic. - Test-driven. Every public method must have tests. Spec-related logic (SCID generation, entry hash verification, log chain validation) must have tests against known test vectors.
Repository Structure
didwebvh-java/
pom.xml # Parent POM (multi-module Maven)
didwebvh-core/ # Core library
pom.xml
src/main/java/io/github/decentralized-identity/didwebvh/
core/ # Top-level API (DidWebVh facade)
model/ # Data model (LogEntry, Parameters, DidDocument, etc.)
crypto/ # Hash, SCID, entry hash, JCS canonicalization
signing/ # Signer interface and proof generation
create/ # DID creation logic
resolve/ # DID resolution and log processing
update/ # DID update, migration, deactivation
validate/ # Log chain validation, witness verification
url/ # DID URL parsing and DID-to-HTTPS transformation
witness/ # Witness data model and proof handling
didweb/ # Parallel did:web document generation
src/test/java/...
src/test/resources/ # Test vectors (JSONL files, JSON files)
didwebvh-signing-local/ # Local JSON key file signer
pom.xml
src/main/java/io/github/decentralized-identity/didwebvh/signing/local/
LocalKeySigner.java
didwebvh-wizard/ # Interactive CLI
pom.xml
src/main/java/io/github/decentralized-identity/didwebvh/wizard/
WizardMain.java
CreateWizard.java
UpdateWizard.java
ResolveWizard.java
Key Technical Decisions
Build System
- Maven with multi-module layout. Parent POM manages dependency versions and plugin configuration.
- Maven Wrapper (
mvnw) is included so no local Maven install is required.
Dependencies (Core module - keep minimal)
com.google.code.gson:gson- JSON parsing/serialization (widely used, Java 11 compatible)io.github.erdtman:java-json-canonicalization- JSON Canonicalization Scheme (JCS, RFC 8785)com.github.multiformats:java-multihash- Multihash encodingio.github.novacrypto:Base58- Base58btc encodingorg.bouncycastle:bcprov-jdk15on+bcpkix-jdk15on- Ed25519, cryptographic operations, Data Integrity proof signing/verificationcom.squareup.okhttp3:okhttp- HTTP client for DID resolution (optional, only in core for network resolution)
Dependencies (Wizard module)
info.picocli:picocli- CLI frameworkorg.jline:jline- Interactive terminal input
Dependencies (Test)
org.junit.jupiter:junit-jupiter- JUnit 5org.assertj:assertj-core- Fluent assertionsorg.mockito:mockito-core- Mockingcom.squareup.okhttp3:mockwebserver- HTTP mocking for resolver tests
Cryptography
- Ed25519 via BouncyCastle for signing and verification (required by spec:
eddsa-jcs-2022cryptosuite) - SHA-256 for hashing (the only hash algorithm permitted by did:webvh:1.0)
- JCS (JSON Canonicalization Scheme, RFC 8785) for deterministic JSON serialization before hashing/signing
- Multihash for self-describing hash format
- Base58btc for encoding hashes and SCIDs
- Multikey format for public key representation in
updateKeys
The Signer Interface
public interface Signer {
/** Returns the key type string (e.g., "Ed25519"). */
String keyType();
/** Returns the verification method URI (e.g., "did:key:z6Mk...#z6Mk..."). */
String verificationMethod();
/** Signs the given data and returns the signature bytes. */
byte[] sign(byte[] data) throws SigningException;
}
This is the primary extension point. Implementors can plug in:
- Local Ed25519 keys (provided by
didwebvh-signing-local) - AWS KMS (user implements
Signercalling AWS SDK) - External API (user implements
Signercalling their signing service) - HSM devices
Data Integrity Proofs
The spec requires eddsa-jcs-2022 cryptosuite with proofPurpose: assertionMethod. The proof generation flow:
- JCS-canonicalize the log entry (without proof field)
- Sign the canonicalized bytes using the
Signer - Construct the
DataIntegrityProofobject withtype,cryptosuite,verificationMethod,proofPurpose,created,proofValue - Attach the proof to the log entry
Builders for Composition
Use builder pattern for CreateDidConfig and UpdateDidConfig so callers can compose their request step by step, then finalize with proof generation:
CreateDidResult result = DidWebVh.create("example.com")
.withSigner(signer)
.withPortable(true)
.withService("linked-domain", "https://example.com")
.execute();
Coding Standards
- No wildcard imports.
- No
@authortags. Use git blame. - Javadoc on all public classes and methods. One-liner is fine for getters.
- Package-private by default. Only expose what callers need.
- Immutable model classes where possible. Use builder or factory methods for construction.
- No checked exceptions in the public API. Wrap in
DidWebVhException(unchecked). - Null safety. Use
@Nullableannotation where nulls are expected. PreferOptionalfor return types that may be absent. Never accept null in public API methods without documenting it.
Testing Standards
- JUnit 5 for all tests.
- Test vectors from the spec (JSONL files) must be included in
src/test/resources/test-vectors/. - Unit tests for each public class.
- Integration tests for end-to-end flows (create -> update -> resolve -> validate).
- Property-based tests are welcome but not required.
- Every PR must pass:
./mvnw clean verify - Use JDK 21 for local full verification. SpotBugs is skipped on JDK 22+ in this repository, so a local JDK 25 run can pass while the Java 11, 17, or 21 CI jobs fail on SpotBugs findings.
CI/CD
GitHub Actions workflows:
- ci.yml: Runs on every push to
mainand all PRs- Matrix build: Java 11, 17, 21, 25 on ubuntu-latest
./mvnw clean verify(compiles, tests, checks)- Code coverage via JaCoCo, uploaded to Codecov
- SonarCloud quality gate
- Checkstyle and SpotBugs static analysis. SpotBugs runs on Java 11, 17, and 21; it is skipped on Java 25 by the Maven profile for JDK 22+.
- release.yml: Triggered on version tag push, publishes to Maven Central via Sonatype
Commit Messages
Use Conventional Commits:
feat: add DID creation with SCID generationfix: correct entry hash calculation for subsequent entriestest: add test vectors for log chain validationdocs: update README with resolve examplechore: configure JaCoCo for coverage reporting
Changelog and Commit Workflow
After completing any change to the codebase, the agent MUST:
- Update the changelog. Add a summary of the change under the
## [Unreleased]section ofCHANGELOG.md, in the appropriate### Added/### Changed/### Fixed/### Removedsubsection (create the subsection if it does not yet exist). Follow the existing style: reference the spec section and/or issue number for non-obvious behaviour. - Propose a commit message. End the response with a suggested Conventional Commits commit message for the change, so the developer can review and commit it. Do not commit on the developer's behalf unless explicitly asked.
How to Work on This Project
- Read
docs/ARCHITECTURE.mdfor the full technical design. - Read
docs/dev/ITERATIONS.mdfor the ordered list of implementation tasks with detailed prompts. - Follow the iterations in order. Each iteration has clear acceptance criteria.
- Run
./mvnw clean verifywith JDK 21 after every change to ensure tests, Checkstyle, SpotBugs, and coverage run locally. - Keep dependencies minimal. Don't add a library for something that can be done in 20 lines.
- After every change, update the
[Unreleased]section ofCHANGELOG.mdand propose a commit message (see Changelog and Commit Workflow).