Skip to content
Back to skills

Hoon Development

ASecurity

Write and compile Hoon code following Nock conventions and NockApp patterns. Use when working with Hoon kernel code, modifying state structures, adding pokes/peeks, or debugging Hoon compilation.

  • 666 stars
  • 0 votes
  • 0 copies
  • 2 views
  • Added February 9, 2026
documentationbashexpresstestingdebuggingdocumentation

Security analysis

A100/100

Scanned February 12, 2026

npx -y skills add majiayu000/claude-skill-registry --skill hoon-development --agent claude-code

Installs into .claude/skills of the current project.

Are you the author of Hoon Development?

Add the live security badge to your README. It updates with every re-scan.

Security grade badge for Hoon Development
[![Security: A — Skills Directory](https://www.skillsdirectory.com/api/skills/majiayu000-hoon-development/badge)](https://www.skillsdirectory.com/skills/majiayu000-hoon-development)

More formats (shields.io, HTML) on the badges page. Keep it an A: scan every change in CI with Pro.

Download with Pro
SKILL.md
---
name: hoon-development
description: Write and compile Hoon code following Nock conventions and NockApp patterns. Use when working with Hoon kernel code, modifying state structures, adding pokes/peeks, or debugging Hoon compilation.
---

# Hoon Development Guide

This skill helps you write idiomatic Hoon code for the Prover NockApp kernel.

## Hoon Basics

### File Structure

```hoon
::  Comments start with ::
::  Documentation comments
::
|%  ::  Core definition (library of types and functions)
+$  type-name     ::  Type definition
  structure
--

|_  =state        ::  Door (object with state)
++  arm-name      ::  Arm (method/function)
  code
--
```

### Type Definitions

```hoon
::  Atoms (basic types)
@ud   :: Unsigned decimal (0, 1, 42)
@t    :: Text/cord ('hello')
@tas  :: Term/symbol (%groth16, %pending)
@da   :: Timestamp/date (~2024.1.1)

::  Complex types
(list @t)              :: List of text
(map @ud @t)           :: Map from numbers to text
(unit @t)              :: Optional text (~ or [~ 'value'])
?(%a %b %c)            :: Union of terms

::  Structures
+$  person
  $:  name=@t
      age=@ud
      email=@t
  ==

::  Unions (discriminated)
+$  action
  $%  [%create name=@t]
      [%update id=@ud name=@t]
      [%delete id=@ud]
  ==
```

## State Management

### State Structure

Your NockApp state should be versioned:

```hoon
+$  state
  $:  %v1                          :: Version marker
      data=(map @ud entry)         :: Your data
      next-id=@ud                  :: ID counter
      config=settings              :: Configuration
  ==
```

### Accessing State Fields

```hoon
::  Read field
=/  current-id  next-id.state

::  Read nested field
=/  first-entry  (~(get by data.state) 1)
```

### Updating State Immutably

**IMPORTANT**: Never mutate state directly. Always create a new state.

```hoon
::  Update single field
state(next-id +(next-id.state))

::  Update multiple fields
state(data new-data, next-id +(next-id.state))

::  Update with complex computation
=/  new-data  (~(put by data.state) key value)
=/  new-id    +(next-id.state)
state(data new-data, next-id new-id)
```

## The ++poke Pattern

All input commands flow through `++poke`:

```hoon
++  poke
  |=  =cause                       :: Take a cause as input
  ^-  [effects=(list effect) _state]  :: Return effects and new state
  ?-  -.cause                      :: Pattern match on cause tag
      %command-one
    ::  Handle command one
    :_  state                      :: Return state first (reversed)
    :~  [%http-response 200 body]  :: Effect list
    ==

      %command-two
    ::  Handle command two
    =/  updated-state  state(...)
    :_  updated-state
    :~  [%http-response 201 body]
        [%log 'Action completed']
    ==
  ==
```

### Key Patterns

1. **Extract inputs from cause**:
   ```hoon
   =/  input-field  field.cause
   ```

2. **Validate inputs**:
   ```hoon
   ?:  =(input-field 0)
     :_  state
     [%http-response 400 '{"error":"Field cannot be zero"}']~
   ```

3. **Compute new values**:
   ```hoon
   =/  new-id  +(next-id.state)
   =/  entry   [id data timestamp]
   ```

4. **Update state**:
   ```hoon
   =/  updated-state  state(data (~(put by data.state) key entry))
   ```

5. **Return effects and state**:
   ```hoon
   :_  updated-state
   :~  [%http-response 200 body]
       [%log 'Success']
   ==
   ```

## Map Operations

### Common Map Functions

```hoon
::  Insert or update
=/  new-map  (~(put by old-map) key value)

::  Lookup (returns unit)
=/  maybe-value  (~(get by map) key)
?~  maybe-value
  :: Handle not found
:: Handle found, use u.maybe-value

::  Delete
=/  new-map  (~(del by old-map) key)

::  Check existence
=/  exists  (~(has by map) key)

::  Convert to list
=/  pairs  ~(tap by map)  :: List of [key value]

::  Get size
=/  count  ~(wyt by map)
```

### Safe Map Access Pattern

```hoon
=/  maybe-entry  (~(get by snarks.state) id.cause)
?~  maybe-entry
  ::  Not found - return 404
  :_  state
  :~  [%http-response 404 '{"error":"Not found"}']
  ==
::  Found - use u.maybe-entry
=/  entry  u.maybe-entry
:: ... continue with entry
```

## List Operations

```hoon
::  Create list
=/  my-list  ~['a' 'b' 'c']
=/  empty-list  ~

::  Add to front
=/  new-list  [item my-list]

::  Iterate/map
=/  doubled  (turn my-list |=(x=@ud (mul x 2)))

::  Filter
=/  evens  (skim my-list |=(x=@ud =(0 (mod x 2))))

::  Fold/reduce
=/  sum  (roll my-list add)

::  Check if empty
?~  my-list
  :: Empty case
:: Non-empty case, i.my-list is head, t.my-list is tail
```

## Control Flow

### Conditionals

```hoon
::  If-then-else (for values)
?:  condition
  value-if-true
value-if-false

::  If-null check
?~  maybe-value
  handle-null
handle-value  :: u.maybe-value is the unwrapped value

::  Pattern matching
?-  value
  %option-a  result-a
  %option-b  result-b
  %option-c  result-c
==
```

### Variable Binding

```hoon
::  Bind variable
=/  name  value

::  Bind with type
=/  name  ^-  @ud  42

::  Sequential bindings
=/  a  1
=/  b  2
=/  c  (add a b)
c  :: Returns 3
```

## Text and String Operations

### Creating Text

```hoon
::  Literal cord (compile-time)
'hello'

::  Convert with crip (runtime)
(crip "hello")

::  Convert tape to cord
=/  t  "hello"
=/  c  (crip t)
```

### Text Formatting

```hoon
::  Format number to text
=/  num-text  (scow %ud 42)         :: "42"
=/  id-text   (scow %ud id.cause)   :: Format ID

::  Convert text to tape for manipulation
=/  tape-form  (trip 'hello')       :: "hello"

::  Concatenate (as tapes)
=/  result  (weld "hello" " world")
=/  cord-result  (crip result)      :: 'hello world'
```

### JSON-ish String Building (Simplified)

```hoon
::  Simple response
'{"success":true,"id":42}'

::  With interpolation (manual)
=/  id-str  (scow %ud id)
(crip (weld "{\"id\":" (weld id-str "}")))
```

**Note**: The prover uses helper functions for JSON formatting. See `++format-submit-response` in prover.hoon.

## Common Helper Functions

### From the Prover Codebase

```hoon
++  format-submit-response
  |=  id=@ud
  ^-  tape
  (weld "{\"success\":true,\"id\":" (weld (trip (scow %ud id)) "}"))

++  format-snark-detail
  |=  [id=@ud entry=snark-entry]
  ^-  tape
  ::  Build JSON response string
  ...
```

### Creating Your Own Helpers

```hoon
++  build-error-response
  |=  message=@t
  ^-  @t
  (crip (weld "{\"error\":\"" (weld (trip message) "\"}")))

++  format-list-response
  |=  items=(list @t)
  ^-  @t
  ::  Convert list to JSON array
  ...
```

## Type Hints and Casts

```hoon
::  Specify return type
=/  value  ^-  @ud  42

::  Cast to type
=/  entry  ^-  snark-entry
  [id proof inputs vk system submitter now %pending ~ notes]

::  Useful for complex structures
=/  new-state  ^-  state
  state(data new-data, next-id new-id)
```

## The Bowl (Context)

In NockApp pokes, you have access to a `bowl` with context:

```hoon
++  poke
  |=  [=cause =bowl:cask]  :: Bowl is available
  ^-  [(list effect:cask) _state]
  ::  Access bowl fields:
  now.bowl      :: Current timestamp (@da)
  our.bowl      :: Our identity
  ::  etc.
```

**Common use**: Get current timestamp

```hoon
=/  timestamp  now.bowl
=/  entry  [id data timestamp ...]
```

**Note**: In the prover, we use `now` directly (it's implicitly from bowl).

## Error Handling

### Validation Pattern

```hoon
::  Check condition
?:  (lth id.cause 1)
  ::  Return error
  :_  state
  :~  [%http-response 400 '{"error":"ID must be positive"}']
  ==

::  Continue with valid input
...
```

### Not-Found Pattern

```hoon
=/  maybe-entry  (~(get by data.state) id.cause)
?~  maybe-entry
  :_  state
  :~  [%http-response 404 '{"error":"Not found"}']
      [%log (crip "Entry {(scow %ud id.cause)} not found")]
  ==
::  Entry exists, use u.maybe-entry
...
```

## Effects

Common effect types:

```hoon
[%http-response code=@ud body=@t]     :: HTTP response
[%log message=@t]                     :: Log message
[%error message=@t]                   :: Error log
```

### Multiple Effects

```hoon
:_  state
:~  [%http-response 201 body]
    [%log 'SNARK submitted']
    [%log (crip "ID: {(scow %ud new-id)}")]
==
```

## Compiling and Testing

### Compilation

```bash
# Compile Hoon to Nock
hoonc prover/hoon/prover.hoon -o prover/out.jam

# Check for syntax errors
hoonc --check prover/hoon/prover.hoon
```

### Common Compilation Errors

1. **Mint failure**: Type mismatch
   - Check your type annotations (`^-  type  value`)
   - Ensure structure matches type definition

2. **Find failure**: Unknown name
   - Check spelling of variables and arms
   - Ensure variables are in scope (`=/` binding)

3. **Nest failure**: Type doesn't fit expected shape
   - Check structure field order
   - Verify all required fields are present

### Debugging Tips

1. **Add log effects**:
   ```hoon
   [%log 'Reached this point']
   [%log (crip "Value: {(scow %ud value)}")]
   ```

2. **Simplify complex expressions**:
   ```hoon
   ::  Instead of nested calls
   =/  step1  (operation1 input)
   =/  step2  (operation2 step1)
   =/  step3  (operation3 step2)
   step3
   ```

3. **Check types with hints**:
   ```hoon
   =/  value  ^-  expected-type  expression
   ```

## Best Practices

1. **Always version your state**: `$: %v1 ...`
2. **Use type hints for complex values**: `^- type value`
3. **Validate inputs early**: Check before updating state
4. **Keep arms focused**: One responsibility per arm
5. **Use helper functions**: Extract formatting and validation
6. **Log important operations**: Help with debugging
7. **Handle errors explicitly**: Don't assume success
8. **Update state immutably**: Use `state(field new-value)`
9. **Test incrementally**: Compile after each change
10. **Follow existing patterns**: Match the style in prover.hoon

## Quick Reference

### Variable Binding
```hoon
=/  name  value           :: Bind variable
=/  name  ^-  @ud  42     :: With type hint
```

### State Update
```hoon
state(field value)                    :: Single field
state(field1 val1, field2 val2)      :: Multiple fields
```

### Map Operations
```hoon
(~(put by map) key value)    :: Insert/update
(~(get by map) key)          :: Lookup (returns unit)
(~(del by map) key)          :: Delete
~(tap by map)                :: Convert to list
```

### Conditionals
```hoon
?:  condition  true-branch  false-branch   :: If-then-else
?~  maybe-val  null-branch  value-branch   :: If-null
?-  value  %a a  %b b  ==                  :: Pattern match
```

### Effects
```hoon
:_  state
:~  [%http-response 200 '{"ok":true}']
    [%log 'Done']
==
```

## Example: Adding a New Poke

Let's add a `%count-snarks` command:

```hoon
::  1. Add to cause type
+$  cause
  $%  ...
      [%count-snarks ~]
  ==

::  2. Implement in ++poke
++  poke
  |=  [=cause =bowl:cask]
  ^-  [(list effect:cask) _state]
  ?-  -.cause
    ...

    %count-snarks
  =/  count  ~(wyt by snarks.state)
  =/  response  (crip (weld "{\"count\":" (weld (trip (scow %ud count)) "}")))
  :_  state
  :~  [%http-response 200 response]
      [%log (crip "Total SNARKs: {(scow %ud count)}")]
  ==
  ==
```

Done! Compile and test:

```bash
hoonc prover/hoon/prover.hoon -o prover/out.jam
```

## Additional Resources

- Hoon School: https://developers.urbit.org/guides/core/hoon-school
- Hoon Standard Library: https://developers.urbit.org/reference/hoon
- NockApp Documentation: Check the nockup project docs

## Common Patterns from Prover Codebase

### ID Generation
```hoon
=/  new-id  next-id.state
:: ... use new-id ...
state(next-id +(next-id.state))
```

### Building Entries
```hoon
=/  entry  ^-  snark-entry
  :*  id
      proof
      inputs
      vk
      system
      submitter
      now
      %pending
      ~
      notes
  ==
```

### Map Insert Pattern
```hoon
=/  updated-state
  state(snarks (~(put by snarks.state) new-id entry), next-id +(next-id.state))
```

### Response with State
```hoon
:_  updated-state
:~  [%http-response 201 (crip (format-submit-response new-id))]
    [%log (crip "SNARK #{(scow %ud new-id)} submitted")]
==
```

Attribution

Is this your skill, or is something wrong with this listing? Request removal or report an issue. Author removals are honored within 72 hours.

Comments

Loading comments…

Newsletter

Get the weekly list of safe new skills, and the ones we pulled.