docs: talk-Skill mit Opt-in-Etikette, AGENTS-Snippet, README Installation/Release/Toast

skills/talk/SKILL.md: wann sprechen (nur auf Trigger in der Session oder
Standing-Order in der AGENTS.md, session-sticky bis Widerruf), wann nicht,
was eine gute Ansage ist (Status · nächster Schritt · wofür der Nutzer
gebraucht wird; Beispiele gut/schlecht), Umgang mit muted/discarded/
--now/Prioritäten, Pitfalls. AGENTS-snippet.md: der Block für Projekt-
AGENTS.md.

README: Installation (Release-Asset mit Prüfsumme, Nix-Flake, go install),
Skill-Abschnitt, Toast als echte Desktop-Benachrichtigung, Release-Ablauf
und nix build in „Entwicklung". Spec-Nachtrag: Release ohne GoReleaser,
Notifications ohne beeep.

Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
This commit is contained in:
m3ta-chironandClaude Fable 5.1 committed 2026-10-24 10:37:46 +02:00
1 parent 423377bade
commit 2e2bc27acf
4 files changed
+152 -3

No files matched your search

+46 -3
View File
@@ -29,6 +29,26 @@ Runtime-Abhängigkeiten.
Say-Flags (gelten auch für `talk "Text"`): `--wait`, `--now`, `--priority`, Say-Flags (gelten auch für `talk "Text"`): `--wait`, `--now`, `--priority`,
`--voice`, `--lang`, `--provider`. `--voice`, `--lang`, `--provider`.
## Installation
**Release-Binary** (Linux, macOS, Windows; amd64/arm64): von den
[Releases](https://code.m3ta.dev/m3tam3re/talk/releases) das passende
`talk_<os>_<arch>` laden, Prüfsumme gegen `checksums.txt` vergleichen, als
`talk` in den PATH legen. Keine weiteren Abhängigkeiten.
```console
curl -LO https://code.m3ta.dev/m3tam3re/talk/releases/latest/download/talk_linux_amd64
sha256sum -c --ignore-missing <(curl -sL https://code.m3ta.dev/m3tam3re/talk/releases/latest/download/checksums.txt)
install -m 755 talk_linux_amd64 ~/.local/bin/talk
```
**Nix** (Flake): `nix run git+https://code.m3ta.dev/m3tam3re/talk -- doctor`
oder in der Konfiguration `inputs.talk.url = "git+https://code.m3ta.dev/m3tam3re/talk";`
und `inputs.talk.packages.${system}.talk` bzw. `inputs.talk.overlays.default`.
Das Paket bringt espeak-ng (OS-Stimme) und libnotify (Toast) mit.
**Aus dem Quelltext:** `go install code.m3ta.dev/m3tam3re/talk/cmd/talk@latest`.
## Erste Schritte ## Erste Schritte
```console ```console
@@ -150,9 +170,10 @@ sind Opt-in wie Mute). In der Ruhezeit verfällt Audio, auch für high
(Burst ist ein Rate-Recht, kein Ruhe-Recht): (Burst ist ein Rate-Recht, kein Ruhe-Recht):
- `quiet_mode = "discard"` (Default): still verwerfen. - `quiet_mode = "discard"` (Default): still verwerfen.
- `quiet_mode = "toast"`: Benachrichtigung statt Audio — derzeit eine - `quiet_mode = "toast"`: Desktop-Benachrichtigung statt Audio — über die
Protokoll-Zeile über den Notification-Pfad (OS-Toast folgt mit der Bordmittel des Systems (Linux `notify-send`, macOS Notification Center,
Notification-Anbindung). Windows Toast), best effort: fehlt das Werkzeug, bleibt es bei der
Protokoll-Zeile, `talk doctor` zeigt es unter „Toast".
- `now:true` **bricht auch die Ruhezeit** (bewusster Ausbruch). - `now:true` **bricht auch die Ruhezeit** (bewusster Ausbruch).
**Länge und Alter:** Zwei weitere Gesetze gegen das, was Prompts gern tun **Länge und Alter:** Zwei weitere Gesetze gegen das, was Prompts gern tun
@@ -350,6 +371,18 @@ talk wrap --wait -- make test
label = "Deployment" # Ansage-Label statt Befehls-Basisname (TALK_WRAP_LABEL) label = "Deployment" # Ansage-Label statt Befehls-Basisname (TALK_WRAP_LABEL)
``` ```
## Für Agenten: Skill und Standing-Order
[`skills/talk/SKILL.md`](skills/talk/SKILL.md) ist die Etikette als
Skill-Artefakt: **striktes Opt-in** (Sprechen nur auf Aufforderung in der
Session oder Standing-Order in der AGENTS.md, session-sticky bis Widerruf),
Inhalt = Status · nächster Schritt · wofür der Nutzer gebraucht wird, nie
die Langantwort, `muted`/`discarded` respektieren. Der Drei-Zeilen-Block
für Projekt-AGENTS.md steht in
[`skills/talk/AGENTS-snippet.md`](skills/talk/AGENTS-snippet.md). Der
Daemon erzwingt Rate-Limit, Längen- und Alters-Grenze, Mute und Ruhezeit
unabhängig davon, was im Prompt steht.
## Entwicklung ## Entwicklung
```console ```console
@@ -357,11 +390,21 @@ go build ./... # bauen
go test ./... # Tests go test ./... # Tests
go vet ./... # statische Analyse go vet ./... # statische Analyse
gofmt -l . # Formatierung prüfen (leerer Output = ok) gofmt -l . # Formatierung prüfen (leerer Output = ok)
nix develop # devShell mit go, gopls, espeak-ng, libnotify
``` ```
CI: `.gitea/workflows/test.yml` (Gitea Actions) läuft vet, gofmt-Check, Tests CI: `.gitea/workflows/test.yml` (Gitea Actions) läuft vet, gofmt-Check, Tests
und Build bei jedem Push und Pull Request. und Build bei jedem Push und Pull Request.
**Release:** Tag `v*` pushen → `.gitea/workflows/release.yml` testet, baut
mit `scripts/release.sh` die sechs Targets (statisch, `CGO_ENABLED=0`,
Version per ldflags) und legt ein Gitea-Release mit `talk_<os>_<arch>[.exe]`
und `checksums.txt` an. Lokal: `scripts/release.sh 1.2.3` → `dist/`. Bewusst
ohne GoReleaser: ein Shell-Skript über `go build` ist dasselbe Artefakt,
lokal wie in CI, ohne zusätzliches Werkzeug. `nix build .#talk` baut das
Nix-Paket (nach Änderungen an go.mod den `vendorHash` in flake.nix
nachziehen — `nix build` nennt den erwarteten Wert).
## Lizenz ## Lizenz
MIT — siehe [LICENSE](LICENSE). MIT — siehe [LICENSE](LICENSE).
+7
View File
@@ -124,3 +124,10 @@ Diese Punkte ersetzen die entsprechenden Aussagen oben (Grilling-Stand
nutzbar sein. Oberstes Kriterium ist Usability für Nicht-Terminal- nutzbar sein. Oberstes Kriterium ist Usability für Nicht-Terminal-
Nutzer; die Bubble-Tea-TUI ist kein Selbstzweck — einfache, klare Nutzer; die Bubble-Tea-TUI ist kein Selbstzweck — einfache, klare
Befehle (`doctor`, `setup`, `test`, `voices`) haben Vorrang. Befehle (`doctor`, `setup`, `test`, `voices`) haben Vorrang.
- **Release ohne GoReleaser:** `scripts/release.sh` baut die sechs Targets
mit `go build`; `.gitea/workflows/release.yml` legt bei Tag `v*` das
Gitea-Release an. Asset-Vertrag unverändert (`talk_<os>_<arch>[.exe]` +
`checksums.txt`). `flake.nix` liefert Paket, App, Overlay und devShell.
- **Notifications ohne beeep:** Desktop-Toast über die Bordmittel des OS
(notify-send / osascript / PowerShell), exec-basiert wie osbuiltin;
zunächst nur für `quiet_mode = "toast"`. Cancel-Button: später.
+13
View File
@@ -0,0 +1,13 @@
# Standing-Order für talk (in die AGENTS.md des Projekts kopieren)
```markdown
## Voice notifications (talk)
Sprich per `talk "<1–2 Sätze>"`, wenn eine Aufgabe länger als ~30 s lief und
fertig ist, wenn du blockiert bist und mich brauchst (dann `talk --now`),
oder wenn etwas fehlgeschlagen ist. Inhalt: Status, nächster Schritt, wofür
du mich brauchst — nie die Antwort selbst. `muted` und `discarded` sind
meine Entscheidung: respektieren, nicht umgehen.
```
Ohne diesen Block (und ohne Aufforderung in der Session) spricht ein Agent
nicht — talk ist striktes Opt-in.
+86
View File
@@ -0,0 +1,86 @@
---
name: talk
description: "Use when the user has asked for voice notifications — explicitly in this session or as a standing order in the project's AGENTS.md — and (1) a long-running task finishes (build, tests, deploy, data job), (2) the agent is blocked and needs the user's decision or approval, (3) something failed that the user should know about now. Triggers: talk, say it, sag Bescheid, melde dich, notify me, let me know when done, voice, Ansage. Strict opt-in: never speak without the user's trigger or standing order."
compatibility: opencode, claude-code, codex
---
# talk — Voice-Notifications für Agenten
`talk "Build fertig"` spricht eine kurze Ansage über den lokalen talk-Daemon
(Queue, Rate-Limit, Mute, Ruhezeiten). Ein Binary, startet den Daemon beim
ersten Aufruf selbst. Nichts zu installieren außer `talk` im PATH.
## When to Use — striktes Opt-in
Sprich **nur**, wenn eines davon gilt:
1. Der Nutzer hat es in dieser Session verlangt („sag Bescheid, wenn der
Build durch ist", „melde dich, wenn du mich brauchst"). Das gilt dann
**session-sticky bis Widerruf** — nicht bei jeder Antwort neu fragen.
2. Die AGENTS.md des Projekts enthält eine Standing-Order (siehe
`AGENTS-snippet.md`).
Dann sprich bei: Abschluss langer Aufgaben (> ~30 s), Blockern, die den
Nutzer brauchen (Entscheidung, Freigabe, Passwort), Fehlern, die sofort
zählen.
## When NOT to Use
- Ohne Trigger oder Standing-Order. Nie „von sich aus plappern".
- Für kurze Antworten, Zwischenstände, jede Tool-Ausgabe.
- Um die Langantwort vorzulesen. Der Daemon kürzt bei 400 Zeichen —
aber Ziel sind 1–2 Sätze.
- Wenn `talk` `muted` oder `discarded: quiet_hours` zurückgibt: Das ist
die Entscheidung des Nutzers. Nicht umgehen, nicht `--now` nachschieben.
## Was eine gute Ansage ist
**Status · nächster Schritt · wofür der Nutzer gebraucht wird.** Nie die
Antwort selbst.
| gut | schlecht |
| --- | --- |
| „Tests grün, PR ist bereit zum Review." | „Ich habe die Tests ausgeführt und alle 247 Tests sind erfolgreich durchgelaufen, außerdem habe ich …" |
| „Deploy fehlgeschlagen, Code 1. Ich brauche deine Entscheidung zur Migration." | „Fehler." |
| „Brauche dein sudo-Passwort im Terminal." | (stumm warten) |
Sprache: in der Sprache des Nutzers schreiben; talk erkennt de/en selbst
(`--lang` erzwingt).
## Usage
```bash
talk "Tests grün, PR bereit zum Review." # non-blocking, Item-ID auf stdout
talk --wait "Deploy fertig." # erst zurückkehren, wenn gesprochen
talk --priority high "Build rot, Code 2." # darf das Rate-Limit verletzen
talk --now "Ich brauche dich: Freigabe im Terminal." # vor die Queue, auch in der Ruhezeit — nur für Blocker
echo "Import fertig" | talk # stdin geht auch
talk wrap -- make test # Befehl ausführen, Erfolg/Misserfolg + Dauer ansagen
```
Antworten auf stdout: eine Item-ID (angenommen), `muted`, oder
`discarded: rate_limit|quiet_hours`. Exit 0 in allen drei Fällen — ein
Verwurf ist kein Fehler. Exit ≠ 0 nur bei echten Problemen (kein Text,
ungültige Flags, Config kaputt); dann nicht wiederholen, sondern dem
Nutzer sagen.
## Etikette gegenüber dem Daemon
- **Rate-Limit** (Default 1 Ansage / 30 s): `normal` parkt, `low` wird
verworfen, `high` darf durch. Nicht alles ist `high`.
- **`--now`** ist für Blocker, die den Nutzer brauchen — nicht für
„fertig". Es bricht aus Ruhezeit und Rate-Limit aus; das ist eine
bewusste Störung.
- **Mute und Ruhezeit** sind Nutzerentscheidungen. Respektieren, nicht
umgehen. Der Daemon erzwingt sie ohnehin.
- Mehrere Dinge gleichzeitig? **Eine** Ansage, die zusammenfasst — nicht
fünf.
## Pitfalls
- `talk` nicht gefunden → nicht improvisieren (kein `say`, `espeak`,
`notify-send`). Dem Nutzer sagen, dass talk fehlt.
- Kein Ton beim Nutzer → `talk doctor` schlagen vorschlagen; nicht selbst
an Keys oder Config drehen.
- Keys kommen aus `TALK_ELEVENLABS_KEY` / `TALK_OPENAI_KEY` (Env). Nie in
Dateien schreiben, nie in Ansagen oder Logs ausgeben.