Holochain Development
Holochain Development Skill
Patterns for developing Holochain 0.6 hApps with HDI 0.7 integrity zomes and HDK 0.6 coordinator zomes.
Environment
This project uses Nix flakes (flake.nix), not shell.nix:
nix develop # Enter dev shell
nix develop --command bun test:unit # Run unit tests in Nix
bun build:zomes # Build Rust zomes
bun build:happ # Build complete hApp
Key Reference Files
- Integrity zome:
dnas/requests_and_offers/zomes/integrity/service_types/src/lib.rs - Coordinator zome:
dnas/requests_and_offers/zomes/coordinator/requests/src/lib.rs - Coordinator CRUD:
dnas/requests_and_offers/zomes/coordinator/requests/src/request.rs - Entry types:
dnas/requests_and_offers/zomes/integrity/requests/src/request.rs - Shared utils:
dnas/requests_and_offers/zomes/coordinator/utils/ - Tryorama tests:
tests/src/requests_and_offers/
Holochain 0.6 Key Patterns
Integrity Zome (HDI 0.7)
Uses hdi::prelude::* (NOT hdk):
use hdi::prelude::*;
#[derive(Serialize, Deserialize)]
#[serde(tag = "type")]
#[hdk_entry_types]
#[unit_enum(UnitEntryTypes)]
pub enum EntryTypes {
MyEntry(MyEntry),
}
#[hdk_entry_helper]
#[derive(Clone, PartialEq)]
pub struct MyEntry {
pub name: String,
pub description: String,
}
#[derive(Serialize, Deserialize)]
#[hdk_link_types]
pub enum LinkTypes {
MyEntryUpdates,
AllMyEntries,
}
#[hdk_extern]
pub fn validate(op: Op) -> ExternResult<ValidateCallbackResult> {
match op.flattened::<EntryTypes, LinkTypes>()? {
FlatOp::StoreEntry(store_entry) => match store_entry {
OpEntry::CreateEntry { app_entry, .. } |
OpEntry::UpdateEntry { app_entry, .. } => match app_entry {
EntryTypes::MyEntry(entry) => validate_my_entry(entry),
},
_ => Ok(ValidateCallbackResult::Valid),
},
_ => Ok(ValidateCallbackResult::Valid),
}
}
Coordinator Zome (HDK 0.6)
Uses hdk::prelude::*:
use hdk::prelude::*;
use my_integrity::*;
// Create: create_entry + get + create_link to path
#[hdk_extern]
pub fn create_my_entry(input: MyEntryInput) -> ExternResult<Record> {
let hash = create_entry(&EntryTypes::MyEntry(input.entry))?;
let record = get(hash.clone(), GetOptions::default())?
.ok_or(wasm_error!(WasmErrorInner::Guest("Entry not found".into())))?;
let path = Path::from("my_entries.active");
create_link(path.path_entry_hash()?, hash, LinkTypes::AllMyEntries, ())?;
Ok(record)
}
// Read: get with GetOptions::default()
#[hdk_extern]
pub fn get_my_entry(hash: ActionHash) -> ExternResult<Option<Record>> {
get(hash, GetOptions::default())
}
// List: LinkQuery::new() with GetStrategy
#[hdk_extern]
pub fn get_all_my_entries() -> ExternResult<Vec<Record>> {
let path = Path::from("my_entries.active");
let link_filter = LinkTypes::AllMyEntries.try_into_filter()
.map_err(|e| wasm_error!(WasmErrorInner::Guest(e.to_string())))?;
let links = get_links(LinkQuery::new(path.path_entry_hash()?, link_filter)
.get_options(GetStrategy::Local))?;
let get_input: Vec<GetInput> = links.into_iter()
.filter_map(|link| link.target.into_action_hash())
.map(|hash| GetInput::new(hash.into(), GetOptions::default()))
.collect();
let records: Vec<Record> = HDK.with(|hdk| hdk.borrow().get(get_input))?
.into_iter().flatten().collect();
Ok(records)
}
// Update: update_entry + create tracking link
#[hdk_extern]
pub fn update_my_entry(input: UpdateInput) -> ExternResult<Record> {
update_entry(input.previous_hash, &input.updated_entry)?;
// ... get and return updated record
}
// Delete link: requires GetOptions::default()
delete_link(create_link_hash, GetOptions::default())?;
Signals & Post-Commit
See coordinator-zome.template.rs for Signal enum and post_commit pattern.
Project Structure
Integrity zomes (hdi) define types + validation; coordinator zomes (hdk) implement business logic.
DNA manifest at dnas/requests_and_offers/workdir/dna/dna.yaml uses path field (not bundled).
Common Tasks
- Add entry type: Create struct with
#[hdk_entry_helper]in integrity, add toEntryTypesenum - Add link type: Add variant to
LinkTypesenum in integrity, use in coordinator - Add zome function: Add
#[hdk_extern]function in coordinator, call from frontend service - Path indexing: Use
Path::from("entity.status")for collection queries - Batch get: Use
HDK.with(|hdk| hdk.borrow().get(get_input))?for efficient multi-get
Troubleshooting
- Build failures: Ensure
nix developshell is active - DHT sync in tests: Add
dhtSync()calls between agent operations - Link queries: Use
GetStrategy::Localfor reading own data,GetStrategy::Networkfor others - Permission errors: Check
agent_info()?.agent_initial_pubkeymatches expected author
More from happenings-community/requests-and-offers
effect-ts architecture
This skill should be used when creating, implementing, or modifying a store, service, or domain layer. Covers Effect-TS services, Svelte 5 stores, store helpers, domain error handling, creating new domains, adding service methods, or validating architectural consistency
17deployment automation
This skill should be used when deploying, releasing, packaging, managing cross-platform builds, or troubleshooting CI/CD pipelines for Holochain hApps
14