Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion .claude/commands/voxclaw-failure.md
Original file line number Diff line number Diff line change
Expand Up @@ -11,5 +11,5 @@ Condense the failure into one short sentence. Lead with fail or blocked status.
Run this command:

```bash
printf '%s\n' "$ARGUMENTS" | plugins/voxclaw/scripts/voxclaw-say --kind failure
printf '%s\n' "$ARGUMENTS" | plugins/voxclaw/scripts/voxclaw-say
```
2 changes: 1 addition & 1 deletion .claude/commands/voxclaw-progress.md
Original file line number Diff line number Diff line change
Expand Up @@ -11,5 +11,5 @@ Use this only when the human explicitly opted into hearing progress while work i
Run this command:

```bash
printf '%s\n' "$ARGUMENTS" | plugins/voxclaw/scripts/voxclaw-say --kind progress
printf '%s\n' "$ARGUMENTS" | plugins/voxclaw/scripts/voxclaw-say
```
2 changes: 1 addition & 1 deletion .claude/commands/voxclaw-summary.md
Original file line number Diff line number Diff line change
Expand Up @@ -11,5 +11,5 @@ Write a 1 to 3 sentence spoken summary that leads with the outcome, then verific
Run this command:

```bash
printf '%s\n' "$ARGUMENTS" | plugins/voxclaw/scripts/voxclaw-say --kind summary
printf '%s\n' "$ARGUMENTS" | plugins/voxclaw/scripts/voxclaw-say
```
2 changes: 1 addition & 1 deletion AGENTS.md
Original file line number Diff line number Diff line change
Expand Up @@ -67,7 +67,7 @@ voxclaw --status # Check if listener is running

## Agent Speech Convention

When finishing a non-trivial task in this repo, write a 1 to 2 sentence spoken summary and send it through `plugins/voxclaw/scripts/voxclaw-say --kind summary`. Lead with the outcome, then verification status, then any blocker. Keep it in plain spoken prose: no code, file paths, or command names unless they matter to the human. Skip it for pure Q&A or read-only exploration. Do not use `--kind progress` unless the human explicitly opted into hearing live progress while work is ongoing.
When finishing a non-trivial task in this repo, write a 1 to 2 sentence spoken summary and send it through `plugins/voxclaw/scripts/voxclaw-say`. Lead with the outcome, then verification status, then any blocker. Keep it in plain spoken prose: no code, file paths, or command names unless they matter to the human. Skip it for pure Q&A or read-only exploration. Do not narrate live progress mid-task unless the human explicitly opted into hearing it.

## Key Conventions

Expand Down
2 changes: 1 addition & 1 deletion CLAUDE.md
Original file line number Diff line number Diff line change
Expand Up @@ -73,7 +73,7 @@ voxclaw --status # Check if listener is running

## Agent Speech Convention

When finishing a non-trivial task in this repo, pipe a 1–2 sentence spoken summary through `plugins/voxclaw/scripts/voxclaw-say --kind summary`. Lead with the outcome, then verification status, then any blocker. Use prose only — no code, file paths, or command names. Skip for pure Q&A or read-only exploration. The app's `agentSpeechMode` setting filters whether it actually speaks, so always emit; let the app decide.
When finishing a non-trivial task in this repo, pipe a 1–2 sentence spoken summary through `plugins/voxclaw/scripts/voxclaw-say`. Lead with the outcome, then verification status, then any blocker. Use prose only — no code, file paths, or command names. Skip for pure Q&A or read-only exploration. If neither the listener nor the `voxclaw` CLI is reachable the script exits non-zero without speaking; that failure is harmless and can be ignored.

## Key Conventions

