A Ruby gem that boots YAML config into a Rack or CLI service and signs every operation as it happens.
A request comes in. The engine walks a chain of boundaries — small pieces of code with declared inputs and outputs. Each boundary produces a crossing: a record of what it did, signed by its identity, linked to the previous crossing by hash. The chain is a Merkle structure; tampering with any record breaks every signature that follows.
The same YAML configures the HTTP server and the command-line tool. Rack is the reference HTTP adapter; Commander is the reference CLI. The engine doesn't care which adapter brought the request in — it runs the chain and records the result.
Logging, tracing, audit trails, and scope-based authorization are work that services usually write on their own, partially, and at the edges. Wanderland builds them into the substrate. Every crossing is signed. Every context is append-only. Every request has a cryptographic provenance chain as a natural side effect of running it.
Sites opt into durable audit by declaring an :audits: mount and an injection. The result: one signed record per request, containing every crossing that occurred during execution, each still signed by its producer. Auditors pick any crossing out of the bundle, reconstruct its canonical payload, and verify against the producer's public key.
:pki:keys:{id})Active development. Ships with HTTP (Rack) and CLI (Commander) adapters. Apache 2.0 licensed.
wanderland.dev
Wanderland::Derive shapes values over ShapeMatcher. It is pure: a record goes in, an augmented record comes out. A clock (now:) and lookups (bindings:) are injected, so it runs without IO — loading lives behind adapters, and Derive transforms what they return.
A value expression is one of three things, and it may appear in any value position, which is the whole recursion:
42, "high", true"fields.status.name", dot-dig into the record; "$me.accountId"` / `"$now" / "$today" read bindings{ op:, from:|on:, args:, cases:, then:, default: }Input positions (from, on) read a bare string as a path; output positions (then, default) read a bare string as a literal. An op-node computes in any position.
Derive.run(record, spec, bindings:, now:) applies an ordered spec — [{ as:, op:, … }] — each entry storing its result under as; later entries read earlier ones. Ops register like matchers, Derive.register(:name) { |value, args, ctx| … }, with builtins pluck, default, age_days, days_until, present, blank, eq, ne, matches, in, gt/gte/lt/lte, map, lower, upper, size, join, coalesce, and the general case. case gates each branch with ShapeMatcher: given an input (from:, or on:) each branch's when is a predicate on that value; with neither, when is a whole-record shape (multi-field conditions). First match's then wins, else default.
Derive.partition(records, categories) is the same first-wins ShapeMatcher pass for bucketing, with optional group_by; a nil or empty match is the catch-all.
The derive_config boundary loads a record (inline data or a YAML file), runs a derive spec, and returns { config: … }, seeding the context so downstream slots gate on derived flags with when: { config: { flag: value } }.
Source: lib/wanderland/derive.rb, lib/wanderland/boundaries/derive_config.rb, spec/wanderland/derive_spec.rb.
Full reference — ops, value expressions, match shapes, registration: Wanderland Derive.