π Pi CLI · antai.live/blog
✍ Tutorial · 5. August 2026August 5, 2026

Pi CLI selbst erweitern: Spracheingabe im Terminal Extending the Pi CLI Yourself: Voice Input in the Terminal

Wie du deinen Terminal-Coding-Agenten mit eigenen, selbst geprompteten Extensions erweiterst — und daraus in ~20 Minuten eine Spracheingabe baust, die dir deine Worte direkt in die Pi-Konsole tippt. How to extend your terminal coding agent with your own, self-prompted extensions — and build from that, in ~20 minutes, a voice input that types your words straight into the Pi console.

AutorAuthor: antai.live Topic: Local AI · OpenRouter · TUI LesedauerRead: ~7 Min.min
0,04 $
pro Stunde Audioper audio hour
~2 s
Transkriptiontranscription
~20 Min
bis zum Setupto set up
100 %
eigener Codeyour own code

Es gibt diesen Moment, wenn die Hände auf der Tastatur liegen, aber der Kopf schon zehn Schritte voraus ist. Dann willst du dem Agenten einfach sagen, was er bauen soll — und er legt los. Das geht, schneller als du denkst, und du brauchst dafür kein Framework, keine neue App und kein Abo. Nur den Pi-Coding-Agenten, einen OpenRouter-Key und ein günstiges Speech-to-Text-Modell. There's that moment when your hands are on the keyboard but your head is already ten steps ahead. Then you just want to tell the agent what to build — and it starts. That's possible, faster than you'd think, and you need no framework, no new app, no subscription. Just the Pi coding agent, an OpenRouter key and a cheap speech-to-text model.

01Was ist Pi überhaupt?What is Pi, anyway?

Ein Coding-Agent, der in deinem Terminal lebt — und sein ganzes Verhalten in ein paar Ordnern steckt, die du editieren darfst. A coding agent that lives in your terminal — and keeps all of its behavior in a few folders you're allowed to edit.

Pi (@mariozechner/pi-coding-agent) ist ein Coding-Agent für die Kommandozeile: Du tippst eine Aufgabe, Pi liest deinen Code, plant, editiert Dateien, führt Kommandos aus. Was Pi von vielen anderen unterscheidet: Es ist auf Eigenbau eingestellt. Seine Konfiguration liegt als normale Dateien unter ~/.pi/agent/ — und alles davon ist dazu da, dass du es anfasst. Pi (@mariozechner/pi-coding-agent) is a coding agent for the command line: you type a task, Pi reads your code, plans, edits files, runs commands. What sets Pi apart from many others: it's built for DIY. Its config lives as plain files under ~/.pi/agent/ — and all of it is meant for you to touch.

Das Killer-Feature ist das Extensions-System: TypeScript-Dateien im Ordner extensions/, die von Pi beim Start geladen werden. Damit kannst du in den Lebenszyklus des Agenten eingreifen — und genau dort liegt unser Hebel für die Spracheingabe. The killer feature is the extensions system: TypeScript files in the extensions/ folder that Pi loads on startup. With that you can hook into the agent's lifecycle — and that's exactly our lever for voice input.

02Die vier BausteineThe four building blocks

Bevor wir bauen, die Landkarte von ~/.pi/agent/. Before we build, the map of ~/.pi/agent/.

BausteinBlockZweckPurposeBeispiel aus der PraxisReal-world example
extensions/TypeScript-Hooks in den Agent-LebenszyklusTypeScript hooks into the agent lifecyclePermission-Gate, Project-Rulespermission gate, project rules
skills/Wiederverwendbares Fachwissen (SKILL.md)reusable know-how (SKILL.md)web-app, trading-bot, brave-searchweb-app, trading-bot, brave-search
prompts/Modus-Prompts: plan / implement / reviewmode prompts: plan / implement / reviewplan.md, implement.md, review.mdplan.md, implement.md, review.md
presets.jsonProvider + Modell + Tools pro Modusprovider + model + tools per modezai / glm-5, thinking level, toolszai / glm-5, thinking level, tools

Für unsere Spracheingabe ist extensions/ der wichtigste Ort. Schauen wir uns an, wie so eine Extension wirklich aussieht — das permission-gate.ts von der Standard-Installation. For our voice input, extensions/ is the most important place. Let's look at how such an extension really looks — the permission-gate.ts from the default install.

ts// ~/.pi/agent/extensions/permission-gate.ts
import type { ExtensionAPI } from "@mariozechner/pi-coding-agent";

export default function permissionGate(pi: ExtensionAPI) {
  const dangerous = [/\brm\s+(-rf?)/i, /\bsudo\b/i, /\bmkfs\b/i];

  pi.on("tool_call", async (event, ctx) => {
    if (event.toolName !== "bash") return undefined;
    const cmd = event.input.command;
    if (dangerous.some(p => p.test(cmd))) {
      if (!ctx.hasUI) return { block: true, reason: "Dangerous, blocked." };
      const choice = await ctx.ui.select("Allow?", ["Yes", "No"]);
      if (choice !== "Yes") return { block: true, reason: "Blocked by user" };
    }
    return undefined;
  });
}

