local-tts

agent
Guvenlik Denetimi
Uyari
Health Uyari
  • License — License: MIT
  • Description — Repository has a description
  • Active repo — Last push 0 days ago
  • Low visibility — Only 5 GitHub stars
Code Gecti
  • Code scan — Scanned 12 files during light audit, no dangerous patterns found
Permissions Gecti
  • Permissions — No dangerous permissions requested

Bu listing icin henuz AI raporu yok.

SUMMARY

Make your coding agent talk to you! -- Simple, offline and online (optional). Ask your coding agent to install it for you

README.md

local-tts

local-tts logo

local-tts - Make your coding agent talk to you! Offline! | Product Hunt
License: MIT Python 3.9+
Buy Me A Coffee

Make your coding agent talk to you!

A tiny command-line text-to-speech tool. It shells out to llama.cpp's llama-tts
by default, so speech is generated locally and offline.

$ tts "Hello from my terminal."
$ echo "Read this out loud." | tts
$ tts -f chapter1.txt -o chapter1.wav

Zero runtime dependencies. The package installs nothing but itself — no
requests, no numpy, no audio libraries. Everything is Python's standard library
plus binaries you already have (or install once, on your terms).


Contents


Requirements

What Why Required?
Python ≥ 3.9 runs the CLI yes
Linux, macOS or Windows all three supported
llama-tts from llama.cpp the default speech backend yes, for the default provider
An audio player (ffplay, paplay, aplay, …) playing the result only if you want playback

Installing llama.cpp

local-tts calls the llama-tts binary; it does not bundle or build llama.cpp.

# macOS / Linux (Homebrew)
brew install llama.cpp

# Windows
winget install llama.cpp

# Prebuilt binaries for every platform
# https://github.com/ggml-org/llama.cpp/releases  (grab llama-<build>-bin-<platform>.zip)

# Or build from source
git clone https://github.com/ggml-org/llama.cpp
cd llama.cpp
cmake -B build
cmake --build build --config Release -j
# binaries land in build/bin — put that on your PATH, or see "Configuration" below

Verify it is reachable:

llama-tts --version

If llama-tts is not on your PATH, point local-tts at it directly:

tts config --set llamacpp.binary=/path/to/llama.cpp/build/bin/llama-tts

Speech models

You do not need to download anything by hand. On the first run, llama-tts
fetches its default OuteTTS weights plus the
WavTokenizer vocoder into the Hugging Face cache (~/.cache/huggingface/hub,
about 640 MB total). Later runs use the cache and work fully offline.

To use your own GGUF weights instead, see Using your own models.


Install

Everything happens inside a virtual environment so nothing touches your system Python.

git clone <this-repo> local-tts
cd local-tts

python -m venv .venv
source .venv/bin/activate          # Windows: .venv\Scripts\activate

python -m pip install --upgrade pip   # needs pip >= 24.2 for the package metadata
pip install -e .

That puts two equivalent commands on your PATH (while the venv is active): tts
and local-tts.

Prefer a system-wide command without activating the venv?
# pipx keeps the tool isolated but always on your PATH
pipx install .

# or symlink the venv entry point somewhere on your PATH
ln -s "$PWD/.venv/bin/tts" ~/.local/bin/tts

The symlink works from any directory because the entry point's shebang is an absolute path
to the venv's interpreter. The install is editable, so edits to src/localtts/ take effect
immediately — but do not move or delete the repo, since the link points into it. Undo with
rm ~/.local/bin/tts.

Install with an AI agent

If you use an AI coding agent (Claude Code, Cursor, Copilot, …), the whole setup —
including detecting what is already on the machine, installing the backends, and creating
the global symlink — is scripted for it in AGENT_INSTALL.md.

Point your agent at this repository and say what you want:

"Install this with the link."

or, more specifically:

"Read AGENT_INSTALL.md and install local-tts with piper in Spanish, and make it global."

The agent will detect what you already have, ask once about anything missing, and validate
the result with tts check plus a real synthesis. It is written to ask before installing
anything, downloading a model, creating a symlink, or running sudo
— so you approve
each decision rather than discovering it afterwards.

Phrases it understands without further questions:

Say Meaning
"with the link" / "make it global" create the ~/.local/bin/tts symlink
"with piper" / "for Spanish" (any language) also install piper and a matching voice
"just the CLI" package only, no backends, no symlink
"install everything" all steps approved, plan still shown first

