Specialized skill for nondominium Holochain DNA development, focusing on zome creation, entry patterns, integrity/coordinator architecture, ValueFlows compliance, and WASM optimization. Use when creating new zomes, implementing entry types, or modifying Holochain DNA code.
Installation
Details
Usage
After installing, this skill will be available to your AI coding assistant.
Verify installation:
skills listSkill Instructions
name: nondominium-holochain-dna-dev description: Specialized skill for nondominium Holochain DNA development, focusing on zome creation, entry patterns, integrity/coordinator architecture, ValueFlows compliance, and WASM optimization. Use when creating new zomes, implementing entry types, or modifying Holochain DNA code.
Nondominium Holochain DNA Development
This skill transforms Claude into a specialized nondominium Holochain DNA development assistant, providing expert guidance for creating zomes, implementing entry patterns, and following ValueFlows standards.
When to Use This Skill
Use this skill when:
- Creating new zomes or modifying existing DNA code
- Implementing entry types and validation functions
- Working with integrity/coordinator architecture
- Following ValueFlows compliance patterns
- Optimizing WASM compilation and performance
- Implementing capability-based access control
- Creating cross-zome communication patterns
Do NOT use for:
- Testing workflows (use the Tryorama testing skill)
- Frontend/UI development (use appropriate web development skills)
- Generic Holochain development outside nondominium context
Core DNA Development Workflows
1. Zome Creation Workflow
Create new zomes following nondominium's 3-zome architecture pattern:
-
Initialize Zome Structure
./scripts/create_zome.sh <zome_name> both -
Implement Integrity Layer
- Define entry types in
lib.rs - Add validation functions
- Define link types and relationships
- See
assets/entry_types/for templates
- Define entry types in
-
Implement Coordinator Layer
- Import integrity types:
use zome_<name>_integrity::*; - Implement CRUD functions following naming conventions
- Add cross-zome calls for business logic
- See
assets/function_templates/for patterns
- Import integrity types:
-
Configure Dependencies
# Cargo.toml [zome_traits] hdk_integrity = "zome_<name>_integrity" -
Validate Structure
./scripts/sync_integrity_coordinator.sh <zome_name>
2. Entry Creation Workflow
Follow ValueFlows-compliant entry patterns:
-
Define Entry Structure - NO TIMESTAMP FIELDS
#[hdk_entry_helper] #[derive(Clone, PartialEq)] pub struct EconomicResource { // Business fields pub resource_specification: ActionHash, // Link to spec pub current_state: String, // Agent information (NO timestamps!) pub created_by: AgentPubKey, } -
Create Input Structure
#[derive(Serialize, Deserialize, Debug)] pub struct CreateEconomicResourceInput { pub resource_specification: ActionHash, pub current_state: String, } -
Implement Create Function
- Get agent pubkey:
agent_info()?.agent_initial_pubkey - Validate input data
- Create entry with NO
created_atfield - Create discovery links for global access
- Create agent links for ownership tracking
- Handle errors with custom error types
- Get agent pubkey:
-
Add Discovery Patterns
// Global anchor - discoverable by everyone let path = Path::from("resources"); create_link(path.path_entry_hash()?, entry_hash, LinkTypes::AllResources, LinkTag::new("resource"))?; // Agent link - discoverable by agent create_link(agent_pubkey, entry_hash, LinkTypes::AgentToResources, LinkTag::new("created"))?; // Hierarchical link - facility to its specification create_link(facility_hash, spec_hash, LinkTypes::SpecificationToFacility, LinkTag::new("implements"))?; -
Get Timestamps from Action Headers When Needed
let record = get(entry_hash, GetOptions::default())?; let action = record.action().as_create()?; let created_at = action.timestamp();
3. Build and Validation Workflow
-
Build WASM
./scripts/build_wasm.sh release [zome_name] -
Validate Patterns
./scripts/validate_entry.sh <zome_name> -
Check Performance
- Monitor WASM file sizes (target < 500KB per zome)
- Review optimization suggestions
- Test memory usage patterns
-
Package hApp
./scripts/package_happ.sh production
Critical Holochain DNA Patterns
✅ CORRECT Data Structure Patterns
NEVER use SQL-style foreign keys in entry fields!
// ❌ WRONG - Direct ActionHash references
struct BadFacility {
pub facility_hash: ActionHash, // SQL-style foreign key
pub owner: ActionHash, // Should be a link instead
}
// ✅ CORRECT - Use links for relationships
struct GoodFacility {
pub conforms_to: ActionHash, // Link to specification
// No direct references to other entries
}
// ✅ CORRECT - Link patterns for relationships
create_link(facility_hash, owner_hash, LinkTypes::FacilityToOwner, LinkTag::new("managed_by"))?;
✅ NO Manual Timestamps
Use Holochain's built-in header metadata:
// ❌ WRONG - Manual timestamps
struct BadEntry {
pub created_at: Timestamp, // Redundant!
pub updated_at: Timestamp, // Redundant!
}
// ✅ CORRECT - No timestamps in entries
struct GoodEntry {
pub name: String,
pub description: String,
// No created_at/updated_at fields
}
// Get timestamps from action header when needed:
let record = get(entry_hash, GetOptions::default())?;
let action = record.action().as_create()?;
let created_at = action.timestamp();
✅ CORRECT Entry Definition Pattern (Updated 2025)
Use #[hdk_entry_helper] macro with proper validation requirements:
#[hdk_entry_helper]
#[derive(Clone, PartialEq)]
pub struct FacilitySpecification {
pub name: String,
pub description: String,
pub facility_type: String, // Use Display impl for enums
pub created_by: AgentPubKey,
pub is_active: bool,
// NO ActionHash fields for relationships
}
#[hdk_entry_types]
#[unit_enum(UnitEntryTypes)]
pub enum EntryTypes {
#[entry_def(required_validations = 2)] // Specify validation requirements
FacilitySpecification(FacilitySpecification),
#[entry_def(required_validations = 2)]
EconomicFacility(EconomicFacility),
#[entry_def(required_validations = 3)] // Higher validation for bookings
FacilityBooking(FacilityBooking),
#[entry_def(required_validations = 2, visibility = "private")]
PrivateFacilityData(PrivateFacilityData),
}
🆕 NEW - Advanced Validation Options:
#[hdk_entry_types]
#[unit_enum(UnitEntryTypes)]
pub enum EntryTypes {
// Public entry with standard validation
#[entry_def(required_validations = 2)]
PublicEntry(PublicEntry),
// Private entry with higher validation
#[entry_def(required_validations = 5, visibility = "private")]
PrivateEntry(PrivateEntry),
// Entry with custom name
#[entry_def(name = "custom_entry", required_validations = 3)]
CustomEntry(CustomEntry),
}
🆕 NEW - Base64 Agent Keys Option: For web-compatible applications, consider base64 encoded agent keys:
#[hdk_entry_helper]
#[derive(Clone, PartialEq)]
pub struct FacilitySpecification {
pub name: String,
pub description: String,
pub created_by: AgentPubKeyB64, // Base64 encoded for web compatibility
pub is_active: bool,
}
✅ CORRECT Link Patterns
Use comprehensive link types for discovery:
#[hdk_link_types]
pub enum LinkTypes {
// Discovery anchors
AllFacilitySpecifications,
AllEconomicFacilities,
// Hierarchical relationships
SpecificationToFacility, // FacilitySpec -> EconomicFacility
FacilityToBookings, // EconomicFacility -> FacilityBookings
// Agent-centric patterns
AgentToOwnedSpecs, // Agent -> FacilitySpecs they created
AgentToManagedFacilities, // Agent -> EconomicFacilities they manage
// Type-based discovery
SpecsByType, // FacilityType -> FacilitySpecs
FacilitiesByLocation, // Location -> EconomicFacilities
FacilitiesByState, // FacilityState -> EconomicFacilities
}
Function Naming Conventions
create_[entry_type]- Creates new entries with validation and linksget_[entry_type]- Retrieves single entry by hashget_all_[entry_type]- Global discovery via anchor linksget_my_[entry_type]- Agent-specific entries onlyupdate_[entry_type]- Updates existing entries with permission checksdelete_[entry_type]- Soft deletes with author validation
Error Handling Patterns
Define custom error types for each zome:
#[derive(Debug, thiserror::Error)]
pub enum ZomeError {
#[error("Entry not found: {0}")]
EntryNotFound(String),
#[error("Insufficient capability: {0}")]
InsufficientCapability(String),
#[error("Validation failed: {0}")]
ValidationError(String),
}
impl From<ZomeError> for WasmError {
fn from(err: ZomeError) -> Self {
error!(err.to_string())
}
}
Link Creation Patterns
Use structured link tagging for efficient queries:
// Discovery anchors
LinkTag::new("facility")
LinkTag::new("category")
// Status-based tags
LinkTag::new("available")
LinkTag::new("occupied")
// Relationship tags
LinkTag::new("created")
LinkTag::new("managed_by")
ValueFlows Integration
Core Data Structures
Implement standard ValueFlows entities:
- EconomicResource: Primary resource entities with state tracking
- EconomicEvent: Resource movements and transformations
- Commitment: Agreements between agents for future exchanges
- ResourceSpecification: Definitions of resource types and properties
Action Vocabulary
Use standard ValueFlows actions:
- Production:
produce,accept,modify - Distribution:
transfer,move,deliver_service - Consumption:
consume,use,work - Exchange:
transfer-custody,certify,review
Validation Rules
Validate ValueFlows compliance:
- Action types must be from standard vocabulary
- Resource state transitions must follow valid patterns
- Economic events must have valid participants
- Commitments must have proper timing constraints
Cross-Zome Communication
Integrity Function Calls
Call integrity functions across zomes:
let result: ExternResult<ValidationStatus> = call_integrity(
zome_info()?.zome_id,
"validate_resource_access".into(),
CapSecret::default(),
ValidateAccessInput {
agent: agent_pubkey,
resource: resource_hash,
},
)?;
Remote Agent Calls
Call functions on other agents' zomes:
let result: ExternResult<ResourceDetails> = call_remote(
agent_pubkey,
zome_zome_resource.zome_name,
"get_resource_details".into(),
CapSecret::default(),
resource_hash,
)?;
Data Access Patterns
✅ CORRECT Cross-Zome Data Access
Use link queries to find related data, then retrieve entries:
// Find all resources managed by agent
let links = get_links(agent_pubkey, LinkTypes::AgentToResources, None)?;
let resource_hashes: Vec<ActionHash> = links.iter()
.map(|link| link.target.clone())
.collect();
// Retrieve each resource entry
let mut resources = Vec::new();
for hash in resource_hashes {
if let Some(record) = get(hash, GetOptions::default())? {
if let Some(entry) = record.entry().as_app_entry() {
if let EntryTypes::EconomicResource(resource) = entry {
resources.push(resource);
}
}
}
}
❌ WRONG - Direct Cross-Zome Entry Access
Never access entries from other zomes directly in your entry fields:
// WRONG - Never store direct references like this
struct BadResource {
pub owner: ActionHash, // SQL-style foreign key!
pub facility: ActionHash, // Direct reference!
}
// CORRECT - Use links instead
struct GoodResource {
pub name: String,
pub description: String,
// No direct ActionHash references
}
// Create relationships with links
create_link(resource_hash, owner_hash, LinkTypes::ResourceToOwner, LinkTag::new("owned_by"))?;
create_link(resource_hash, facility_hash, LinkTypes::ResourceToFacility, LinkTag::new("located_at"))?;
Modern Validation Patterns (2025)
Current Validation Callback Structure
Based on recent Holochain projects, here's the modern validation pattern:
#[hdk_extern]
pub fn validate(op: Op) -> ExternResult<ValidateCallbackResult> {
match op {
Op::StoreRecord(_) => Ok(ValidateCallbackResult::Valid),
Op::StoreEntry { .. } => Ok(ValidateCallbackResult::Valid),
Op::RegisterCreateLink(create_link) => {
let (create, _action) = create_link.create_link.into_inner();
let link_type = LinkTypes::try_from(ScopedLinkType {
zome_index: create.zome_index,
zome_type: create.link_type,
})?;
// Link-specific validation logic
match link_type {
LinkTypes::AgentToResource => {
// Validate agent has permission to create this link
Ok(ValidateCallbackResult::Valid)
}
LinkTypes::ResourceToSpecification => {
// Validate resource exists and specification is valid
let _resource: Resource = must_get_entry(create.target_address.clone().into())?.try_into()?;
Ok(ValidateCallbackResult::Valid)
}
_ => Ok(ValidateCallbackResult::Invalid("Unknown link type".to_string())),
}
}
Op::RegisterDeleteLink(_) => {
Ok(ValidateCallbackResult::Invalid("Deleting links isn't valid".to_string()))
}
Op::RegisterUpdate { .. } => {
Ok(ValidateCallbackResult::Invalid("Updating entries isn't valid".to_string()))
}
Op::RegisterDelete { .. } => {
Ok(ValidateCallbackResult::Invalid("Deleting entries isn't valid".to_string()))
}
Op::RegisterAgentActivity { .. } => Ok(ValidateCallbackResult::Valid),
}
}
🆕 Link Tag Validation Pattern
Modern projects use link tags for validation data:
Op::RegisterCreateLink(create_link) => {
let link_type = LinkTypes::try_from(ScopedLinkType {
zome_index: create.zome_index,
zome_type: create.link_type,
})?;
if link_type == LinkTypes::Attestation {
// Extract agent from link tag and validate against entry
let agent = AgentPubKey::try_from(
SerializedBytes::try_from(create.tag.clone())
.map_err(|e| wasm_error!(e))?
).map_err(|e| wasm_error!(e))?;
let attestation: Attestation = must_get_entry(create.target_address.clone().into())?.try_into()?;
if AgentPubKey::from(attestation.about) == agent {
Ok(ValidateCallbackResult::Valid)
} else {
Ok(ValidateCallbackResult::Invalid("Tag doesn't point to about".to_string()))
}
} else {
Ok(ValidateCallbackResult::Valid)
}
}
Performance Optimization
WASM Size Management
- Use minimal dependencies and feature flags
- Prefer compact data structures (u8 flags, bit fields)
- Use
wee_allocfor memory allocation - Enable LTO (Link-Time Optimization) in release builds
Query Optimization
- Use targeted link queries with tag filters
- Implement pagination for large result sets
- Batch operations when possible
- Cache frequently accessed cross-zome data
Memory Management
- Avoid unnecessary clones of large data structures
- Use references instead of owned data where possible
- Implement efficient serialization patterns
- Monitor memory usage in complex operations
Capability-Based Security
Role Management
Implement hierarchical capability levels:
- Viewer (100): Read-only access to resources
- Member (200): Basic participation and resource usage
- Contributor (300): Resource modification and contribution
- Manager (400): Resource management and member oversight
- Admin (500): Full administrative access
- Owner (1000): Complete ownership and control
Access Control Patterns
// Check capability before operations
if !agent_has_capability(&agent_pubkey, "create_resource") {
return Err(ZomeError::InsufficientCapability(
"Agent lacks 'create_resource' capability".to_string()
).into());
}
// Store capability grants as entries
let capability = CapabilityEntry {
agent: target_agent,
role: "contributor".to_string(),
capability_level: 300,
granted_by: agent_pubkey,
expires_at: Some(expiration_time),
// ... other fields
};
Quality Assurance
Validation Checklist
Critical Pattern Validation:
- No SQL-style foreign keys in entry fields (use links instead)
- No manual timestamps in entries (use header metadata)
- Proper
#[hdk_entry_helper]macro usage on all structs - Link-based relationships for all data associations
- Discovery anchor links created for global data access
- Agent-centric links for ownership and tracking
Standard Validation:
- Entry types follow ValueFlows standards
- Functions follow naming conventions
- Error handling implemented with custom types
- Cross-zome calls properly validated
- Capability checks implemented for sensitive operations
- WASM size under target limits
- Performance optimizations applied
Best Practices
DO ✅
- Follow proper Holochain patterns (no SQL-style foreign keys, no manual timestamps)
- Use
#[hdk_entry_helper]macro on all entry structs - Create link-based relationships for all data associations
- Follow the 3-zome architecture (person, resource, governance)
- Implement ValueFlows-compliant data structures
- Use capability-based access control
- Create discovery anchor links for global data access
- Create agent-centric links for ownership tracking
- Get timestamps from action headers when needed
- Validate all input data before entry creation
- Implement proper error handling with custom types
- Optimize WASM size and performance
- Use targeted link queries with filters
DON'T ❌
- NEVER use SQL-style foreign keys in entry fields
- NEVER add manual timestamps like
created_atorupdated_atto entries - NEVER store direct ActionHash references in entry fields
- Create entries without required metadata fields
- Skip capability validation for sensitive operations
- Use generic error messages without context
- Create monolithic functions that do too much
- Ignore ValueFlows standards for economic data
- Build WASM without optimization flags
- Create cross-zome dependencies without validation
- Store sensitive data without encryption
- Skip validation of agent permissions
- Use inefficient data retrieval patterns
Resources
Scripts/
Executable automation scripts for DNA development:
create_zome.sh- Creates new zomes with integrity/coordinator structurebuild_wasm.sh- Compiles Rust code to WASM with optimizationvalidate_entry.sh- Validates entry creation patterns and conventionssync_integrity_coordinator.sh- Ensures layer consistency across zomespackage_happ.sh- Packages hApp bundles for distribution
References/
Comprehensive documentation for DNA development patterns:
zome_patterns.md- Core architectural patterns and conventionsvalueflows_compliance.md- ValueFlows implementation guidelinesentry_creation_patterns.md- Detailed entry creation workflowsperformance_patterns.md- Optimization techniques and best practices
Assets/
Code templates and boilerplate for rapid DNA development:
zome_template/- Complete integrity/coordinator zome templatesentry_types/- Common entry type patterns (basic, ValueFlows, capabilities)function_templates/- CRUD and query function templates
Note: This skill is specifically tailored for the nondominium project's ValueFlows-based economic resource sharing architecture and should not be used for generic Holochain development outside this context.
More by Microck
View allPDF manipulation toolkit. Extract text/tables, create PDFs, merge/split, fill forms, for programmatic document processing and analysis.
Use this skill for requests related to web research; it provides a structured approach to conducting comprehensive web research
Replace with description of the skill and when Claude should use it.
Guides Claude in creating well-structured SKILL.md files following best practices. Provides clear guidelines for naming, structure, and content organization to make skills easy to discover and execute.
