--- 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: 1. **Initialize Zome Structure** ```bash ./scripts/create_zome.sh both ``` 2. **Implement Integrity Layer** - Define entry types in `lib.rs` - Add validation functions - Define link types and relationships - See `assets/entry_types/` for templates 3. **Implement Coordinator Layer** - Import integrity types: `use zome__integrity::*;` - Implement CRUD functions following naming conventions - Add cross-zome calls for business logic - See `assets/function_templates/` for patterns 4. **Configure Dependencies** ```toml # Cargo.toml [zome_traits] hdk_integrity = "zome__integrity" ``` 5. **Validate Structure** ```bash ./scripts/sync_integrity_coordinator.sh ``` ### 2. Entry Creation Workflow Follow ValueFlows-compliant entry patterns: 1. **Define Entry Structure - NO TIMESTAMP FIELDS** ```rust #[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, } ``` 2. **Create Input Structure** ```rust #[derive(Serialize, Deserialize, Debug)] pub struct CreateEconomicResourceInput { pub resource_specification: ActionHash, pub current_state: String, } ``` 3. **Implement Create Function** - Get agent pubkey: `agent_info()?.agent_initial_pubkey` - Validate input data - Create entry with **NO** `created_at` field - Create discovery links for global access - Create agent links for ownership tracking - Handle errors with custom error types 4. **Add Discovery Patterns** ```rust // 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"))?; ``` 5. **Get Timestamps from Action Headers When Needed** ```rust let record = get(entry_hash, GetOptions::default())?; let action = record.action().as_create()?; let created_at = action.timestamp(); ``` ### 3. Build and Validation Workflow 1. **Build WASM** ```bash ./scripts/build_wasm.sh release [zome_name] ``` 2. **Validate Patterns** ```bash ./scripts/validate_entry.sh ``` 3. **Check Performance** - Monitor WASM file sizes (target < 500KB per zome) - Review optimization suggestions - Test memory usage patterns 4. **Package hApp** ```bash ./scripts/package_happ.sh production ``` ## Critical Holochain DNA Patterns ### ✅ CORRECT Data Structure Patterns **NEVER use SQL-style foreign keys in entry fields!** ```rust // ❌ 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:** ```rust // ❌ 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: ```rust #[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**: ```rust #[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: ```rust #[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: ```rust #[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 links - `get_[entry_type]` - Retrieves single entry by hash - `get_all_[entry_type]` - Global discovery via anchor links - `get_my_[entry_type]` - Agent-specific entries only - `update_[entry_type]` - Updates existing entries with permission checks - `delete_[entry_type]` - Soft deletes with author validation ### Error Handling Patterns Define custom error types for each zome: ```rust #[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 for WasmError { fn from(err: ZomeError) -> Self { error!(err.to_string()) } } ``` ### Link Creation Patterns Use structured link tagging for efficient queries: ```rust // 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: ```rust let result: ExternResult = 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: ```rust let result: ExternResult = 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: ```rust // Find all resources managed by agent let links = get_links(agent_pubkey, LinkTypes::AgentToResources, None)?; let resource_hashes: Vec = 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: ```rust // 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: ```rust #[hdk_extern] pub fn validate(op: Op) -> ExternResult { 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: ```rust 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_alloc` for 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 ```rust // 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_at` or `updated_at` to 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 structure - `build_wasm.sh` - Compiles Rust code to WASM with optimization - `validate_entry.sh` - Validates entry creation patterns and conventions - `sync_integrity_coordinator.sh` - Ensures layer consistency across zomes - `package_happ.sh` - Packages hApp bundles for distribution ### References/ Comprehensive documentation for DNA development patterns: - `zome_patterns.md` - Core architectural patterns and conventions - `valueflows_compliance.md` - ValueFlows implementation guidelines - `entry_creation_patterns.md` - Detailed entry creation workflows - `performance_patterns.md` - Optimization techniques and best practices ### Assets/ Code templates and boilerplate for rapid DNA development: - `zome_template/` - Complete integrity/coordinator zome templates - `entry_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.