# `Tayori.Config`
[🔗](https://github.com/hattoriai/tayori/blob/v0.1.0/lib/tayori/config.ex#L1)

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's `Phoenix.PubSub`, on which the app's pages
    hear of a new entry as it is published (required).
  * `:vault` - the app's `Cloak.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 the `Tayori.Notifier` behaviour, 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's `Swoosh.Mailer`, which sends the emails of
    the `:subscriptions` feature (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`, or `oban: [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, as
    `Tayori.Jobs` explains.
  * `:inbox` - where the changes of the inbox come from, and what they
    say when they do not (see `Tayori.Inbox` and the Automation guide):
      * `:sources` - `{module, opts}` of `Tayori.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 (see `Tayori.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 (see `Tayori.Digest`):
      * `:every` - `:manual` (the admin asks), `:ingest` (each time
        changes come), `{:weekly, day}` (`:monday` ... `:sunday`;
        `:weekly` is 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 `:locales` too,
        translated by the model (`false`).
  * `:emails` - when the subscribers get the entries to email (the
    `:subscriptions` feature; see `Tayori.Subscribers`):
      * `:every` - `:each`, an email for each entry when it is
        published, or an email of the entries of a period:
        `{:weekly, day}` (`:weekly` is 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](mcp.md) guide):
      * `:resolver` - the app's `Tayori.Resolver`, which says what the
        principal of a request may do (`c:Tayori.Resolver.resolve_access/1`)
        and who writes (`c:Tayori.Resolver.author/1`), as in the admin.
        Without it, nobody may use the server.
      * `:upload_url` - the address of the uploads route of `tayori_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` - the `Kotoba.Storage` of the uploads (Kotoba's own
        config when not given), the one of the admin's editor.
  * `:scheduler` - `false` runs 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, and
    `Tayori.Test.announce!/0` announces in the test's process (`true`).
  * `:embed` - the sites of the `:embed` feature (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.

# `digest`

```elixir
@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.

# `emails`

```elixir
@type emails() :: %{
  every: :each | :monthly | {:weekly, atom()} | {:days, pos_integer()},
  at: Time.t()
}
```

The `:emails` option, checked.

# `feature`

```elixir
@type feature() ::
  :reactions | :announcements | :analytics | :subscriptions | :webhooks | :embed
```

An extra the app can turn on.

# `inbox`

```elixir
@type inbox() :: %{
  sources: [{module(), keyword()}],
  ingest_on_start: boolean(),
  audience: String.t(),
  kinds: %{required(String.t()) =&gt; String.t()},
  github: %{label_prefix: String.t(), only_labeled: boolean()}
}
```

The `:inbox` option, checked.

# `mcp`

```elixir
@type mcp() :: %{
  resolver: module() | nil,
  upload_url: String.t() | nil,
  storage: module() | nil
}
```

The `:mcp` option, checked.

# `t`

```elixir
@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
}
```

# `default_locale`

```elixir
@spec default_locale(t()) :: String.t()
```

The language every entry has.

# `feature?`

```elixir
@spec feature?(t(), feature()) :: boolean()
```

Whether the app turned an extra on.

# `features`

```elixir
@spec features() :: [feature()]
```

All the extras an app can turn on.

# `get`

```elixir
@spec get() :: t()
```

The config of the running Tayori. Raises when Tayori is not in the app's
supervision tree.

# `new`

```elixir
@spec new(keyword()) :: t()
```

Builds the config from the options of the child, and checks them.

# `put`

```elixir
@spec put(t()) :: :ok
```

Keeps the config for the whole node.

---

*Consult [api-reference.md](api-reference.md) for complete listing*
