Skip to main content

Speak text aloud from the terminal. Built for LLM agents to talk to you, with offline system TTS when no API key is configured.

Project description

saynow

npm PyPI CI dependencies MIT

Speak text aloud from the terminal. Built so LLM agents can talk to you.

saynow "the build finished, 42 tests passed"

Works with no configuration — it falls back to your OS's built-in voice, which is offline, free, and needs no API key. Add a key for better audio.

Install

pip install saynow          # or: uv tool install saynow

No third-party dependencies — standard library only. An identical npm package exists for Node; both read the same config file, so pick whichever runtime you already have.

Usage

saynow "text to speak"              # speak an argument
echo "text" | saynow                # speak stdin
pytest 2>&1 | tail -1 | saynow      # speak a command's last line
saynow -p openai -v nova "hello"    # pick a provider and voice
saynow --save note.mp3 "hello"      # write a file instead of playing
Provider Quality Needs
system Fair Nothing — built into the OS
openai Good OPENAI_API_KEY
elevenlabs Best ELEVENLABS_API_KEY
openrouter Good OPENROUTER_API_KEY

If a cloud provider is configured but its key is missing, saynow warns on stderr and speaks with the system voice anyway. Use --strict to opt out. Concurrent calls are serialized so speech never overlaps.

Configure

saynow init                          # interactive setup
saynow config set provider openai
saynow voices                        # available voices
saynow models                        # OpenRouter models that can speak

Config lives at ~/.config/saynow/config.json, mode 0600. Precedence is defaults → config file → environment → flags. API keys are never accepted as flags, since argv is visible to ps and lands in shell history.

Use it from an agent

Add this to your CLAUDE.md, AGENTS.md, or equivalent:

You can speak to the user out loud with `saynow "<text>"`. Use it for things
worth interrupting for: a long task finishing, a question that blocks
progress, or an error that needs attention. Keep it to one short sentence —
it is spoken aloud, not read. Do not narrate routine progress.

Asking, and showing

--ask speaks, then waits: a bubble appears in the corner with the transcript and a reply box, and whatever is typed comes back on stdout.

answer=$(saynow --from "billing · migration" --ask "Drop the old table?")

Exit 0 means they answered, 2 means they dismissed it or were away — never read 2 as consent. --file report.md renders a Markdown document in the same bubble: headings, tables, code, links and images, local or remote.

The bubble needs a window shell — Xcode command line tools on macOS, or any Chromium-based browser. Without one saynow still speaks, --ask exits 2, and --file is read aloud rather than shown.

Both builds read the same config file, so installing the npm one alongside this changes nothing you have already set up.

Claude Code users can install the plugin, which teaches Claude when to speak:

/plugin marketplace add dhruvyad/saynow
/plugin install saynow@saynow

Full reference

saynow --help    # complete reference: every flag, setting, and exit code

License

MIT — source at https://github.com/dhruvyad/saynow

Project details


Download files

Download the file for your platform. If you're not sure which to choose, learn more about installing packages.

Source Distribution

saynow-0.11.0.tar.gz (45.8 kB view details)

Uploaded Source

Built Distribution

If you're not sure about the file name format, learn more about wheel file names.

saynow-0.11.0-py3-none-any.whl (47.0 kB view details)

Uploaded Python 3

File details

Details for the file saynow-0.11.0.tar.gz.

File metadata

  • Download URL: saynow-0.11.0.tar.gz
  • Upload date:
  • Size: 45.8 kB
  • Tags: Source
  • Uploaded using Trusted Publishing? Yes
  • Uploaded via: twine/6.1.0 CPython/3.13.14

File hashes

Hashes for saynow-0.11.0.tar.gz
Algorithm Hash digest
SHA256 4adfbfb27ce725e0787369f72660391ae8bdd920c93205f7f48c9a1c42b55ecf
MD5 e05539470c57e330066c81a90de0674d
BLAKE2b-256 d7f1ecf5a2d23d2eebabe5b629af343d8688aa70a73e595ca5994342e0e66915

See more details on using hashes here.

Provenance

The following attestation bundles were made for saynow-0.11.0.tar.gz:

Publisher: release.yml on dhruvyad/saynow

Attestations: Values shown here reflect the state when the release was signed and may no longer be current.

File details

Details for the file saynow-0.11.0-py3-none-any.whl.

File metadata

  • Download URL: saynow-0.11.0-py3-none-any.whl
  • Upload date:
  • Size: 47.0 kB
  • Tags: Python 3
  • Uploaded using Trusted Publishing? Yes
  • Uploaded via: twine/6.1.0 CPython/3.13.14

File hashes

Hashes for saynow-0.11.0-py3-none-any.whl
Algorithm Hash digest
SHA256 9a5b01d8d86dc9ff8cc3f8a45c9ecaa124300a6b02eddd0140dea793fda16c37
MD5 55494c8d535179ffe017c2801e876424
BLAKE2b-256 1fd0309d23380cab7e6e5edcc6f1babd5e69f5202f5c121fe0b7a77f5bd468c3

See more details on using hashes here.

Provenance

The following attestation bundles were made for saynow-0.11.0-py3-none-any.whl:

Publisher: release.yml on dhruvyad/saynow

Attestations: Values shown here reflect the state when the release was signed and may no longer be current.

Supported by

AWS Cloud computing and Security Sponsor Datadog Monitoring Depot Continuous Integration Fastly CDN Google Download Analytics Pingdom Monitoring Sentry Error logging StatusPage Status page