lantern

honk-user-guide

HONK User Guide

The functor F: FS β†’ DNS preserves structure. This tool is the morphism.

Installation

# Clone from sourcehut
git clone https://git.sr.ht/~graemefawcett/honk
cd honk

# Install as Python module
pip install -e .

# Or install directly
pip install git+https://git.sr.ht/~graemefawcett/honk

# Verify
honk --help

# Initialize config
honk init

Quick Start

Reading from DNS

# Fetch content to file
honk get pelicans
# Creates pelicans.out (27KB JPEG)

# Output to stdout
honk cat rss | bash
# Executes the RSS discovery command

# Specify domain
honk get mydata --domain=example.com

Writing to DNS

# Configure credentials first
vim ~/.config/honk/config.json

# Upload a file
honk put myimage photo.jpg

# With gzip compression (sets flag 0x0001)
honk put myimage photo.jpg --gzip

# With custom flags
honk put myscript install.sh --flags=4  # EXEC flag

Unicode Mode

# Encode text as AAAA records
honk unicode "HONKπŸͺΏβ€"
# Output:
# example.com. AAAA 0001:0048:004f:004e:004b:d83e:debf:2764

# Decode AAAA records
honk unicode-get haiku --domain=loss.dev

Shell Integration

# Print shell function to add to ~/.bashrc
honk install >> ~/.bashrc
source ~/.bashrc

# Now use directly
honk_get pelicans > pelican.jpg
honk_get rss | bash

Configuration

Config file: ~/.config/honk/config.json

{
  "domain": "loss.dev",
  "dns_provider": "dnsmadeeasy",
  "dnsmadeeasy": {
    "api_key": "your-api-key",
    "secret_key": "your-secret-key",
    "domain_id": "123456"
  },
  "chunk_size": 250,
  "default_ttl": 300
}

Getting DNS Made Easy Credentials

  • Log in to https://dnsmadeeasy.com
  • Go to Account β†’ API Credentials
  • Generate API key and secret
  • Find domain ID in the DNS management dashboard URL

Commands

Command Description
File Operations
honk get <name> Fetch content via SRV manifest
honk put <name> <file> Upload content to DNS (auto-detects flags)
honk cat <name> Output content to stdout
honk ls List all HONK resources with metadata
honk tree <name> Show resource structure
Queue Primitives
honk enqueue <queue> <payload> Add JSON to queue (timestamped TXT)
honk dequeue <queue> Pop oldest unread item, update offset
honk dequeue <queue> --peek Read without updating offset
honk qdepth <queue> Get unread count
honk qdepth <queue> --all Show total/unread/offset breakdown
Counter Primitives
honk incr <counter> [amount] Increment CRDT counter (AAAA record)
honk counter <counter> Read counter total (sum all nodes)
Encoding
honk encode <file> Encode file to JSON chunks
honk decode <out> <chunks...> Decode chunks to file
honk unicode <text> Encode text as AAAA records
honk unicode-get <name> Decode AAAA records as UTF-16
Setup
honk init Create config file
honk domains List available domains
honk domains --set Set domain_id interactively

Flags (Capability Bitfield)

The SRV port field is a 16-bit capability bitfield. Bit 0 (HONK) is always set.

Flag Hex Meaning
HONK 0x0001 Protocol marker (always set)
GZIP 0x0002 Content is gzip compressed
URL 0x0004 Content is a URL
EXEC 0x0008 Content is executable
BINARY 0x0010 Content is base64 binary
IMAGE 0x0020 Content is an image
UTF16 0x0040 Content is UTF-16 encoded
ENCRYPTED 0x0080 Content is encrypted
SIGNED 0x0100 Content has signature

Common combinations:

  • 0x0001 (H) - Raw text
  • 0x0003 (HG) - Gzipped text
  • 0x0011 (HB) - Binary (no compression)
  • 0x0031 (HBI) - Image
  • 0x000B (HGX) - Gzipped executable

honk put auto-detects flags from file type. Use -y to accept without prompting.

How It Works

Queue System

Queues use timestamped TXT records. No deletes needed - offset tracking handles consumption.

# Queue items (timestamped)
_1766099487050.jobs.q.loss.dev  TXT  '{"task":"build"}'
_1766099487051.jobs.q.loss.dev  TXT  '{"task":"deploy"}'

