Claude-skill-registry Holochain Development

Holochain DHT development for distributed coordination. Activate when: (1) Building Holochain applications (hApps), (2) Writing Zome code in Rust, (3) Configuring conductor and lair-keystore, (4) Working with DHT entries and links, or (5) Setting up Holochain development environment.

install
source · Clone the upstream repo
git clone https://github.com/majiayu000/claude-skill-registry
Claude Code · Install into ~/.claude/skills/
T=$(mktemp -d) && git clone --depth=1 https://github.com/majiayu000/claude-skill-registry "$T" && mkdir -p ~/.claude/skills && cp -r "$T/skills/data/holochain" ~/.claude/skills/majiayu000-claude-skill-registry-holochain-development-4a394c && rm -rf "$T"
manifest: skills/data/holochain/SKILL.md
source content

Holochain Development

Overview

Holochain is a framework for building fully distributed, peer-to-peer applications. It uses a distributed hash table (DHT) for data storage and validation without global consensus.

Key Concepts

ConceptDescription
hAppHolochain Application - a collection of DNAs
DNADistributed Network Architecture - defines data types and validation rules
ZomeA module within a DNA written in Rust/WASM
EntryA piece of data stored on the DHT
LinkA directed connection between two entries
AgentA participant in the network with a unique key pair
ConductorRuntime that hosts hApps and manages connections
LairKey management service (lair-keystore)

Installation

Via Nix (Recommended)

# flake.nix
{
  inputs.holochain.url = "github:holochain/holochain";

  devShells.default = pkgs.mkShell {
    packages = [
      holochain
      lair-keystore
      hc  # Holochain CLI
    ];
  };
}

Via Cargo

cargo install holochain
cargo install lair_keystore

Quick Start

Create a New hApp

# Scaffold new project
hc scaffold web-app my-happ

# Structure created:
# my-happ/
# ├── dnas/
# │   └── my_dna/
# │       ├── workdir/
# │       └── zomes/
# │           └── coordinator/
# │               └── src/lib.rs
# ├── ui/
# └── workdir/

# Build the hApp
hc dna pack dnas/my_dna/workdir
hc app pack workdir

Zome Development

// zomes/coordinator/src/lib.rs
use hdk::prelude::*;

#[hdk_entry_helper]
pub struct Post {
    pub title: String,
    pub content: String,
}

#[hdk_extern]
pub fn create_post(post: Post) -> ExternResult<ActionHash> {
    create_entry(&EntryTypes::Post(post.clone()))
}

#[hdk_extern]
pub fn get_post(action_hash: ActionHash) -> ExternResult<Option<Record>> {
    get(action_hash, GetOptions::default())
}

#[hdk_extern]
pub fn get_all_posts() -> ExternResult<Vec<Record>> {
    let path = Path::from("all_posts");
    let links = get_links(path.path_entry_hash()?, LinkTypes::AllPosts, None)?;

    let posts: Vec<Record> = links
        .into_iter()
        .filter_map(|link| get(link.target, GetOptions::default()).ok().flatten())
        .collect();

    Ok(posts)
}

Entry Definitions

#[hdk_entry_defs]
#[unit_enum(UnitEntryTypes)]
pub enum EntryTypes {
    Post(Post),
    Comment(Comment),
}

#[hdk_link_types]
pub enum LinkTypes {
    AllPosts,
    PostToComments,
}

Conductor Configuration

# conductor-config.yaml
environment_path: /tmp/holochain
keystore:
  type: lair_server
  connection_url: unix:///tmp/lair/socket?k=...

admin_interfaces:
  - driver:
      type: websocket
      port: 4444

network:
  transport_pool:
    - type: webrtc
      signal_url: wss://signal.holochain.org

Testing

Unit Tests (Rust)

#[cfg(test)]
mod tests {
    use super::*;
    use holochain::sweettest::*;

    #[tokio::test(flavor = "multi_thread")]
    async fn test_create_post() {
        let (conductors, _) = SweetConductorBatch::from_standard_config(1).await;
        let apps = conductors.setup_app("test", &[]).await.unwrap();

        let post = Post {
            title: "Test".to_string(),
            content: "Content".to_string(),
        };

        let hash: ActionHash = conductors[0]
            .call(&apps[0].cells()[0].zome("posts"), "create_post", post)
            .await;

        assert!(!hash.is_empty());
    }
}

Integration Tests (Tryorama)

// tests/src/post.test.ts
import { runScenario } from '@holochain/tryorama';

test('create and get post', async () => {
  await runScenario(async scenario => {
    const appBundleSource = { path: './workdir/my-happ.happ' };
    const [alice] = await scenario.addPlayers([{ appBundleSource }]);

    const post = { title: 'Hello', content: 'World' };
    const hash = await alice.cells[0].callZome({
      zome_name: 'posts',
      fn_name: 'create_post',
      payload: post,
    });

    expect(hash).toBeTruthy();
  });
});

Common Patterns

Validation Rules

#[hdk_extern]
pub fn validate(op: Op) -> ExternResult<ValidateCallbackResult> {
    match op.flattened::<EntryTypes, LinkTypes>()? {
        FlatOp::StoreEntry(OpEntry::CreateEntry { entry, .. }) => {
            match entry {
                EntryTypes::Post(post) => {
                    if post.title.is_empty() {
                        return Ok(ValidateCallbackResult::Invalid(
                            "Title cannot be empty".into()
                        ));
                    }
                    Ok(ValidateCallbackResult::Valid)
                }
                _ => Ok(ValidateCallbackResult::Valid)
            }
        }
        _ => Ok(ValidateCallbackResult::Valid)
    }
}

Signal Emission

#[hdk_extern]
pub fn create_post(post: Post) -> ExternResult<ActionHash> {
    let hash = create_entry(&EntryTypes::Post(post.clone()))?;

    // Emit signal to UI
    emit_signal(&Signal::PostCreated { hash: hash.clone(), post })?;

    Ok(hash)
}

Commands Reference

CommandDescription
hc scaffold web-app <name>
Create new hApp project
hc dna pack <workdir>
Package DNA
hc app pack <workdir>
Package hApp
hc sandbox generate
Generate sandbox environment
hc sandbox run
Run sandbox conductor
holochain -c <config>
Run conductor with config
lair-keystore server
Start keystore server

External Links