| 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> bothImplement 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.