Das Muster ist klar: Du exportierst eine Funktion, die das ExtensionAPI-Objekt bekommt, und registrierst mit pi.on(...) Hooks. Pi selbst liefert dir ctx.ui zum Interagieren (Select, Notify) und erwartet, dass du undefined (okay) oder {block, reason} zurückgibst. The pattern is clear: you export a function that receives the ExtensionAPI object, and register hooks with pi.on(...). Pi hands you ctx.ui to interact (select, notify) and expects you to return undefined (okay) or {block, reason}.

03Der Trick: Lass Pi die Extension selbst bauenThe trick: let Pi build the extension itself

Du musst die TypeScript-API nicht auswendig lernen. Die ehrlich schnellste Art, eine Extension zu bekommen, ist: Pi in einem normalen Gespräch darum bitten. Das ist der „selbst gepromptete" Teil — du erklärst Pi im Chat, was die Extension können soll, und Pi schreibt sie dir nach ~/.pi/agent/extensions/. You don't need to memorize the TypeScript API. The honestly fastest way to get an extension is: ask Pi for it in a normal conversation. That's the "self-prompted" part — you explain to Pi in chat what the extension should do, and Pi writes it into ~/.pi/agent/extensions/.

de / prompt# an Pi gerichtet / to Pi
Baue mir eine Extension ~/.pi/agent/extensions/task-notify.ts.
Sie soll nach jedem bash-Tool-Call, der länger als 20s dauert,
eine Termin-Nachricht über ctx.ui.notify ausgeben.
Nutze die ExtensionAPI aus @mariozechner/pi-coding-agent.

Pi kennt sein eigenes API besser als du — und kann dir danach direkt sagen, wie du die Datei testest (normalerweise: Pi neu starten oder Session neu laden). Der Punkt: Extensions sind erweitertes Prompting. Du steuerst Pi nicht nur über die Tastatur, sondern gibst ihm Dateien, die sein Verhalten permanent prägen. Pi knows its own API better than you do — and can then tell you directly how to test the file (usually: restart Pi or reload the session). The point: extensions are extended prompting. You don't just steer Pi via the keyboard, you give it files that permanently shape its behavior.

Wer seinen Agenten promptet, bekommt Antworten. Wer ihm Extensions baut, bekommt einen Mitarbeiter. Prompt your agent and you get answers. Build it extensions and you get a colleague. — antai.live
Modell-EmpfehlungModel pick

DeepSeek V4 Flash für den Agenten DeepSeek V4 Flash for the agent

Der Agent selbst verbraucht die meisten Tokens. Setz dort ein günstiges, starkes Reasoning-Modell ein — aktueller Tipp: DeepSeek V4 Flash (deepseek/deepseek-v4-flash-0731), die aktuellste Flash-Version.

The agent itself burns most of the tokens. Put a cheap, strong reasoning model there — current pick: DeepSeek V4 Flash (deepseek/deepseek-v4-flash-0731), the latest flash release.

0,09 $
je 1M Inputper 1M input
0,18 $
je 1M Outputper 1M output
1M
Tokens Kontexttoken context

Eintrag in presets.json: "provider": "deepseek", "model": "deepseek-v4-flash-0731".

Entry in presets.json: "provider": "deepseek", "model": "deepseek-v4-flash-0731".

04Das Beispiel: Spracheingabe im TerminalThe example: voice input in the terminal

Genug Theorie. Wir bauen jetzt die Spracheingabe: Mikrofon → Transkription → automatisch in die Pi-Konsole. Enough theory. Now we build the voice input: mic → transcription → automatically into the Pi console.

Warum OpenRouter + ein günstiges STT-Modell?Why OpenRouter + a cheap STT model?

OpenRouter ist ein Aggregator: ein Key, viele Modelle. Unter den Audio-Modellen findest du ein sehr günstiges Sprach-zu-Text-Modell — extrem genau und mit 0,04 US$ pro Stunde Audio praktisch kostenlos. Und der Clou: OpenRouter nimmt die Anfrage als JSON entgegen (kein lästiges multipart/form-data), Audio wird als Base64 übergeben. OpenRouter is an aggregator: one key, many models. Among the audio models sits a very cheap speech-to-text model — extremely accurate and at $0.04 per audio hour practically free. And the kicker: OpenRouter accepts the request as JSON (no fiddly multipart/form-data), audio is passed as base64.

0,04 $
STT-Modell / StundeSTT model / hour
JSON
einfache API, Base64simple API, base64
~2 s
bis zum Textto text

