# Agent Task: Add ARIA Labels to Icon-Only Buttons (Task 4.2)

> **Parallel execution:** SAFE to run alongside ALL other agents.
> **Files touched:** ONLY `.tsx` component files — adds `aria-label` attributes to existing JSX elements.
> **No conflicts:** Agents 1/2 touch `globals.css`, Agent 3 touches `providers.tsx`/`layout.tsx`. This agent only adds attributes to component JSX — never touches CSS, layout, or provider files.

---

## Pre-Flight Checklist

```bash
# 1. Ensure git is clean in every repo
for repo in learning_ai_flowmonk learning_ai_trails learning_ai_jarvis_jr learning_ai_notes learning_ai_local_memory_gpt learning_ai_fastgap learning_ai_clock learning_ai_local_llms learning_ai_common_plat learning_voice_ai_agent; do
  echo "=== $repo ===" && cd /Users/sd9235/code/mygh/$repo && git status --short
done

# 2. Pull latest (other agents may have pushed)
for repo in learning_ai_flowmonk learning_ai_trails learning_ai_jarvis_jr learning_ai_notes learning_ai_local_memory_gpt learning_ai_fastgap learning_ai_clock learning_ai_local_llms learning_ai_common_plat learning_voice_ai_agent; do
  cd /Users/sd9235/code/mygh/$repo && git pull --ff-only origin main 2>&1 | tail -1
done
```

**STOP condition:** If any repo has uncommitted changes, stash or commit them first.

---

## What Counts as an Icon-Only Button

A button is "icon-only" if it renders **no visible text** — only an SVG icon or a Lucide component:

```tsx
// BROKEN — no accessible name
<button onClick={handleClose}><X className="h-4 w-4" /></button>

// FIXED — add aria-label
<button onClick={handleClose} aria-label="Close"><X className="h-4 w-4" /></button>
```

Also check for:

- `<button>` with only an `<svg>` child
- `<button>` with only a Lucide icon (`<Plus />`, `<Trash2 />`, `<Settings />`, etc.)
- `<Link>` styled as a button with only an icon
- Icon-only elements inside `<DialogClose>`, `<AlertDialogCancel>`, etc.

**NOT icon-only (do NOT add aria-label):**

- Buttons with visible text: `<button><Plus /> Add Item</button>` — already accessible
- Buttons that already have `aria-label`
- Pure decorative icons not wrapped in an interactive element

---

## Repos to Process

| Repo                           | Web Dir                                                     | Estimated buttons |
| ------------------------------ | ----------------------------------------------------------- | ----------------- |
| `learning_ai_flowmonk`         | `web/src/`                                                  | ~5-10             |
| `learning_ai_trails`           | `web/src/`                                                  | ~10-15            |
| `learning_ai_jarvis_jr`        | `web/src/`                                                  | ~10-15            |
| `learning_ai_notes`            | `web/src/`                                                  | ~10-15            |
| `learning_ai_local_memory_gpt` | `web/src/`                                                  | ~15-20            |
| `learning_ai_fastgap`          | `web/src/`                                                  | ~15-20            |
| `learning_ai_clock`            | `web/src/`                                                  | ~20+              |
| `learning_ai_local_llms`       | `dashboard/src/`                                            | ~10-15            |
| `learning_ai_common_plat`      | `dashboards/admin-web/src/` + `dashboards/tracker-web/src/` | ~20 each          |
| `learning_voice_ai_agent`      | `user-dashboard-web/src/`                                   | ~15               |

---

## Per-Repo Procedure

### Step 0: Audit — find ALL candidates (DRY RUN — no edits yet)

Run all three searches and save the combined output:

```bash
cd /Users/sd9235/code/mygh/<repo>
WEBDIR="web/src"  # or "dashboard/src" for local-llms, "user-dashboard-web/src" for voice-agent

echo "=== Buttons without aria-label ==="
grep -rn '<button' $WEBDIR/ --include='*.tsx' | grep -v 'aria-label'

echo ""
echo "=== Icon imports (to know which icons are used) ==="
grep -rn "from 'lucide-react'" $WEBDIR/ --include='*.tsx' | head -20

echo ""
echo "=== Buttons with only icon children (high-confidence candidates) ==="
grep -rn '<button' $WEBDIR/ --include='*.tsx' -A3 | grep -B1 'className="h-[0-9]\|className="w-[0-9]' | grep '<button'
```

### Step 1: Read each candidate file and classify

For each button found, read the actual file and determine:

| Classification                | Action                    | Example                                     |
| ----------------------------- | ------------------------- | ------------------------------------------- |
| **Icon-only, no aria-label**  | ADD aria-label            | `<button><X /></button>`                    |
| **Icon-only, has aria-label** | SKIP (already fixed)      | `<button aria-label="Close"><X /></button>` |
| **Icon + text**               | SKIP (already accessible) | `<button><Plus /> Add</button>`             |
| **Not a button**              | SKIP                      | `<div><X /></div>` (not interactive)        |

**Critical:** Read the JSX carefully. Don't add aria-label to buttons that already have visible text children, even if text is in a `<span>`.

### Step 2: Choose good labels

Use this reference table. **Always prefer context-specific labels:**