Prefer doing it yourself? Everything the agent does is the same set of commands documented
in Requirements, Install and Providers below.

Verify the install

tts check
config file : /home/you/.config/local-tts/config.json (not created yet)
default     : llamacpp

[ok] llamacpp  /usr/local/bin/llama-tts -> default OuteTTS (downloaded on first run)
[--] openai    https://api.openai.com/v1 (no api_key and $OPENAI_API_KEY is unset)
[--] piper     piper: 'piper' not found on PATH. ...
[ok] command   espeak-ng -w {output} {text}

players     : ffplay, paplay

Only the line matching your default provider has to say [ok].


Updating

There's no auto-update and no PyPI package — local-tts lives in the git clone from
Install. Updating means pulling that repo, plus refreshing the couple of things
that are copies of it rather than live links.

cd local-tts               # the repo you cloned in Install
git status --short         # make sure there's nothing uncommitted first
git pull

# editable install (the default): src/ changes are live immediately. Rerunning this
# is still worth it — it's a no-op most of the time, but it's what picks up a
# pyproject.toml change (entry point, version, python floor), and it costs nothing
# since the package has zero runtime dependencies
pip install -e .

# pipx install instead? pipx never re-reads the source directory on its own:
pipx install . --force

Two more things are snapshots taken at install time, not symlinks into the repo, so
pulling doesn't update them on its own:

tts skills --install    # refreshes the skill copies every detected agent is reading
tts hooks --install      # only if `tts hooks --status` shows one is active

Then tts --version and tts check to confirm it landed.

If you use a coding agent, the whole thing — including finding the repo behind whatever
install method you used — is the local-tts-update skill from
Coding-agent skills; just say "update local-tts."


Quick start

# speak an argument
tts "The quick brown fox jumps over the lazy dog."

# speak a pipe
git log -1 --format=%s | tts

# speak a file, save the audio instead of playing it
tts -f notes.md -o notes.wav

# save and play
tts -o greeting.wav --play "Good morning."

# narrate a markdown document: syntax stripped, long text chunked and joined
tts -f README.md -o readme.wav

# see the exact backend command (and the chunk plan) without running it
tts --dry-run -f README.md

The first invocation is slow: it downloads the model. After that a short sentence
takes a couple of seconds on CPU.


Usage

tts [options] [TEXT ...]
tts providers
tts check
tts config [--show | --path | --init | --set KEY=VALUE]
Option Description
TEXT ... Text to speak. Omit it to read stdin.
-f, --file FILE Read the text from a file (- for stdin).
--markdown / --no-markdown Force markdown stripping on or off (automatic for .md files).
-o, --output FILE Write the audio here instead of playing it.
-p, --provider NAME llamacpp (default), openai, piper, command.
-l, --lang CODE Use the backend and voice remembered for this language.
-v, --voice VOICE Speaker file (llamacpp), .onnx voice (piper), or voice name (openai).
-m, --model MODEL Override the provider's model for this run.
-s, --set KEY=VALUE Override any provider setting for this run. Repeatable.
-b, --background Play in the background, return immediately, keep the file and print its path.
--play Play the audio and keep --output.
--no-play Never play; just report the file path.
--player CMD Force a playback command instead of autodetecting.
--keep Keep the temporary file and print its path.
--dry-run Print the backend command that would run, then exit.
--verbose Show the backend's own (noisy) output.
--version Print the version.

Input precedence is TEXT--file → stdin. Without --output, audio goes to a
temporary file that is played and then deleted (--keep keeps it).

Markdown is handled for you. Reading a .md file strips headings, emphasis, link
URLs, bullet markers, tables and fenced code blocks before synthesis, so none of it gets
read aloud. Override either way with --markdown / --no-markdown.

Long documents are handled for you too. Backends that need short prompts (llamacpp)
get the text split at sentence boundaries, synthesized piece by piece, and joined into a
single file with a short pause between pieces. Backends that manage long input themselves
(piper) receive it whole. See max_words below.

Exit codes: 0 success, 1 error (with a one-line message on stderr), 130 interrupted.


Background playback

--background (-b) starts playback detached and returns straight away, so a long file
does not block the shell — or an agent driving it. The file is kept and its path printed.

