Aqua Voice × Claude Cowork: Systematizing Voice Input Customization with Automated Weekly Analysis

Aqua Voice × Claude Cowork: Systematizing Voice Input Customization with Automated Weekly Analysis

Every week, I implemented a system that has Claude analyze voice input logs to automatically improve Aqua Voice settings. Proposals for dictionary, replacements, and customInstructions are delivered via Slack, and by registering only the ones I find acceptable, I continuously improve voice input accuracy.
2026.05.28

This page has been translated by machine translation. View original

Hello, I'm Kema.

Have you ever used voice input?
I myself have been handling most of my work with voice input lately, and the time I spend typing has decreased considerably.
However, I have the frustration that proper nouns and technical terms get misrecognized, and my verbal habits and speech patterns remain in the text as-is.

In Aqua Voice, which I use, you can customize accuracy with three features: dictionary, replacements, and customInstructions, but registering these manually each time is quite a hassle.

So in this article, I'll cover a system that has Claude analyze Aqua Voice voice input logs and automatically deliver weekly improvement suggestions for dictionary, replacements, and customInstructions.

I'm using the Claude Code Cowork schedule feature and Slack notifications.
I hope this will be useful for those who want to continuously improve their voice input accuracy.

What is Aqua Voice?

Since some of you may not be familiar with Aqua Voice, let me give a brief introduction.
Aqua Voice is a voice input app available for Mac / Windows / iOS / Chrome extension.
There are 4 pricing plans: Free (Starter), Pro ($8/month, annual billing), Team ($12/month, annual billing), and Enterprise, and customInstructions and Custom Dictionary up to 800 entries are available on the Pro plan and above.

Source: Aqua Voice - Fast and Accurate Voice Dictation for Mac and Windows | Aqua Voice

Since the Starter plan description does not include Custom Instructions, and Tune with Custom Instructions first appears in the Pro plan description, you need a Pro plan or higher subscription to use customInstructions.

Aqua Voice has a model called Avalon that can recognize technical terms with high accuracy.
For people like me who frequently voice input IT terminology, there are fewer misrecognitions and it's comfortable to use.

Furthermore, there are three features for customizing recognition results to suit yourself.

  • dictionary: Register proper nouns and specialized terms to reduce misrecognitions (e.g., preventing AgentCore from being recognized in katakana as "エージェントコア")
  • replacements: Replace specific spoken phrases entirely with different text (e.g., saying "メアド" inputs taro.yamada@example.com)
  • customInstructions: Specify style, tone, and formatting rules for transcription results in natural language (e.g., filler removal, handling of line break commands, text style unification)

By using these 3 features, you can improve voice input accuracy to match your own usage.

Important: To make custom instructions (customInstructions) work correctly, change the streaming mode to "Always" in the settings screen. If left at the default setting, custom instructions may not be reflected.

What We'll Implement This Time

Maintaining customInstructions, dictionary, and replacements requires manually updating them while observing your own voice input habits and misrecognition tendencies, which is quite a hassle.
So in this article, we'll create a system that has Claude take over that burden.

Specifically, once a week, we'll send Aqua Voice voice input logs to Claude to analyze:

  • Which words should be added to dictionary
  • Which spoken phrases should be registered in replacements
  • What style instructions should be added to customInstructions

and have the suggestions sent as Slack notifications.
For weekly automated execution, we'll use Claude Code's Cowork scheduled tasks.

Overview

The overall picture of the system to be implemented is as follows.

Key points:

  • Mac-side constant processing (every 5 minutes): Whenever new history is added to Aqua Voice's settings.json, aqua_archive.py takes the diff and mirrors it to a separate folder
  • Cowork-side weekly processing: Claude loads the previous week's logs and current Aqua Voice settings for analysis. Saves improvement suggestions to the knowledge base while notifying Slack DM
  • My work: Review the suggestions delivered via Slack and manually register only the necessary ones in the Aqua Voice UI (designed without automatic reflection)

Setup Procedure

The setup procedure consists of the following 2 steps.

The paths and settings values in this article are expressed with placeholders. Please replace them with your own environment according to the table below.

Placeholder What to replace with
<YOUR_USER> macOS username (e.g., taro.yamada)
<ARCHIVE_PATH> Archive save destination for voice logs (absolute path). Any folder readable from Cowork is fine. Example: /Users/taro.yamada/Documents/aqua-voice-archive
<KNOWLEDGE_PATH> Knowledge save destination for analysis results (absolute path). Example: /Users/taro.yamada/Documents/aqua-voice-knowledge
<YOUR_SLACK_EMAIL> Your own email address for Slack notifications

0. Prerequisites

We proceed with the assumption that the following conditions are met.

  • macOS (verified on Darwin 25.5 in this article)
  • Aqua Voice installed with Pro plan subscription (customInstructions requires Pro plan)
  • Aqua Voice Streaming Mode set to "Always" (Mac only. Required to make customInstructions work)
  • Environment where Claude Code Cowork is usable
  • Slack MCP connected to Cowork session (enable Slack connector from Claude Code MCP settings)
  • Python 3 available at /usr/bin/python3 (macOS standard)

1. Create a System to Automatically Archive Voice Logs to a Separate Folder

Aqua Voice voice logs are saved in the history key of ~/Library/Application Support/Aqua Voice/settings.json, but since they are FIFO-overwritten at the last 100 items, if left alone, old logs will be deleted in about 22 hours.

