Skip to main content

Shell notification sound on selected exit codes; interactive installer for zsh/bash/fzf.

Project description

faah

Play a short sound when your interactive shell hits “command not found” (127) or “not executable” (126) by default — not for every failing command (false, grep miss, etc.), unless you opt in. Optional fzf defaults and Cursor / VS Code helper file copies.

Install (PyPI / uv) — recommended

pip install faah
# or
uv tool install faah

Then run the interactive installer (requires a TTY):

faah
# same as:
faah install

Use faah help for usage (preferred over faah --help; both work).

Roadmap

Released changes are listed in CHANGELOG.md. Planned direction for 2.1+ and later (plugin-style hooks for visuals and audio, optional config file, shell parity, CI/portability) is in ROADMAP.md.

This syncs bundled shell assets into ~/.config/faah/ (or $XDG_CONFIG_HOME/faah when XDG_CONFIG_HOME is set) and adds a single marked block to ~/.zshrc and/or ~/.bashrc that sources the managed init/faah.{zsh,bash} files.

Non-interactive (e.g. CI):

faah install --yes

Terminal-matrix (cmatrix-style F / A / H / ! rain) is the only visual: it runs on faah usage mistakes and on shell-hook triggers (127 / 126 by default), unless you opt out. faah install asks about matrix for each shell you install; faah install --yes defaults to on. Opt out with --no-matrix (adds export FAHH_DISABLE_MATRIX=1 in a matrix-disable block). Older installs may still have banner-env / matrix-env blocks — a new faah install removes those legacy markers.

Other commands:

Command Purpose
faah help Show CLI usage (preferred over faah --help)
faah doctor Check mpv/ffplay/paplay/aplay, fzf, sound file
faah doctor --fix On Debian/Ubuntu with apt-get, install missing tools (sudo)
faah play Play the sound once
faah terminal-matrix F / A / H / ! rain: full-screen on a TTY; scrolling line flood when stderr is not a TTY (use -s / --seconds for duration)
faah uninstall Remove faah blocks from rc files and install/ helpers
faah --version Package version

Upgrade:

pip install -U faah
# or
uv tool upgrade faah

If you previously installed 2.0.0rc1, upgrade with pip install -U faah (or uv tool upgrade faah) to get the current line. 2.0.1 includes the mpv no-window fix for faah play / play-faah.sh. 2.1.0 (terminal-matrix overhaul, hook fixes, and related changes) is documented in CHANGELOG.md.

Development (from this repo)

Uses uv (see pyproject.toml and uv.lock).

uv sync --all-extras
PYTEST_DISABLE_PLUGIN_AUTOLOAD=1 uv run pytest -q
uv run ruff check src tests
uv run python -m build

Console entrypoint: faahfaah.cli:main.

Repository layout

Everything user-facing after install lives under ~/.config/faah/, populated from a single bundled tree in the Python package:

src/faah/
├── __init__.py          # version
├── cli.py               # Typer CLI
├── cli_exit.py          # usage-error (exit 2) → matrix
├── terminal_matrix.py   # cmatrix-style effect + plain flood
├── sound.py             # play MP3 via mpv/ffplay/…
├── installer/           # rc blocks, sync bundled data, editor copies
└── data/                # only copy of shell assets (sdist/wheel)
    ├── assets/sounds/fahhh.mp3
    ├── scripts/play-faah.sh
    ├── zsh/  bash/  fzf/  init/
    ├── cursor/          # optional editor fragments (→ install/cursor when selected)
    └── vscode/
tests/                     # pytest
.github/workflows/         # CI + PyPI publish
Path Role
src/faah/ Python package; src/faah/data/ is the bundled shell + sound + editor snippets
src/faah/data/cursor/README.md Cursor terminal notes
src/faah/data/vscode/README.md VS Code terminal notes
ROADMAP.md Planned features and design direction (2.1+)

Environment variables

