# https://github.com/Wolfe-Jam/grok-faf-voice Project Manual

Generated at: 2026-07-21 16:58:55 UTC

## Table of Contents

- [Overview & Getting Started](#page-1)
- [Memory System & .fafm Format](#page-2)
- [Voice Agents, Voices & Tools](#page-3)
- [Architecture, Context & Deployment](#page-4)

<a id='page-1'></a>

## Overview & Getting Started

### Related Pages

Related topics: [Memory System & .fafm Format](#page-2), [Voice Agents, Voices & Tools](#page-3), [Architecture, Context & Deployment](#page-4)

<details>
<summary>Related Source Files</summary>

The following source files were used to generate this page:

- [README.md](https://github.com/Wolfe-Jam/grok-faf-voice/blob/main/README.md)
- [ONBOARDING.md](https://github.com/Wolfe-Jam/grok-faf-voice/blob/main/ONBOARDING.md)
- [pyproject.toml](https://github.com/Wolfe-Jam/grok-faf-voice/blob/main/pyproject.toml)
- [examples/hello.py](https://github.com/Wolfe-Jam/grok-faf-voice/blob/main/examples/hello.py)

</details>

# Overview & Getting Started

## What is grok-faf-voice

`grok-faf-voice` is the **voice profile** of the **FAF (Format for AI Facts)** ecosystem — a sibling library to `claude-fafm-sdk`, which serves as the knowledge profile. Together, the two packages share the same `.fafm` file format but expose different surface areas: `grok-faf-voice` focuses on conversational / voice interaction, while `claude-fafm-sdk` focuses on parsed, structural access to the same payloads. Cross-links are now established in the README and `pyproject.toml` so that users landing on either repository can find the other half of the system. Source: [README.md:1-40]()

The project carries the **FAF defines. MD...** manifesto — the .fafm paper is cited via a Zenodo DOI badge (`10.5281/zenodo.20348942`) in the README, providing a permanent, citable reference for the underlying format specification. Source: [README.md:10-20]()

## Release Status

The current published version is **v0.3.2**. Earlier 0.3.x PyPI releases carry two important capability milestones:

| Version | Capability |
|---------|-----------|
| 0.3.0 | Local souls / cross-vendor read |
| 0.3.1 | Parsed accessors |
| 0.3.2 | Sibling cross-link (current) |

Prior to the 0.3.x line, PyPI was last at `0.2.2`. Source: [README.md:25-35]()

## Quick Start

### Installation

Install the package from PyPI:

```bash
pip install grok-faf-voice
```

Dependencies and entry points are declared in `pyproject.toml`. The `grok-faf-voice` distribution depends on the shared `.fafm` format and is configured so that users of `claude-fafm-sdk` can be smoothly redirected (and vice versa) through the cross-link metadata. Source: [pyproject.toml:1-50]()

### Hello Voice

A minimal entry point lives at `examples/hello.py`. The example demonstrates the canonical "open a .fafm payload, speak through it" loop using the public API. Source: [examples/hello.py:1-30](). Run it directly to verify your environment:

```bash
python examples/hello.py
```

### Onboarding Path

New contributors should follow `ONBOARDING.md`, which walks through the repository layout, the role of each submodule, and the local-dev workflow. The file aligns with the README's quickstart but adds contributor-specific guidance (branching, linting, release tagging). Source: [ONBOARDING.md:1-60]()

## How the Two Profiles Fit Together

The voice and knowledge profiles share storage but differ in access patterns. The voice profile is tuned for low-latency, turn-based interaction; the knowledge profile is tuned for structured, programmatic retrieval. Both read the same `.fafm` artifacts, and v0.3.0's "cross-vendor read" milestone ensures a payload produced by one profile can be opened by the other without translation. Source: [README.md:40-55]()

## Project Layout

At a glance, the repository is organized for first-time contributors:

- `README.md` — entry point, Zenodo citation, PyPI badge, sibling cross-link.
- `ONBOARDING.md` — contributor onboarding and dev workflow.
- `pyproject.toml` — packaging metadata, dependency pins, sibling-package reference.
- `examples/hello.py` — minimal runnable script that exercises the public voice surface.

Source: [README.md:1-40](), Source: [ONBOARDING.md:1-30](), Source: [pyproject.toml:1-20](), Source: [examples/hello.py:1-15]().

## Next Steps

1. Read the README to confirm the version matches what you intend to consume (current: v0.3.2).
2. If you also need parsed/structural access, install `claude-fafm-sdk` — the sibling cross-link in `pyproject.toml` will keep the two installed side by side without conflict.
3. Walk through `ONBOARDING.md` if you plan to contribute.
4. Run `examples/hello.py` as a smoke test before integrating `grok-faf-voice` into your own application.

Source: [README.md:50-70](), Source: [ONBOARDING.md:30-60]()

For deeper topics — parsed accessors, local souls, and cross-vendor read semantics — consult the dedicated wiki pages that follow this overview.

---

<a id='page-2'></a>

## Memory System & .fafm Format

### Related Pages

Related topics: [Overview & Getting Started](#page-1), [Voice Agents, Voices & Tools](#page-3), [Architecture, Context & Deployment](#page-4)

<details>
<summary>Related Source Files</summary>

The following source files were used to generate this page:

- [grok_faf_voice/memory.py](https://github.com/Wolfe-Jam/grok-faf-voice/blob/main/grok_faf_voice/memory.py)
- [grok_faf_voice/__init__.py](https://github.com/Wolfe-Jam/grok-faf-voice/blob/main/grok_faf_voice/__init__.py)
- [examples/hello_grok_with_memory.py](https://github.com/Wolfe-Jam/grok-faf-voice/blob/main/examples/hello_grok_with_memory.py)
- [README.md](https://github.com/Wolfe-Jam/grok-faf-voice/blob/main/README.md)
- [CHANGELOG.md](https://github.com/Wolfe-Jam/grok-faf-voice/blob/main/CHANGELOG.md)
- [pyproject.toml](https://github.com/Wolfe-Jam/grok-faf-voice/blob/main/pyproject.toml)
- [CITATION.cff](https://github.com/Wolfe-Jam/grok-faf-voice/blob/main/CITATION.cff)
</details>

# Memory System & .fafm Format

The Memory System in `grok-faf-voice` is the persistence layer that gives voice interactions continuity across sessions. It is built around a single file format — the `.fafm` (FAF Memory) — that captures a "soul" of context the voice client reloads on startup and merges with new conversations. The implementation is intentionally vendor-agnostic: the same `.fafm` file is readable by `grok-faf-voice` (the voice profile) and `claude-fafm-sdk` (the knowledge profile) as of v0.3.2. Source: [CHANGELOG.md:1-15]()

## Purpose and Scope

The Memory System solves a specific problem in conversational AI: without persistence, a voice agent has no recollection of prior sessions, user preferences, or project context. The `.fafm` format provides a portable, human-readable container that:

- Stores structured metadata (project identity, version, timestamps, attributes)
- Carries parsed accessors introduced in v0.3.1 for typed property access
- Supports local "souls" and cross-vendor reads added in v0.3.0
- Cross-links between the voice and knowledge profiles

Source: [CHANGELOG.md:1-10](), [pyproject.toml:1-30]()

## Core Module: `memory.py`

The `grok_faf_voice/memory.py` module is the entry point for all memory operations. It exposes the public API consumed by `__init__.py` and the example scripts. Key responsibilities include:

- Loading `.fafm` files from disk on initialization
- Serializing in-memory state back to the file system
- Providing parsed accessor methods for typed reads of common attributes
- Emitting the canonical format expected by sibling projects

The module is re-exported through the package root so consumers import it as part of the public surface. Source: [grok_faf_voice/__init__.py:1-20]()

## The .fafm File Format

The `.fafm` format is the on-disk representation of a memory "soul." It is designed to be:

- **Human-readable** — easy to inspect and edit
- **Vendor-neutral** — consumable across the grok and claude profiles
- **Versioned** — carries a version field so readers can migrate safely
- **Citeable** — backed by a Zenodo DOI (10.5281/zenodo.20348942) per the `CITATION.cff` entry

The format and its theoretical grounding are documented in a separately published paper; the repository cites it for users wanting deeper context. Source: [CITATION.cff:1-20]()

## Usage Pattern

The canonical workflow is demonstrated in `examples/hello_grok_with_memory.py`, which shows how a voice session:

1. Instantiates the memory loader with a path to an existing or new `.fafm` file
2. Reads prior context via parsed accessors
3. Sends a request to the Grok voice endpoint with the loaded context attached
4. Writes any new state back to the `.fafm` file on completion

This pattern keeps the agent stateless at the network layer while maintaining continuity at the file layer. Source: [examples/hello_grok_with_memory.py:1-40]()

## Version History and Cross-Profile Compatibility

The Memory System has evolved through three releases that matter for users:

| Version | Memory Capability |
|---------|-------------------|
| 0.3.0 | Local souls and cross-vendor read of `.fafm` |
| 0.3.1 | Parsed accessors for typed property reads |
| 0.3.2 | Cross-link to `claude-fafm-sdk` knowledge profile |

The first PyPI release in the 0.3.x line supersedes the previous 0.2.2 on the registry. Source: [CHANGELOG.md:1-15](), [pyproject.toml:1-40]()

## Data Flow Summary

```mermaid
flowchart LR
  A[User voice input] --> B[grok-faf-voice client]
  B --> C[memory.py loader]
  C --> D[(.fafm file on disk)]
  D --> C
  C --> B
  B --> E[Grok voice API]
  E --> B
  B --> F[.fafm writer]
  F --> D
```

The flow makes clear that the `.fafm` file is the single source of truth, read at session start and updated at session end. Source: [grok_faf_voice/memory.py:1-30](), [examples/hello_grok_with_memory.py:1-40]()

## Limitations and Notes

- The Memory System is local-first; there is no built-in remote sync layer.
- Version migration is the consumer's responsibility; the format version field should be checked before writes.
- Cross-vendor reads require the target profile to be installed or its parser available; `.fafm` alone is necessary but not always sufficient for full round-trips.

Source: [CHANGELOG.md:1-15](), [README.md:1-40]()

---

<a id='page-3'></a>

## Voice Agents, Voices & Tools

### Related Pages

Related topics: [Overview & Getting Started](#page-1), [Memory System & .fafm Format](#page-2), [Architecture, Context & Deployment](#page-4)

<details>
<summary>Related Source Files</summary>

The following source files were used to generate this page:

- [grok_faf_voice/agent.py](https://github.com/Wolfe-Jam/grok-faf-voice/blob/main/grok_faf_voice/agent.py)
- [grok_faf_voice/custom_voices.py](https://github.com/Wolfe-Jam/grok-faf-voice/blob/main/grok_faf_voice/custom_voices.py)
- [grok_faf_voice/scratchpad.py](https://github.com/Wolfe-Jam/grok-faf-voice/blob/main/grok_faf_voice/scratchpad.py)
- [grok_faf_voice/tools.py](https://github.com/Wolfe-Jam/grok-faf-voice/blob/main/grok_faf_voice/tools.py)
- [grok_faf_voice/utils/transcribe.py](https://github.com/Wolfe-Jam/grok-faf-voice/blob/main/grok_faf_voice/utils/transcribe.py)
- [examples/hello_custom_voice.py](https://github.com/Wolfe-Jam/grok-faf-voice/blob/main/examples/hello_custom_voice.py)
</details>

# Voice Agents, Voices & Tools

## Purpose and Scope

`grok-faf-voice` exposes a voice-first agent runtime on top of the `.fafm` format. The "Voice Agents, Voices & Tools" subsystem covers three tightly coupled concerns:

- **Voice Agents** — the `VoiceAgent` runtime that binds a voice, a transcript, and an optional tool set into a single turn-based conversation loop.
- **Voices** — preset personas shipped with the package plus user-defined custom voices persisted as `.fafm` files.
- **Tools** — first-class callable functions that the agent can invoke mid-turn, with their schemas generated automatically from type annotations.

The subsystem's role is to make voice interaction composable: a developer declares *who* speaks (voice), *what* they know (the `.fafm` body and scratchpad), and *what* they can do (tools); the agent wires those declarations into an executable loop `Source: [grok_faf_voice/agent.py:1-40]()`. As of the v0.3.2 release, this voice profile cross-links with `claude-fafm-sdk` (the knowledge profile) so the same `.fafm` document can be addressed from either side.

## Voice Agents

`VoiceAgent` is the entry point. Constructing one requires a voice identifier, an audio path (WAV) or live recording, and an optional tool list. The agent:

1. Transcribes the supplied audio via `transcribe_audio` `Source: [grok_faf_voice/agent.py:55-72]()`.
2. Looks up the matching voice definition (built-in or custom).
3. Loads any persisted scratchpad state attached to the voice.
4. Composes a prompt that mixes the voice's persona, scratchpad context, transcript, and tool schemas.
5. Streams a reply, optionally emitting tool calls and incorporating their results before the next user turn.

Agents are stateless across processes; all durable memory lives in the voice's `.fafm` file or its associated scratchpad `Source: [grok_faf_voice/scratchpad.py:1-30]()`. This means a `VoiceAgent` can be reconstructed on any machine that has the file, which is the property the cross-vendor read support (added in 0.3.0) relies on.

## Voices

Voices are persona records. Built-in voices live in `custom_voices.py` alongside user-extensible presets `Source: [grok_faf_voice/custom_voices.py:1-40]()`. A voice record carries:

- A stable `name` and `slug` used for lookup.
- A `persona` block (tone, vocabulary, sample phrasing).
- A `scratchpad` reference pointing at the running state file.
- Zero or more declared `tools`.

Custom voices are typically created with the `hello_custom_voice.py` example, which demonstrates registering a new voice and verifying the registration round-trips through the `.fafm` parser `Source: [examples/hello_custom_voice.py:1-30]()`.

### Voice lookup workflow

```mermaid
flowchart LR
    A[User audio] --> B[transcribe_audio]
    B --> C{Voice specified?}
    C -- yes --> D[Load voice record]
    C -- no --> E[Default voice]
    D --> F[Load scratchpad]
    E --> F
    F --> G[Compose prompt + tools]
    G --> H[Agent reply]
```

The diagram shows the path from raw audio to a reply; transcript, voice record, and scratchpad are the three inputs that must succeed before the model is invoked `Source: [grok_faf_voice/utils/transcribe.py:1-25]()`.

## Tools

Tools are registered as plain Python callables. The `tools` module inspects each function's signature and type hints to derive a JSON schema the model can call against `Source: [grok_faf_voice/tools.py:1-50]()`. A tool has three parts:

| Part | Source | Purpose |
|---|---|---|
| Function body | User code | Side-effecting action (HTTP call, file write, lookup). |
| Type-annotated signature | Function def | Auto-converted to JSON schema for the model. |
| Optional docstring | Function def | Used as the tool's natural-language description. |

When the model emits a tool call, the agent executes it, captures the return value, and feeds it back into the next model turn before finalizing the spoken reply `Source: [grok_faf_voice/agent.py:72-110]()`. Tool execution is synchronous within a single turn; long-running tools should return intermediate state rather than blocking the loop.

## Scratchpad and Cross-Profile Continuity

The scratchpad (`scratchpad.py`) is the bridge between voice and knowledge. It stores short-term conversational state (open questions, partial results) so a voice agent can resume a thread without re-reading the entire `.fafm` body `Source: [grok_faf_voice/scratchpad.py:30-70]()`. Combined with the parsed accessors introduced in 0.3.1, a voice agent and a `claude-fafm-sdk` knowledge agent can share the same file and inspect each other's scratchpad entries through the standard accessor API.

## Typical Usage Pattern

1. Define or pick a voice from `custom_voices.py`.
2. Record or supply a WAV file.
3. Instantiate `VoiceAgent(voice=slug, audio=path, tools=[fn1, fn2])`.
4. Iterate: each call transcribes, prompts, optionally invokes tools, and returns audio + text `Source: [examples/hello_custom_voice.py:20-40]()`.

This pattern is intentionally small: the heavy lifting lives in the `.fafm` format, so users write little glue code and the agent's behavior remains portable across vendors.

---

<a id='page-4'></a>

## Architecture, Context & Deployment

### Related Pages

Related topics: [Overview & Getting Started](#page-1), [Memory System & .fafm Format](#page-2), [Voice Agents, Voices & Tools](#page-3)

<details>
<summary>Related Source Files</summary>

The following source files were used to generate this page:

- [grok_faf_voice/context.py](https://github.com/Wolfe-Jam/grok-faf-voice/blob/main/grok_faf_voice/context.py)
- [grok_faf_voice/context_bus.py](https://github.com/Wolfe-Jam/grok-faf-voice/blob/main/grok_faf_voice/context_bus.py)
- [grok_faf_voice/ledger.py](https://github.com/Wolfe-Jam/grok-faf-voice/blob/main/grok_faf_voice/ledger.py)
- [grok_faf_voice/_merge_models.py](https://github.com/Wolfe-Jam/grok-faf-voice/blob/main/grok_faf_voice/_merge_models.py)
- [Dockerfile](https://github.com/Wolfe-Jam/grok-faf-voice/blob/main/Dockerfile)
- [deploy_to_livekit.sh](https://github.com/Wolfe-Jam/grok-faf-voice/blob/main/deploy_to_livekit.sh)
</details>

# Architecture, Context & Deployment

## Overview

The `grok-faf-voice` package implements the **voice profile** of the `.fafm` (Format-Aware Format) specification, paired with its sibling knowledge profile [`claude-fafm-sdk`](https://github.com/Wolfe-Jam/claude-fafm-sdk). At v0.3.2, the two profiles cross-link in `README.md` and `pyproject.toml`, sharing a single canonical format where "FAF defines. MD..." captures machine-readable project truth.

The runtime is built around three concerns: a **`Context`** object that holds `.fafm` state in memory, a **`ContextBus`** that routes mutations across producers and consumers, and a **`Ledger`** that records an immutable trail of every change. Deployment is containerized via `Dockerfile` and shipped to LiveKit through `deploy_to_livekit.sh`, while `_merge_models.py` reconciles cross-vendor writes introduced in v0.3.0.

## Runtime Architecture

The voice agent runs as a stateless LiveKit worker that hydrates `.fafm` content into a live `Context`, mediates updates through a `ContextBus`, and persists every change to a `Ledger`. The bus decouples producers (voice transcripts, user commands, cross-vendor imports) from consumers (the TTS loop, the knowledge profile, the on-disk `.fafm`). This separation is what allows a real-time audio path to share state with a slower knowledge profile without blocking either side. Source: [grok_faf_voice/context.py:1-120]().

`context.py` owns the canonical `Context` type — the in-memory representation of a parsed `.fafm` document. The parsed accessors added in v0.3.1 expose typed properties so callers do not re-parse the frontmatter on every read; the v0.2.x path forced a full YAML parse on each access, which was unacceptable inside a TTS frame loop. Source: [grok_faf_voice/context.py:40-120]().

`context_bus.py` provides the publish/subscribe surface. Subscribers register handlers keyed on topic, and the bus guarantees at-least-once delivery into the ledger hook before fan-out. A failing subscriber cannot block the bus — handlers run in isolation, and a crash mid-delivery still leaves an audit entry. Source: [grok_faf_voice/context_bus.py:1-90]().

`ledger.py` is append-only. Each bus event is hashed and chained so any later tampering is detectable. This satisfies the "FAF defines" promise: the format on disk is the source of truth, and the runtime cannot silently rewrite history. Source: [grok_faf_voice/ledger.py:1-150]().

## Cross-Vendor Merge Layer

`_merge_models.py` is the private adapter layer introduced for v0.3.0's cross-vendor read. When a Grok voice session ingests a `.fafm` originally authored by a Claude knowledge session (or vice versa), the merge models reconcile field shapes, namespace collisions, and version drift before the merged result enters the bus. The underscore prefix marks the module as internal: callers depend on the public `Context` API, not on these Pydantic models directly. This layer is what enables the v0.3.2 cross-link — both profiles can read and write the same `.fafm` without agreeing on a single author. Source: [grok_faf_voice/_merge_models.py:1-200]().

## Deployment Pipeline

```mermaid
flowchart LR
    A[Source .fafm on disk] --> B[Context hydration]
    B --> C[ContextBus]
    C --> D[Ledger append]
    D --> E[Voice / TTS loop]
    C --> F[claude-fafm-sdk<br/>knowledge profile]
    G[Dockerfile] --> H[Container image]
    H --> I[deploy_to_livekit.sh]
    I --> J[LiveKit worker pool]
    J --> E
```

The `Dockerfile` builds a slim Python image, installs the package from PyPI (currently 0.3.x), and copies a default `.fafm` seed. It exposes no HTTP port by default — the container is a LiveKit worker, not a web service. The slim base keeps cold-start time compatible with LiveKit's auto-scaling worker pool. Source: [Dockerfile:1-60]().

`deploy_to_livekit.sh` is the operator entry point. It tags the image, pushes to the registry configured for the LiveKit deployment, and triggers a worker rollout. The script is intentionally short so it can be re-run on every release; the v0.3.0 → v0.3.1 → v0.3.2 sequence each shipped through this same path without modification. Source: [deploy_to_livekit.sh:1-80]().

## Versioning & External Anchors

- **PyPI**: the package graduated from 0.2.2 to the 0.3.x line starting with v0.3.0 (local souls / cross-vendor read) and v0.3.1 (parsed accessors). The voice profile and the knowledge profile now share one `.fafm` schema. Source: [pyproject.toml]() (referenced via README cross-link).
- **Zenodo**: the `.fafm` format paper is cited via DOI `10.5281/zenodo.20348942`, giving the architecture a stable external reference independent of any single release tag.
- **Sibling project**: [`claude-fafm-sdk`](https://github.com/Wolfe-Jam/claude-fafm-sdk) implements the knowledge profile; the bus is the contract that lets the two stay in sync without sharing a process.

## Operational Notes

- **Statelessness**: every worker rehydrates context from `.fafm` on boot; the ledger is what carries state across restarts. Source: [grok_faf_voice/ledger.py:1-150]().
- **Failure isolation**: a failing subscriber cannot block the bus; ledger append happens before fan-out so a crash mid-delivery leaves an audit trail. Source: [grok_faf_voice/context_bus.py:1-90]().
- **Upgrade path**: rolling from 0.2.2 to 0.3.x requires re-parsing legacy `.fafm` files through the new accessors; the merge layer backfills any missing fields during that pass. Source: [grok_faf_voice/_merge_models.py:1-200]().

---

<!-- evidence_pipeline_checked: true -->
<!-- evidence_injected: true -->

---

## Pitfall Log

Project: Wolfe-Jam/grok-faf-voice

Summary: Found 7 structured pitfall item(s), including 0 high/blocking item(s). Top priority: Configuration risk - Configuration risk requires verification.

## 1. Configuration risk - Configuration risk requires verification

- Severity: medium
- Evidence strength: source_linked
- Finding: Project evidence flags a configuration risk. Review the linked source before relying on this workflow.
- User impact: May increase setup, validation, or first-run risk for the user.
- Evidence: capability.host_targets | https://github.com/Wolfe-Jam/grok-faf-voice

## 2. Capability evidence risk - Capability evidence risk requires verification

- Severity: medium
- Evidence strength: source_linked
- Finding: README/documentation is current enough for a first validation pass.
- User impact: May increase setup, validation, or first-run risk for the user.
- Evidence: capability.assumptions | https://github.com/Wolfe-Jam/grok-faf-voice

## 3. Maintenance risk - Maintenance risk requires verification

- Severity: medium
- Evidence strength: source_linked
- Finding: Project evidence flags a maintenance risk. Review the linked source before relying on this workflow.
- User impact: May increase setup, validation, or first-run risk for the user.
- Evidence: evidence.maintainer_signals | https://github.com/Wolfe-Jam/grok-faf-voice

## 4. Security or permission risk - Security or permission risk requires verification

- Severity: medium
- Evidence strength: source_linked
- Finding: no_demo
- User impact: May increase setup, validation, or first-run risk for the user.
- Evidence: downstream_validation.risk_items | https://github.com/Wolfe-Jam/grok-faf-voice

## 5. Security or permission risk - Security or permission risk requires verification

- Severity: medium
- Evidence strength: source_linked
- Finding: no_demo
- User impact: May increase setup, validation, or first-run risk for the user.
- Evidence: risks.scoring_risks | https://github.com/Wolfe-Jam/grok-faf-voice

## 6. Maintenance risk - Maintenance risk requires verification

- Severity: low
- Evidence strength: source_linked
- Finding: issue_or_pr_quality=unknown。
- User impact: May increase setup, validation, or first-run risk for the user.
- Evidence: evidence.maintainer_signals | https://github.com/Wolfe-Jam/grok-faf-voice

## 7. Maintenance risk - Maintenance risk requires verification

- Severity: low
- Evidence strength: source_linked
- Finding: release_recency=unknown。
- User impact: May increase setup, validation, or first-run risk for the user.
- Evidence: evidence.maintainer_signals | https://github.com/Wolfe-Jam/grok-faf-voice

<!-- canonical_name: Wolfe-Jam/grok-faf-voice; human_manual_source: deepwiki_human_wiki -->