We'll set up a script that extracts logs to a folder readable from Cowork before they're deleted, and launchd to run it periodically. In this article, we'll use the placeholder <ARCHIVE_PATH> for the save destination (a regular folder like ~/Documents/aqua-voice-archive/ is fine).

Note: The reason we don't read directly from ~/Library/Application Support/ is that Cowork's scheduled tasks cannot read ~/Library/Application Support/ due to sandbox restrictions. We need to mirror to readable paths (such as ~/Documents/, ~/Downloads/, ~/Library/CloudStorage/...).

1-1. Place the Archive Script

Create the archive directory and place the Python script.

mkdir -p "$HOME/Library/Application Support/aqua-voice-archive/data"

Create $HOME/Library/Application Support/aqua-voice-archive/aqua_archive.py and paste the following. Replace <ARCHIVE_PATH> in the script with the absolute path of the save destination you've chosen.

Full text of aqua_archive.py (click to expand)
#$HOME/Library/Application Support/aqua-voice-archive/aqua_archive.py
"""
Script that permanently archives Aqua Voice transcription history to a specified folder.

Reads the history array from settings.json and appends unsaved entries to
week folder-specific history.jsonl files based on their timestamps.
Also mirrors key settings such as dictionary / replacements / customInstructions
to settings-snapshot.json (so they can be referenced from Cowork).
"""

import json
import os
import sys
import traceback
from datetime import datetime, timedelta, timezone
from pathlib import Path

HOME = Path.home()
SETTINGS_PATH = HOME / "Library/Application Support/Aqua Voice/settings.json"
# Archive save destination (any folder readable from Cowork is fine)
ARCHIVE_DIR = Path("<ARCHIVE_PATH>")
SNAPSHOT_PATH = ARCHIVE_DIR / "snapshot.json"
SETTINGS_SNAPSHOT_PATH = ARCHIVE_DIR / "settings-snapshot.json"
DATA_DIR = ARCHIVE_DIR / "data"

# Main keys to save from settings.json
SETTINGS_SNAPSHOT_KEYS = [
    "dictionary",
    "replacements",
    "customInstructions",
    "transcriptionModel",
    "language",
    "deepContext",
    "casualMessaging",
    "promptSet",
    "computerControlCustomInstructions",
]

# JST (UTC+9) fixed. Aqua Voice timestamps are UTC so conversion is needed
JST = timezone(timedelta(hours=9))

def parse_iso_to_jst(iso_str: str) -> datetime:
    """Convert ISO 8601 string to JST datetime. Handles 'Z' suffix."""
    normalized = iso_str.replace("Z", "+00:00")
    dt_utc = datetime.fromisoformat(normalized)
    return dt_utc.astimezone(JST)

def week_folder_name(dt_jst: datetime) -> str:
    """Generate Monday-based week folder name from JST datetime (YYYY-MMDD_YYYY-MMDD)."""
    days_since_monday = dt_jst.weekday()
    monday = dt_jst.date() - timedelta(days=days_since_monday)
    sunday = monday + timedelta(days=6)
    return f"{monday.strftime('%Y-%m%d')}_{sunday.strftime('%Y-%m%d')}"

def collect_known_session_ids() -> set[int]:
    """Collect known sessionIds from all history.jsonl files under data/."""
    known: set[int] = set()
    if not DATA_DIR.exists():
        return known
    for jsonl_path in DATA_DIR.glob("*/history.jsonl"):
        try:
            with jsonl_path.open("r", encoding="utf-8") as f:
                for line in f:
                    line = line.strip()
                    if not line:
                        continue
                    try:
                        entry = json.loads(line)
                        sid = entry.get("sessionId")
                        if sid is not None:
                            known.add(sid)
                    except json.JSONDecodeError:
                        continue
        except OSError:
            continue
    return known

def append_entries_to_week(entries: list[dict]) -> dict[str, int]:
    """Sort entries by week folder and append to history.jsonl."""
    by_week: dict[str, list[dict]] = {}
    for entry in entries:
        ts = entry.get("timestamp")
        if not ts:
            continue
        try:
            dt_jst = parse_iso_to_jst(ts)
        except ValueError:
            continue
        week_name = week_folder_name(dt_jst)
        by_week.setdefault(week_name, []).append(entry)

    result: dict[str, int] = {}
    for week_name, week_entries in by_week.items():
        week_dir = DATA_DIR / week_name
        week_dir.mkdir(parents=True, exist_ok=True)
        week_entries.sort(key=lambda e: e.get("timestamp", ""))
        jsonl_path = week_dir / "history.jsonl"
        with jsonl_path.open("a", encoding="utf-8") as f:
            for entry in week_entries:
                f.write(json.dumps(entry, ensure_ascii=False) + "\n")
        result[week_name] = len(week_entries)
    return result

def write_archive_log(lines: list[str]) -> None:
    """Append operation log to archive.log for the week containing the current time."""
    now_jst = datetime.now(JST)
    week_name = week_folder_name(now_jst)
    week_dir = DATA_DIR / week_name
    week_dir.mkdir(parents=True, exist_ok=True)
    log_path = week_dir / "archive.log"
    with log_path.open("a", encoding="utf-8") as f:
        for line in lines:
            f.write(line + "\n")
        f.write("---\n")

