docs: reposition around team-coordination, sync specs to code, prune stale docs

Reframe README around the real bottleneck (human coordination, not
engineering ability) with the "five-minute meeting" cost story; rewrite the
demo script to match. Update gemini/livekit/mongodb/digitalocean specs to
reflect shipped code (Gemini Live agent, TTS, embeddings, Lyria via
Interactions API; current API routes; hermes_jobs collections). Add hermes.md.
Rename graph.md -> cont_learning.md. Remove outdated/dead docs (agent-learning
scaffolding, graph-discovery, handoffs, superpowers, idea/plan/demo-setup) and
the bundled LiveKit starter under examples/. Rewire CLAUDE.md doc-first gate
off the deleted PLAN.md.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01LuV8W8oNYRsDWKoqK8Mkqc
This commit is contained in:
Ramis
2026-06-28 06:40:16 -07:00
parent 6f01571edb
commit 12dbf69431
116 changed files with 620 additions and 20796 deletions
+77 -97
View File
@@ -1,138 +1,118 @@
# Gemini Integration Spec
PodMan uses Gemini for two distinct jobs: **vision** (understanding screens) and **voice** (urgent voice cues).
Status: active / matches code.
PodMan uses Gemini for five jobs, all through the `@google/genai` SDK
(`GoogleGenAI`) with a single `GEMINI_API_KEY` (`GOOGLE_API_KEY` /
`GOOGLE_GENERATIVE_AI_API_KEY` also accepted):
1. **Vision** — turn screen frames into structured work context.
2. **Embeddings** — vector recall over past coordination events.
3. **TTS voice** — spoken urgent escalations over LiveKit.
4. **Live conversation** — a real-time voice agent teammates talk to.
5. **GenMedia (Lyria)** — a per-pod background score.
Collision detection and intervention text are **deterministic in code**, not
Gemini calls. PodMan does not ask Gemini "is this a conflict?" — that is decided
by `backend/src/collision/detector.ts` from fused vision + git truth. This is a
deliberate reliability choice for the live demo.
---
## 1. Vision — Screen Understanding
## 1. Vision — screen understanding
**Model:** `gemini-2.0-flash` (fast, cheap, strong multimodal)
**Model:** `GEMINI_VISION_MODEL` (default `gemini-2.0-flash`)
**Code:** `backend/src/vision/gemini.ts``analyzeFrame()`
**Trigger:** every 30s per active engineer, when Hermes receives a `POST /ingest` frame
**Trigger:** the LiveKit agent samples a JPEG frame from each engineer's
screen-share track (not an HTTP upload — frames arrive over LiveKit).
**Input:** base64-encoded JPEG, max 1280×720, ~5080KB after compression
**Input:** a single base64 JPEG, sampled at low media resolution.
**Prompt:**
```
You are analyzing a software engineer's screen during a coding session.
Extract the following JSON. If you cannot determine a field with confidence above 0.7, set it to null.
**Output:** structured JSON via `responseJsonSchema` (no markdown parsing):
```ts
{
"currentFile": "string | null", // active file visible in editor tab or title bar
"inferredTask": "string | null", // 1 sentence: what the engineer appears to be doing
"terminalVisible": true | false, // is a terminal or CLI panel visible
"recentTerminalOutput": "string | null", // last meaningful line of terminal output if visible
"confidence": 0.01.0 // your overall confidence in this extraction
currentFile: string, // open file path, e.g. src/auth/session.ts
currentSymbol: string, // function/class under the cursor
activity: string, // editing | reading | debugging | terminal | PR review
hasUnpushedChanges: boolean, // dirty git gutter / modified markers visible
confidence: number // 0..1
}
Respond with valid JSON only. No explanation. No markdown.
```
**Confidence gate:** if `confidence < 0.6`, Hermes discards the frame — no state update, no event detection triggered.
**Latency/cost levers (in code):**
**Rate limit:** 1 call per engineer per 30s. With 3 engineers = 6 calls/min ≈ $0.002/min at Flash pricing.
- `thinkingConfig: { thinkingBudget: 0 }` — minimal thinking for the ambient loop.
- `mediaResolution: MEDIA_RESOLUTION_LOW` — smaller image tokens.
- Missing `confidence` defaults to `0.5`.
**Demo setup requirement:** editors must have large font (18pt+), single window, file name clearly visible in tab. This is the primary reliability lever.
**Demo reliability:** large editor font, single window, visible file tab. This is
the primary lever for clean reads.
---
## 2. Event Detection — Coordination Awareness
## 2. Embeddings — semantic recall
**Model:** `gemini-2.0-flash` (text only, fast)
**Model:** `GEMINI_EMBEDDING_MODEL` (default `gemini-embedding-001`, 768 dims)
**Code:** `backend/src/memory/vectors.ts`
**Trigger:** after every successful state write to MongoDB, Hermes runs event detection over all active engineer contexts.
Each collision is embedded into a short memory text (`file`, `symbol`,
`engineers`, `severity`, unpushed flag) and stored on the `collisions` document.
On a new collision PodMan embeds the query and runs MongoDB Atlas `$vectorSearch`
(index `collision_embedding`) to recall similar past events and their outcomes.
**Input:** JSON snapshot of all engineers' current states + ownership map
**Prompt:**
```
You are a team coordination agent. Below is the current state of each engineer on the team.
Engineer states:
{{engineerStates}}
Ownership map (who owns which files):
{{ownershipMap}}
Detect if any of these coordination events are occurring:
- DEPENDENCY_READY: an engineer who was blocked or waiting now has what they need because another engineer completed relevant work
- BLOCKER_DETECTED: an engineer appears stuck (same file, error in terminal, no progress) and another teammate could help
- DUPLICATE_WORK: two or more engineers are working on the same file simultaneously
If an event is detected, respond with:
{
"event": "DEPENDENCY_READY" | "BLOCKER_DETECTED" | "DUPLICATE_WORK" | null,
"involvedEngineers": ["engineerId", ...],
"file": "string | null",
"reason": "1 sentence explanation"
}
If no event, respond with { "event": null }.
Respond with valid JSON only.
```
**Provider order:** Voyage (`VOYAGE_API_KEY`, `voyage-4-lite`) is tried first when
present; Gemini embeddings are the fallback. Without either, recall degrades to
exact signature/file matching — the demo still works.
---
## 3. Intervention Text Generation
## 3. TTS voice — urgent escalation over LiveKit
**Model:** `gemini-2.0-flash` (text only)
**Model:** `GEMINI_LIVE_MODEL` (default `gemini-3.1-flash-tts-preview`)
**Default voice:** `GEMINI_TTS_VOICE` (default `Charon`)
**Code:** `backend/src/voice/live.ts``speak()` / `speakInRoom()`
**Trigger:** when event detection returns a non-null event
**Input:** event type + engineer names + file + reason
**Prompt:**
```
You are PodMan, a friendly AI teammate. Generate a short spoken message (12 sentences max) to notify the team about this coordination event.
Event: {{eventType}}
Engineers involved: {{engineerNames}}
File: {{file}}
Context: {{reason}}
Rules:
- Use first names only
- Be direct and specific
- Do not use filler words
- Sound natural when spoken aloud
- Do not start with "Hey" or "Attention"
Respond with the message text only.
```
**Example output:**
> "Carol — Alice just got the auth endpoint running. You're clear to integrate."
Flow: a short, natural voice line is generated for a critical collision, returned
as audio, and published as a LiveKit microphone-source audio track. The track is
held for the audio duration plus tail/hold so browsers do not cut playout short.
Browser audio must be unlocked by a user gesture first. The frontend always
renders the `VOICE_CUE` text as a fallback. See `docs/livekit.md` for delivery.
---
## 4. Voice Output — Gemini TTS via LiveKit
## 4. Live conversation — real-time voice agent
**Model:** `gemini-3.1-flash-tts-preview`
**Default voice:** `Charon`
**Model:** `GEMINI_CONVERSATION_MODEL` (default `gemini-3.1-flash-live-preview`)
**Code:** `agents/podman-live-conversation/agent.py` (Python LiveKit Agents,
`google.realtime.RealtimeModel`)
**Integration:** Hermes asks Gemini TTS for short PCM audio, then publishes that audio into the room as a short LiveKit audio track. The code still preserves a Gemini Live path for future available Live models.
A teammate can start a live, streaming speech-to-speech session with PodMan. The
agent answers using **function tools** rather than guessing, including:
**Flow:**
- `get_active_pod_context`, `get_recent_changes`, `search_team_memory`
- `search_repo`, `repo_recent_commits`, `repo_find_commits` (repo + git history)
- `record_conversation_note`
- `delegate_to_hermes`, `abort_active_hermes_job` (hands work to the async Hermes
job runner — see `docs/hermes.md`)
1. Intervention message text generated (step 3)
2. Hermes wraps it in a natural-speaking prompt for Gemini TTS
3. Gemini returns audio with the configured prebuilt voice
4. Hermes publishes the audio into the LiveKit room
5. The frontend still renders the `VOICE_CUE` text, but browser TTS is off unless explicitly enabled
Started/stopped via `POST /api/pods/:id/live-conversation/start` and `.../stop`.
**Why Gemini TTS first:**
---
- Natural voice quality is better than browser `speechSynthesis`
- Tone and pacing can be steered directly in the prompt
- The voice name is configurable with `GEMINI_TTS_VOICE`
- LiveKit remains the delivery layer, so teammates hear the same room audio
## 5. GenMedia — Lyria background score
**Model:** `lyria-3-clip-preview` (override with `GEMINI_MUSIC_MODEL`)
**Endpoint:** Gemini **Interactions API** (`/v1beta/interactions`)
**Code:** `backend/src/voice/music.ts`
A pod-specific ~30s clip is generated through the Interactions API, cached in
MongoDB, and served via `GET /api/pods/:id/music` to play as ambient room audio.
---
## Cooldown
Per-pod cooldown of **3 minutes** between urgent voice cues. Prevents spam if multiple risks fire simultaneously. Implemented in Hermes, not in Gemini.
Per-pod cooldown (`NUDGE_COOLDOWN_MS`, default 180000 ms / 3 min) gates repeated
interventions. Implemented in `backend/src/memory/policy.ts`, not in Gemini.