Schritt für SchrittStep by step

1

Audiodatei aufnehmenRecord audio

Mit ffmpeg vom Mikrofon in ein OGG (16 kHz, Mono — perfekt für Speech-to-Text).With ffmpeg from the mic into OGG (16 kHz, mono — perfect for speech-to-text).

bashffmpeg -y -f pulse -i default -ac 1 -ar 16000 /tmp/voice.ogg
# Auf dem Mac:  -f avfoundation -i ":0"
2

An OpenRouter schickenSend to OpenRouter

Audio als Base64, als JSON — Endpunkt /v1/audio/transcriptions.Audio as base64, as JSON — endpoint /v1/audio/transcriptions.

bashB64=$(base64 -w0 /tmp/voice.ogg)
curl -s https://openrouter.ai/api/v1/audio/transcriptions \
  -H "Authorization: Bearer $OPENROUTER_API_KEY" \
  -H "Content-Type: application/json" \
  -d "{\"model\":\"\",\"input_audio\":{\"data\":\"$B64\",\"format\":\"ogg\"}}" \
  | jq -r '.text' > /tmp/transcript.txt
3

In Pi autopastenAuto-paste into Pi

Zwei Wege — je nachdem, ob Pi gerade läuft oder nicht.Two ways — depending on whether Pi is running or not.

bash# Variante A: frisch starten mit gesprochenem Prompt
TRANSCRIPT=$(cat /tmp/transcript.txt)
pi "$TRANSCRIPT"

# Variante B: in ein laufendes Pi-Terminal (tmux) tippen
tmux send-keys -t pi "`cat /tmp/transcript.txt`" Enter

Und das Ganze in einem Skript verpackt — der eigentliche Sprach-zu-Text-Workflow: And the whole thing bundled into one script — the actual speech-to-text workflow:

bash · voice.sh#!/usr/bin/env bash
set -euo pipefail
OUT=/tmp/voice.ogg
ffmpeg -y -f pulse -i default -ac 1 -ar 16000 "$OUT" 2>/dev/null
B64=$(base64 -w0 "$OUT")
TXT=$(curl -s https://openrouter.ai/api/v1/audio/transcriptions \
  -H "Authorization: Bearer ${OPENROUTER_API_KEY:?}" \
  -H "Content-Type: application/json" \
  -d "{\"model\":\"\",\"input_audio\":{\"data\":\"$B64\",\"format\":\"ogg\"}}" \
  | jq -r '.text')
printf '%s' "$TXT"
# Nutzung: pi "$(voice.sh)"  →  sprich, und Pi legt los

Der F3-Workflow: sprechen → einfügen → editieren → sendenThe F3 workflow: speak → paste → edit → send

Das oben tippt den Text sofort ab. Fürs Arbeiten willst du aber nichts automatisch senden, sondern zuerst einfügen und dann selbst entscheiden. Dafür gibt's den F3-Toggle: Ein Druck startet die Aufnahme, der nächste schickt sie an STT und fügt das Transkript in die Pi-Eingabe ein — ohne zu senden. Danach kannst du weiterreden (wieder F3), weitertippen oder manuell korrigieren, bis du Enter drückst. The above types the text out immediately. For real work you want nothing auto-sent, but pasted first so you decide. That's what the F3 toggle is for: one press starts recording, the next sends it to STT and pastes the transcript into Pi's input — without sending. Afterwards you can keep speaking (F3 again), keep typing, or edit manually until you hit Enter.

bash · voice-key.sh#!/usr/bin/env bash
set -euo pipefail
OUT=/tmp/voice.ogg

if [[ -f "$OUT" ]]; then
  # 2. F3-Druck: Aufnahme stoppen → STT → EINFÜGEN ohne Senden
  pkill -f "ffmpeg.*voice.ogg" || true
  sleep 0.2
  B64=$(base64 -w0 "$OUT")
  TXT=$(curl -s https://openrouter.ai/api/v1/audio/transcriptions \
    -H "Authorization: Bearer ${OPENROUTER_API_KEY:?}" \
    -H "Content-Type: application/json" \
    -d "{\"model\":\"\",\"input_audio\":{\"data\":\"$B64\",\"format\":\"ogg\"}}" \
    | jq -r '.text')
  rm -f "$OUT"
  tmux send-keys -t pi -l "$TXT"  # -l = literal, NICHTS absenden
else
  # 1. F3-Druck: Aufnahme starten
  ffmpeg -y -f pulse -i default -ac 1 -ar 16000 "$OUT" 2>/dev/null &
fi