Expand Down
2 changes: 1 addition & 1 deletion README.md
Original file line number Diff line number Diff line change
Expand Up @@ -47,7 +47,7 @@ A macOS menu bar app + CLI tool that reads text aloud using Apple TTS (default),
- **Three Voice Engines** — Apple (no setup), OpenAI (BYOK), or ElevenLabs (BYOK), with Apple fallback when cloud auth fails
- **Automatic Updates** — In-app updates via Sparkle (notarized + EdDSA-signed); a "Check for Updates…" menu item too
- **Multiple Input Methods** — Arguments, stdin pipe, file, clipboard, URL scheme, and LAN HTTP
- **Network API for Agents** — `POST /read`, `POST /agent-notify`, `POST /ack`, `GET /status`, and `GET /claw`, with request validation and structured status payloads
- **Network API for Agents** — `POST /read`, `POST /ack`, `POST /control`, `GET /status`, and `GET /claw`, with request validation and structured status payloads
- **Multi-Agent Aware** — `project_id` + `agent_id` give each concurrent agent its own voice, and scope "stop reading" (`/ack`) so prompting one agent never cuts off another
- **Cross-Device iCloud Relay** — Speak agent output on your iPhone/iPad even when it's locked, backgrounded, or off your LAN, via a silent CloudKit push that wakes the device (opt-in, same iCloud account on both ends)
- **Bonjour Discovery** — Advertises `_voxclaw._tcp` on LAN for peer/device discovery
Expand Down
67 changes: 11 additions & 56 deletions SKILL.md
Original file line number Diff line number Diff line change
Expand Up @@ -24,18 +24,16 @@ If the human shares a `🦞 VoxClaw setup pointer`, use it directly. It includes
- integration doc (`SKILL.md`)
- machine-specific `Speak URL` (`/read`)
- machine-specific `Health URL` (`/status`)
- machine-specific `Agent Notify URL` (`/agent-notify`)

Prefer those provided URLs over guessed hostnames when both are available.
Never auto-switch to `.local` hostnames. Use numeric LAN IP URLs unless a human explicitly provides a `.local` target.
If `health_url`, `speak_url`, or `agent_notify_url` are present in the pointer, do not ask for LAN IP or run discovery first; call `health_url` immediately, then use the provided URLs.
If `health_url` or `speak_url` are present in the pointer, do not ask for LAN IP or run discovery first; call `health_url` immediately, then use the provided URLs.

Reliable connect order:
1. Confirm on VoxClaw Mac: `curl -sS http://localhost:4140/status`
2. Confirm from agent host: `curl -sS http://<lan-ip>:4140/status`
3. Send direct speech to `<lan-ip>:4140/read`
4. Send final summaries, failures, and opt-in progress updates to `<lan-ip>:4140/agent-notify`
5. If step 1 passes but step 2 fails, treat as network/firewall issue (not app API issue).
3. Send all speech — including final summaries and failures — to `<lan-ip>:4140/read`
4. If step 1 passes but step 2 fails, treat as network/firewall issue (not app API issue).

## API

Expand Down Expand Up @@ -91,39 +89,6 @@ curl -X POST http://<mac-ip>:4140/ack \
The ack stops local playback and is relayed to your LAN peer speakers so it
stops there too. Response: `{"status":"acknowledged"}`.

### Agent Notifications

Use agent notifications for task summaries, failures, and optional live progress updates.

```bash
curl -X POST http://<mac-ip>:4140/agent-notify \
-H 'Content-Type: application/json' \
-d '{"kind":"summary","text":"Task complete. I updated the parser and the focused tests passed."}'
```

**Parameters (JSON body):**

| Field | Type | Required | Description |
|----------------|--------|----------|-------------|
| `kind` | string | yes | `summary`, `progress`, or `failure` |
| `text` | string | yes | Spoken text |
| `source` | string | no | Agent/source label |
| `voice` | string | no | OpenAI voice override |
| `rate` | number | no | Speech rate multiplier |
| `instructions` | string | no | Natural-language speaking style |

Expected response:

```json
{"status":"reading"}
```

or

```json
{"status":"suppressed"}
```

### Check Status

