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

keryx

module
v0.28.1 Latest Latest
Warning

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

Go to latest
Published: Oct 23, 2026 License: MIT

README

keryx

keryx · say it "KEH-riks" (/ˈkɛrɪks/) · from Greek κῆρυξ, "herald". Other readings (Modern Greek "KEE-riks", biblical "KAY-roox", Classical Attic /kɛ̂ːryks/) are all equally welcome (about the name).

Turn a written post into a short narrated video and publish it to social platforms, on demand or on a schedule.

keryx is the content-marketing automation for phpboyscout.uk. It builds a 9:16 reel from a storyboard: text cards over generated or uploaded images, narration in a cloned voice, and a music bed matched to the theme. It publishes reels, and text or image posts about the same article, to Instagram, YouTube, TikTok, LinkedIn, Facebook, Threads, X, Bluesky and Mastodon. You run it from the CLI or the local web studio, and a GitLab scheduled pipeline runs it unattended. It is built on go-tool-base.

Status. The generation pipeline works end to end. The CLI takes a storyboard through ElevenLabs voice-clone narration and a music bed, Gemini cards and cover, to an assembled 1080×1920 mp4, and composes social copy for each platform. Publishing adapters for all nine platforms are compiled in, but each platform decides for itself whether your app may post publicly (what keryx cannot tell you). The local web studio is in active development. Design source of truth: spec 0001.

For engineers: start here

Specs live on the project wiki, not in this repository. A spec is a point-in-time decision record, and keeping them here buried the living documentation beside them. docs/development/specs/index.md is the register.

Read For
spec 0001 The design: purpose, providers, themes, the authoring loop, persistence, roadmap. The source of truth.
0053 · 0054 · 0055 · 0056 The interface contracts: the studio's wire format, what the studio owes a human, the CLI and MCP surfaces, and the workspace state they share. These supersede 0002.
AGENTS.md Ways of working for AI coding agents: architecture rules, the domain facts that must stay in parity, the traps.
docs/ User documentation, organised by Diátaxis.

What it does

The fast path is one command. keryx reel make generates the narration, music and cards, selects take 1 of each, and builds the reel in a single pass. It prints a plan and a spend estimate first, and asks you to confirm when the estimate is over the cap. A re-run generates only what has no selection yet.

keryx reel new <slug> --bundle <content-dir>             # scaffold a reel workspace
keryx storyboard draft <post.md> --workspace <slug>      # LLM-draft the board (or --inject <board.json>)
keryx reel make -w <slug> --theme editorial              # VO + music + cards + build in one pass (--dry-run to preview)
keryx social gen -w <slug> --platform instagram          # compose the caption, tags and link for a platform
keryx approve instagram -w <slug>                        # the posting gate: nothing publishes without it
keryx publish instagram -w <slug>                        # post now
keryx publish due                                        # CI/scheduled: post what is approved and due
keryx studio                                             # web UI: manage reels, author, preview, publish

To audition rather than accept take 1, run each stage yourself. Every generative stage produces candidate takes and you pick one. The takes you did not pick are kept.

keryx voice gen  --workspace <slug> --line 1 --takes 2   # VO takes for one line
keryx voice pick <line> <take> --workspace <slug>        #   ... listen, then select
keryx music gen  --workspace <slug> --takes 2 && keryx music pick <take> --workspace <slug>
keryx cards gen  --workspace <slug> --card 0 --theme editorial   # card illustrations (or `cards set` your own)
keryx cards pick <card> <take> --workspace <slug>
keryx cover --theme clay --scene "..."                   # a themed cover image
keryx reel build --workspace <slug>                      # assemble the 9:16 reel (timed to the VO, or --silent)

Only some commands accept -w as the short form of --workspace. The stage commands in the second block need the long flag.

editorial and clay above are theme keywords you define yourself. keryx init seeds no themes, and the first one you add with keryx theme add becomes the default (why).

Config lives in the owning project. keryx reads a repo-root .keryx.yaml (themes, providers, non-secret settings), deep-merged over the user files in ~/.keryx/. Command-line flags override both. Environment variables do not: keryx has no environment layer over its config, and reads only a fixed list of variables such as API keys (the list).

