Skip to content

Instantly share code, notes, and snippets.

Show Gist options
  • Select an option

  • Save nazt/b67dbd1cd3cb21e6a4d65b0916d69391 to your computer and use it in GitHub Desktop.

Select an option

Save nazt/b67dbd1cd3cb21e6a4d65b0916d69391 to your computer and use it in GitHub Desktop.
Oracle Voice Tray v0.2.0 - Tauri macOS menu bar TTS app

Learning: Graduated Projects Need Their Own Soul

Discovered: 2026-01-04 | Context: voice-tray-v2 spinoff from Nat-s-Agents

Pattern

When a project graduates (spins off) from the main incubation repo, it needs its own minimal soul structure.

Setup Steps

  1. /soul-lite - Create minimal ψ/ (HOME, WIP, memory/)
  2. /oracle-init - Install philosophy + writing style
  3. /awaken - Install commands, agents, skills
  4. Reference parent Oracle thread for history

Structure

[graduated-repo]/
├── ψ/
│   ├── HOME.md
│   ├── WIP.md
│   └── memory/
│       ├── retrospectives/
│       └── learnings/
├── .claude/
│   ├── knowledge/
│   ├── commands/
│   ├── agents/
│   └── skills/
└── CLAUDE.md

Knowledge Flow

  • Retrospectives: Stay local in graduated repo
  • Learnings: Can flow back to parent repo
  • Context: Reference parent Oracle thread (thread 13 for voice-tray-v2)

Why

Graduated projects are independent but connected. They need their own memory while maintaining links to origin story.

Concepts

incubation, spinoff, project-soul, graduation

Learning: Parallel Agent Research Pattern

Discovered: 2026-01-04 | Context: voice-tray-v2 onboarding

Pattern

When exploring unknown territory or reconstructing history, spawn N agents (5-10) with different search vectors. Combine results.

Implementation

Agent 1: claude-mem query A
Agent 2: claude-mem query B
Agent 3: Oracle search
Agent 4: Oracle DB direct
Agent 5: Git history
Agent 6: Codebase analysis
...

Launch all in parallel with run_in_background: true, then collect with TaskOutput.

When to Use

  • New repo onboarding
  • Deep context gathering
  • History reconstruction
  • Multi-source research

Benefits

  • 10 agents × 5 min = 50 agent-minutes in 5 wall-clock minutes
  • Different angles catch different info
  • Redundancy validates findings
  • Faster than serial exploration

Concepts

research, parallel-agents, context-gathering, onboarding

Retrospective: Oracle Voice Tray Build & Bug Fixes

2026-01-05 07:25 | voice-tray-v2 | ~30 min session

What Happened

Continued from previous session. Built Oracle Voice Tray app, renamed from voice-tray-v2, fixed two bugs using Oracle knowledge base.

Timeline

Time Event
~07:00 Build app with pnpm (npm had issues)
~07:10 Rename to "Oracle Voice Tray"
~07:15 DMG .VolumeIcon.icns bug - consulted Oracle
~07:18 Applied DMG polish fix from 2026-01-03_dmg-icon-polish.md
~07:20 MQTT infinite loop bug discovered
~07:22 Fixed clean_session setting
~07:25 Added learnings to Oracle

Bugs Fixed

Bug 1: DMG .VolumeIcon.icns Visible

Symptom: Ugly .VolumeIcon.icns file showing in DMG installer window

Solution (from Oracle learning):

SetFile -a V "/Volumes/AppName/.VolumeIcon.icns"
chflags hidden "/Volumes/AppName/.VolumeIcon.icns"

Oracle consulted: oracle_search("DMG icon VolumeIcon") → found 2026-01-03_dmg-icon-polish.md

Bug 2: MQTT Infinite Speech Loop

Symptom: App speaks infinitely when receiving MQTT messages

Root cause: set_clean_session(false) - broker replays ALL queued messages on reconnect

Fix: Changed to set_clean_session(true)

New learning added: 2026-01-05_mqtt-cleansession-bug.md


What Worked

