Holochain Development

SKILL.md

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 to EntryTypes enum
  • Add link type: Add variant to LinkTypes enum 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 develop shell is active
  • DHT sync in tests: Add dhtSync() calls between agent operations
  • Link queries: Use GetStrategy::Local for reading own data, GetStrategy::Network for others
  • Permission errors: Check agent_info()?.agent_initial_pubkey matches expected author
Weekly Installs
0
GitHub Stars
12
First Seen
Jan 1, 1970