How it's built

  • The tool is stateless and the project owns the state. keryx holds no per-project data. Reels, config, themes and the schedule live in the owning project's git repo (here, the blog). Git holds the authored files. The media goes to a versioned, S3-compatible bucket, pinned by a committed media.lock (set it up).
  • Backends are pluggable. Image, video, voice and music generation, and rendering, each sit behind a provider interface chosen in config. The defaults are Gemini for images, ElevenLabs for voice and music, and afmpeg for rendering (FFmpeg compiled to WebAssembly, so no system ffmpeg is needed). No video adapter exists yet. Each platform has its own Publisher.
  • Themes are config, not code. Palette, voice, music prompt and card illustration style live in ~/.keryx/themes.yaml and the project's .keryx.yaml, which wins on a clash. The studio picks up an edit to a project's .keryx.yaml without a restart.
  • Ported from working Python. The blog's scripts/gen-*.py were the reference implementation, and Phase 1 ported them to Go at parity.

Develop

This project uses just:

just              # tidy, generate, build → bin/keryx
just test         # unit tests + coverage
just test-race    # race detector
just lint         # golangci-lint
just ci           # full local CI (tidy, generate, test, test-race, lint, test-e2e)
just docs-serve   # serve the docs site locally

CI runs on GitLab through the shared phpboyscout/cicd components (Go and Svelte lint, test and security jobs, goreleaser, the docs site), and colophon cuts the releases.

Install

go install gitlab.com/phpboyscout/keryx/cmd/keryx@latest

The main package is cmd/keryx, so the module path alone does not install anything. Pre-built archives are attached to each GitLab release.

Then write the configuration file. keryx refuses to run without one:

keryx init

Build order (posting)

The first four adapters were built in the order Instagram → YouTube → TikTok → LinkedIn. Of those four, Instagram is the only one you can post to your own account from with no app review. The others have audit or partner lead times worth starting early (see the design spec on the wiki).

Licence

Copyright © Matt Cockayne.

Directories