Der entscheidende Teil ist tmux send-keys -t pi -l "$TXT": Das -l (literal) schickt den Text als Tipp-Eingabe, ohne Return. Das Transkript landet also in der Eingabezeile von Pi — aber Pi startet nicht. Du kannst jetzt weiterreden, tippen oder editieren und erst mit Enter wirklich senden. The crucial part is tmux send-keys -t pi -l "$TXT": the -l (literal) sends the text as typed input, without a Return. So the transcript lands in Pi's input line — but Pi does not start. You can now keep speaking, typing, or editing and only send for real with Enter.

Keybind:Keybind: Binde F3 an voice-key.sh (z. B. über deinen Fenstermanager, sxhkd oder ein Terminal-Hotkey-Tool). Erster Druck = aufnehmen, zweiter Druck = transkribieren + einfügen. Bind F3 to voice-key.sh (e.g. via your window manager, sxhkd, or a terminal hotkey tool). First press = record, second press = transcribe + paste.
Wichtig:Note: Setze OPENROUTER_API_KEY in deiner Shell (z. B. in ~/.bashrc). Der Key ist geheim — nie einchecken, nie teilen. OpenRouter keyed nach dem Account, nicht nach Gerät. Set OPENROUTER_API_KEY in your shell (e.g. in ~/.bashrc). The key is secret — never commit it, never share it. OpenRouter keys to the account, not the device.

05Vom Skript zur Extension (Bonus)From script to extension (bonus)

Das Skript ist eine schnelle Lösung. Elegant wird es, wenn du Pi beibringst, von sich aus auf Sprachbefehle zu reagieren — per before_agent_start-Hook: Du kannst in den System-Prompt schreiben, dass bei Keyboard-Shortcut Ctrl+R die Sprachaufnahme läuft. So wird aus einem Tippen ein Workflow. The script is the quick fix. It gets elegant when you teach Pi to respond to voice commands on its own — via a before_agent_start hook: you can write into the system prompt that pressing Ctrl+R starts the voice recording. That turns typing into a workflow.

ts// ~/.pi/agent/extensions/voice-hint.ts  (von Pi selbst gepromptet)
import type { ExtensionAPI } from "@mariozechner/pi-coding-agent";

export default function voiceHint(pi: ExtensionAPI) {
  pi.on("before_agent_start", async (event) => {
    return {
      systemPrompt: event.systemPrompt + `

## Voice Input
Ctrl+R records the mic and transcribes via voice.sh.
If the user says "voice", run: pi "$(bash ~/bin/voice.sh)"
`,
    };
  });
}

Jetzt gibt es keinen Unterschied mehr zwischen „tippen" und „sprechen" für Pi — und das ist genau die Freiheit, für die man sich einen eigenen Agenten baut. Now there's no difference between "typing" and "speaking" for Pi — and that's exactly the freedom you build your own agent for.

06Was du daraus machstWhat you make of it

Die Spracheingabe ist nur das einfachste Beispiel. Dasselbe Muster — Extension, die du Pi im Chat beschreibst — bildet auch einen Brave-Search-Hook, ein automatisches Web-App-Scaffold oder einen Trading-Bot-Auslöser. Und weil alles nur Dateien in ~/.pi/agent/ sind, kannst du es jederzeit weitergeben, versionieren oder löschen. Voice input is just the simplest example. The same pattern — an extension you describe to Pi in chat — also forms a Brave-search hook, an automatic web-app scaffold, or a trading-bot trigger. And because it's all just files in ~/.pi/agent/, you can share, version, or delete them anytime.

Kurz & knackigThe short version

  • Pi wird über extensions/, skills/, prompts/ und presets.json erweitert.Pi is extended via extensions/, skills/, prompts/, presets.json.
  • Extensions = erweitertes Prompting. Beschreib sie Pi im Chat, Pi schreibt dir den TypeScript-Code.Extensions = extended prompting. Describe them to Pi in chat, Pi writes the TypeScript.
  • Spracheingabe: OpenRouter-Key + günstiges STT-Modell (0,04 $/Std.) + ffmpeg → Sprache in die Pi-Konsole.Voice input: OpenRouter key + cheap STT model ($0.04/hr) + ffmpeg → speech into the Pi console.
  • Auto-Paste per pi "$(...)" oder tmux send-keys.Auto-paste via pi "$(...)" or tmux send-keys.

Probier es aus — dein Agent wartet schon. Try it out — your agent is already waiting.

→ So was für dein Unternehmen?→ Want this for your business?

Wir bauen KI-Agenten, Sprach-Assistenten & Automatisierung We build AI agents, voice assistants & automation

Aus diesem Tutorial wird bei dir ein einsatzbereiter Workflow — für Vertrieb, Support, Backoffice. Von der kostenlosen Erstberatung bis zum laufenden System. Hamburg & bundesweit. Turn this tutorial into a production workflow for your sales, support, or back office — from a free first consultation to a running system. Hamburg & nationwide.

digibit-it.de · Jetzt KontaktGet in touch
oder direkt:or directly: info@digibit-it.de