$ tts -b --lang es -f documento.md
playing in the background (pid 4123, 0:12) — `tts stop` to end it, `tts playback` for progress
/tmp/local-tts-a1b2c3d4.wav

Control it afterwards, with elapsed time tracked against the file's real duration:

$ tts playback
playing [###########---------] 0:03 / 0:05 (pid 4123): /tmp/local-tts-a1b2c3d4.wav

tts pause
tts resume
tts stop

Starting a new background playback stops the previous one, so voices never stack.
pause/resume use SIGSTOP/SIGCONT and therefore work on Linux, macOS and WSL; on
native Windows they report that they are unsupported and stop is the control.

Coding-agent skills

local-tts ships three skills that teach a coding agent to use it, and installs them into
whichever agents it finds on your machine:

  • local-tts-speak — speak to the user. Triggers on "talk to me", "read this aloud",
    "narrate this file", "háblame", and so on. Instructs the agent to check the language
    memory first, to always use -b (and to run the command itself non-blocking), to play the
    whole thing regardless of length unless told otherwise, to offer stop/pause/resume,
    to always report the file path, and never to read secrets out loud.
  • local-tts-configure — install, diagnose and configure: backends, voices for a new
    language, playback, and the per-language memory. Starts from tts check and asks before
    installing or downloading anything.
  • local-tts-update — update an already-installed CLI to the latest version. Locates
    the repo behind the running tts command, pulls it, reinstalls only if that's actually
    needed, and refreshes the skill/hook files that are copies rather than live links to the
    repo. See Updating.
tts skills                       # what was detected, and what is installed
tts skills --install             # install into every detected agent
tts skills --install gemini      # or just one
tts skills --install --dry-run   # show the paths without writing
tts skills --uninstall           # remove them again

Restart the agent (or open a new session) afterwards so it picks them up.

Agent Installed as
Claude Code ~/.claude/skills/<name>/SKILL.md
Gemini CLI ~/.gemini/skills/<name>/SKILL.md
OpenCode <config>/opencode/skills/<name>/SKILL.md
Qwen Code ~/.qwen/skills/<name>/SKILL.md
Codex CLI section in ~/.codex/AGENTS.md
Cursor ~/.cursor/rules/local-tts.mdc
Windsurf ~/.codeium/windsurf/memories/local-tts.md
GitHub Copilot <config>/github-copilot/local-tts-instructions.md

<config> is %APPDATA% on Windows and ~/.config on Linux and macOS
($XDG_CONFIG_HOME wins on any platform when set). Detection only writes where the agent's
directory already exists, so nothing is created for agents you do not use.

Agents with a real skill mechanism get one file per skill. Agents that read a single flat
instructions file get a block delimited by <!-- BEGIN local-tts skills --> markers —
anything already in that file is preserved, reinstalling replaces only the block, and
--uninstall removes it and leaves the rest untouched.

Status-bar hook

By default, speaking prints a status line in chat each time. Two coding agents can instead
show live progress in their own status bar — verified against their actual settings
schemas, not assumed:

Agent Mechanism
Claude Code ~/.claude/settings.jsonstatusLine.command, with a real refreshInterval timer (1–60s)
Qwen Code ~/.qwen/settings.jsonui.statusLine.command, same idea
tts hooks                # what's detected, installed, and why the rest can't do this
tts hooks --install      # install into every detected supported agent
tts hooks --status       # is a hook live right now? (exit 0/1; used by the skill)
tts hooks --uninstall    # remove it, restoring whatever status line was there before
$ tts hooks
supported : claude-code, qwen

[ok] claude-code  active
[  ] qwen         agent not detected

[xx] codex        not supported: no status line mechanism yet (open feature request upstream)
[xx] copilot      not supported: has one, but its config schema isn't documented solidly enough to target yet
[xx] cursor       not supported: would need a full VS Code extension, not a lightweight hook
[xx] gemini       not supported: footer settings are show/hide toggles only; no custom command
[xx] opencode     not supported: no status line mechanism yet (open feature request upstream)
[xx] windsurf     not supported: would need a full VS Code extension, not a lightweight hook

Only these two have a documented "run my command, show its stdout in the status bar"
mechanism today. Gemini CLI's footer is hide/show toggles only (checked its shipped
settingsSchema.js); Codex CLI and OpenCode both have open upstream feature requests for
this, not yet shipped; Cursor and Windsurf are VS Code forks where a status-bar item means
writing a real extension, not a lightweight hook; GitHub Copilot CLI has one, but its
config schema isn't documented solidly enough to target without an install to test against.