Path Synopsis
cmd
keryx command
Registers the chat providers this tool ships, one module per line.
Registers the chat providers this tool ships, one module per line.
internal
authcmd
Package authcmd holds the auth command's non-Cobra logic.
Package authcmd holds the auth command's non-Cobra logic.
avatar
Package avatar resolves the named avatar registry (config `avatars.*`) and composes per-panel image prompts for the "actor" capability: a recurring character (the author, later co-authors) composited into reel panels via image-to-image, reacting to each beat.
Package avatar resolves the named avatar registry (config `avatars.*`) and composes per-panel image prompts for the "actor" capability: a recurring character (the author, later co-authors) composited into reel panels via image-to-image, reacting to each beat.
avatarcmd
Package avatarcmd is the shared logic behind `keryx avatar` (add/list/show): register a recurring character, auto-capture its likeness/style/palette via a one-off vision analysis (spec 0006 §4), and persist it to the config registry (avatars.*).
Package avatarcmd is the shared logic behind `keryx avatar` (add/list/show): register a recurring character, auto-capture its likeness/style/palette via a one-off vision analysis (spec 0006 §4), and persist it to the config registry (avatars.*).
certsource
Package certsource resolves keryx's TLS certificate source (spec 0027), shared by the studio HTTPS bind and the OAuth callback loopback.
Package certsource resolves keryx's TLS certificate source (spec 0027), shared by the studio HTTPS bind and the OAuth callback loopback.
chatgen
Package chatgen wires the GTB chat client for keryx's optional AI generation (storyboard draft, social copy).
Package chatgen wires the GTB chat client for keryx's optional AI generation (storyboard draft, social copy).
cliout
Package cliout adapts keryx commands to the GTB output model.
Package cliout adapts keryx commands to the GTB output model.
configstore
Package configstore assembles keryx's configuration — once (spec 0048).
Package configstore assembles keryx's configuration — once (spec 0048).
configtest
Package configtest builds in-memory config.Store values for tests.
Package configtest builds in-memory config.Store values for tests.
content
Package content is keryx's SSG-agnostic content source (spec 0033 §4).
Package content is keryx's SSG-agnostic content source (spec 0033 §4).
docblocks
Package docblocks finds the fenced console blocks in keryx's docs that are marked for checking against real command output (keryx #20).
Package docblocks finds the fenced console blocks in keryx's docs that are marked for checking against real command output (keryx #20).
fontcmd
Package fontcmd wires the font library to a command's props (spec 0057 D2/D4).
Package fontcmd wires the font library to a command's props (spec 0057 D2/D4).
fonts
Package fonts carries the typefaces keryx can always draw with, and parses any typeface into a reusable face (spec 0057).
Package fonts carries the typefaces keryx can always draw with, and parses any typeface into a reusable face (spec 0057).
gen/elevenlabs
Package elevenlabs adapts ElevenLabs into keryx's voice and music provider seams (pkg/provider).
Package elevenlabs adapts ElevenLabs into keryx's voice and music provider seams (pkg/provider).
gen/gemini
Package gemini adapts Google's Gemini / Imagen into keryx's image provider seam (pkg/provider).
Package gemini adapts Google's Gemini / Imagen into keryx's image provider seam (pkg/provider).
gencache
Package gencache is keryx's content-addressed generation cache (R-GEN-8 / R-GLOBAL-9): a generated artefact set — a VO line's takes, a music bed, a card's illustrations — is keyed by a hash of its request (text/scene/prompt + all the settings that affect the output).
Package gencache is keryx's content-addressed generation cache (R-GEN-8 / R-GLOBAL-9): a generated artefact set — a VO line's takes, a music bed, a card's illustrations — is keyed by a hash of its request (text/scene/prompt + all the settings that affect the output).
gencmd
Dry run (R-GLOBAL-5): price a generation without performing it.
Dry run (R-GLOBAL-5): price a generation without performing it.
genutil
Package genutil holds small shared helpers for the generation commands (theme resolution from props, flag-default fallbacks, output paths).
Package genutil holds small shared helpers for the generation commands (theme resolution from props, flag-default fallbacks, output paths).
gitrepo
Package gitrepo is keryx's thin wrapper over GTB's pkg/vcs/repo — the single git layer for the studio (spec 0012).
Package gitrepo is keryx's thin wrapper over GTB's pkg/vcs/repo — the single git layer for the studio (spec 0012).
imagery
Package imagery lists the pictures a project already has, so a post can be given one that was made for a reel, another post or an article (spec 0062 D4, D6).
Package imagery lists the pictures a project already has, so a post can be given one that was made for a reel, another post or an article (spec 0062 D4, D6).
lexicon
Package lexicon reads and writes a project's pronunciation.yaml — the local, version-controlled source of truth for its pronunciation-dictionary rules (spec 0022 R-GEN-35).
Package lexicon reads and writes a project's pronunciation.yaml — the local, version-controlled source of truth for its pronunciation-dictionary rules (spec 0022 R-GEN-35).
lexiconcmd
Package lexiconcmd is the shared logic behind `keryx voice lexicon` — the list/add/sync verbs that manage a project's pronunciation.yaml and push it to the active voice provider's dictionary (spec 0022 R-GEN-35).
Package lexiconcmd is the shared logic behind `keryx voice lexicon` — the list/add/sync verbs that manage a project's pronunciation.yaml and push it to the active voice provider's dictionary (spec 0022 R-GEN-35).
mediastore
Package mediastore syncs a reel workspace's MEDIA to the configured object store.
Package mediastore syncs a reel workspace's MEDIA to the configured object store.
postcmd
Package postcmd is the posting state machine behind `keryx approve` and `keryx publish`/`publish all`/`publish due` (0055 R-POST/R-AUTH, 0060 D1–D7, 0061 D1–D4).
Package postcmd is the posting state machine behind `keryx approve` and `keryx publish`/`publish all`/`publish due` (0055 R-POST/R-AUTH, 0060 D1–D7, 0061 D1–D4).
publish/bluesky
Package bluesky is the Bluesky publisher (spec 0060 D9): the first adapter that takes a text-and-image post.
Package bluesky is the Bluesky publisher (spec 0060 D9): the first adapter that takes a text-and-image post.
publish/facebook
Package facebook is the Facebook Page publisher (spec 0060 D10, the Meta phase): a text-and-image announcement goes to a Page as a photo post (bytes uploaded, so no public URL is needed) or, with no image, as a feed post whose link Facebook turns into a card.
Package facebook is the Facebook Page publisher (spec 0060 D10, the Meta phase): a text-and-image announcement goes to a Page as a photo post (bytes uploaded, so no public URL is needed) or, with no image, as a feed post whose link Facebook turns into a card.
publish/instagram
Package instagram is the Instagram Reels publisher (spec 0001 §4, build-order #1 — own-account posting under Standard Access, no App Review).
Package instagram is the Instagram Reels publisher (spec 0001 §4, build-order #1 — own-account posting under Standard Access, no App Review).
publish/linkedin
`keryx auth linkedin` — the interactive LinkedIn OAuth flow (spec 0009 §3).
`keryx auth linkedin` — the interactive LinkedIn OAuth flow (spec 0009 §3).
publish/mastodon
Package mastodon is the Mastodon publisher (spec 0060 D17): a text-and-image announcement becomes a status on the configured instance, the images uploaded as bytes first.
Package mastodon is the Mastodon publisher (spec 0060 D17): a text-and-image announcement becomes a status on the configured instance, the images uploaded as bytes first.
publish/threads
Package threads is the Threads publisher (spec 0060 D15): a text-and-image announcement becomes a Threads post through Meta's container → publish flow, the Instagram shape with a Threads-specific app id, secret and host.
Package threads is the Threads publisher (spec 0060 D15): a text-and-image announcement becomes a Threads post through Meta's container → publish flow, the Instagram shape with a Threads-specific app id, secret and host.
publish/tiktok
`keryx auth tiktok` — the interactive TikTok OAuth flow (spec 0008 §3).
`keryx auth tiktok` — the interactive TikTok OAuth flow (spec 0008 §3).
publish/x
Package x is the X (Twitter) publisher (spec 0060 D16): a text-and-image announcement becomes a post through the v2 API, the image uploaded first by the chunked media flow.
Package x is the X (Twitter) publisher (spec 0060 D16): a text-and-image announcement becomes a post through the v2 API, the image uploaded first by the chunked media flow.
publish/youtube
Package youtube is the YouTube (Shorts) publisher + auth adapter (spec 0007).
Package youtube is the YouTube (Shorts) publisher + auth adapter (spec 0007).
reel
Package reel holds the deterministic core of the reel pipeline: the storyboard schema and validation, the VO-driven timing maths, orphan-controlled text wrapping, and accent-word parsing.
Package reel holds the deterministic core of the reel pipeline: the storyboard schema and validation, the VO-driven timing maths, orphan-controlled text wrapping, and accent-word parsing.
reelcmd
Package reelcmd holds the shared logic behind the `keryx reel` workspace subcommands (new/list/rename/duplicate/rm/link).
Package reelcmd holds the shared logic behind the `keryx reel` workspace subcommands (new/list/rename/duplicate/rm/link).
refreshcmd
Package refreshcmd orchestrates `keryx auth refresh` (spec 0010): it builds the configured write-back + notifier backends, fans out across the enabled platforms' refreshers, fires alerts, and reports per-platform status.
Package refreshcmd orchestrates `keryx auth refresh` (spec 0010): it builds the configured write-back + notifier backends, fans out across the enabled platforms' refreshers, fires alerts, and reports per-platform status.
render/afmpeg
Package afmpeg renders a keryx timeline by driving FFmpeg compiled to WebAssembly (the ffmpeg-wasi engine) through the afmpeg library — no system ffmpeg binary, entirely in memory.
Package afmpeg renders a keryx timeline by driving FFmpeg compiled to WebAssembly (the ffmpeg-wasi engine) through the afmpeg library — no system ffmpeg binary, entirely in memory.
render/cards
Package cards renders a single storyboard card to a PNG — block mode (a line over a solid palette background, optional cover bookend) and overlay mode (a full-bleed media panel + bottom scrim + overlaid line).
Package cards renders a single storyboard card to a PNG — block mode (a line over a solid palette background, optional cover bookend) and overlay mode (a full-bleed media panel + bottom scrim + overlaid line).
render/ffmpeg
Package ffmpeg renders a keryx timeline into a finished MP4 by shelling out to ffmpeg — the default Renderer adapter (spec §3.4).
Package ffmpeg renders a keryx timeline into a finished MP4 by shelling out to ffmpeg — the default Renderer adapter (spec §3.4).
render/progress
Package progress parses ffmpeg's `-progress` output — the machine-readable key=value blocks ffmpeg emits (one `key=value` per line, a block terminated by `progress=continue|end`) when run with `-progress pipe:N`.
Package progress parses ffmpeg's `-progress` output — the machine-readable key=value blocks ffmpeg emits (one `key=value` per line, a block terminated by `progress=continue|end`) when run with `-progress pipe:N`.
render/silence
Package silence parses ffmpeg's silencedetect filter log — the shared piece both render backends (shell-out ffmpeg and in-memory afmpeg) use to surface internal silences for VO take screening (spec 0023).
Package silence parses ffmpeg's silencedetect filter log — the shared piece both render backends (shell-out ffmpeg and in-memory afmpeg) use to surface internal silences for VO take screening (spec 0023).
social
Package social models an article's announcement set (social.json in the article's bundle): a list of pieces — reels and posts — each carrying its per-platform copy and posting status/schedule/result (0056 R-SOC-6..8 as amended by 0060 D1/D2 and 0061 D1).
Package social models an article's announcement set (social.json in the article's bundle): a list of pieces — reels and posts — each carrying its per-platform copy and posting status/schedule/result (0056 R-SOC-6..8 as amended by 0060 D1/D2 and 0061 D1).
socialcmd
Package socialcmd is the shared logic behind `keryx social` (set/show/gen) and `keryx post` (new/list/rm).
Package socialcmd is the shared logic behind `keryx social` (set/show/gen) and `keryx post` (new/list/rm).
specbundle
Package specbundle turns the studio's split OpenAPI document into the single self-contained file the docs surface serves (spec 0053 §3).
Package specbundle turns the studio's split OpenAPI document into the single self-contained file the docs surface serves (spec 0053 §3).
specbundle/cmd/specbundle command
Command specbundle writes the studio's bundled OpenAPI document.
Command specbundle writes the studio's bundled OpenAPI document.
spend
Package spend is keryx's shared generation-cost model (spec 0013 §5, 0031 §5): the per-unit price estimate every surface agrees on (CLI, studio, MCP), and the spend guard threshold that gates a runaway batch.
Package spend is keryx's shared generation-cost model (spec 0013 §5, 0031 §5): the per-unit price estimate every surface agrees on (CLI, studio, MCP), and the spend guard threshold that gates a runaway batch.
takes
Package takes manages candidate takes and the selected slot for a reel workspace (spec 0001 §3.2 "take management"; contract 0002 §2, R-WS-1).
Package takes manages candidate takes and the selected slot for a reel workspace (spec 0001 §3.2 "take management"; contract 0002 §2, R-WS-1).
takescmd
Package takescmd is the shared logic behind the take-management verbs (voice/music/cards pick, cards set, reel prune).
Package takescmd is the shared logic behind the take-management verbs (voice/music/cards pick, cards set, reel prune).
textleak
Package textleak screens generated card illustrations for accidental text (R-GEN-26): image models sometimes render stray letters/words into the art, which look wrong in a promo reel.
Package textleak screens generated card illustrations for accidental text (R-GEN-26): image models sometimes render stray letters/words into the art, which look wrong in a promo reel.
theme
Package theme models keryx's config-driven aesthetic profiles.
Package theme models keryx's config-driven aesthetic profiles.
themecmd
Package themecmd holds the shared logic behind the `keryx theme` subcommands (list/show/add/edit/rm).
Package themecmd holds the shared logic behind the `keryx theme` subcommands (list/show/add/edit/rm).
themestore
Package themestore assembles the config store themes resolve through (spec 0042 §3.6, absorbing spec 0046 step 3).
Package themestore assembles the config store themes resolve through (spec 0042 §3.6, absorbing spec 0046 step 3).
workspace
Package workspace models a reel workspace on disk — the resumable unit of the authoring loop (spec 0001 §3.2, contract 0002 §2).
Package workspace models a reel workspace on disk — the resumable unit of the authoring loop (spec 0001 §3.2, contract 0002 §2).
mocks
pkg
accounts
Package accounts owns ~/.keryx/accounts.yaml — the user-scoped file that holds platform credentials and nothing else (spec 0042 §3.4, D6).
Package accounts owns ~/.keryx/accounts.yaml — the user-scoped file that holds platform credentials and nothing else (spec 0042 §3.4, D6).
cmd/reel/make
Package make is `keryx reel make`: one-command reel orchestration (spec 0020).
Package make is `keryx reel make`: one-command reel orchestration (spec 0020).
credscan
Package credscan finds literal credentials sitting in a config file.
Package credscan finds literal credentials sitting in a config file.
notify
Package notify is keryx's pluggable alert seam (spec 0010 §6): a Notifier interface with config-selected backends (none, webhook, …).
Package notify is keryx's pluggable alert seam (spec 0010 §6): a Notifier interface with config-selected backends (none, webhook, …).
oauth
Package oauth is keryx's provider-neutral OAuth *capture* layer for the CLI: it builds nothing protocol-specific itself, but given an already-built authorize URL and a resolved redirect URI it runs the local callback server (+ stdin paste fallback) and returns the authorization code.
Package oauth is keryx's provider-neutral OAuth *capture* layer for the CLI: it builds nothing protocol-specific itself, but given an already-built authorize URL and a resolved redirect URI it runs the local callback server (+ stdin paste fallback) and returns the authorization code.
objectstore
Package objectstore is the studio/CLI seam to a versioned object store (spec 0039): workspace MEDIA lives in a bucket, git keeps the authored state plus a media.lock manifest pinning each file's content hash and object version.
Package objectstore is the studio/CLI seam to a versioned object store (spec 0039): workspace MEDIA lives in a bucket, git keeps the authored state plus a media.lock manifest pinning each file's content hash and object version.
objectstore/cdk
Package cdk is the multi-backend object-store adapter (spec 0040): one implementation over gocloud.dev/blob, which speaks S3, Google Cloud Storage, Azure Blob, the local filesystem and memory through a single portable API.
Package cdk is the multi-backend object-store adapter (spec 0040): one implementation over gocloud.dev/blob, which speaks S3, Google Cloud Storage, Azure Blob, the local filesystem and memory through a single portable API.
objectstore/s3
Package s3 is the S3 object-store adapter (spec 0039 §3.4): keryx's default storage backend, registered as storage.provider "s3".
Package s3 is the S3 object-store adapter (spec 0039 §3.4): keryx's default storage backend, registered as storage.provider "s3".
provider
Package provider defines keryx's pluggable backend seams.
Package provider defines keryx's pluggable backend seams.
publish
Package publish is the posting seam: one narrow Publisher interface per social platform (spec 0001 §4.1) plus a name-keyed registry so each adapter (internal/publish/<platform>) lands independently and `post all` fans out across the enabled platforms.
Package publish is the posting seam: one narrow Publisher interface per social platform (spec 0001 §4.1) plus a name-keyed registry so each adapter (internal/publish/<platform>) lands independently and `post all` fans out across the enabled platforms.
refresh
Package refresh is keryx's token-refresh seam (spec 0010): a Refresher per platform plus a name-keyed registry, mirroring pkg/publish.
Package refresh is keryx's token-refresh seam (spec 0010): a Refresher per platform plus a name-keyed registry, mirroring pkg/publish.
studio
Package studio serves keryx's local web UI (spec 0011): a single-user web app bound to localhost by default (R-API-3), serving the embedded Svelte SPA plus a thin /api/v1 surface whose handlers map 1:1 to CLI workspace operations.
Package studio serves keryx's local web UI (spec 0011): a single-user web app bound to localhost by default (R-API-3), serving the embedded Svelte SPA plus a thin /api/v1 surface whose handlers map 1:1 to CLI workspace operations.
studio/gen
Code generated by ogen, DO NOT EDIT.
Code generated by ogen, DO NOT EDIT.
studio/spec
Package spec carries the studio's OpenAPI document as one self-contained file, for serving at /openapi.yaml and rendering in the docs console (spec 0053 §3).
Package spec carries the studio's OpenAPI document as one self-contained file, for serving at /openapi.yaml and rendering in the docs console (spec 0053 §3).
test
e2e/steps
Package steps holds the keryx BDD end-to-end suite: Gherkin features in /features driven against a compiled keryx binary.
Package steps holds the keryx BDD end-to-end suite: Gherkin features in /features driven against a compiled keryx binary.

Jump to

Keyboard shortcuts

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