def main() -> int:
    log_lines: list[str] = []
    now_str = datetime.now(JST).strftime("%Y-%m-%d %H:%M:%S")
    log_lines.append(f"[{now_str}] start")

    if not SETTINGS_PATH.exists():
        log_lines.append(f"[{now_str}] error: settings.json not found at {SETTINGS_PATH}")
        write_archive_log(log_lines)
        return 1

    try:
        with SETTINGS_PATH.open("r", encoding="utf-8") as f:
            settings = json.load(f)
    except (OSError, json.JSONDecodeError) as e:
        log_lines.append(f"[{now_str}] error: failed to read settings.json: {e}")
        write_archive_log(log_lines)
        return 1

    history = settings.get("history", [])
    if not isinstance(history, list):
        log_lines.append(f"[{now_str}] error: history is not a list")
        write_archive_log(log_lines)
        return 1

    log_lines.append(f"[{now_str}] settings.json read: {len(history)} entries")

    known_ids = collect_known_session_ids()
    log_lines.append(f"[{now_str}] known sessionIds: {len(known_ids)}")

    new_entries = [
        e for e in history
        if isinstance(e, dict) and e.get("sessionId") is not None and e["sessionId"] not in known_ids
    ]
    log_lines.append(f"[{now_str}] new entries detected: {len(new_entries)}")

    if new_entries:
        result = append_entries_to_week(new_entries)
        for week_name in sorted(result.keys()):
            log_lines.append(f"[{now_str}] appended: {week_name}/history.jsonl  +{result[week_name]} entries")
    else:
        log_lines.append(f"[{now_str}] skip (no new entries, but snapshot refreshed)")

    try:
        ARCHIVE_DIR.mkdir(parents=True, exist_ok=True)
        with SNAPSHOT_PATH.open("w", encoding="utf-8") as f:
            json.dump(history, f, ensure_ascii=False, indent=2)
        log_lines.append(f"[{now_str}] snapshot.json updated")
    except OSError as e:
        log_lines.append(f"[{now_str}] error: failed to write snapshot.json: {e}")
        write_archive_log(log_lines)
        return 1

    try:
        settings_snapshot = {"snapshotAt": datetime.now(JST).isoformat()}
        for key in SETTINGS_SNAPSHOT_KEYS:
            settings_snapshot[key] = settings.get(key)
        with SETTINGS_SNAPSHOT_PATH.open("w", encoding="utf-8") as f:
            json.dump(settings_snapshot, f, ensure_ascii=False, indent=2)
        log_lines.append(f"[{now_str}] settings-snapshot.json updated")
    except OSError as e:
        log_lines.append(f"[{now_str}] error: failed to write settings-snapshot.json: {e}")
        write_archive_log(log_lines)
        return 1

    end_str = datetime.now(JST).strftime("%Y-%m-%d %H:%M:%S")
    log_lines.append(f"[{end_str}] done")
    write_archive_log(log_lines)
    return 0

if __name__ == "__main__":
    try:
        sys.exit(main())
    except Exception:
        traceback.print_exc(file=sys.stderr)
        sys.exit(1)

The script does the following:

  1. Reads ~/Library/Application Support/Aqua Voice/settings.json
  2. Collects known sessionIds from data/**/history.jsonl and extracts unsaved entries
  3. Appends to history.jsonl by JST Monday-based week folders
  4. Updates snapshot.json (mirror of the last 100 history items) and settings-snapshot.json (mirror of dictionary, replacements, customInstructions, etc.)

Note on why it's written in Python: This article assumes Mac operation, but it's intentionally written in Python to also work on Windows.

1-2. Place 2 launchd plists

Since Aqua Voice updates settings.json with atomic rename (writes to a temp file then swaps), launchd's WatchPaths can lose track of the file. Therefore, we'll operate with periodic execution.

Create 2 types of plists.

plist Role Trigger
com.user.aquavoice-archiver Run aqua_archive.py every 5 minutes StartInterval: 300
com.user.aquavoice-snapshot-weekly Force sync at 00:55 on Monday StartCalendarInterval

The forced sync at Monday 00:55 is a mechanism to reliably prepare the latest settings-snapshot.json before the Cowork scheduled task runs at 01:00.

Note: 5-minute interval is adjustable to your preference: The StartInterval value doesn't have to be 5 minutes (300 seconds). I was initially worried that running every 5 minutes might put a heavy load, but in practice each run takes only 0.1 to 0.5 seconds, so even setting it to 1 minute is no problem. Conversely, even at 10 to 15 minutes, since history retains the last 100 items, you won't miss any.

Create $HOME/Library/LaunchAgents/com.user.aquavoice-archiver.plist and paste the following. Replace <YOUR_USER>.

<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
<plist version="1.0">
<dict>
    <key>Label</key>
    <string>com.user.aquavoice-archiver</string>

    <key>ProgramArguments</key>
    <array>
        <string>/usr/bin/python3</string>
        <string>/Users/<YOUR_USER>/Library/Application Support/aqua-voice-archive/aqua_archive.py</string>
    </array>

    <key>StartInterval</key>
    <integer>300</integer>

    <key>RunAtLoad</key>
    <true/>

    <key>StandardOutPath</key>
    <string>/Users/<YOUR_USER>/Library/Application Support/aqua-voice-archive/data/launchd-stdout.log</string>

    <key>StandardErrorPath</key>
    <string>/Users/<YOUR_USER>/Library/Application Support/aqua-voice-archive/data/launchd-stderr.log</string>
</dict>
</plist>

Next, create $HOME/Library/LaunchAgents/com.user.aquavoice-snapshot-weekly.plist.

