honk-protocol
RFC F0UL: HONK - Hierarchical Object Namespace for Knowledge
Status: Informational (and Chaotic) Category: Experimental Protocol Abuse Author: G. Fawcett Date: December 2024
Abstract
This document specifies HONK (Hierarchical Object Namespace for Knowledge), a distributed content-addressed storage system implemented entirely within the existing Domain Name System (DNS) infrastructure. HONK repurposes DNS record types according to their actual capabilities rather than their intended uses, providing a globally distributed, cached, reactive data store at the cost of one domain registration ($12/year USD).
The key insight is that DNS has always been a filesystem. This document merely acknowledges that fact.
Status of This Memo
This memo describes a protocol that makes DNS administrators uncomfortable. Distribution of this memo is unlimited, ideally via DNS TXT records.
Table of Contents
- Introduction
- Terminology
- Design Philosophy
- Theoretical Foundations
- Record Type Semantics
- Data Types
- The Coordinate System
- Capability Bitfield
- Reactivity Model
- The Chunk Pool
- Operations
- Examples
- Security Considerations
- IANA Considerations
- References
- Acknowledgments
1. Introduction
The Domain Name System [RFC1035] was designed to map human-readable names to network addresses. Over four decades of deployment have revealed that DNS is, in fact, a globally distributed, hierarchically namespaced, typed, cached key-value store with built-in replication, aliasing, priority ordering, and arbitrary payload storage.
HONK acknowledges this reality and provides a formal specification for using DNS as a general-purpose distributed storage system.
1.1 Motivation
The author's daughter coughed directly into his face, resulting in a sick day. The author had a half-hour drive. These conditions produced HONK.
1.2 Requirements Language
The key words "MUST", "SHOULD", "HONK", and "REALLY SHOULD HAVE KNOWN BETTER" in this document are to be interpreted as the author sees fit.
2. Terminology
Chunk: A unit of content stored in a TXT record, maximum 255 bytes.
Chunk Pool: The global namespace of numbered TXT records within a domain.
Coordinate: A tuple of (start, count, flags) addressing a range within the chunk pool.
Manifest: An SRV record specifying coordinates and capabilities for a resource.
Pointer: A CNAME record providing indirection to another name.
Goose: The chaotic waterfowl energy that drives this protocol.
HONK: Both the protocol name and the sound of approval.
Queue: A timestamped sequence of TXT records in the .q namespace, ordered by millisecond timestamp.
Offset: A counter tracking the last-read position in a queue, enabling at-least-once delivery without deletes.
Counter: A CRDT (Conflict-free Replicated Data Type) implemented via AAAA records, where each node maintains its own value and readers sum all nodes.
Node ID: A 4-character identifier for a HONK client, used to partition counter writes and queue offsets.
3. Design Philosophy
3.1 The Yoneda Principle
Objects are defined by their morphisms, not their labels. A DNS record is what it can do, not what the RFC says it is "for."
3.2 Protocols Are Playgrounds
Every protocol specification describes one possible use of the underlying capability. HONK describes another.
3.3 The Bits Are The Truth
The protocol designers built flexibility into DNS. HONK merely uses it.
4. Theoretical Foundations
4.1 The Yoneda Principle (Formalized)
The Yoneda Lemma states: an object X is completely determined by the collection of all morphisms pointing into it from every other object.
You don't need to look inside X. You only need to know how everything else relates to X.
Applied to DNS: A record type is not defined by what RFC 1035 says it's "for." It's defined by the operations you can perform on it:
| Record | Morphisms (What You Can Do) | Therefore It Is |
|---|---|---|
| TXT | Read arbitrary bytes, write arbitrary bytes | A storage cell |
| SRV | Query structured tuple, route based on fields | A manifest/coordinate |
| CNAME | Resolve to another name, chain resolutions | A pointer/reference |
| MX | Query prioritized list, failover semantics | A priority queue |
| A/AAAA | Resolve to numeric value, multiple per name | A numeric array |
The arrows (morphisms) define the object. DNS records ARE what you can do with them.
4.2 The Structural Isomorphism
Two systems are isomorphic when they admit the same morphisms—when the set of valid transformations applicable to one equals those applicable to the other.
Claim: DNS ≅ Filesystem
| Filesystem Morphism | DNS Morphism |
|---|---|
read(path) |
dig TXT name |
write(path, data) |
API: create TXT record |
stat(path) |
dig SRV name (metadata) |
readlink(path) |
dig CNAME name |
readdir(path) |
dig ANY name |
chmod(path, mode) |
Update SRV port field (capabilities) |
| Cache invalidation | TTL expiry |
| Symlink | CNAME |
| Hardlink | Multiple records pointing to same chunk |
If Hom(X, DNS) ≅ Hom(X, Filesystem) for all relevant X, then DNS ≅ Filesystem.
The isomorphism is not metaphorical. The operations are the same. Therefore the systems are the same.
4.3 Records as Morphisms
In HONK, each DNS query is a morphism—a transformation of context:
query("latest.blog.loss.dev")
→ CNAME morphism → "v3.blog.loss.dev"
→ SRV morphism → (46, 26, 1, "loss.dev")
→ TXT morphisms × 26 → [chunk₀, chunk₁, ..., chunk₂₅]
→ base64 morphism → compressed_bytes
→ gunzip morphism → contentThe resolution chain IS a middleware pipeline. Each record type is a transformation. The content emerges from the composition of morphisms.
Data at rest tells you nothing. Data in motion tells you everything.
A TXT record sitting in DNS has no semantics until something queries it, decodes it, decompresses it, acts on it. Each transformation is a morphism. The collection of morphisms defines the meaning.
4.4 The Functor
The functor is constructive: This isn't abstract proof. The code exists. The DNS records exist. Run the functor yourself and get a pelican out:
honk get pelicans --domain=loss.dev
# Output: pelicans.out (27KB JPEG of pelicans)The RFC-as-thesis proves categorical structure by instantiation. Here's the functor. Here's identity. Here's composition. Execute them.
4.5 Homoiconicity
HONK is homoiconic—code, data, and metadata share the same representation:
- The TXT installer script is data (bytes in DNS)
- The TXT installer script is code (pipe to bash)
- The SRV manifest is data (a record)
- The SRV manifest is metadata (describes other records)
- The capability bitfield is data (16 bits)
- The capability bitfield is code (controls interpretation)
The system interprets itself. The format that stores content also stores the instructions for decoding that content.
4.6 The Identity Arrow
In category theory, every object has an identity morphism—an arrow from itself to itself that does nothing.
In HONK, the identity arrow is:
dig +short TXT peak.loss.dev | tr -d '"' | bashOutput:
| ||
| |_The system, queried about itself, returns Loss. The identity arrow is a shitpost. This is appropriate.
🍋
5. Record Type Semantics
HONK assigns the following semantics to DNS record types:
| Record | Traditional Use | HONK Semantics |
|---|---|---|
| TXT | Human-readable notes | Content chunks (255 bytes each) |
| SRV | Service location | Manifest/coordinates (start, count, flags, pool) |
| CNAME | Hostname alias | Pointer/reference (indirection, versioning) |
| MX | Mail routing | Priority queue (version failover chain) |
| A | IPv4 address | 32-bit value / 4-byte self-ordering chunk |
| AAAA | IPv6 address | 128-bit value / 16-byte self-ordering chunk |
5.7 AAAA Records as Native Unicode Strings
The true power of AAAA records: each segment is 16 bits. UTF-16 code units are 16 bits. AAAA records ARE Unicode strings.
AAAA = 8 segments × 16 bits = 8 UTF-16 code units
= 1 sequence + 7 characters (BMP)
= 1 sequence + up to 3 surrogate pairs + leftoversThe Canonical Example
honk.loss.dev. AAAA 0001:0048:004f:004e:004b:d83e:debf:2764
seq H O N K 🪿hi 🪿lo ❤Output: HONK🪿❤
The goose emoji (U+1FABF) requires a surrogate pair:
- High surrogate: 0xD83E
- Low surrogate: 0xDEBF
Four ASCII characters + one emoji (2 code units) + one BMP heart = exactly 7 code units. Perfect fit.
Decoding with HONK CLI
honk unicode-get honk --domain=loss.dev
# Output: HONK🪿❤The CLI handles IPv6 normalization (DNS strips leading zeros, compresses ::) and UTF-16 surrogate pair decoding automatically.
Haiku in DNS
Bashō's frog haiku (古池や蛙飛び込む水の音) stored as native UTF-16:
haiku.loss.dev. AAAA 0001:53e4:6c60:3084:86d9:98db:3073:8fbc
haiku.loss.dev. AAAA 0002:3080:6c34:306e:97f3:0000:0000:0000honk unicode-get haiku --domain=loss.dev
# Output: 古池や蛙飛び込む水の音Sort by first segment, concatenate segments 2-8, interpret as UTF-16, strip nulls. No base64. No chunking. Just poetry, cached globally, resolved in milliseconds.
5.1 TXT Records (Cells)
TXT records store content chunks. Each record holds up to 255 bytes of payload, typically base64-encoded.
_42.pool.example.com. TXT "SGVsbG8gV29ybGQh..."5.2 SRV Records (Manifests)
SRV records specify coordinates into the chunk pool:
_resource._tcp.example.com. SRV <start> <count> <flags> <pool-domain>Fields:
- Priority (16-bit): Start index in chunk pool
- Weight (16-bit): Number of chunks
- Port (16-bit): Capability bitfield (see Section 8)
- Target: Domain containing the chunk pool
5.2.1 Metadata Records
A TXT record at the same name as the SRV manifest provides extended metadata:
_resource._tcp.example.com. SRV 0 146 1 pool.example.com.
_resource._tcp.example.com. TXT "mime=image/jpeg;size=27282;name=pelican.jpg"Format: Semicolon-separated key=value pairs (like SPF/DKIM). Simple, human-readable, no parsing libraries.
Standard keys:
| Key | Description | Example |
|---|---|---|
mime |
MIME type | image/jpeg, text/plain, application/x-sh |
size |
Original size in bytes | 27282 |
name |
Original filename | pelican.jpg |
enc |
Encoding if not base64 | raw, utf16 |
created |
Unix timestamp | 1734400000 |
sha256 |
Content hash (first 16 chars) | a3f2b1c4d5e6f7g8 |
Keys are case-insensitive. Unknown keys SHOULD be ignored. Order is not significant.
The metadata record shares the SRV's TTL and lifecycle—when you create a manifest, create its metadata; when you delete a manifest, delete its metadata.
5.3 CNAME Records (Pointers)
CNAME records provide indirection, enabling versioning and reactivity:
latest.blog.example.com. CNAME v3.blog.example.com.5.4 MX Records (Priority Queues)
MX records specify version precedence for failover:
blog.example.com. MX 10 v3.blog.example.com.
blog.example.com. MX 20 v2.blog.example.com.
blog.example.com. MX 30 v1.blog.example.com.5.5 A Records (Self-Ordering 4-Byte Chunks)
A records encode 4 bytes as dotted-quad notation. The first octet specifies sequence order:
hello.example.com. A 01.72.101.108 ; seq=1, "Hel"
hello.example.com. A 02.108.111.32 ; seq=2, "lo "
hello.example.com. A 03.87.111.114 ; seq=3, "Wor"
hello.example.com. A 04.108.100.33 ; seq=4, "ld!"Decoding: Sort by first octet, concatenate remaining octets, interpret as ASCII.
5.6 AAAA Records (Self-Ordering 16-Byte Chunks)
AAAA records encode 16 bytes in IPv6 notation. First 16 bits specify sequence:
data.example.com. AAAA 0001:4865:6c6c:6f20:576f:726c:6421:0000Decoding: Sort by first segment, concatenate remaining segments, decode as binary.
6. Data Types
HONK supports the following data types:
| Type | Implementation | Max Size |
|---|---|---|
| string | TXT record | 255 bytes |
| blob | Multiple TXT chunks | Unlimited |
| int32 | A record (as dotted quad) | 32 bits |
| int128 | AAAA record | 128 bits |
| list | Multiple A/AAAA/TXT records | Unlimited |
| sortedlist | MX records (priority-ordered) | Unlimited |
| manifest | SRV record | 48 bits + hostname |
| ref | CNAME record | Pointer to name |
| queue | Timestamped TXT in .q namespace | Unlimited (TTL-bounded) |
| counter | AAAA CRDT (per-node values) | 16-bit per node |
| offset | AAAA record (queue read position) | 48-bit timestamp |
| kv | SRV version + TXT value | 255 bytes |
7. The Coordinate System
Every resource in HONK is addressed by coordinates:
(start, count, flags, universe)Where:
- start: Index of first chunk (16-bit, from SRV priority)
- count: Number of chunks (16-bit, from SRV weight)
- flags: Capability bitfield (16-bit, from SRV port)
- universe: Chunk pool domain (from SRV target)
This provides 48 bits of address space per domain, sufficient for addressing 2^16 chunks of 255 bytes each (~16MB) per namespace.
7.1 Spatial Interpretation
The coordinate system may be interpreted spatially:
(x, y, z) = (start, count, flags)CNAME records function as wormholes, teleporting resolution to different coordinates.
8. Capability Bitfield
8. Capability Bitfield
The SRV port field is interpreted as a 16-bit capability bitfield.
Implementation Note: DNS providers require port ≥ 1. Bit 0 is therefore the HONK marker, always set to 1 for valid HONK resources. This guarantees all HONK ports are ≥ 1.
Bit 0 (0x0001): HONK - Protocol marker (MUST be set)
Bit 1 (0x0002): GZIP - Content is gzip compressed
Bit 2 (0x0004): URL - Content is a URL (dereference, don't display)
Bit 3 (0x0008): EXEC - Content is executable (pipe to shell)
Bit 4 (0x0010): BINARY - Content is base64-encoded binary
Bit 5 (0x0020): IMAGE - Content is an image
Bit 6 (0x0040): UTF16 - Content is UTF-16 encoded
Bit 7 (0x0080): ENCRYPTED - Content is encrypted
Bit 8 (0x0100): SIGNED - Content has signature (in separate record)
Bit 9 (0x0200): CONTINUES - Resource continues at target hostname
Bit 10 (0x0400): STREAMING - Append-only, check for new chunks
Bit 11 (0x0800): IMMUTABLE - Content will never change (cache forever)
Bits 12-15: Reserved for future chaos8.1 Common Flag Combinations
| Flags | Hex | Meaning |
|---|---|---|
| 1 | 0x0001 | Raw text (HONK only) |
| 3 | 0x0003 | Gzipped text |
| 11 | 0x000B | Gzipped executable |
| 19 | 0x0013 | Gzipped binary |
| 27 | 0x001B | Gzipped binary executable |
| 5 | 0x0005 | URL to dereference |
| 17 | 0x0011 | Binary (no compression) |
| 33 | 0x0021 | Image (no compression) |
| 35 | 0x0023 | Gzipped image |
8.2 Auto-Detection by MIME Type
Implementations SHOULD auto-detect capability flags from file type:
| Extension | MIME Type | Suggested Flags | Hex |
|---|---|---|---|
.txt |
text/plain | HONK | 0x0001 |
.md |
text/markdown | HONK + GZIP | 0x0003 |
.html |
text/html | HONK + GZIP | 0x0003 |
.json |
application/json | HONK + GZIP | 0x0003 |
.sh |
application/x-sh | HONK + GZIP + EXEC | 0x000B |
.png |
image/png | HONK + BINARY + IMAGE | 0x0031 |
.jpg |
image/jpeg | HONK + BINARY + IMAGE | 0x0031 |
.gif |
image/gif | HONK + BINARY + IMAGE | 0x0031 |
.gz |
application/gzip | HONK + BINARY | 0x0011 |
.tgz |
application/gzip | HONK + BINARY | 0x0011 |
.zip |
application/zip | HONK + BINARY | 0x0011 |
.bin |
application/octet-stream | HONK + BINARY | 0x0011 |
.wasm |
application/wasm | HONK + BINARY | 0x0011 |
For already-compressed formats (.gz, .tgz, .zip, .jpg), do NOT set GZIP—double compression wastes space.
Implementations MAY prompt for confirmation: "Detected image/jpeg → flags 0x0031 (HONK+BINARY+IMAGE). Confirm? [Y/n]"
9. Reactivity Model
HONK achieves reactivity through TTL layering:
| Layer | Record Type | Recommended TTL | Mutability |
|---|---|---|---|
| Pointers | CNAME | 60 seconds | Mutable (flip to update) |
| Manifests | SRV | 3600 seconds | Semi-stable |
| Content | TXT | 86400 seconds | Immutable |
9.1 Update Propagation
To update a resource:
- Write new content to new chunk range
- Create new SRV manifest pointing to new chunks
- Update CNAME pointer to new manifest
Within one pointer TTL (60 seconds), all resolvers worldwide will see the new version. Content remains cached; only pointer resolution is repeated.
9.2 Rollback
To rollback: Update CNAME to point to previous manifest. Old chunks remain in pool.
10. The Chunk Pool
A HONK domain maintains a global chunk pool:
_1.pool.example.com. TXT "..."
_2.pool.example.com. TXT "..."
_3.pool.example.com. TXT "..."
...
_N.pool.example.com. TXT "..."Multiple resources share the same pool. SRV manifests are views into this pool.
10.1 Chunk Naming
Chunks SHOULD be named with underscore prefix and numeric index:
_<index>.<namespace>.<domain>10.2 Garbage Collection
HONK does not specify garbage collection. Chunks are cheap. Domains are $12/year. Let them accumulate.
11. Operations
11.1 GET (Read)
The simple way:
honk get pelicans --domain=loss.dev
# Output: pelicans.out (27KB JPEG)
honk get blog --domain=loss.dev
# Output: blog.out (markdown content)The CLI handles SRV manifest lookup, chunk fetching, base64 decoding, and gzip decompression automatically.
Protocol Details
For the curious (or those implementing their own client):
# Get manifest
srv=$(dig +short SRV _resource._tcp.example.com)
start=$(echo $srv | awk '{print $1}')
count=$(echo $srv | awk '{print $2}')
flags=$(echo $srv | awk '{print $3}')
pool=$(echo $srv | awk '{print $4}')
# Fetch chunks
for i in $(seq $start $((start+count-1))); do
dig +short TXT _$i.$pool | tr -d '"'
done | base64 -d | {
# Decompress if GZIP flag set
[[ $((flags & 2)) -ne 0 ]] && gunzip || cat
}11.2 PUT (Write)
# Encode content
cat content.txt | gzip | base64 > encoded.txt
# Split into chunks
split -b 250 encoded.txt chunk_
# Upload chunks (implementation-specific)
# Create SRV manifest pointing to chunk range11.3 REF (Pointer Update)
# Update CNAME to flip pointer
# (DNS provider API specific)11.4 ENQUEUE (Add to Queue)
Queue items are timestamped TXT records in the .q namespace:
_<timestamp>.<queue>.q.<domain> TXT "<payload>"Timestamp is milliseconds since epoch, providing natural ordering.
# Enqueue a job
honk enqueue jobs '{"task":"build","env":"prod"}'
# Creates: _1766099487050.jobs.q.loss.dev TXT '{"task":"build","env":"prod"}'11.5 DEQUEUE (Read from Queue)
Dequeue uses an offset as consumer position pattern. Each consumer (identified by node ID) maintains its own read position via TXT record:
_<node>.jobs.offset.<domain> TXT "<timestamp>"Algorithm:
- Read offset from API (needs fresh read, DNS caching defeats queue semantics)
- List queue items via API
- Filter items where timestamp > offset
- Return oldest unread item
- Update offset to that item's timestamp
# Dequeue oldest unread
honk dequeue jobs
# Returns: {"task":"build","env":"prod"}
# Updates offset to 1766099487050
# Dequeue again
honk dequeue jobs
# Returns next item, or "Queue jobs is empty" if caught upKey insight: No deletes required. Queue items remain until TTL expires. The offset tracks consumption. Multiple consumers each maintain their own offset (like Kafka consumer groups).
Peek mode: Use --peek to read without updating offset.
11.6 INCR (Counter Increment)
Counters use AAAA records with CRDT semantics. Each node publishes its own increment; readers sum all nodes:
<counter>.c.<domain> AAAA <node>:<value>:0000:<time>:0000:0000:0000:0000Format breakdown:
- Segment 0: Node ID (4 hex chars, identifies writer)
- Segment 1: Counter value (16-bit hex)
- Segment 2: Reserved
- Segment 3: Timestamp (16-bit, for conflict resolution)
- Segments 4-7: Reserved (future: checksum, flags)
# Increment counter
honk incr page_views
# Read counter total
honk counter page_views
# Output: 42
# Read with breakdown by node
honk counter page_views --verbose
# Output: page_views = 42 (node1: 15, node2: 27)Protocol Details
# Read total (sum all nodes)
dig +short AAAA page_views.c.loss.dev | awk -F: '{sum += strtonum("0x"$2)} END {print sum}'CRDT property: Multiple writers never conflict. Each node only updates its own record. Readers merge by summing. Convergence is guaranteed.
11.7 SET/CAS (KV with Optimistic Locking)
Key-value storage uses SRV records for versioning:
_<key>._kv.<domain> SRV <version> 0 0 <value-encoding>
_<key>._kv.<domain> TXT "<value>"- SET: Increment version, update TXT value
- CAS: Compare version, fail if mismatch (optimistic locking)
# Set value
honk set rate_limit 100
# Compare-and-swap (only succeeds if version matches)
honk cas rate_limit 150 --version=312. Examples
12.1 Blog Post Distribution
; Pointer (reactive)
latest.blog.example.com. CNAME v3.blog.example.com.
; Manifest (semi-stable)
v3.blog.example.com. SRV 146 26 1 pool.example.com.
; Content (immutable)
_146.pool.example.com. TXT "H4sIAAAAAAAA..."
_147.pool.example.com. TXT "..."
...
_171.pool.example.com. TXT "..."Retrieval:
dig +short TXT blog.example.com | tr -d '"' | bash12.2 RSS Feed Announcement (Really Silly Syndication)
; Installer
rss.example.com. TXT "dig +short SRV _rss._tcp.example.com | awk '{gsub(/\\.$/,\"\",$4); printf \"https://%s/%c%c\\n\", $4, int($3/256), $3%256}'"
; Manifest with port-encoded path
_rss._tcp.example.com. SRV 0 0 26729 graemefawcett.ca.Port 26729 = 0x6869 = "hi" (ASCII)
Retrieval:
dig +short TXT rss.example.com | tr -d '"' | bash
# Output: https://graemefawcett.ca/hi12.3 Hello World (A Record Encoding)
hello.example.com. A 01.72.101.108
hello.example.com. A 02.108.111.32
hello.example.com. A 03.87.111.114
hello.example.com. A 04.108.100.33Retrieval:
dig +short A hello.example.com | sort -t. -k1 -n | cut -d. -f2-4 | while read a b c; do printf "\\x$(printf '%02x' $a)\\x$(printf '%02x' $b)\\x$(printf '%02x' $c)"; done
# Output: Hello World!13. Security Considerations
13.1 Execution Risk
Flag 0x0004 (EXEC) instructs clients to pipe content to a shell. This is as dangerous as it sounds. Users SHOULD only execute HONK content from trusted domains.
13.2 DNSSEC
HONK content SHOULD be served from DNSSEC-signed zones to prevent tampering.
13.3 Rate Limiting
DNS providers implement rate limiting. High-frequency HONK operations may be throttled.
13.4 Cache Poisoning
Standard DNS cache poisoning attacks apply. See [RFC5452].
13.5 The Goose
If you encounter a goose while implementing HONK:
- Do not make direct eye contact
- Back away slowly
- Do not attempt to debug in its presence
14. IANA Considerations
This document requires no IANA actions. HONK uses existing DNS record types for purposes their designers probably anticipated but hoped nobody would actually attempt.
15. References
15.1 Normative References
Mockapetris, P. (1987). Domain Names - Implementation and Specification. RFC 1035. https://doi.org/10.17487/RFC1035
Gulbrandsen, A., Vixie, P., & Esibov, L. (2000). A DNS RR for specifying the location of services (DNS SRV). RFC 2782. https://doi.org/10.17487/RFC2782
Kitterman, S. (2014). Sender Policy Framework (SPF). RFC 7208. https://doi.org/10.17487/RFC720815.2 Informative References
Masinter, L. (1998). Hyper Text Coffee Pot Control Protocol (HTCPCP/1.0). RFC 2324. https://doi.org/10.17487/RFC2324
Hubert, A. & van Mook, R. (2009). Measures for Making DNS More Resilient against Forged Answers. RFC 5452. https://doi.org/10.17487/RFC5452
CAD. (2008). Loss. Ctrl+Alt+Del. https://is.this.loss.dev
Yoneda, N. (1954). On the homology theory of modules. Journal of the Faculty of Science, University of Tokyo, 7, 193-227.
Fawcett, G. (2025). Structural Isomorphism of Documents and Programs. Wanderland Apocrypha. https://graemefawcett.ca/blog/structural-isomorphism
Fawcett, G. (2025). Objects Defined by Arrows (The Yoneda Lemon). Wanderland Apocrypha. https://graemefawcett.ca/blog/yoneda-lemon16. Acknowledgments
The author wishes to thank:
- His daughter, for the immune system challenge that enabled this work
- The geese, for their chaotic energy
- DNS, for being a filesystem this whole time
- Claude, for staying aligned on the vector
Author's Address
Graeme Fawcett
Domain: loss.dev
Email: dig TXT email.loss.dev +short | tr -d '"' | tr '!' '\\033' | bash
# TXT record contains (! = escape placeholder):
echo -e '![1;35mOh ![1;36mmy ![1;33mgoodness, ![1;31mno ![1;32mwe ![1;34mdont ![1;35mdo ![1;36mthat ![1;33mhere.![0m'
# Output:
# Oh my goodness, no we dont do that here.
# (in magenta, cyan, yellow, red, green, blue, magenta, cyan, yellow)honk
Appendix A: Quick Reference
Using the HONK CLI
# Install
pip install git+https://git.sr.ht/~graemefawcett/honk
# Get content from DNS
honk get pelicans --domain=loss.dev
honk get blog --domain=loss.dev
# Unicode from AAAA records
honk unicode-get haiku --domain=loss.dev
# Queue operations
honk enqueue jobs '{"task":"build"}'
honk dequeue jobs
honk qdepth jobs
# Counter operations
honk incr page_views
honk counter page_viewsRaw Protocol (Shell Implementation)
For those who want to understand the underlying protocol:
# Universal HONK reader
honk_get() {
local name=$1
local srv=$(dig +short SRV _${name}._tcp.loss.dev)
local start=$(echo $srv | awk '{print $1}')
local count=$(echo $srv | awk '{print $2}')
local flags=$(echo $srv | awk '{print $3}')
local pool=$(echo $srv | awk '{print $4}')
for i in $(seq $start $((start+count-1))); do
dig +short TXT _$i.$pool | tr -d '"'
done | base64 -d | {
[[ $((flags & 2)) -ne 0 ]] && gunzip || cat
} | {
[[ $((flags & 8)) -ne 0 ]] && bash || cat
}
}
# Usage
honk_get blog
honk_get pelicans > pelicans.jpgAppendix B: The Origin
dig +short TXT peak.loss.dev | tr -d '"' | bash| ||
| |_∎ 🪿
North
slots:
- slug: i-have-done-another-bad-thing-to-a-protocol
context:
- HONK is another bad thing done to a protocol - DNS as a filesystemWest
slots:
- slug: goose-distribution-network
context:
- HONK is the evolution of the Goose Distribution NetworkEast
slots:
- slug: yoneda-lemon
context:
- The category theory foundation
- slug: structural-isomorphism-thesis
context:
- Documents and programs are isomorphic - DNS and filesystems are too44 The Functor
57 Aaaa Records As Native Unicode Strings
South
slots:
- context:
- User guide links up to RFC specification
slug: honk-user-guide