Asi syrup
Syrup binary serialization for OCapN/CapTP wire format. Canonical encoding for capability messages.
git clone https://github.com/plurigrid/asi
T=$(mktemp -d) && git clone --depth=1 https://github.com/plurigrid/asi "$T" && mkdir -p ~/.claude/skills && cp -r "$T/skills/syrup" ~/.claude/skills/plurigrid-asi-syrup && rm -rf "$T"
skills/syrup/SKILL.mdSyrup: Binary Serialization for OCapN
Trit: -1 (MINUS - constraining/validating serialization) Color: #8B4513 (Saddlebrown - like syrup) Source: ocapn/syrup
Overview
Syrup is a lightweight binary serialization format for the OCapN (Object Capability Network). It provides canonical encoding - the same data always serializes to identical bytes - making it suitable for hashing, signing, and capability transport.
Core principle: Simple, canonical, easy to implement across languages.
Type Encoding Reference
| Type | Format | Example |
|---|---|---|
| Boolean | or | = true |
| Positive int | | |
| Negative int | | = -123 |
| Bytestring | | |
| String | | |
| Symbol | | |
| Float | | IEEE 754 single |
| Double | | IEEE 754 double |
| List | | = [3,4,5] |
| Dict | | |
| Set | | |
| Record | | |
Installed Implementations
Python
# pip install via: gh repo clone ocapn/syrup && cd syrup/impls/python from syrup import syrup_encode, syrup_decode, Symbol, record # Encode syrup_encode({"name": "alice", "age": 30}) # => b'{3"age30+4"name5"alice}' # Decode syrup_decode(b'{3"age30+4"name5"alice}') # => {'age': 30, 'name': 'alice'} # Symbols (for Lisp-like keys) syrup_encode({Symbol('species'): b'cat'}) # => b"{7'species3:cat}" # Records (custom types) syrup_encode(record('date', 2024, 5, 1)) # => b'<4"date2024+5+1+>'
Guile Scheme
;; Install: copy syrup.scm to your Guile load path (use-modules (syrup)) ;; Encode (syrup-encode 42) ;; => #vu8(52 50 43) ; "42+" (syrup-encode '("hello" "world")) ;; => #vu8(91 53 34 104 101 108 108 111 53 34 119 111 114 108 100 93) ;; Decode (syrup-decode #vu8(52 50 43)) ;; => 42 ;; Records (syrup-encode (make-syrec* (string->utf8 "date") 2024 5 1))
Racket
#lang racket (require syrup) ;; Encode (syrup-encode #hash(("name" . "alice") ("age" . 30))) ;; => #"{3\"age30+4\"name5\"alice}" ;; Decode (syrup-decode #"{3\"age30+}") ;; => #hash(("age" . 30)) ;; Records (syrup-encode (record* #"date" 2024 5 1)) ;; => #"<4:date2024+5+1+>" ;; Marshalling custom types (struct point (x y) #:transparent) (syrup-encode (point 1 2) #:marshallers (list (cons point? (λ (p) (record* 'point (point-x p) (point-y p))))))
Package:
syrup (installed via raco pkg)
Canonical Property
Syrup guarantees canonical encoding:
- Dictionaries: Keys sorted by their serialized byte representation
- Sets: Items sorted by their serialized byte representation
- No duplicate keys: Dicts must not contain the same key twice
This means:
hash(syrup_encode(x)) == hash(syrup_encode(y)) iff x == y
Backwards Compatibility
Syrup decoders accept:
- Bencode:
→ dictd3:agei12ee - Canonical S-expressions:
→ list(3:foo 3:bar)
# Bencode syrup_decode(b'd3:agei12e4:name5:Missye') # => {b'age': 12, b'name': b'Missy'} # S-expressions syrup_decode(b'(3:cat 7:tabatha)') # => [b'cat', b'tabatha']
GF(3) Triads
# Wire Format Bundle syrup (-1) ⊗ captp (0) ⊗ gay-mcp (+1) = 0 ✓ [Colored Capabilities] syrup (-1) ⊗ localsend-mcp (0) ⊗ tailscale-file (+1) = 0 ✓ [P2P Transfer] syrup (-1) ⊗ beeper-mcp (0) ⊗ agent-o-rama (+1) = 0 ✓ [Message Encoding] # Serialization Stack syrup (-1) ⊗ preserves (0) ⊗ json (+1) = 0 ✓ [Format Spectrum]
Commands
# Python (after installing to PYTHONPATH) python3 -c "from syrup import *; print(syrup_encode({'test': 42}))" # Guile (after installing to load path) guile -c "(use-modules (syrup)) (display (syrup-encode 42))" # Racket (after raco pkg install) racket -e "(require syrup) (displayln (syrup-encode #hash((\"x\" . 1))))"
Use Cases
| Use Case | Why Syrup |
|---|---|
| CapTP messages | Wire format for capability transport |
| Content addressing | Canonical = deterministic hashes |
| Signing | Sign serialized form, verify anywhere |
| Storage | Compact binary, self-describing |
| Cross-language | Same bytes from Python/Guile/Racket |
Related Skills
| Skill | Relation |
|---|---|
| captp | CapTP uses Syrup as wire format |
| preserves | Syrup is a Preserves serialization |
| localsend-mcp | P2P transfer could use Syrup |
| acsets | Serialize ACSets with Syrup |
Installation
# Clone the repo gh repo clone ocapn/syrup # Python: add to PYTHONPATH or copy syrup.py cp syrup/impls/python/syrup.py ~/.local/lib/python3/ # Guile: copy to load path cp syrup/impls/guile/syrup.scm ~/.local/share/guile/site/3.0/ # Racket: install package cd syrup/impls/racket && raco pkg install syrup/
References
Skill Name: syrup
Type: Binary Serialization Format
Trit: -1 (MINUS)
GF(3): Constrains data to canonical form
Invariant: Same data → same bytes, always