<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
<plist version="1.0">
<dict>
    <key>Label</key>
    <string>com.user.aquavoice-snapshot-weekly</string>

    <key>ProgramArguments</key>
    <array>
        <string>/usr/bin/python3</string>
        <string>/Users/<YOUR_USER>/Library/Application Support/aqua-voice-archive/aqua_archive.py</string>
    </array>

    <key>StartCalendarInterval</key>
    <dict>
        <key>Weekday</key>
        <integer>1</integer>
        <key>Hour</key>
        <integer>0</integer>
        <key>Minute</key>
        <integer>55</integer>
    </dict>

    <key>StandardOutPath</key>
    <string>/Users/<YOUR_USER>/Library/Application Support/aqua-voice-archive/data/launchd-weekly-stdout.log</string>

    <key>StandardErrorPath</key>
    <string>/Users/<YOUR_USER>/Library/Application Support/aqua-voice-archive/data/launchd-weekly-stderr.log</string>
</dict>
</plist>

1-3. Register with launchd

Load the 2 plists with the following commands.

launchctl load "$HOME/Library/LaunchAgents/com.user.aquavoice-archiver.plist"
launchctl load "$HOME/Library/LaunchAgents/com.user.aquavoice-snapshot-weekly.plist"

Since com.user.aquavoice-archiver has RunAtLoad: true, it will execute once immediately upon registration.

Verify that they are registered.

launchctl list | grep aquavoice
# Example output
-	0	com.user.aquavoice-archiver
-	0	com.user.aquavoice-snapshot-weekly

If there are errors, they will be output to the standard error log.

cat "$HOME/Library/Application Support/aqua-voice-archive/data/launchd-stderr.log"

An empty file means it's normal.

2. Create a Cowork Scheduled Task

From here, we'll create the mechanism for Claude (Cowork) to perform analysis.

2-1. Create a New Scheduled Task in Cowork

  1. Click "Scheduled" in the Cowork sidebar to open the Scheduled tasks screen

  2. Click the "+ New task" button in the upper right of the screen, and from the dropdown that appears, select "Set up manually"

07-cowork-scheduled-new-task

  1. The "Create Scheduled Task" dialog will open. Enter the following:

08-cowork-task-form

Item Input content
Name aqua-voice-weekly-analysis
Description Aqua Voice weekly settings analysis task
Prompt body Content equivalent to SKILL.md described below (write the prompt directly)
Frequency Select "Weekly" and specify Every Monday 01:00
Model Claude Sonnet 4.6 recommended
  1. Press the "Save" button to create the task

2-2. Prompt Body to Pass to the Task

Replace the generated SKILL.md with the following content. Keep the name in the front matter as the task creation ID, and only replace description. Replace <ARCHIVE_PATH> and <KNOWLEDGE_PATH> with the absolute paths of your chosen save destinations.

The prompt includes not only logic for detecting addition candidates but also deletion candidates. With Aqua Voice's Pro plan, you can register up to 800 entries in dictionary, so you won't need to worry about deletion in the beginning. However, the longer you use it, the more registered words will accumulate, so to avoid problems when the limit is reached, I've built in from the start a mechanism that suggests words that haven't appeared for 8 consecutive weeks as deletion candidates.

Full text of SKILL.md (click to expand)
---
name: aqua-voice-weekly-analysis
description: Aqua Voice weekly settings analysis — Generate improvement suggestions for dictionary, replacements, and customInstructions and save to knowledge base
---

# Aqua Voice Weekly Settings Analysis Task

Runs automatically every Monday at 01:00. Analyzes Aqua Voice voice logs, generates improvement suggestions for dictionary, replacements, and customInstructions, saves them to the knowledge base, and notifies Slack.

All data is mirror-saved to a designated folder readable from Cowork. Do not directly access `~/Library/Application Support/` (cannot be read from sandbox).

---

## Step 1: Identify and Load Last Week's history.jsonl

Archive directory:
`<ARCHIVE_PATH>/data/`

Use Bash to identify the "previous week (Mon-Sun)" folder from the execution date (Monday):

```bash
python3 -c "
from datetime import datetime, timedelta
today = datetime.today()
last_monday = today - timedelta(days=today.weekday() + 7)
last_sunday = last_monday + timedelta(days=6)
print(f'{last_monday.strftime(\"%Y-%m%d\")}_{last_sunday.strftime(\"%Y-%m%d\")}')
"
```

Use the folder name obtained above to read all lines of `history.jsonl`. If the folder doesn't exist, record "No log from last week" and output in Steps 7 and 8, then end.

---

## Step 2: Load Current Settings Snapshot

Load the following file:
`<ARCHIVE_PATH>/settings-snapshot.json`

Keys included: `dictionary`, `replacements`, `customInstructions`, `transcriptionModel`, `language`, `deepContext`, `casualMessaging`, `promptSet`, `computerControlCustomInstructions`, `snapshotAt`

---

## Step 3: Load Past Suggestion Files (Last 4 weeks; 8 weeks for dictionary deletion)

Load `aqua-voice-suggestions-*.md` files under `<KNOWLEDGE_PATH>/notes/`, 4 weeks for addition candidates and 8 weeks for dictionary deletion candidates.

For each suggestion, aggregate the following from past files:
- Number of weeks appeared (for calculating continuation score)
- Appearance count per week (history)

Criteria for judging same suggestion:
- dictionary: word to add matches
- replacements: both from and to match
- customInstructions: meaning is equivalent (text similarity 80% or above)

