diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index 9574103a..161e6542 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -3,6 +3,7 @@ name: CI on: pull_request: branches: [main] + types: [opened, reopened, ready_for_review] push: # Least privilege: CI only needs to read the repo. Actions are pinned to commit diff --git a/CLAUDE.md b/CLAUDE.md index 0756f0a1..5a9d3558 100644 --- a/CLAUDE.md +++ b/CLAUDE.md @@ -62,7 +62,7 @@ Each file in `aai_cli/commands/` is a Typer sub-app (`transcribe`, `stream`, `tr - **`agent/`** — full-duplex voice agent (mic in, TTS out via `voices.py`). - **`code_gen/`** — backs `--show-code` on `transcribe`/`stream`/`agent`: builds a ready-to-run Python SDK script from exactly the flags passed (no API key needed; generated code reads `ASSEMBLYAI_API_KEY`). - **`auth/`** — browser-assisted `aai login` via AMS + **Stytch B2B OAuth discovery** (`discovery.py`, `flow.py`, `loopback.py`, `ams.py`). Not Stytch Connected Apps. -- **`init/`** — scaffolds a self-contained FastAPI + HTML starter (`transcribe`/`stream`/`agent` templates), optionally installs deps and opens the browser; writes the key to a git-ignored `.env`. +- **`init/`** — scaffolds a self-contained FastAPI + HTML starter (`audio-transcription`/`live-captions`/`voice-agent` templates), optionally installs deps and opens the browser; writes the key to a git-ignored `.env`. - **`commands/claude.py`** — `aai claude install/status/remove` shells out to `claude mcp add` (the `assemblyai-docs` MCP) and `npx skills add` (the AssemblyAI skill). Missing `claude`/`npx` is reported and skipped, not an error. ## Conventions diff --git a/README.md b/README.md index 70f255fc..7981bf12 100644 --- a/README.md +++ b/README.md @@ -31,8 +31,8 @@ aai transcribe --sample # transcribe the hosted wildfires.mp3 sample ## Scaffold a starter app ```sh -aai init # pick a template, scaffold it, install deps, open the browser -aai init transcribe myapp # non-interactive: template + directory +aai init # pick a template, scaffold it, install deps, open the browser +aai init audio-transcription myapp # non-interactive: template + directory ``` `aai init` copies a small, self-contained FastAPI + HTML project you can run locally @@ -183,6 +183,8 @@ aai stream path/to/audio.wav # 16 kHz mono WAV streams directly aai stream path/to/audio.mp3 # other formats need ffmpeg on PATH aai stream https://…/clip.mp3 # a URL works too (decoded via ffmpeg) aai stream # from the microphone; Ctrl-C to stop +aai stream --system-audio # macOS: system/app audio + mic as separate sessions +aai stream --system-audio-only # macOS: system/app audio without the mic ``` `aai stream` exposes the full `StreamingParameters` surface as curated flags: @@ -208,6 +210,14 @@ aai stream --sample \ --config vad_threshold=0.7 ``` +On macOS, `--system-audio` uses ScreenCaptureKit to capture system/app audio +without a loopback driver and streams it in a separate Streaming session from +the microphone. The default terminal UI labels finalized turns as `You:` or +`System:`. The first run may ask for Screen & System Audio Recording and +Microphone permissions. The helper does not record screen frames, but macOS +still uses that combined permission label for native system audio capture. +`--system-audio-only` skips the microphone. + ## Live transcript → live LLM `aai stream --llm "PROMPT"` runs a prompt over the live transcript through LLM Gateway, diff --git a/aai_cli/commands/init.py b/aai_cli/commands/init.py index a6dff8cb..b1f0c726 100644 --- a/aai_cli/commands/init.py +++ b/aai_cli/commands/init.py @@ -56,7 +56,7 @@ def _resolve_dir(directory: str | None, template: str, *, here: bool) -> Path: return Path.cwd() if directory: return Path(directory) - return Path.cwd() / f"{template}-app" + return Path.cwd() / template @app.command( @@ -64,8 +64,11 @@ def _resolve_dir(directory: str | None, template: str, *, here: bool) -> Path: epilog=examples_epilog( [ ("Scaffold a new app interactively", "aai init"), - ("Scaffold a transcribe app into ./my-app", "aai init transcribe my-app"), - ("Scaffold into the current directory", "aai init transcribe --here"), + ( + "Scaffold an audio transcription app into ./my-app", + "aai init audio-transcription my-app", + ), + ("Scaffold into the current directory", "aai init audio-transcription --here"), ] ), ) @@ -74,9 +77,7 @@ def init( template: str | None = typer.Argument( None, help="Template to scaffold (omit to pick interactively)." ), - directory: str | None = typer.Argument( - None, help="Target directory (default: