Self-contained handoff for a fresh session: rebuild the light/real-data graph to
the dark Bauhaus mock's quality + structure (metrics rail, learning-loop rail,
activity stream, selected-node panel) and make the graph dynamic (force-directed
+ animated), in light shadcn. Captures architecture, data, the dynamic-layout
options, what to feed the new panels, files, gotchas, and acceptance criteria.
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
The deployed graph was an unreadable mess: full file paths centered on nodes
bled across columns, and collision labels showed garbage vision symbols
("infra/README.md### Running the git watcher").
- node labels are now the last two path segments (full path in summary)
- collision labels are just the file (drop the junk #symbol)
- cap file nodes to 9 (collision files prioritized)
demo-pod: 22 -> 20 clean nodes; no label bleed.
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Materializer (live.ts) — cut demo-pod from 110 -> 22 nodes:
- cap to 8 recent collisions; collapse repeats by memorySignature
- collapse interventions to one (most recent) per collision
- filter junk 'files' (URLs, env vars, browser/app names, scratch/test) to
real source paths only
- prune test-artifact engineers (a/b/verify/codex-check/-testrepo) + any node
orphaned by that
- collisions referenced by accepted outcomes bypass the cap so the learned_from
money path never drops; risk-paths metric counts distinct signatures
UI: per-pod 'Team memory' action on each PodCard's menu (replaces the header
button that always opened pods[0]).
Verified against live demo-pod data (joins connect); typechecks clean.
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Verified materializePodGraph against real demo-pod data (joins all connect:
21/21 interventions->collisions, learned_from produced). Tuning:
- engineer nodes are case-insensitive (merges Shakthi/shakthi)
- git (engineer_states) now only CONFIRMS editing on files vision/collisions
already surfaced, instead of adding the whole repo diff (killed a 29-file
node explosion from a watcher running against the full podman repo)
Cut demo-pod from 110 -> 77 nodes; git file-edges 39 -> 6.
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
- backend/src/graph/live.ts: materializePodGraph builds the graph from the real
collections (pods, engineer_states, observations, collisions, interventions,
outcomes) instead of the demo seed. Parses git-status paths, fuses git+vision,
draws collides/warns/learned_from, computes live metrics + a column layout.
- store.ts: loadPodGraph now prefers live → seeded team_model.graph → demo.
- GraphView.tsx: light/shadcn theme (from the team-memory-theme work), composed
from the ruixen primitives; node-shape encoding unchanged.
- docs/graph.md: live data→graph mapping + fallback order.
Typechecks clean. Not yet runtime-verified end-to-end (Atlas creds rotated again).
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
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
infra/Caddyfile: add podman.live + www.podman.live (serve app + proxy /api),
so the domain is durable in the canonical config (not just a manual edit).
index.html: Open Graph + Twitter Card meta (title, description, og:image) so
sharing www.podman.live renders a rich preview. Adds a 1200x630 og.png card
(generated from og.svg) under public/.
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
SVG favicon (dark #0b0f17 tile, emerald "P" + live dot) wired via
<link rel="icon"> in index.html. Fixes the favicon.ico 404.
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Resolve App.tsx header conflict: keep main's "Privacy-limited" badge AND the
"Team memory" graph button (both in the header action group). server.ts and
backend/package.json auto-merged cleanly — main's closeMemory/shutdown and the
graph:seed script are both preserved.
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Resolve conflicts:
- backend/src/server.ts: keep main's getPresence + closeRoom (room auto-cleanup)
and add the graph imports/routes (additive).
- frontend/src/App.tsx: take main's shadcn command-center UI and re-integrate
GraphView — import, graphPodId state, an early-return render branch, and a
shadcn "Team memory" button next to Refresh.
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
- reachFrom now returns the direct outbound edges PLUS the recursive
$graphLookup reaches, de-duped by edge id, with maxDepth to bound cycles.
It was dropping edges straight off the start node. [review P2]
- GraphView SVG nodes are keyboard-accessible: role/tabIndex/aria-label +
Enter/Space handler alongside onClick. [review P3]
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Adds the team_model graph layer (the "it learned" view) and its visualization,
per docs/graph.md. Demo-backed first; built on origin/main conventions.
- shared: PodGraph / node / edge / metric types + GraphNodeDoc / GraphEdgeDoc
- backend/src/graph: demo graph data; Mongo store (loadPodGraph w/ demo
fallback, seedGraph, reachFrom via $graphLookup); graph:seed script
- backend/src/server.ts: additive GET /api/pods/:id/graph + /graph/reach/:node
- frontend: dark-Bauhaus GraphView + fetch helper, reachable from a
"Team memory" toggle in App.tsx
- docs/graph.md: spec (data model, $graphLookup, API, demo-first plan)
Demo-backed: the route serves a grounded demo graph when team_model has no
graph yet; graph:seed writes team_model + graph_nodes/graph_edges so the
$graphLookup traversal is real. Swap loadPodGraph to live team_model later.
Known follow-ups before merge: branch is based on 65a0791; origin/main is now
at 1294b84, so this needs a rebase + App.tsx conflict resolution (teammate
rewrote App.tsx with live room view / one-click join).
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
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
DELETE /api/pods/:id now also calls closeRoom (RoomServiceClient.deleteRoom)
to end the live LiveKit room and disconnect anyone connected. PodView listens
for RoomEvent.Disconnected and returns the user to the pod list, so a deleted
pod cleanly kicks everyone out instead of stranding them in a dead room.
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Use the member name as the LiveKit identity (was random per join) so a
refresh/rejoin replaces the existing session instead of leaving a ghost
participant in the room. Set roomConfig on the token (emptyTimeout 60s,
departureTimeout 20s) so empty rooms and departed participants clean up
promptly. Pods map 1:1 to a deterministic room name, so joins reuse the
same room rather than spawning new ones.
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
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
Join UX: click a member's name to join directly, or type a name and "Join"
(adds to roster + joins) — removes the redundant dropdown step. "Add" still
adds to the roster without joining.
Presence: new GET /api/presence (LiveKit RoomServiceClient) reports who's
connected per pod. The pod list polls it and shows a "N in room" badge plus a
green dot on members currently connected, so people can see active pods and jump in.
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
- PodView now shows LIVE LiveKit participants (updates as people join/leave,
active-speaker highlight) instead of the static roster — no refresh needed.
- "Play beat" button publishes a generated 4/4 beat into the room so every
participant hears the same audio (speaker lights up) — a real connectivity test.
- "Share my screen" is now a deliberate button; joining only connects to the
room (fast/reliable), so a denied/slow screen prompt no longer fails the join.
- Session persisted in sessionStorage with auto-reconnect, so a refresh keeps
you in the room instead of dropping back to the pod list.
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Backend: atomic create with insert-retry-on-duplicate-key (removes slug
TOCTOU race + wrong 400s), resilient per-index creation so a unique-index
failure can't silently drop the constraint or block seeding, idempotent
race-safe seeding via $setOnInsert, type validation + size caps on all pod
fields/members, removeMember no-ops without a write, /api/outcome guarded.
Frontend: per-pod busy state (one mutation no longer disables every card),
joined pod derived from the list (can't go stale), create keeps inputs on error.
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
The precaching PWA SW was serving an old bundle after deploys (stale UI).
Switch to selfDestroying so it unregisters + clears caches on all clients;
deploys are now always fresh. Re-add a tuned PWA before the demo.
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Pods are persisted in MongoDB and CRUD'd via /api/pods (list/create/get/
update/delete + add/remove member). Shared Pod reshaped to a persisted entity
(members: string[], description, timestamps) + PodInput. Backend seeds Demo/
Frontend/Backend Pods on first run (Squad -> Pod rename). Frontend replaces
hardcoded teams with live data: PodCard (member chips add/remove, inline edit,
delete, join) + CreatePodForm; App fetches+mutates via API. Removes teams.ts/
TeamCard; gitignores test artifacts.
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
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
Replace the in-memory store with a real MongoDB-backed store. Adds memory/db.ts
(client singleton, typed collections, startup ping + indexes) and rewrites
record{Observation,Collision,Intervention,Outcome} to insert into Mongo
(best-effort — failures log, don't crash). Server connects on startup and
exposes GET /api/memory/stats for verification.
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>