Variable Meaning
XDG_CONFIG_HOME If set, managed config is $XDG_CONFIG_HOME/faah (must not point at a parent of your clone such that this path equals the repository root). If unset, faah uses ~/.config/faah (i.e. $HOME/.config/faah).
FAHH_ROOT Managed config root (default: ~/.config/faah when using installed snippets)
FAHH_SOUND Path to sound file (default: $FAHH_ROOT/assets/sounds/fahhh.mp3)
FAHH_DISABLED If non-empty, hooks do nothing
FAHH_PLAY_ON_NONZERO If set and FAHH_PLAY_EXIT_CODES is unset: play on any non-zero exit
FAHH_PLAY_EXIT_CODES Space-separated codes that trigger sound (default: 127 126). Use all for any non-zero.
FAHH_IGNORE_EXIT When mode is all: codes to never trigger sound (default: 130)
FAHH_DISABLE_MATRIX If 1 / true / yes / on, skip terminal-matrix visuals (CLI usage errors and shell hooks). Set by faah install --no-matrix.
FAHH_REPLACE_NOT_FOUND If set (non-empty, not 0/false/no/off), install command_not_found_handler (zsh) or command_not_found_handle (bash 4+). Unknown commands: matrix + sound only — no default command not found line.
FAHH_MATRIX_SEC Duration for faah terminal-matrix when -s is omitted (default ~0.85 s).
FAHH_MATRIX_CLI_SEC Duration for faah usage mistakes (exit 2); default ~0.6 s (faster than a full run).
FAHH_MATRIX_HOOK_SEC Duration when zsh/bash hooks invoke matrix (default ~0.72 s).
FAHH_PYTHON Interpreter for python -m faah when faah is not on PATH (default python3). Must be a Python that has faah installed.
FAHH_MATRIX_FPS Frames per second (860, default ~26).
FAHH_MATRIX_CHARS Character set (default FAH!).

Troubleshooting

  • Usage errors / hooks: On faah … mistakes (exit 2), faah.cli:main runs terminal-matrix on stderr (unless FAHH_DISABLE_MATRIX). For unknown shell commands, set FAHH_REPLACE_NOT_FOUND=1 so zsh/bash call faah’s handler (matrix + sound) instead of the default command not found line. Run faah install --yes after upgrading so ~/.config/faah/zsh/faah.zsh / bash/faah.bash stay current.

  • Not a TTY: You still get a scrolling F/A/H/! flood (lighter than before). Hooks try faah first, then python3 -m faah if the CLI is not on PATH. faah doctor shows whether faah was found.

  • Feels slow: Lower FAHH_MATRIX_SEC, FAHH_MATRIX_HOOK_SEC, or FAHH_MATRIX_CLI_SEC (defaults were shortened in recent versions). Raise FAHH_MATRIX_FPS (e.g. 32) for snappier TTY animation.

  • No module named faah after a bad command: the shell hook used to run python3 -m faah whenever the faah program was missing from PATH. System /usr/bin/python3 often has no faah installed — that message is from Python. Fix: install the CLI (pip install faah, uv tool install faah, or uv sync in the repo and put faah on PATH), or run faah install --yes after upgrading so ~/.config/faah matches. The hook now runs python3 -m faah only if import faah succeeds (silent otherwise). Optional: export FAHH_PYTHON=/path/to/venv/bin/python if faah is only installed in a venv.

  • No sound: Install mpv or ffplay; run faah doctor.

  • A window opens when playing (mpv/ffplay): faah passes --force-window=no, --no-video, and --vo=null to mpv, and -nodisp to ffplay. Run faah install --yes to refresh ~/.config/faah/scripts/play-faah.sh, or upgrade faah. If it persists, check mpv --version and your desktop session (Wayland/X11).

  • faah install runs the hook instead of the CLI (e.g. you see faah:source: and the Python CLI never runs): Older rc snippets defined a shell function named faah that shadowed the real faah on your PATH. Workaround: run command faah install --yes once (zsh/bash: bypasses the function; same idea as \faah in zsh). After that, faah install updates the marked block to a one-liner that does not define faah, so the CLI works normally.

  • source: no such file ... ~/.config/faah/init/faah.zsh: Your rc still runs the faah bootstrap, but ~/.config/faah is missing or incomplete (removed by hand, failed install, etc.). Fix: run faah install --yes (or command faah install --yes if the function still shadows—see above), or remove the faah block from ~/.zshrc / ~/.bashrc (see faah uninstall). To edit rc without loading it: zsh -f then nano ~/.zshrc. The managed line is [[ -r ... ]] && source ... so a missing top-level init file does not error on startup.

  • Other errors from faah on startup: The rc line only skips loading when that main init/faah.{zsh,bash} is absent or not readable. It does not silence failures from source itself (e.g. syntax error in that file) or from nested source lines inside managed files (e.g. a partial/corrupt tree). Those messages are intentional so you notice a broken install—run faah install --yes or faah doctor, or remove the faah block.

  • assets/, bash/, zsh/, … appeared at the root of your git clone (with XDG_CONFIG_HOME unset): The intended location is ~/.config/faah, not the repo. This usually means ~/.config/faah was a symlink to your clone (or XDG_CONFIG_HOME used to be wrong so $XDG_CONFIG_HOME/faah was the clone). Fix: remove the symlink and use a real directory (mkdir -p ~/.config/faah after removing the link), delete stray copies from the clone (git status, then remove untracked assets/, bash/, … only if they are not part of src/faah/data/), run faah doctor — it reports unsafe if the resolved path still looks like a source checkout. Newer faah versions refuse to sync into a path that looks like the development repository.

  • Editors: Integrated terminals must load your interactive shell rc. See src/faah/data/cursor/README.md and src/faah/data/vscode/README.md.