---

## Step 4: Analysis

### 4-1. Detecting dictionary Addition Candidates

Important: Don't judge based on simple divergence between `rawText` and `content` alone (to avoid false positives where LLM correction has correctly fixed content).

Target cases where problems remain in content (final output):

| Detection condition | Example |
|---|---|
| Spelling variations: Multiple expressions mixed in content for the same intent | Both `Claude` and `クロード` appear |
| Remaining katakana: Proper noun that should be in English notation appears in katakana in content | `プレジデント` (should be `Presigned`) |
| Remaining misconversion: Clearly different conversion from intent that has become established in content | `蔵人` (should be `Claude`) |

Must not semantically duplicate words already registered in dictionary.

### 4-2. Detecting dictionary Deletion Candidates

Among existing dictionary registered words, those that have not appeared in either content or rawText for 8 consecutive weeks.

### 4-3. Detecting replacements Addition Candidates

- The same URL, command, or fixed phrase appears 3 or more times in content, including similar patterns
- Always present "from (spoken phrase) → to (converted text)" as a pair

### 4-4. Detecting replacements Deletion Candidates

The `from` phrase of existing replacements has not appeared in either content or rawText for 8 consecutive weeks.

### 4-5. Detecting customInstructions Addition Candidates

| Category | Detection condition |
|---|---|
| Filler removal | "あー", "えー", "えーと", "あのー", "まあ", "なんか" each remain 5+ times in content |
| Missing command words | "改行", "かっこ", "かぎかっこ" remain as strings in content |
| Duplicate rephrasing | Same expression appears consecutively |
| Spelling variations (style) | Mixed half-width/full-width numbers, inconsistent presence/absence of katakana long vowel marks, etc. |

### 4-6. Recommendation Score Calculation Logic (Common to All Types)

```
Recommendation score = max(frequency score, continuation score) + match bonus + decay
```

Frequency score (strength of this week alone):

| Appearances this week | Score |
|---|---|
| 20 or more | 90% |
| 10-19 | 75% |
| 5-9 | 55% |
| 3-4 | 40% |
| 1-2 | 20% |
| 0 | 0% |

Continuation score (number of weeks appeared in last 4 weeks):

| Weeks appeared | Score |
|---|---|
| 4 consecutive weeks | 95% |
| 3 weeks | 75% |
| 2 weeks | 55% |
| 1 week | 30% |
| 0 weeks | 0% |

- Match bonus (matches past pending suggestion): +10%
- Decay (0 occurrences this week + exists only as past pending): -15%
- Recommendation score clipped to 0-100%

Auto-archive:
- Addition candidates: Remove from suggestion list if zero appearances for 4 consecutive weeks
- dictionary deletion candidates: Only suggest after 8 consecutive weeks of zero

---

## Step 5: Generate Suggestions

Summarize each suggestion in the following format (dictionary addition/deletion, replacements addition/deletion, customInstructions addition):

```
### [Type] Value: <Content>
- Type: <Type>
- Recommendation Score: XX%
- Frequency Score: XX% (N items this week)
- Continuity Score: XX% (appeared N weeks out of the last 4 weeks)
- Adjustment: +10% / -15% / none
- Appearance History: [N items this week, N items 1 week ago, N items 2 weeks ago, N items 3 weeks ago]
- Status: Confirmed Candidate (80% or above) / Pending (below 80%)
```

---

## Step 6: Saving to Knowledge Base

Create a Markdown file at the following path (overwrite if file already exists):

`<KNOWLEDGE_PATH>/notes/aqua-voice-suggestions-YYYY-MM-DD.md`

Front matter:
```yaml
---
created: YYYY-MM-DD
tags: [aqua-voice, wip]
summary: Aqua Voice Weekly Analysis YYYY-MM-DD - N confirmed candidates, N pending
---
```

Body structure:
1. Confirmed Candidates (recommendation score 80% or above)
2. Pending (recommendation score below 80%)
3. Archived suggestions (if any)
4. This week's statistics

---

## Step 7: Notification Summary Output (Chat)

Always write the file path as a full path.

```
Aqua Voice Weekly Analysis Report YYYY-MM-DD

[This Week's Statistics]
• Number of analyzed entries: N items
• Confirmed candidates (80% or above): N items
• Pending: N items

[Confirmed Candidates (Recommendation Score 80% or above)]
• [dictionary add] <word> — Recommendation Score XX% (N items this week, appeared N weeks out of last 4 weeks)
• [replacements add] from "<utterance>" → to "<conversion target>" — Recommendation Score XX%
• [customInstructions add] <category>: <one-line description> — Recommendation Score XX%

[Pending (Recommendation Score below 80%)]
(same as above)

[Detail File]
<KNOWLEDGE_PATH>/notes/aqua-voice-suggestions-YYYY-MM-DD.md
```

If both confirmed candidates and pending are 0 items, send only a short message saying "No suggestions this week."

---

## Step 8: Slack DM Notification to Self

1. Search for `<YOUR_SLACK_EMAIL>` using `slack_search_users` to get your own user ID
2. Send a DM to the retrieved user ID using `slack_send_message`

If Slack MCP is unavailable or sending fails, note that fact only in the chat output and finish.

2-3. Manually Run the Task Once for Testing

