My/Team streams were one flat lane; source provenance was buried as a
gray badge by the filename. Group each lane into Signals (vision/git
inputs) and Reasoning & decisions (collision/intervention/outcome), and
promote source to a color-coded provenance chip with a readable kind
label. Presentation-only; no shared-type or backend changes.
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01VpySDjxpM1usXMEngJRWqG
Agent-published LiveKit audio is unreliable for voice: the track is
short-lived (publish, speak ~3s, unpublish) and blocked by browser
autoplay, so participants heard nothing even though the server published
fine. The VOICE_CUE text already arrives over the data channel, so speak
it in the browser via speechSynthesis instead — instant and reliable.
Prime speechSynthesis from user gestures (Enable sound, Share screen) so
later cues are allowed to play.
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01AaCFWMkYQmTcuPsxaaACft
Document the box topology so future sessions (and teammates' agents) don't
rediscover it the hard way: systemd-managed services (never launch the agent
manually — duplicate podman-hermes identities evict each other and silently
drop interventions), Caddy serving the static frontend from /var/www/podman,
the deploy procedure, and the shared-package build order.
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01AaCFWMkYQmTcuPsxaaACft
Voice generation, critical escalation, and audio publish all worked, but
participants heard nothing: browsers block autoplay of the agent's audio
track until a user gesture. Add the canonical LiveKit unlock — listen for
AudioPlaybackStatusChanged and show an "Enable sound" button that calls
room.startAudio() so PodMan's voice cues are actually heard.
Also make collision alerts short and direct instead of chatty AI prose:
card: "Conflict: ram + yahya both on README.md (unpushed). Seen before."
voice: "Conflict. ram + yahya, both on README.md."
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01AaCFWMkYQmTcuPsxaaACft
Live observations showed two engineers both dirty on README.md but zero
collisions firing. Two root causes:
1. normalize() only lowercased and prepended src/, so the same file at
different path depths ("agent.ts" vs "backend/src/agent.ts") never
matched. Replace with lowercased-basename matching.
2. Git ground truth (engineer_states.changedFiles) was only used to set
the unpushed flag, never to match the file. The strongest signal was
wasted.
Detector now fuses vision currentFile AND git changedFiles into one
file->engineers map, so a collision fires when two people share a dirty
file even if both screens aren't on it at the same instant.
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01AaCFWMkYQmTcuPsxaaACft
Reverse the best-effort error swallowing. MongoDB is core to PodMan's
continual-learning story and must always be used, so a broken memory
layer must surface immediately rather than silently masquerade as
working (which is how observations stayed at 0 unnoticed).
- agent verifies Mongo via initMemory() at boot; bad creds / unreachable
Atlas now fail loudly before joining the room, not mid-demo
- server exits on Mongo init failure instead of warning and limping on
- getGitStates and onScreenFrame no longer swallow Mongo errors
- memory persist() logs the failure and rethrows instead of warning
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01AaCFWMkYQmTcuPsxaaACft
A Mongo auth/connection failure in getGitStates escaped uncaught and
killed the agent process on the first screen frame, so collision
detection never ran. Make git-state fusion best-effort (degrade to
vision-only) and wrap the whole onScreenFrame loop so no per-frame
Gemini/GitHub/Mongo error can crash the long-running agent.
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01AaCFWMkYQmTcuPsxaaACft
room.disconnect() removes the participant from LiveKit but doesn't stop
the underlying OS capture. Without track.stop() the screen share indicator
keeps running after Leave. beatRef already had cleanup; add the same for
screenTrackRef.
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01AaCFWMkYQmTcuPsxaaACft
Add getGitStates(podId) to db.ts — queries the engineer_states collection
written by scripts/podman-agent.mjs and returns a map keyed by engineer name.
In PodMan.onScreenFrame(), fuse before detectCollisions(): if an engineer has
changedFiles in engineer_states, force hasUnpushedChanges=true on their context.
This overrides Gemini vision's unreliable pixel-based guess with deterministic
local git state — preventing the money-moment collision from silently not firing.
Key assumption: LiveKit participant identity matches the --name arg used when
running the git watcher (e.g. identity "alice" → --name alice).
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01AaCFWMkYQmTcuPsxaaACft
- Add scripts/podman-agent.mjs — polls git every 15s, upserts changedFiles/
diffStat/recentCommit/branch into MongoDB engineer_states collection
- README: add "Git watcher" section with per-laptop demo commands for each
team member (alice/bob/carol --pod demo-pod)
- PLAN.md: mark scheduled git truth ✅ partial, update acceptance checklist,
clarify remaining fusion step (GIT_REPORT data channel wire-up still needed)
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01AaCFWMkYQmTcuPsxaaACft
No fixed ownership — any teammate can pick up any task.
PLAN.md: drop Owner field from all tasks, remove team assignments table.
CLAUDE.md: remove ownership map table and person-specific lane rules.
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01FFbfi4Cmb7BY75Wtne7bZn
Hard gate: all code must trace to docs/PLAN.md task or a spec.
Claude must stop, consult, and update docs before writing unplanned code.
Includes off-plan signals checklist and rationale for 4-person concurrent team.
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01FFbfi4Cmb7BY75Wtne7bZn
Tell Claude this repo has 4 simultaneous owners with distinct lanes.
Adds ownership map, rules for staying in lane, merge conflict guidance,
and integration point contract rules.
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01FFbfi4Cmb7BY75Wtne7bZn
- Remove all docs/generated/* (stale research output from prior workflow)
- Rewrite PLAN.md as ordered implementation plan: 10 tasks by dependency + demo criticality
- Each task has owner, estimate, dependencies, specific files to create/modify
- Cut line separates must-ship from nice-to-have
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01FFbfi4Cmb7BY75Wtne7bZn