Inspiration
Group chats are noisy. Most bots make it worse—talking too much, at the wrong times, with zero sense of vibe. We wanted an AI that behaves like a considerate teammate: quick when helpful, silent when not, and actually learns the people in the room.
What it does
- Selective speaking: Decides when to chime in (mentions, direct questions, confusion, milestones, de-escalation) and when to stay quiet (side-banter, solved threads).
- Micro-replies: Keeps outputs ≤3 sentences unless asked for depth; playful, weird, never mean.
- Memory: Stores lightweight facts about each participant and rolling notes about group norms (etiquette, inside jokes, boundaries).
- Context steering: Grounds replies in the last window of chat to stay on-thread.
- Safety rails: No hallucinated specifics, avoids stereotypes, and respects cooldowns to prevent spam.
How we built it
- Frontend: Next.js (App Router), sticky composer, scroll-locked message list, presence pills.
Backend:
- Supabase for auth (Google OAuth), Realtime messages, and storage of chat/memory.
- Decision route (
/api/decision): prompts an LLM for a STRICT-JSON policy verdict{speak, why, topic}. - Reply route (
/api/fred): if and only ifspeak=true, crafts the actual message using windowed context.
LLMs:
- JanitorAI completions for chat generation (OpenAI-compatible endpoint).
- Letta for agent memory blocks (per-user “facts” and a
group_dynamicblock) and the decision JSON.
Guardrails: freshness gate (≤15s) so Fred only replies to recent human messages; last-speaker check to avoid back-to-back Freds; once-per-thread nudge cooldown.
Challenges we ran into
- Edge vs server nuances: accessing
req.url/origins and environment vars on Vercel vs local. - SSE/stream handling: stitching
data: { "choices":[{"delta":...}] }into one coherent string. - Persona drift: keeping Fred playful but not mean; tightening the system prompt and adding “Do/Don’t” tables.
- Double-posting: race conditions between realtime inserts and decision calls—fixed with freshness and “last is Fred” checks.
- Env setup: mismatched keys (service role vs anon) and missing base URLs causing 401s/“too_old” no-ops.
Accomplishments that we're proud of
- A bot that actually knows when to shut up.
- Clean STRICT-JSON decision contract powering consistent behavior.
- Live group memory that accumulates norms without leaking private info.
- A lightweight, pleasant UI with sticky input, smooth scroll, and presence.
What we learned
- “When to speak” is as important as “what to say.” Policy+JSON beats pure prompting.
- Tiny fundamentals—cooldowns, last-speaker checks, and recency filters—dramatically improve perceived intelligence.
- Memories need scope (per-user vs group) and limits (trimmed, summarized) to stay useful.
What's next for fred67
- Multi-room & threads: per-channel norms, thread-aware decisions.
- Memory UI: view/edit personal notes and group dynamic logs.
- Better retrieval: embeddings + summaries for long-term context.
- Bridges: Slack/Discord/Telegram connectors.
- Moderation & safety: toxicity filters, escalation patterns, and red-team prompts.
- Analytics: talk/silence ratios, helpfulness reactions, configurable guardrails.
- Mobile PWA & notifications: light, fast, installable client.
Built With
- jllm
- letta
- nextjs
- oauth
- supabase

Log in or sign up for Devpost to join the conversation.