| Icon                                      | Good Label                                              | Bad Label            |
| ----------------------------------------- | ------------------------------------------------------- | -------------------- |
| `<X />`                                   | `"Close"` / `"Close dialog"` / `"Dismiss notification"` | `"X"`                |
| `<Plus />`                                | `"Create new zone"` / `"Add task"` (context!)           | `"Plus"`             |
| `<Trash2 />`                              | `"Delete task"` / `"Remove agent"`                      | `"Trash"`            |
| `<Edit />` / `<Pencil />`                 | `"Edit flow"` / `"Rename"`                              | `"Pencil"`           |
| `<Settings />`                            | `"Open settings"`                                       | `"Gear"`             |
| `<Menu />` / `<PanelLeft />`              | `"Toggle sidebar"` / `"Open menu"`                      | `"Menu icon"`        |
| `<ChevronLeft />` / `<ChevronRight />`    | `"Go back"` / `"Next"` / `"Collapse sidebar"`           | `"Arrow"`            |
| `<Search />`                              | `"Search"`                                              | `"Magnifying glass"` |
| `<Copy />`                                | `"Copy to clipboard"`                                   | `"Copy"`             |
| `<Sun />` / `<Moon />`                    | `"Switch to light theme"` / `"Switch to dark theme"`    | `"Sun"`              |
| `<Pin />` / `<Unpin />`                   | `"Pin conversation"` / `"Unpin"`                        | `"Pin"`              |
| `<RefreshCw />`                           | `"Refresh"` / `"Retry"`                                 | `"Refresh icon"`     |
| `<MoreVertical />` / `<MoreHorizontal />` | `"More options"`                                        | `"Dots"`             |
| `<Download />`                            | `"Export data"` / `"Download"`                          | `"Arrow down"`       |
| `<Eye />` / `<EyeOff />`                  | `"Show password"` / `"Hide password"`                   | `"Eye"`              |
| `<Send />`                                | `"Send message"`                                        | `"Send"`             |

### Step 3: Apply fixes — one file at a time

For each file with icon-only buttons, use the edit tool to add `aria-label` to each element.

**Pattern — simple icon button:**

```tsx
// BEFORE
<button onClick={handleClose}>
  <X className="h-4 w-4" />
</button>

// AFTER — add aria-label attribute
<button onClick={handleClose} aria-label="Close">
  <X className="h-4 w-4" />
</button>
```

**Pattern — conditional icons:**

```tsx
// BEFORE
<button onClick={toggle}>
  {expanded ? <ChevronUp /> : <ChevronDown />}
</button>

// AFTER — dynamic aria-label
<button onClick={toggle} aria-label={expanded ? "Collapse" : "Expand"}>
  {expanded ? <ChevronUp /> : <ChevronDown />}
</button>
```

**Pattern — icon Link:**

```tsx
// BEFORE
<Link href="/settings"><Settings className="h-5 w-5" /></Link>

// AFTER
<Link href="/settings" aria-label="Settings"><Settings className="h-5 w-5" /></Link>
```

### Step 4: Verify — recount unlabeled icon buttons

```bash
echo "=== Remaining unlabeled buttons ==="
grep -rn '<button' $WEBDIR/ --include='*.tsx' | grep -v 'aria-label' | grep -v '>[A-Za-z]'
```

This will have false positives (buttons with text in child components), but the count should be MUCH lower than Step 0. Manually verify each remaining hit.

**STOP condition:** If you find a button you're unsure about (can't tell if it has visible text), SKIP it. Better to miss one than add a redundant label.

### Step 5: Build Gate (MANDATORY)

```bash
cd web && pnpm run build 2>&1 | tail -20
```

Adding `aria-label` should NEVER break a build, but verify anyway.

**If build fails:** Your edit likely had a syntax error (missing quote, unclosed attribute). Check `git diff` and fix.

### Step 6: Commit and push

```bash
git add -A
git commit -m "feat(a11y): add aria-label to icon-only buttons across web app"
git push origin main
```

### Step 7: Pull latest before next repo

Other agents may have pushed while you worked. Always pull before starting the next repo:

```bash
cd /Users/sd9235/code/mygh/<next-repo> && git pull --ff-only origin main
```

---

## Rollback Recipe

```bash
git revert HEAD --no-edit && git push origin main
```

---

## Order (simplest first)

1. `learning_ai_flowmonk` — ~5-10 icon buttons
2. `learning_ai_trails` — ~10-15
3. `learning_ai_jarvis_jr` — ~10-15
4. `learning_ai_notes` — ~10-15
5. `learning_ai_local_memory_gpt` — ~15-20 (chat UI)
6. `learning_ai_fastgap` — ~15-20 (body viz controls)
7. `learning_ai_clock` — ~20+ (timer controls, pomodoro)
8. `learning_ai_local_llms` — ~10-15 (dashboard/ path)
9. `learning_ai_common_plat` — admin-web + tracker-web (~20 each)
10. `learning_voice_ai_agent` — user-dashboard-web (~15)

Complete each repo fully (audit → fix → build → commit → push) before starting the next.

---

## Rules

- **ONLY add `aria-label` attributes** — no other changes to JSX, no CSS, no logic
- **NEVER add aria-label to buttons with visible text** — that creates confusing double-announcement
- **NEVER change visual appearance** — no className changes, no style changes
- **Use context-specific labels** — `"Delete task"` not `"Delete"` when the context is clear from the component
- **Skip when unsure** — better to miss one than introduce a redundant or wrong label
- **The `@bytelyst/ui` components already have aria-labels** — don't duplicate on `Modal`, `ConfirmDialog`, `Toast`
- **Pull before each repo** — other agents are running in parallel
- **Build must pass** before committing
- Commit message: `feat(a11y): add aria-label to icon-only buttons across web app`