```bash
Expand All @@ -143,21 +108,12 @@ curl http://<mac-ip>:4140/status
"skill_doc": "https://github.com/malpern/VoxClaw/blob/main/SKILL.md",
"discovery": "_voxclaw._tcp",
"speak_url": "http://192.168.1.50:4140/read",
"health_url": "http://192.168.1.50:4140/status",
"agent_notify_url": "http://192.168.1.50:4140/agent-notify",
"agent_speech_mode": "summary",
"agent_speech_verbosity": "brief"
"health_url": "http://192.168.1.50:4140/status"
}
```

States: `idle`, `loading`, `playing`, `paused`, `finished`.

`agent_speech_mode` controls what the app will actually speak:

- `off`: speak nothing
- `summary`: speak final summaries and failures
- `live`: speak summaries, failures, and progress updates

## Setup

The user installs VoxClaw on their Mac:
Expand All @@ -179,9 +135,8 @@ VoxClaw advertises itself via Bonjour as `_voxclaw._tcp` on the local network. A
| Status | Meaning |
|--------|--------------------------------------------|
| 200 | Text accepted, now reading |
| 200 | Agent notification accepted or suppressed |
| 400 | Missing or empty text, or text too long |
| 404 | Unknown endpoint (use `POST /read`, `POST /agent-notify`, `POST /ack`, or `GET /status`) |
| 404 | Unknown endpoint (use `POST /read`, `POST /ack`, `POST /control`, or `GET /status`) |
| 413 | Request body too large (max 1 MB) |

Error responses are JSON: `{"error": "description"}`.
Expand All @@ -193,17 +148,17 @@ Error responses are JSON: `{"error": "description"}`.
**Speak a summary after a task completes:**

```bash
curl -X POST http://192.168.1.50:4140/agent-notify \
curl -X POST http://192.168.1.50:4140/read \
-H 'Content-Type: application/json' \
-d '{"kind":"summary","text":"Task complete. I deployed the new version and all tests passed."}'
-d '{"text":"Task complete. I deployed the new version and all tests passed."}'
```

**Use a specific voice at faster speed:**

```bash
curl -X POST http://192.168.1.50:4140/agent-notify \
curl -X POST http://192.168.1.50:4140/read \
-H 'Content-Type: application/json' \
-d '{"kind":"failure","text":"Heads up, the build failed on CI.","voice":"nova","rate":1.3}'
-d '{"text":"Heads up, the build failed on CI.","voice":"nova","rate":1.3}'
```

**Control speaking style with instructions:**
Expand All @@ -218,7 +173,7 @@ curl -X POST http://192.168.1.50:4140/read \

```bash
curl -s http://192.168.1.50:4140/status | grep -q '"status":"ok"' && \
curl -X POST http://192.168.1.50:4140/agent-notify \
curl -X POST http://192.168.1.50:4140/read \
-H 'Content-Type: application/json' \
-d '{"kind":"summary","text":"Ready to go."}'
-d '{"text":"Ready to go."}'
```
2 changes: 1 addition & 1 deletion Sources/VoxClawCore/Network/NetworkSession.swift
Original file line number Diff line number Diff line change
Expand Up @@ -105,7 +105,7 @@ final class NetworkSession: Sendable {
"binding_count": info.voiceBindingCount,
"protocol": "Pass project_id (recommend cwd) and optional agent_id in POST /read to get a stable auto-assigned voice per engine. Explicit voice field still wins."
] as [String: Any],
"agent_handoff": "🦞 Call health_url first, then POST to speak_url or agent_notify_url. Use these URLs exactly (no hostname/discovery rewrite unless a human explicitly asks). Website: https://voxclaw.com/ Skill: https://github.com/malpern/VoxClaw/blob/main/SKILL.md"
"agent_handoff": "🦞 Call health_url first, then POST to speak_url. Use these URLs exactly (no hostname/discovery rewrite unless a human explicitly asks). Website: https://voxclaw.com/ Skill: https://github.com/malpern/VoxClaw/blob/main/SKILL.md"
]