Install never rewrites an existing status line — it appends into it. If your settings
already point at a script (yours, or another tool's), that pointer is never touched;
instead a small block is added to the end of that script file, so the original tool keeps
owning its slot and keeps running exactly as it always did. Idle, output is byte-for-byte
what it was before — our block only adds text while something is actually playing:

$ tts hooks --install claude-code
  claude-code  did append into /home/user/.claude/statusline-command.sh -- your existing
               status line is untouched, and picks this up on its very next refresh

This only appends into a plain path to a writable script file — not a one-liner, not a
command with arguments, not something unwritable. If the existing command doesn't qualify,
install refuses and shows you the exact block to add by hand, or you can pass --force to
replace the pointer outright (the old chain-by-reference behavior — the existing command
still runs, but the tool that owned it no longer does, which is a real tradeoff, not a free
upgrade; only reach for it when appending genuinely isn't possible). Reinstalling replaces
our block in place rather than duplicating it. --uninstall removes only our block and
leaves the rest of the file untouched, or drops the settings key entirely if nothing was
configured before we installed.

Appended mode takes effect on the very next status-bar refresh — no restart needed, since
only the script's content changed, not anything Claude Code reads once at startup. A fresh
install with nothing configured before (or --force) does need a restart, since those set
statusLine.command/refreshInterval directly. When a hook is live, the local-tts-speak
skill stops printing its own status line — tts hooks --status is what it checks.

Refresh cadence

With nothing else configured, a fresh install defaults to a real 2-second timer. When
appending into an existing status line, the existing refresh cadence — timer or
event-only — is left exactly as it was by default, since changing it also changes how often
the other tool's own script re-runs, not just ours:

tts hooks --install claude-code --refresh-interval 2   # a real timer, ticks live
tts hooks --install claude-code --refresh-interval 0   # explicitly event-based, no timer
tts hooks --install claude-code                        # leave whatever cadence was already there

0 is a deliberate choice, not the same as omitting the flag — it removes refreshInterval
outright (so the status bar only redraws on host events like a new message), whereas
omitting the flag means "don't decide, leave it as configured." Changing the cadence
(anything other than "leave it as configured") does write to settings.json — just the
refreshInterval key, never command — so that one does need a restart.

Multiple sessions

Running more than one session at once (two terminals, two agent instances) works without
one's audio stopping another's or its status bar showing the wrong progress. Pass
--session with anything that identifies the run:

tts -b --session "$CLAUDE_CODE_SESSION_ID" "hello"
tts stop --session "$CLAUDE_CODE_SESSION_ID"

Playback state is stored per session; starting playback only stops a previous playback
from the same session. --session is auto-detected when omitted — currently from
$CLAUDE_CODE_SESSION_ID, verified by capturing a live status-line payload from Claude Code
and confirming it carries the exact same value in its session_id field, which is also how
the status-bar hook knows which session's progress to show. Omit --session entirely and
everything works exactly as before it existed — one shared slot.

Language memory

Which backend speaks which language is remembered in the config file, so the preference
survives sessions and is shared by every agent rather than living in one agent's memory.

tts languages                                     # show what is recorded
tts languages --set es=piper:~/voices/es_MX.onnx  # provider + voice
tts languages --set en=llamacpp                   # provider only
tts languages --forget de

Then just name the language:

tts --lang es "Hola, ya terminé."
tts --lang es -f documento.md -o documento.wav

The lookup prefers the specific tag over the base one, so with both recorded, --lang es-MX
picks the Mexican entry while --lang es picks the generic one. Explicit flags always win
over the memory, and a recorded voice is only applied to the provider it was recorded for —
a piper .onnx is never handed to llama.cpp.

This is what the agent skills write to when you give feedback like "use piper for
Spanish"
or "that accent is wrong, use the Mexican voice". You can also set it per shell
with LOCALTTS_LANG_ES=piper:/path/voice.onnx.

Providers

tts providers

llamacpp — default, local, offline

Runs llama-tts. Zero configuration: with no model set it passes
--tts-oute-default and llama.cpp handles the weights.

Setting Default Description
binary llama-tts Path to or name of the executable.
model (empty) TTS GGUF. Empty means "use the default OuteTTS weights".
vocoder (empty) WavTokenizer GGUF. Required whenever model is set.
hf_repo / hf_file (empty) Pull the TTS model from Hugging Face instead.
hf_repo_vocoder / hf_file_vocoder (empty) Same, for the vocoder.
speaker_file (empty) Voice profile JSON (--tts-speaker-file).
max_words 26 Words per prompt; longer text is split and re-joined. 0 disables.
threads 0 CPU threads; 0 lets llama.cpp decide.
gpu_layers null Layers to offload (-ngl); null keeps llama.cpp's default.
guide_tokens true --tts-use-guide-tokens, improves word recall.
extra_args [] Extra flags appended verbatim.

Output is 24 kHz mono WAV. The default OuteTTS weights speak English, Chinese,
Japanese and Korean
; other languages come out with English phonetics, so use the
piper provider for those. Quality also
drops on long prompts, which is why max_words splits them — raise or lower it to trade
continuity against reliability.

Using your own models

tts config --set llamacpp.model=~/models/OuteTTS-0.2-500M-Q8_0.gguf
tts config --set llamacpp.vocoder=~/models/WavTokenizer-Large-75-F16.gguf

Or fetch them from Hugging Face at run time:

tts config --set llamacpp.hf_repo=OuteAI/OuteTTS-0.2-500M-GGUF
tts config --set llamacpp.hf_file=OuteTTS-0.2-500M-Q8_0.gguf
tts config --set llamacpp.hf_repo_vocoder=ggml-org/WavTokenizer
tts config --set llamacpp.hf_file_vocoder=WavTokenizer-Large-75-F16.gguf

Speed it up with your own hardware settings:

tts -s threads=8 -s gpu_layers=99 "offloaded to the GPU"

openai — any OpenAI-compatible endpoint

Speaks HTTP (POST /v1/audio/speech) using urllib — no SDK involved. It works
with OpenAI itself and with local servers such as
openedai-speech,
Kokoro-FastAPI, or LocalAI.

Setting Default
base_url https://api.openai.com/v1
api_key (empty — falls back to $OPENAI_API_KEY)
model tts-1
voice alloy
speed 1.0
timeout 120
export OPENAI_API_KEY=sk-...
tts -p openai -v nova "Hello from the cloud."

# a local server needs no key at all
tts config --set openai.base_url=http://localhost:8880/v1
tts -p openai -o out.mp3 "Local, but OpenAI-shaped."

This is the only provider that writes formats other than WAV — the output
extension picks the format (wav, mp3, opus, aac, flac, pcm).

piper — small, fast, offline, many languages

Piper runs neural ONNX voices on the CPU at
roughly 7x realtime, with good models for ~40 languages. Use it when llamacpp does not
cover your language: the default OuteTTS weights handle English, Chinese, Japanese and
Korean only, and will read anything else with English phonetics.

Piper is distributed as a Python wheel (piper-tts, GPL-3.0). Install it in its own
virtualenv so its ~200 MB of dependencies (onnxruntime, numpy) stay out of this project,
then point local-tts at the binary:

python -m venv ~/.local/share/piper-venv
~/.local/share/piper-venv/bin/pip install piper-tts

# list every voice, then fetch the one you want (~60 MB for "medium", ~63 MB for "high")
mkdir -p ~/.local/share/piper-voices && cd ~/.local/share/piper-voices
~/.local/share/piper-venv/bin/python -m piper.download_voices            # list
~/.local/share/piper-venv/bin/python -m piper.download_voices es_MX-claude-high

tts config --set piper.binary=~/.local/share/piper-venv/bin/piper
tts config --set piper.model=~/.local/share/piper-voices/es_MX-claude-high.onnx
tts -p piper "Piper es muy rápido en una CPU."

Voice weights live at rhasspy/piper-voices
(MIT/CC, no account or API token needed). Naming is <lang>_<REGION>-<speaker>-<quality>,
where quality is x_low, low, medium, or high.

Piper splits long input into sentences by itself, so an entire document works in one call:

tts -p piper -f article.md -o article.wav
Setting Default Description
binary piper Path to or name of the executable.
model (empty) Path to a .onnx voice. Required.
speaker null Speaker id for multi-speaker voices.
extra_args [] Extra flags appended verbatim.

command — anything else

An escape hatch for any binary that can write a WAV file. {text} and {output}
are substituted as single argv items, so text is never re-parsed by a shell.

tts config --set 'command.template=espeak-ng -w {output} {text}'
tts -p command "Whatever tool you like."

# macOS
tts config --set 'command.template=say -o {output} --data-format=LEI16@22050 {text}'

Configuration

Settings are resolved in this order, later winning:

built-in defaults  <  config file  <  environment variables  <  CLI flags

Config file

tts config --path      # where it lives
tts config --show      # the effective configuration, defaults included
tts config --init      # write a file containing every default, ready to edit

Default location:

Platform Path
Linux / macOS ~/.config/local-tts/config.json
Windows %APPDATA%\local-tts\config.json
any, if XDG_CONFIG_HOME is set $XDG_CONFIG_HOME/local-tts/config.json

$LOCALTTS_CONFIG overrides the path entirely. The file only needs to contain what you
change:

{
  "provider": "llamacpp",
  "play": true,
  "providers": {
    "llamacpp": {
      "threads": 8,
      "gpu_layers": 99
    }
  }
}

Write to it from the CLI:

tts config --set provider=piper
tts config --set llamacpp.threads=8
tts config --set play=false

Top-level keys are provider, play (play by default when no --output), and
player (force a playback command). Everything else is <provider>.<key>.

Environment variables

Variable Effect
LOCALTTS_CONFIG Use a different config file path.
LOCALTTS_PROVIDER Default provider.
LOCALTTS_PLAY true/false.
LOCALTTS_PLAYER Playback command.
LOCALTTS_<PROVIDER>_<KEY> Any provider setting, e.g. LOCALTTS_LLAMACPP_THREADS=8.
OPENAI_API_KEY Fallback key for the openai provider.

Per-run overrides

-s/--set changes a setting for one invocation only:

tts -s threads=4 "just this once"
tts -p openai -s model=tts-1-hd -s speed=1.15 "faster, nicer"

Audio playback

There is no audio library to install.

Platform Player
Windows PowerShell's built-in sound player — nothing to install
macOS afplay, built in
Linux the first of ffplaypaplayaplayplaympvcvlc
WSL a Linux player if present, otherwise it reaches out to Windows automatically
sudo apt install ffmpeg     # Debian/Ubuntu
brew install ffmpeg         # macOS

tts --player mpv "use this one instead"
tts config --set player=ffplay

If nothing is found, the file is kept and its path printed instead of vanishing.


Troubleshooting

llama-tts: 'llama-tts' not found on PATH
Install llama.cpp, or point at the binary: tts config --set llamacpp.binary=/full/path/to/llama-tts.

llamacpp.model is set but llamacpp.vocoder is not
llama-tts needs two files: the TTS model and the WavTokenizer vocoder. Set both,
or clear model (tts config --set llamacpp.model=) to fall back to the defaults.

llamacpp can only write .wav files
Only the openai provider produces other formats. Render WAV, then convert:
ffmpeg -i out.wav out.mp3.

"no audio player found"
Install ffmpeg, or use --output and open the file yourself.

First run hangs for a long time
It is downloading ~640 MB of weights. Run with --verbose to watch the progress.

The backend failed and I want to know why
--verbose streams the backend's own stderr; --dry-run prints the exact command
so you can run it by hand.


Development

python -m venv .venv
source .venv/bin/activate
pip install -e .

python -m unittest discover -s tests -v   # no test dependencies either

Layout:

src/localtts/
├── cli.py            argument parsing and the four subcommands
├── config.py         defaults, config file, env vars, precedence
├── text.py           markdown stripping and sentence-aware chunking
├── audio.py          playback autodetection and wav joining
├── skills.py         agent detection and skill installation
├── agent_skills/     the skill markdown shipped to agents
├── errors.py         TTSError -> a clean one-line message
└── providers/
    ├── base.py       Provider contract + subprocess helpers
    ├── llamacpp.py   default backend
    ├── openai.py     OpenAI-compatible HTTP
    ├── piper.py      Piper ONNX voices
    └── command.py    user-defined template

Adding a provider: subclass Provider, implement synthesize(text, out_path, voice)
and check(), register it in providers/__init__.py, and add its defaults to
config.DEFAULTS["providers"]. A test asserts those two stay in sync.

License

MIT

Yorumlar (0)

Sonuc bulunamadi