Rather than waiting for the scheduled execution, first do a manual test run to confirm everything works correctly.

  1. Click the aqua-voice-weekly-analysis task you created from the "Scheduled" section in the Cowork sidebar
  2. Press the "Run now" button on the task detail screen
  3. Confirm that the analysis report is output in the execution result chat

During the first run, Cowork will show access permission dialogs in sequence. Press "Allow" for all of them.

  • Read permission for the archive folder (<ARCHIVE_PATH>)
  • Read/write permission for the knowledge folder (<KNOWLEDGE_PATH>)
  • Permission to execute slack_send_message for Slack MCP

Approved content is automatically recorded in userSelectedFolders and approvedPermissions.
Since subsequent automatic runs will proceed without dialogs, there is no need to manually edit scheduled-tasks.json.

Note: Since Cowork's scheduled tasks run in a sandbox, they can only read paths that have been permitted. However, ~/Library/Application Support/ itself is outside the sandbox scope and cannot be permitted, so it is not possible to directly read Aqua Voice's own settings.json. This is why we mirror it to a separate folder in Step 1.

Verifying Operation

Verify the test results from "2-3. Manually Run the Task Once for Testing" on the following 2 points.

Verifying Cowork Task Operation

The report is delivered in two ways: a Slack DM summary and a Markdown detail file in the knowledge base.
Let's look at the contents of each.

Summary Delivered via Slack DM

If the test results from "2-3. Manually Run the Task Once for Testing" arrive in Slack, it's a success. The actual report that arrives looks like this:

05-slack-weekly-report

The body text is in the following format (only a one-line summary of type, recommendation score, and count):

Aqua Voice Weekly Analysis Report 2026-05-24

