🪝 yoink

Adding a service via `yoink add`

Pick a vetted template (postgres, redis, meilisearch, …), answer prompts, get a sealed-secret-ready service fragment.

Pick a template, answer the prompts, get a service fragment with sealed secrets dropped into your project. Same code path for bundled templates and 3rd-party repos.

To publish your own, see Authoring templates.

Try it

yoink add postgres            # accessory: postgres on a named volume
yoink add redis               # accessory: redis with secure defaults
yoink add meilisearch         # accessory: full-text search w/ sealed master key
yoink add rustfs              # accessory: self-hosted S3-compatible object storage
yoink add restic-backups      # accessory: nightly volume backups to any S3
yoink add openclaw --up       # app: render fragment + run `yoink up`

What it does

  1. Fetches templates/<name>/ from oddur/yoink@main (or another repo; see below).
  2. Reads the template's template.yaml manifest.
  3. Prompts for variables without a default. --yes uses every default.
  4. Renders the files with minijinja.
  5. Generates and seals declared secrets into your secrets.age — random bytes never leave the local process.
  6. Adds the fragment glob to your yoink.yaml include: list if not already covered.
  7. Prints the manifest's notes, usually how to wire the service into your app.

Every step gates on a confirmation diff. --yes skips prompts (required in CI).

Bundled templates

TemplateKindWhat you get
postgresaccessoryPostgres 18 + named volume + <NAME>_PASSWORD sealed; opt-in WAL archiving for PITR
redisaccessoryRedis 7 with secure-by-default options
meilisearchaccessoryMeilisearch + volume + sealed master key
rustfsaccessoryApache-2.0 S3-compatible object storage; sealed root credentials
restic-backupsaccessoryNightly volume snapshots via resticker (restic + go-cron) to any S3-compatible bucket
openclawappPlaceholder app template (rename + repoint image: to suit)

The full set lives at https://github.com/oddur/yoink/tree/main/templates.

Pinning to a specific version

yoink add postgres resolves to oddur/yoink@main by default. Pin to a tag or commit:

yoink add [email protected]
yoink add postgres@a1b2c3d

The cache is content-addressed by resolved SHA — re-running with the same pin is a no-op (no network).

To bypass the main → SHA cache after a branch update:

yoink add postgres --refresh

3rd-party templates

Use the gh: prefix:

yoink add gh:acme/yoink-templates/clickhouse
yoink add gh:acme/[email protected]/clickhouse
yoink add gh:acme/yoink-templates@a1b2c3d/clickhouse

Same diff/confirm flow as bundled templates. The confirmation header shows the resolved short SHA.

CI / non-interactive

Set variables via --var key=value; --yes skips confirmations:

yoink add postgres --yes \
  --var service_name=db \
  --var memory=1g

Missing variables fail fast in non-interactive mode rather than defaulting to empty.

Troubleshooting

  • "variable X has no default": pass --var X=value or run interactively.
  • "couldn't resolve …@main": GitHub API unreachable. Falls back to the cached SHA if you've added this template before with the same ref; otherwise pass @<sha>.
  • "rendered file failed yoink validation": template bug; report it (or open a PR for bundled templates).

See also

On this page