Compare commits
4
Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
1b61c1cb0c | ||
|
|
fc606ace2d | ||
|
|
7c3a3c46f0 | ||
|
|
b11d18b4b4 |
@@ -23,20 +23,27 @@ This repository serves as a **personal AI operating system** - a collection of s
|
|||||||
│ └── profile.md # Work style, PARA areas, preferences
|
│ └── profile.md # Work style, PARA areas, preferences
|
||||||
├── commands/ # Custom command definitions
|
├── commands/ # Custom command definitions
|
||||||
│ └── reflection.md
|
│ └── reflection.md
|
||||||
├── skills/ # Opencode Agent Skills (14 skills)
|
├── skills/ # Opencode Agent Skills (18 skills)
|
||||||
│ ├── agent-development/ # Agent creation and configuration
|
│ ├── agent-development/ # Agent creation and configuration
|
||||||
|
│ ├── basecamp-project/ # Basecamp project setup & workflows
|
||||||
│ ├── brainstorming/ # Ideation & strategic thinking
|
│ ├── brainstorming/ # Ideation & strategic thinking
|
||||||
|
│ ├── changelog/ # Changelog generation
|
||||||
|
│ ├── crunch-jobs/ # Scheduled voice notifications & AI jobs
|
||||||
│ ├── doc-translator/ # Documentation translation
|
│ ├── doc-translator/ # Documentation translation
|
||||||
│ ├── excalidraw/ # Architecture diagrams
|
│ ├── excalidraw/ # Architecture diagrams
|
||||||
|
│ ├── m3ta-brain/ # Shared brain vault integration
|
||||||
│ ├── mem0-memory/ # DEPRECATED — replaced by opencode-memory plugin
|
│ ├── mem0-memory/ # DEPRECATED — replaced by opencode-memory plugin
|
||||||
│ ├── obsidian/ # Obsidian vault management
|
│ ├── obsidian/ # Obsidian vault management
|
||||||
│ ├── outline/ # Outline wiki integration
|
│ ├── outline/ # Outline wiki integration
|
||||||
│ ├── pdf/ # PDF manipulation toolkit
|
│ ├── pdf/ # PDF manipulation toolkit
|
||||||
|
│ ├── plan-writing/ # Implementation plan authoring
|
||||||
│ ├── prompt-engineering-patterns/ # Prompt patterns
|
│ ├── prompt-engineering-patterns/ # Prompt patterns
|
||||||
│ ├── qmd/ # Knowledge retrieval via QMD
|
│ ├── qmd/ # Knowledge retrieval via QMD
|
||||||
│ ├── reflection/ # Conversation analysis
|
│ ├── reflection/ # Conversation analysis
|
||||||
|
│ ├── shared-brain-vault/ # Git-synced Obsidian vault
|
||||||
│ ├── skill-creator/ # Meta-skill for creating skills
|
│ ├── skill-creator/ # Meta-skill for creating skills
|
||||||
│ ├── systematic-debugging/ # Debugging methodology
|
│ ├── systematic-debugging/ # Debugging methodology
|
||||||
|
│ ├── voice-notify/ # ElevenLabs TTS voice notifications
|
||||||
│ └── xlsx/ # Spreadsheet handling
|
│ └── xlsx/ # Spreadsheet handling
|
||||||
├── scripts/ # Repository utility scripts
|
├── scripts/ # Repository utility scripts
|
||||||
│ └── test-skill.sh # Test skills without deploying
|
│ └── test-skill.sh # Test skills without deploying
|
||||||
|
|||||||
@@ -0,0 +1,131 @@
|
|||||||
|
---
|
||||||
|
name: crunch-jobs
|
||||||
|
description: "Use when: (1) The user asks to be reminded at a specific time, (2) Schedule recurring notifications, (3) Set up AI-powered scheduled jobs (summarize, review, report), (4) Run custom pipeline scripts on a schedule with voice output. Triggers: remind me, erinnere mich, schedule, cron, daily, weekly, täglich, jeden Montag, crunch, talk at, notify me at, voice reminder."
|
||||||
|
compatibility: opencode
|
||||||
|
---
|
||||||
|
|
||||||
|
# crunch-jobs
|
||||||
|
|
||||||
|
Schedule voice-notified reminders and AI crunch jobs on NixOS via `systemd` transient timers. When a timer fires, results are spoken aloud through `talk` (ElevenLabs TTS).
|
||||||
|
|
||||||
|
No NixOS rebuild needed — jobs are created at runtime via `systemd-run --user` and survive reboots.
|
||||||
|
|
||||||
|
## Prerequisites
|
||||||
|
|
||||||
|
- `crunch` and `talk` installed (via `m3ta-nixpkgs`)
|
||||||
|
- `ELEVENLABS_API_KEY` in environment (or agenix secrets)
|
||||||
|
- `loginctl enable-linger <username>` — **critical**: without this, user timers stop when the session ends
|
||||||
|
|
||||||
|
**Companion skill:** `voice-notify` covers the `talk` TTS script internals.
|
||||||
|
|
||||||
|
## Command Reference
|
||||||
|
|
||||||
|
```
|
||||||
|
crunch at <time> <message> One-shot (14:30 or "2026-07-03 14:30")
|
||||||
|
crunch in <duration> <message> One-shot after delay (30m, 2h, 1h30m)
|
||||||
|
crunch daily <time> <message> Recurring daily
|
||||||
|
crunch weekly <day> <time> <message> Recurring weekly (Mon or Montag)
|
||||||
|
crunch ai <engine> <type> <time> <prompt> AI crunch (pi|opencode)
|
||||||
|
crunch script <type> <time> <script.sh> [args] Custom script → talk
|
||||||
|
crunch list List active jobs
|
||||||
|
crunch cancel <name> Cancel a job
|
||||||
|
crunch purge Remove fired one-shot jobs
|
||||||
|
```
|
||||||
|
|
||||||
|
## Decision Flow
|
||||||
|
|
||||||
|
### 1. What kind of job?
|
||||||
|
|
||||||
|
| User intent | Command |
|
||||||
|
|---|---|
|
||||||
|
| "Erinnere mich an X" (just speak a message) | `crunch <type> <time> <message>` |
|
||||||
|
| "Fasse Y zusammen und sag mir Bescheid" (AI processes data) | `crunch ai <engine> <type> <time> <prompt>` |
|
||||||
|
| Complex multi-step pipeline (fetch → process → write → speak) | `crunch script <type> <time> <script.sh>` |
|
||||||
|
|
||||||
|
### 2. When?
|
||||||
|
|
||||||
|
| User says (DE/EN) | Type | Time spec |
|
||||||
|
|---|---|---|
|
||||||
|
| "in 30 Minuten" / "in 30m" | `in` | `"30m"` |
|
||||||
|
| "in 2 Stunden" | `in` | `"2h"` |
|
||||||
|
| "um 14:30" | `at` | `"14:30"` |
|
||||||
|
| "morgen um 10:00" | `at` | `"10:00"` (fires next 10:00) |
|
||||||
|
| "am 3. Juli um 15:00" | `at` | `"2026-07-03 15:00"` |
|
||||||
|
| "täglich um 9 Uhr" | `daily` | `"09:00"` |
|
||||||
|
| "jeden Montag um 9" | `weekly` | `"Mon 09:00"` |
|
||||||
|
| "freitags um 17:00" | `weekly` | `"Fri 17:00"` |
|
||||||
|
|
||||||
|
Day names: Mo/Mon/Montag→Mon, Di/Tue→Tue, Mi/Wed→Wed, Do/Thu→Thu, Fr/Fri→Fri, Sa/Sat→Sat, So/Sun→Sun.
|
||||||
|
|
||||||
|
### 3. Construct and execute the command.
|
||||||
|
|
||||||
|
## Job Types
|
||||||
|
|
||||||
|
### Simple Voice Reminders
|
||||||
|
|
||||||
|
Just speaks the message at the scheduled time:
|
||||||
|
|
||||||
|
```bash
|
||||||
|
crunch at "14:30" "Müll rausbringen"
|
||||||
|
crunch in "30m" "Build ist fertig — Ergebnis checken"
|
||||||
|
crunch daily "09:00" "Guten Morgen! Tagesplanung:"
|
||||||
|
crunch weekly "Fri 16:00" "Weekly Review nicht vergessen"
|
||||||
|
```
|
||||||
|
|
||||||
|
### AI Crunch Jobs
|
||||||
|
|
||||||
|
Runs a prompt through `pi` or `opencode` in print mode (non-interactive). Agent processes data, stdout → `talk`:
|
||||||
|
|
||||||
|
```bash
|
||||||
|
crunch ai pi in "2h" "Lies die neuesten Git-Commits und gib eine 3-Satz Zusammenfassung"
|
||||||
|
crunch ai opencode daily "07:30" "Check die PostgreSQL-Logs auf Errors der letzten 24h"
|
||||||
|
crunch ai pi weekly "Mon 09:00" "Generiere Weekly Summary aus git log"
|
||||||
|
```
|
||||||
|
|
||||||
|
The agent has full file-system access. It can call CLI tools, write files, and chain operations. Only the final stdout becomes the voice message.
|
||||||
|
|
||||||
|
### Custom Script Jobs
|
||||||
|
|
||||||
|
Runs any shell script on schedule. Script stdout → `talk`. Empty stdout = silence (no error).
|
||||||
|
|
||||||
|
```bash
|
||||||
|
crunch script daily "08:00" ~/scripts/basecamp-daily.sh
|
||||||
|
crunch script weekly "Mon 09:00" ~/scripts/weekly-report.sh arg1 arg2
|
||||||
|
```
|
||||||
|
|
||||||
|
Example script — fetches data, AI summarizes, writes report, speaks summary:
|
||||||
|
|
||||||
|
```bash
|
||||||
|
#!/usr/bin/env bash
|
||||||
|
# ~/scripts/basecamp-daily.sh
|
||||||
|
TODOS=$(basecamp todos --today 2>/dev/null) || exit 0
|
||||||
|
echo "$TODOS" | pi -p "Erstelle strukturierte Summary, speichere als ~/reports/daily.md. Antworte mit Top 3 Prioritäten."
|
||||||
|
```
|
||||||
|
|
||||||
|
## After Scheduling
|
||||||
|
|
||||||
|
- crunch outputs `✓ Scheduled: crunch-<name>-<random>`
|
||||||
|
- Share the job name with the user (needed for cancel)
|
||||||
|
- List: `crunch list`
|
||||||
|
- Cancel: `crunch cancel <name>`
|
||||||
|
|
||||||
|
## Examples
|
||||||
|
|
||||||
|
```
|
||||||
|
User: "Erinnere mich in 30 Minuten daran, den Build zu checken"
|
||||||
|
→ crunch in "30m" "Build checken"
|
||||||
|
|
||||||
|
User: "Jeden Morgen um 8 will ich meine Basecamp Todos hören"
|
||||||
|
→ crunch ai pi daily "08:00" "Hole heutige Todos aus Basecamp, antworte mit Top 3 Prioritäten"
|
||||||
|
|
||||||
|
User: "Freitags um 16 Uhr will ich ein Weekly Report als Voice"
|
||||||
|
→ crunch script weekly "Fri 16:00" ~/scripts/weekly-report.sh
|
||||||
|
```
|
||||||
|
|
||||||
|
## Pitfalls
|
||||||
|
|
||||||
|
- **Lingering**: Without `loginctl enable-linger <user>`, user systemd timers STOP when the session ends. Verify: `loginctl show-user <username> | grep Linger`
|
||||||
|
- **No session on servers**: `systemd-run --user` needs an active user session. On headless servers, use system-level timers or Hermes cron instead.
|
||||||
|
- **Quote messages**: Always quote the message/prompt argument (spaces, special chars).
|
||||||
|
- **Date format**: Specific dates must be `YYYY-MM-DD` for `crunch at`.
|
||||||
|
- **Voice toggle**: `VOICE_NOTIFY=0` silences all talk output globally.
|
||||||
@@ -0,0 +1,120 @@
|
|||||||
|
---
|
||||||
|
name: voice-notify
|
||||||
|
description: "Use when: (1) A long-running task (build, test, migration, cruncher job) completes, (2) The user asks to be notified audibly, (3) An agent finishes delegated work and should announce results, (4) Important errors or completions need immediate attention. Triggers: talk, voice, notify, audio, abbrechen, notify me, let me know when done, cruncher, job complete."
|
||||||
|
compatibility: opencode
|
||||||
|
---
|
||||||
|
|
||||||
|
# voice-notify
|
||||||
|
|
||||||
|
ElevenLabs TTS voice notifications with a dismissable desktop popup. Audio playback and notification appear simultaneously — click **⛔ Abbrechen** to stop playback.
|
||||||
|
|
||||||
|
## Prerequisites
|
||||||
|
|
||||||
|
- `talk` binary installed (via `m3ta-nixpkgs pkgs.talk`)
|
||||||
|
- ElevenLabs API key at `/run/agenix/elevenlabs-key` (preferred) or `ELEVENLABS_API_KEY` env var (fallback)
|
||||||
|
- Desktop notification daemon (DMS, dunst, mako, etc.)
|
||||||
|
- Audio playback (`mpv`) and PipeWire/PulseAudio running
|
||||||
|
|
||||||
|
## When to Use
|
||||||
|
|
||||||
|
- **Task completed** — after builds, tests, migrations, deployments (>30s runtime)
|
||||||
|
- **Cruncher job finished** — long data processing pipelines
|
||||||
|
- **Agent delegated work done** — when a subagent finishes and the user should know
|
||||||
|
- **User requested audio feedback** — "notify me when done", "let me know"
|
||||||
|
- **Critical errors** — build failures, test crashes, missing dependencies
|
||||||
|
|
||||||
|
## When NOT to Use
|
||||||
|
|
||||||
|
- Quick responses (< 30s of work)
|
||||||
|
- `VOICE_NOTIFY=0` is set — respect the toggle, stay silent
|
||||||
|
- Headless server without audio/desktop
|
||||||
|
- User is in a meeting/streaming — audio would be disruptive
|
||||||
|
|
||||||
|
## Usage
|
||||||
|
|
||||||
|
### Basic
|
||||||
|
|
||||||
|
```bash
|
||||||
|
talk "Build abgeschlossen. Alle 247 Tests erfolgreich."
|
||||||
|
```
|
||||||
|
|
||||||
|
### Stdin (Pipe)
|
||||||
|
|
||||||
|
```bash
|
||||||
|
echo "Deployment fertig" | talk
|
||||||
|
nixos-rebuild build 2>&1 | tail -3 | talk
|
||||||
|
|
||||||
|
# AI agent print mode → talk
|
||||||
|
pi -p "Review diesen Code" | talk
|
||||||
|
opencode run "Erkläre diese Funktion" -q | talk
|
||||||
|
```
|
||||||
|
|
||||||
|
Argument has priority; if no argument is given, `talk` reads from stdin. This enables piping from any command or AI agent.
|
||||||
|
|
||||||
|
### After Task Completion
|
||||||
|
|
||||||
|
```bash
|
||||||
|
# Am Ende eines langen Jobs:
|
||||||
|
talk "Cruncher Job komplett. 3 Dateien verarbeitet, 0 Fehler."
|
||||||
|
```
|
||||||
|
|
||||||
|
### Disable Temporarily
|
||||||
|
|
||||||
|
```bash
|
||||||
|
export VOICE_NOTIFY=0 # stumm schalten
|
||||||
|
# ... agent work ...
|
||||||
|
export VOICE_NOTIFY=1 # wieder an
|
||||||
|
```
|
||||||
|
|
||||||
|
## Integration Patterns
|
||||||
|
|
||||||
|
### Pattern 1: Cruncher Job Wrapper
|
||||||
|
|
||||||
|
For any long-running job, use the wrapper script at `scripts/cruncher-notify.sh`:
|
||||||
|
|
||||||
|
```bash
|
||||||
|
# Statt direkt:
|
||||||
|
python3 process_data.py --input data.csv
|
||||||
|
|
||||||
|
# Mit Voice Notification:
|
||||||
|
cruncher-notify.sh "Data Import" -- python3 process_data.py --input data.csv
|
||||||
|
# → 🔊 "Data Import erfolgreich. Dauer: 3 Minuten 42 Sekunden."
|
||||||
|
```
|
||||||
|
|
||||||
|
On failure: `❌ "Data Import fehlgeschlagen, Code 1"`.
|
||||||
|
|
||||||
|
### Pattern 2: Agent Hook
|
||||||
|
|
||||||
|
Add to `AGENTS.md` in any project:
|
||||||
|
|
||||||
|
```markdown
|
||||||
|
## Voice Notifications
|
||||||
|
When `VOICE_NOTIFY != 0` and the task took longer than 30 seconds,
|
||||||
|
call at the end: `talk "[brief summary]"`
|
||||||
|
```
|
||||||
|
|
||||||
|
### Pattern 3: Post-Build / Post-Test
|
||||||
|
|
||||||
|
```bash
|
||||||
|
# Makefile oder CI script:
|
||||||
|
test:
|
||||||
|
pytest tests/
|
||||||
|
talk "Tests durchgelaufen: $$(pytest tests/ -q --tb=no 2>&1 | tail -1)"
|
||||||
|
```
|
||||||
|
|
||||||
|
## Toggle Behaviour
|
||||||
|
|
||||||
|
| Value | Effect |
|
||||||
|
|-------|--------|
|
||||||
|
| `VOICE_NOTIFY=1` (default) | Notifications active |
|
||||||
|
| `VOICE_NOTIFY=0` | `talk` exits immediately, no audio, no popup |
|
||||||
|
| unset | Defaults to enabled |
|
||||||
|
|
||||||
|
Set per-shell, per-user, or system-wide via Home-Manager `home.sessionVariables`.
|
||||||
|
|
||||||
|
## Pitfalls
|
||||||
|
|
||||||
|
- **No audio?** Check `/run/agenix/elevenlabs-key` exists and is readable (or `ELEVENLABS_API_KEY` env var). HTTP 402 = no credits
|
||||||
|
- **No popup?** Ensure a notification daemon is running (`notify-send` needs a daemon)
|
||||||
|
- **Cancel button doesn't stop audio?** Fixed: the poll loop now uses `[ -s ]` (non-empty check) instead of `[ -f ]` (exists). The action file is created as empty by the shell redirect; it's only filled when the user clicks Abbrechen.
|
||||||
|
- **`pw-play` doesn't work** — it can't decode MP3; `talk` uses `mpv` which handles all formats
|
||||||
@@ -0,0 +1,39 @@
|
|||||||
|
#!/usr/bin/env bash
|
||||||
|
# cruncher-notify.sh — Wrapper für Jobs mit Voice Notification
|
||||||
|
# Usage: cruncher-notify.sh "Job Name" -- <command...>
|
||||||
|
# Example: cruncher-notify.sh "Data Import" -- python3 import.py --input data.csv
|
||||||
|
set -euo pipefail
|
||||||
|
|
||||||
|
JOB_NAME="$1"
|
||||||
|
shift
|
||||||
|
[ "$1" = "--" ] && shift || { echo "Usage: $0 \"Job Name\" -- <command...>"; exit 1; }
|
||||||
|
|
||||||
|
START_TS=$(date +%s)
|
||||||
|
|
||||||
|
echo "▶ $JOB_NAME gestartet: $(date +%H:%M:%S)"
|
||||||
|
|
||||||
|
set +e
|
||||||
|
"$@"
|
||||||
|
JOB_EXIT=$?
|
||||||
|
set -e
|
||||||
|
|
||||||
|
END_TS=$(date +%s)
|
||||||
|
DURATION=$(( END_TS - START_TS ))
|
||||||
|
MIN=$(( DURATION / 60 ))
|
||||||
|
SEC=$(( DURATION % 60 ))
|
||||||
|
|
||||||
|
if [ "$JOB_EXIT" -eq 0 ]; then
|
||||||
|
STATUS_TEXT="erfolgreich"
|
||||||
|
STATUS_ICON="✅"
|
||||||
|
else
|
||||||
|
STATUS_TEXT="fehlgeschlagen (Code $JOB_EXIT)"
|
||||||
|
STATUS_ICON="❌"
|
||||||
|
fi
|
||||||
|
|
||||||
|
echo "$STATUS_ICON $JOB_NAME $STATUS_TEXT in ${MIN}m${SEC}s"
|
||||||
|
|
||||||
|
if [ "${VOICE_NOTIFY:-1}" != "0" ] && command -v talk &>/dev/null; then
|
||||||
|
talk "$JOB_NAME $STATUS_TEXT. Dauer: $MIN Minuten $SEC Sekunden."
|
||||||
|
fi
|
||||||
|
|
||||||
|
exit "$JOB_EXIT"
|
||||||
Reference in New Issue
Block a user