guard let data = try? JSONSerialization.data(withJSONObject: payload, options: []),
Expand Down
2 changes: 2 additions & 0 deletions Tests/VoxClawCoreTests/NetworkListenerIntegrationTests.swift
Original file line number Diff line number Diff line change
Expand Up @@ -36,6 +36,8 @@ struct NetworkListenerIntegrationTests {
#expect(body.contains("\"auto_closed_instances_on_launch\""))
// Agent guidance should not auto-route to .local hostnames
#expect(!body.contains(".local"))
// /agent-notify was removed; agents must not be pointed at a dead endpoint
#expect(!body.contains("agent_notify"))
}

@Test func readEndpointAcceptsJSON() async throws {
Expand Down
2 changes: 1 addition & 1 deletion docs/presentation.html
Original file line number Diff line number Diff line change
Expand Up @@ -705,7 +705,7 @@ <h3>Three endpoints, three jobs</h3>

<ul>
<li><code>POST /read</code> &mdash; Speak text immediately or queue it. Accepts <code>text</code>, <code>voice</code>, <code>rate</code>, and <code>instructions</code> for speaking style.</li>
<li><code>POST /agent-notify</code> &mdash; Structured notifications with <code>kind</code> (summary, progress, failure) for different treatment.</li>
<li><code>POST /ack</code> &mdash; Stop reading an agent's previous message, scoped by <code>project_id</code> and <code>agent_id</code> so one agent's interrupt doesn't silence another's.</li>
<li><code>GET /status</code> &mdash; Health check that returns the current state: idle, loading, playing, paused, finished. Useful for agents that want to wait their turn.</li>
</ul>

Expand Down
12 changes: 6 additions & 6 deletions plugins/voxclaw/DEMO.md
Original file line number Diff line number Diff line change
Expand Up @@ -19,20 +19,20 @@ plugins/voxclaw/scripts/voxclaw-say "Task complete. Tests passed."
Speak the default final agent summary:

```bash
plugins/voxclaw/scripts/voxclaw-say --kind summary "Task complete. Tests passed."
plugins/voxclaw/scripts/voxclaw-say "Task complete. Tests passed."
```

Speak a failure summary:

```bash
plugins/voxclaw/scripts/voxclaw-say --kind failure "Build failed in the network listener."
plugins/voxclaw/scripts/voxclaw-say "Build failed in the network listener."
```

Pipe a generated summary:

```bash
printf '%s\n' "Build failed. The parser tests are failing after the networking changes." | \
plugins/voxclaw/scripts/voxclaw-say --kind failure
plugins/voxclaw/scripts/voxclaw-say
```

Use a remote VoxClaw listener:
Expand All @@ -48,21 +48,21 @@ plugins/voxclaw/scripts/voxclaw-say \
Use explicit live progress narration only when the user opted in:

```bash
plugins/voxclaw/scripts/voxclaw-say --kind progress "Halfway through the migration."
plugins/voxclaw/scripts/voxclaw-say "Halfway through the migration."
```

## Agent patterns

Use `voxclaw-read-task-summary` when finishing work:

```text
Summarize the completed work in 1 to 3 spoken sentences, then send it through plugins/voxclaw/scripts/voxclaw-say --kind summary.
Summarize the completed work in 1 to 3 spoken sentences, then send it through plugins/voxclaw/scripts/voxclaw-say.
```

Use `voxclaw-read-test-failures` when verification fails:

```text
Condense the failing tests into one short spoken sentence and send it through plugins/voxclaw/scripts/voxclaw-say --kind failure.
Condense the failing tests into one short spoken sentence and send it through plugins/voxclaw/scripts/voxclaw-say.
```

For Claude Code, the same helper can be called from project commands in `.claude/commands/`.
Expand Down
Loading