Help us shape the future of Go! Take the 2026 Go Developer Survey

billy

command module
v0.2.0 Latest Latest
Warning

This package is not in the latest version of its module.

Go to latest
Published: Oct 11, 2026 License: Apache-2.0 Imports: 25 Imported by: 0

README

billy

Audiobookshelf skill for Amazon Alexa.

A single self-contained Go executable that joins a tailnet with an embedded Tailscale node (tsnet) and serves the Alexa skill endpoint over Tailscale Funnel — no reverse proxy, no separate tailscaled, no cloud function.

Status: early. The current build reaches the internet over Funnel, verifies and captures Alexa requests, and can play one externally configured, non-sensitive MP3 on an AudioPlayer-capable Alexa device with pause, resume, stop, and lifecycle handling. There is no Audiobookshelf integration yet.

Build

mise install   # match the pinned toolchain
just verify    # fmt + build + lint + test
just build     # produces dist/billy

Releases ship Linux, macOS and Windows builds for both amd64 and arm64.

Run

Configuration comes from the environment:

Variable Required Purpose
TS_AUTHKEY yes, on first run Reusable, non-ephemeral tailnet auth key
BILLY_BOOK_DESCRIPTOR yes Path to the external JSON descriptor for the one book to serve
BILLY_HOSTNAME no Tailnet node name (default billy) — determines the Funnel URL
BILLY_STATE_DIR no tsnet node state; defaults under the user config dir
BILLY_CAPTURE_DIR no Captured requests; defaults under the user config dir
BILLY_CERT_CHAIN_URL no Public S3 certificate URL used for best-effort startup cache warming
TS_AUTHKEY=tskey-auth-... BILLY_BOOK_DESCRIPTOR=/srv/billy/book.json ./billy

The descriptor is strict JSON. Its mp3 path is relative to the descriptor's own directory and cannot escape it:

{
  "title": "The configured title",
  "author": "Optional author",
  "mp3": "media/book.mp3"
}

The node's Funnel URL is https://<hostname>.<tailnet>.ts.net. /healthz answers 200, /alexa is the authenticated skill endpoint, and /media/book.mp3 publicly serves only the validated MP3 with byte-range support. Invalid book configuration prevents the listener from opening. Certificate cache warming runs asynchronously and never blocks readiness or fails startup; if it cannot complete, the first valid request performs the same bounded fetch.

Captured requests are secret material. Alexa envelopes contain a live apiAccessToken along with user and device identifiers. The capture directory is gitignored and created owner-only; treat its contents as credentials.

The tailnet needs a little configuration before any of that works — see docs/tailscale-setup.md, then docs/alexa-skill-setup.md.

Skill

The Alexa skill lives in alexa/ as an ASK CLI project, so the manifest and interaction model are reviewable files rather than console state:

export BILLY_SKILL_ENDPOINT=https://<host>.<tailnet>.ts.net/alexa
just skill-deploy    # create or update the skill
just skill-corpus    # replay scripted utterances to fill the capture directory
just skill-talk      # interactive dialog with the deployed skill

See AGENTS.md for conventions and setup.md for the implementation plan.

Documentation

Overview

Command billy is a self-hosted Alexa skill endpoint for Audiobookshelf.

It reaches the public internet over an embedded Tailscale Funnel listener, verifies each Alexa request in-process, and captures the exact bytes of every verified request.

Directories

Path Synopsis
pkg
alexaverify
Package alexaverify verifies that an inbound HTTP request really was sent by Alexa.
Package alexaverify verifies that an inbound HTTP request really was sent by Alexa.
alexaverify/internal/corpusgen command
Command corpusgen regenerates alexaverify's synthetic signed request corpus.
Command corpusgen regenerates alexaverify's synthetic signed request corpus.

Jump to

Keyboard shortcuts

? : This menu
/ : Search site
f or F : Jump to
y or Y : Canonical URL