# Show HN: Beckon, distinct sounds for what your AI coding agent needs

> Source: <https://github.com/Isa1asN/beckon>
> Published: 2026-08-28 07:12:17+00:00

Distinct sounds for your AI coding agent, so you don't have to watch the terminal.

beckon binds to your agent's lifecycle hooks and plays a different sound depending on what it needs:

| Sound | Meaning | What to do |
|---|---|---|
| rising chime | finished its turn | go look |
| insistent sting | blocked on your decision | go unblock it |
| falling tone | it failed | go read the error |
| slow pulse | rate-limited or throttled | wait |

A single undifferentiated ding tells you something happened. It doesn't tell you whether to get up.

```
cargo install beckon-cli   # the binary is called `beckon`
beckon init                # binds the hooks — shows a diff and asks first
beckon test                # hear the active pack
```

Or from source: `git clone https://github.com/Isa1asN/beckon && cd beckon && cargo install --path .`

`init`

prints the exact change it will make to `~/.claude/settings.json`

, copies
the file to `settings.json.beckon-backup-<timestamp>`

beside itself, and only
then writes. `beckon uninstall`

removes beckon's entries and leaves everything
else alone.

It refuses to touch a settings file it cannot round-trip: invalid JSON, invalid
UTF-8, a non-object root, or an unfamiliar `hooks`

shape. A file it does accept
is re-serialised, so non-canonical formatting (CRLF, tabs, duplicate keys) is
normalised. Content is preserved; the backup keeps the original bytes.

| Builds | Test suite | Audio verified | |
|---|---|---|---|
| Linux x86-64 | yes | yes | yes |
| macOS | yes | in CI | no |
| Windows | yes | in CI | no |

CI runs the full suite on all three. CI runners have no sound device, so playback there goes through the null backend — the macOS and Windows audio paths compile and are exercised structurally, but nobody has heard them. Reports welcome.

Also built without the `embedded-audio`

feature, which is the shape a fully
static musl binary takes: no cpal, no libasound, falling back to a system
player.

Requires Claude Code. Other agents are planned; the adapter seam exists and is
documented in [docs/DESIGN.md](/Isa1asN/beckon/blob/main/docs/DESIGN.md).

```
beckon test                     # play every sound in the active pack
beckon packs                    # list packs
beckon use cipher               # switch pack
beckon mute 30m                 # quiet for a while (45s, 2h, …); unmute ends it
beckon doctor                   # why is it quiet? every reason, listed
beckon config set volume 0.4
beckon uninstall
```

By default beckon:

- says nothing when a turn finished in under 30 seconds — you were still watching
- always plays a blocking alert, however fast it arrived, because a permission prompt stalls progress
- doesn't repeat the same sound for the same session within 1.5 seconds
- stays quiet for a tool failure, since a failing test is normal work
(
`beckon config set events.tool-failed true`

to change that) - ignores a tool you interrupted yourself
- caps concurrent sounds at 8

If it's quiet and you didn't ask it to be, `beckon doctor`

says why.

Each project gets a stable transposition from a consonant scale, so
`api-server`

and `worktree-auth`

sound different with the same pack, and two
sounding together harmonise rather than clash. Nothing to configure; disable
with `beckon config set identity.per_project false`

.

Rate limiting is scoped per session and per state. A machine-wide throttle would let one agent's completion chime swallow another's permission alert.

Three ship inside the binary, all original, all CC0:

**aurora**— calm starship computer. Soft triangle arpeggios, long reverb.** cipher**— stealth-game alert. Short, dry, cuts through.** unit-7**— deadpan lab robot. Mechanical FM bleeps, no reverb.

A pack is a TOML file, not a folder of audio. Sounds are synth recipes — oscillators, envelopes, filters — about a kilobyte of text:

```
[sounds.done]
type = "synth"
reverb = { room = 0.55, mix = 0.34 }

[[sounds.done.layer]]
wave = "triangle"
notes = ["C5", "E5", "G5"]
step_ms = 92
filter = { kind = "lowpass", cutoff_hz = 3200 }
```

So a pack is provably original, weighs nothing, and can be reviewed as a diff. Auditing a folder of binary blobs for licence provenance is what makes shared sound libraries impractical.

To write one, drop a `pack.toml`

in `~/.local/share/beckon/packs/<id>/`

. It
shadows a built-in of the same name, so you can fork `aurora`

and keep the name.
`beckon test <id>`

to hear it.

You don't need to author a pack to use your own audio:

```
beckon config set sounds.needs-you ~/sounds/alert.wav
```

Anything you don't override falls through to the active pack, at every step of
the fallback chain — replace `failed`

and `rate-limited`

follows it. wav, ogg,
flac and mp3 are supported. The path is checked when you set it, so a typo fails
immediately rather than becoming silence you notice days later.

Or write the table directly:

```
# ~/.config/beckon/config.toml
[sounds]
needs-you = "~/sounds/alert.wav"
done      = "~/sounds/ding.wav"
```

`[sounds]`

is honoured only in your own config, never in a project's
`.beckon.toml`

. A repository you clone can change *when* beckon makes a noise;
it cannot name files on your machine and have them opened by a media decoder.

Sample files are bounded: regular files only, 10 MiB and 30 seconds maximum, and a pack's samples must resolve inside the pack after symlinks are followed.

- No daemon. Nothing runs between hooks. Your agent invokes beckon, it decides in ~5ms, hands playback to a detached child, and exits.
- No network at hook time.
- No telemetry.
- Packs are data, never executed.
- Exits 0 unconditionally — bad config, no audio device, corrupt input, panic.
beckon binds hooks that block the agent on a non-zero exit, so this is
verified against the release binary, where
`panic = "abort"`

puts it beyond the reach of`cargo test`

.

- Publish to crates.io
- Hear it on macOS and Windows (CI builds and tests there already)
-
`beckon install github:user/repo`

— packs from git - A browsable community pack index
- SSH: escape sequences so a remote agent alerts your local terminal
- Adapters for Codex, Cursor, Gemini
- npm and Homebrew distribution

```
git clone https://github.com/Isa1asN/beckon && cd beckon
./scripts/install-hooks.sh   # pre-commit: fmt + clippy
./check.sh --release         # everything CI enforces
```

`main`

requires a pull request and **signed commits**. If you don't already
sign, GitHub will reject the push without much explanation:

```
git config --global gpg.format ssh
git config --global user.signingkey ~/.ssh/id_ed25519.pub
git config --global commit.gpgsign true
```

Then add the same key to GitHub under Settings → SSH and GPG keys with key type
**Signing Key** — an authentication key does not count, and that catches most
people out.

CI runs fmt, clippy with `-D warnings`

, the suite on Linux/macOS/Windows, a
build with no audio backend, an MSRV check, the release-binary safety script,
and crates.io packaging. `./check.sh --release`

covers everything except the
other two platforms.

New sound packs are welcome — a pack is a TOML file, so a pull request adding
one is reviewable as a diff. Design notes: [docs/DESIGN.md](/Isa1asN/beckon/blob/main/docs/DESIGN.md).

Code is MIT OR Apache-2.0. The built-in packs are CC0-1.0.