# Offset per consumer (tracks last-read timestamp)  
_a25a.jobs.offset.loss.dev  TXT  "1766099487050"

Dequeue flow:

  • Read offset for this node
  • Find items where timestamp > offset
  • Return oldest unread
  • Update offset to that timestamp

Multiple consumers each track their own offset (like Kafka consumer groups).

Counter System (CRDT)

Counters use AAAA records. Each node writes its own record; readers sum all.

page_views.c.loss.dev  AAAA  a25a:002a:0000:1234:0000:0000:0000:0000
page_views.c.loss.dev  AAAA  b3f1:0015:0000:1235:0000:0000:0000:0000
# Total: 0x2a + 0x15 = 63

CRDT property: No conflicts. Each node only updates its own record. Convergence guaranteed.

SRV Manifest

_mydata._tcp.loss.dev. SRV <start> <count> <flags> <pool>
  • start: First chunk index in pool
  • count: Number of chunks
  • flags: Capability bitfield
  • pool: Domain containing chunks

Chunk Pool

_12345.loss.dev. TXT "base64chunk..."
_12346.loss.dev. TXT "base64chunk..."
_12347.loss.dev. TXT "base64chunk..."

Resolution Flow

query(_mydata._tcp.loss.dev)
  β†’ SRV: 12345 3 1 loss.dev
  β†’ fetch _12345.loss.dev, _12346.loss.dev, _12347.loss.dev
  β†’ concatenate chunks
  β†’ base64 decode
  β†’ gunzip (if flags & 1)
  β†’ output

Examples

List Resources

honk ls
#   NAME        TYPE                SIZE  CHUNKS  FLAGS
#   pelicans    image/jpeg        27282     146      H
#   test-meta   text/plain           24       1      H

Upload an Image

# Auto-detects flags from file type
honk put pelican photo.jpg -y

# Result:
# {
#   "name": "pelican",
#   "domain": "loss.dev",
#   "start": 45678,
#   "count": 146,
#   "flags": 1
# }

Retrieve Anywhere

# On any machine with dig
honk get pelican --domain=loss.dev

# Or the pure DNS one-liner:
dig +short SRV _pelican._tcp.loss.dev | ...

Queue: Job Processing

# Producer: add jobs to queue
honk enqueue jobs '{"task":"build","repo":"myapp"}'
honk enqueue jobs '{"task":"deploy","env":"prod"}'

# Consumer: process jobs
while job=$(honk dequeue jobs 2>/dev/null); do
  echo "Processing: $job"
  # do work...
done

# Monitor queue depth
honk qdepth jobs --all
#   Queue: jobs
#   Total:  4
#   Unread: 0
#   Offset: 1766100657799

Counter: Page Views

# Increment (each node tracks its own count)
honk incr page_views

# Read total (sums all nodes - CRDT merge)
honk counter page_views
# 42

# Scrape via DNS for monitoring
dig +short AAAA page_views.c.loss.dev

Really Silly Syndication

# RSS feed announcement
dig +short TXT rss.loss.dev | tr -d '"' | bash
# Output: https://graemefawcett.ca/hi

See Also

Verification

The reflection validates reality. πŸͺž

Test Suite Status

TableConfig:
  array_path: tests
  columns:
    Category: class
    Test: test
    Status: status
  format: markdown

❌ Fence Execution Error: "'honk-test-suite' - Curiouser and curiouser! That path seems to have vanished. Perhaps you meant: 'honk-user-guide', 'poke-test-fixture'?"

Summary

Metric Value
Total Tests 34
Passed βœ… 34
Failed ❌ 0
Success Rate 100%

Tests run via pytest against mocked DNS Made Easy API.


  • (honk-protocol) - RFC F0UL specification [honk-protocol]
  • (goose-distribution-network) - The origin story [goose-distribution-network]
  • (yoneda-lemon) - Why objects are defined by morphisms [yoneda-lemon]

honk πŸͺΏ

North

slots:
- context:
  - User guide links up to RFC specification
  slug: honk-protocol

South

slots:
- context:
  - Linking user guide to test suite (LGD pattern)
  slug: honk-test-suite
↑ northhonk-protocol
↓ southhonk-test-suite