Contributing

See CONTRIBUTING.md.

Pre-commit (optional)

pre-commit install
pre-commit run -a

License

Scripts and documentation: MIT License (SPDX-License-Identifier: MIT).

The bundled sound may be subject to separate rights; replace it with your own file if needed.

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

faah-2.1.0.tar.gz (62.5 kB view details)

Uploaded Source

Built Distribution

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

faah-2.1.0-py3-none-any.whl (65.3 kB view details)

Uploaded Python 3

File details

Details for the file faah-2.1.0.tar.gz.

File metadata

  • Download URL: faah-2.1.0.tar.gz
  • Upload date:
  • Size: 62.5 kB
  • Tags: Source
  • Uploaded using Trusted Publishing? Yes
  • Uploaded via: twine/6.1.0 CPython/3.13.12

File hashes

Hashes for faah-2.1.0.tar.gz
Algorithm Hash digest
SHA256 3d5bb71ac51a3b829a7722fca462bd8fe47eee8ccb3d9e4e93b3e299bbe35c00
MD5 8545662b13080be64d7790c4e0c3e689
BLAKE2b-256 30aa1f21a17d6518eeec36efb71d6a030cbaa0757b7e1574877ddf1d6ef9ef59

See more details on using hashes here.

Provenance

The following attestation bundles were made for faah-2.1.0.tar.gz:

Publisher: publish.yml on guilyx/faah

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

File details

Details for the file faah-2.1.0-py3-none-any.whl.

File metadata

  • Download URL: faah-2.1.0-py3-none-any.whl
  • Upload date:
  • Size: 65.3 kB
  • Tags: Python 3
  • Uploaded using Trusted Publishing? Yes
  • Uploaded via: twine/6.1.0 CPython/3.13.12

File hashes

Hashes for faah-2.1.0-py3-none-any.whl
Algorithm Hash digest
SHA256 97e797ecc991c0cfb40fe92ae8af9b4d908d0bad97271da6979890146496c251
MD5 9c3a97094e384a3a6938d789e8f10de6
BLAKE2b-256 74beb944beaeb8e24dfc1179e2734ccfad68cd9b757ad74f39810608ca32a3e7

See more details on using hashes here.

Provenance

The following attestation bundles were made for faah-2.1.0-py3-none-any.whl:

Publisher: publish.yml on guilyx/faah

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