[This Week's Statistics]
• Number of analyzed entries: 596 items
• Confirmed candidates (80% or above): 8 items
• Pending: 8 items

[Confirmed Candidates (Recommendation Score 80% or above)]
• [dictionary add] S3 — Recommendation Score 100% (31 items this week)
• [dictionary add] Bedrock — Recommendation Score 85% (10 items this week)
• [customInstructions add] Filler removal: Instruction text to remove "なんか", "まあ", "えー" — Recommendation Score 100% (なんか 99 items this week)

[Pending (Recommendation Score below 80%)]
• [dictionary add] Cognito — Recommendation Score 65% (6 items this week)
• [dictionary delete] Antigravity / GenU / ハーネスエンジニアリング / 冗長化 — Recommendation Score 65%

[Detail File]
<KNOWLEDGE_PATH>/notes/aqua-voice-suggestions-2026-05-24.md

The Slack side only shows a list of what was suggested.
The specific instruction text block used for customInstructions registration is not included in the Slack message body.

Opening the Markdown Detail File

By opening the "Detail File" path at the end of the Slack message body, you can view the Markdown report saved in the knowledge base.

open "<KNOWLEDGE_PATH>/notes/aqua-voice-suggestions-2026-05-24.md"

The full text of the actually delivered report is as follows:

Full text of aqua-voice-suggestions-2026-05-24.md (click to expand)
---
created: 2026-05-24
tags: [aqua-voice, wip]
summary: AquaVoice Weekly Analysis 2026-05-24 - 8 confirmed candidates, 8 pending (analyzed 596 items from 2026-0511 to 0517)
---

# AquaVoice Weekly Analysis Report 2026-05-24

Target week: 2026-0511 to 2026-0517 (596 items). Settings snapshot: 2026-05-24T18:53:37+09:00.

---

## 1. Confirmed Candidates (Recommendation Score 80% or above)

### [dictionary add] Value: S3
- Type: dictionary add
- Word to add: `S3`
- Detection reason: Appears in content but absent in rawText (corrected via deep context)
- Recommendation Score: 100%
- Frequency Score: 90% (appeared in 31 entries this week)
- Continuity Score: 30% (appeared in 1 week out of last 4 weeks)
- Adjustment: +10% (matches past pending)
- Appearance History: [31 items this week, 1 week ago -, 2 weeks ago -, 3 weeks ago -]
- Status: **Confirmed Candidate**

### [dictionary add] Value: RDS
- Type: dictionary add
- Word to add: `RDS`
- Detection reason: Appears in content but absent in rawText (misrecognized as "RTS" etc.)
- Recommendation Score: 100%
- Frequency Score: 90% (appeared in 29 entries this week)
- Continuity Score: 30% (appeared in 1 week out of last 4 weeks)
- Adjustment: +10% (matches past pending)
- Appearance History: [29 items this week, 1 week ago -, 2 weeks ago -, 3 weeks ago -]
- Status: **Confirmed Candidate**

### [dictionary add] Value: AWS
- Type: dictionary add
- Word to add: `AWS`
- Detection reason: Appears in content but absent in rawText
- Recommendation Score: 100%
- Frequency Score: 90% (appeared in 24 entries this week)
- Continuity Score: 30% (appeared in 1 week out of last 4 weeks)
- Adjustment: +10% (matches past pending)
- Appearance History: [24 items this week, 1 week ago -, 2 weeks ago -, 3 weeks ago -]
- Status: **Confirmed Candidate**

### [dictionary add] Value: VPC
- Type: dictionary add
- Word to add: `VPC`
- Detection reason: content 18 entries / rawText 20 entries (also appears in rawText but with correction discrepancy)
- Recommendation Score: 85%
- Frequency Score: 75% (18 entries this week, 10-19 item range)
- Continuity Score: 30% (appeared in 1 week out of last 4 weeks)
- Adjustment: +10% (matches past pending)
- Appearance History: [18 items this week, 1 week ago -, 2 weeks ago -, 3 weeks ago -]
- Status: **Confirmed Candidate**

### [dictionary add] Value: Fargate
- Type: dictionary add
- Word to add: `Fargate`
- Detection reason: Appears in content but absent in rawText
- Recommendation Score: 85%
- Frequency Score: 75% (10 entries this week)
- Continuity Score: 30% (appeared in 1 week out of last 4 weeks)
- Adjustment: +10% (matches past pending)
- Appearance History: [10 items this week, 1 week ago -, 2 weeks ago -, 3 weeks ago -]
- Status: **Confirmed Candidate**

### [dictionary add] Value: LLM
- Type: dictionary add
- Word to add: `LLM`
- Detection reason: Appears in content but absent in rawText
- Recommendation Score: 85%
- Frequency Score: 75% (10 entries this week)
- Continuity Score: 30% (appeared in 1 week out of last 4 weeks)
- Adjustment: +10% (matches past pending)
- Appearance History: [10 items this week, 1 week ago -, 2 weeks ago -, 3 weeks ago -]
- Status: **Confirmed Candidate**

### [dictionary add] Value: Bedrock
- Type: dictionary add
- Word to add: `Bedrock`
- Detection reason: Appears in content but absent in rawText
- Recommendation Score: 85%
- Frequency Score: 75% (10 entries this week)
- Continuity Score: 30% (appeared in 1 week out of last 4 weeks)
- Adjustment: +10% (matches past pending)
- Appearance History: [10 items this week, 1 week ago -, 2 weeks ago -, 3 weeks ago -]
- Status: **Confirmed Candidate**

### [customInstructions add] Filler Removal
- Type: customInstructions add
- Category: Filler removal
- Instruction text to register (English recommended, copy-paste ready):
  ```
  Remove filler words and verbal tics from the transcription output. Specifically, remove or omit: 「なんか」「まあ」「えー」「えーと」「あのー」when used as fillers (not meaningful words). Do not remove these if they carry semantic meaning.
  ```
- Recommendation Score: 100%
- Frequency Score: 90% (なんか=99 times, まあ=22 times, えー=7 times remaining in content)
- Continuity Score: 30% (appeared in 1 week out of last 4 weeks)
- Adjustment: +10% (matches past pending)
- Appearance History: [this week なんか99/まあ22/えー7/えーと4, 1 week ago -, 2 weeks ago -, 3 weeks ago -]
- Status: **Confirmed Candidate**
- Note: 「なんか」 is often used as a meaningful word (clearly filler in about 5 out of 76 entries). It is important to explicitly state in the instruction text "keep meaningful words."

---

## 2. Pending (Recommendation Score below 80%)

### [dictionary add] Value: Cognito
- Type: dictionary add
- Word to add: `Cognito`
- Detection reason: content 6 entries / rawText 0 entries
- Recommendation Score: 65%
- Frequency Score: 55% (6 entries this week, 5-9 item range)
- Continuity Score: 30% (appeared in 1 week out of last 4 weeks)
- Adjustment: +10% (matches past pending)
- Appearance History: [6 items this week, 1 week ago -, 2 weeks ago -, 3 weeks ago -]
- Status: Pending

### [dictionary add] Value: Claude (spelling variation)
- Type: dictionary add
- Word to add: `Claude`
- Detection reason: "Claude" (7 items) and "クロード" (4 items) mixed in content. In rawText, "クロード" is dominant (6 items), "Claude" is zero.
- Recommendation Score: 55%
- Frequency Score: 55% (7 entries this week, 5-9 item range)
- Continuity Score: 0% (no previous suggestion, new)
- Adjustment: none
- Appearance History: [7 items this week (+ クロード 4 items mixed), 1 week ago -, 2 weeks ago -, 3 weeks ago -]
- Status: Pending (new)
- Note: Anthropic is already registered. Adding Claude alone is expected to unify "クロード" → "Claude."

### [dictionary add] Value: CloudWatch
- Type: dictionary add
- Word to add: `CloudWatch`
- Detection reason: content 5 entries / rawText 0 entries (misrecognized as "クラウドウォッチドッグス" etc.)
- Recommendation Score: 55%
- Frequency Score: 55% (5 entries this week, 5-9 item range)
- Continuity Score: 0% (no previous suggestion, new)
- Adjustment: none
- Appearance History: [5 items this week, 1 week ago -, 2 weeks ago -, 3 weeks ago -]
- Status: Pending (new)

### [dictionary add] Value: HubSpot
- Type: dictionary add
- Word to add: `HubSpot`
- Detection reason: content 3 entries / rawText 0 entries
- Recommendation Score: 50%
- Frequency Score: 40% (3 entries this week, 3-4 item range)
- Continuity Score: 30% (appeared in 1 week out of last 4 weeks)
- Adjustment: +10% (matches past pending)
- Appearance History: [3 items this week, 1 week ago -, 2 weeks ago -, 3 weeks ago -]
- Status: Pending

### [dictionary add] Value: ALB
- Type: dictionary add
- Word to add: `ALB`
- Detection reason: content 4 entries / rawText 0 entries
- Recommendation Score: 40%
- Frequency Score: 40% (4 entries this week, 3-4 item range)
- Continuity Score: 0% (no previous suggestion, new)
- Adjustment: none
- Appearance History: [4 items this week, 1 week ago -, 2 weeks ago -, 3 weeks ago -]
- Status: Pending (new)

### [dictionary add] Value: IAM
- Type: dictionary add
- Word to add: `IAM`
- Detection reason: content 3 entries / rawText 0 entries
- Recommendation Score: 40%
- Frequency Score: 40% (3 entries this week, 3-4 item range)
- Continuity Score: 0% (no previous suggestion, new)
- Adjustment: none
- Appearance History: [3 items this week, 1 week ago -, 2 weeks ago -, 3 weeks ago -]
- Status: Pending (new)

### [dictionary delete] Antigravity / GenU / Skills / ハーネスエンジニアリング / 冗長化 / NATGateway
- Type: dictionary delete
- Target words: `Antigravity`, `GenU`, `Skills`, `ハーネスエンジニアリング`, `冗長化`, `NATGateway`
- Detection reason: Zero appearances in both content and rawText this week
- Recommendation Score: 40%
- Frequency Score: 0% (0 items this week)
- Continuity Score: 30% (appeared in pending for 1 week out of last 4 weeks)
- Adjustment: +10% (matches past pending)
- Appearance History: [0 items this week, 1 week ago -, 2 weeks ago -, 3 weeks ago -]
- Status: Pending (8 consecutive zero weeks required. Currently only 1 week)

### [dictionary add] Value: Presigned (remaining misrecognition)
- Type: dictionary add
- Word to add: `Presigned`
- Detection reason: Misrecognized in rawText as "プレゼント URL", "プレザイン". Some cases also not fully corrected in content.
- Recommendation Score: 20%
- Frequency Score: 20% (2 entries this week, 1-2 item range)
- Continuity Score: 0% (no previous suggestion, new)
- Adjustment: none
- Appearance History: [2 items this week, 1 week ago -, 2 weeks ago -, 3 weeks ago -]
- Status: Pending (new)

---

## 3. Archived Suggestions

None

---

## 4. This Week's Statistics

- Number of analyzed entries: 596 items
- Confirmed candidates (recommendation score 80% or above): 8 items
- Pending (recommendation score below 80%): 8 items
- replacements addition candidates: none (no repeating patterns 3 or more times)
- replacements deletion candidates: none
- Usage status of major dictionary words: AgentCore=20 items, Anthropic=8 items, Markdown=8 items, ナレッジ=5 items (all still in active use)

---

_Auto-generated: AquaVoice weekly analysis task (run on 2026-05-24). Apply changes manually._

If this report arrives, all you need to do is register the items listed in the "Confirmed Candidates" section directly into the Aqua Voice UI.
Readers don't need to think up English instruction text themselves or analyze misrecognition trends.

  • Dictionary addition: Register the word to add for each item (e.g., S3, RDS, AWS, VPC ...) directly from the "+ Add" button in the Dictionary tab
  • customInstructions addition: Copy the entire instruction text code block and paste it into the Instructions tab, then save
  • Dictionary deletion: Delete the items listed under target words from the Dictionary tab

By simply reflecting what is written in the report, your weekly operations will run smoothly. The specific registration steps are explained in the next section, "Applying Suggestions to Aqua Voice."

Applying Suggestions to Aqua Voice

Among the candidates that appear in the report, manually register the ones you find convincing into the Aqua Voice UI (no automatic application is done).
The registration destinations correspond to 3 tabs matching the type in the report ([dictionary add] / [replacements add] / [customInstructions add]).

From the "+ Add" button in the Dictionary tab, paste in the words listed under [dictionary add] in the report and register them.

02-aqua-voice-dictionary

From the "+ Add" button in the Replacements tab, paste in the from (spoken phrase) and to (conversion target text) listed under [replacements add] in the report and register them as-is.

03-aqua-voice-replacements

In the Instructions tab, paste the Markdown-format instruction text presented under [customInstructions add] in the report and press "Save".
The format doesn't have to be natural English prose — paste the Markdown exactly as Claude generated it (including headings, bullet points, and code examples). Structured descriptions also work more reliably on the Aqua Voice side.

04-aqua-voice-custom-instructions

This completes the full operation verification. From here, you simply enter the routine of checking Slack each week and registering the convincing suggestions into Aqua Voice. The execution schedule (day of week and time) follows the timing you specified in "2-1. Creating a New Scheduled Task in Cowork," so feel free to set it to whatever fits your own lifestyle.

Summary

Recently, I've been hearing the term "harness engineering" more and more.
It mainly comes up in the context of coding AI like Claude Code, but the idea of not just introducing AI and calling it done — but rather continuing to improve it through ongoing operation — seems likely to become far more widely adopted going forward.

Voice input is also a target for this approach.
Collect logs, send them to AI, receive improvement suggestions.
Simply running this cycle causes the quality of voice input to improve the more you use it.

On top of that, if you speak your thoughts aloud and keep them in logs, they themselves become personal knowledge. I believe the use of voice input logs can be extended to purposes such as verbalizing thoughts and converting tacit knowledge into explicit knowledge.

There's still so much I want to say about voice input, so I hope to continue publishing related articles on DevelopersIO in the future.


生成AI活用はクラスメソッドにお任せ

過去に支援してきた生成AIの支援実績100+を元にホワイトペーパーを作成しました。御社が抱えている課題のうち、どれが解決できて、どのようなサービスが受けられるのか?4つのフェーズに分けてまとめています。どうぞお気軽にご覧ください。

生成AI資料イメージ

無料でダウンロードする

Share this article