hikyaku 飛脚hikyaku 飛脚

A YAML-configured message relay

Read from one or more endpoints. Deliver to one or more endpoints.

Over almost any protocol, from one YAML spec, with an AI router and retries and fallbacks at every layer.

brew install xavidop/tap/hikyaku

Homebrew is for macOS. On Linux and Windows, use a package, Scoop or a release archive, or run ghcr.io/xavidop/hikyaku.

version: 1
name: support-intake
sources:
  - { name: webhooks, type: http, mode: listen, listen: ":8080", path: /ingest }
destinations:
  - { name: billing, type: https, url: https://billing.internal/events, fallback: [billing-dr] }
  - { name: billing-dr, type: https, url: https://billing-dr.internal/events }
  - { name: support, type: https, url: https://support.internal/hook }
routes:
  - name: triage
    from: [webhooks]
    router:
      type: ai                          # a System One decision model
      model: typesafe/jev-1.13.0
      candidates:
        - { name: billing, description: "Payments, invoices, refunds" }
        - { name: support, description: "Bugs, outages, how-to questions" }
      min_confidence: 0.6
      on_low_confidence: [support]
      fallback:                         # ai ▸ rules ▸ static
        - { type: rules, rules: [{ when: 'msg.json.type.startsWith("invoice.")', to: [billing] }] }
        - { type: static, to: [support] }

How it works

Source to envelope to router chain to every destination, with a fallback at each step

How a message travels through hikyakuSources over http, ws, sse, stdin and file feed the Source stage, which listens, polls or subscribes and reconnects with backoff. Each message becomes an envelope, goes through filters and transforms, then a router chain of ai, rules and static routers. The AI router asks Genkit Go: System One decision models or GenerateData on any model, with model retries and fallbacks. Delivery applies a timeout, retries with Retry-After, a circuit breaker, a retry budget and a fallback chain to each destination: billing falls back to billing-dr, support is a failover group, and the dashboard is best-effort. What fails everywhere goes to the dead-letter queue, which has its own fallback and can be replayed. The admin API serves health, readiness, metrics and reload.SOURCESDESTINATIONShttp · httpsws · wssssestdin · filehikyaku飛脚Sourcelisten · poll · subscribeEnvelopeCloudEventsTransformsCEL · jq · templatesRouter chainai ▸ rules ▸ staticGenkit GoSystem One decision modelsor GenerateData on any modelretries + model fallbacksreconnect · backoff · failover URLsbackpressure: 503 + Retry-AfterDeliverytimeout ▸ retry + Retry-After ▸ breaker ▸ budget ▸ fallback chain ▸ DLQAdmin API /healthz /readyz /metrics /reload · OTel traces · Prometheusbillingfallback ▸ billing-drsupportgroup: failover a → bdashboardbest-effortdead lettersown fallback · replay

Every layer has a retry policy and a fallback: destinations fall back to other destinations, models to other models, the AI router to CEL rules and a static catch-all, and the dead-letter queue to stdout. Concepts walks through it.

Why hikyaku

A relay you can leave running

protocols

Many protocols, one envelope

HTTP, WebSocket, SSE, gRPC, TCP/UDP, Kafka, NATS, MQTT, RabbitMQ, Redis, SQS/SNS/EventBridge, S3, Pub/Sub, GCS, Service Bus and Event Hubs. Sources listen, poll or subscribe, and acknowledge their broker only once a message is delivered or dead-lettered.

ai router

Routing that knows how sure it is

System One decision models by default: typed answers with calibrated probabilities, so min_confidence means something, and one request asks about every candidate. Or any Genkit generative model through GenerateData.

history

It remembers the last call

Past calls live in Redis and reach the model as conversation turns. Follow-ups stick to where the last message went, and corrections teach it per customer. If Redis is down, routing carries on without it.

resilience

Nothing dropped silently

Retries with jitter and Retry-After, deadlines, circuit breakers, retry budgets, fallback chains, failover groups, hedging, model and router fallbacks, and a dead-letter queue with its own fallback and replay.

one binary

A CLI, a container, a Helm chart

Run it on your machine with hikyaku run, ship the distroless image, or install the Helm chart with probes, a ServiceMonitor and a Gateway API route. The same spec everywhere.

safe by default

Declared, redacted, guarded

Secrets are mamori refs, redacted from logs and /debug. The AI only picks destinations the spec declares, states are redacted before a model sees them, and templated hosts pass an SSRF guard.

Quick start

A webhook that fans out, then a route an AI decides

$ brew install xavidop/tap/hikyaku
$ hikyaku init --template webhook-fanout   # hikyaku.yaml
$ hikyaku validate                         # refs, cycles, CEL, templates
$ hikyaku run                              # sources on :8080, admin on :9090
$ curl localhost:8080/ingest -d '{"type":"invoice.paid"}'

hikyaku init scaffolds the spec, validate checks it, and the webhook you post reaches every destination of the route. Thequick start goes step by step.

$ make build-llmfake                 # a fake decision model, no key
$ ./bin/hikyaku route --dry-run \
    -f examples/ai-triage/hikyaku.llmfake.yaml \
    --source webhooks --data @examples/ai-triage/msg.json

The ai-triage example routes on a fake decision model, so it runs with no key: the dry run prints the router, the model, each candidate's probability and the fallback hops it would take. See Routing.