The options of Tayori, given to its child in the app's supervision tree:
children = [
MyApp.Repo,
{Phoenix.PubSub, name: MyApp.PubSub},
{Tayori,
repo: MyApp.Repo,
pubsub: MyApp.PubSub,
secret_key_base: Application.fetch_env!(:my_app, MyAppWeb.Endpoint)[:secret_key_base],
locales: ["en", "pt-PT"]},
MyAppWeb.Endpoint
]Options:
:repo- the app's Ecto repo, where the entries are (required).:pubsub- the app'sPhoenix.PubSub, on which the app's pages hear of a new entry as it is published (required).:vault- the app'sCloak.Vault(MyApp.Vault), which encrypts the AI key of the admin with the app's own keys, and rotates them with the app's other secrets. Without it,:secret_key_base.:secret_key_base- the secret the AI key is encrypted with when there is no:vault. With neither, the admin cannot keep a key, and has no AI.:locales- the languages the entries are written in, the first the one every entry has (["en"]).:prefix- the schema of the tables, in PostgreSQL.:notifier- a module of theTayori.Notifierbehaviour, told of each entry once, when it is published.:features- the extras the app wants, none by default; the changelog itself is always there. A feature that is off has no admin page, no route, no element and no process::reactions- readers react to an entry with an emoji.:announcements- an entry shown as a popup, a toast or a banner in the app, until a date.:analytics- the views of each entry, by where it was read.:subscriptions- readers subscribe by email on the public page, and an entry can be sent to them.:webhooks- webhooks, Slack and Discord, told of each entry.:embed- the news on another origin than the app's, with a reader's signed token (Tayori.Embed).
:mailer- the app'sSwoosh.Mailer, which sends the emails of the:subscriptionsfeature (required with it).:email_from- who the emails are from:{"Atelier", "news@atelier.app"}or an address (required with:subscriptions).:page_url- the address of the public page ("https://atelier.app/changelog"), for the links of the emails (required with:subscriptions).:reactions- the emoji readers react with (["👍", "🎉", "❤️", "🚀", "👀"]).:oban- the app's Oban, which then sends what a publication sends (the emails, the webhooks, the call to the:notifier) as jobs:oban: Oban, oroban: [name: MyApp.Oban, queue: :news]for another instance or queue (:default). The queue must be one the app runs. Without it, they are sent by tasks in the node, asTayori.Jobsexplains.:inbox- where the changes of the inbox come from, and what they say when they do not (seeTayori.Inboxand the Automation guide)::sources-{module, opts}ofTayori.Source, such as{Tayori.Sources.Changelog, path: {:my_app, "priv/CHANGELOG.md"}}or{Tayori.Sources.Fragments, path: {:my_app, "priv/news"}}([]).:ingest_on_start- read the sources when the app starts, which is a deploy's new code (true).:audience- of a change that does not say:"public"or"internal"("public").:kinds- the category of each kind of change a source names,%{"added" => "new", "fixed" => "fixed"}(%{}). A kind that is a category's key is that category.:github- how a merged pull request's labels speak to the inbox (seeTayori.GitHub)::label_prefix("changelog:"), and:only_labeled, to take only the pull requests with a label of the prefix (false).
:digest- when the inbox becomes an entry (seeTayori.Digest)::every-:manual(the admin asks),:ingest(each time changes come),{:weekly, day}(:monday...:sunday;:weeklyis Monday),:monthly(the first day), or{:days, n}, n days after the last (:manual).:at- the time of day of a scheduled digest, UTC (~T[09:00:00]).:publish-:draft, for the admin to read and publish, or:publish, at once (:draft).:minimum- the changes a scheduled digest needs (1): with fewer, they wait for the next.:translate- with AI, the entry in the other:localestoo, translated by the model (false).
:emails- when the subscribers get the entries to email (the:subscriptionsfeature; seeTayori.Subscribers)::every-:each, an email for each entry when it is published, or an email of the entries of a period:{:weekly, day}(:weeklyis Monday),:monthly(the first day), or{:days, n}(:each).:at- the time of day of an email of a period, UTC (~T[09:00:00]).
:mcp- the MCP server,Tayori.MCP, for an app that serves it with Sake (see the MCP guide)::resolver- the app'sTayori.Resolver, which says what the principal of a request may do (Tayori.Resolver.resolve_access/1) and who writes (Tayori.Resolver.author/1), as in the admin. Without it, nobody may use the server.:upload_url- the address of the uploads route oftayori_api, whole ("https://atelier.app/api/news/uploads"), where an agent sends its screenshots. Without it, an agent sends only small images, in the call.:storage- theKotoba.Storageof the uploads (Kotoba's own config when not given), the one of the admin's editor.
:scheduler-falseruns no scheduler: nothing is announced, and no schedule runs, by itself. For an app's tests, where the scheduler's queries would outlive a test's sandbox, andTayori.Test.announce!/0announces in the test's process (true).:embed- the sites of the:embedfeature (required with it)::origins- the origins the JSON API answers, each a scheme and a host, with a port if not the default (["https://www.atelier.app"]): no path, no wildcard.:max_age- how long a reader token is valid, in seconds (86400, a day).
The feature also needs
:secret_key_base, which signs the tokens.
Summary
Types
The :digest option, checked.
The :emails option, checked.
An extra the app can turn on.
The :inbox option, checked.
The :mcp option, checked.
Functions
The language every entry has.
Whether the app turned an extra on.
All the extras an app can turn on.
The config of the running Tayori. Raises when Tayori is not in the app's supervision tree.
Builds the config from the options of the child, and checks them.
Keeps the config for the whole node.
Types
@type digest() :: %{ every: :manual | :ingest | :monthly | {:weekly, atom()} | {:days, pos_integer()}, at: Time.t(), publish: :draft | :publish, minimum: pos_integer(), translate: boolean() }
The :digest option, checked.
@type emails() :: %{ every: :each | :monthly | {:weekly, atom()} | {:days, pos_integer()}, at: Time.t() }
The :emails option, checked.
@type feature() ::
:reactions | :announcements | :analytics | :subscriptions | :webhooks | :embed
An extra the app can turn on.
@type inbox() :: %{ sources: [{module(), keyword()}], ingest_on_start: boolean(), audience: String.t(), kinds: %{required(String.t()) => String.t()}, github: %{label_prefix: String.t(), only_labeled: boolean()} }
The :inbox option, checked.
The :mcp option, checked.
@type t() :: %Tayori.Config{ digest: digest(), email_from: String.t() | {String.t(), String.t()} | nil, emails: emails(), embed: %{origins: [String.t(), ...], max_age: pos_integer()} | nil, features: [feature()], inbox: inbox(), locales: [String.t(), ...], mailer: module() | nil, mcp: mcp() | nil, notifier: module() | nil, oban: %{name: term(), queue: atom()} | nil, page_url: String.t() | nil, prefix: String.t() | nil, pubsub: atom(), reactions: [String.t(), ...], repo: module(), scheduler: boolean(), secret_key_base: String.t() | nil, vault: module() | nil }
Functions
The language every entry has.
Whether the app turned an extra on.
@spec features() :: [feature()]
All the extras an app can turn on.
@spec get() :: t()
The config of the running Tayori. Raises when Tayori is not in the app's supervision tree.
Builds the config from the options of the child, and checks them.
@spec put(t()) :: :ok
Keeps the config for the whole node.