Pattern Evidence
Oracle consult before fix Found DMG fix in 10 seconds
pnpm over npm Faster install (2.8s vs npm's longer time)
Link related learnings Connected persistence bugs together

Deliverables

Item Path
App Oracle Voice Tray.app
DMG Oracle Voice Tray_0.2.0_aarch64.dmg (8.2 MB)
Learning 1 2026-01-05_mqtt-cleansession-bug.md
Learning 2 2026-01-05_oracle-voice-tray-v020-bug-fixes-summary.md

Key Insight

Both bugs relate to persistence behavior:

  • DMG: Finder caches/persists file visibility in .DS_Store
  • MQTT: Broker persists messages when clean_session=false

Meta-pattern: Be explicit about what should persist vs reset on restart/reconnect.


Code Changes

// src-tauri/src/mqtt.rs line 21
// Before:
mqttoptions.set_clean_session(false);

// After:
mqttoptions.set_clean_session(true);
// src-tauri/tauri.conf.json
"productName": "Oracle Voice Tray"
"identifier": "com.laris.oracle-voice-tray"

Next

  • Test app with actual Claude Code hooks
  • Consider version bump to 0.2.1
  • Commit all changes

Session #2 on voice-tray-v2 repo

Voice Tray v2 - Bugs and Fixes Documentation

This document captures the bugs encountered and fixes applied during Voice Tray v2 development, researched from claude-mem historical observations.


Bug #1: Duplicate Tray Icon Bug

Observation IDs: 5241, 5242, 5243, 5245, 5246, 5250 Type: bugfix Date Fixed: 2026-01-02

Symptoms

  • Two tray icons appeared in the macOS menu bar
  • One icon was transparent/ghost icon that handled click events
  • The other icon was non-functional

Root Cause

Dual tray initialization - both tauri.conf.json configuration AND programmatic TrayIconBuilder code were creating separate tray instances.

This is a known Tauri 2.0 issue tracked as tauri-apps/tauri#8982.

The problematic configuration in tauri.conf.json:

"trayIcon": {
  "iconPath": "icons/32x32.png",
  "iconAsTemplate": false
}

Combined with code-based initialization in lib.rs:

TrayIconBuilder::new()

Fix Applied

Remove the trayIcon section from tauri.conf.json and keep only the code-based TrayIconBuilder initialization.

This same fix was previously applied to oracle-status-tray in commit a6bc658b (Issue #74).

Rule: Use either config OR code for tray initialization, never both.


Bug #2: White Square / Black Square / Invisible Icon Bug

Observation IDs: 5390, 5404, 5420, 5423, 5431, 5435, 8491 Type: bugfix Date Fixed: 2026-01-03

Symptoms

  • Tray icon appeared as a black square in the menu bar
  • Or icon was completely invisible
  • Or icon showed with a dark background instead of transparency

Root Causes (Three Hidden Traps)

  1. JPEG disguised as PNG: AI-generated icons from Antigravity/Gemini output JPEG image data with .png extension - the files claim to be PNG but contain JPEG data with baked-in dark backgrounds

  2. Checkered background illusion: Image viewers show checkered patterns for "transparency" but the actual dark background was baked into the image data

  3. Palette-based PNG format: PNG files using PaletteAlpha format fail to decode correctly in Tauri - requires TrueColorAlpha format

  4. Inverted alpha channel: Initial ImageMagick brightness-to-alpha conversion was inverted - dark pixels became opaque while white lines became transparent (alpha mean 2.3/255, nearly invisible)

  5. Rust png crate limitation: The png crate cannot automatically convert palette-based PNG to RGBA format

Fix Applied

ImageMagick Conversion Workflow:

magick source.png \
  -fuzz 30% \
  -trim \
  -transparent "rgb(45,46,45)" \
  -resize 22x22 \
  -level 0%,40% \
  PNG32:output.png

Key elements:

  • -fuzz 30-40%: Fuzzy matching to remove variations of dark background
  • -transparent "rgb(45,45,45)": Remove the dark background color
  • -level 0%,50%: Brighten remaining pixels to white
  • PNG32:: Force TrueColorAlpha format output
  • -trim: Remove AI-generated padding

Rust Code Changes:

  • Switched from png crate to image crate
  • Use to_rgba8() for automatic format conversion
  • Icons embedded at compile time using include_bytes! macro

Icon Sizing:

  • macOS menu bar requires 22x22 pixel dimensions
  • Multiple resolutions tested: 16x16 -> 32x32 -> 44x44 -> 64x64

Verification

Use file command to verify actual image format:

file your-icon.png

Check alpha channel statistics:

identify -verbose icon.png | grep -A5 "Alpha:"

Bug #3: Build Failures

Observation IDs: 5068, 5228, 5266 Type: bugfix Date: 2026-01-02

Issues Encountered

  1. Proc Macro Panic (ID: 5266)

    • Build fails with "proc macro panicked" error
    • Compilation stopped preventing library build
  2. Permission Denied Error (ID: 5228)

    • Shell evaluation error during rebuild
    • Occurred after tray icon configuration changes
  3. Compilation Error in lib.rs (ID: 5068)

    • Unused variable warning in mqtt.rs
    • Unnecessary mut in lib.rs

Resolution

  • Fix code issues identified in warnings
  • Ensure clean process termination before rebuild
  • Use bun tauri build not just cargo build when icons change (include_bytes! caches at compile time)

Bug #4: Icons Too Small in Menu Bar

Observation IDs: 5495, 5538, 5539, 5569 Type: change (iterative improvement) Date: 2026-01-03

Issue

Icons appeared too small or sparse in the macOS menu bar, especially on retina displays.

Resolution

Progressive icon resolution increases:

  1. 16x16 -> 32x32 (initial improvement)
  2. 32x32 -> 44x44 (retina adjustment)
  3. 44x44 -> 64x64 (final increase)

Final recommendation: Use 22x22 for macOS menu bar icons, or provide @2x versions.


Related Projects

The duplicate tray icon bug was first encountered and fixed in oracle-status-tray:

  • Commit: a6bc658b
  • Issue: #74
  • Date: 2025-12-30

The /trace command successfully located this previous fix in ~20 seconds via Oracle's context-finder.


Key Learnings

  1. Tauri 2.0 tray initialization: Use either config OR code, never both
  2. AI-generated icons: Always verify actual format with file command
  3. PNG transparency: Use PNG32 format flag for guaranteed TrueColorAlpha
  4. Rust image handling: Use image crate over png crate for automatic format conversion
  5. macOS menu bar: Icons should be 22x22 pixels for standard displays
  6. Compile-time assets: Changes to include_bytes! assets require full Tauri rebuild

Document generated from claude-mem observations on 2026-01-04

Voice Tray v2 - Research Notes

Generated: 2026-01-04 by 10 parallel research agents

Executive Summary

Voice Tray v2 is a Tauri 2.0 macOS menu bar app that provides centralized text-to-speech for Claude Code. It was spun off from Nat-s-Agents on 2026-01-04 (1.7GB → 11MB) after graduating from the incubation system.


Timeline

Date Event
Jan 2, 2026 v1 complete (HTTP only) in ψ/incubate/voice-tray/
Jan 2, 2026 v2 started (MQTT backend)
Jan 3, 2026 Dynamic lips icon + overnight bug fixes
Jan 4, 2026 Spun off to own repo (laris-co/voice-tray-v2)

Architecture

Claude Code Hooks
       ↓
voice-tray-notify.sh (HTTP) or voice-tray-mqtt-notify.sh (MQTT)
       ↓
Voice Tray v2 (Tauri app, port 37779)
       ↓
macOS `say -v [voice] -r [rate]`
       ↓
Timeline UI + Audio Output

Tech Stack

Component Technology
Framework Tauri 2.0 (Rust + WebView)
HTTP Server Axum 0.7
MQTT Client rumqttc 0.24
Async Runtime Tokio
Frontend Vanilla HTML/CSS/JS
Voice macOS say command
Icons PNG32 via ImageMagick

Features

  • Dual Input: HTTP POST /speak + MQTT voice/speak topic
  • Voice Queue: Sequential processing, no overlap
  • Timeline UI: 320x400 popup from menu bar click
  • Dynamic Tray Icon: Lips change (idle/speaking states)
  • Per-Agent Voices: Configured in scripts/agent-voices.toml

Agent Voice Config

Agent Voice Rate
Main Samantha 190 wpm
Agent 1 Daniel (British) 220 wpm
Agent 2 Karen (Australian) 220 wpm
Agent 3 Rishi (Indian) 220 wpm

API

HTTP (port 37779)

# Queue voice
curl -X POST http://127.0.0.1:37779/speak \
  -H "Content-Type: application/json" \
  -d '{"text":"Hello","voice":"Samantha","rate":190}'

# Get timeline
curl http://127.0.0.1:37779/timeline

# Get status
curl http://127.0.0.1:37779/status

MQTT (broker 127.0.0.1:1883)

mosquitto_pub -t voice/speak -m '{"text":"Hello","voice":"Daniel"}'

Spinoff Details

Why Spun Off

  • Rust target/ directory grew to 1.7GB
  • Nat-s-Agents repo became bloated
  • Project matured enough to graduate from incubation

Spinoff Process (2026-01-04)

  1. gh repo create laris-co/voice-tray-v2 --private
  2. rsync code (excluding target/)
  3. Push to new repo
  4. Result: 1.7GB → 11MB

Commit

7795f99a feat: spinoff voice-tray-v2 (1.7GB → 11MB own repo)

Location History

Phase Path
Incubate (v1) Nat-s-Agents/ψ/incubate/voice-tray/ (still exists)
Incubate (v2) Nat-s-Agents/ψ/incubate/voice-tray-v2/ (moved)
Graduated /Users/nat/Code/github.com/laris-co/voice-tray-v2/

Where to Get More Info

Oracle MCP

  • Thread 13: "Voice Tray v2 Project Context" - full context dump
  • Use: mcp__oracle-v2__oracle_thread(threadId: 13, message: "your question")

claude-mem

  • Search: mcp__plugin_claude-mem_claude-mem-search__search(query: "voice-tray")
  • Recent: Check observations #5217-#5250 (Jan 2-3 work)

Git History (Nat-s-Agents)

cd /Users/nat/Code/github.com/laris-co/Nat-s-Agents
git log --oneline --grep="voice-tray" | head -20

Documentation Files

File Content
ψ/writing/drafts/2026-01-02_voice-tray-building-tauri-app-with-ai.md Blog draft
ψ/writing/drafts/2026-01-03_tauri-tray-icon-antigravity-workflow.md Icon guide
ψ/memory/retrospectives/2026-01/02/23.12_voice-tray-v2-complete.md Retrospective
ψ/memory/learnings/2026-01-04_voice-tray-v2-spun-off*.md Spinoff record

GitHub

  • Issue #92: feat: Voice Tray v2 — MQTT Backend
  • Repo: https://github.com/laris-co/voice-tray-v2

Bugs Fixed

  1. Duplicate Tray Icon - Removed dual initialization in tauri.conf.json (Tauri issue #8982)
  2. White Square Icon - Fixed SVG bounding box, converted to PNG32 with ImageMagick
  3. Multi-monitor Positioning - Use physical coordinates for popup placement

Key Patterns Learned

  1. Tauri 2.0 Tray: Left vs right click handling, LSUIElement for no dock icon
  2. PNG32 Format: Required for menu bar transparency on macOS
  3. ImageMagick: -fuzz 30% -transparent -trim -resize 22x22 PNG32:
  4. Click Debounce: 300ms to prevent double windows
  5. MQTT Retained: Use for status messages that new subscribers need

Incubation Lifecycle (Oracle Pattern)

🌱 Seed → 🌕 Grow → 🎓 Graduate → 🤝 Reunion

Voice Tray v2 is now at 🎓 Graduate phase - living in its own repo while knowledge (retrospectives, learnings) stays in Nat-s-Agents.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment